InputFocusImpl.mesa
Copyright Ó 1985, 1986, 1987, 1988, 1990, 1991, 1992 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) March 3, 1987 7:04:40 pm PST
Pier, November 17, 1988 5:03:14 pm PST
Bier, March 5, 1991 8:04 pm PST
Doug Wyatt, January 2, 1990 3:43:00 pm PST
Willie-s, October 29, 1991 6:32 pm PST
Christian Jacobi, March 3, 1992 12:16 pm PST
Michael Plass, March 13, 1992 10:54 am PST
DIRECTORY
InputFocus, MultiCursors, Process, Rope, TIPPrivate, TIPUser, UserInputOps, UserInputGetActions, ViewerClasses, ViewerEvents, ViewerOps, ViewerPrivate, ViewersWorld, ViewersWorldInstance, ViewersWorldRefType, ViewersWorldTypes, WindowManager;
InputFocusImpl:
CEDAR
MONITOR
IMPORTS MultiCursors, Process, TIPPrivate, TIPUser, UserInputOps, UserInputGetActions, ViewerEvents, ViewerOps, ViewerPrivate, ViewersWorld, ViewersWorldInstance, WindowManager
EXPORTS InputFocus, ViewersWorldRefType, ViewerPrivate
SHARES ViewerEvents
= BEGIN
Focus: TYPE = InputFocus.Focus;
FocusRec: TYPE = InputFocus.FocusRec;
LORA: TYPE = LIST OF REF ANY;
Viewer: TYPE = ViewerClasses.Viewer;
ViewersWorldRef: TYPE = REF ViewersWorldObj;
ViewersWorldObj: PUBLIC TYPE = ViewersWorldTypes.ViewersWorldObj;
Global variables
WindowManagerTIPTable:
PUBLIC TIPUser.TIPTable ¬
TIPUser.InstantiateNewTIPTable["WindowMgr.tip"];
vWorld: ViewersWorldRef ¬ ViewersWorldInstance.GetWorld[];
NewWorld: ViewersWorldInstance.SetNotifyProc = {
vWorld ¬ viewersWorld
};
Public procedures
SetInputFocus:
PUBLIC
ENTRY
PROC [self: Viewer ¬
NIL, info:
REF ¬
NIL] = {
ENABLE UNWIND => NULL; -- release lock
ModifyInputFocus[kill];
vWorld.currentFocus.owner ¬ self; -- note that we don't flush any CaptureButtons!
vWorld.currentFocus.info ¬ info;
vWorld.currentFocus.link ¬ NIL;
ModifyInputFocus[set];
IF vWorld.currentFocus.owner # NIL THEN ChangeTIPContext[vWorld.currentFocus.owner];
};
GetInputFocus:
PUBLIC
PROC
RETURNS [Focus] = {
RETURN [vWorld.currentFocus];
};
PushInputFocus:
PUBLIC
ENTRY
PROC [self: Viewer ¬
NIL, info:
REF ¬
NIL] = {
ENABLE UNWIND => NULL; -- release lock
ModifyInputFocus[push];
vWorld.currentFocus ¬ NEW[FocusRec ¬ [owner: self, info: info, link: vWorld.currentFocus]];
ModifyInputFocus[set];
ChangeTIPContext[vWorld.currentFocus.owner];
};
NotifyProc: TYPE = InputFocus.NotifyProc;
CaptureButtons:
PUBLIC
ENTRY
PROC
[proc: NotifyProc, tip: TIPUser.TIPTable, viewer: Viewer ¬
NIL, captureKeyboard:
BOOL ¬
FALSE] = {
ENABLE UNWIND => NULL; -- release lock
vWorld.captureProc ¬ proc;
vWorld.captureTIP ¬ tip;
vWorld.captureViewer ¬ viewer;
};
PopInputFocus:
PUBLIC
ENTRY
PROC = {
ENABLE UNWIND => NULL; -- release lock
IF vWorld.currentFocus.link = NIL THEN RETURN;
ModifyInputFocus[kill];
vWorld.currentFocus ¬ vWorld.currentFocus.link;
ModifyInputFocus[pop];
ChangeTIPContext[vWorld.currentFocus.owner];
};
Private procedures
ModifyInputFocus:
INTERNAL
PROC [action: ViewerClasses.ModifyAction] = {
owner: ViewerClasses.Viewer ¬ vWorld.currentFocus.owner; -- good for the whole invocation
modify: ViewerClasses.ModifyProc ¬ NIL;
SELECT action
FROM
set => IF ViewerEvents.ProcessEvent[setInputFocus, owner, TRUE] THEN RETURN;
kill => IF ViewerEvents.ProcessEvent[killInputFocus, owner, TRUE] THEN RETURN;
ENDCASE;
SELECT
TRUE
FROM
owner = NIL => {};
owner.iconic => ViewerPrivate.IconModify[owner, action];
(modify ¬ owner.class.modify) # NIL => modify[owner, action];
ENDCASE;
SELECT action
FROM
set => [] ¬ ViewerEvents.ProcessEvent[setInputFocus, owner, FALSE];
kill => [] ¬ ViewerEvents.ProcessEvent[killInputFocus, owner, FALSE];
ENDCASE;
};
transparentTIP: TIPUser.TIPTable ~ TIPUser.TransparentTIPTable[];
ChangeTIPContext:
INTERNAL
PROC [self: Viewer, interrupt:
BOOL ¬
FALSE] = {
table: TIPUser.TIPTable ¬ NIL;
IF self#
NIL
THEN
SELECT
TRUE
FROM
self.iconic => table ¬ ViewerPrivate.iconTIP;
self.transparentTIP => table ¬ transparentTIP;
ENDCASE => table ¬ self.tipTable;
TIPPrivate.ResetTIPContext[vWorld.focusTIP, table, MasterNotifyProc, interrupt];
MapCoordinateResults:
PROC [results:
LORA, coords: TIPUser.TIPScreenCoords ¬
NIL] = {
FOR lst:
LORA ¬ 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:
PUBLIC TIPPrivate.TIPNotifyProc ~ {
PROC [results: LIST OF REF ANY, clientData: REF ANY];
convert a TIPNotify into an InputFocusNotify.
MasterNotifyProc is called for keyboard input. See MasterButtonProc below for mouse actions.
InnerMasterNotifyProc:
PROC ~ {
owner: Viewer ~ vWorld.currentFocus.owner;
IF owner.iconic
THEN ViewerPrivate.IconNotify[owner, results]
ELSE {
MapCoordinateResults[results];
owner.class.notify[vWorld.currentFocus.owner, results, device, user, display];
};
};
IF vWorld.inputEnabled
AND vWorld.currentFocus.owner#
NIL
THEN
InnerMasterNotifyProc[
! AMEvents2.Debugging => IF vWorld.forkNewNotifier THEN PrivateUnWedgeNotifier[]
];
InnerMasterNotifyProc[];
};
parseInfo: TIPPrivate.TIPParseInfo ¬ TIPPrivate.CreateParseInfo[NIL, "InputFocus"];
MasterButtonProc:
PUBLIC TIPPrivate.TIPButtonProc ~ {
PROC [screenXY: TIPScreenCoords, mouseEvent: MouseEvent, state: UserInput.Handle, clientData: REF ANY] RETURNS [consume: BOOL ← FALSE];
InnerMasterButtonProc:
PROC
RETURNS [consume:
BOOL ¬
FALSE] ~ {
results: LORA ¬ NIL;
viewer: ViewerClasses.Viewer ¬ NIL;
client: BOOL ¬ FALSE;
device, user, display: REF;
TIPParse:
PROC [table: TIPUser.TIPTable, mapCoords:
BOOL ¬
TRUE] = {
actionBody: UserInputGetActions.InputActionBody;
parseInfo.inCreek ¬ state; -- OK since we only ever do one parse
parseInfo.tableHead ¬ table;
actionBody ¬ UserInputGetActions.GetInputActionBody[handle: parseInfo.inCreek, waitMode: forever, acceptance: clicksAndMotion];
results ¬ TIPPrivate.WideMatchEvent[parseInfo, actionBody];
device ¬ actionBody.device;
user ¬ actionBody.user;
display ¬ actionBody.display;
UserInputOps.Close[parseInfo.localCreek];
IF mapCoords THEN MapCoordinateResults[results, screenXY];
};
IF NOT vWorld.inputEnabled THEN RETURN [FALSE];
IF vWorld.captureProc #
NIL
THEN {
-- someone is capturing all input events
TIPParse[vWorld.captureTIP, FALSE];
IF results #
NIL
THEN {
captureProc: InputFocus.NotifyProc ¬ vWorld.captureProc; --sample just once
IF captureProc # NIL THEN captureProc[vWorld.captureViewer, results, device, user, display];
};
RETURN [TRUE];
};
[viewer, client] ¬ ViewerOps.MouseInViewer[screenXY];
SELECT
TRUE
FROM
viewer =
NIL => {
cursorName: ATOM;
TIPParse[NIL, FALSE]; -- consume event (and find out what device produced it)
cursorName ¬ IF ISTYPE[device, ATOM] THEN NARROW[device] ELSE NIL;
IF WindowManager.waitCount=0
AND MultiCursors.GetACursor[cursorName] # textPointer
THEN
MultiCursors.SetACursor[textPointer, cursorName];
};
viewer.iconic => {
TIPParse[ViewerPrivate.iconTIP, FALSE];
IF results # NIL THEN ViewerPrivate.IconNotifyMouse[viewer, results, device, user, display];
};
client => {
cursor: ViewerClasses.CursorType ¬ viewer.cursor;
cursorName: ATOM;
TIPParse[IF viewer.transparentTIP THEN transparentTIP ELSE viewer.tipTable]; -- sets both "results" and "device"
IF cursor=none THEN cursor ¬ viewer.class.cursor;
IF cursor#last
THEN {
Applications that would like the cursor left alone can set the cursor to last
cursorName ¬ IF ISTYPE[device, ATOM] THEN NARROW[device] ELSE NIL;
IF WindowManager.waitCount=0
AND cursor#MultiCursors.GetACursor[cursorName]
THEN MultiCursors.SetACursor[cursor, cursorName];
};
IF results # NIL THEN viewer.class.notify[viewer, results, device, user, display];
};
ENDCASE => {
TIPParse[WindowManagerTIPTable];
IF results # NIL THEN ViewerPrivate.ProcessWindowManagerInput[viewer, results, device, user, display];
};
RETURN [TRUE];
};
consume ¬ InnerMasterButtonProc[
! AMEvents2.Debugging => IF vWorld.forkNewNotifier THEN PrivateUnWedgeNotifier[]
];
consume ¬ InnerMasterButtonProc[];
};
PrivateUnWedgeNotifier:
PROC = {
exciting code to make a new notifier when ours is dying
ViewerOps.BlinkDisplay[];
vWorld.currentFocus ¬ NEW[FocusRec];
ViewersWorld.RestartInput[vWorld];
};
WaitingCursor:
PROC = {
aWhile: Process.Ticks = Process.MsecToTicks[170];
ViewerPrivate.InitializeHourglass[56];
UNTIL vWorld #
NIL
AND vWorld.inputEnabled
DO
ViewerPrivate.TickHourglass[];
Process.Pause[aWhile];
ENDLOOP;
WindowManager.RestoreCursor[];
};
<<Initialization>>
<<TRUSTED {
cursor for amusement during start-up
Process.Detach[FORK WaitingCursor];
};
>> -- doesn't work in the portable world. Needs to know what the hardware is too early
CreateDebugButton:
PUBLIC
PROC = {
};
wideViewers: BOOL ¬ TRUE;
ViewersWorldInstance.CallWhenSet[NewWorld];
END.