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: BOOLFALSE];
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.