EditNotifyImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
written by Bill Paxton, March 1981
last edit by Bill Paxton, October 18, 1982 10:42 am
Michael Plass, March 29, 1985 2:31:39 pm PST
Doug Wyatt, September 22, 1986 4:54:02 pm PDT
DIRECTORY
Tioga,
TiogaPrivate;
EditNotifyImpl: CEDAR MONITOR LOCKS data USING data: EditNotifyData
EXPORTS TiogaPrivate
= BEGIN OPEN Tioga, TiogaPrivate;
EditNotify
EditNotifyData: TYPE ~ REF EditNotifyDataRep;
EditNotifyDataRep: PUBLIC TYPE ~ MONITORED RECORD [
beforeProcs: NotifyArray,
afterProcs: NotifyArray,
unlocked: CONDITION,
lockCount: INTEGER ← 0
];
NotifyList: TYPE = REF NotifyListBody;
NotifyListBody: TYPE = RECORD [
next: NotifyList,
action: EditNotifyProc,
changeSet: ChangeSet
];
NotifyArray: TYPE = ARRAY Priority OF NotifyList;
Lock: ENTRY PROC [data: EditNotifyData] = {
data.lockCount ← data.lockCount+1;
};
Unlock: ENTRY PROC [data: EditNotifyData] = {
data.lockCount ← data.lockCount-1;
IF data.lockCount <= 0 THEN { data.lockCount ← 0; BROADCAST data.unlocked };
};
InternalRemove: PROC [data: EditNotifyData, proc: EditNotifyProc, time: When] = {
FOR p: Priority IN Priority DO
prev: NotifyList ← NIL;
list: NotifyList ← IF time=before THEN data.beforeProcs[p]
ELSE data.afterProcs[p];
IF list=NIL THEN LOOP;
UNTIL list=NIL DO
IF list.action = proc THEN EXIT;
prev ← list; list ← list.next;
REPEAT FINISHED => LOOP; -- proc not found on this list
ENDLOOP;
IF prev#NIL THEN prev.next ← list.next
ELSE IF time=before THEN data.beforeProcs[p] ← list.next
ELSE data.afterProcs[p] ← list.next;
ENDLOOP;
};
EntryAdd: ENTRY PROC [data: EditNotifyData, proc: EditNotifyProc, time: When, priority: Priority, changeSet: ChangeSet] = {
ENABLE UNWIND => NULL;
WHILE data.lockCount > 0 DO WAIT data.unlocked; ENDLOOP;
InternalRemove[data, proc, time];
IF time=before THEN
data.beforeProcs[priority] ←
NEW[NotifyListBody ← [data.beforeProcs[priority], proc, changeSet]]
ELSE data.afterProcs[priority] ←
NEW[NotifyListBody ← [data.afterProcs[priority], proc, changeSet]];
};
EntryRemove: ENTRY PROC [data: EditNotifyData, proc: EditNotifyProc, time: When] = {
remove proc from list of notification procedures
ENABLE UNWIND => NULL;
WHILE data.lockCount > 0 DO WAIT data.unlocked; ENDLOOP;
InternalRemove[data, proc, time];
};
AddEditNotifyProc: PUBLIC PROC [world: World, proc: EditNotifyProc, time: When ← after,
priority: Priority ← normal, changeSet: ChangeSet ← defaultChangeSet] ~ {
data: EditNotifyData ~ world.editNotify;
EntryAdd[data, proc, time, priority, changeSet];
};
RemoveEditNotifyProc: PUBLIC PROC [world: World, proc: EditNotifyProc, time: When ← after] ~ {
data: EditNotifyData ~ world.editNotify;
EntryRemove[data, proc, time];
};
GetList: PROC [data: EditNotifyData, p: Priority, time: When] RETURNS [NotifyList] = {
RETURN [IF time=before THEN data.beforeProcs[p] ELSE data.afterProcs[p]]
};
EditNotify: PUBLIC PROC [world: World, change: REF READONLY Change, time: When] = {
call notification procedures
data: EditNotifyData ~ world.editNotify;
IF change#NIL THEN { ENABLE UNWIND => Unlock[data];
kind: ChangeType ~ change.kind;
Lock[data];
FOR p: Priority IN Priority DO
FOR lst: NotifyList ← GetList[data, p, time], lst.next UNTIL lst=NIL DO
IF lst.changeSet[kind] THEN lst.action[change];
ENDLOOP;
ENDLOOP;
Unlock[data];
};
};
UndoEvent
CreateEvent: PUBLIC PROC RETURNS [Event] = {
RETURN [NEW[EventBody ← [subevents: NIL]]];
};
NoteEvent: PUBLIC PROC [world: World, undoProc: UndoProc, undoRef: REF Change] = {
event: Event ~ IF world=NIL THEN NIL ELSE world.currentEvent;
IF event = NIL THEN RETURN;
event.subevents ← NEW[SubEventBody ←
[next: event.subevents, undoProc: undoProc, undoRef: undoRef]];
};
UndoEvent: PUBLIC PROC [world: World, undoEvent: Event] = {
calls undoProc[undoRef] for each subevent
in reverse order that subevents originally happened
sub: SubEvent;
IF undoEvent=NIL THEN RETURN;
sub ← undoEvent.subevents; undoEvent.subevents ← NIL;
UNTIL sub=NIL DO sub.undoProc[world, sub.undoRef]; sub ← sub.next; ENDLOOP;
};
ResetEvent: PUBLIC PROC [event: Event] = {
IF event # NIL THEN event.subevents ← NIL;
};
EmptyEvent: PUBLIC PROC [event: Event] RETURNS [BOOL] = {
RETURN [event=NIL OR event.subevents=NIL];
};
END.