Event Handling Thoughts

Keyboard Input Focus

Problem Statement: Assume a McCLIM frame has the keyboard input focus on the window manager/desktop environment level.1

1. How do we communicate to the (human) user which sheet/pane/gadget would receive a key event if a key was pressed? (And what do we do for McCLIM frames that do not have the focus on the window manager/desktop environment level)

2. When a key is actually pressed, to which sheet/pane/gadget should the key-pressed-event (and key-released-event) be delivered?

Denitions

ˆ Note how in the "no wm focus"/inactive gadgets case the foreground color is dimmed an the list gadget does not highlight the selected item.

ˆ Also note how the blue border indicates the keyword input focus in the "wm focus" case. 1Can the window manager focus and keyboard input focus be separate on this level?

1 Constraints from the Specication ˆ cursor-focus cursor

When true, the sheet owning the cursor has the input focus.

ˆ (setf port-keyboard-input-focus) focus port

The client to which keyboard events are to be dispatched

ˆ stream-set-input-focus stream with-input-focus (stream) &body body Implemented in terms of the above, but note:

By default, an application frame gives the input focus to the window associated with frame-query-io.

Specication of Desired Behavior This section describes the expected behavior in terms of user-observable reactions to events generated by the user and the environment. It does not describe the implementation.

Reaction to Speci Events 1. The window manager takes the focus away from a McCLIM frame

(a) The sheet/pane/gadget that has the keyboard input focus loses the keyboard input focus and indicates this visually. (b) All sheets/panes/gadgets within the McCLIM frame switch from state active to state inactive and indicate this visually (we do not currently do this, but GTK applications, for example, do).

2. The window manager gives the focus to a McCLIM frame without a pointer button press in the frame (i.e. the behavior typically bound to M-Tab)

(a) All sheets/panes/gadgets within the McCLIM frame switch from state inactive to state active and indicate this visually (we do not currently do this, but GTK applications, for example, do). (b) A sheet/pane/gadget gets the keyboard input focus:

2 If the frame gets the window manager focus for the rst time According to the specication, the sheet that is the value of frame-query-io gets the keyboard input focus and indicates this visually. If the frame has had the window manager focus before the sheet/pane/gadget that had the keyboard input focus when the frame last had the window manager focus gets the key- board input focus and indicates this visually.

3. The window manager gives the focus to a McCLIM frame in response to a pointer button press in the McCLIM frame. Is this just 2. followed by 5.?

4. The pointer enters a sheet/pane/gadget (within a McCLIM frame). This does not have an eect on the keyboard input focus (A "focus follows mouse" policy might be added later, though).

5. A pointer button is pressed over a sheet/pane/gadget (within a Mc- CLIM frame that already has the window manager focus).

(a) The sheet/pane/gadget that has the keyboard input focus loses the keyboard input focus and indicates this visually. (b) The new port pointer sheet gets the keyboard input focus and indicates this visually. What happens if the new port pointer sheet does not accept input? The keyboard input focus could either remain unchanged or be delegated to some other sheet/pane/gadget. What happens if the pointer is moved out of the sheet instead of released? If the new port pointer sheet accepts input, it should get the keyboard input focus irregardless of the button release.

6. A key is pressed or released over a sheet/pane/gadget (within a Mc- CLIM frame).

(a) The event is dispatched If the gesture of the event is bound to the "focus next" (or "focus previous", "focus parent", etc.) command then ???.

3 If the gesture of the event is not bound to the "focus next" command the event is dispatched to the sheet/pane/gadget s that has the keyboard input focus. (b) What happens if s does accept/handle the event? Imagine a slider-pane has the keyboard input focus. when the "down" key is pressed the slider adjusts its value, repaints, keeps the keyboard input focus. If however, say, the "f1" or "escape" key is pressed, maybe some other sheet like a menu should respond. Also, the frame's command table can have keystrokes bound to commands. Consider the McCLIM debugger which binds "e" to Evaluate In Frame. This currently prevents the user from typ- ing "e" into text editors and input streams. On the other hand, typing "e" while a slider-pane has the keyboard input focus could run the debugger command just ne.

7. The user inputs a "focus next" command. Probably out of scope for now

Implementation Port Event Distribution

Overview TODO what about enabled/disabled sheets? Ports generate "raw" events (KIND, s, p) where KIND is the event kind, s is the event sheet (a mirrored sheet) and p is the event position in s. These raw events are processed in distribute-event which does one or more of the following for each event:

ˆ dispatch event e to its event sheet se ˆ dispatch event e to a dierent

ˆ dispatch synthesized events instead of or in addition to e raw event -> distribute-event maybe -> synthesize -> synthesized event -> dispatch event maybe -> dispatch event

4 Denitions port pointer sheet Let e be the most recent pointer event distributed by a given port, let se be e's sheet and let pe be e's position.

ˆ If e is not an exit event, the port pointer sheet after processing e is the sheet (mirrored or not) s such that s is a descendant of se 0 and pe ∈ region(s) and there is no descendant s of s such that 0 pe ∈ region(s ).

ˆ If e is an exit event, let sm be se's rst mirrored ancestor. The port pointer sheet after processing e is

 sm if sm is not a graft  nil if sm is a graft port pressed sheet Let epress be the most recent button press event and erelease the most recent button release event distributed by a given port. Let let se be epress's sheet and let pe be epress's position.

ˆ If erelease occurred after epress, the port pressed sheet is nil. ˆ If erelease did not occur after epress, the port pressed sheet is the sheet (mirrored or not) s such that s is a descendant of se and 0 pe ∈ region(s) and there is no descendant s of s such that pe ∈ region(s0). port grabbed sheet TODO

Synthesis of Boundary Events Specication

Let e1, e2,... be the sequence of (potentially synthesized) boundary events 2 dispatched by a given port . Let stacki be the state of a stack that is main- tained according to

stack0 = () ( stack if is an enter event (sei , i−1) ei stacki = rest where stacki−1 = (s, rest) if ei is an exit event

2I.e., this specication describes the expected event output of a port after potentially discarding, re-routing and synthesizing events. It does not describe the root causes of the eventually produced events or how the port processes events.

5 The following properties must hold for each stack : i = (si,1, . . . , si,ni ) 1. is a graft (the parent of the sheet at the bottom of the parent(si,ni ) stack must be a graft)

2. ∀si,j, si,j+1, 1 ≤ j ≤ ni − 1 : parent(si,j) = si,j+1 (adjacent sheets on the stack must be parent and child)

3. If is an exit event, then stack (exit events must only ei i = (sei ,... ) refer to the sheet at the top of the stack)

These properties ensure that

ˆ It is not possible to dispatch two enter events for a given sheet without an exit event between them. Otherwise property 2) would be violated.

ˆ There fore, no sheet appears on the stack twice.

ˆ It is not possible to dispatch two exit events for a given sheet without an enter event between them. Other property 3) would be violated when dispatching the second exit event.

Algorithm

Let e0 and e be the two most recent events with e0 occurring before e. Let 0 se be e's sheet and let pe be e's position. Let spointer and spointer be the port pointer sheets after processing e0 and e respectively.

0 1. If e is neither an enter nor an exit event, it must be true that mirrored-ancestor(spointer) = mirrored-ancestor(spointer). Let sma = mirrored-ancestor(spointer) and 0 sca = common-ancestor(spointer, spointer). sma = sca may or may not hold, but it is true that sma is an ancestor of sca.

ˆ Dispatch a sequence of synthesized exit events: 0 (exit, spointer, pe) 0 (exit, parent(spointer), pe) . .

(exit, s, pe) where parent(s) = sca ˆ Dispatch a sequence of synthesized enter events:

(enter, s1, pe) where parent(s1) = sca ∧ s1 ancestor of spointer (enter, s2, pe) where parent(s2) = s1 ∧ s2 ancestor of spointer

6 . .

(enter, spointer, pe) 2. If e is an enter event (a) Dispatch synthesized exit events (b) Dispatch e (c) Dispatch synthesized enter events

3. Exit

(a) Dispatch synthesized exit events (b) Dispatch e (c) Dispatch synthesized enter events

Specics of X Has multiple kinds of boundary events, some of which must be handled specially to  our model: "inferior" enter/exit events The events are generated when the pointer moves from a parent X window to a child X window or the other way around. For the rst case (parent  child), X generates an exit event for parent X window. However, since "entered" sheets from a stack, entering a child does equate exiting the parent. Similarly, for the second case (child  parent), X generates an enter event for the parent X window. Grab/ungrab enter/exit events When a pointer button is pressed, X generates enter/exit events. TODO

Feedback overview ˆ "raw" events doesn't have necessarily a target sheet (if you look from the CLIM specication perspective). It is true that in McCLIM device event has a slot sheet and backends are expected to initialize it ˆ not all events have the event position in x (i.e window-repaint-event or window-destroy-event)). Most of them do

7 denitions ˆ three special types of sheets are dened, but given this is a roadmap we should also specify the "focused sheet" for keyboard events: pointer, pressed, grabbed and port-keyboard-input-focus sheets

ˆ port-pointer-sheet description should at least hint that z-ordering should play a role here when leaf sheets overlap, otherwise it is ambigous (be- cause there may be multiple sheets with region containing the pointer which are i.e siblings)

ˆ in port-pressed-sheet instead of repeating denition for port-pointer- sheet I' simply say: if e-release did not occur after epress, the port pressed sheet is the port-pointer-sheet of the e-press event

ˆ port-grabbed-sheet is a sheet which is set (programmatically) with a macro with-pointer-grabbed

ˆ port-keyboard-input-focus is a sheet which is set either programmati- cally or in response to window-manager-focus-event synthesis of boundary events ˆ the stack description is clear and describes accurately how that should behave

ˆ in the algorithm: 1. OK, 2. true (b, c are glued in the PR), 3. True (a,b are glued in the PR)

8