InputFocusImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Doug Wyatt, May 24, 1985 10:12:10 am PDT
Russ Atkinson (RRA) April 8, 1986 8:43:37 pm PST
DIRECTORY
AMEvents USING [Debugging],
CedarProcess USING [DoWithPriority],
ClassIncreek USING [Increek],
Cursors USING [CursorType, GetCursor, SetCursor],
InputFocus USING [Focus, FocusRec],
Process USING [Detach, Pause, MsecToTicks, Ticks],
TIPPrivate,
TIPUser,
ViewerEvents USING [ProcessEvent],
ViewerOps USING [BlinkDisplay, MouseInViewer],
ViewerClasses USING [Viewer, ModifyAction, NotifyProc],
ViewerPrivate,
WindowManager USING [RestoreCursor, waitCount];
InputFocusImpl:
CEDAR
MONITOR
IMPORTS AMEvents, CedarProcess, Cursors, Process, TIPPrivate, TIPUser, ViewerEvents, ViewerOps, ViewerPrivate, WindowManager
EXPORTS InputFocus, ViewerPrivate
SHARES ViewerEvents
= BEGIN OPEN ViewerClasses, InputFocus;
forkNewNotifier:
BOOL ←
TRUE;
If forkNewNotifier=TRUE, MasterNotifyProc and MasterButtonProc will fork a new notifier (and destroy the old one) when they detect AMEvents.Debugging.
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:
REF ←
NIL] = {
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];
};
ModifyInputFocus:
PROC [action: ViewerClasses.ModifyAction] = {
ENABLE ANY => {IF ViewerPrivate.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 ViewerPrivate.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 => NULL; -- release lock
ModifyInputFocus[push];
currentFocus ← NEW[FocusRec ← [owner: self, info: info, link: currentFocus]];
ModifyInputFocus[set];
ChangeTIPContext[currentFocus.owner];
};
CaptureButtons:
PUBLIC
ENTRY
PROC [proc: NotifyProc, tip: TIPUser.TIPTable,
viewer: Viewer ←
NIL] = {
ENABLE UNWIND => NULL; -- release lock
captureProc ← proc;
captureTIP ← tip;
captureViewer ← viewer;
};
PopInputFocus:
PUBLIC
ENTRY
PROC = {
ENABLE UNWIND => NULL; -- release lock
IF currentFocus.link = NIL THEN RETURN;
ModifyInputFocus[kill];
currentFocus ← currentFocus.link;
ModifyInputFocus[pop];
ChangeTIPContext[currentFocus.owner];
};
ChangeTIPContext:
PROC [self: Viewer, interrupt:
BOOL ←
FALSE] = {
TIPPrivate.ResetTIPContext[focusTIP,
IF self=NIL THEN NIL ELSE IF self.iconic THEN ViewerPrivate.iconTIP ELSE self.tipTable,
MasterNotifyProc, interrupt];
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
TIPPrivate.stdCoords =>
IF coords#
NIL
THEN TIPPrivate.stdCoords^ ← coords^
ELSE [] ← ViewerOps.MouseInViewer[TIPPrivate.stdCoords];
ENDCASE;
ENDLOOP;
};
MasterNotifyProc: TIPPrivate.TIPNotifyProc ~ {
convert a TIPNotify into an InputFocusNotify.
InnerMasterNotifyProc:
PROC ~ {
ENABLE ANY => {IF ViewerPrivate.UserErrorQuery[] THEN CONTINUE};
IF currentFocus.owner.iconic THEN ViewerPrivate.IconNotify[currentFocus.owner, results]
ELSE {
MapCoordinateResults[results];
currentFocus.owner.class.notify[currentFocus.owner, results];
};
};
IF inputEnabled
AND currentFocus.owner#
NIL
THEN InnerMasterNotifyProc[!
AMEvents.Debugging => IF forkNewNotifier THEN PrivateUnWedgeNotifier[]
];
};
MasterButtonProc: TIPPrivate.TIPButtonProc ~ {
InnerMasterButtonProc:
PROC
RETURNS [consume:
BOOL ←
FALSE] ~ {
results: LIST OF REF ANY;
viewer: ViewerClasses.Viewer;
client: BOOL;
TIPParse:
PROC [table: TIPUser.TIPTable, mapCoords:
BOOL ←
TRUE] = {
parseInfo.inCreek ← state; -- OK since we only ever do one parse
parseInfo.tableHead ← table;
results ← TIPPrivate.ParseOneEvent[parseInfo];
IF mapCoords THEN MapCoordinateResults[results, screenXY];
};
IF NOT inputEnabled THEN RETURN[FALSE];
IF captureProc#
NIL
THEN {
TIPParse[captureTIP, FALSE];
IF results#
NIL
THEN captureProc[captureViewer, results];
! ANY => {IF ViewerPrivate.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[ViewerPrivate.iconTIP, FALSE];
IF results#
NIL
THEN ViewerPrivate.IconNotify[viewer, results];
! ANY => {IF ViewerPrivate.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 viewer.class.notify[viewer, results];
! ANY => {IF ViewerPrivate.UserErrorQuery[] THEN CONTINUE}];
}
ELSE {
TIPParse[WindowManagerTIPTable];
IF results#
NIL
THEN ViewerPrivate.ProcessWindowResults[viewer, results];
! ANY => {IF ViewerPrivate.UserErrorQuery[] THEN CONTINUE}];
};
RETURN[TRUE];
};
consume ← InnerMasterButtonProc[!
AMEvents.Debugging => IF forkNewNotifier THEN PrivateUnWedgeNotifier[]
];
};
PrivateUnWedgeNotifier:
PROC = {
exciting code to make a new notifier when ours is dying
ViewerOps.BlinkDisplay[];
currentFocus ← NEW[FocusRec];
TIPPrivate.DestroyClient[focusTIP]; -- destroy old notifier
StartTIP[]; -- make a new notifier
};
EnableInput:
PUBLIC
PROC = {
TIPPrivate.DiscardTypeAhead[focusTIP];
inputEnabled ← TRUE;
};
inputEnabled: PUBLIC BOOL ← FALSE; -- procs above will ignore TIP input while FALSE
parseInfo: TIPPrivate.TIPParseInfo ← TIPPrivate.CreateParseInfo[];
currentFocus: Focus ← NEW[FocusRec]; -- this is the head of the focus stack
WindowManagerTIPTable:
PUBLIC TIPUser.TIPTable ←
TIPUser.InstantiateNewTIPTable["WindowMgr.tip"];
focusTIP: PUBLIC TIPPrivate.TIPClient;
StartTIP:
PROC = {
inner:
PROC = {
focusTIP ← TIPPrivate.CreateClient[buttons: MasterButtonProc, notify: MasterNotifyProc];
TIPPrivate.DiscardTypeAhead[focusTIP];
};
CedarProcess.DoWithPriority[LOOPHOLE[ViewerPrivate.VMgrPriority], inner];
};
WaitingCursor:
PROC =
BEGIN
OPEN ViewerPrivate;
aWhile: Process.Ticks = Process.MsecToTicks[100];
InitializeHourglass[56];
UNTIL ViewerPrivate.inputEnabled DO TickHourglass[]; Process.Pause[aWhile]; ENDLOOP;
WindowManager.RestoreCursor[];
END;
TRUSTED {
cursor for amusement during start-up
Process.Detach[FORK WaitingCursor];
};
StartTIP[];
END.