InputFocusImpl.mesa; written by S. McGregor
Last Edited by McGregor, June 3, 1983 3:48 pm
Last Edited by: Maxwell, January 24, 1983 3:06 pm
Last Edited by: Wyatt, November 10, 1983 4:55 pm
DIRECTORY
AMEvents USING [Debugging],
ClassIncreek USING [Increek],
Cursors USING [CursorType, GetCursor, SetCursor],
IconManager USING [IconModify, IconNotify, iconTIP],
ImplErrors USING [UserErrorQuery],
InputFocus USING [Focus, FocusRec],
Process USING [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, NotifyViewer],
ViewerClasses USING [Viewer, ModifyAction, NotifyProc],
ViewersStallNotifier USING [],
WindowManager USING [waitCount],
WindowManagerPrivate USING [ProcessWindowResults, VMgrPriority];
InputFocusImpl: CEDAR MONITOR
IMPORTS AMEvents, Cursors, IconManager, ImplErrors, Process, TIPUser, UserTerminal, ViewerEvents, ViewerOps, WindowManager, WindowManagerPrivate
EXPORTS InputFocus, ViewersStallNotifier
SHARES InputFocus, TIPUser, ViewerEvents
= BEGIN OPEN InputFocus;
Viewer: TYPE = ViewerClasses.Viewer;
inputEnabled: PUBLIC BOOL ← FALSE; -- procs below will ignore TIP input while FALSE
WindowManagerTIPTable: PUBLIC TIPUser.TIPTable ← NIL;
focusTIP: PUBLIC TIPUser.TIPClient ← NIL;
currentFocus: Focus ← NEW[FocusRec]; -- this is the head of the focus stack
parseInfo: TIPUser.TIPParseInfo ← TIPUser.CreateParseInfo[];
captureProc: ViewerClasses.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:
REF ←
NIL] = {
ENABLE UNWIND => { --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];
};
ModifyInputFocus:
PROC[action: ViewerClasses.ModifyAction] = {
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 {
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];
};
IF action=set
THEN
[] ← ViewerEvents.ProcessEvent[setInputFocus, currentFocus.owner, FALSE];
IF action=kill
THEN
[] ← ViewerEvents.ProcessEvent[killInputFocus, currentFocus.owner, FALSE];
};
GetInputFocus: PUBLIC PROC RETURNS[Focus] = { RETURN[currentFocus] };
PushInputFocus:
PUBLIC
ENTRY
PROC[self: Viewer ←
NIL, info:
REF ←
NIL] = {
ENABLE UNWIND => { --release lock-- };
ModifyInputFocus[push];
currentFocus ← NEW[FocusRec ← [owner: self, info: info, link: currentFocus]];
ModifyInputFocus[set];
ChangeTIPContext[currentFocus.owner];
};
PopInputFocus:
PUBLIC
ENTRY
PROC = {
ENABLE UNWIND => { --release lock-- };
IF currentFocus.link=NIL THEN RETURN;
ModifyInputFocus[kill];
currentFocus ← currentFocus.link;
ModifyInputFocus[pop];
ChangeTIPContext[currentFocus.owner];
};
ChangeTIPContext:
PROC [self: Viewer, interrupt:
BOOLEAN ←
FALSE] = {
tipTable: TIPUser.TIPTable ← NIL;
IF self#NIL THEN tipTable ← (IF self.iconic THEN IconManager.iconTIP ELSE self.tipTable);
TIPUser.ResetTIPContext[focusTIP, tipTable, MasterNotifyProc, interrupt]
CaptureButtons:
PUBLIC
ENTRY
PROC[proc: ViewerClasses.NotifyProc, tip: TIPUser.TIPTable,
viewer: Viewer ← NIL] = {
ENABLE UNWIND => { --release lock-- };
captureProc ← proc;
captureTIP ← tip;
captureViewer ← viewer;
};
ReleaseButtons:
PUBLIC
ENTRY
PROC = {
ENABLE UNWIND => { --release lock-- };
captureProc ← NIL;
captureTIP ← NIL;
captureViewer ← NIL;
};
MapCoordinateResults:
PROC[results:
LIST
OF
REF
ANY, coords: TIPUser.TIPScreenCoords ←
NIL] =
{
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;
};
MasterNotifyProc: TIPUser.TIPNotifyProc
-- [results: LIST OF REF ANY] -- = {
convert a TIPNotify into an InputFocusNotify.
ENABLE AMEvents.Debugging => PrivateUnWedgeNotifier[];
IF inputEnabled
AND currentFocus.owner#
NIL
THEN {
ENABLE ANY => {IF ImplErrors.UserErrorQuery[] THEN CONTINUE};
IF currentFocus.owner.iconic THEN [] ← IconManager.IconNotify[currentFocus.owner, results]
ELSE {
MapCoordinateResults[results];
ViewerOps.NotifyViewer[currentFocus.owner, results];
};
};
};
MasterButtonProc: TIPUser.TIPButtonProc = {
[screenXY: TIPScreenCoords, button: Interminal.KeyName, state: ClassIncreek.Increek]
RETURNS [consume: BOOL ← FALSE]
ENABLE AMEvents.Debugging => PrivateUnWedgeNotifier[];
results: LIST OF REF ANY;
viewer: ViewerClasses.Viewer;
client: BOOL;
TIPParse:
PROC [table: TIPUser.TIPTable, mapCoords:
BOOLEAN ←
TRUE] = {
parseInfo.inCreek ← state; -- OK since we only ever do one parse
parseInfo.tableHead ← table;
results ← TIPUser.ParseOneEvent[parseInfo];
IF mapCoords THEN MapCoordinateResults[results, screenXY];
};
IF ~inputEnabled THEN RETURN;
IF captureProc#
NIL
THEN {
TIPParse[captureTIP, FALSE];
IF results#
NIL
THEN [] ← captureProc[captureViewer, results
! ANY => {IF ImplErrors.UserErrorQuery[] THEN CONTINUE}];
RETURN[TRUE];
};
[viewer, client] ← ViewerOps.MouseInViewer[screenXY];
IF viewer=
NIL
THEN {
IF WindowManager.waitCount=0
AND Cursors.GetCursor[]#textPointer
THEN
Cursors.SetCursor[textPointer];
TIPParse[NIL, FALSE] -- consume event
}
ELSE
IF viewer.iconic
THEN {
TIPParse[IconManager.iconTIP, FALSE];
IF results#
NIL
THEN [] ← IconManager.IconNotify[viewer, results
! ANY => {IF ImplErrors.UserErrorQuery[] THEN CONTINUE}];
}
ELSE
IF client
THEN {
IF WindowManager.waitCount=0
AND viewer.class.cursor#Cursors.GetCursor[]
THEN
Cursors.SetCursor[viewer.class.cursor];
TIPParse[viewer.tipTable];
IF results#
NIL
THEN ViewerOps.NotifyViewer[viewer, results
! ANY => {IF ImplErrors.UserErrorQuery[] THEN CONTINUE}];
}
ELSE {
TIPParse[WindowManagerTIPTable];
IF results#
NIL
THEN [] ← WindowManagerPrivate.ProcessWindowResults[viewer, results
! ANY => {IF ImplErrors.UserErrorQuery[] THEN CONTINUE}];
};
RETURN[TRUE];
};
UnWedgeNotifier:
PUBLIC
PROC [process:
PROCESS, kind:
ATOM] = {
NOP since handled by informational signals in MasterNotify and MasterButton procs
};
PrivateUnWedgeNotifier:
PROC = {
exciting code to make a new notifier when ours is dying
TRUSTED {UserTerminal.BlinkDisplay[]};
currentFocus ← NEW[FocusRec];
TIPUser.DestroyClient[focusTIP]; -- destroy old notifier
StartTIP[]; -- make a new notifier
};
EnableInput:
PUBLIC
PROC = {
TIPUser.DiscardTypeAhead[focusTIP];
inputEnabled ← TRUE;
};
StartTIP:
PROC =
TRUSTED {
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];
};
WindowManagerTIPTable ← TIPUser.InstantiateNewTIPTable["WindowMgr.tip"];
StartTIP[];
END.