; ; File: OSEventMgr.a ; ; Contains: Macintosh OS Event Manager ; ; Written by: Andy Hertzfeld 02-Nov-81 ; ; Copyright: © 1981-1993 by Apple Computer, Inc. All rights reserved. ; ; Change History (most recent first): ; ; 12/13/93 PN Roll in KAOs and Horror changes to support Malcom and AJ ; machines. ; 11/11/93 rab Added the label OldOSEventAvail at the original entry point for ; OSEventAvail. Changed GetOSEvent to bsr to the old entry point ; and bypass the rolled in HelpMgr Patch. This fixes bug# 1123113. ; Also backed out SM7 since it is no longer necessary. ; 5/18/93 rab Fix Radar #1082829. Change GetOSEvent so that it doesn't do ; smgrpostmunging if smgrCore hasn't been set up (= -1). ; 12/30/92 rab Made a change to InitEvents so that it does nothing if the ; EventQueue has already been set up. This keeps DiskInsertEvents ; from getting lost if the boot fails. ; 12/16/92 SWC Moved InitEvents here from StartBoot. ; 12/09/92 HI Modified the HelpMgr patch code in OSEventAvail to check for the ; emIsDragging field of ExpandMem; if set, then the patch is ; bypassed. This prevents HelpMgr from removing/displaying another ; help balloon and altering the WMgrPort's clipRgn, penPat, and ; penMode and allows DragTheRgn to properly remove the drag region. ; (Hoon Im) ; 6/22/92 RB Rolled-in the Help Manager patch to OSEventAvail from ; BalloonPthc28.a, HMOSEventAvailPatch. ; 6/12/92 CS Roll-in Reality Changes: ; <6> 6/12/92 FM Change the BigJmp to SMgrPostMunging to be a jsr through the ; internal scriptmgr vector. ; 5/21/92 kc Append "Trap" to the names of ; PostEvent,GetOSEvent,OSEventAvail,Enqueue and Dequeue to avoid ; name conflict with the glue. ; 5/17/92 kc Remove "With PmgrRec." ; <5> 4/27/92 JSM Get rid of conditionals: hasIdle and isUniversal are always ; true, onMac is always false. This file now has no conditionals. ; <4> 8/30/91 JSM Cleanup header. ; <3> 6/12/91 LN Changed #include 'HardwareEqu.a' to 'HardwarePrivateEqu.a' ; <2> 3/29/90 MSH Add universal run time test for IdleUpdate call. ; <1.6> 11/1/89 MSH Rolling in changes from HcMac Reality sources: Pmgr equates now ; in record format. ; <1.5> 8/22/89 SES Removed references to nFiles. ; <1.4> 3/31/89 MSH Bump LastAct if an event is available. ; <1.3> 2/21/89 PKE Rearranged GetOSEvent so DeleteEvt doesn't return through ; SMgrPostMunging (this also fixes a FlushEvents bug caused by ; BigJMP), and so A0 is correctly set up when GetOSEvent returns ; through SMgrPostMunging. ; <1.2> 1/16/89 GGD Added a scratch register parameter to the BigJMP macro calls ; since it will be needed when they change to use PC relative ; addressing. ; <1.1> 11/10/88 CCH Fixed Header. ; <1.0> 11/9/88 CCH Adding to EASE. ; <1.4> 10/27/88 PKE added support for script manager ; <¥1.3> 9/23/88 CCH Got rid of inc.sum.d and empty nFiles ; <1.2> 9/8/88 MSH New version of sleep/idle support. ; <1.1> 4/18/88 CSL Add support for SLEEP & IDLE in PostEvent ; <1.0> 2/10/88 BBM Adding file for the first time into EASEÉ ; 12/12/86 EMT Shuffle keyboard globals for Excel. Affects OSEventMgr.a, kbd.a, ; nSysEqu.a ; 10/9/86 bbm Modified to mpw aincludes. ; 9/24/86 EMT Changed interrupt mask in PostEvent and company to disable SCC ; as well as VIA interrupts. ; 7/28/86 EMT Changed to use long word NewKeyLast instead of KeyLast for Apple ; Desktop Bus machines ; 2/19/86 BBM Made some modifications to work under MPW ; 10/28/85 DLD Changed FlushEvents to put a -1 into LastSPExtra for FontMGR ; 7/24/85 RDC Changed interrupt level settings to use equate Added spearate ; include statement for HWequ file (no longer in systlqk.sym) ; 6/7/85 JTC Make results of os routines long. <07Jun85> ; 3/3/85 LAK Don't flush events masked out by FlEvtMask in FlushEvents (this ; is a new mask, initialized at SysInit time to $FF7F, i.e., all ; events except DIP events). This is an attempt to correct the ; problem that -1 is a common parameter given to FlushEvents at ; the start of a program, even though a flush of DIP is probably ; not intended. ; 1/31/85 LAK Removed false RTE. ; 1/23/85 LAK Adapted for new equate files. Added equate for NoEvtAvail ; (equate was deleted from SysErr.Text) ; 8/17/83 LAK PostEvent now uses EvtBufCnt instead of hardwired EvtMax. ; 2/22/83 LAK made all routines observe Pascal regsave conventions. ; 1/3/83 AJH Got rid of update event, changed names of GetNextEvent and ; EventAvail ; 10/16/82 LAK Update events return 0 in D0 now for GetNextEvent and ; EventAvail. ; 10/1/82 LAK A0 saved over checkupdate call now . . . ; 7/26/82 LAK FLUSHEVENTS returns # of event type it stopped on, if any Added ; update events . . . ; 6/9/82 LAK Moved keyboard auto-repeat function here ; ; ; This is the event manager for the MacIntosh Operating ; system. It manipulates events on the system event queue. ; Its major routines are "PostEvent" which adds an event to the ; event queue, and "GetNextEvent" which returns the next event ; in the queue. PostEvent may be called from an interrupt (level 1) ; or completion routine; all other routines in the event ; manager must be called from the main thread of execution. There are ; two other Event Manager routines, "FlushEvents" and "EventAvail", ; giving a total of 4 routines. Some of these routines call other ones, ; and all are accessible via operating system calls: ; ; os call --> GetNextEvent os call --> FlushEvents ; | ; v ; os call --> EventAvail ; | ; (auto-key event generation) ; | ; v ; os call --> PostEvent ; ; The Event Manager manages its own private buffer to get storage for the ; event queueing elements. It does this because PostEvent runs at interrupt ; level and thus cannot call the standard storage allocator. ; BLANKS ON STRING ASIS LOAD 'StandardEqu.d' INCLUDE 'HardwarePrivateEqu.a' INCLUDE 'UniversalEqu.a' INCLUDE 'ScriptPriv.a' INCLUDE 'Balloons.a' ; INCLUDE 'BalloonsPriv.a' ; INCLUDE 'PowerPrivEqu.a' ; INCLUDE 'Processes.a' Events PROC EXPORT EXPORT InitEvents,PostEventTrap,GetOSEventTrap,OSEventAvailTrap,FlushEvents,NewEMFunction IMPORT EnqueueTrap,DequeueTrap,SMgrPostMunging NoEvtAvail EQU -1 ; (moved from SysErr.Text) EvtOffset EQU 6 ; event record offset from start of ; event queue element ;_______________________________________________________________________ ; ; Routine: InitEvents afe0 ; ; Arguments: D0 (input) -- number of elements in the event queue ; D0 (output) -- result code ; ; Function: This routine initializes the event queue to the size ; specified in D0. ; ; Other: uses D0,D1,D2,A0,A1 ;_______________________________________________________________________ InitEvents move.w EventQueue,d2 ; check the first word of the EventQ bge.s @exit ; if ­-1 it's set up, leave it alone MOVE.W D0,D2 MOVEQ #EvtQBlkSize,D0 MULU D2,D0 MOVE.L D0,D1 ; save a copy of the size _NewPtr ,SYS,CLEAR ; get memory for storage allocator LEA EvtBufCnt,A1 SUBQ #1,D2 ; set up lo mem event buffer count (-1) MOVE.W D2,(A1) ; EvtBufCnt CLR.L -(A1) ; EventQueue QTail CLR.L -(A1) ; EventQueue QHead CLR.W -(A1) ; EventQueue QFlags MOVE.L A0,-(A1) ; SysEvtBuf ; fill buffer with all ones @InitEvLoop NOT.W (A0)+ ; 0000 -> FFFF SUBQ #2,D1 ; more to do? BNE.S @InitEvLoop ; size must have been divisible by 4 MOVE.W #$FFEF,-(A1) ; SysEvtMask - enable all events except key up CLR.W KeyLast ; initialize keyboard repeat stuff @exit RTS ; ;_______________________________________________________________________ ; ; Routine: PostEvent b010 ; ; Arguments: A0 (input) -- event number (16-bit) ; D0 (input) -- event message (32-bit) ; D0 (output) -- result: 0=event posted, 1=not posted ; A0 (output) -- ptr to event queue element if posted (used ; internally by Eventavail) ; ; Function: This routine adds an event to the system event queue. The ; specified eventnumber and event message are logged for the ; event. The current time, mouse position, state of command ; key, option key, shift key, alpha lock key, and mouse button ; are additional event queueing elements included in ; each event. An event is only posted if enabled by the System ; Event Mask; if not enabled, a result code of 1 is returned. ; This routine will delete the first element of the event queue ; (the oldest element), if the queue is full, to make room for ; the new event: this guarantees that an enabled event will be ; posted. ; ; So that events of the same type are received and ; logged in correct time order of occurrance, the calling routine ; should disable further interrupts from the same source until ; the event has been posted. This works since each event type ; typically has but one source. All interrupts are disabled ; during this routine, first to guarantee the integrity of the ; free buffer allocation and second to enforce the time-ordering ; of events. Currently, only level 1 interrupts are masked because ; SCC interrupts do not generate any events; if that changes (e.g., ; and SCC system error event is defined), SCC interrupts would ; also have to be masked. ; ; PostEvent can be called by EventAvail to post an auto-key event; ; it is never called to post an update event. ; ; Calling sequence: MOVE.W #eventnumber,A0 ; MOVE.L #message,D0 ; _PostEvent ; ; Other: uses D0,D1,D2,A0,A1 ;_______________________________________________________________________ PostEventTrap with PowerDispRec TestFor SupportsIdle BEQ.S @notsupported MOVE.L D0,-(SP) _UsrIdleUpdate ; user update activity log MOVE.L (SP)+,D0 @notsupported MOVE.W SysEvtMask,D2 ; system event mask MOVE.W A0,D1 ; event number BTST D1,D2 ; is this event enabled? BNE.S GetFreeOne MOVEQ #EvtNotEnb,D0 ; if not, skip all this stuff RTS GetFreeOne MOVE SR,-(SP) ; save interrupt state MOVE.L D0,-(SP) ; event message MOVE.W A0,-(SP) ; event number MOVE.L SysEvtBuf,A0 ; get address of system event buffer ADDQ.L #EvtOffset,A0 ; point to event record ($FFFF=free) MOVEQ #EvtQBlkSize,D0 ; for speed MOVEQ #-1,D1 ; ibid SUB D0,A0 ; back pointer down one MOVE.W EvtBufCnt,D2 ; event buffer count - 1 ORI #HiIntMask,SR ; no interrupts, please GetEbufLoop ADD D0,A0 ; bump to next event queue element CMP.W EvtNum(A0),D1 ; is this element free? DBEQ D2,GetEbufLoop ; loop till we get one or no more left LEA EventQueue,A1 ; point A1 to queue header BEQ.S GotEvtElement ; Z-flag set from CMP only ; no more event buffers available. remove first queue element for a wraparound ; (queue elements are added at the end of the queue, so the first element ; has been around the longest . . .); there must be >1 elements in the queue ; since there are no free elements and given that 29 interrupting processes cannot ; grab elements and not post them into the queue. MOVE.L QHead(A1),A0 ; point A0 to first queue element MOVE.L QLink(A0),QHead(A1) ; special case delete: first element ; of a queue of length > 1 ; now A0 points to a free element ADDQ.L #EvtOffset,A0 ; point to event record part ; We got an event queueing element, so fill in the system info and queue it up GotEvtElement MOVE.W (SP)+,EvtNum(A0) ; set up the event number MOVE.L (SP)+,EvtMessage(A0) ; set up the message BSR.S FillRecord ; fill out the rest of the record SUBQ.L #EvtOffset,A0 ; and point to start of queue element MOVE #EvType,QType(A0) ; set up the q-element type field JSR EnqueueTrap ; let queueing routines queue it up MOVE (SP)+,SR ; restore interrupt state MOVEQ #0,D0 ; zero result code RTS ; and return ; FillRecord fills out the standard fields in an event record pointed to by A0 FillRecord MOVE.L Ticks,EvtTicks(A0) ; fill in the current time MOVE.L Mouse,EvtMouse(A0) ; and the current mouse point MOVE KeyMap+6,D1 ; get meta-key states ROL.W #1,D1 ; rotate around MOVE.B D1,EvtMeta(A0) ; update metakey field MOVE.B MBState,EvtMBut(A0) ; get mouse button state EndWith RTS ;_______________________________________________________________________ ; ; Routine: OSEventavail b09c ; ; Arguments: A0 (input) -- pointer to user event record (32-bit) ; D0 (input) -- set of events desired (event mask) ; D0 (output) -- 0=non-null event returned, -1=null event ; returned ; A0 (output) -- pointer to user event record ; A1 (output) -- pointer to event queue element when D0=0 ; (used internally by GetNextEvent) ; ; Function: This routine polls for availability of certain types of events. ; The user-specified event record format is identical to that of ; the queue element, except for the queue header fields. If no ; events are available, the null event is returned along with ; a -1 result code in D0. ; ; EventAvail is also called by GetNextEvent. ; ; Calling sequence: MOVE.W #EventMask,D0 ; LEA EventBuffer,A0 ; _EventAvail ; ; Other: uses D0,D1,D2,A0,A1 ;_______________________________________________________________________ OSEventAvailTrap ANDI.L #$FFFF,D0 OSEventAvailSkippingAndi with PowerDispRec MOVEM.L A0-A1/D0-D2,-(SP) ; we need to save these regs MOVE.L ExpandMem,A0 ; point to the expand mem ptr TST.B ExpandMemRec.emIsDragging(A0) ; called from DragTheRgn? BNE.S @DoNothing ; yes, skip HelpMgr patch code MOVE.L ExpandMemRec.emHelpGlobals(A0),A0 ; A0 = global ptr TST.B hmgWhatIs(A0) ; is Balloon help mode on? BEQ.S @DoNothing ; no, let's not scan for a content window TST.W hmgOSEventReentrantCount(A0) ; test the reentrant count BNE.S @DoNothing ; do nothing on the reentrant case ST hmgOSEventReentrantCount(A0) ; say that we're busy ; from BalloonExtensions.a: ptchHMCallTrackerInContext SUBQ #$8, SP SUBQ #$2, SP PEA.L $2(SP) MOVEQ.L #-$1, D0 ; like _GetFrontProcess but not quite MOVE.L D0, -(SP) MOVE #$39, -(SP) _OSDispatch TST (SP)+ BNE.B @wasError SUBQ #$2, SP PEA.L $2(SP) _WakeUpProcess TST (SP)+ BNE.B @wasError SUBQ #$2, SP MOVE #$FC, D0 ; from Balloonptch28.p: HMBalloonBulk _Pack14 TST (SP)+ @wasError AddQ #$8, SP ; from BalloonExtensions.a: ptchHMGetHelpGlobal MOVE.L ExpandMem,A0 ; point to the expand mem ptr MOVE.L ExpandMemRec.emHelpGlobals(A0),A0 ; return the global ptr on the stack CLR hmgOSEventReentrantCount(A0) @DoNothing MOVEM.L (SP)+,A0-A1/D0-D2 ; restore 'em, rb, end OldOSEventAvail ; LEA EventQueue,A1 ; get address of event queue ; Since PostEvent could dequeue the first element at any time, the event you ; are on may suddenly be recycled and you may end up dequeueing a different event ; or suddenly find yourself at the end of the queue when you were just at the ; beginning. By disabling interrupts during the search, this is avoided. MOVE SR,-(SP) ; save interrupt state ORI #HiIntMask,SR ; no event-generating interrupts MOVE.L QHead(A1),D1 ; get address of 1st element BEQ.S TstAutoEvent ; if nil, check for auto events EventALoop MOVE.L D1,A1 ; get pointer into A-reg MOVE EvtNum+EvtOffset(A1),D1 ; get its event number BTST D1,D0 ; is it one we want? BNE.S GotEventAvail ; if so, we got one! MOVE.L QLink(A1),D1 ; follow the link to the next one BNE.S EventALoop ; if we got one, check it out ; there wasn't an event in the queue for us, so check for auto events TstAutoEvent AND.W SysEvtMask,D0 ; figure in system mask for pseudo-evts BTST #AutoKeyEvt,D0 ; do we want this kind? BEQ.S NoEventAvail ; go on if not MOVE.W HiKeyLast, D0 ; SWAP D0 ; MOVE.W KeyLast, D0 ; TST.L D0 ; key down to autorepeat? BEQ.S NoEventAvail ; if not, return null event MOVE.L Ticks,D1 ; check first threshold MOVE.L D1,D2 SUB.L KeyTime,D1 CMPI.L #$8000,D1 BGE @skip CMP KeyThresh,D1 BLT.S NoEventAvail ; br if not time yet @skip SUB.L KeyRepTime,D2 ; check second threshold CMP KeyRepThresh,D2 BLT.S NoEventAvail ; br if not time yet MOVE.L Ticks,KeyRepTime ; repeat it: first note the time MOVE.L A0,-(SP) ; save pointer to user's buffer MOVE #AutoKeyEvt,A0 ; get event number ; D0 already contains the correct event message BSR PostEventTrap ; go post it MOVE.L A0,A1 ; get pointer to event queue element MOVE.L (SP)+,A0 ; restore pointer to user's buffer ; and return the event GotEventAvail MOVE (SP)+,SR ; restore interrupt state MOVEQ #(EvtBlkSize/4),D0 ; get size of evt record in longwords MOVEM.L A0-A1,-(SP) ; preserve regs ADD.L #EvtOffset,A1 ; bump to record part of event element TestFor SupportsIdle BEQ.S @notsupported MOVE.L D0,-(SP) _IdleUpdateDispatch ; set for overall activity MOVE.L (SP)+,D0 @notsupported @1 MOVE.L (A1)+,(A0)+ ; move it into user's buffer SUBQ #1,D0 BNE.S @1 ; loop till done MOVEM.L (SP)+,A0-A1 ; get regs back RTS ; D0 is zero ; there wasn't any event available so return the null event in the users event ; record and a flag in D0 NoEventAvail BSR.S FillRecord ; fill in record for null events MOVE (SP)+,SR ; restore interrupt state CLR.W EvtNum(A0) ; return the null event CLR.L EvtMessage(A0) ; zero message for null events MOVEQ #NoEvtAvail,D0 ; and D0 non-zero EndWith RTS ;_______________________________________________________________________ ; ; Routine: GetOSEvent b1aa ; ; Arguments: A0 (input) -- pointer to user event buffer (32-bit) ; D0 (input) -- type of event desired (event mask) ; D0 (output) -- 0=non-null event returned, -1=null event ; returned ; ; Function: This routine returns the next event in the system event queue. ; The returned event is dequeued, thereby freeing up the space ; which holds that queue element. If no events of the types ; enabled by the mask exist, the null event is returned. ; ; Calling sequence: MOVE.W #EventMask,D0 ; LEA EventBuffer,A0 ; _GetNextEvent ; ; Other: uses D0,D1,D2,A0,A1 ;_______________________________________________________________________ GetOSEventTrap ANDI.L #$FFFF,D0 GetOSEventSkippingAndi BSR.S OldOSEventAvail ; first find the event BNE.S @EventDone ; don't dequeue null or update events MOVE.L A0,-(SP) ; save user's event record ptr MOVE.L A1,A0 ; pointer to event queue element LEA EventQueue,A1 ; A1 points to the queue BSR.S DeleteEvt ; get rid of it MOVE.L (SP)+,A0 ; restore user's event record ptr ; (needed by SMgrPostMunging) MOVEQ #0,D0 ; exit with result code 0 ; Check for ScripMgr related events and do some processing on them movem.l a0/a2,-(sp) ; save a0/a2 GetSMgrCore a2 ; load SMgr globals. cmpa.l #-1,a2 ; see if smgrCore is set up yet beq.s @tooEarly ; bail out if it isn't move.l smgrRecord.sVectSMgrPostMunging(a2),a2 ; get SMgrPostMunging <4/26/88ldc> jsr (a2) ; Expects an EventPtr in a0 @tooEarly movem.l (sp)+,a0/a2 ; restore a0/a2 @EventDone rts DeleteEvt JSR DequeueTrap ; dequeue it (D0 destroyed) MOVE #$FFFF,EvtNum+EvtOffset(A0) ; and release its storage RTS ;_______________________________________________________________________ ; ; Routine: FlushEvents b1ea ; ; Arguments: D0 (input) -- low word: events to remove (event mask) ; high word: events on which to stop (event mask) ; D0 (output) -- event type of event which terminated search ; ; Function: This routine removes events of type specified by the caller. On ; entry, D0 contains a long word of two 16-bit event masks. The ; low-order 16 bits contains a mask of events to remove, and the ; high-order 16 bits contains a mask of events that, once ; encountered, terminate the event removal process. ; ; Calling sequence: MOVE.L #EventMasks,D0 ; _FlushEvents ; ; Other: uses D0,D1,D2,A0,A1 ;_______________________________________________________________________ FlushEvents MOVE SR,-(SP) ; save interrupt state MOVEM.L D3-D4,-(SP) ; preserve Pascal regs ; put a -1 into LastSPExtra (long) for the FontMGR (fixes a bug when under Switcher). MOVEQ #-1,D1 ; <28-Oct-85> MOVE.L D1,LastSPExtra ; <28-Oct-85> MOVE.L D0,D1 SWAP D1 ; mask of events to stop on MOVE.W D0,D4 ; mask of events to remove AND.W FlEvtMask,D4 ; only flush masked events <03Mar85> LEA EventQueue,A1 ; A1 points to the queue ; Since PostEvent could dequeue the first element at any time, the event you ; are on may suddenly be recycled and you may end up dequeueing a different event ; or suddenly find yourself at the end of the queue when you were just at the ; beginning. By disabling interrupts during the search, this is avoided. ORI #HiIntMask,SR ; no event-generating interrupts MOVE.L QHead(A1),D3 ; get pointer to first element BEQ.S AllFlushed ; if nothing there, we're done FEventLoop MOVE.L D3,A0 ; get pointer into A-reg MOVE.L QLink(A0),D3 ; save the link MOVE EvtNum+EvtOffset(A0),D2 ; get number of current event BTST D2,D1 ; is it in the stop mask? BNE.S FlushStop ; if so, stop BTST D2,D4 ; is it one to delete? BEQ.S NoFlush ; if not, skip BSR.S DeleteEvt ; otherwise, delete it (clobbers D0) NoFlush TST.L D3 ; any more to do? BNE.S FEventLoop ; if so, loop AllFlushed MOVEQ #0,D2 ; exit with 0 result code FlushStop MOVEM.L (SP)+,D3-D4 ; restore regs MOVE D2,D0 ; exit with number of event we stopped EXT.L D0 ; make result long <07Jun85> MOVE.W (SP)+, SR ; on as our result RTS NewEMFunction ; b232 MoveA.L (A7)+, A1 CmpI #$1, D0 BEQ.B L13 CmpI #$2, D0 BEQ.B L14 CmpI #$3, D0 BEQ.B L15 MoveQ.L #$C, D0 DC.W $A9C9 L13 Move.L (A7)+, D0 MoveA (A7)+, A0 Move.L A1, -(A7) Bsr GetFreeOne Bra.B L16 L14 MoveA.L (A7)+, A0 Move.L (A7)+, D0 Move.L A1, -(A7) Bsr OSEventAvailSkippingAndi Not.L D0 AndI.L #$101, D0 Bra.B L16 L15 MoveA.L (A7)+, A0 Move.L (A7)+, D0 Move.L A1, -(A7) Bsr GetOSEventSkippingAndi Not.L D0 AndI.L #$101, D0 L16 Move.L D0, $4(A7) Rts END