sys7.1-doc-wip/OS/OSEventMgr.a

581 lines
22 KiB
Plaintext

;
; 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):
;
; <SM12> 12/13/93 PN Roll in KAOs and Horror changes to support Malcom and AJ
; machines.
; <SM11> 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.
; <SM10> 5/18/93 rab Fix Radar #1082829. Change GetOSEvent so that it doesn't do
; smgrpostmunging if smgrCore hasn't been set up (= -1).
; <SM9> 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.
; <SM8> 12/16/92 SWC Moved InitEvents here from StartBoot.
; <SM7> 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)
; <SM6> 6/22/92 RB Rolled-in the Help Manager patch to OSEventAvail from
; BalloonPthc28.a, HMOSEventAvailPatch.
; <SM5> 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.
; <SM4> 5/21/92 kc Append "Trap" to the names of
; PostEvent,GetOSEvent,OSEventAvail,Enqueue and Dequeue to avoid
; name conflict with the glue.
; <SM3> 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…
; <C517> 12/12/86 EMT Shuffle keyboard globals for Excel. Affects OSEventMgr.a, kbd.a,
; nSysEqu.a
; <C206> 10/9/86 bbm Modified to mpw aincludes.
; <C173> 9/24/86 EMT Changed interrupt mask in PostEvent and company to disable SCC
; as well as VIA interrupts.
; <C89> 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' ;
Events PROC EXPORT
EXPORT InitEvents,PostEventTrap,GetOSEventTrap,OSEventAvailTrap,FlushEvents
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
;
; 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 <SM9>
bge.s @exit ; if ≠-1 it's set up, leave it alone <SM9>
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 ; <SM9>
;_______________________________________________________________________
;
; Routine: PostEvent
;
; 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 <C173 24Sep86>
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
;
; 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
IMPORT ptchHMGetBalloons ; <SM6> rb, start
IMPORT ptchHMCallTrackerInContext
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? <SM7>
BNE.S @DoNothing ; yes, skip HelpMgr patch code <SM7>
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
JSR ptchHMCallTrackerInContext
@DoNothing
MOVEM.L (SP)+,A0-A1/D0-D2 ; restore 'em, <SM6> rb, end
OldOSEventAvail ; <SM11>
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 <C173 24Sep86>
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? <C517/12Dec86>
BEQ.S NoEventAvail ; go on if not <C517/12Dec86>
MOVE.W HiKeyLast, D0 ; <C517/12Dec86>
SWAP D0 ; <C517/12Dec86>
MOVE.W KeyLast, D0 ; <C517/12Dec86>
TST.L D0 ; key down to autorepeat? <C517/12Dec86>
BEQ.S NoEventAvail ; if not, return null event
MOVE.L Ticks,D1 ; check first threshold
MOVE.L D1,D2
SUB.L KeyTime,D1
CMP KeyThresh,D1
BLT.S NoEventAvail ; br if not time yet
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 <C517/12Dec86>
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
;
; 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 BSR.S OldOSEventAvail ; first find the event <SM11>
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 <SM10>
beq.s @tooEarly ; bail out if it isn't <SM10>
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 <SM10>
@EventDone
rts
DeleteEvt JSR DequeueTrap ; dequeue it (D0 destroyed)
MOVE #$FFFF,EvtNum+EvtOffset(A0) ; and release its storage
RTS
;_______________________________________________________________________
;
; Routine: FlushEvents
;
; 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 <C173 24Sep86>
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
END