; Copyright 1996 Acorn Computers Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;     http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
; > Wimp09

;;-----------------------------------------------------------------------------
;; Claim a block big enough for the RMA sprite pool area, then attempt to
;; map the RMA against the ROM working out the difference.
;;
;; Then claim the block so that it is big enough fill in both areas, build
;; the list and then sort it.  Using the OS_HeapSort SWI.
;;
;; in   [baseofsprites] = current RAM sprite area
;;      [baseofromsprites] = current ROM sprite area
;;      [list_at] = address of sorted list / =0 if none
;;      [listsize] = size of sorted list / =0 if none
;;      [addtoolstolist] = 0 if not to / >0 then add tool sprites pool (if present)
;;      [tool_areaCB] = valid control block for adding tool sprites (if required)
;; out  [list_at] = base of sorted list / =0 if none
;;      [list_size] = size of sorted list (aligned to boundary)
;;      [list_end] = real end of list used when scanning for sprite
;;-----------------------------------------------------------------------------

alignvalue      * 64                    ; *MUST* be a Log2 value

        ASSERT  list_size=list_at+4

makespritelist Entry   "R0-R4,R8-R9"

        LDRB    R3,addtoolstolist
        TEQ     R3,#0                   ; should I add the tool sprites?
        LDRNE   R0,=SpriteReason_ReadAreaCB +&100
        ADRNEL  R1,tool_areaCB
        SWINE   XOS_SpriteOp            ; Yes then decode the RAM based control block
;
        MOV     R8,R3
        Debuga  sprite,"Sprite count for Tools =",R8
;
        LDR     R0,=SpriteReason_ReadAreaCB +&100
        LDR     R1,baseofromsprites
        SWI     XOS_SpriteOp            ; attempt to get number of ROM sprites
;
        ADD     R8,R8,R3                ; add to growing total
        Debuga  sprite,", ROM =",R3
;
        LDRB    R3,addtoolstolist
        TEQ     R3,#0                   ; Adding tool sprites?
        LDREQ   R0,=SpriteReason_ReadAreaCB +&100
        LDREQ   R1,baseofsprites        ; base of RAM area
        SWIEQ   XOS_SpriteOp            ; No then include iconsprites
;
        Debug   sprite,", RAM =",R3
;
        ADD     R3,R8,R3                ; total number of sprites to be obtained
        ADD     R3,R3,#alignvalue -1
        BICS    R3,R3,#alignvalue -1    ; align to nice boundary
        BLEQ    freelist                ; un allocate the list (if null)
        BEQ     %FT60                   ; exit - if null (flag as so)
;
        LDR     R2,list_size
        CMP     R2,R3,LSL #2            ; is the current buffer big enough?
        BHS     %FT10                   ; if not then skip the new cliam
;
        BL      freelist                ; release the current list
;
        MOV     R0,#ModHandReason_Claim
        MOV     R3,R3,ASL #2
        BL     XROS_Module              ; attempt to claim

        DebugE  sprite,"Cant allocate list buffer "

        BVS     %FT60                   ; and fall back if failed to get required memory
;
        Debug   sprite,"list buffer allocated at, size:",R2,R3
;
        ADRL    R0,list_at
        STMIA   R0,{R2,R3}              ; store bounds of the list away
10
        LDR     R3,list_at              ; R3 -> buffers to store names pointers at

        Debug   sprite,"Start of sprite list: ",R3

        LDRB    R0,addtoolstolist
        TEQ     R0,#0                   ; Adding tool sprites?
        BNE     %FT25                   ; Yes then jump, don't include RAM icon sprites

        LDR     R0,baseofsprites
        LDR     R1,[R0,#saFirst]
        ADD     R1,R1,R0                ; R1 -> first sprite in area
        LDR     R2,[R0,#saNumber]       ; R2 = count for number of sprites
;
        Debug   sprite,"RAM sprites; first, count =",R1,R2
;
20      SUBS    R2,R2,#1
        STRPL   R1,[R3],#4              ; store a pointer away
        LDRPL   R0,[R1,#spNext]
        ADDPL   R1,R1,R0                ; advance to the next sprite
        BPL     %BT20                   ; looping until finished
;
        Debug   sprite,"End of RAM sprite list =",R3
;
25      LDR     R0,baseofromsprites
        LDR     R1,[R0,#saFirst]
        ADD     R1,R1,R0                ; R1 -> start of ROM pool
        LDR     R2,[R0,#saNumber]       ; R2 = counter for number of sprites in area
;
        Debug   sprite,"ROM sprites; first, count =",R1,R2
30
        SUBS    R2,R2,#1                ; decrease counter
        STRPL   R1,[R3],#4              ; store another pointer away
        LDRPL   R0,[R1,#spNext]
        ADDPL   R1,R1,R0                ; advance to next
        BPL     %BT30                   ; looping until finished (bla de bla)
;
        LDRB    R2,addtoolstolist
        TEQ     R2,#0                   ; add the tools area to the list of sprites
        BEQ     %FT35
;
        ADRL    R0,tool_areaCB
        LDR     R1,[R0,#saFirst]
        ADD     R1,R1,R0
        LDR     R2,[R0,#saNumber]
;
        Debug   sprite,"Tool sprites; first, count =",R1,R2
31
        SUBS    R2,R2,#1                ; have we finished copying the pointers yet?
        STRPL   R1,[R3],#4
        LDRPL   R0,[R1,#spNext]
        ADDPL   R1,R1,R0                ; advance to next sprite
        BPL     %BT31                   ; until finished
35
        Debug   sprite,"End of entire list =",R3
;
; Now perform a Heap Sort of the list.
;
        Push    "R3"                    ; storing the top limit away
        LDR     R1,list_at              ; start of list
        SUB     R0,R3,R1
        MOV     R0,R0,ASR #2            ; number of items in list
      [ debugsprprior
        ADRL    R2,checkspritenames     ; comparison routine
      |
        ADR     R2,checkspritenames     ; comparison routine
      ]
        MOV     R3,WsPtr

        Debug   sprite,"HeapSort: Items, At, Checker =",R0,R1,R2

        TST     R1,#2_111:SHL:29        ; high address?
        BNE     %FA37
        SWI     XOS_HeapSort            ; attempt to sort the list
        B       %FA39
37      Push    "R7"
        MOV     R7,#0
        SWI     XOS_HeapSort32          ; use new SWI with 32-bit address
        Pull    "R7"

39      Pull    "R3"                    ; restore original boundary for the list

; Now attempt to remove duplicates by simply scanning down the list from start to
; end.  This we do by checking first to see if we have reached the end, if we
; have then we can exit.  Otherwise we get two pointers if they are the
; same then we block the entire list back down assuming that the first name
; compared is the

      [ SpritePriority
        LDR     R8,baseofhisprites
      |
        LDR     R8,baseofsprites
      ]
        LDR     R9,[R8,#saEnd]
        LDR     R2,list_at              ; start of the list to be scanned

        Debug   sprite,"HeapSort done, scan the list for duplicates"

40      SUB     R4,R3,R2
        CMP     R4,#8                   ; have we finished yet?
        STRLO   R3,list_end             ; setup the chopping end
        EXIT    LO

        LDMIA   R2,{R0,R1}
        BL      checkspritenames        ; are the two sprite names the same?
        ADDNE   R2,R2,#4
        BNE     %BT40                   ; loop back until all finished

 [ debugsprite
        ADD     R14,R0,#spName
        DebugS  sprite,"Duplicate:",R14,12
 ]
        SUB     R14,R0,R8               ; is first sprite in the RAM low area? (or high-priority if SpritePriority true)
        CMP     R14,R9
        ADDCC   R2,R2,#4                ; advance past entry if inside the RAM area, otherwise copy next name over current

      [ SpritePriority
        LDR     R4,[R2]                 ; note address of sprite being removed from list
      ]
        MOV     R0,R2                   ; start to copy from
50      CMP     R0,R3                   ; have we finished yet?
        SUBEQ   R3,R3,#4
        BEQ     %FT55                   ; looping until all copied (modify the end pointer as required)

        LDR     R1,[R0,#4]
        STR     R1,[R0],#4              ; copy it down
        B       %BT50                   ; loop until the list has been moved

55
      [ SpritePriority
        LDR     R0, preferredpool
        TEQ     R0, #0
        DebugIf EQ, sprprior, "RAM sprites preferred"
        BEQ     %BT40                   ; don't do anything if RAM sprites have priority

        Push    "R8,R9"
        LDR     R8, baseofsprites       ; see if the removed sprite was in the RAM sprite area
        LDR     R9, [R8, #saEnd]
        SUB     R0, R4, R8
        CMP     R0, R9
        Pull    "R8,R9", HS
      [ debugsprprior
        ADDHS   R4, R4, #spName
        DebugSIf HS, sprprior, "This removed sprite was not in RAM area: ", R4, 12
      ]
        BHS     %BT40                   ; don't do anything if removed sprite wasn't in the RAM sprite area

        Push    "R2,R5"
        LDR     R5, [R4, #spNext]       ; size of sprite (== amount to shift later pointers down by)
      [ debugsprprior
        Debug   sprprior, "Deleting sprite from RAM area: addr, size =", R4, R5
        ADD     R4, R4, #spName
        DebugS  sprprior, "- name = ", R4, 12
        SUB     R4, R4, #spName
      ]
        MOV     R0, #512
        ORR     R0, R0, #SpriteReason_DeleteSprite
        MOV     R1, R8
        MOV     R2, R4
        SWI     XOS_SpriteOp            ; delete the unnecessary sprite
    [ windowsprite
      [ ThreeDPatch
        MOV     R0,#0                   ; RAM pointers are now stale
        BL      reset_all_tiling_sprites
      |
        MOV     R0,#-1                  ; RAM pointers are now stale
        STR     R0,tiling_sprite
      ]
    ]
        LDR     R2, list_at             ; go back to beginning of list
56      CMP     R2, R3                  ; have we finished yet?
        Pull    "R2,R5,R8,R9", EQ
        BEQ     %BT40                   ; go back to check next pair of sprites

        LDR     R0, [R2]
        SUB     R1, R0, R8
        CMP     R1, R9
        ADDHS   R2, R2, #4
        BHS     %BT56                   ; this sprite wasn't in the RAM area, so won't have been affected by the deletion
        CMP     R0, R4
        ADDLO   R2, R2, #4
        BLO     %BT56                   ; this sprite was below the deleted sprite, so again no action is required
        SUB     R0, R0, R5
      [ debugsprprior
        ADD     R0, R0, #spName
        DebugS  sprprior, "Realigned sprite:", R0, 12
        SUB     R0, R0, #spName
      ]
        STR     R0, [R2]                ; move pointer down
        ADD     R2, R2, #4
        B       %BT56                   ; check next pointer
      |
        B       %BT40                   ; go back to check next pair of sprites
      ]

60      MOV     R0,#-1
        STR     R0,list_at              ; flag as no valid list setup
        STR     R0,list_size
        EXIT

;..............................................................................

; Compare the two sprite names, ensuring case insensitive and truncating
; at the twelth character

; in    R0 -> sprite to compare
;       R1 -> sprite to compare against
; out   NE/EQ GT/LT CS/CC

checknames Entry "R0-R4"
        B       %FT05

checkspritenames ALTENTRY

        ADD     R0,R0,#spName           ; ensure pointing at the sprite names
        ADD     R1,R1,#spName
05      MOV     R2,#12                  ; maximum string length = 12 characters

10      LDRB    R3,[R0],#1
        LDRB    R4,[R1],#1              ; get characters
        CMP     R3,#32
        MOVLE   R3,#0
        CMP     R4,#32
        MOVLE   R4,#0                   ; convert to terminators if required
        ASCII_LowerCase R3,LR
        ASCII_LowerCase R4,LR           ; ensure that the characters are lower case
        CMP     R3,R4                   ; and that they match
        EXIT    NE                      ; returning if not the same
;
        TEQ     R3,#0                   ; is it the end of the strings?
        SUBNES  R2,R2,#1
        BNE     %BT10                   ; loop back if still characters pending
;
        CMP     R3,R4                   ; compare the final characters
        EXIT


;;-----------------------------------------------------------------------------
;; Free list - attempt to release the list memory if currently allocated.
;;
;; in   [list_at] >0 then release block
;; out  [list_at] [list_size] = 0
;;-----------------------------------------------------------------------------

freelist EntryS  "R0-R2"

        Debug   sprite,"Calling to free sprite list",#list_at
;
        LDR     R2,list_at
        CMP     R2,R2,ASR #31           ; is the list memory allocated?
        MOVNE   R0,#ModHandReason_Free
        BLNE    XROS_Module              ; yes, so release it (ignore errors)
;
        MOV     R2,#0
        STR     R2,list_at
        STR     R2,list_size            ; mark as released
;
        EXITS


;;-----------------------------------------------------------------------------
;; Locate a sprite name setting its pointers to meaningful values.  This routine
;; attempts to binary chop the sprite list created by calling "makespritelist".
;;
;; Based on the algorithm in Knuth; Sorting/Searching, pp 407
;;
;; in   [spritename] --> sprite name
;; out  R2 -> sprite, VS/VC if not found/found
;;-----------------------------------------------------------------------------

getspriteaddr Entry "R0-R1,R3-R5"

        LDR     R0,spritename           ; get pointer to name to compare against
;
        LDR     R2,list_at              ; base of sprite pointerrs
        CMP     R2,R2,ASR #31           ; this may be 0 (not initialised) or -1 (no room)
        BEQ     %FT20
        LDR     R3,list_end
        SUB     R3,R3,R2
        SUB     R3,R3,#4
        MOV     R3,R3,ASR #2            ; u = size of list
        MOV     R4,#0                   ; l = 0

10      CMP     R4,R3                   ; if l>u then not found
        BGT     %FT20
;
        ADD     R5,R4,R3
        MOV     R5,R5,ASR #1            ; i = (l+u) /2
;
        LDR     R1,[R2,R5,ASL #2]
        ADD     R1,R1,#spName
;
        BL      checknames
        ADDGT   R4,R5,#1                ; if [R0]>[R1] l = i + 1
        SUBLT   R3,R5,#1                ; if [R0]<[R1] l = i - 1
        BNE     %BT10
;
        LDR     R2,[R2,R5,ASL #2]       ; R2 -> sprite found !!!
        CLRV
        EXIT
20
        MOV     R2,#0                   ;
        SETV                            ; else return 'cos not found V set!
        EXIT


;;-----------------------------------------------------------------------------
;; Handle the opening of the messages file - check first to see if it has
;; already been opened.
;;
;; in   -
;; out  R0 -> 16 byte block for messages (may already be open)
;;-----------------------------------------------------------------------------

GetMessages ROUT

        Push    "R1-R2,LR"
;
        LDR     R0,messages
        CMP     R0,#0                   ; is it open yet?
        BNE     %FT10
;
        ADRL    R0,message_block
        ADR     R1,messfsp
        MOV     R2,#0                   ; let MessageTrans do caching
        SWI     XMessageTrans_OpenFile
        ADRVCL  R0,message_block
        STRVC   R0,messages             ; pointer to messages block

        Debug   err,"Message block @",R0
10
        Pull    "R1-R2,PC"

messfsp = "WindowManager:Messages",0
        ALIGN


;;-----------------------------------------------------------------------------
;; Handle losing the messages file if its already opened.
;;-----------------------------------------------------------------------------

LoseMessages ROUT

        Push    "R0,LR"
;
        LDR     R0,messages
        CMP     R0,#0                   ; is it already open? (clears V)
        SWINE   XMessageTrans_CloseFile
        STRVS   R0,[SP]
;
        MOV     R14,#0
        STR     R14,messages            ; flag as lost (always!)
;
        Pull    "R0,PC"


;;-----------------------------------------------------------------------------
;; QuickLookup - look up token (no buffer), parameters in R4-R7 are optional
;;
;; in   R0 -> token to lookup
;; out  R0 -> text found
;;      R1 = length of text found
;;-----------------------------------------------------------------------------
QuickLookup
        Entry   "R2,R3"
        MOV     R1,R0
        MOV     R2,#0
        MOV     R3,#0
        BL      GetMessages             ; open messages if required
        SWI     XMessageTrans_Lookup
        MOVVC   R0,R2
        MOVVC   R1,R3
        EXIT

;;-----------------------------------------------------------------------------
;; LookupToken - resolve token into user specified buffer (with parameters)
;;
;; in   R0 -> token to lookup
;;      R2 -> buffer
;;      R3 = length of buffer
;;      R4 -> %0 substitution
;;      R5-R7 assumed to be zero
;;-----------------------------------------------------------------------------

LookupToken Entry "R1-R7"

        MOV     R1,R0                   ; -> token to be used
        B       %FA10

;;------------------------------------------------------------------------------
;; LookupToken1 - lookup token into user specified buffer
;;
;; in   R0 -> token to lookup
;;      R2 -> buffer
;;      R3 = length of buffer
;;------------------------------------------------------------------------------

LookupToken1 ALTENTRY

        MOV     R1,R0
        MOV     R4,#0                   ; justincase!
        MOV     R5,#0
10      MOV     R6,#0
        MOV     R7,#0
        BL      GetMessages             ; open messages if required
        SWI     XMessageTrans_Lookup
        EXIT


;;-----------------------------------------------------------------------------
;; Lookup an error block expanding and then return.
;;
;; in   R0 -> error block
;; out  R0 -> error block and overflow set
;;-----------------------------------------------------------------------------

ErrorLookup ROUT

        Push    "R0-R7,LR"
;
        BL      GetMessages             ; attempt to open the file
        ADDVS   sp,sp,#4
        BVS     %FT10                   ; reporting any errors in the process
;
        MOV     R1,R0                   ; R1 -> control block
        Pull    "R0"                    ; R0 -> error block
        MOV     R2,#0
        MOV     R4,#0                   ; no parameters
        MOV     R5,#0
        MOV     R6,#0
        MOV     R7,#0

 [ debugerr
        Debuga  err,"WimpErrorLookup,r0,r1",R0,R1
        ADD     R14, R0, #4
        DebugS  err," Token:",R14
 ]
        SWI     XMessageTrans_ErrorLookup
10
        Pull    "R1-R7,PC"              ; look it up and then return


;------------------------------------------------------------------------------
; Constants required for message checking routines
;------------------------------------------------------------------------------

messcheck_version       * 284


;;-----------------------------------------------------------------------------
;; Wimp_AddMessages
;;
;; This SWI will add a null terminated list of messages to the list of
;; accepted messages on the current task.  This is really only any use for
;; tasks which know about Wimp >= 284.
;;
;; in   R0 -> list of messages / =0 for none
;; out  -
;;-----------------------------------------------------------------------------

SWIWimp_AddMessages

        MyEntry "AddMessages"

        Debug   msgsel,"Wimp_AddMessages: list ->",R0

        MOVS    R3,R0
        BEQ     ExitWimp                ; if no messages to add then exit

        LDR     R4,taskhandle           ; currently active task

        LDR     R0,[WsPtr,R4]           ; -> task record
        LDR     R0,[R0,#task_wimpver]
        LDR     R1,=messcheck_version
        CMP     R0,R1                   ; is it worth adding to the list?
        BLHS    addmessages

        B       ExitWimp

;..............................................................................

; Add a list of messages to the messages to the internal task handle specified,
; in doing so we may actually have to allocate a block.
;
; The routine attempts to add the messages at the end and then perform
; a heap sort.  Having first checked for duplicates, this is not a speed
; critical operation (ie. not called on null-event).

; in    R3 -> list of messages / null terminated
;       R4 = internal task handle to add messages to / assumed to be valid
; out   -

addmessages Entry "R0-R7"

        Debug   msgsel,"add messages: list, task =",R3,R4

        MOV     R5,#0
10      LDR     R6,[R3,R5]
        TEQ     R6,#0                   ; end of the list encountered?
        ADDNE   R5,R5,#4
        BNE     %BT10                   ; loop back until finished scanning

        CMP     R5,#0                   ; is there any messages to add?
        EXIT    EQ                      ; if not then return without doing anything

        Debug   msgsel,"size of messages list =",R5

; R5 = size of messages list to add / create

        LDR     R4,[WsPtr,R4]           ; get pointer to the task block

        LDR     R2,[R4,#task_messages]
        CMP     R2,#nullptr
        EXIT    EQ                      ; the real fix for the AddMessages-to-task-that-already-wants-them bug
        CMP     R2,#0
        BNE     addmoremessages         ; add to the list if non-zero, create new block

        Push    "R3"
        MOV     R3,R5                   ; size of list to create
        MOV     R0,#ModHandReason_Claim
        BL     XROS_Module              ; attempt to allocate
        Pull    "R3"
        EXIT    VS

        Debug   msgsel,"new message buffer: size, at =",R5,R2

        STR     R2,[R4,#task_messages]
        STR     R5,[R4,#task_messagessize]
        Push    "R2,R5"

20      LDR     R6,[R3],#4
        TEQ     R6,#0
        STRNE   R6,[R2],#4              ; copy a message number
        BNE     %BT20                   ; loop back until all checked

        Pull    "R2,R6"
        B       sortmessages            ; ensure they are sorted

;..............................................................................

; add more to the current list - extend the current block by R5 and then
; attempt to add the messages at the end removing duplicates, once
; done shrink the block down to a real size.

; in    R3 -> list of messages to be added
;       R4 -> task record
;       R5 = number of words to append

addmoremessages
        LDR     R1,[R4,#task_messagessize]
        LDR     R2,[R4,#task_messages]  ; current list information

 [ RO4 :LAND: false ; This is too late to do this fix; if the app wants all messages, the the Wimp hasn't allocated a
                    ; messages list, and so addmoremessages doesn't get called. Interestingly, this fix is undone in
                    ; the patches to 4.02...
; MB FIX
; If the current message list has only the 0 terminator in it then the application wants all messages.
; So, don't bother adding these new messages as that will stop all other messages getting through.
	LDR	R14,[R2,#0]
	TEQ	R14,#0
	EXIT	EQ
; end MB FIX
 ]

        Push    "R3"
        MOV     R0,#ModHandReason_ExtendBlock
        MOV     r3, r5                  ;  jb/ma 4/1/06 r5 is already the extra space required
        BL     XROS_Module              ; attempt to extend it
        Pull    "R3"                    ; preserve the list pointer
        EXIT    VS

        Debug   msgsel,"extended message block at, size =",R2,R1

        MOV     R6,R1                   ; extending boundary  (old message size)

30      LDR     R7,[R3],#4              ; get a value from the list
        TEQ     R7,#0
        BEQ     %FT50

        Debug   msgsel,"adding message (check for duplicate) =",R7

        MOV     R0,R1                   ; index to check entries by

40      SUBS    R0,R0,#4
        STRMI   R7,[R2,R6]
        ADDMI   R6,R6,#4                ; add in at the end if end reached
        BMI     %BT30

        LDR     R14,[R2,R0]             ; get a message number
        CMP     R14,R7                  ; does it already exist
        BNE     %BT40                   ; loop back until found
        B       %BT30                   ; if it doesn't then try another entry

50      ADD     r3,r1,r5                ; jb/ma 18/1/06 total needed + claimed
        SUBS    r3,r6,r3                ; jb/ma 18/1/06 actual less above
                                        ; so give back any not needed
        MOVNE   R0,#ModHandReason_ExtendBlock
        BLNE   XROS_Module              ; reduce back to a meaningful size
        EXIT    VS

        Debug   msgsel,"after block truncate: at, change =,size =",R2,R3,R6

        STR     R2,[R4,#task_messages]  ; update to contain new size
        STR     R6,[R4,#task_messagessize] ; jb/ma 4/1/06 this is the actual size
                                           ; r3 is only the change in size

sortmessages
        Debug   msgsel,"sort list at, size =",R2,R6

        MOV     R0,R6,LSR #2            ; size of the list to be sorted
        MOV     R1,R2                   ; -> list to be sorted
        MOV     R2,#0                   ; sorting unsigned integers
        TST     R1,#2_111:SHL:29
        BNE     %FT55
        SWI     XOS_HeapSort
        B       %FT57
55      MOV     R7,#0
        SWI     XOS_HeapSort32
57
        Debug   msgsel,"list sorted and ready to rock and roll"

        EXIT


;;-----------------------------------------------------------------------------
;; Wimp_RemoveMessages
;;
;; Attempt to remove a set of messages being accepted by a task, no errors
;; are generated for unknown messages.  This call only applies to tasks
;; with a version >= 284.
;;
;; in   R0 -> list of messages / =0 for none
;; out  -
;;-----------------------------------------------------------------------------

SWIWimp_RemoveMessages

        MyEntry "RemoveMessages"

        Debug   msgsel,"Wimp_RemoveMessages: list at =",R0

        MOVS    R3,R0                   ; is there a messages list?
        CMPNE   R3,#nullptr
        BEQ     ExitWimp                ; exit if there is no list supplied

        LDR     R4,taskhandle

        LDR     R0,[WsPtr,R4]           ; -> task that is currently active
        LDR     R0,[R0,#task_wimpver]   ; = version number known by this task
        LDR     R1,=messcheck_version
        CMP     R0,R1                   ; is the tasks version number valid for this call?
        BLHS    removemessages

        B       ExitWimp

;..............................................................................

; remove the list of messages at R3 using internal handle of R4.

; in    R3 -> list of messages (will be non-zero)
;       R4 = internal task handle
; out   -

removemessages Entry "R1-R2,R4-R8"

        Debug   msgsel,"Selective remove task, list at =",R3,R4

        LDR     R4,[WsPtr,R4]           ; -> task block

        LDR     R2,[R4,#task_messages]
        CMP     R2,R2,ASR #31           ; are there any messages listed?
                                        ; (or does the task need to continue to receive all messages anyway?)
        LDRNE   R6,[R4,#task_messagessize]
        CMPNE   R6,#0
        EXIT    EQ                      ; if no messages then return

        Debug   msgsel,"selective remove list, size =",R2,R6

; R2 -> messages list
; R6 = size of the list to be scanned

10      MOV     R7,#0                   ; index into the list

        LDR     R8,[R3],#4              ; get message to be removed
        CMP     R8,#0
        BEQ     %FT40                   ; when end of list reached then reduce block size

        Debug   msgsel,"scan to remove message =",R8

; R7 = index into list of messages being scanned
; R8 = message to be removed

20      CMP     R7,R6                   ; have we reached the end of the list yet?
        BGE     %BT10                   ; loop back as finished scanning

        LDR     R0,[R2,R7]              ; get message we are looking at
        CMP     R0,R8                   ; remove this one?
        ADDNE   R7,R7,#4
        BNE     %BT20                   ; loop back until all checked

        Debug   msgsel,"message found at offset =",R7

30      CMP     R7,R6                   ; have we finished yet?
        ADDLT   R14,R7,#4
        LDRLT   R0,[R2,R14]
        STRLT   R0,[R2,R7]              ; copy the next message into the current slot
        ADDLT   R7,R7,#4                ; advance the pointer
        BLT     %BT30                   ; loop back until all checked

        Debug   msgsel,"message removed: new list size =",R6

        SUB     R6,R6,#4
        B       %BT10                   ; and try again until whole list scanned
40
        LDR     R3,[R4,#task_messagessize]  ; old size
        STR     R6,[R4,#task_messagessize]  ; new size
        SUBS    r3,r6,r3                ; jb/ma 4/1/06 check what we did not use
                                        ; and give back any unused

        MOVNE   R0,#ModHandReason_ExtendBlock
        BLNE    XROS_Module              ; attempt to reduce the block size
        STRVC   R2,[R4,#task_messages]  ; and then store updated block pointer

        Debug   msgsel,"after extend block: size of list =",R2,R6

        EXIT


;;-----------------------------------------------------------------------------
;; Remove all messages allocated to this task - flagging as removed.
;;
;; in   R5 = internal task handle
;; out  -
;;-----------------------------------------------------------------------------

removeallmessages Entry "R0,R2,R4-R5"

        Debug   msgsel,"remove all messages for task =",R5

        LDR     R5,[WsPtr,R5]           ; -> task record to be modified

        LDR     R2,[R5,#task_messages]
        CMP     R2,R2,ASR #31           ; is there a list attached
        MOVNE   R0,#ModHandReason_Free
        BLNE   XROS_Module              ; attempt to release it

        MOV     R2,#-1                  ; flag as no list of messages
        STR     R2,[R5,#task_messages]
        MOV     R2,#0
        STR     R2,[R5,#task_messagessize]

        CLRV
        EXIT


;;------------------------------------------------------------------------------
;; Scan to see if a message is active for the specified task.  This routine
;; must scan using the internal task handle specified and see if we can
;; broadcast to it.
;;
;; The routine takes the destination task handle and looks to see if it
;; has a messages list attached, if the pointer to this list is -1 (default)
;; then it is assumed that all messages are passed through (old style task)
;; otherwise it attempts to binary chop the list to find the required
;; message.
;;
;; in   R2 -> message block
;;      R3 -> task block (known to be alive)
;;      R5 = external task handle
;; out  R5 = R5 AND msf_broadcast
;;              IF R5 =0 on entry or message is not supported
;;------------------------------------------------------------------------------

checkformessage

        Entry   "R0-R4"

        [ CnP
        ; check to see if we are sending a Message_DataLoad to a writeable icon
        ; if so, we may need to handle this separately later on for drag/drop purposes
        LDR     R14,[R2,#ms_action + msb_size]
        TEQ     R14,#Message_DataLoad
        BNE     %FT90

        ADRL    R14,clipboard_taskhandle
        LDR     R14,[R14]
        TEQ     R5,R14
        BEQ     %FT90                  ; no need to mess with messages to us

        LDR     R14,[R2,#ms_taskhandle + msb_size]
        TEQ     R5,R14
        BEQ     %FT90                  ; we sent it, so no need to interfere

        LDR     R14,[R2,#msDataTransfer_filetype + msb_size]
        LDR     R4,=FileType_Text
        TEQ     R4,R14
        BNE     %FT90                   ; not a Text file, so ignore

        Push    "handle"
        LDR     handle,[R2,#msDataTransfer_window + msb_size]
        BL      checkhandle
        BVC     %FT10                   ; window handle in the message is valid
        CLRV
        B       %FT89                   ; suppress error if handle not valid and continue message delivery as normal
10
        LDR     R14,[R2,#msDataTransfer_icon + msb_size]
        LDR     R4,[handle,#w_nicons]
        CMP     R14,R4
        BHS     %FT89                    ; icon handle not valid, so abort and continue message delivery as normal

        LDR     R4,[handle,#w_icons]
        ADD     R4,R4,R14,LSL #i_shift
        LDR     R4,[R4,#i_flags]
        AND     R4,R4,#if_buttontype
        TEQ     R4,#ibt_writeable :SHL: ib_buttontype
        TEQNE   R4,#ibt_dwritable :SHL: ib_buttontype
        BNE     %FT89                    ; icon is not writeable, so no need to interfere

        ; we're possibly going to interfere with this message

        ; for now, take a copy of the message and allow it to propagate as normal
        ; if the message is not handled then we'll pick it up later on
        LDR     R0,clipboard_spritearea_addr
        TEQ     R0,#0
        BEQ     %FT89                    ; no valid store for message, so give up

        ; is it the original or a bounce?
        LDR     R14,[R2,#16]             ; gets wimp_poll reason code
        ; if it's a bounce, we block it.  We will take over handling and will fake a bounce if need be.
        TEQ     R14,#User_Message_Acknowledge
        ANDEQ   R5,R5,#msf_broadcast
        Pull    "handle",EQ
        EXIT    EQ

        ADRL    R14,clipboard_pollword
        LDR     R1,[R14]
        BIC     R1,R1,#clipboard_pw_dataload_flag
        STR     R1,[R14]                 ; dataload flag is clear at the moment

        ; copy the message to our store area
        Push    "R2-R3"
        ADD     R2,R2,#msb_size
        LDR     R1,[R2,#ms_size]         ; number of bytes to copy
        ADD     R0,R0,#cnp_message_dataload_park
20
        LDR     R3,[R2],#4
        STR     R3,[R0],#4
        SUBS    R1,R1,#4
        BNE     %BT20
        Pull    "R2-R3"
89
        Pull    "handle"
90
        ]

        LDR     R0,[R3,#task_messages]
        LDR     R1,[R3,#task_messagessize]
        CMP     R0,#nullptr             ; are all messages enabled?
        EXIT    EQ                      ; yes, so send all of them

        Debug   msgsel,"into check for message; block at, task, external =",R2,R3,R5

        LDR     R2,[R2,#ms_action +msb_size]
        TEQ     R2,#Message_Quit        ; message quit is always allowed
        EXIT    EQ                      ; so always return ....

        TEQ     R0,#0                   ; duff list characteristics?
        TEQNE   R1,#0
        ANDEQ   R5,R5,#msf_broadcast
        EXIT    EQ                      ; if so then return flaging as don't broadcast - quit already trapped!

        Debug   msgsel,"list at, size, msg =",R0,R1,R2

        SUB     R1,R1,#4
        MOV     R1,R1,LSR #2            ; R1 = size of list
        MOV     R3,#0                   ; R3 = l = 0

10      CMP     R1,R3                   ; end of list reached?
        ANDLT   R5,R5,#msf_broadcast
        EXIT    LT                      ; yes, so mark as not to be sent and then return

        ADD     R4,R1,R3
        MOV     R4,R4,LSR #1            ; get the mid point

        LDR     R14,[R0,R4,LSL #2]      ; get the message at this location
        CMP     R14,R2
        SUBGT   R1,R4,#1
        ADDLT   R3,R4,#1                ; adjust based on result, if equal then don't bother
        BNE     %BT10                   ; looping whilst not found

        Debug   msgsel,"message found =",R14,R2

        EXIT


        END