ViewerEventsImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Doug Wyatt, March 30, 1985 2:48:18 pm PST
Russ Atkinson (RRA) May 6, 1986 11:57:28 pm PDT
DIRECTORY
FS USING [ComponentPositions, Error, ExpandName],
Rope USING [ROPE, Run, SkipTo],
ViewerClasses USING [Viewer],
ViewerEvents USING [EventProc, EventRegistration, ViewerEvent],
ViewerPrivate USING [Severity],
UserProfile USING [Boolean, GetProfileName, ProfileChanged];
ViewerEventsImpl: CEDAR MONITOR
IMPORTS FS, Rope, 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]];
Exports to ViewerPrivate
Error: PUBLIC SIGNAL [severity: ViewerPrivate.Severity ← fatal, msg: Rope.ROPENIL] = CODE;
UserErrorQuery: PUBLIC ENTRY PROC RETURNS [continue: BOOLFALSE] = TRUSTED {
RRA: formerly used to query user as to whether or not to continue when an uncaught error occurs in a paint or TIP notification procedure (not currently used, perhaps this entire module should go away).
ENABLE UNWIND => NULL;
IF UserProfile.Boolean["Viewers.WorldSwapDebug", FALSE] THEN RETURN [FALSE];
};
Exports to ViewerEvents
RegisterEventProc: PUBLIC ENTRY PROC [proc: ViewerEvents.EventProc,
event: ViewerEvents.ViewerEvent, filter: REFNIL, before: BOOLTRUE] RETURNS [ViewerEvents.EventRegistration] = {
Monitorized CONS onto the head of the list. We don't check for duplicates, and the unique key passed back is the new entry itself.
RETURN [eventProcs[event] ← CONS[[proc, filter, before], eventProcs[event]]];
};
UnRegisterEventProc: PUBLIC ENTRY PROC [proc: ViewerEvents.EventRegistration, event: ViewerEvents.ViewerEvent] = {
Copy the previous list without the given entry. We copy this to avoid needing to monitorize ProcessEvent (who needs the hassle, after all).
newHead: EventProcs ← NIL;
newTail: EventProcs ← NIL;
FOR each: EventProcs ← eventProcs[event], each.rest WHILE each # NIL DO
IF proc # each THEN {
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] = {
This guarantees that the sampling is atomic.
RETURN [eventProcs[event]];
};
ProcessEvent: PUBLIC PROC [event: ViewerEvents.ViewerEvent, viewer: ViewerClasses.Viewer, before: BOOL] RETURNS [abort: BOOLFALSE] = {
Notice that we do not have to monitorize this processing since the sampling of GetHead[event] is atomic and the list is never changed by smashing elements.
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;
};
User profile handling
NoticeProfileChanges: ViewerEvents.EventProc = {
[viewer: ViewerClasses.Viewer, event: ViewerEvent, before: BOOL]
RETURNS
[abort: BOOLFALSE]
IF viewer # NIL THEN {
ENABLE FS.Error => GOTO GiveUp;
name1: ROPEFS.ExpandName[viewer.file].fullFName;
bang1: INT ← Rope.SkipTo[name1, 0, "!"];
name2: ROPEFS.ExpandName[UserProfile.GetProfileName[]].fullFName;
bang2: INT ← Rope.SkipTo[name2, 0, "!"];
IF bang1 # 0 AND bang1 = bang2 AND Rope.Run[name1, 0, name2, 0, FALSE] = bang1 THEN
The profile is the same (except for version info), so notify about a change
UserProfile.ProfileChanged[edit];
EXITS GiveUp => NULL;
};
};
[] ← RegisterEventProc[NoticeProfileChanges, save, $Text, FALSE];
END.