DIRECTORY ViewerInputQueue, Process USING [Detach, DisableTimeout, EnableAborts], Rope USING [ROPE], SafeStorage USING [NewZone], ViewerClasses USING [NotifyProc, Viewer]; ViewerQueueImpl: CEDAR MONITOR LOCKS q USING q: Queue IMPORTS Process, SafeStorage EXPORTS ViewerInputQueue = BEGIN Viewer: TYPE = ViewerClasses.Viewer; ROPE: TYPE = Rope.ROPE; Action: TYPE = ViewerInputQueue.Action; ClientProgrammingError: ERROR = CODE; InternalProgrammingError: ERROR = CODE; zone: ZONE = SafeStorage.NewZone[]; Queue: TYPE = REF QueueObj; QueueObj: PUBLIC TYPE = MONITORED RECORD [ firstEvent: Event _ NIL, pushModel: BOOL, newEvent: CONDITION, notifierRunning: BOOL _ FALSE ]; Event: TYPE = LIST OF ViewerInputQueue.Action; Create: PUBLIC PROC [pushModel: BOOL] RETURNS [queue: Queue] = TRUSTED { queue _ zone.NEW[QueueObj_ [pushModel: pushModel]]; Process.DisableTimeout[@queue.newEvent]; Process.EnableAborts[@queue.newEvent]; RETURN[queue]; }; EnQueue: PUBLIC PROC [q: Queue, action: ViewerInputQueue.Action] = { newEvent: Event _ zone.CONS[first: action, rest: NIL]; InternalEnqueue[q, newEvent]; }; DequeueAction: PUBLIC ENTRY PROC [q: Queue] RETURNS [ViewerInputQueue.Action] = { event: Event; IF q.pushModel THEN RETURN WITH ERROR ClientProgrammingError; WHILE q.firstEvent=NIL DO WAIT q.newEvent ENDLOOP; event _ q.firstEvent; q.firstEvent_ q.firstEvent.rest; RETURN [event.first]; }; Flush: PUBLIC ENTRY PROC [q: Queue, proc: PROC[Action]_ NIL] = { IF proc = NIL THEN q.firstEvent_ NIL ELSE FOR event: Event _ q.firstEvent, event.rest UNTIL event = NIL DO proc[event.first]; ENDLOOP; }; InternalEnqueue: ENTRY PROC [q: Queue, e: Event] = { qEnd: Event; IF q.firstEvent=NIL THEN q.firstEvent_ e ELSE { FOR qEnd_ q.firstEvent, qEnd.rest UNTIL qEnd.rest=NIL DO ENDLOOP; qEnd.rest_ e }; IF q.pushModel THEN { IF q.notifierRunning THEN RETURN; q.notifierRunning_ TRUE; TRUSTED {Process.Detach[FORK Notifier[q]]}; } ELSE NOTIFY q.newEvent }; Notifier: PROC [q: Queue] = { event: Event; UNTIL (event _ Dequeue[q]) = NIL DO ENABLE ABORTED => {Flush[q]; LOOP}; event.first.notify[event.first.viewer,event.first.list]; ENDLOOP; }; Dequeue: ENTRY PROC [q: Queue] RETURNS [event: Event] = { IF NOT q.pushModel THEN RETURN WITH ERROR InternalProgrammingError; IF q.firstEvent=NIL THEN {q.notifierRunning_ FALSE; RETURN[NIL]}; event_ q.firstEvent; q.firstEvent_ q.firstEvent.rest; }; END. ¬ViewerInputQueue.mesa Last Edited by: Pausch, August 15, 1983 9:35 am When input actions to notify procs in the viewer package must be synchronous, they are pushed onto queues and later read off by this package. Each input action is described by a triplet of the notify proc to call, and the viewer and list of REF ANY (from a tip table, menu definition, etc.) to pass to the noify proc. Each queue contains a list of pending events. If pushModel is TRUE, then notifierRunning is a BOOL that indicates whether or not a process is currently processing an event. (notifierRunning is ignored if NOT pushModel. If NOT pushModel, then newEvent is a CONDITION on which a client process may wait for the next event to occur. (newEvent is ignored if pushModel). Flushes all pending button presses and menu selections in the context of q. This procedure can be called, e.g., when some illegal actions suggests the user is confused an further mouse-ahead should be ignored. Proc will get called for each Action in the queue, to allow cleanup, NOTIFY's, etc. Adds another event e to the end of q's event list, and set a notifier running again if there wasn't one. Note that the caller of this procedure does the NEW of the Event, outside the monitor, but leaves the rest field NIL to be assigned by this procedure. This process is not under the queue monitor. There are exactly one or zero notifiers per queue, so that no more than one event happens at a time. FORKed from InternalEnqueue. should be doing greying type things with the buttons ... should be doing UNgreying type things with the buttons ... Removes the first event on q's event list, returning NIL if list empty. Called from Notifier. Κr– "cedar" style˜Jšœ™J™/šΟk ˜ Jšœ˜Jšœœ(˜5Jšœœœ˜Jšœ œ ˜Jšœœ˜)J˜—Jš œœœœœ ˜5J˜š˜Jšœ˜J˜—Jšœ˜ J˜Jšœœ˜$Jšœœœ˜Jšœœ˜'Jšœœœ˜%Jšœœœ˜'Jšœœ˜#J˜JšœοΟcΒ™±J™J˜Jšœœœ ˜š œ œœ œœ˜*Jšœœ˜Jšœ œ˜Jšœ  œ˜Jšœœ˜Jšœ˜J˜—Jšœœœœ˜.J˜š Οnœœœ œœœ˜HJšœ œ#˜3Jšœ(˜(Jšœ&˜&Jšœ˜Jšœ˜—J˜šŸœœœ0˜DJšœœœ˜6J˜J˜J˜—š Ÿ œœœœ œ˜QJšœ ˜ Jš œ œœœœ˜=Jš œœœœ œ˜2Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜—J˜š Ÿœœœœœ œ˜@Jšœ§™§Jšœœœ˜$š œœ)œ œ˜EJšœ˜Jšœ˜—Jšœ˜—J˜šŸœœœ˜4Jšœ€™€Jšœ ˜ šœœ˜Jšœ˜—šœ˜Jš œœ œœœ˜AJšœ ˜ Jšœ˜—šœ œ˜Jšœœœ˜!Jšœœ˜Jšœœ˜+Jšœ˜—Jšœœ ˜Jšœ˜—J˜šŸœœ˜Jšœ―™―J˜ šœœ˜#Jšœœœ˜#Jšœ8™8J˜8Jšœ:™:Jšœ˜—Jšœ˜—J˜šŸœœœ œ˜9Jšœ^™^Jš œœ œœœœ˜CJš œœœœœœ˜AJšœ˜Jšœ ˜ J˜J˜—Jšœ˜—…— Zx