; ; File: DeskMgr.a ; ; Contains: The desk manager is the interface between the applications and the desk ornament/ ; RAM-based driver system. When an application receives an event, it passes it to ; the desk manager to allow the system to capture events for desk ornaments and ; other system functions. The applications also call the desk manager routine ; "SystemTask" in their main loop to give the drivers back some good "main thread" ; time to call the memory manager or keep the desk ornaments alive. ; ; Written by: Andy Hertzfeld 23-Oct-82 ; ; Copyright: © 1982-1993 by Apple Computer, Inc. All rights reserved. ; ; Change History (most recent first): ; ; 8/16/93 BH Manual-eject handling now looks at all of a volume's open files ; to determine if the volume needs to be updated, rather than just ; the vcbDirty flag. ; 8/3/93 BH Added manual-eject event support to SystemEvent. ; 1/27/93 CSS Patch the SystemMenu function to handle the Keyboard menu, and ; input method menus correctly. Also, fix the dispatcher to point ; to the SystemMenu routine in this file again. ; 11/18/92 SWC Removed the HcMac IdleMind code since the _IdleMind call is now ; made in SyncIdleTime. ; 11/01/92 HY Conditionalize call to IdleMind for LC930 ROM. We don't ; include any of the PowerMgr stuff for this ROM and IdleMind ; is one of the vectors conditionalized in :Make:VectorTable.a. ; 7/17/92 CSS Jeff copied this directly from Reality, but with the ; diffences in include file structure over there, it compiled. ; Here in SuperMario, it didn't. The reason is that SuperMario ; includes PowerEqu.a in StandardEqu.a while Reality includes ; PowerPrivEqu.a. So, I am including PowerPrivEqu.a back ; in this file. Maybe someday we can figure out why Power anything ; is included in StandardEqu.a. ; <11> 7/8/92 JSM Merge changes from SuperMario: roll-in HMSystemTaskPatch and ; HMSystemMenuPatch from Balloonptch28.a. Also, add a change from ; FixSystemClick that wasÕt originally done in <5> and roll-in ; GetDCtlRefNumFromHandleForSendDrvrMsg and ; GetDCtlRefNumFromHandleForClosingDeskAccessory patches from ; DeskMgrPatches.a. ; <10> 5/5/92 JSM Get rid of conditionals: get rid of local conditional ; ApplDefEvent which will never be true, hasIdle, hasJaws, and ; isUniversal are always true, hasNormandy is always false. This ; file now has no conditionals. ; <9> 2/10/92 JSM Moved this file to DeskMgr folder, keeping all the old ; revisions. ; <8> 11/16/91 DTY Replacing hard addresses with a record to make the equates Òmore ; universalÓ is nice but useless if the code has no way of getting ; to those addresses any more. Add an equate for VidRAMStkPtr to ; this file to keep the ROM build building until the hardware guys ; figure out what theyÕre trying to do. ; <7> 9/14/90 MSH Newer, faster version of power cycling (should probably be ; vectorized someday). ; <6> 9/13/90 BG Removed <4>. 040s are working more reliably now. ; <5> 8/2/90 csd Fixed SystemClick to get the window variant in a 32-bit clean ; way. ; <4> 7/16/90 BG Added EclipseNOPs for flakey 040s. ; <3> 5/16/90 MSH Added Waimea Power Cycling to the portable idle code. Fully ; universal of course. ; <2> 1/12/90 CCH Adding include of ÒHardwarePrivateEqu.aÓ. ; <2.6> 12/4/89 MSH Ported over the forked off hcmac source changes. ; <2.5> 8/22/89 SES Removed references to nFiles. ; <2.4> 6/8/89 KSM Restored to version 1.9 (last real change). ; <2.3> 6/2/89 KSM Updated conditionals for ROM/SYS build AGAIN (again). ; <2.2> 6/2/89 KSM Updated conditionals for ROM/SYS build AGAIN. ; <2.1> 6/2/89 KSM Updated conditionals for ROM/SYS build. ; <2.0> 6/1/89 KSM Added check to handle events for tear off menus. ; <1.9> 5/15/89 EMT Checked for NIL frontwindow in SystemEvent, fixes BRC #34592. ; <1.8> 5/15/89 MSH Test of watch cursor had the wrong register. ; <1.7> 3/31/89 MSH Moved the idle stuff to a subroutine at the end of the file. ; <1.6> 3/9/89 MSH Check the time out dirty flag before using them. ; <1.5> 3/3/89 MSH No longer have to check for LastAct and LastHd initialized. ; <1.4> 2/28/89 MSH Time outs reduced to one each for sleep and hard disk. ; <1.3> 2/8/89 MSH Moved all sleep and hard disk time out in from poweResourceMgr.a ; <1.2> 12/14/88 MSH Had to make file hardware dependent to support idle mode. ; <1.1> 11/10/88 CCH Fixed Header. ; <1.0> 11/9/88 CCH Adding to EASE. ; <¥1.2> 9/23/88 CCH Got rid of inc.sum.d and empty nFiles ; <1.1> 5/16/88 BBM Give Notification Manager time as well. ; <1.0> 2/11/88 BBM Adding file for the first time into EASEÉ ; 1/14/87 JTC 32-bit friendly changes, rolled in much later since TJ had ; access to the file during the 32-bit drive. ; 10/14/86 TJ Fixed missing drive # in call to DoEject; no longer complains ; about ejecting drive #243. ; 9/9/86 TJ Extended the DiskHandler to accept DiskInsertEvt "Eject" events; ; the upper word if -1 means a disk eject, not insert. Eject ; function goes through a trap vector, no longer a ROM jump ; vector. ; 2/19/86 BBM Made some modifications to work under MPW ; 9/26/85 BBM Made DeskMgr pass on events greater than 8. Event 9 is still ; ignored and reserved for future use. To pass on application ; defined events, set the conditional assembly flag ApplDefEvent ; to 1. ; 2/20/85 LAK Special IOPermission value set for OpenDeskAcc Opens. ; 1/30/85 LAK Lock/Unlock window def proc around call. ; 1/29/85 EHB Checked for NIL frontwindow in SystemTask ; 1/29/85 EHB Unlocked WindowDef before LoadResource in SystemClick ; 1/23/85 LAK Adapted for new equate files. ; 9/6/83 AJH Made SystemEdit save and restore the port ; 9/5/83 AJH Fixed bug in SystemEdit ; 8/30/83 SC Fixed bug in Movem.l in system click ; 8/15/83 AJH monster code krunch (from code review with Jerome, Capps) ; 8/9/83 AJH Removed NetEvent support, general code crunch ; 6/30/83 AJH Added CloseDeskAcc, SystemEdit ; 6/23/83 SC Added support for multiple windows (Changed SearchWindow) ; 6/19/83 AJH Made the desk mgr control call asynchronous ; 6/17/83 LAK Changed to use UnitNtryCnt lomem var instead of equate. ; 6/15/83 AJH Added OpenDeskAcc ; 5/10/83 AJH Made it use a hook to close desk ornaments ; 4/27/83 AJH Made SystemClick call deskHook with wmgrPort clip set up ; 3/7/83 AJH Made TaskLock a byte flag (instead of word) ; 2/9/83 AJH Made SystemTask not call active drivers ; 2/8/83 AJH Changed DragWindow call to provide boundsRect ; 1/24/83 AJH SystemMenu lets orn own menuBar; new I/O calls ; 1/23/83 AJH added support for diskInserted events, deskHook in SystemClick ; 1/20/83 AJH fixed stack bug in goAway handling code ; 12/19/82 AJH Added SystemMenu, handling of activate/deactivate events ; 11/16/82 AJH Added TaskLock to SystemTask to avoid re-entrancy problems ; BLANKS ON STRING ASIS LOAD 'StandardEqu.d' INCLUDE 'HardwarePrivateEqu.a' INCLUDE 'MMUEqu.a' INCLUDE 'UniversalEqu.a' INCLUDE 'BalloonsPriv.a' INCLUDE 'TSMPrivate.a' ; CSS INCLUDE 'ScriptPriv.a' ; CSS DeskMgr PROC EXPORT EXPORT SystemEvent,SystemClick,SystemTask,SystemMenu,SystemEdit EXPORT OpenDeskAcc,CloseDeskAcc WITH ProductInfo,DecoderInfo,VideoInfo ; ; FUNCTION SystemEvent(theEvent: EventRecord): BOOLEAN; ; ; SystemEvent is called by an application when it receives an event from the ; event manager. SystemEvent determines if the event should be handled by the ; application or the system. If the application should handle it, SystemEvent ; returns FALSE; otherwise, SystemEvent calls the appropriate system code to handle ; the event and returns TRUE. ; SystemEvent MOVE.L A3,-(SP) ;preserve a work register MOVE.L 8(SP),A3 ;get pointer to event record CLR.W 12(SP) ;assume its not for us (return FALSE) ; preserve the current port SUBQ #4,SP ;make some room on stack MOVE.L SP,-(SP) ;point to it _GetPort ;remember the current port ; case out on the Event.What field MOVE.W EvtNum(A3),D0 ;get the event number CMP #12,D0 ;only handle events 0-8 <26sep85> BBM BCC.S DoneSEvt ;if not one of ours, ignore it ; ADD.W D0,D0 ;double for word index LEA EvtDTable,A0 ;get address of dispatch table ADD.W 0(A0,D0),A0 ;compute dispatch address JMP (A0) ;dispatch to proper handler ; ; Here is the system event dispatch table, offset-encoded for compactness ; EvtDTable DC.W DoneSEvt-EvtDTable ;null event is ignored (0) DC.W DoneSEvt-EvtDTable ;mouse down is ignored (1) DC.W IfTopWants-EvtDTable ;feed mouse up to top window (2) DC.W IfTopWants-EvtDTable ;feed key down to top window (3) DC.W IfTopWants-EvtDTable ;feed key up to top window (4) DC.W IfTopWants-EvtDTable ;feed auto-key to top window (5) DC.W SysUpdate-EvtDTable ;handle system update events (6) DC.W DiskHandler-EvtDTable ;handle disk inserted events (7) DC.W SysUpdate-EvtDTable ;handle activate events (8) DC.W DoneSEvt-EvtDTable ;reserved event is ignored (9) <26sep85> BBM DC.W IfTopWants-EvtDTable ;feed network to top window (10) <26sep85> BBM DC.W IfTopWants-EvtDTable ;feed device drvr to top window (11) <26sep85> BBM ; ; DoneSEvt is the code for returning to the application when the desk manager ; is all finished its work. Events that are ignored branch here, too, since the ; result has already been flagged false. The alternative entry point "DoneSysEvt" ; is used to return true. ; DoneSysEvt ADDQ.B #1,16(SP) ;flag the result "TRUE" DoneSEvt _SetPort ;restore it MOVE.L (SP)+,A3 ;recover work register MOVE.L (SP)+,(SP) ;strip parameter RTS ;return to caller ; ; IfTopWants feeds the event to a driver if that driver's window is the frontMost ; visible window and the driver has the event enabled. First use FrontWindow ; to find the frontMost visible window ; IfTopWants SUBQ #4,SP ;make space for function result _FrontWindow ;find out the frontMost window MOVE.L (SP)+,D0 ; get windowPtr <1.9> BEQ.S DoneSEvt ; no searching for NIL windows! <1.9> MOVE.L D0,A0 ; else search for window in A0 <1.9> BSR.S SearchWindow ;get handle to DCE that owns the window BNE.S DoneSEvt ;if none, we're done ; ; At this point, A1 is a pointer to the driver control entry that owns the window. ; See if it wants this event. ; MOVE EvtNum(A3),D0 ;get number of event MOVE DCtlEMask(A1),D1 ;get event mask BTST D0,D1 ;this event enabled? BEQ.S DoneSEvt ;if not, we're done ; BSR.S SendDrvrMsg ;feed the event to the driver BRA.S DoneSysEvt ;return TRUE ; ; ; SearchWindow takes the window pointer in A0 and fetches the windowKind. System ; windows have negative kinds and the kind is the -UnitNumber of the driver. ; So, using the - kind as an index into the unit table yields the handle/pointer ; to the driver (if installed). ; If one is found, A0 contains its handle, A1 contains a pointer and the ; Z flag is set. If none are found or the window isn't a system kind, the ; Z-flag is cleared. ; SearchWindow MOVE windowKind(A0),D0 ; get the unit number from window BPL.S noGoodSearch ; if not sys. kind, ignore it NOT D0 ; flip it (bitwise) CMP UnitNtryCnt,D0 BPL.S noGoodSearch ASL #2,D0 ; * 4 MOVE.L UTableBase,A0 ; point to the driver table MOVE.L 0(A0,D0),A0 ; get the handle MOVE.L (A0),A1 ; dereference MOVEQ #0,D0 ; set z flag RTS noGoodSearch MOVEQ #-1,D0 ; clear z flag RTS ; ; SendDrvrMsg sends the driver (whose DCE pointer is in A1) a "feedEvent" control ; call. A pointer to the relevant event record is in A3 ; SendDrvrMsg MOVEQ #64,D0 ;message 64 is "feedEvent" ; SendDCommon LINK A6,#-$32 ;get some space for the control p-block LEA IORefNum-$32(A6),A0 ;point A0 at the block MOVE.W DCtlRefNum(A1),(A0)+ ;set up the refNum MOVE.W D0,(A0)+ ;set up the control "opCode" MOVE.L A3,(A0) ;set up event ptr as parameter LEA -$32(A6),A0 ;point to pBlock _Control ,IMMED ;make the control call ; UNLK A6 ;de-allocate parameter block RTS ;return to caller ; ; SendRunMsg sends the "run" opcode control call to the driver whose DCE ptr is in A1 ; It shares lots of code with "SendDrvrMsg" ; SendRunMsg MOVEQ #65,D0 ;the run message is 65 BRA.S SendDCommon ;use common code ; ; SysUpdate handles update events for system windows. On entry, A3 points to the ; event record. ; SysUpdate MOVE.L EvtMessage(A3),A0 ;get the window pointer BSR.S SearchWindow ;try to find the window BNE DoneSEvt ;if not found, we're done ; ; OK, we found the driver control entry of the driver that owns the window to be ; update. Send it the "feedEvent" message ; BSR SendDrvrMsg ;send update message BRA DoneSysEvt ;return TRUE ; ; DiskHandler handles a disk inserted event by calling the file system "suck em up" ; routine. It passes the event through to the application (by returning FALSE), ; adding the result of the "suck em up" call to the event.message field ; DiskHandler tst.w EvtMessage(A3) ;if an Eject event, beq.s @1 ;handle as a Command-Shift- IF hasManEject THEN ; CMPI.W #-2,EvtMessage(A3) ; is this a manual eject? BEQ.S HandleManEject ; ENDIF ; move.l jDoEject,A0 ; move.w EvtMessage+2(A3),D1 ;the drive number, moveq #1,D2 ;flag from "keyboard" jsr (A0) ;eject the disk bra.s DoneSysEvt ;mark as taken, no error @1 SUB.W #64,SP MOVE.L SP,A0 ;point to it MOVE.W EvtMessage+2(A3),IODrvNum(A0) ;get the "disk ID" parameter _MountVol ;tell OS to do its thing ADD.W #64,SP ;deallocate space on stack MOVE.W D0,EvtMessage(A3) ;return result to application BRA DoneSEvt ;always return "FALSE" IF hasManEject THEN ; IMPORT SwitchDisk,ClearSysErrorUpdateRect HandleManEject MOVE.W EvtMessage+2(A3),D1 ; drive number MOVEA.L VCBQHdr+qHead,A2 @chkvcb MOVE.L A2,D0 BEQ.S DoneSysEvt ; nothing to see here, folks...move along CMP.W vcbDrvNum(A2),D1 BEQ.S @gotvcb MOVEA.L qLink(A2),A2 BRA.S @chkvcb @gotvcb MOVE.W vcbFlags(A2),D0 BTST #vcbDirty,D0 ; VCB dirty? BNE.S @dirtyvol ; yes: go deal with it... MOVEA.L FCBsPtr,A1 ; no: check FCBs for dirty files... . MOVEQ #2,D1 ; offset to first FCB . @chkfcb MOVE.L fcbFlNm(A1,D1),D0 ; open file? . BEQ.S @nextfcb ; no, skip it . CMPA.L fcbVPtr(A1,D1),A2 ; does it belong to our volume? . BNE.S @nextfcb ; no, skip it . BTST.B #fcbModBit,fcbMdRByt(A1,D1) ; is it dirty? . BNE.S @dirtyvol ; yes, go try to get the vol back . @nextfcb ADD.W FSFCBLen,D1 ; offset to next FCB . CMP.W (A1),D1 ; reached the end yet? . BEQ @offline ; yes: everything's clean, so just offline it . BRA.S @chkfcb ; check out the next one @dirtyvol MOVE.W vcbDRefNum(A2),-(SP) ; save driver refnum MOVE.W vcbDrvNum(A2),vcbDRefNum(A2) ; save old drive num here CLR.W vcbDrvNum(A2) ; and make it look offline so MountVol can do a remount MOVE.W #dsDirtyDisk,D4 ; err code for SwitchDisk JSR SwitchDisk ; ask for the disk BSET #7,DSWndUpdate ; don't need evt mgr to update syserr box JSR ClearSysErrorUpdateRect ; we'll draw over it TST.W D0 ; SwitchDisk result BNE.S @warning ; DS request aborted--warn the user SUBA.L #ioVQElSize,SP ; volumeParam CLR.L ioVNPtr(SP) ; no name MOVE.W vcbVRefNum(A2),ioVRefNum(SP) ; vrefnum MOVEA.L SP,A0 _FlushVol ADDA.L #ioVQElSize+2,SP ; clean up stack (incl. DRefNum saved earlier) CLR.L -(SP) ; result space MOVE.W #-16413,-(SP) ; "You may now remove the disk" DLOG ID CLR.L -(SP) ; allocate dialog record in heap MOVEQ #-1,D0 MOVE.L D0,-(SP) ; come up in front _GetNewDialog MOVE.L (SP),-(SP) ; dialog ptr MOVE.W vcbDrvNum(A2),D0 ; drive num for filter proc MOVE.L D0,-(SP) ; dialog ptr is already on stack _SetWRefCon SUBQ #2,SP ; result PEA @filter ; filter to watch for ejection PEA 4(SP) ; -> result _ModalDialog MOVE.W (SP)+,A3 ; result (in A3 cause it's already saved--silly, I know) _DisposeDialog ; ptr is already on stack MOVE.W A3,D0 BMI.S @offline ; disk was ejected BRA.S DoneSysEvt ; user OKed, disk is flushed and present @warning MOVE.W vcbDRefNum(A2),vcbDrvNum(A2) ; restore VCB stuff we tweaked to MOVE.W (SP)+,vcbDRefNum(A2) ; make the vol look offline CLR.W -(SP) ; result MOVE.W #-16414,-(SP) ; "You may lose data" ALRT ID CLR.L -(SP) ; no filter _CautionAlert ADDQ #2,SP ; clear result @offline SUBA.L #ioVQElSize,SP ; paramblock on the stack MOVEA.L SP,A0 ; point to it CLR.L ioVNPtr(A0) ; don't use the name... MOVE.W vcbVRefNum(A2),ioVRefNum(A0) ; use the vRefNum instead _Offline ; mark it offline ADDA.L #ioVQElSize,SP ; goodbye paramblock NEG.W vcbDRefNum(A2) ; volume has been ejected--flip this to indicate it BRA.S DoneSysEvt @filter LINK A6,#-14-EvtBlkSize ; some local space CLR.W 20(A6) ; default return: false MOVEA.L 12(A6),A0 ; A0 -> evt record CMPI.W #keyDwnEvt,evtNum(A0) ; keyDown? BNE.S @update MOVE.L evtMessage(A0),D0 ; key CMPI.B #$0D,D0 ; return? BEQ.S @ok CMPI.B #$03,D0 ; enter? BNE.S @chkeject @ok MOVEA.L 8(A6),A0 ; A0 -> itemHit MOVE.W #1,(A0) ; itemHit=OK button MOVE.B #1,20(A6) ; handled it, so return true BRA @exit @update CMPI.W #updatEvt,evtNum(A0) ; update? BNE.S @chkeject PEA -18(A6) ; old GrafPtr _GetPort MOVE.L 16(A6),-(SP) ; dialog ptr _SetPort MOVE.L 16(A6),-(SP) ; dialog ptr MOVE.W #1,-(SP) ; OK button item number PEA -2(A6) ; item type PEA -6(A6) ; item handle PEA -14(A6) ; item rect _GetDItem ; get info PEA -14(A6) ; item rect MOVE.L #$FFFCFFFC,-(SP) ; -4,-4 _InsetRect MOVE.L #$00030003,-(SP) ; 3,3 _PenSize PEA -14(A6) ; rect MOVE.L #$00100010,-(SP) ; curvature: 16,16 _FrameRoundRect ; outline OK button _PenNormal MOVE.L -18(A6),-(SP) ; old GrafPtr _SetPort BRA.S @exit @chkeject LEA -14-EvtBlkSize(A6),A0 ; local event record MOVE.W #128,D0 ; disk-insert event mask _GetOSEvent BNE.S @exit ; didn't get anything we wanted TST.W -14-EvtBlkSize+evtMessage(A6) ; really an insertion? BPL.S @repost ; yes: save it for later SUBQ #4,SP ; no: an ejection--get dialog refcon MOVE.L 16(A6),-(SP) ; dialog ptr _GetWRefCon MOVE.L (SP)+,D0 ; refcon==drive number we're watching for CMP.W -14-EvtBlkSize+evtMessage+2(A6),D0 ; got it? BNE.S @repost ; no: throw it back MOVEA.L 8(A6),A0 ; A0 -> itemHit MOVE.W #-1,(A0) ; itemHit=-1 for ejection MOVE.B #1,20(A6) ; handled it, so return true BRA.S @exit @repost MOVE.L -14-EvtBlkSize+evtMessage(A6),D0 ; get message MOVEA.W #DiskInsertEvt,A0 ; event type _PostEvent ; post it @exit UNLK A6 ; clean up locals MOVEA.L (SP),A0 ; get return addr ADDA.L #16,SP ; clean up parameters JMP (A0) ; return ENDIF ; ; PROCEDURE SystemClick(theEvent: EventRecord; theWindow: windowPtr); ; ; SystemClick is used to feed "mouse button down" events to the driver/desk ; ornament system after they've been classified by FindWindow as a click in ; a system window. If the clicked-in window is the frontmost visible window, ; feed it the event. Otherwise we unhilite the current "frontWindow" and ; hilite and BringToFront the clicked in window. ; SystemClick MOVEM.L D0/D3-D4/A3-A4,-(SP) ;preserve some work registers ;D0 to reserve space on stack MOVE.L SP,-(SP) ;push "savePort" _GetPort ;remember the current grafPort on stack MOVE.L 24(SP),A4 ; get theWindow into A4 MOVE.L WindowDef(A4),A3 ; get the window def proc handle into A3 MOVE.L 28(SP),D4 ; get theEvent into D4 MOVE.L A4,D0 ; test the window ptr BEQ CheckDeskHook ; if nil, check the desk hook MOVE.L A4,A0 ; pass in A0 BSR SearchWindow ;find it in the driver list BNE.S DoneSClick ;if not found, ignore the call MOVE.L A0,D3 ;remember DCE handle (formerly remembered the pointer) (from FixSystemClick) <11> ; ; we found the window in the device table; A1 points to the DCE entry of the driver ; that owns the window. First see what part of the window its in by calling ; the window definition proc to classify. ; MOVEQ #0,D0 ;clear out high part MOVE.B WindowDef(A4),D0 ;get selector CLR.L -(SP) ;make room for the result subq #2, SP ; room for window variant move.l A4, -(SP) ; push window pointer _GetWVariant ; legally get the window variant MOVE.L A4,-(SP) ;push the window ptr MOVE #WHitMsg,-(SP) ;the message is "HitTest" MOVE.L D4,A0 ;get the event MOVE.L EvtMouse(A0),-(SP) ;push the mouse point (global) ; don't lock window def before loading. Be 32-bit friendly in any case. JTC MOVE.L A3,-(SP) ; make sure window def proc is loaded _LoadResource ; MOVEA.L A3,A0 ;def proc handle _HLock ;lock before call MOVEA.L (A3),A0 ;deref the proc JSR (A0) ;invoke it MOVEA.L A3,A0 ;def proc handle _HUnlock ;lock before call MOVE.L (SP)+,D0 ;get the result code BEQ.S DoneSClick ;if 0, nothing to do SUBQ #2,D0 ;is it in drag? BEQ.S DragClick ;if so, drag it SUBQ #2,D0 ;how about GoAway? BEQ.S GoAwayClick ;if so, handle it ; ; its in the content of the window. See if its on top ; CLR.L -(SP) ;make room for function result _FrontWindow ;figure out the frontmost one MOVE.L (SP)+,D0 ;get the result CMP.L A4,D0 ;is it ours? BNE.S NotFrontMost ;if not, go bring ours to the top ; ; our window is the frontmost, so send it the event ; MOVE.L D4,A3 ;get event ptr in A3 ; begin roll-in GetDCtlRefNumFromHandleForSendDrvrMsg patch <11> move.l d3,a1 ;put DCE handle in an address register to dereference it <11> move.l (a1),a1 ;get the DCE pointer now <11> ; end roll-in GetDCtlRefNumFromHandleForSendDrvrMsg patch <11> BSR SendDrvrMsg ;send it the "mouseDown" message ; ; all done with SystemClick so restore registers, strip parameters and return to caller ; DoneSClick _SetPort ;restore it MOVEM.L (SP)+,D3-D4/A3-A4 ;restore work registers MOVE.L (SP)+,A0 ;get the return address ADDQ #8,SP ;strip parameters JMP (A0) ;return to caller ; ; CheckDeskHook is called when the user called SystemClick with a NIL window ; pointer. Call the desk hook if its installed ; CheckDeskHook TST.L DeskHook ;got something? BEQ.S DoneSClick ;if not, just ignore it MOVE.L WmgrPort,-(SP) ;push the wmgrPort _SetPort ;get into the wmgrPort MOVE.L GrayRgn,-(SP) ;push the gray region _SetClip ;make that the clip CLR.L -(SP) ;push NIL _ClipAbove ;clip to all windows MOVE.L D4,A0 ;get event pointer MOVE.L DeskHook,A1 ;get address in A-reg MOVEQ #-1,D0 ;flag its from SystemClick JSR (A1) ;call the deskHook BRA.S DoneSClick ;all done... ; ; at this point, the user has clicked in a system window that isn't the frontmost. ; We must unHilite the old front window, bring the one just clicked in to the ; front and hilite it. ; NotFrontMost ; MOVE.L A4,-(SP) ;push our window _SelectWindow ;select it ; BRA.S DoneSClick ;all done! ; ; It was clicked in the drag area of a system window so drag it ; DragClick MOVE.L A4,-(SP) ;push the window MOVE.L D4,A0 ;get the event MOVE.L EvtMouse(A0),-(SP) ;push the point MOVE.L (A5),A0 ;point to grafGlobals PEA ScreenBits+Bounds(A0) ;use screenBits.bounds as boundsRect _DragWindow ;its a drag! BRA.S DoneSClick ; ; It was clicked in the GoAway button so track it and, if necessary, close the ; driver ; GoAwayClick CLR.W -(SP) ;make room for result MOVE.L A4,-(SP) ;push the window MOVE.L D4,A0 ;get the event MOVE.L EvtMouse(A0),-(SP) ;push the point _TrackGoAway ;track it TST.B (SP)+ ;time to go Away? BEQ.S DoneSClick ;if not, we're done ; ; the user pushed the GoAway button so close this driver ; ; begin roll-in GetDCtlRefNumFromHandleForClosingDeskAccessory patch <11> move.l d3,a1 ;put DCE handle in an address register to dereference it <11> move.l (a1),a1 ;get the DCE pointer now <11> ; end roll-in GetDCtlRefNumFromHandleForClosingDeskAccessory patch <11> MOVE.L CloseOrnHook,D0 ;is there a hook installed BNE.S DoCloseHook ;if so, use it MOVE.W DCtlRefNum(A1),-(SP) ;push the refNum _CloseDeskAcc ;close it BRA.S DoneSClick ;all done! DoCloseHook MOVE.L D0,A0 ;get hook address in A-reg JSR (A0) ;invoke it BRA.S DoneSClick ;all done ; ; PROCEDURE SystemTask; ; ; SystemTask is called by the applications when they don't have anything better ; to do, hopefully at least once through their main loop. SystemTask gives ; a call to any driver that has the "NeedsTime" flag set in its header. ; SystemTask provides a way for asynchronous tasks to call the memory manager, ; since any driver can hook into "main thread" time. The DrvrCount parameter ; in the driver header specifies the number of ticks the driver needs between ; systemTask calls. A value of 0 causes it to be called everytime systemTask ; is called. ; SystemTask ; begin roll-in HMSystemTaskPatch patch <11> MOVE.L ExpandMem,A0 MOVE.L $78(A0),D0 BEQ.S @BalloonsOff CLR -(SP) _HMGetBalloons TST.B (SP)+ BEQ.S @BalloonsOff SUBQ #2,SP ; make room for a dummy OSErr <11> _HMBalloonBulk ; <11> ADDQ #2,SP ; toss result (for now) <11> @BalloonsOff ; end roll-in HMSystemTaskPatch patch <11> IMPORT NMTask ; JSR NMTask ;Give time to Notification Manager MOVEM.L D2-D4/A3-A4,-(SP) ;save some work registers ; ; if this is a re-entrant call, just punt ; BSET #7,TaskLock ;flag that we're in system task BNE TaskDone ;if re-entrant, just exit ; SUBQ #4,SP ;make space on stack MOVE.L SP,-(SP) ;push pointer to it _GetPort ;remember the old port ; ; first see if the FrontWindow is a system Window. If so, give it a chance to ; set the cursor shape ; CLR.L -(SP) ;make room for result _FrontWindow ;find out the front one MOVE.L (SP)+,D0 ; get windowPtr BEQ.S NotSWindow ; no searching for NIL windows! MOVE.L D0,A0 ; else search for window in A0 BSR SearchWindow ;get the DCE ptr in A1 BNE.S NotSWindow ;if we cant find it, skip ; ; send the window pointed to by A0 a "cursor" message ; BTST #DrvrActive,DCtlFlags+1(A1) ;is it active? BNE.S NotSWindow ;skip if its active MOVEQ #66,D0 ;D0 contains "cursor" message BSR SendDCommon ;send the cursor message NotSWindow MOVE.L UTableBase,A3 ;point to the driver table MOVE.L A3,A4 MOVE.W UnitNtryCnt,D3 ;get number of entries MOVE.L D3,D4 ; ; here is the main loop for SystemTask. For each driver that's installed, see if ; it needs time. If so, send it the RUN message. ; SysTLoop MOVE.L (A3)+,D0 ;get DCE handle BEQ.S NextTSys ;if NIL, this drivers not installed MOVE.L D0,A0 ;need it in an A-reg MOVE.L (A0),A1 ;get the DCE ptr in A1 ; ; BTST #DNeedTime,DCtlFlags(A1) ;does it need time at all? ; BEQ.S NextTSys ;if not, go check the next one ; BTST #DOpened,DCtlFlags+1(A1) ;is it opened? ; BEQ.S NextTSys ;if not, go check next one ; BTST #DrvrActive,DCtlFlags+1(A1) ;is it active? ; BNE.S NextTSys ;if so, don't call it MOVE.W DCtlFlags(A1),D0 ;get the flags AND #$20A0,D0 ;get rid of the don't care bits CMP.W #$2020,D0 ;in the right state (see above) BNE.S NextTSys ;if not, skip ; ; it might need time so check out the elapsed time from the last time it was called ; MOVEQ #0,D0 ;zero high part of D0 MOVE.W DCtlDelay(A1),D0 ;get delay tick count BEQ.S DoItNow ;if zero, always do it MOVE.L Ticks,D2 SUB.L DCtlCurTicks(A1),D2 CMP.L D0,D2 BCS.S NextTSys ; ; its time to give it a call ; MOVE.L Ticks,DCtlCurTicks(A1) ;update last called time DoItNow BSR SendRunMsg ;send it the "RUN" message ; ; here is the bottom of the main loop. See if there are any more entries to process ; CMP.L UTableBase,A4 BNE.S NotSWindow CMP UnitNtryCnt,D4 BNE.S NotSWindow NextTSys SUBQ.W #1,D3 BGT.S SysTLoop ;loop if there's more to do _SetPort ;restore it CLR.B TaskLock ;flag that we're done TaskDone MOVEM.L (SP)+,D2-D4/A3-A4 ;restore work registers RTS ;return to caller ; ; PROCEDURE SystemMenu(menuResult: LongInt); ; ; Feeds a menu event to the open driver that owns a menu matching the ID ; or, if MBarEnable is set, just feed it to the topMost window ; SystemMenu MOVE.L 4(SP),D1 ;get the menuResult parameter SWAP D1 ;get theMenu in low part CMP.W #kHMHelpMenuID,D1 ; is it help menu id? BEQ @HandleHelpMenu ; then handle it. CMP.W #-kTSMSystemMenuID,D1 ; is it input method menu (pencil) BEQ @HandleInputMethodMenu ; then handle it. CMPI.W #kKeyboardMenuID,D1 ; is this keyboard ? BEQ @HandleKeyboardMenu ; then handle it BRA @SpecialMenusHandled ; begin roll-in __SystemMenuPatch from TSMDispatch CSS <11> @HandleInputMethodMenu SWAP D1 ;put the high word back MOVE.L D1,-(SP) ;move it onto the stack PEA (SP) ;push the address MOVE #35,D0 _TSMDispatch ;and send it to the input method ADDQ #4,SP ;get rid of space for menuresult MOVE.L (SP)+,(SP) ;strip parameter RTS ;return to caller ; end roll-in __SystemMenuPatch from TSMDispatch CSS ; begin roll-in ptchSystemMenu from ScriptMgrSystemMenusPatch CSS <11> @HandleKeyboardMenu SWAP D1 ;put the high word back MOVE.L D1,-(SP) ;move it onto the stack IMPORT HandleKeyboardMenu JSR HandleKeyboardMenu ;go handle the keyboard menu. MOVE.L (SP)+,(SP) ;strip parameter RTS ;return to caller ; end roll-in ptchSystemMenu from ScriptMgrSystemMenusPatch CSS <11> ; begin roll-in HMSystemMenuPatch patch <11> @HandleHelpMenu MOVE.L ExpandMem,A0 ; point to the expand mem ptr <11> MOVE.L ExpandMemRec.emHelpGlobals(A0),A0 ; A0 = global ptr <11> MOVE.W #kHMHelpMenuID,hmgSystemMenuID(A0) ; set the global system menu ID to our help menu ID <11> SWAP D1 ; fix menuResult, so the item is in low word <11> MOVE.W D1,hmgSystemMenuItem(A0) ; and put the item into our system menu item global <11> CLR.W -(SP) ; do a HiliteMenu(0); for apps that only call this <11> _HiliteMenu ; for their own menus [Nisus, Quicken, Adobe apps, etc.] <11> MOVE.L 4(SP),D1 ;get the menuResult parameter again <11> SWAP D1 ;get theMenu in low part again <11> ; end roll-in HMSystemMenuPatch patch <11> @SpecialMenusHandled MOVEM.L A2-A3,-(SP) ;preserve work registers MOVE.W MBarEnable,D0 ;who owns the menuBar? BEQ.S @1 ;if the app, we're cool MOVE.W D0,D1 ;get ID in D1 @1 MOVE.L UTableBase,A2 ;point to base of driver table MOVE.W UnitNtryCnt,D2 ;get number of entries ; SMLoop MOVE.L (A2)+,D0 ;fetch DCE handle BEQ.S NextSM ;if none, skip MOVE.L D0,A0 ;get handle in A0 MOVE.L (A0),A1 ;and ptr in A1 ; BTST #DOpened,DCtlFlags+1(A1) ;is it open? BEQ.S NextSM ;if not, don't consider it CMP.W DCtlMenu(A1),D1 ;does this one own it? BNE.S NextSM ;if not, try the next one ; ; we found one that owns the menu, so send it the message ; FeedToOrn MOVE.L 12(SP),A3 ;get param into A3 MOVEQ #67,D0 ;signal "menu" call BSR SendDCommon ;send the message BRA.S DoneSM ;return TRUE ; ; loop till we find one ; NextSM SUBQ.W #1,D2 BGT.S SMLoop ;loop till driver table's exhausted DoneSM MOVEM.L (SP)+,A2-A3 ;restore work registers MOVE.L (SP)+,(SP) ;strip parameter RTS ;return to caller ; FUNCTION SystemEdit(editCmd: INTEGER): BOOLEAN; ; ; SystemEdit is called by an application when it receives an edit request ; from the user (usually through a menu). If the topMost window is a system ; window, SystemEdit returns true and sends the corresponding desk accessory ; an edit control call; otherwise SystemEdit returns false. SystemEdit CLR.W 6(SP) ;assume false SUBQ #8,SP ;make room for function result PEA 4(SP) ;push pointer to buffer on stack _GetPort ;remember the port _FrontWindow ;get the frontWindow MOVE.L (SP)+,D0 ;is there one? BEQ.S DoneSEdit ;if not, we're done ; There is a front window, so send it the edit message MOVE.L D0,A0 BSR SearchWindow ;get DCE ptr in A1 BNE.S DoneSEDit ;branch if unsuccessful MOVE.W 8(SP),D0 ;get edit index ADD.W #68,D0 ;offset it to indicate edit BSR SendDCommon ;send the message ADDQ.B #1,10(SP) ;flag it as true ; all done with SystemEdit DoneSEdit _SetPort ;restore the port BRA.S TwoByteExit ;use common code to exit ; FUNCTION OpenDeskAcc(theName: Str255): INTEGER; ; opens a desk accessory and shows its window, returning the refCon. ; If the refCon = 0, it was a bad open. OpenDeskAcc CLR.W 8(SP) ;return 0 as the default SUB #$32,SP ;get 32 bytes for a parameter block MOVE.L $36(SP),IOFileName(SP) ;set up name CLR.W IODrvNum(SP) ;use default volume MOVE.W #$0040, IOFileType(SP) ;clear type byte, special permissions to ID OpenDeskAcc CLR.L IOOwnBuf(SP) ;use system buffer MOVE.L SP,A0 ;point to it _Open ;open the driver BNE.S DoneOpenDAcc ;if an error, don't return refNum MOVE.W IORefNum(SP),D0 ;get the refNum MOVE D0,$3A(SP) ;return the refNum ; figure out the DCE ptr NOT.W D0 ; bitwise complement to get unitnum ASL.W #2,D0 ; multiply by four MOVE.L UTableBase,A1 ; get address of unit table MOVE.L 0(A1,D0.W),A1 ; add in the offset MOVE.L (A1),A1 ; dereference handle ; get the window ptr and, if one exists, show it MOVE.L DCtlWindow(A1),D0 ;get the window ptr BEQ.S DoneOpenDAcc MOVE.L D0,-(SP) MOVE.L D0,-(SP) ;push it twice _SelectWindow _ShowWindow ;show it! DoneOpenDAcc ADD.W #$32,SP ;strip the pBlock MOVE.L (SP)+,(SP) ;strip parameter RTS ; PROCEDURE CloseDeskAcc(refNum: INTEGER); ; close the desk accessory (or driver) with the specified refNum CloseDeskAcc MOVE.W 4(SP),D0 ;get the refNum SUB #$32,SP ;get space for param block MOVE.W D0,IORefNum(SP) ;set up refNum MOVE.L SP,A0 _Close ;close it! ADD #$32,SP ;pop off param block TwoByteExit MOVE.L (SP)+,A0 ADDQ #2,SP JMP (A0) END