InputFocusImpl.mesa;
Last Edited by McGregor, September 22, 1982 2:30 pm
Last Edited by: Maxwell, January 24, 1983 3:06 pm
DIRECTORY
ClassIncreek USING [Increek],
Cursors USING [CursorType, GetCursor, SetCursor],
IconManager USING [IconModify, IconNotify, iconTIP],
ImplErrors USING [UserErrorQuery],
InputFocus,
Process USING [Detach, GetPriority, Priority, SetPriority],
TIPUser USING [CreateParseInfo, CreateClient, DestroyClient, DiscardTypeAhead,
InstantiateNewTIPTable, ParseOneEvent, ResetTIPContext, stdCoords,
TIPButtonProc, TIPClient, TIPNotifyProc, TIPParseInfo, TIPScreenCoords, TIPTable],
UserTerminal USING [BlinkDisplay],
ViewerEvents USING [ProcessEvent],
ViewerOps USING [MouseInViewer],
ViewerClasses USING [Viewer, ModifyAction, NotifyProc],
ViewersStallNotifier,
WindowManager USING [waitCount],
WindowManagerPrivate USING [ProcessWindowResults, VMgrPriority];
InputFocusImpl: CEDAR MONITOR
IMPORTS Cursors, IconManager, ImplErrors, Process, TIPUser, UserTerminal, ViewerEvents,
ViewerOps, WindowManager, WindowManagerPrivate
EXPORTS InputFocus, ViewersStallNotifier
SHARES InputFocus, TIPUser, ViewerEvents =
BEGIN OPEN ViewerClasses, InputFocus;
captureProc: NotifyProc ← NIL;  -- client preempting all button events
captureTIP: TIPUser.TIPTable ← NIL; -- TIP Table associated with the capture.
captureViewer: Viewer ← NIL;  -- focus data private to the capture.
SetInputFocus: PUBLIC ENTRY PROC [self: Viewer ← NIL, info: REFNIL] =
BEGIN
ENABLE UNWIND => NULL; -- release lock
ModifyInputFocus[kill];
currentFocus.owner ← self; -- note that we don't flush any CaptureButtons!
currentFocus.info ← info;
currentFocus.link ← NIL;
ModifyInputFocus[set];
IF currentFocus.owner#NIL THEN ChangeTIPContext[currentFocus.owner];
END;
ModifyInputFocus: PROC [action: ViewerClasses.ModifyAction] =
BEGIN
ENABLE ANY => {IF ImplErrors.UserErrorQuery[] THEN CONTINUE};
IF action=set THEN
IF ViewerEvents.ProcessEvent[setInputFocus, currentFocus.owner, TRUE] THEN RETURN;
IF action=kill THEN
IF ViewerEvents.ProcessEvent[killInputFocus, currentFocus.owner, TRUE] THEN RETURN;
IF currentFocus.owner # NIL THEN BEGIN
IF currentFocus.owner.iconic THEN IconManager.IconModify[currentFocus.owner, action]
ELSE IF currentFocus.owner.class.modify#NIL THEN
currentFocus.owner.class.modify [currentFocus.owner, action];
END;
IF action=set THEN [] ← ViewerEvents.ProcessEvent[setInputFocus, currentFocus.owner, FALSE];
IF action=kill THEN [] ← ViewerEvents.ProcessEvent[killInputFocus, currentFocus.owner, FALSE];
END;
GetInputFocus: PUBLIC PROC RETURNS [Focus] = {RETURN[currentFocus]} ;
PushInputFocus: PUBLIC ENTRY PROC [self: Viewer ← NIL, info: REFNIL] = BEGIN
ENABLE UNWIND => NULL; -- release lock
ModifyInputFocus[push];
currentFocus ← NEW[FocusRec ← [owner: self, info: info, link: currentFocus]];
ModifyInputFocus[set];
ChangeTIPContext[currentFocus.owner];
END;
CaptureButtons: PUBLIC ENTRY PROC [proc: NotifyProc, tip: TIPUser.TIPTable, viewer: Viewer ← NIL] =
BEGIN
ENABLE UNWIND => NULL; -- release lock
captureProc ← proc;
captureTIP ← tip;
captureViewer ← viewer;
END;
PopInputFocus: PUBLIC ENTRY PROC = BEGIN
ENABLE UNWIND => NULL; -- release lock
IF currentFocus.link = NIL THEN RETURN;
ModifyInputFocus[kill];
currentFocus ← currentFocus.link;
ModifyInputFocus[pop];
ChangeTIPContext[currentFocus.owner];
END;
ChangeTIPContext: PROC [self: Viewer, interrupt: BOOLEANFALSE] =
{TIPUser.ResetTIPContext[focusTIP,
IF self=NIL THEN NIL ELSE IF self.iconic THEN IconManager.iconTIP ELSE self.tipTable,
MasterNotifyProc, interrupt]};
MapCoordinateResults: PROC[results: LIST OF REF ANY, coords: TIPUser.TIPScreenCoords ← NIL] =
BEGIN
FOR lst: LIST OF REF ANY ← results, lst.rest UNTIL lst = NIL DO
SELECT lst.first FROM
TIPUser.stdCoords => IF coords#NIL THEN TIPUser.stdCoords^ ← coords^
ELSE [] ← ViewerOps.MouseInViewer[TIPUser.stdCoords];
ENDCASE;
ENDLOOP;
END;
MasterNotifyProc: TIPUser.TIPNotifyProc -- [results: LIST OF REF ANY] -- = BEGIN
convert a TIPNotify into an InputFocusNotify.
IF inputEnabled AND currentFocus.owner#NIL THEN BEGIN
ENABLE ANY => {IF ImplErrors.UserErrorQuery[] THEN CONTINUE};
IF currentFocus.owner.iconic THEN IconManager.IconNotify[currentFocus.owner, results]
ELSE BEGIN
MapCoordinateResults[results];
currentFocus.owner.class.notify[currentFocus.owner, results];
END;
END;
END;
MasterButtonProc: TIPUser.TIPButtonProc = BEGIN
[screenXY: TIPScreenCoords, button: Interminal.KeyName, state: ClassIncreek.Increek]
RETURNS [consume: BOOL ← FALSE]
results: LIST OF REF ANY;
viewer: ViewerClasses.Viewer;
client: BOOL;
TIPParse: PROC [table: TIPUser.TIPTable, mapCoords: BOOLEANTRUE] = BEGIN
parseInfo.inCreek ← state; -- OK since we only ever do one parse
parseInfo.tableHead ← table;
results ← TIPUser.ParseOneEvent[parseInfo];
IF mapCoords THEN MapCoordinateResults[results, screenXY];
END;
IF ~inputEnabled THEN RETURN;
IF captureProc#NIL THEN BEGIN
TIPParse[captureTIP, FALSE];
IF results#NIL THEN captureProc[captureViewer, results
! ANY => {IF ImplErrors.UserErrorQuery[] THEN CONTINUE}];
RETURN[TRUE];
END;
[viewer, client] ← ViewerOps.MouseInViewer[screenXY];
IF viewer=NIL THEN BEGIN
IF WindowManager.waitCount=0 AND Cursors.GetCursor[]#textPointer THEN
Cursors.SetCursor[textPointer];
TIPParse[NIL, FALSE] -- consume event
END
ELSE IF viewer.iconic THEN BEGIN
TIPParse[IconManager.iconTIP, FALSE];
IF results#NIL THEN IconManager.IconNotify[viewer, results
! ANY => {IF ImplErrors.UserErrorQuery[] THEN CONTINUE}];
END
ELSE IF client THEN BEGIN
IF WindowManager.waitCount=0 AND viewer.class.cursor#Cursors.GetCursor[] THEN
Cursors.SetCursor[viewer.class.cursor];
TIPParse[viewer.tipTable];
IF results#NIL THEN viewer.class.notify[viewer, results
! ANY => {IF ImplErrors.UserErrorQuery[] THEN CONTINUE}];
END
ELSE BEGIN
TIPParse[WindowManagerTIPTable];
IF results#NIL THEN WindowManagerPrivate.ProcessWindowResults[viewer, results
! ANY => {IF ImplErrors.UserErrorQuery[] THEN CONTINUE}];
END;
RETURN[TRUE];
END;
lastUnwedged: PROCESSLOOPHOLE[0]; -- one slot debug log of last process unwedged
UnWedgeNotifier: PUBLIC PROC [process: PROCESS, kind: ATOM] = BEGIN
exciting code to make a new notifier when ours is dying
IF focusTIP.matcher = process THEN BEGIN
TRUSTED {UserTerminal.BlinkDisplay[]};
lastUnwedged ← process;
currentFocus ← NEW[FocusRec];
fork this guy so we waste a process rather than wedge the world
TRUSTED {Process.Detach[FORK TIPUser.DestroyClient[focusTIP]]};
StartTIP; -- make a new notifier
END;
END;
EnableInput: PUBLIC PROC = BEGIN
TIPUser.DiscardTypeAhead[focusTIP];
inputEnabled ← TRUE;
END;
inputEnabled: PUBLIC BOOLEANFALSE; -- procs above will ignore TIP input while FALSE
parseInfo: TIPUser.TIPParseInfo ← TIPUser.CreateParseInfo[];
currentFocus: Focus ← NEW[FocusRec]; -- this is the head of the focus stack
WindowManagerTIPTable: PUBLIC TIPUser.TIPTable ←
TIPUser.InstantiateNewTIPTable["/Indigo/CedarViewers/Viewers/WindowMgr.tip"];
focusTIP: PUBLIC TIPUser.TIPClient;
StartTIP: PROC = TRUSTED BEGIN
oldPriority: Process.Priority = Process.GetPriority[];
Process.SetPriority[WindowManagerPrivate.VMgrPriority]; -- so TIP forked at VMgrPriority
focusTIP ← TIPUser.CreateClient[buttons: MasterButtonProc, notify: MasterNotifyProc];
TIPUser.DiscardTypeAhead[focusTIP];
Process.SetPriority[oldPriority];
END;
StartTIP[];
END.