Below is the description of the focus model for multiple keyboards. I have implemented and tested all but the PointerRoot/None cases and so far it seems to work, but then again, there's tricky bits in the details.
Two things make the focus model trickier than the enter/leave model: NotifyPointer events and the ability to set the focus to PointerRoot/None. Both of these may cause unbalanced events. Assumptions for this document: A is the current focus window. B is the window the focus is about to change to. W is the window we want to deliver events to. P is the pointer window, i.e. the window the mouse pointer is on at the moment. == Identical cases to the Enter/Leave model == 1. A and B are above W 2. A is above W, B is W 3. A is above W, B is below W 4. A is W, B is above W 5. A and B are W 6. A is W, B is below W 7. A is below W, B is above W 8. A is below W, B is W 9. A is below W, B is below W Each of these cases exists in six varieties, P is below A, P is A, P is above A, P is below B, P is B and P is above B. The only exception are PointerRoot/None cases which only have three varieties of P. The implementation of all cases that do not include None or PointerRoot is equivalent to the enter/leave model described in http://lists.freedesktop.org/archives/xorg/2008-August/037606.html (provided NotifyPointer is ignored) === Special NotifyPointer handling === NotifyPointer handling is different each case, and in the MPX model NotifyPointer handling depends on the local treatment of an event. Since the model allows for changing the detail field, the NotifyPointer handling must be adjusted to fit the core protocol description for the new state of the detail field. For example, if a window receives a FocusIn(NotifyInferior) and P is below B but not A or below A, FocusIn(NotifyPointer) must be sent between B and including P. If B has a descendant with a focus, supress all events. The core protocol spec define that a NotifyPointer may be sent to the descendants of a window * receiving a FocusIn(NotifyInferior), if they are not descendants of the source window. * receiving a FocusOut(NotifyInferior), if they are not descendants of the target window. * receiving a FocusOut(NotifyNonlinear). * receiving a FocusIn(NotifyNonlinear). The various PointerRoot/None cases are ignored for now. The problem we face with these cases is the presence of multiple pointers. Given pointers P1 and P2, paired with keyboards K1 and K2, respectively, may provide the case where NotifyPointer events are sent to windows based on location of P2. Could this be a problem? Even worse, changes in the detail field for local adjustments may result in a client receiving to sets of NotifyPointer events - this cannot happen in the core model. The solution to this would be to tie NotifyPointer events to the keyboard that focus events are being sent for. For example, the detail is changed to NotifyInferior because of the keyboard K's focus in a descendant of W. Only send NotifyPointer events for the pointer paired with K (if appropriate). == Focus cases that do not exist in the enter/leave model == Case 10: A is W, B is PointerRoot or None and W is NOT a root window. Core: FocusOut(Nonlinear) to W MPX: 10.a: if W has another focus, suppress the event 10.b: otherwise, if a descendant of W has another focus, the focus window as seen by W switches to this descendant. FocusOut(Inferior) to W 10.c: otherwise, FocusOut(Nonlinear) to W Case 11: A is W, B is PointerRoot or None and W is a root window Core: FocusOut(Nonlinear) to W, then FocusIn(PointerRoot or None) to W MPX: 11.a: if W has another focus, suppress the event 11.b: otherwise, if a descendant of W has another focus, the focus window as seen by W switches to this descendant. FocusOut(Inferior) to W 11.c: otherwise, FocusOut(Nonlinear) to W, then FocusIn(PointerRoot or None) to W Case 12: A is below W, B is PointerRoot or None and W is NOT a root window Core: FocusOut(NonlinearVirtual) to W MPX: 12.a: if W has another focus, suppress the event, 12.b: otherwise, if a descendant of W has another focus, the focus window as seen by W does not change. suppress the event. 12.c: otherwise, FocusOut(NonlinearVirtual) to W Case 13: A is below W, B is PointerRoot or None and W is a root window Core: FocusOut(NonlinearVirtual) to W, then FocusIn(PointerRoot or None) to W MPX: 13.a: if W has another focus, suppress the event 13.b: otherwise, if a descendant of W has another focus, the focus window as seen by W does not change. suppress the event. 13.c: otherwise, FocusOut(NonlinearVirtual) to W, then FocusIn(PointerRoot or None) Case 14: A is PointerRoot or None, B is W and W is NOT a root window Core: FocusIn(Nonlinear) to W MPX: 14.a: if W has another focus, suppress the event 14.b: otherwise, if a descendant of W has another focus, the focus as seen by W changes from the descendant to W. FocusIn(Inferior) to W 14.c: otherwise, FocusIn(Nonlinear) to W Case 15: A is PointerRoot or None, B is W and W is a root window Core: FocusOut(PointerRoot or None) to W, then FocusIn(Nonlinear) to W MPX: 15.a: if W has another focus, suppress the event 15.b: otherwise, if a descendant of W has another focus, the focus as seen by W changes from the descendant to W. FocusIn(Inferior) to W 15.c: otherwise, FocusOut(PointerRoot or None) to W, then FocusIn(Nonlinear) to W Case 16: A is PointerRoot or None, B is below W and W is NOT a root window Core: FocusIn(NonlinearVirtual) to W MPX: 16.a: if W has another focus, suppress the event 16.b: otherwise, if a descendant of W has another focus, the focus as seen by W does not change. suppress the event. 16.c: otherwise, FocusIn(NonlinearVirtual) to W Case 17: A is PointerRoot or None, B is below W and W is a root window Core: FocusOut(PointerRoot or None) to W, then FocusIn(NonlinearWirtual) to W MPX: 17.a: if W has another focus, suppress the event 17.b: otherwise, if a descendant of W has another focus, the focus as seen by W does not change. suppress the event. 17.c: otherwise, FocusOut(PointerRoot or None) to W, then FocusIn(NonlinearVirtual) to W Case 18: A is PointerRoot or None, B is None or PointerRoot and W is NOT a root window Core: No event to W MPX: No event to W Case 19: A is PointerRoot or None, B is None or PointerRoot and W is a root window Core: FocusOut(PointerRoot or None) to W, then FocusIn(None or PointerRoot) to W MPX: 19.a: if W has another focus, suppress the event. 19.b: otherwise, if a descendant of W has another focus, the focus window as seen by W does not change. suppress the event 19.c: otherwise, FocusOut(PointerRoot or None) to W, then FocusIn(None or PointerRoot) to W Case 20: A is not a descendant of W, B is PointerRoot or None and W is a root window Core: FocusIn(PointerRoot or None) to W MPX: 20.a: if W has another focus, suppress the event 20.b: otherwise, if a descendant of W has another focus, the focus window as seen by W does not change. suppress the event. 20.c: otherwise, FocusIn(PointerRoot or None) to W Case 21: A is PointerRoot or None, B is NOT below W and W is a root window. Core: FocusOut(PointerRoot or None) to W MPX: 21.a: if W has another focus, suppress the event 21.b: otherwise, if a descendant of W has another focus, the focus window as seen by W does not change. suppress the event. 21.c: otherwise, FocusOut(PointerRoot or None) to W Problems: Unbalanced PointerRoot or None events. Assuming F1 and F2 are two foci. F1 and F2 are in window A. F1 changes to PointerRoot. No event is sent to the root window. F2 changes to window B on a different screen. FocusOut(NonlinearVirtual) is sent to the root window. If F1 now changes back from PointerRoot to A, the root window would receive an unbalanced FocusOut(PointerRoot). NotifyPointer in the PointerRoot or None cases may be sent: * to the descendants of a window receiving a FocusOut(Nonlinear) * to the descendants of a window receiving a FocusIn(Nonlinear) * to the descendants of a root window receiving FocusIn(PointerRoot) * to the descendants of a root window receiving FocusOut(PointerRoot) These cases suffer from the same problems as the other cases, but also from the following requirement: "If the old focus is PointerRoot, FocusOut with detail Pointer is generated on each window from P up to and including P’s root (in order)" [X protocol spec, p 81] The "old focus" would need to be determined by running through all keyboards, checking the focus and eliminating those root windows with an explicitly focused keyboard. Nonetheless, it leaves the case where some root windows have a perceived PointerRoot/None state and others a NotifyInferior/Nonlinear. Comments? Cheers, Peter _______________________________________________ xorg mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/xorg
