SlackProcess.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last edited by Pier on October 17, 1986 4:57:55 pm PDT
DIRECTORY
Imager, IO, Rope, ViewerClasses;
SlackProcess: CEDAR DEFINITIONS = BEGIN
SlackProcess implements a general queue which can be used to "take up the slack" between user generated input events and system generated responses to these events. Multiple slack processes and their associated queues may be used by many clients; the slack process issues a handle containing MONITORED data for use by the client. Actions may be queued by calls to QueueInputAction or QueueInputActionNoPoint. If the client wishes, calls to QueueOrBashInputAction, QueueOrBashInputActionNoPoint will replace the prior action on the queue with the new action IF the prior action is of the same type as the new action. The type of an action is denoted by an ATOM as the first element of the input action list.
Each SlackProcess provides a logging feature for clients. A client can register a Logging procedure and enable/disable Session logging. With logging enabled, the registered Logging procedure will be called every time an action is dequeued. The client may then save a log or script of the session in progress for later playback to a future SlackProcess.
Each SlackProcess provides an abort feature for clients. A client can register an Abort procedure and some abort data and enable/disable aborting. With aborting enabled, the slack queue will be flushed and the registered abort procedure will be called (with the abort data as argument) every time an abort occurs. The current trigger for the abort action is holding down SHIFT-SWAT (SHIFT-Spare3) on a Dorado with the cursor in the viewer to be aborted. If the viewer specified when aborting is registered is NIL, then the cursor position will be ignored when checking for abort.
Point: TYPE = Imager.VEC; -- RECORD [x, y: REAL]
EventProc: TYPE = PROC [event: LIST OF REF ANY, clientData: REF ANY];
MouseEventProc: TYPE = PROC [event: LIST OF REF ANY, point: Point, clientData: REF ANY];
LoggingProc: TYPE = PROC [point: Point, action: LIST OF REF ANY, mouseEvent: BOOL, clientData: REF ANY];
AbortProc: TYPE = PROC [data: REF ANY];
SlackHandle: TYPE = REF SlackData;
The SlackData record should be considered PRIVATE by clients of SlackProcess
SlackData: TYPE = MONITORED RECORD [
slackProcess: PROCESS,
queue: Queue,
log: Log,
abort: Abort
]; -- eventually should be opaque ??
defaultSize: NAT = 50;
Queue: TYPE = REF QueueData;
The QueueData record and its fields should be considered PRIVATE by clients of SlackProcess
QueueData: TYPE = RECORD [
notFull: CONDITION,
head: NAT ← 0,
tail: NAT ← 0,
size: NAT ← 0,
clientDatas: ClientDatas ← NIL,
actions: Actions ← NIL,
points: Points ← NIL,
mouseProcs: MouseProcs ← NIL,
eventProcs: EventProcs ← NIL
];
ClientDatas: TYPE = REF ClientDatasData;
ClientDatasData: TYPE = RECORD[SEQUENCE len: NAT OF REF ANY];
Actions: TYPE = REF ActionsData;
ActionsData: TYPE = RECORD[SEQUENCE len: NAT OF LIST OF REF ANY];
Points: TYPE = REF PointsData;
PointsData: TYPE = RECORD[SEQUENCE len: NAT OF Point];
MouseProcs: TYPE = REF MouseProcsData;
MouseProcsData: TYPE = RECORD[SEQUENCE len: NAT OF MouseEventProc];
EventProcs: TYPE = REF EventProcsData;
EventProcsData: TYPE = RECORD[SEQUENCE len: NAT OF EventProc];
Log: TYPE = REF LogData;
The LogData record and its fields should be considered PRIVATE by clients of SlackProcess
LogData: TYPE = RECORD[
head: NAT ← 0,
size: NAT ← 0,
loggerEnabled: BOOLFALSE,
logger: LoggingProc ← NIL,
received: Received, -- received an action versus performed an action.
bashed: Bashed, -- bashed an action versus performed an action.
events: Events,
points: Points
];
Received: TYPE = REF ReceivedData;
ReceivedData: TYPE = RECORD[SEQUENCE len: NAT OF BOOL];
Bashed: TYPE = REF BashedData;
BashedData: TYPE = RECORD[SEQUENCE len: NAT OF BOOL];
Events: TYPE = REF EventsData;
EventsData: TYPE = RECORD[SEQUENCE len: NAT OF REF ANY];
Abort: TYPE = REF AbortData;
AbortData: TYPE = RECORD [
enabled: BOOLFALSE,
proc: AbortProc,
viewer: ViewerClasses.Viewer,
data: REF
];
Create: PROC [queueSize: NAT ← 50, logSize: NAT ← 50, loggingProc: LoggingProc ← NIL, abortProc: AbortProc ← NIL, abortData: REF ANYNIL, abortViewer: ViewerClasses.Viewer ← NIL] RETURNS[handle: SlackHandle];
FlushQueue: PROC [handle: SlackHandle];
Removes all unprocessed actions from the slack queue. CAUTION: If the caller is counting on a certain set of actions to be done atomically, this call could destroy its invariants.
Restart: PROC [handle: SlackHandle];
Creates a new slack process. Call this procedure if a bug in the slack process forces it to be aborted.
QueueInputAction: PROC [handle: SlackHandle, callBack: MouseEventProc, inputAction: LIST OF REF ANY, point: Point, clientData: REF ANY];
Queues the (mouse) action and returns immediately. The action is guaranteed to be done eventually (unless the queue overflows); i.e. the callBack proc will eventually be called with the inputAction, point, and clientData as parameters. The point should be in client coordinates.
QueueOrBashInputAction: PROC [handle: SlackHandle, callBack: MouseEventProc, inputAction: LIST OF REF ANY, bashable: LIST OF ATOM, point: Point, clientData: REF ANY];
Queues the (mouse) action and returns immediately. If this mouse action is right behind another of the same type, it replaces it. The point should be in client coordinates.
QueueInputActionNoPoint: PROC [handle: SlackHandle, callBack: EventProc, inputAction: LIST OF REF ANY, clientData: REF ANY];
For actions generated from menus or TIP tables (i.e. not from mouse points). Behaves like QueueInputAction.
QueueOrBashInputActionNoPoint: PROC [handle: SlackHandle, callBack: EventProc, inputAction: LIST OF REF ANY, bashable: LIST OF ATOM, clientData: REF ANY];
For actions generated from menus or TIP tables (i.e. not from mouse points). Behaves like QueueOrBashInputAction.
QueueInputActionAndWait: PROC [handle: SlackHandle, callBack: MouseEventProc, inputAction: LIST OF REF ANY, point: Point, clientData: REF ANY ];
Queues the action, and does not return until it is accomplished. Useful when so many calls are planned that the slack queue is sure to overflow with QueueInputAction.
SlackProcess keeps a ring buffer of recent input actions (called the log) for debugging purposes.
LogRawMouse: PROC [handle: SlackHandle, point: Point];
May be called by a client's NotifyProc to simply record raw mouse or client coordinates on the queue. SlackProcess will dequeue them and do nothing. Useful to discover the queue delay between getting a mouse event and actually processing it.
OutputLog: PROC [handle: SlackHandle, stream: IO.STREAM];
Output the "LogSize-1" most recent events to the stream. The most recent event is output first.
SlackProcess supports reporting of all actions dequeued from the slack queue, which can be recorded and played back by the client to recreate the session. The client must provide a logging procedure to be called whenever an action is dequeued for the application. The registered LoggingProc will be called at every dequeue of an event.
EnableSessionLogging: PROC [handle: SlackHandle];
DisableSessionLogging: PROC [handle: SlackHandle];
RegisterLogger: PROC [handle: SlackHandle, loggingProc: LoggingProc];
EnableAborts: PROC [handle: SlackHandle];
DisableAborts: PROC [handle: SlackHandle];
RegisterAbortProc: PROC [handle: SlackHandle, abortProc: AbortProc ← NIL, abortData: REF ANYNIL, abortViewer: ViewerClasses.Viewer ← NIL];
The registered abortProc will be called (if aborts are enabled) with abortData as argument when the slack process is aborted.
END.