<<>> <> <> <> <> <> <> <> DIRECTORY Rope USING [ROPE], ViewerClasses USING [Viewer], ViewerEvents USING [EventProc, EventRegistration, ViewerEvent], ViewerPrivate USING [Severity], UserProfile USING [Boolean]; ViewerEventsImpl: CEDAR MONITOR IMPORTS UserProfile EXPORTS ViewerEvents, ViewerPrivate = BEGIN ROPE: TYPE = Rope.ROPE; EventProcs: TYPE = LIST OF RECORD[proc: ViewerEvents.EventProc, filter: REF, before: BOOL]; ArrayEventProcs: TYPE = ARRAY ViewerEvents.ViewerEvent OF EventProcs; eventProcs: REF ArrayEventProcs ¬ NEW[ArrayEventProcs ¬ ALL[NIL]]; <> Error: PUBLIC SIGNAL [severity: ViewerPrivate.Severity ¬ fatal, msg: Rope.ROPE ¬ NIL] = CODE; UserErrorQuery: PUBLIC ENTRY PROC RETURNS [continue: BOOL ¬ FALSE] = TRUSTED { <> ENABLE UNWIND => NULL; IF UserProfile.Boolean["Viewers.WorldSwapDebug", FALSE] THEN RETURN [FALSE]; }; <> RegisterEventProc: PUBLIC PROC [proc: ViewerEvents.EventProc, event: ViewerEvents.ViewerEvent, filter: REF ¬ NIL, before: BOOL ¬ TRUE] RETURNS [ViewerEvents.EventRegistration ¬ NIL] = { <> IF proc # NIL THEN { key: EventProcs ¬ LIST[[proc, filter, before]]; <> innerRegister: ENTRY PROC = { eventProcs[event] ¬ CONS[[proc, filter, before], eventProcs[event]]; }; innerRegister[]; RETURN [key]; }; }; UnRegisterEventProc: PUBLIC ENTRY PROC [proc: ViewerEvents.EventRegistration, event: ViewerEvents.ViewerEvent] = { <> newHead: EventProcs ¬ NIL; newTail: EventProcs ¬ NIL; who: EventProcs ¬ NIL; WITH proc SELECT FROM ep: EventProcs => { IF ep.first.proc = NIL THEN RETURN; who ¬ ep; }; ENDCASE => RETURN; FOR each: EventProcs ¬ eventProcs[event], each.rest WHILE each # NIL DO IF who.first = each.first THEN { <> IF newTail # NIL THEN newTail.rest ¬ each.rest ELSE newHead ¬ each.rest; who.first.proc ¬ NIL; -- don't let this key be used again! EXIT; } ELSE { <> new: EventProcs ¬ LIST[each.first]; IF newTail # NIL THEN newTail.rest ¬ new ELSE newHead ¬ new; newTail ¬ new; }; ENDLOOP; eventProcs[event] ¬ newHead; }; GetHead: ENTRY PROC [event: ViewerEvents.ViewerEvent] RETURNS [EventProcs] = INLINE { <> RETURN [eventProcs[event]]; }; ProcessEvent: PUBLIC PROC [event: ViewerEvents.ViewerEvent, viewer: ViewerClasses.Viewer, before: BOOL] RETURNS [abort: BOOL ¬ FALSE] = { <> FOR l: EventProcs ¬ GetHead[event], l.rest UNTIL l=NIL DO IF l.first.before = before THEN { filter: REF ¬ l.first.filter; IF filter = NIL OR filter = viewer OR (viewer # NIL AND filter = viewer.class.flavor) THEN { proc: ViewerEvents.EventProc ¬ l.first.proc; IF proc # NIL THEN abort ¬ proc[viewer, event, before ! ABORTED => {abort ¬ TRUE; EXIT}].abort; IF abort THEN RETURN; }; }; ENDLOOP; }; END.