; 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. ; ; > Sources.Wimp07 ;;---------------------------------------------------------------------------- ;; Constants used by Wimp_SendMessage ;;---------------------------------------------------------------------------- ^ 0 msb_link # 4 msb_receiver # 4 msb_allsender # 4 ; for R2 on exit from Wimp_Poll msb_handle # 4 ; remember window/icon handle msb_reasoncode # 4 msb_size # 4 ; is also size of header! msb_sender # 4 msb_myref # 4 msb_yourref # 4 ; ms_xxx defined in Hdr.Messages ms_sender * ms_taskhandle ; for convenience! min_messsize * ms_data ; only applies to 17,18,19 max_messsize * 256 msf_broadcast * 1:SHL:31 MSToWimpMagicHandle * &706d6957 ; Reads "Wimp" in *memoryi, is not word aligned and has top bit (msf_broadcast) clear MACRO $lab CheckMsgQ $lab [ NKmessages1 LDR R0,lastpointer SUBS R0,R0,R2 STREQ R0,lastpointer ] MEND ;;---------------------------------------------------------------------------- ;; Return Message to task (called by Wimp_Poll) ;; Entry: R2 --> message to send (same as [headpointer] ;; [headpointer] --> message blocks (linked list) ;; Exit: [taskhandle] set up ;; message block removed from list, if necessary ;; code branches to ExitPoll, unless task dead or code is masked out ;; broadcast messages of type 12: ;; if any task acknowledges it, no more tasks get the broadcast ;; if no tasks acknowledge it, the block is returned to sender ;; - the code seems to have dropped out nicely !!! ;; Note: ;; if a task or window has been subsequently deleted, ;; the message is not delivered (returned if appropriate) ;;---------------------------------------------------------------------------- returnmessage [ debugpk LDR R5,[R2,#msb_receiver] MOV R5,R5,LSL #16 LDR R14,=&16840000 TEQ R14,R5 BNE glurg LDR R14,[R2,#msb_reasoncode] ; if its a message then checking LDR R5,[R2,#msb_allsender] Debug pk,"About to send message to TM ",R14,R5 LDR R14,[R2,#msb_link] CMP R14,#nullptr BEQ glurg LDR R5,[R14,#msb_receiver] LDR R14,[R14,#msb_reasoncode] Debug pk,"Next reason code message is ",R14,R5 LDR R14,[R2,#msb_link] CMP R14,#nullptr BEQ glurg LDR R14,[R14,#msb_link] CMP R14,#nullptr BEQ glurg LDR R14,[R14,#msb_reasoncode] Debug pk,"And the next is is ",R14 glurg ] ; ; set up 'sender', so ExitPoll can return R2 = sender's handle if necessary ; LDR R14,[R2,#msb_allsender] STR R14,sender ; ; page in appropriate task - if doing broadcast, update count ; LDR R5,[R2,#msb_receiver] TST R5,#msf_broadcast ADDNE R14,R5,#4 ; on to next task STRNE R14,[R2,#msb_receiver] LDRNE R0,=maxtaskhandle:OR:msf_broadcast CMPNE R14,R0 BICCS R5,R5,#msf_broadcast ; last one is just 'ordinary' ; ; if the task has died, don't send the message !!! ; TEQ R5,#0 ; if zero, don't send message BEQ %FT01 ; ; Catch messages to Wimp ; LDR R14,=MSToWimpMagicHandle TEQ R5,R14 BEQ autowimp_menu MOV R14,R5,LSL #32-flag_versionbit LDR R3,[wsptr,R14,LSR #32-flag_versionbit] ; R3 --> task data TST R3,#task_unused BNE %FT01 ; give up now! ; LDR R14,[R2,#msb_reasoncode] ; if its a message then checking CMP R14,#User_Message CMPNE R14,#User_Message_Recorded CMPNE R14,#User_Message_Acknowledge BLEQ checkformessage ; LDR R3,[R3,#task_flagword] ; R3 = flag word (if not dead) BIC R14,R5,#msf_broadcast MOVS R14,R14,LSR #flag_versionbit ; if version bits set, TEQNE R14,R3,LSR #flag_versionbit ; ensure they are the same! MOVEQ R14,#1 LDREQ R0,[R2,#msb_reasoncode] TSTEQ R3,R14,LSL R0 ; check whether this code is masked out 01 ANDNE R5,R5,#msf_broadcast ; mark lower bits 0 ==> don't send it! ; ; R5 (bits 0..19) = 0 ==> don't send message ; MOV R14,R5,LSL #32-flag_versionbit MOVS R14,R14,LSR #32-flag_versionbit BEQ postposting ; Task R14,,"Message return" ; page in appropriate task ADD R1,R2,#msb_size ; R1 --> actual message bit BL calcmessagesize ; R3 = size of message block BVS ExitPoll ; Debug ms,"Message: task,rc,R1,size =",#taskhandle,R0,userblk,R3 TEQ R3,#0 BEQ postposting MOV R4,userblk 01 LDR R14,[R1],#4 ; copy into [userblk] STR R14,[R4],#4 SUBS R3,R3,#4 BNE %BT01 ; ; having copied the block out, decide whether to free the heap block ; postposting TST R5,#msf_broadcast ; if broadcast, BNE doneblock ; keep the block ; LDR R0,[R2,#msb_reasoncode] ; (may not have been loaded) TEQ R0,#User_Message_Recorded ; unless recorded, BEQ %FT01 ; delete block ; LDR R14,[R2,#msb_link] STR R14,headpointer ; Debug ms,"Freeing block at:",R2 Push "R0" CheckMsgQ MOV R0,#ModHandReason_Free BL XROS_Module Pull "R0" B doneblock 01 Debug ms,"Marking 'return to sender':",R2 MOV R14,#User_Message_Acknowledge ; mark 'return to sender' STR R14,[R2,#msb_reasoncode] LDR R14,[R2,#msb_sender] ; redirect back to sender STR R14,[R2,#msb_receiver] doneblock BICS R14,R5,#msf_broadcast BNE ExitPoll ; R0, [userblk] set up B repollwimp ; may call returnmessage again ;;---------------------------------------------------------------------------- ;; Send Message ;; Entry: R0 = reason code to generate ;; R1 --> message block ;; R1+0 = size of block ;; R1+4 = handle of sending task (filled in by Wimp) ;; R1+8 = my ref field (filled in by Wimp) ;; R1+12 = your ref field (0 if none) ;; R1+16 = message action ;; R1+20 = message data (format depends on [R1+16] ;; R2 = task / window handle (Wimp can tell them apart) ;; R2 = 0 ==> broadcast ;; R3 = icon handle (if R2 = window handle on entry) ;; Exit: R2 = actual task handle (or 0 if R2=0 on entry) ;; [R1+8] = reference number of message (if R0 was 17 or 18 on entry) ;; if [R1+12] <> 0, then any message with that myref value is killed ;; Errors: no room in RMA for message block ;; illegal task/window handle ;; illegal reason code (R0 on entry to Wimp_SendMessage) ;; illegal message block size (must be <= 256, and be a multiple of 4) ;;---------------------------------------------------------------------------- SWIWimp_SendMessage MyEntry "SendMessage" ; first find out if application is sending a font changed message Push "R0-R1" LDR R0,[R1,#16] LDR R1,=Message_FontChanged CMP R0,R1 Pull "R0-R1" BNE ordinary_message TEQ R0,#User_Message BNE ordinary_message [ outlinefont BL FindFont ; this will broadcast the message if it succeedes ] BLVC BPR_invalidatewholescreen B ExitWimp ordinary_message BL int_sendmessage STR R2,[sp,#1*4] ; return R2 = actual task handle B ExitWimp ; (0 if error has occurred) int_sendmessage_fromwimp Push "LR" LDR R14,taskhandle Push "R14" MOV R14,#0 ; fake it so sender is task 0 STR R14,taskhandle BL int_sendmessage Pull "R14" STR R14,taskhandle Pull "PC" ; NK's optimise ; if there is already a message_slot_size on the message queue ; for this task, then just update it rather than add another. [ NKmessages2 check_mem_message TEQ R0,#User_Message MOVNE PC,LR Push "R7,LR" LDR R7,=Message_SlotSize LDR LR,[R1,#16] TEQ LR,R7 Pull "R7,PC",NE ; check queue Push "R0-R3" LDR R0,headpointer LDR R2,taskhandle CMP R2,#0 LDRGT R14,[wsptr,R2] ; NB task must be alive! LDRGT R14,[R14,#task_flagword] MOVGT R14,R14,LSR #flag_versionbit ORRGT R2,R2,R14,LSL #flag_versionbit CMP R0,#nullptr LDRNE R0,[R0,#msb_link] ; skip first message on stack - it may already have been delivered to some tasks 05 CMP R0,#nullptr BEQ %FT99 LDR R3,[R0,#msb_reasoncode] TEQ R3,#User_Message LDREQ R3,[R0,#msb_sender] TEQEQ R3,R2 ; its the same task, is it the right message? LDREQ R3,[R0,#msb_size+16] TEQEQ R3,R7 LDRNE R0,[R0,#msb_link] BNE %BT05 LDR R2,[R1,#24] ; new next slot LDR R1,[R1,#20] ; new current STR R1,[R0,#msb_size+20] STR R2,[R0,#msb_size+24] Pull "R0-R3,R7,PC" 99 CMP PC,#0 Pull "R0-R3,R7,PC" ] int_sendmessage Push "R3-R7,handle,LR" ; Debuga ms,"*" ; ; validate receiving task / window handle ; [ NKmessages2 BL check_mem_message Pull "R3-R7,handle,PC",EQ ] MOV R6,#msh_wastask ; assume not a window handle first ; CMP R2,#0 ; 0 ==> broadcast to all tasks LDREQ R2,=(:INDEX:taskpointers):OR:msf_broadcast BEQ gottaskhandle ; TST R2,#3 BEQ trytaskhandle ; CMP R2,#nullptr2 ; is this the icon bar? MOVNE R6,R2 ; R6 = window handle BNE %FT01 ; Push "R0,R1" ORR R6,R3,#msh_iconbar ; R6 = window/icon handle MOV R4,R3 ; R4 = icon handle BL findicon ; R7 --> iconbar left/right (ignored) Pull "R0,R1" LDREQ R2,[R2,#icb_taskhandle] MOVNE R2,#0 ; if not found, don't deliver B %FT02 ; else add in version bits 01 MOVS handle,R2 ; if R2<0, treat as system window MOVMI R2,#0 ; 0 => system, -1 => menu BLPL checkhandle ; preserves flags (unless error) Pull "R3-R7,handle,PC",VS ; illegal window handle LDRPL R2,[handle,#w_taskhandle] 02 ; see if this window belongs to the Wimp or the menu owner ; if version 2.18 or later, menu owners can receive messages for menus CMP R2,#0 ; get the Wimp to interpret some actions CMPLE R0,#Close_Window_Request LDRLE R2,=MSToWimpMagicHandle ; Special Wimp window task handle for message system BLE gottaskhandle CMP R2,#0 ; if this is a Wimp window, BGT %FT03 LDRLT R2,menutaskhandle ; see if the menu owner is clever CMPLT R2,#0 MOVLT R2,#0 BLE gottaskhandle ; don't deliver if Wimp window or no menus LDR R14,[wsptr,R2] TST R14,#task_unused MOVNE R14,#0 LDREQ R14,[R14,#task_wimpver] ; does it know about Wimp 2.18? CMP R14,#218 MOVLT R2,#0 BLT gottaskhandle 03 ; convert internal task handle to external form LDR R14,[wsptr,R2] ; add in version bits (if alive) TST R14,#task_unused LDREQ R14,[R14,#task_flagword] MOVEQ R14,R14,LSR #flag_versionbit ORREQ R2,R2,R14,LSL #flag_versionbit B gottaskhandle trytaskhandle BL validtask ; In: R2=task, Out: R5=internal task BVS %FT99 ; don't worry if it's dead yet ; work out sender for all types of message gottaskhandle LDR R4,taskhandle ; set up sender and myref fields CMP R4,#0 LDRGT R14,[wsptr,R4] ; NB task must be alive! LDRGT R14,[R14,#task_flagword] MOVGT R14,R14,LSR #flag_versionbit ORRGT R4,R4,R14,LSL #flag_versionbit STR R4,sender ; used later when block is copied ; ; now check for user message / other reason code ; Debug ms,"SendMessage: R0,R1,R2,R6 (processed) =",R0,R1,R2,R6 TEQ R0,#User_Message TEQNE R0,#User_Message_Recorded TEQNE R0,#User_Message_Acknowledge BNE notusermess ; Push "R3-R7" LDMIA R1,{R3-R7} Debug ms,"UserMessage:",R3,R4,R5,R6,R7 Pull "R3-R7" ; ; delete queued message if referenced by 'yourref' ; (it is being acknowledged) ; LDR R3,[R1,#ms_yourref] ; NB: ms_ not msb_ !!! ADR R4,headpointer-msb_link 01 LDR R5,[R4,#msb_link] CMP R5,#nullptr BEQ doneackmess ; finished LDR R14,[R5,#msb_myref] TEQ R14,R3 ; same id? MOVNE R4,R5 BNE %BT01 [ true LDR R14,[R5,#msb_reasoncode] ; WAGA WAGA WAGA!!!! TEQ R14,#User_Message TEQNE R14,#User_Message_Recorded TEQNE R14,#User_Message_Acknowledge MOVNE R4,R5 BNE %BT01 ] ; Debug ms,"Acknowledged block deleted:",R5 Push "R0-R2" LDR R14,[R5,#msb_link] ; #nullptr in version 1.43 !!! STR R14,[R4,#msb_link] CheckMsgQ MOV R0,#ModHandReason_Free MOV R2,R5 BL XROS_Module Pull "R0-R2" ; ignore errors doneackmess ; ; set up sender and myref fields automatically ; NB: sender taskhandle includes version number bits! ; LDR R14,myref ADDS R14,R14,#1 ; clears V too! ADDEQ R14,R14,#1 ; avoid 0 STR R14,myref ; LDR R3,ROMstart LDR R5,ROMend CMP R1,R3 ; don't splat the ROM! CMPHS R5,R1 LDR R4,sender ; worked out earlier STRLO R4,[R1,#ms_sender] STRLO R14,[R1,#ms_myref] Debug ms,"New sender,my_ref =",R4,R14 ; ; check for User_Message_Acknowledge - if it is, then don't actually send it ; (the message has already done its job) ; TEQ R0,#User_Message_Acknowledge BEQ %FT99 ; return R2 = actual task handle notusermess BL calcmessagesize ; R0,R1 = reasoncode,block; ; ; on exit R3 = size Push "R0-R3" ; reasoncode,block,receiver,size ADDVC R3,R3,#msb_size BLVC claimblock ; R2 --> allocated block ADDVS sp,sp,#4*4 BVS %FT99 ; use lastpointer to determine where we should put the message [ NKmessages1 LDR R4,lastpointer CMP R4,#nullptr ADREQ R4,headpointer-msb_link | ADR R4,headpointer-msb_link 01 LDR R14,[R4,#msb_link] CMP R14,#nullptr MOVNE R4,R14 BNE %BT01 ] STR R2,[R4,#msb_link] ; add to end of list (FIFO) STR R6,[R2,#msb_handle] ; hope this is still intact! [ NKmessages1 STR R2,lastpointer ] Pull "R4-R7" ; ; R4=reasoncode, R5=block, R6=receiver, R7=size ; MOV R0,#nullptr ASSERT msb_link = 0 ASSERT msb_receiver = 4 ASSERT msb_allsender = 8 LDR R14,sender STMIA R2,{R0,R6,R14} ; STR R4,[R2,#msb_reasoncode] ; reason code ADD R2,R2,#msb_size B %FT03 01 LDR R14,[R5,R7] TEQ R4,#User_Message ; can't be User_Message_Acknowledge! TEQNE R4,#User_Message_Recorded BNE %FT02 TEQ R7,#ms_sender LDREQ R14,sender ; in case block was in ROM TEQ R7,#ms_myref LDREQ R14,myref ; ditto 02 STR R14,[R2,R7] 03 SUBS R7,R7,#4 ; now the actual message block BPL %BT01 ; ; message is not actually sent until the next Wimp_Poll ; MOVS R2,R6 ; on exit R2 = actual task handle MOVMI R2,#0 ; if broadcast, don't confuse punter 99 MOVVS R2,#0 ; message not sent if error occurs Pull "R3-R7,handle,PC" LTORG ; Get the Wimp to decide a message directly, if addressed at a system window ; In: R2 -> msb message block ; R5 = MSToWimpMagicHandle ; Out: Goes to postposting (to junk message) ; R2, R5 preserved autowimp_menu LDR R0,[R2,#msb_reasoncode] TEQ R0,#Open_Window_Request BEQ %FT01 TEQ R0,#Close_Window_Request BNE postposting LDR R0,[R2,#msb_size+u_handle] BL int_close_window B postposting 01 Push "R2,R5" ; LDR R1,[R2,#msb_allsender] Debug autoopen,"Open request came from task :",r1 TEQ r1,#0 Pull "R2,R5",NE BNE postposting ; refuse to open if not from WIMP. ; ADD R1,R2,#msb_size MOV userblk,R1 Debug opn,"Openning one of the wimp's windows..." BL int_open_window Debug opn,"Wimp window successfully opened" Pull "R2,R5" B postposting ; ; Entry: R2 = external task handle ; Exit: R5 = internal task handle, V clear (if valid) ; R0 --> "Bad Task handle", V set (if invalid) ; note that the version bits are not validated at this stage ; preserves all but R5 if no error ; validtask Push "R3,LR" ; LDR R5,=:INDEX:taskpointers MOV R3,#maxtasks MOV R14,R2,LSL #32-flag_versionbit 01 TEQ R14,R5,LSL #32-flag_versionbit Pull "R3,PC",EQ ; do this even if task is dead ADD R5,R5,#4 ; (message is ignored later) SUBS R3,R3,#1 BNE %BT01 Debug opn,"**** validtask fails handle",R2 MyXError WimpBadTaskHandle Pull "R3,PC" MakeErrorBlock WimpBadTaskHandle LTORG ; ; Entry: R2 = external task handle ; Exit: R5 = internal task handle, V clear (if valid) ; R6 --> task block (if alive) ; R0 --> "Bad Task handle", V set (if invalid, or dead) ; validtask_alive Push "LR" ; BL validtask Pull "PC",VS ; LDR R6,[wsptr,R5] ; if this is not the same task TST R6,#task_unused LDREQ R14,[R6,#task_flagword] ; (compare version numbers) MOVEQ R14,R14,LSR #flag_versionbit TEQEQ R14, R2,LSR #flag_versionbit [ debug Pull "PC",EQ Debug err,"**** validtask_alive fails handle",R2 ] MyXError WimpBadTaskHandle,NE Pull "PC" ; ; Entry: R0 = reason code ; R1 --> user block ; calcmessagesize Push "LR" ; CMP R0,#max_reason BCS err_badreason ADR R14,mess_sizes LDR R3,[R14,R0,LSL #2] CMP R3,#0 Pull "PC",GE ; < 0 ==> work it out ; TEQ R0,#Menu_Select BEQ go_menuselsize TEQ R0,#User_Message TEQNE R0,#User_Message_Recorded TEQNE R0,#User_Message_Acknowledge BNE err_badreason LDR R3,[R1,#ms_size] TST R3,#3 ; must be a multiple of 4 BNE err_badmesssize CMP R3,#max_messsize RSBLSS R14,R3,#min_messsize ; must include header Pull "PC",LS err_badmesssize MyXError WimpBadMessageSize Pull "PC" mess_sizes DCD 4 * 0 ; null DCD 4 * 1 ; redraw_window DCD 4 * 8 ; open_window (wh,x0,y0,x1,y1,sx,sy,bh) DCD 4 * 1 ; close_window DCD 4 * 1 ; ptr_leaving_window DCD 4 * 1 ; ptr_entering_window DCD 4 * 6 ; mouse_click (mx,my,bt,wh,ih,ob) DCD 4 * 4 ; user_dragbox (x0,y0,x1,y1) DCD 4 * 7 ; key_pressed (wh,ih,x,y,h,i,k) DCD -1 ; menu_select DCD 4 * 10 ; scroll_window (cf. open_window) DCD 4 * 6 ; lose_caret DCD 4 * 6 ; gain_caret DCD 0 ; DCD 0 ; reserved (13..16) DCD 0 ; DCD 0 ; DCD -1 ; user_message DCD -1 ; user_message_recorded DCD -1 ; user_message_acknowledge ASSERT (.-mess_sizes) = max_reason*4 go_menuselsize MOV R3,R1 ; R3 --> start of block 01 LDR R14,[R3],#4 CMP R14,#0 ; stop on -1 BGE %BT01 SUB R3,R3,R1 ; R3 = size of block Pull "PC" err_badreason MyXError WimpBadReasonCode Pull "PC" MakeErrorBlock WimpBadMessageSize MakeErrorBlock WimpBadReasonCode ; ; mark any queued messages relating to windows/icons if window/icon deleted ; Entry: R0 = window/icon handle ; msh_iconbar * 1:SHL:30 msh_wastask * 1:SHL:29 byemessages Push "R1,LR" ; ADR R1,headpointer-msb_link 01 LDR R1,[R1,#msb_link] CMP R1,#nullptr Pull "R1,PC",EQ ; LDR R14,[R1,#msb_handle] TEQ R14,R0 MOVEQ R14,#0 STREQ R14,[R1,#msb_receiver] ; this won't now be delivered B %BT01 ;;---------------------------------------------------------------------------- ;; Start task ;; Entry: R0 --> command (passed to XOS_CLI) ;; Exit: eventually the Wimp will get back to you !!! ;;---------------------------------------------------------------------------- SWIWimp_StartTask MyEntry "StartTask" ; ; you can only start a task if you are a live Wimp task yourself ; LDR R5,taskhandle LDR R6,singletaskhandle TEQ R5,R6 LDRNE R4,[wsptr,R5] ; check that parent is alive TEQNE R4,#task_unused ; note TEQ not TST !!! MyXError WimpCantTask,EQ ; ; save FP registers on Wimp_StartTask if task knows about Wimp 2.23 onwards ; BLVC saveFPregs ; R4 -> task block BVS ExitWimp ; ; save VFP context, lazily if possible ; Push "R0-R1" MOV R0,#0 MOV R1,#VFPSupport_ChangeContext_Lazy+VFPSupport_ChangeContext_AppSpace SWI XVFPSupport_ChangeContext MOVVS R0,#0 ; Ignore error (probably means VFPSupport isn't loaded) STR R0,[R4,#task_vfpcontext] Pull "R0-R1" ; ; find a spare task handle for the new task ; ADRL R5,taskpointers MOV R6,#maxtasks 01 LDR R14,[R5],#4 TST R14,#task_unused BNE %FT02 SUBS R6,R6,#1 BNE %BT01 ; MyXError WimpNoTasks B ExitWimp 02 SUB R5,R5,#4 ; R5 --> task data pointer entry ; ; now stash the parent task on the return stack, and start up the new one ; ADRL R1,taskbuffer 01 LDRB R14,[R0],#1 STRB R14,[R1],#1 CMP R14,#32 ; terminate on any ctrl-char BCS %BT01 ; BL mapslotout ; map parent out of the way ; LDR R14,taskSP LDR handle,polltaskhandle STR handle,[R14],#4 ; empty ascending stack STR R14,taskSP SUB R14,R5,wsptr STR R14,taskhandle ; ; we must mark the task used, so that ExitPoll can swap into it ; Version number = 0 => task is not initialised ; MOV R0,#0 ; latest known Wimp version BL markinitialised ; changes task 'version number' BVS ExitWimp ; LDR R14,taskhandle ; assume single-tasking for now STR R14,singletaskhandle ; MOV R14,#0 ; reset all handlers STR R14,handlerword STR R14,parentquithandler ; must start application !!! BL setdefaulthandlers ; ; allocate memory for the new task, then use callback to start it up ; [taskbuffer..] contains the *command to execute ; ADRL R14,Module_BaseAddr BL allocateslot ; updates memorylimit ; ADRL R0,taskbuffer ; copy of *command is in here LDR R5,taskhandle LDR R5,[wsptr,R5] ADRL R14,runthetask ; PC must be set up explicitly STR R14,[R5,#task_registers+4*15] ; note PC has no flags, ie USR on 26-bit ; this next bit is harmless on a 26-bit system, as the 17th word is ignored MRS R14,CPSR BIC R14,R14,#2_11101111 ; get USR26/USR32, ARM, FIQs+IRQs on STR R14,[R5,#task_registers+4*16] ; ; to be on the safe side, bring up a text window if any chars printed ; Push "R0" ; this allows escape etc. SWI XWimp_CommandWindow ; in case this is a wally task Pull "R0" ; Remember *command ptr CLRV B ExitPoll_tochild ; swap tasks, and end up at 'runthetask' MakeErrorBlock WimpCantTask MakeErrorBlock WimpNoTasks ; ; Entry point where we run the task! ; Entry: R0 --> command to execute ; entered in USR mode (I hope!) ; runthetask MOV R1,R0 ; close down the task !!! SWI Wimp_CloseDown MOV R0,R1 SWI OS_CLI ; R0 --> OS_CLI command SWI OS_Exit ; exit back to Wimp ; ; set up default environment handlers (Wimp should replace them all) ; only reset the ones corresponding to 0 bits in [handlerword] ; 0 in table ==> leave alone (MemoryLimit,ApplicationSpaceSize) ; 1 in table ==> use default handler ; >1 in table ==> use values in table ; setdefaulthandlers Push "R1-R6,LR" ; ADR R4,defaulthandlers ; R4 --> data LDR R5,handlerword ; R5 = flag word (0 bit ==> set it) MOV R6,#MaxEnvNumber 01 LDR R1,[R4],#4 ; if zero, it's not an address offset TEQ R1,#0 RSBEQ R0,R6,#MaxEnvNumber ; R1=0 ==> use default handler SWIEQ XOS_ReadDefaultHandler ; NB: R0 can be set to 0 by this call! Pull "R1-R6,PC",VS ADDNE R1,R1,R4 ; R1 --> code address MOVNE R2,wsptr ADRNE R3,errorbuffer 02 MOVS R5,R5,LSR #1 ; has this handler been set already? RSBCC R0,R6,#MaxEnvNumber SWICC XOS_ChangeEnvironment SUBS R6,R6,#1 BNE %BT01 ; Pull "R1-R6,PC" ; ; Default settings to pass to SWI XOS_ChangeEnvironment ; R1 --> code address / buffer pointer ; R2 = returned in R12 (if R1 is an address) - maybe ; R3 --> block (if R1 is an address) ; defaulthandlers DCD 0 ; MemoryLimit DCD 0 ; UndefinedHandler DCD 0 ; PrefetchAbortHandler DCD 0 ; DataAbortHandler DCD 0 ; AddressExceptionHandler DCD 0 ; OtherExceptionHandler DCD Do_ErrorHandler-.-4 DCD 0 ; CallBackHandler DCD 0 ; BreakPointHandler DCD 0 ; EscapeHandler DCD 0 ; EventHandler DCD Do_ExitHandler-.-4 DCD 0 ; UnusedSWIHandler DCD 0 ; ExceptionDumpArea DCD 0 ; ApplicationSpaceSize DCD Module_BaseAddr-.-4 ; CAO pointer DCD 0 ; upcall handler ASSERT (.-defaulthandlers)/4 = MaxEnvNumber ; ; report error contained in errorhandlerbuffer ; in USR mode here! ; Do_ErrorHandler MOV R12,R0 ; wsptr is in R0! [ debugtask1 ADRL R13,stackspace Debuga task1,"Error reported to Wimp: " CLI "HostVdu" ADRL R0,errorbuffer+8 ; skip saved PC & error number SWI XOS_Write0 SWI XOS_NewLine CLI "TubeVdu" ] ADRL R0,errorbuffer+4 ; skip saved PC MOV R1,#erf_cancelbox:OR:erf_htcancel:OR:erf_dontwait MOV R2,#nullptr ; no application SWI XWimp_ReportError SWI XOS_Exit ; must abort task (no error handler) ; ; delete task and exit back to the Wimp ; NB we must be in USR mode !!! ; NB Wimp_CloseDown causes the command window to be closed too ; Do_ExitHandler [ debugtask1 ADRL R13,stackspace ; need some stack to call debug! ] SWI XWimp_CloseDown ; delete task (may restore handler) 01 MOV R0, #198 ; read EXEC file handle MOV R1, #0 MOV R2, #&FF SWI XOS_Byte TEQ R1, #0 ; was an EXEC file open? BEQ %FT02 MOV R0,#OSArgs_EOFCheck ; if end of file, ignore it! SWI XOS_Args TEQ R2,#0 BNE %FT02 ADR r0, CliDPrompt ADR r1, errorbuffer MOV r2, #?errorbuffer MOV r3, #0 MOV r4, #3 SWI XOS_ReadVarVal MOVVC r0,r1 MOVVC r1,r2 ADRVS r0, DefaultPrompt MOVVS r1, #1 SWI OS_WriteN ADR R0,errorbuffer MOV R1,#?errorbuffer MOV R2,#32 MOV R3,#&FF SWI OS_ReadLine ; provoke errors (handler is there) SWICC OS_CLI ; should preserve flags BCC %BT01 MOV R0,#126 ; acknowledge escape SWI OS_Byte ADR R0,ErrorBlock_Escape MOV R1,#0 MOV R2,#0 ; global error SWI MessageTrans_ErrorLookup SWI OS_GenerateError ; generate escape error MakeErrorBlock Escape 02 Debug task1,"Exitting back to Wimp" ADR R1,errorbuffer ; ensure R1 > &8000 !!! SWI XWimp_Poll ; if task returns, it must be the last Debug task1,"Poll returns - Exitting from Wimp" SWI OS_Exit CliDPrompt = "CLI$Prompt", 0 [ debug ALIGN ] DefaultPrompt = "*" ALIGN ;;----------------------------------------------------------------------------- ;; Exit point for task-switching ;;----------------------------------------------------------------------------- ; Report any errors during Wimp_Poll internally, unless single-tasking reporterror LDR R5,taskhandle LDR R6,singletaskhandle TEQ R5,R6 BEQ returnerror ; can return errors to single task MOV R1,#erf_okbox ADR R2,wimp SWI XWimp_ReportError B repollwimp wimp DCB "Wimp",0 ALIGN ExitPoll_tochild Debug task1,"Exit to child:",#taskhandle MOV R14,#-2 STR R14,sender ; don't call postfilters B ExitPoll ExitPoll_toparent Debug task1,"Exit to parent:",#taskhandle MOV R14,#-1 STR R14,sender ; don't return R2 from Wimp_StartTask ExitPoll Debug poll2, "ExitPoll" BVS reporterror ; don't return to caller returnerror ; The Wimp MUST NOT exit to a dead task (no register data !!!) ; Wimp_Poll tries to find a live task on entry - it calls OS_Exit if none left LDR handle,taskhandle ; LDR R14,ptr_DomainId STR handle,[R14] ; for Stuart Debug task,"Exit Poll: (old),task,reason =",#polltaskhandle,handle,R0 TEQ R0,#No_Reason ; Not a null event? [ Stork [ PokeBorder Push "R0-R1",NE LDRNE R1, =&40FFFF00 ; cyan = fast MOVNE R0, #VIDC STRNE R1, [R0] Pull "R0-R1",NE ] LDRNE R14, WimpPortableFlags BICNE R14, R14, #PowerSave STRNE R14, WimpPortableFlags ; (so go at full speed) TSTNE R14, #PortableFeature_Speed ; And speed switching works? | LDRNE R14,WimpPortableFlag TEQNE R14,#0 ; And the portable module present? ] BEQ %FT01 Push "R0-R1" MOV R0,#0 MOV R1,#0 SWI XPortable_Speed ; if not a null event then make it go fast Pull "R0-R1" 01 [ debugtask3 LDR R14,singletaskhandle CMP R14,#nullptr ; if single-tasking, CMPNE R14,handle ; we mustn't exit to anyone else!!! BEQ %FT01 Debug task3,"Task swap: single,taskhandle =",R14,handle 01 ] Push "R0-R1" LDR R4,[wsptr,handle] TEQ R4,#task_unused [ debugtask4 ; Stamp with event time for task priority and swapping SWINE XOS_ReadMonotonicTime BEQ %FT00 Debug task4,"Time",R0 00 STRNE R0,[R4,#task_eventtime] ] ; restore FP registers if they were saved (ie. save block present) LDRNE R0,[R4,#task_fpblock] TEQNE R0,#0 ; NE => restore registers MOVEQ R5,#C_runtime_status ; ensure caller gets &70000 if he didn't save regs WFSEQ R5 BEQ %FT01 Debug fp,"Restoring FP state from block at",R0 MOV R5,#0 ; avoid FP exceptions WFS R5 ; will still occur if FPEmulator RMKilled [ FPE4 [ false LFM F0,4,[R0,#fp_reg0] ; (only gets here if active previously) LFM F4,4,[R0,#fp_reg4] | ; AAsm assembles the above as post-indexed not pre-indexed. ; Do it manually (bluch). DCD &ED900200 :OR: (fp_reg0:SHR:2) DCD &ED904200 :OR: (fp_reg4:SHR:2) ] | LDFE F0,[R0,#fp_reg0] ; (only gets here if active previously) LDFE F1,[R0,#fp_reg1] LDFE F2,[R0,#fp_reg2] LDFE F3,[R0,#fp_reg3] LDFE F4,[R0,#fp_reg4] LDFE F5,[R0,#fp_reg5] LDFE F6,[R0,#fp_reg6] LDFE F7,[R0,#fp_reg7] ] LDR R5,[R0,#fp_status] WFS R5 01 ; restore VFP context TEQ R4,#task_unused LDRNE R0,[R4,#task_vfpcontext] MOVNE R1,#VFPSupport_ChangeContext_Lazy TEQNE R0,#0 ; We should already be on the null context, so only call if user does have a context to restore SWINE XVFPSupport_ChangeContext Pull "R0-R1" ; [ StartTaskPostFilter LDR R14,sender CMP R14,#-1 BLT %FT01 ; Are we starting up Wimp_StartTask? BNE %FT02 ; Are we returning from Wimp_StartTask? ; We're returning from Wimp_StartTask and ; R0 = task handle of child (or 0). Wimps before 3.96 ; would not call the post-filter in this case, but would ; call it if Wimp_StartTask returned 0 (so the filter ; would think a null event was happening.) Now, the ; Toolbox (and probably other filters) relies on the ; post filter to monitor the current task. If the postfilter ; doesn't get called here then there is no way of telling ; that this task has become active. So, we now call the filter ; with a null event, and ignore any attempt to claim it. (In ; the past the filter was able to claim the "null" event if ; Wimp_StartTask returned 0, causing instant death. ; This is the problem that hit Toolbox 1.33). ; ; Hopefully this shouldn't cause any problems, as filters ; will have had to be able to deal with the dummy "null" ; event for at least some Wimp_StartTask calls already. Push "R0,R1" MOV R0,#No_Reason MOV R1,userblk CallFilter postfilter ; call the post-poll filter (ignoring Pull "R0,R1" ; R0 return) B %FT01 02 | CMP R0,#max_reason ; Valid message? BHS %FT01 ; No then jump,maybe -> *command from Wimp_StartTask ] Push "R1" MOV R1,userblk CallFilter postfilter ; call the post-poll filter Pull "R1" CMP R0,#-1 BEQ repollwimp ; if it claimed then just re-poll 01 [ AutoHourglass Push "R0-R2" LDR R1, hourglass_status [ debugautohg Push "handle" LDR handle, taskhandle Debug autohg, "Hourglass_On at task switch: taskhandle, old status =", handle, R1 Pull "handle" ] TEQ R1, #2 SWIEQ XHourglass_Off ; if autohourglass is still pending or animating, turn it off TEQ R1, #0 MOVEQ R0, #WrchV ; get back on WrchV if necessary ADREQ R1, deactivate_hourglass_on_wrchv BLEQ claim MOV R0, #hourglass_delay SWI XHourglass_Start ; turn on using special delay time CLRV ; ignore errors MOV R1, #2 STR R1, hourglass_status ; mark autohourglass fully active Pull "R0-R2" ] BL DeletePollTask ; Delete task from polltask list ; don't need to do callback if this is the same task LDR R14,polltaskhandle ; see if this is the same task TEQ handle,R14 ; NB doesn't affect V flag!!! BEQ putsender_ExitWimp ; exit, and set up R2 if required ; ; ensure that R0 and the flags are passed back to the correct task ; bodge: if same task, also keep R0 and flags now ; [ No32bitCode Push "R0,PC" ; save R0 and flags SETPSR I_bit, R5 ; disable interrupts | MRS R5,CPSR Push "R0,R5" ORR R5,R5,#I32_bit MSR CPSR_c,R5 ] ; ; NB preserve R14 in this code LDR R5,[wsptr,handle] STR R0,[R5,#task_registers+4*0] [ No32bitCode LDR R0,[R5,#task_registers+4*15] | TEQ PC,PC ; 32-bit system? LDRNE R0,[R5,#task_registers+4*15] ; 26-bit: modify R15 LDREQ R0,[R5,#task_registers+4*16] ; 32-bit: modify CPSR ] BICVC R0,R0,#V_bit ; set up correct V bit ORRVS R0,R0,#V_bit [ No32bitCode STR R0,[R5,#task_registers+4*15] ; save for new task | STRNE R0,[R5,#task_registers+4*15] STREQ R0,[R5,#task_registers+4*16] ] ; ; set up callback handler ; NOTE: since the task is already paged in, its handlers are set up already ; XXXX: it appears that the handlers are not always in the block yet! ; Debug task1,"Setting callback handler" ; MOV R0,#CallBackHandler ; be careful when old task is dead ADR R1,callbackpoll MOV R2,wsptr LDR R3,[wsptr,R14] ; save old task registers TST R3,#task_unused ADDEQ R3,R3,#task_registers ; be careful of dead tasks! ADRNEL R3,registerbuffer ; use temporary buffer (regs ignored) SWI XOS_ChangeEnvironment ADR R14,oldcallback STMIA R14,{R1-R3} ; will be restored later ; ; Exit temporarily - comes back to callback handler ; NB -- SWI XWimp_Poll must be used, since I don't know about bit 17 ; SWI XOS_SetCallBack ; set call back flag ; Pull "R0,R14" [ No32bitCode TEQP R14,#0 ; restore flags, ready for exit | MSR CPSR_cf,R14 ; restore flags+ints, ready for exit ] ; B ExitWimp_noswitch ; pulls registers & exits to callback ;.............................................................................. ; here R12 --> workspace (set up by ChangeEnvironment) ; ; Should enter this code in SVC mode with Ints off ; restore environment for new task callbackpoll [ debugtask Push "R0,LR" ; [ No32bitCode Push "PC" Pull "R0" AND R0,R0,#ARM_CC_Mask | MRS R0, CPSR ] Debug task,"Flags on entry to callbackpoll:",R0 ; Pull "R0,LR" ] ; LDR R14,taskhandle LDR R4,[wsptr,R14] ; NB task cannot be dead BL getsender_R2 ; if [R4,#task_wimpver] >= 253 STRGE R2,[R4,#task_registers+2*4] ; return R2 = sender's handle ADR R0,oldcallback LDMIA R0,{R1-R3} MOV R0,#CallBackHandler SWI XOS_ChangeEnvironment ; restore client's handler! ; ; exit to caller ; TEQ PC,PC ; are we 26 or 32-bit? ADD lr_svc,R4,#task_registers ; lr_svc --> register block LDREQ R0,[lr_svc,#16*4] MSREQ SPSR_cxsf,R0 LDMIA lr_svc,{R0-R14}^ ; restore USR regs NOP LDR lr_svc,[lr_svc,#15*4] MOVS PC,lr_svc ; exit to caller, restoring flags ;.............................................................................. ; WrchV routine to deactivate the autohourglass as soon as a character is output. ; The argument for this is that if the task is plotting something, you probably ; don't need the Wimp putting up an hourglass to let you know that the machine ; hasn't stiffed. ; Using this approach, the hourglass isn't shown, for example, while Paint is ; doing a screen grab (it doesn't Wimp_Poll, but it does plot a box on the screen). ; It also copes transparently with command windows, ShellCLI etc. ; On entry: R12 -> workspace ; [hourglass_status] = 1 or 2 (by definition) ; processor is in SVC mode [ AutoHourglass deactivate_hourglass_on_wrchv Entry "R0-R2" LDR R1, hourglass_status Debug autohg, "Hourglass_Off at WrchV, old status =", R1 TEQ R1, #2 SWIEQ XHourglass_Off ; turn off hourglass if necessary MOV R0, #WrchV ADR R1, deactivate_hourglass_on_wrchv BL release ; release WrchV MOV R1, #0 STR R1, hourglass_status ; mark fully deactivated EXITS ; pass on call (NB: nowhere to return errors to) ] ;............................................................................. ; In R4 -> task block of current task ; Out FP registers saved if FPEmulator present and task knows Wimp 2.23 saveFPregs EntryS "R0-R3" Debug fp,"Saving FP state for task",#taskhandle Debuga fp,"Reading FP status: " RFS R1 ; <==== NB: pending trap can occur here ; so do it before claiming block! Debug fp," value =",R1 LDR R2,[R4,#task_fpblock] ; block may already be claimed CMP R2,#0 ; (assume will be required again) MOVEQ R3,#fp_size BLEQ claimblock ; R2 -> block address STRVS R0,[sp,#Proc_RegOffset] EXIT VS STR R2,[R4,#task_fpblock] Debug fp,"FP save block at",R2 STR R1,[R2,#fp_status] LDR R1,=C_runtime_status ; now C run-time status value WFS R1 [ FPE4 [ false SFM F0,4,[R2,#fp_reg0] SFM F4,4,[R2,#fp_reg4] | ; AAsm assembles the above as post-indexed not pre-indexed. ; Do it manually (bluch). DCD &ED820200 :OR: (fp_reg0:SHR:2) DCD &ED824200 :OR: (fp_reg4:SHR:2) ] | STFE F0,[R2,#fp_reg0] STFE F1,[R2,#fp_reg1] STFE F2,[R2,#fp_reg2] STFE F3,[R2,#fp_reg3] STFE F4,[R2,#fp_reg4] STFE F5,[R2,#fp_reg5] STFE F6,[R2,#fp_reg6] STFE F7,[R2,#fp_reg7] ] ; EXITS ; preserve flags ;............................................................................. ; In handle = task handle of current task (must be alive) ; R12 -> module workspace ; [sp..] = stacked R1.. ; Out exits to Wimp with or without R2 set up (as appropriate) putsender_ExitWimp SavePSR R3 ; save flags LDR R4,[wsptr,handle] BL getsender_R2 ; GE => R2 = task handle of sender STRGE R2,[sp,#4] ; R2 = second word on stack RestPSR R3,,f ; restore error state B ExitWimp ;............................................................................. ; In R4 -> task block for task about to receive an event ; R12 -> module workspace ; Out GE => R2 = task handle of task that sent it (0 => Wimp) getsender_R2 LDR R2,[R4,#task_wimpver] ; latest known Wimp version number Debug ms,"getsender_R2: handle, wimpver, sender =",#taskhandle,R4,R2,#sender CMP R2,#253 LDRGE R2,sender ; GE => R2 = sender's task handle CMPGE R2,#0 ; -1/-2 => this is a Wimp_StartTask MOV PC,LR ;;---------------------------------------------------------------------------- ;; Error reporting SWI ;;---------------------------------------------------------------------------- ; ; Entry: R1 --> icon definition ; R2 = coords to centre on (horizontally) ; Exit: x0,x1 = left,right of icon ; icon definition updated ; setbuttonx LDR x0,[R1,#i_bbx0] LDR x1,[R1,#i_bbx1] SUB x1,x1,x0 SUB x0,R2,x1,ASR #1 ADD x1,x0,x1 STR x0,[R1,#i_bbx0] STR x1,[R1,#i_bbx1] MOV PC,LR ; must preserve flags ; ; Entry: R0 --> error block ; R1 = flags ; bit 0 ==> OK box displayed ; bit 1 ==> Cancel box displayed ; bit 2 ==> highlight Cancel box (else highlight OK box) ; bit 3 ==> dont wait for confirmation (if text-based) ; bit 4 ==> omit 'Error from ' in title bar ; bit 5 ==> 'poll' error window (ie. leave open & exit) ; bit 6 ==> finish polling error window, select [r1] and close it ; bit 7 ==> don't beep (even if WimpFlags bit 4 clear) ; bit 8 ==> new type error report ; bits 9-11 ==> error type ; ; R2 --> application name (<=0 ==> Wimp has detected the error) ; R3 --> sprite name (for new type error report) ; R4 --> sprite area, or 1 for Wimp area (for new type error report) ; R5 --> comma separated additional button list, or 0 for none (for new type error report) ; ; Exit: R1 = 1 ==> Continue (OK) box was selected ; R1 = 2 ==> Cancel box was selected ; R1 = 3,4... ==> additional button pressed ; ;Rough outline (not gospel!) JRC 24 Jul 1997 ; Make service call ErrorStarting ; IF in command mode ; THEN report error in text ; poll for a key press ; return key pressed (Return/Escape) ; ELSE IF closing an open error box ; THEN return button-click specified ; ELSE Create a window structure ; Make service call WimpReportError 1 ; Switch output to screen ; Disable file redirection ; Enable VDU, disable Spool, printer & serial ; Beep ; Add the icon definitions to the window structure ; int_open_window ; int_redraw_window ; int_get_rectangle ; Smash hourglass ; Bound pointer to window ; Flush keyboard and mouse ; Start IconHigh ; DO Read key with no time limit ; Check mousebuttons ; WHILE nothing happens ; Unbound pointer ; int_close_window ; Stop IconHigh ; Make service call ErrorButtonPressed ; Make service call ErrorEnding ; Restore file redirection ; Restore output to previous state ; Make service call WimpReportError ; FI ; FI errorprefix DCB "NoError",0 errorprefix1 DCB "Error",0 errorprefix2 DCB "ErrorF",0 execcom DCB "Exec",0 ALIGN ; tempworkspace layout ^ 0 errtws_spritearea # 4 ; +0 as passed in R4 / set by service call claimant(s) errtws_buttonlist # 4 ; +4 pointer to comma-separated list of buttons errtws_iconend # 4 ; +8 icon handle of (rightmost == first-in-string == highest-icon-handle) extra button, + 1 errtws_describebuttons # 4 ; +12 comma-separated list of buttons to use when program error is Described errtws_icondata # 4 ; +16 if a "may have gone wrong" window, -> start of icon data for error window, else 0 errtws_cancelstr # 4 ; +20 -> "Cancel" errtws_flags # 4 ; +24 errtws_mustntuse # 4 ; +28 corrupted by text plotting code SWIWimp_ReportError MyEntry "ReportError" ; [ ErrorServiceCall Push "R0-R5" Pull "R2-R7" LDR R1,=Service_ErrorStarting SWI XOS_ServiceCall Push "R2-R7" Pull "R0-R5" MOV userblk,R1 ] Push "R0-R3" ; [ NewErrorSystem STR R4,tempworkspace+errtws_spritearea ; R4 gets horribly corrupted ; but is required for 3.21 STR R5,tempworkspace+errtws_buttonlist ; ditto! ] LDR R4,commandflag ORR R14,R4,#cf_suspended STR R14,commandflag ; suspend this whatever TEQ R14,#cf_active:OR:cf_suspended BNE useerrorwindow noerrorwindow ; come back here if error window dead TST R1,#erf_dontwait ADREQ R0,execcom ; cancel exec file (if any) SWIEQ XOS_CLI ; Pull "R0-R3" ; ; report error as a line of text ; TST R1,#erf_pollexit ; finish - cancel suspended state ANDNE R1,R1,#erf_okbox:OR:erf_cancelbox BNE ExitError ; TST R4,#cf_suspended ; if suspended and poll bit set, TSTNE R1,#erf_poll BNE %FT11 ; don't re-print the error message ; SWI XOS_WriteI+4 ; just in case SWI XOS_NewLine ; textual form of error report ADD R0,R0,#4 SWI XOS_Write0 SWI XOS_NewLine ; TST R1,#erf_dontwait ; R1 preserved if bit 3 was set BNE ExitError ; TST R1,#erf_poll ; unless polling, BNE %FT51 Push "R2,R3" ; ADRL R0,pressspace ADRL R2,errorbuffer MOV R3,#?errorbuffer BL LookupToken1 ; resolve the press-space to continue token ; ADRL R0,errorbuffer SWI XOS_Write0 ; display it SWI XOS_NewLine ; followed by a new line ; Pull "R2,R3" 51 BL flushkbdmouse ; only done the first time 11 BL pollforkey BNE %FT12 LDR R1,[sp,#0*4] TST R1,#erf_poll ; if no result, loop unless erf_poll BEQ %BT11 ; MOV R1,#0 ; leave command window suspended B ExitError2 ; return 'no result' 12 TEQ R1,#&1B ; escape key ==> non-default Debug err,"ReportError: key=",R1 MOVNE R1,#erf_okbox MOVEQ R1,#erf_cancelbox LDR R14,[sp,#0*4] TST R14,#erf_htcancel EORNE R1,R1,#erf_okbox:EOR:erf_cancelbox ANDS R14,R14,#erf_okbox:OR:erf_cancelbox MOVEQS R14,#erf_okbox ; if flags =0 it has an OK box ANDS R1,R1,R14 ; can't select button that wasn't there TSTEQ R14,#erf_poll BEQ %BT11 ; try again if 0 not allowed! Debug err,"ReportError: return",R1 ExitError LDR R14,commandflag BIC R14,R14,#cf_suspended STR R14,commandflag ExitError2 STR R1,[sp,#0*4] B ExitWimp ; ; report error in a window ; useerrorwindow LDR R8,errorhandle ; R8 = relative error window handle CMP R8,#nullptr BEQ noerrorwindow ; oops! ; ADRL R0,execcom ; always cancel exec file (if any) SWI XOS_CLI ; Abs handle,R8 ; handle --> window definition ; TST R1,#erf_pollexit BEQ %FT01 ADD sp,sp,#4*4 ; skip junk on stack TST R4,#cf_suspended ; is error window open? BEQ ExitError ; forget it if not (unsuspend window) MOV R4,#1 ; highlight either icon 1 or 4 TST R1,#erf_okbox ; ('OK' preferably) MOVEQ R4,#4 B finisherror ; make selection and close error window 01 TST R4,#cf_suspended ; if suspended and poll bit set, TSTNE R1,#erf_poll Pull "R4-R7" ; R4-R7 = original R0-R3 BLEQ starterrorbox MOV R0, #229 ; Read current escape condition enable state so we can restore it later MOV R1, #0 MOV R2, #255 SWI XOS_Byte STRB r1, old_escape MOV R0, #229 ; Disable escape conditions (Wimp hasn't actually checked for them for a long time) MOV R1, #1 MOV R2, #0 SWI XOS_Byte ; ; bodge polling loop - look for mouse click in OK / Cancel boxes ; - also <escape> (27, or escape condition) ; pollit MOV R0,#&81 ; read key with 0 time limit MOV R1,#0 MOV R2,#0 SWI XOS_Byte ; CS => escape, else R1 = &FF => no char TEQ R2,#&FF BEQ %FT02 ; no key pressed ; Debug err,"ReportError: pollit key=",R1 TEQ R1,#&0D TEQNE R1,#&1B ; old allow <CR> and <Esc> BNE %FT02 ; LDR R14, tempworkspace+errtws_flags ; to work out which button the key corresponds to, we need the current flags ; note 1: these flags will be correct for "may have gone wrong" boxes Debug err,"Error flags=",R14 ; note 2: these flags have not been checked to ensure there is at least an OK button MOV R4, #-1 ; Return button not yet determined MOV R5, #-1 ; Escape button not yet determined MVN R14, R14 ; makes life easier when doing comparisons TST R14, #erf_okbox ; CMPEQ R4, #-1 ; have we found both buttons yet? ; MOVEQ R4, R5 ; Return -> previous Escape button MOVEQ R5, #1 ; Escape -> OK button TST R14, #erf_cancelbox ; CMPEQ R4, #-1 ; have we found both buttons yet? MOVEQ R4, R5 ; Return -> previous Escape button MOVEQ R5, #4 ; Escape -> Cancel button ; note, the Describe button is never selected by a keypress TST R14, #erf_newtype BNE %FT06 LDR R2, tempworkspace+errtws_buttonlist AcceptLoosePointer_NegOrZero R2,0 CMP R2,R2,ASR #31 BEQ %FT06 ; if no extra buttons, skip next section LDR R2, tempworkspace+errtws_iconend CMP R2, #8 ; are there at least 1 extra buttons? CMPHS R4, #-1 ; have we found both buttons yet? MOVEQ R4, R5 ; Return -> previous Escape button SUBEQ R5, R2, #1 ; Escape -> highest-numbered (rightmost) extra button CMP R2, #9 ; are there at least 2 extra buttons? CMPHS R4, #-1 ; have we found both buttons yet? MOVEQ R4, R5 ; Return -> previous Escape button SUBEQ R5, R2, #2 ; Escape -> second highest-numbered (second rightmost) extra button 06 TST R14, #erf_okbox :OR: erf_cancelbox :OR: erf_htcancel EOREQ R4, R4, R5 ; if all three flags were set, the meanings of Return and Escape are reversed EOREQ R5, R4, R5 EOREQ R4, R4, R5 CMP R5, #-1 ; if no Escape button has been found, an OK/Continue button will have been added MOVEQ R5, #1 CMP R4, #-1 ; if no Return button has been found, there is only one button, so act as for Escape TEQNE R1, #&1B ; was Escape pressed? MOVEQ R4, R5 ; R4 now holds selected icon number Debug err,"Icon=",R4 ; B finisherror 02 LDR R5,mousebuttons BL getmouseposn ; R0,R1 = mouse coords, R2 = buttons Push "R5" MOV R5,#0 ; don't match shaded icons (not that there are any) BL int_get_pointer_info ; R3,R4 = window/icon handle Pull "R5" ;Debug upcall, "int_get_pointer_info: w, i, oldbuttons, newbuttons:", R3, R4, R5, R2 LDR R14,errorhandle TEQ R3,R14 ; must be error window! BNE notover [ NewErrorSystem SUB R14, R4, #6 ; Describe button is handle 6, additional buttons are 7 to 6+maxno_error_buttons CMP R14, #maxno_error_buttons CMPLS R14, R14 ; set Z if in range ] TEQNE R4,#1 ; icon 1 = 'OK' box TEQNE R4,#4 ; icon 4 = 'Cancel' box BNE notover [ false EOR R14,R2,R5 ; AR 13/8/97 look at both transitions, fixed a problem of double clicks | BIC R14,R2,R5 ; look for +ve edge SELECT/ADJUST ] BICS R14,R14,#button_middle ; (ignore menu button) BNE finisherror notover LDR R14,[sp,#0*4] ; should we retry? TST R14,#erf_poll BEQ pollit MOV R1,#0 ; return 0 and go back to poller B ExitError2 ; stores R1 in top stack entry finisherror Push "R4" ; R4 = 1 or 4 (icon to select) ; Debug upcall, "finishing error ", r4 MOV R0,R4 ; R0 = icon handle MOV R1,#is_inverted ; R1 = EOR word MOV R2,#is_inverted ; R2 = BIC word BL int_set_icon_state ; handle --> window definition BL clearpointerwindow [ NCErrorBox Push "r0-r2" MOV R0, #0 ; Unconditionally turn off IconHigh SWI XIconHigh_Stop ; SJM 25Mar99 Do not restore the pointer shape here ; anymore now that we have Wimp_Extend support Pull "r0-r2" ] ; ADR userblk,errorhandle ; userblk --> window handle BL int_close_window [ ChildWindows BL int_flush_opens ; this is necessary to avoid block-copying if the error box ] ; is subsequently displayed at a different size ; Pull "R1" TEQ R1,#4 ; 1 ==> OK box selected MOVEQ R1,#2 ; 2 ==> Cancel box selected [ NewErrorSystem CMP R1,#6 BEQ notoveryet SUBHI R1,R1,#2 LDRHI R2,tempworkspace+errtws_iconend SUBHI R1,R2,R1 ; extra icons 7-10 return 6-3 ] [ ErrorServiceCall BL InstallErrorButtonPressedHandlers MOV R2,R1 MOV R0,#0 LDR R1,=Service_ErrorButtonPressed LDR R3,tempworkspace+errtws_buttonlist SWI XOS_ServiceCall BL RemoveErrorButtonPressedHandlers CMP R0,#0 BEQ servicecallend ; module wants error dialog redisplayed redisplayerrorbox LDMIA R2!,{R4-R7} LDMIA R2,{R1-R2} ADR R3,tempworkspace+errtws_spritearea ; also updates errtws_buttonlist STMIA R3,{R1-R2} MOV userblk,R5 Push "PC" ; routine returns with Pull "PC" B starterrorbox_draw ; This actually Pushes PC+12 on the stack NOP B pollit servicecallend LDR R1,=Service_ErrorEnding SWI XOS_ServiceCall MOV R1,R2 ] Debug upcall,"ReportError returns R1",R1 STR R1,[sp,#0*4] [ NewErrorSystem ; now replace Quit with Cancel if necessary LDR R1,tempworkspace+errtws_icondata TEQ R1,#0 BEQ %FT05 LDR R6,tempworkspace+errtws_cancelstr STR R6,[R1,#i_data+i_size*4] MOV R1,#0 STR R1,tempworkspace+errtws_icondata [ true LDR R0, progerrsaveblk + 4*1 ; retrieve flags TEQ R2, #2 ; was quit pressed, as opposed to continue? ANDNE R1, R0, #erf_ocontcode MOVNE R1, R1, LSR #erf_ocontcode_shift ANDEQ R1, R0, #erf_ocancelcode MOVEQ R1, R1, LSR #erf_ocancelcode_shift TSTEQ R0, #erf_cancelbox ; If quit clicked, but underlying window had no cancel TEQEQ R1, #0 ; and no return code has been specified either, MOVEQ R1, #99 ; flag that we'll have to call the exit handler. TEQ R1, #0 ; Otherwise, no return code means we have to pass 1 or 2 as appropriate MOVEQ R1, R2 ; for compatibility reasons. STR R1, [sp] | TEQ R2,#2 ; was quit pressed ? BNE %FT05 LDR R1,progerrsaveblk + 4*1 TST R1,#erf_cancelbox BNE %FT05 ; it asked for a cancel button, assume it will quit anyway MOV R1,#99 ; flag that control should be passed to exit handler instead STR R1,[SP] ] 05 ] ; ; tidy up afterwards ; tidyupaftererror BL losewindowrects ; just in case - don't lose memory! ADR R6,errorstack-14*4 ; this is where we put it previously LDMIA R6!,{R1} ; Get old VDU status Debug err,"VDU status restored",R1 TST R1, #&80 ; Was screen disabled by VDU 21? SWINE XOS_WriteI+21 ; Yes then disable it LDMIA R6!,{R1} ; Get FX3 state Debug err,"FX3 status restored",R1 MOV R0,#3 SWI XOS_Byte ; Restore it LDMIA R6!,{R0,R1} ; Get redirection handles Debug err,"Redirection handles restored",R0,R1 SWI XOS_ChangeRedirection ; Restore redirection LDMIA R6!,{R0-R1,R2-R5} STR R0,redrawhandle STR R1,rlinks+windowrects ADR R14,clipx0 ; restore clip window too! STMIA R14,{R2-R5} LDMIA r6,{R0-R3} SWI XOS_SpriteOp ; send output back to original ; MOV R0,#124 ; acknowledge escape (just in case) SWI XOS_Byte ; LDR R14,commandflag ; finally un-suspend the window BIC R14,R14,#cf_suspended STR R14,commandflag [ outlinefont ;Restore the current font and font colours that were in force on ; entry, if they've been changed. This must be done *before* ; making the service call, so the code in ExitWimp is too late. Push "r0-r3" LDR R0, currentfont TEQ R0, #0 BEQ ReportError_restored_font_colours LDR R1, systemfont TEQ R1, R0 LDRNE R1, currentbg LDRNE R2, currentfg LDRNE R3, currentoffset SWINE XFont_SetFontColours MOV R0, #0 STR R0, currentfont ReportError_restored_font_colours Pull "r0-r3" ] [ NCErrorBox ADRL R14, ptrpreserveflag MOV R0, #0 STR R0, [R14] ; move the pointer the next time the error box is opened ] MOV R0, #229 ; restore the old escape condition disable state LDRB R1, old_escape MOV R2, #0 SWI XOS_Byte MOV R1,#Service_WimpReportError MOV R0,#0 ; closing down STRB R0,errorbox_open SWI XOS_ServiceCall ; LDR R1,[sp] TEQ R1,#99 ; QUIT, rather than escape was pressed SWIEQ XOS_Exit B ExitWimp [ NewErrorSystem notoveryet LDR R1,tempworkspace+errtws_icondata LDR R4,tempworkspace+errtws_cancelstr STR R4,[R1,#i_data+i_size*4] MOV R1,#0 STR R1,tempworkspace+errtws_icondata LDR R1,tempworkspace+errtws_describebuttons ; Get back buttons STR R1,tempworkspace+errtws_buttonlist [ false ADRL R5, ptrpreserveflag MOV R4, #1 STR R4, [R5] ; note not to move the pointer ] ADRL R1,progerrsaveblk LDMIA R1,{R4-R7} MOV userblk,R5 Push "PC" ; routine returns with Pull "PC" B starterrorbox_draw ; This actually Pushes PC+12 on the stack NOP B pollit [ ErrorServiceCall InstallErrorButtonPressedHandlers ; Install Exit, Error and UpCall_NewApplication handlers for Service_ErrorButtonPressed client Entry "R0-R4" ADRL R4, errorbuttonoldhandlers MOV R0, #ExitHandler ADR R1, ErrorButtonExitHandler MOV R2, R12 SWI XOS_ChangeEnvironment STMIA R4!, {R1-R3} MOV R0, #ErrorHandler ADR R1, ErrorButtonErrorHandler MOV R2, R12 ADRL R3, watchdogerror ; since errorbox_open is set, this won't be used by "App may have gone wrong" SWI XOS_ChangeEnvironment STMIA R4!, {R1-R3} MOV R0, #UpCallHandler ADR R1, ErrorButtonUpCallHandler MOV R2, R12 SWI XOS_ChangeEnvironment STMIA R4!, {R1-R3} EXIT RemoveErrorButtonPressedHandlers ; Remove handlers installed in InstallErrorButtonPressedHandlers Entry "R0-R4" ADRL R4, errorbuttonoldhandlers MOV R0, #ExitHandler LDMIA R4!, {R1-R3} SWI XOS_ChangeEnvironment MOV R0, #ErrorHandler LDMIA R4!, {R1-R3} SWI XOS_ChangeEnvironment MOV R0, #UpCallHandler LDMIA R4!, {R1-R3} SWI XOS_ChangeEnvironment EXIT ErrorButtonErrorHandler ; This shouldn't ever be called, but if it is, then the SVC stack has been flattened, ; so we can't realistically continue execution afterwards; we also can't use an error ; box to display the message, since one is already open. So just print the message, ; then drop through the exit handler to tidy up the old error box. MOV R12, R0 ADRL R0, watchdogerror + 8 ; skip the PC word and error number SWI XOS_Write0 SWI XOS_NewLine ; drop through... ErrorButtonExitHandler SWI XOS_EnterOS ; we need a stack BL RemoveErrorButtonPressedHandlers LDR R1, =Service_ErrorEnding MOV R2, #2 ; fake a "Cancel" button for the purposes of this service call SWI XOS_ServiceCall ; SVC stack has been flattened by OS_Exit, but the rest of the error box code ; assumes it can use the word at sp_svc to hold the R1 value to pass back from ; Wimp_ReportError. Use the top word of the SVC stack for this purpose instead - ; it'll be flattened again when *we* call OS_Exit. MOV R1, #99 ; re-use magic value that causes OS_Exit to be called Push "R1" B tidyupaftererror ErrorButtonUpCallHandler TEQ R0, #UpCall_NewApplication MOVEQ R0, #0 ; deny new application MOV PC, R14 ] LTORG MACRO $lab MakeInvisible $num LDR R14,[handle,#w_icons] LDR R14,[R14,#i_flags+i_size*$num] ORR R14,R14,#is_deleted LDR R0,[handle,#w_icons] STR R14,[R0,#i_flags+i_size*$num] MEND MACRO $lab MakeInvisibleReg $reg Push "R0,$reg" MOV $reg,$reg , LSL #i_shift LDR R0,[handle,#w_icons] ADD R0,R0,$reg LDR R14,[R0,#i_flags] ORR R14,R14,#is_deleted STR R14,[R0,#i_flags] Pull "R0,$reg" MEND ; 16 byte boundaries of sprites to use errspritetable DCB "error",0,0,0 DCD 0,0 DCB "information",0 DCD 0 DCB "warning",0 DCD 0,0 DCB "program",0 DCD 0,0 DCB "question" DCD 0,0 DCB "user1",0,0,0 DCD 0,0 DCB "user2",0,0,0 DCD 0,0 DCB "program",0 DCD 0,0 noprogapp DCB "Application",0 errorptoken DCB "ErrorP",0 quitlabel DCB "Quit",0 ] ; In R4-R7 = normal R0-R3 for Wimp_ReportError ; R8 = relative handle of error window ; Out [..errorstack] = (10 words) = stashed data ; original SwitchOutputToSprite values, clip window etc. starterrorbox Push "LR" ; copy error message (because messagetrans is unhelpful) ADRL R0,watchdogerror TEQ R0,R4 ; is this coming from us? BEQ %FT05 ADD R0,R4,#4 BL count0 CMP R1,#237 BCS %FT05 MOV R0,R4 ADRL R4,copyerror MOV R1,R4 LDR LR,[R0],#4 STR LR,[R1],#4 BL copy0 05 [ NewErrorSystem ; bit 31 is reserved, used internally BIC R5,R5,#erf_describe BIC userblk,userblk,#erf_describe MOV R1,#0 STR R1,tempworkspace+errtws_icondata ; make sure no label swapping ; is the error box already up? Don't need to save VDU info. LDRB R1,errorbox_open CMP R1,#1 BEQ starterrorbox_reenter ; check to see if this is a program error, if so use the watchdog area ; to create a temporary error block. and try not to use the stack!!! [ Bits30and23 LDR R0,=&C0800000 ; bit 31 + bit 30 + bit 23 LDR R1,[R4] AND R1,R1,R0 TEQ R1,#&80000000 ; DA, AE etc. EOR R0,R0,#&80000000 TEQNE R1,R0 ; pgm error (new) | LDR R1,[R4] AND R1,R1,#&80000000 TEQ R1,#&80000000 BLNE IsThisProgErr ] BNE starterror_next ADRL R1,progerrsaveblk STMIA R1,{R4-R7} MOV R1,#&07000000 STR R1,watchdogerror LDR R1,errorhandle Abs R1,R1 ; real windows are Rel-ative LDR R1,[R1,#w_icons] LDR R2,[R1,#i_data+i_size*4] ; cancel button STR R2,tempworkspace+errtws_cancelstr STR R1,tempworkspace+errtws_icondata ; make life easier later ADR R0,quitlabel ; SMC: now lookup text for button ADRL R2,quittext MOV R3,#buttontextsize BL LookupToken STR R2,[R1,#i_data+i_size*4] MOVS R4,R6 CMPNE R4,#nullptr ADREQ R4,noprogapp LDRB R14,[R4] TEQ R14,#"\\" ADDEQ R4,R4,#1 ADRL R2,watchdogerrtxt MOV R3,#?watchdogerrtxt ADR R0,errorptoken BL LookupToken ADRL R4,watchdogerror LDR R1,tempworkspace+errtws_buttonlist ; store buttons away STR R1,tempworkspace+errtws_describebuttons ; in case we need them again ; when user hits describe TST R5,#erf_newtype [ true LDR R5,=erf_describe:OR:erf_cancelbox:OR:erf_okbox | MOV R5,#erf_describe:OR:erf_cancelbox:OR:erf_okbox ] ORR R5,R5,#erf_newtype ; continue rather than ok MOV userblk,R5 MOV R6,#0 MOVEQ R7,#0 ; make sure no sprite if original error wasn't new type STREQ R6,tempworkspace+errtws_spritearea STR R6,tempworkspace+errtws_buttonlist ; no custom buttons LDR R6,progerrsaveblk + 4*2 ; app name starterror_next ] MOV R1,#Service_WimpReportError MOV R0,#1 ; starting up STRB R0,errorbox_open SWI XOS_ServiceCall CLRV ; just in case MOV R0,#SpriteReason_SwitchOutputToSprite MOV R1,#0 MOV R2,#0 ; Switch to screen ADRL R14,save_context LDR R3,[R14] SWI XOS_SpriteOp BVC %FT05 ; B %FT05 ; if we get an error here, then its potentially quite serious... CLRV ; chances are it will happen again ADD SP,SP,#4 MOV R1,#2 STR R1,[sp] ; cancel [ outlinefont ;Restore the current font and font colours that were in force on ; entry, if they've been changed. This must be done *before* ; making the service call, so the code in ExitWimp is too late. Push "r0-r3" LDR R0, currentfont TEQ R0, #0 BEQ ReportError_restored_font_colours2 LDR R1, systemfont TEQ R1, R0 LDRNE R1, currentbg LDRNE R2, currentfg LDRNE R3, currentoffset SWINE XFont_SetFontColours MOV R0, #0 STR R0, currentfont ReportError_restored_font_colours2 Pull "r0-r3" ] MOV R1,#Service_WimpReportError MOV R0,#0 ; closing down STRB R0,errorbox_open SWI XOS_ServiceCall B ExitWimp 05 ADR R14,errorstack ; FD stack STMDB R14!,{R0-R3} ; remember for later ADR R0,clipx0 ; remember current clip rectangle LDMIA R0,{R0-R3} STMDB R14!,{R0-R3} LDR R0,redrawhandle LDR R1,rlinks+windowrects ; NB requires YUK=false to work STMDB R14!,{R0,R1} ; Restore normal VDU output MOV R3, R14 ; R3 = error stack MOV R0,#0 MOV R1,#0 SWI XOS_ChangeRedirection ; Disable all redirection STMDB R3!,{R0,R1} ; Save old handles Debug err,"Redirected i/p, o/p handles",R0,R1 MOV R0,#3 MOV R1,#&14 ; Enable VDU, disable Spool, printer & serial SWI XOS_Byte STMDB R3!,{R1} ; Save for later Debug err,"OS_Byte 3 status was",R1 MOV R2, #0 MOV R1, #0 MOV R0, #218 SWI XOS_Byte ; Flush VDU queue MOV R0,#117 SWI XOS_Byte ; Read VDU status STMDB R3!,{R1} ; Save for later Debug err,"VDU status is",R1 TST R1, #&80 ; Screen disabled by VDU 21? SWINE XOS_WriteI+6 ; Yes then re-enable it with VDU 6 LDRB R14,sysflags ; beep unless suppressed by user TST R14,#sysflags_nobeep TSTEQ R5,#erf_nobeep ; can be suppressed in the call SWIEQ XOS_WriteI+7 ; ; now set up temporary state for drawing the error box ; STR R8,redrawhandle starterrorbox_reenter MOV R14,#nullptr STR R14,rlinks+windowrects ; pretend there aren't any! ; starterrorbox_draw Debug err,"starterrorbox_draw" STR R5, tempworkspace+errtws_flags ; for later use by pollit Push "R4-R7" [ NewErrorSystem ; make sure we have default pointer MOV R0,#SpriteReason_SetPointerShape ADRL R2,ptr_default2 [ NCErrorBox MOV R3,#&41 ; reprogram shape data, but don't switch to shape 1 yet | MOV R3,#1 ] MOV R4,#0 MOV R5,#0 MOV R6,#0 MOV R7,#0 SWI XWimp_SpriteOp ; take from Wimp's sprite area(s) ] BL set16x32chars Pull "R0-R3" ; R0-R3 = original registers ; Push "R0" ; R0 --> error block ; ; construct title string (depends on R1 bit 4 and R2) ; Push "R2-R5" ; AcceptLoosePointer_NegOrZero R2,0 CMP R2,R2,ASR #31 ; do they want an application name? ADREQL R0,errorprefix1 BICEQ R1,R1,#erf_omiterror ADRNEL R0,errorprefix2 ; -> suitable token TST R1,#erf_omiterror ADRNEL R0,errorprefix ; include prefixing message? MOV R5,#0 MOVS R4,R2 ; parameter for the title string CMPNE R4,#nullptr BEQ %FT01 LDRB R14,[R4] TEQ R14,#"\\" ADDEQ R4,R4,#1 01 ; MOV R3,#?errortitle ADRL R2,errortitle ; -> title string for dialogue box BL LookupToken ; ADRL R2,errortitle ; DebugS err,"errortitle=",R2 Pull "R2-R5" [ NewErrorSystem ; set up sprites in dialogue box MOV R0,userblk AND R0,R0,#erf_errortype addr R14,errspritetable TST userblk,#erf_newtype ADDNE R0,R14,R0 , LSR #erb_errortype-4 MOVEQ R0,R14 TST userblk,#erf_describe ADDNE R0,R0,#48 ; program symbol ; R14 now points to error type sprite name <= 12 chars LDR R14,[handle,#w_icons] ADD R14,R14,#i_data+i_size*3 Push "R1,R2" LDMIA R0,{R0-R2} STMIA R14,{R0-R2} ; copy name Pull "R1,R2" ; set up app sprite MOV R0,#1 STR R0,[handle,#w_areaCBptr] TST userblk,#erf_newtype BEQ oldappsprite AcceptLoosePointer_NegOrZero R3,0 CMP R3,R3,ASR #31 LDREQ R14,[handle,#w_icons] ADDEQ R14,R14,#i_size ; make sure default says 'OK' ADREQ R0,contlabel Push "R2",EQ ; SMC: now lookup text for button but leave it to oldappsprite2 (must preserve R2) ADREQL R2,conttext BEQ oldappsprite2 LDR R2,tempworkspace+errtws_spritearea CMP R2,#1 STRHI R2,[handle,#w_areaCBptr] MOV R2,R3 ; sprite given so use it LDR R14,[handle,#w_icons] ADD R14,R14,#i_size ; make sure default says 'Continue' ADR R0,contlabel Push "R2,R3,R14" ; SMC: now lookup text for button (made complicated by preserving regs) ADRL R2,conttext MOV R3,#buttontextsize BL LookupToken LDR R14,[SP,#8] STR R2,[R14,#i_data] Pull "R2,R3,R14" ; ADD R14,R14,#i_data+i_size Push "R1,R2" MOV R1,#11 B oldapploop oklabel [ :LNOT: STB DCB "OK",0,0 ] contlabel DCB "Continue",0 noappname DCB "switcher",0 [ true ptr_default2 DCB "ptr_default",0 ] ALIGN oldappsprite LDR R14,[handle,#w_icons] ADD R14,R14,#i_size ; make sure default says 'OK' ADR R0,oklabel Push "R2" ; SMC: now lookup text for button ADRL R2,oktext oldappsprite2 Push "R3,R14" ; SMC: must preserve registers over sub-routine call MOV R3,#buttontextsize BL LookupToken Pull "R3,R14" STR R2,[R14,#i_data] Pull "R2" ADD R14,R14,#i_data+i_size Push "R1,R2" CMP R2,R2,ASR #31 ADREQ R2,noappname MOVEQ R1,#11 BEQ oldapploop ; is [R2] <= a space ? LDRB R0,[R2] CMP R0,#" " ADRLS R2,noappname MOVLS R1,#11 BLS oldapploop ; copy !<R2> to sprite name MOV R0,#"!" STRB R0,[R14],#1 MOV R1,#10 oldapploop LDRB R0,[R2],#1 STRB R0,[R14],#1 SUBS R1,R1,#1 BNE oldapploop ; R1 now zero STRB R1,[R14] ; make sure its terminated SUB R2,R14,#11 ; get R2 back to name that is actually used ; R2 should have a valid sprite, does it exist? LDR R1,[handle,#w_areaCBptr] [ SpritePriority Push "R2" CMP R1, #1 ; try any user area before either Wimp area SETPSR V_bit, R0, EQ ; SETV will *not* do, it corrupts Z MOVNE R0, #256+24 ; attempt to select sprite SWINE XOS_SpriteOp MOVVS R0, #256+24 LDRVS R1, baseofhisprites LDRVS R2, [SP] SWIVS XOS_SpriteOp ; not there? try again within high-priority area MOVVS R0, #256+24 LDRVS R1, baseoflosprites LDRVS R2, [SP] SWIVS XOS_SpriteOp ; not there? try again within low-priority area Pull "R2" ; sprite op can stuff R2 | CMP R1,#1 LDREQ R1,baseofsprites MOV R0,#24+256 ; attempt to select sprite Push "R2" SWI XOS_SpriteOp LDRVS R1,baseofromsprites MOVVS R0,#256+24 ; would have been done by the error! LDRVS R2,[SP] SWIVS XOS_SpriteOp ; not there? try again within the ROM Pull "R2" ; sprite op can stuff R2 ] LDRVS R0,[R2,#-8] ; icon's ymax LDRVC R0,[R2,#-16] ; ymin SUBVC R0,R0,#60 ; gap STR R0,[R2,#+i_size-8] ; icon 3's ymax Pull "R1,R2" doneappsprite Debug err,"doneappsprite" MOV R0,#-1 Push "R0" ; we use the stack to keep track of displayed icons ; ; put appropriate OK / Cancel box(es) into error window ; LDR R14,tempworkspace+errtws_buttonlist TST userblk,#erf_newtype AcceptLoosePointer_NegOrZero R14,0,NE,R0 CMPNE R14,R14,ASR #31 BNE %FT10 TST userblk,#erf_okbox:OR:erf_cancelbox ORREQ userblk,userblk,#erf_okbox ; ensure there is at least an OK ; 10 TST userblk,#erf_okbox MOV R0,#1 ; this is icon 1 Push "R0",NE ; displayed LDR R0,[handle,#w_icons] LDR R14,[R0,#i_flags+i_size*1] ORR R14,R14,#is_deleted ; will be undeleted later if necessary STR R14,[R0,#i_flags+i_size*1] ; TST userblk,#erf_cancelbox MOV R0,#4 ; this is icon 4 Push "R0",NE ; is displayed LDR R0,[handle,#w_icons] LDR R14,[R0,#i_flags+i_size*4] ORR R14,R14,#is_deleted ; will be undeleted later if necessary STR R14,[R0,#i_flags+i_size*4] AND R0, userblk, #erf_okbox :OR: erf_cancelbox :OR: erf_htcancel TEQ R0, #erf_okbox :OR: erf_cancelbox :OR: erf_htcancel ; in this case, we must swap over the position of the OK/Cancel buttons to reflect the effect of keypresses MOVEQ R0, #1 STREQ R0, [sp] MOVEQ R0, #4 STREQ R0, [sp, #4] TST userblk,#erf_describe MOV R0,#6 ; this is icon 6 Push "R0",NE ; is displayed LDR R0,[handle,#w_icons] LDR R14,[R0,#i_flags+i_size*6] ORR R14,R14,#is_deleted ; will be undeleted later if necessary STR R14,[R0,#i_flags+i_size*6] ; now do dynamic icons 7,8,9,10 LDR R2,tempworkspace+errtws_buttonlist AcceptLoosePointer_NegOrZero R2,0 CMP R2,R2,ASR #31 MOVEQ R3,#7 BEQ markinvisibleicons TST userblk,#erf_newtype MOVEQ R3,#7 BEQ markinvisibleicons ; these are indirected captain. Can't splurge the data as it may come from ROM! ; need to copy it somewhere safe. MOV R0,#-1 Push "R0" MOV R14,#0 ADRL R3,errorbuttons MOV R1,#errorbuttonsize MOV R4,#maxno_error_buttons ; this is the maximum number of additional buttons we can have Push "R3" ; the first button is always at the start of the string setupdynamicsloop SUBS R1,R1,#1 ; run out of buffer space? (one byte required for terminator) LDRNEB R0,[R2],#1 ; get character from source TSTNE R0,#224 ; is it a control character? STREQB R14,[R3] ; null-terminate the copy and finish BEQ %FT06 CMP R0,#"," ; is it a comma? STRNEB R0,[R3],#1 ; no: copy character and loop BNE setupdynamicsloop STRB R14,[R3],#1 ; yes: copy a NULL SUBS R4,R4,#1 ; decrement buttons counter Push "R3",NE ; unless we've got all the buttons we can, push the button address and loop BNE setupdynamicsloop 06 [ debugerr Push "R0-R8" ADD R0, sp, #9*4 LDMIA R0,{R0-R8} Debug err, "setupdynamicsloop: stack contains",R0,R1,R2,R3,R4,R5,R6,R7,R8 Pull "R0-R8" ] ; stack now holds pointers to button labels MOV R3,#7 LDR R1,[handle,#w_icons] Pull "R0" setupiconsloop ADD R2,R1,R3, LSL #i_shift ; R2-> icon STR R0,[R2,#i_data] Pull "R0" ADD R3,R3,#1 CMP R0,#-1 BNE setupiconsloop STR R3,tempworkspace+errtws_iconend ; number of extra buttons (+7) [ debugerr Push "R0-R8" ADD R0, sp, #9*4 LDMIA R0,{R0-R8} Debug err, "setupiconsloop: stack contains",R0,R1,R2,R3,R4,R5,R6,R7,R8 Pull "R0-R8" ] ; now set what needs to be displayed and aligned SUB R2,R3,#1 displayiconsloop Push "R2" SUB R2,R2,#1 CMP R2,#6 BNE displayiconsloop markinvisibleicons MOV R2,#-1 Push "R2" ; stack now contains list, eg: (-1, 7, 8, 9, 10, 6, 4, 1, -1) ; if number >maxno_error_buttons, we must make some invisible, then position the rest ; unused icons need to be made invisible markinvisloop CMP R3,#7+maxno_error_buttons-1 BHI markinvend MakeInvisibleReg R3 ADD R3,R3,#1 CMP R3,#7+maxno_error_buttons BLO markinvisloop markinvend ; count icons on stack ADD R2,sp,#4 ; jump -1 MOV R0,#0 countstackicons LDR R1,[R2],#4 CMP R1,#-1 ADDNE R0,R0,#1 BNE countstackicons CMP R0,#maxno_error_buttons+1 BLO alignicons Pull "R1" SUB R0,R0,#maxno_error_buttons marktoomanyicons Pull "R1" MakeInvisibleReg R1 SUBS R0,R0,#1 BNE marktoomanyicons MOV R0,#-1 Push "R0" alignicons Debug err,"alignicons" ; stack now has at most maxno_error_buttons icons, R2-8 -> icon to appear on far right. SUB R2,R2,#8 LDR R0,[handle,#w_wex1] ; R0 is max x coord, use as running right posn SUB R0,R0,#20 ; 20 OS unit border LDR R1,[R2],#-4 LDR R14,[handle,#w_icons] ; the first icon is always a default (aka "highlighted") one ADD R3, R14, R1, LSL #i_shift ; R3 -> first icon LDR R4, errbut_y0_def STR R4, [R3, #i_bby0] LDR R4, errbut_y1_def STR R4, [R3, #i_bby1] LDR R4, errbut_fl_def STR R4, [R3, #i_flags] LDR R4, errbut_va_def STR R4, [R3, #i_data + 4] LDR R4, errbut_w_def B alignanddisplayicon alignnexticon ADD R3, R14, R1, LSL #i_shift ; R3 -> icon LDR R4, errbut_y0 STR R4, [R3, #i_bby0] LDR R4, errbut_y1 STR R4, [R3, #i_bby1] LDR R4, errbut_fl STR R4, [R3, #i_flags] LDR R4, errbut_va STR R4, [R3, #i_data + 4] LDR R4, errbut_w alignanddisplayicon ; R1 is icon number, R14 is icon base, R0 is rhs of icon, R4 is minimum width [ StretchErrorButtons Push "R0,R1,R2,R4,R14" LDR R1,[R3,#i_flags] ADD R2,R3,#i_data BL seticonptrs LDR R2,[R3,#i_data] Debug err,">textwidth" BL textwidth Debug err,"<textwidth" ADD R5,R4,#36 ; allow 18 OS-units each side, in case it's a default button Pull "R0,R1,R2,R4,R14" max R4,R5 ] MOV R5,R0 SUB R0,R0,R4 SUB R0,R0,#20 ; gap between buttons SUB R4,R5,R4 STR R4,[R3,#i_bbx0] STR R5,[R3,#i_bbx1] LDR R1,[R2],#-4 CMP R1,#-1 BNE alignnexticon ADD SP,SP,#4 ; skip -1 clearstack Pull "R1" CMP R1,#-1 BNE clearstack ; now resize window if necessary, by moving lhs. CMP R0,#0 MOVGT R0,#0 ; this is the work area x0 required by the buttons LDR R14, [handle, #w_icons] LDR R1, errmess_x0 ADD R2, R14, #i_size * 0 ; R2 -> text icon definition ADD R3, R0, R1 ; stretch text icon to fit window STR R3, [R2, #i_bbx0] [ StretchErrorText LDR R0, [sp] ; get error block pointer ADD R0, R0, #4 STR R0, [R2, #i_data + 0] ; set up text pointer now, we need it to calculate the icon width Push "R1-R6, R10, R14" 06 MOV R1, #-1 STR R1, linecount ; activate line counting LDR R2, [sp, #1*4] ; R2 -> text icon definition LDMIA R2, {x0, y0, x1, y1} ;\. LDR R1, [R2, #i_flags] ; | LDR R2, [R2, #i_data + 0] ; | set up registers for line count [ outlinefont ; | LDR R3, systemfont ;/ TEQ R3, #0 ADREQL R14, iconformatted_system ADRNEL R14, iconformatted_fancy | ADRL R14, iconformatted_system ] Push "PC" ; PC+12 is actually stored MOV PC, R14 ; branch to appropriate routine - returns using Pull "PC" NOP LDR R0, linecount Debug err, "Error message icon line count =", R0 CMP R0, #errmess_maxlines BLE %FT01 ; satisfactory number of lines, we don't need to stretch any further LDR R2, [sp, #1*4] ; R2 -> text icon definition LDR R3, [R2, #i_bbx0] SUB R3, R3, #errmess_increment ; enlarge window by one step STR R3, [R2, #i_bbx0] B %BT06 01 Pull "R1-R6, R10, R14" LDR R3, [R2, #i_bbx0] SUB R0, R3, R1 ; stretch window to fit icon MOV R1, #0 STR R1, linecount ; deactivate line counting ] STR R0,[handle,#w_wex0] LDR R1,[handle,#w_wex1] STR R0,[handle,#w_wax0] ; horizontal centring dealt with later STR R1,[handle,#w_wax1] ; but the visible width *must* match the horizontal work area extent width ADD R2, R14, #i_size * 2 ; move app sprite LDR R3, [R2, #i_bbx0] LDR R4, [R2, #i_bbx1] SUB R4, R4, R3 ; R4 = old width LDR R3, errapp_x0 ADD R3, R3, R0 ; make relative to new window edge ADD R4, R4, R3 STR R3, [R2, #i_bbx0] STR R4, [R2, #i_bbx1] ADD R2, R14, #i_size * 3 ; move type sprite LDR R3, [R2, #i_bbx0] LDR R4, [R2, #i_bbx1] SUB R4, R4, R3 ; R4 = old width LDR R3, errtype_x0 ADD R3, R3, R0 ; make relative to new window edge ADD R4, R4, R3 STR R3, [R2, #i_bbx0] STR R4, [R2, #i_bbx1] ADD R2, R14, #i_size * 5 ; stretch divider sprite STR R0, [R2, #i_bbx0] STR R1, [R2, #i_bbx1] [ NCErrorBox ADD R2, R14, #i_size * 15 ; move left border STR R0, [R2, #i_bbx0] ADD R4, R0, #8 ; magic number: width of vertical borders STR R4, [R2, #i_bbx1] ADD R2, R14, #i_size * 17 ; stretch top border STR R0, [R2, #i_bbx0] ADD R2, R14, #i_size * 18 ; stretch bottom border STR R0, [R2, #i_bbx0] ] ; and we're done!! | ; ; put appropriate OK / Cancel box(es) into error window ; TST userblk,#erf_okbox:OR:erf_cancelbox ; 0 ==> just OK box MOVEQ userblk,#erf_okbox TST userblk,#erf_okbox ORREQ userblk,userblk,#erf_htcancel ; highlight one of them ; TST userblk,#erf_okbox LDR R14,[handle,#w_icons] LDR R14,[R14,#i_flags+i_size*1] BIC R14,R14,#is_inverted ; ensure not inverted initially ORREQ R14,R14,#is_deleted BICNE R14,R14,#is_deleted TST userblk,#erf_htcancel LDRNE R0,unhighlighted_colour ; values read from icons initially LDREQ R0,highlighted_colour ; values read from icons initially BIC R14,R14,#if_bcol:OR:if_fcol ORR R14,R14,R0 LDR R0,[handle,#w_icons] STR R14,[R0,#i_flags+i_size*1] ; TST userblk,#erf_cancelbox LDR R14,[handle,#w_icons] LDR R14,[R14,#i_flags+i_size*4] BIC R14,R14,#is_inverted ; ensure not inverted initially ORREQ R14,R14,#is_deleted BICNE R14,R14,#is_deleted TST userblk,#erf_htcancel LDREQ R0,unhighlighted_colour ; values read from icons initially LDRNE R0,highlighted_colour ; values read from icons initially BIC R14,R14,#if_bcol:OR:if_fcol ORR R14,R14,R0 LDR R3,[handle,#w_icons] STR R14,[R3,#i_flags+i_size*4] LDR R2,[R3,#i_bbx0+i_size*0] LDR R3,[R3,#i_bbx1+i_size*0] SUB R3,R3,R2 AND R14,userblk,#erf_okbox:OR:erf_cancelbox CMP R14,#2 ; poss. values are 1,2,3 (L,R,BOTH) LDRNE R1,[handle,#w_icons] ADDNE R1,R1,#i_size*1 ADDHI R2,R2,R3,ASR #2 ; add 1/4 of width if both present ADDLO R2,R2,R3,ASR #1 ; add 1/2 of width if 'OK' only BLNE setbuttonx ; R1-->icon,R2=centre x-coord ADDHS R2,R2,R3,ASR #1 ; add 1/2 of width -> Cancel LDRHS R1,[handle,#w_icons] ADDHS R1,R1,#i_size*4 BLHS setbuttonx ; R1-->icon,R2=centre x-coord ] ; ; work out window coords (use coords in template) ; ADD R1,handle,#w_wax0 ASSERT cx0=R2 Debug err, "working out window coords" ; Push "R1" ; centre the dialogue LDMIA R1,{cx0,cy0,cx1,cy1} SUB cx1,cx1,cx0 SUB cy1,cy1,cy0 MOV R0,#-1 MOV R1,#VduExt_YWindLimit SWI XOS_ReadModeVariable MOV y0,R2 ; screen height in pixels MOV R1,#VduExt_YEigFactor SWI XOS_ReadModeVariable MOV y0,y0,ASL R2 MOV y0,y0,LSR #1 ; half screen height in OS units SUB cy0,y0,cy1,LSR #1 ; - half the box height ADD cy1,cy1,cy0 ; + box height MOV R1,#VduExt_XWindLimit SWI XOS_ReadModeVariable MOV x0,r2 ; screen width in pixels MOV R1,#VduExt_XEigFactor SWI XOS_ReadModeVariable MOV x0,x0,ASL r2 MOV x0,x0,LSR #1 ; half screen width in OS units SUB cx0,x0,cx1,LSR #1 ADD cx1,cx1,cx0 ; - half box width + box width Pull "R1" LDR x0,[R1,#16] LDR y0,[R1,#20] LDR x1,[R1,#24] ; ; construct window block on stack, for use in OpenWindow etc. ; LDR R14,[sp,#0*4] ; get error block pointer ADD R14,R14,#4 LDR R0,[handle,#w_icons] STR R14,[R0,#0*i_size+i_data+0] ; ASSERT cx0=R2 LDR R0,errorhandle Push "R0,cx0,cy0,cx1,cy1,x0,y0,x1,R9-R12" ; 12 words needed on stack MOV userblk,sp Debug err,"int_open_window" BL int_open_window [ ChildWindows BLVC int_flush_opens ; this is necessary to set the rectangles lists correctly ] ; BLVC visibleouterportion ; handle --> window definition already BLVC int_redraw_window BVS donegetr getrlp TEQ R0,#0 BEQ donegetr BL int_get_rectangle BVC getrlp donegetr SWI XHourglass_Smash ; turn off hourglass (if displayed) ; ignore errors ADD R14,handle,#w_x0 ; confine pointer to error box LDMIA R14,{x0,y0,x1,y1} BL pointerwindow ; MOV R0, #ScreenBlankerReason_Unblank SWI XScreenBlanker_Control ; unblank screen (if blanked) ; BL flushkbdmouse ; get ready to read these ; [ NCErrorBox ADRL R0, ptrpreserveflag LDR R0, [R0] TEQ R0, #0 ; Should we move the pointer over the default action button? BNE %FT01 Push "cx0-y0" LDR R14, errorhandle Abs R14, R14 LDR cx0, [R14, #w_wax1] SUB cx0, cx0, #20 ; 20 OS unit border LDR cx1, errbut_w_def SUB cx0, cx0, cx1, ASR #1 ; screen x of icon centre LDR cy1, [R14, #w_way1] LDR y0, [R14, #w_scy] SUB y0, cy1, y0 ; screen y of wao LDR cy0, errbut_y0_def LDR cy1, errbut_y1_def ADD cy0, cy0, cy1 ADD cy0, y0, cy0, ASR #1 ; screen y of icon centre SUB sp, sp, #8 MOV R1, sp MOV R0, #3 STRB R0, [R1] strw cx0, R1, 1 strw cy0, R1, 3 MOV R0, #&15 SWI XOS_Word ; Set mouse position ADD sp, sp, #8 ADRL R0, ptrsuspendflag ; Update our copy of the coords LDR R1, [R0] ; because IconHigh reads the mouse TEQ R1, #2 ; position using Wimp_GetPointerInfo! MOVEQ R1, #1 ; If pointer is currently hidden STREQ R1, [R0] ; until the next mouse move, remember BL getmouseposn ; to discount next mouse read. Pull "cx0-y0" 01 MOV R0, #106 MOV R1, #0 SWI XOS_Byte ; Read current pointer number (also turns it off, but we'll soon switch it back) ADRL R14, ptrshlflag STR R1, [R14] ; Store old pointer shape MOV R0, #2 SWI XIconHigh_Start ; Unconditionally start single-tasking IconHigh ADRL R14, ptrshlflag MOV R0, #106 LDR R1, [R14] ; Restore pointer to the way it was after Hourglass_Smash SWI XOS_Byte ; (also undoes any unwelcome changes due to IconHigh_Start) ] ADD sp,sp,#13*4 ; forget open block / error pointer Pull "PC" [ NewErrorSystem errwatchdogguard DCD &E240569E LTORG [ :LNOT: Bits30and23 IsThisProgErr ; returns EQ is proram error, R4-> error number Push "R0-R2,lr" LDR R2,[R4] AND R0,R2,#&3f000000 ; mask 'prog-detect' TEQ R0,#27 :SHL: 24 ; escape shifted Pull "R0-R2,PC",EQ ADR R0,progerrslist 01 LDR R1,[R0],#4 TEQ R1,R2 Pull "R0-R2,PC",EQ CMP R1,#-1 BNE %BT01 MOVS R1,#1 ; NE Pull "R0-R2,PC" ] ] END