2 * Copyright © 2008 Red Hat, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
23 * Authors: Peter Hutterer
27 #ifdef HAVE_DIX_CONFIG_H
28 #include <dix-config.h>
32 #include <X11/extensions/XI2.h>
33 #include <X11/extensions/XIproto.h>
34 #include <X11/extensions/XI2proto.h>
36 #include "windowstr.h"
37 #include "scrnintstr.h"
38 #include "exglobals.h"
39 #include "enterleave.h"
40 #include "eventconvert.h"
42 #include "inpututils.h"
46 * This file describes the model for sending core enter/leave events and
47 * focus in/out in the case of multiple pointers/keyboard foci.
49 * Since we can't send more than one Enter or Leave/Focus in or out event per
50 * window to a core client without confusing it, this is a rather complicated
53 * For a full description of the enter/leave model from a window's
55 * http://lists.freedesktop.org/archives/xorg/2008-August/037606.html
57 * For a full description of the focus in/out model from a window's
59 * http://lists.freedesktop.org/archives/xorg/2008-December/041740.html
62 * - The core protocol spec says that "In a LeaveNotify event, if a child of the
63 * event window contains the initial position of the pointer, then the child
64 * component is set to that child. Otherwise, it is None. For an EnterNotify
65 * event, if a child of the event window contains the final pointer position,
66 * then the child component is set to that child. Otherwise, it is None."
68 * By inference, this means that only NotifyVirtual or NotifyNonlinearVirtual
69 * events may have a subwindow set to other than None.
71 * - NotifyPointer events may be sent if the focus changes from window A to
72 * B. The assumption used in this model is that NotifyPointer events are only
73 * sent for the pointer paired with the keyboard that is involved in the focus
74 * events. For example, if F(W) changes because of keyboard 2, then
75 * NotifyPointer events are only sent for pointer 2.
78 static WindowPtr PointerWindows
[MAXDEVICES
];
79 static WindowPtr FocusWindows
[MAXDEVICES
];
82 * Return TRUE if 'win' has a pointer within its boundaries, excluding child
86 HasPointer(DeviceIntPtr dev
, WindowPtr win
)
90 /* FIXME: The enter/leave model does not cater for grabbed devices. For
91 * now, a quickfix: if the device about to send an enter/leave event to
92 * a window is grabbed, assume there is no pointer in that window.
94 * There isn't enough beer in my fridge to fix this properly.
96 if (dev
->deviceGrab
.grab
)
99 for (i
= 0; i
< MAXDEVICES
; i
++)
100 if (PointerWindows
[i
] == win
)
107 * Return TRUE if at least one keyboard focus is set to 'win' (excluding
108 * descendants of win).
111 HasFocus(WindowPtr win
)
115 for (i
= 0; i
< MAXDEVICES
; i
++)
116 if (FocusWindows
[i
] == win
)
123 * Return the window the device dev is currently on.
126 PointerWin(DeviceIntPtr dev
)
128 return PointerWindows
[dev
->id
];
132 * Search for the first window below 'win' that has a pointer directly within
133 * it's boundaries (excluding boundaries of its own descendants).
135 * @return The child window that has the pointer within its boundaries or
139 FirstPointerChild(WindowPtr win
)
143 for (i
= 0; i
< MAXDEVICES
; i
++) {
144 if (PointerWindows
[i
] && IsParent(win
, PointerWindows
[i
]))
145 return PointerWindows
[i
];
152 * Search for the first window below 'win' that has a focus directly within
153 * it's boundaries (excluding boundaries of its own descendants).
155 * @return The child window that has the pointer within its boundaries or
159 FirstFocusChild(WindowPtr win
)
163 for (i
= 0; i
< MAXDEVICES
; i
++) {
164 if (FocusWindows
[i
] && FocusWindows
[i
] != PointerRootWin
&&
165 IsParent(win
, FocusWindows
[i
]))
166 return FocusWindows
[i
];
173 * Set the presence flag for dev to mark that it is now in 'win'.
176 EnterWindow(DeviceIntPtr dev
, WindowPtr win
, int mode
)
178 PointerWindows
[dev
->id
] = win
;
182 * Unset the presence flag for dev to mark that it is not in 'win' anymore.
185 LeaveWindow(DeviceIntPtr dev
)
187 PointerWindows
[dev
->id
] = NULL
;
191 * Set the presence flag for dev to mark that it is now in 'win'.
194 SetFocusIn(DeviceIntPtr dev
, WindowPtr win
)
196 FocusWindows
[dev
->id
] = win
;
200 * Unset the presence flag for dev to mark that it is not in 'win' anymore.
203 SetFocusOut(DeviceIntPtr dev
)
205 FocusWindows
[dev
->id
] = NULL
;
209 * Return the common ancestor of 'a' and 'b' (if one exists).
210 * @param a A window with the same ancestor as b.
211 * @param b A window with the same ancestor as a.
212 * @return The window that is the first ancestor of both 'a' and 'b', or the
213 * NullWindow if they do not have a common ancestor.
216 CommonAncestor(WindowPtr a
, WindowPtr b
)
218 for (b
= b
->parent
; b
; b
= b
->parent
)
225 * Send enter notifies to all windows between 'ancestor' and 'child' (excluding
226 * both). Events are sent running up the window hierarchy. This function
230 DeviceEnterNotifies(DeviceIntPtr dev
,
232 WindowPtr ancestor
, WindowPtr child
, int mode
, int detail
)
234 WindowPtr parent
= child
->parent
;
236 if (ancestor
== parent
)
238 DeviceEnterNotifies(dev
, sourceid
, ancestor
, parent
, mode
, detail
);
239 DeviceEnterLeaveEvent(dev
, sourceid
, XI_Enter
, mode
, detail
, parent
,
244 * Send enter notifies to all windows between 'ancestor' and 'child' (excluding
245 * both). Events are sent running down the window hierarchy. This function
249 CoreEnterNotifies(DeviceIntPtr dev
,
250 WindowPtr ancestor
, WindowPtr child
, int mode
, int detail
)
252 WindowPtr parent
= child
->parent
;
254 if (ancestor
== parent
)
256 CoreEnterNotifies(dev
, ancestor
, parent
, mode
, detail
);
259 A is above W, B is a descendant
261 Classically: The move generates an EnterNotify on W with a detail of
262 Virtual or NonlinearVirtual
265 Case 3A: There is at least one other pointer on W itself
266 P(W) doesn't change, so the event should be suppressed
267 Case 3B: Otherwise, if there is at least one other pointer in a
269 P(W) stays on the same descendant, or changes to a different
270 descendant. The event should be suppressed.
272 P(W) moves from a window above W to a descendant. The subwindow
273 field is set to the child containing the descendant. The detail
274 may need to be changed from Virtual to NonlinearVirtual depending
275 on the previous P(W). */
277 if (!HasPointer(dev
, parent
) && !FirstPointerChild(parent
))
278 CoreEnterLeaveEvent(dev
, EnterNotify
, mode
, detail
, parent
,
283 CoreLeaveNotifies(DeviceIntPtr dev
,
284 WindowPtr child
, WindowPtr ancestor
, int mode
, int detail
)
288 if (ancestor
== child
)
291 for (win
= child
->parent
; win
!= ancestor
; win
= win
->parent
) {
293 A is a descendant of W, B is above W
295 Classically: A LeaveNotify is generated on W with a detail of Virtual
299 Case 3A: There is at least one other pointer on W itself
300 P(W) doesn't change, the event should be suppressed.
301 Case 3B: Otherwise, if there is at least one other pointer in a
303 P(W) stays on the same descendant, or changes to a different
304 descendant. The event should be suppressed.
306 P(W) changes from the descendant of W to a window above W.
307 The detail may need to be changed from Virtual to NonlinearVirtual
308 or vice-versa depending on the new P(W). */
310 /* If one window has a pointer or a child with a pointer, skip some
312 if (HasPointer(dev
, win
) || FirstPointerChild(win
))
315 CoreEnterLeaveEvent(dev
, LeaveNotify
, mode
, detail
, win
,
323 * Send leave notifies to all windows between 'child' and 'ancestor'.
324 * Events are sent running up the hierarchy.
327 DeviceLeaveNotifies(DeviceIntPtr dev
,
329 WindowPtr child
, WindowPtr ancestor
, int mode
, int detail
)
333 if (ancestor
== child
)
335 for (win
= child
->parent
; win
!= ancestor
; win
= win
->parent
) {
336 DeviceEnterLeaveEvent(dev
, sourceid
, XI_Leave
, mode
, detail
, win
,
343 * Pointer dev moves from A to B and A neither a descendant of B nor is
344 * B a descendant of A.
347 CoreEnterLeaveNonLinear(DeviceIntPtr dev
, WindowPtr A
, WindowPtr B
, int mode
)
349 WindowPtr X
= CommonAncestor(A
, B
);
354 Classically: The move generates a LeaveNotify on W with a detail of
355 Ancestor or Nonlinear
358 Case 3A: There is at least one other pointer on W itself
359 P(W) doesn't change, the event should be suppressed
360 Case 3B: Otherwise, if there is at least one other pointer in a
362 P(W) changes from W to a descendant of W. The subwindow field
363 is set to the child containing the new P(W), the detail field
366 The pointer window moves from W to a window above W.
367 The detail may need to be changed from Ancestor to Nonlinear or
368 vice versa depending on the the new P(W)
371 if (!HasPointer(dev
, A
)) {
372 WindowPtr child
= FirstPointerChild(A
);
375 CoreEnterLeaveEvent(dev
, LeaveNotify
, mode
, NotifyInferior
, A
,
378 CoreEnterLeaveEvent(dev
, LeaveNotify
, mode
, NotifyNonlinear
, A
,
382 CoreLeaveNotifies(dev
, A
, X
, mode
, NotifyNonlinearVirtual
);
386 A is a descendant of W, B is a descendant of W
388 Classically: No events are generated on W
389 MPX: The pointer window stays the same or moves to a different
390 descendant of W. No events should be generated on W.
392 Therefore, no event to X.
395 CoreEnterNotifies(dev
, X
, B
, mode
, NotifyNonlinearVirtual
);
400 Classically: The move generates an EnterNotify on W with a detail of
401 Ancestor or Nonlinear
404 Case 2A: There is at least one other pointer on W itself
405 P(W) doesn't change, so the event should be suppressed
406 Case 2B: Otherwise, if there is at least one other pointer in a
408 P(W) moves from a descendant to W. detail is changed to Inferior,
409 subwindow is set to the child containing the previous P(W)
411 P(W) changes from a window above W to W itself.
412 The detail may need to be changed from Ancestor to Nonlinear
413 or vice-versa depending on the previous P(W). */
415 if (!HasPointer(dev
, B
)) {
416 WindowPtr child
= FirstPointerChild(B
);
419 CoreEnterLeaveEvent(dev
, EnterNotify
, mode
, NotifyInferior
, B
,
422 CoreEnterLeaveEvent(dev
, EnterNotify
, mode
, NotifyNonlinear
, B
,
428 * Pointer dev moves from A to B and A is a descendant of B.
431 CoreEnterLeaveToAncestor(DeviceIntPtr dev
, WindowPtr A
, WindowPtr B
, int mode
)
436 Classically: The move generates a LeaveNotify on W with a detail of
437 Ancestor or Nonlinear
440 Case 3A: There is at least one other pointer on W itself
441 P(W) doesn't change, the event should be suppressed
442 Case 3B: Otherwise, if there is at least one other pointer in a
444 P(W) changes from W to a descendant of W. The subwindow field
445 is set to the child containing the new P(W), the detail field
448 The pointer window moves from W to a window above W.
449 The detail may need to be changed from Ancestor to Nonlinear or
450 vice versa depending on the the new P(W)
452 if (!HasPointer(dev
, A
)) {
453 WindowPtr child
= FirstPointerChild(A
);
456 CoreEnterLeaveEvent(dev
, LeaveNotify
, mode
, NotifyInferior
, A
,
459 CoreEnterLeaveEvent(dev
, LeaveNotify
, mode
, NotifyAncestor
, A
,
463 CoreLeaveNotifies(dev
, A
, B
, mode
, NotifyVirtual
);
466 A is a descendant of W, B is W
468 Classically: A EnterNotify is generated on W with a detail of
472 Case 3A: There is at least one other pointer on W itself
473 P(W) doesn't change, the event should be suppressed
475 P(W) changes from a descendant to W itself. The subwindow
476 field should be set to the child containing the old P(W) <<< WRONG */
478 if (!HasPointer(dev
, B
))
479 CoreEnterLeaveEvent(dev
, EnterNotify
, mode
, NotifyInferior
, B
, None
);
484 * Pointer dev moves from A to B and B is a descendant of A.
487 CoreEnterLeaveToDescendant(DeviceIntPtr dev
, WindowPtr A
, WindowPtr B
, int mode
)
490 A is W, B is a descendant of W
492 Classically: A LeaveNotify is generated on W with a detail of
496 Case 3A: There is at least one other pointer on W itself
497 P(W) doesn't change, the event should be suppressed
499 P(W) changes from W to a descendant of W. The subwindow field
500 is set to the child containing the new P(W) <<< THIS IS WRONG */
502 if (!HasPointer(dev
, A
))
503 CoreEnterLeaveEvent(dev
, LeaveNotify
, mode
, NotifyInferior
, A
, None
);
505 CoreEnterNotifies(dev
, A
, B
, mode
, NotifyVirtual
);
510 Classically: The move generates an EnterNotify on W with a detail of
511 Ancestor or Nonlinear
514 Case 2A: There is at least one other pointer on W itself
515 P(W) doesn't change, so the event should be suppressed
516 Case 2B: Otherwise, if there is at least one other pointer in a
518 P(W) moves from a descendant to W. detail is changed to Inferior,
519 subwindow is set to the child containing the previous P(W)
521 P(W) changes from a window above W to W itself.
522 The detail may need to be changed from Ancestor to Nonlinear
523 or vice-versa depending on the previous P(W). */
525 if (!HasPointer(dev
, B
)) {
526 WindowPtr child
= FirstPointerChild(B
);
529 CoreEnterLeaveEvent(dev
, EnterNotify
, mode
, NotifyInferior
, B
,
532 CoreEnterLeaveEvent(dev
, EnterNotify
, mode
, NotifyAncestor
, B
,
538 CoreEnterLeaveEvents(DeviceIntPtr dev
, WindowPtr from
, WindowPtr to
, int mode
)
545 if (IsParent(from
, to
))
546 CoreEnterLeaveToDescendant(dev
, from
, to
, mode
);
547 else if (IsParent(to
, from
))
548 CoreEnterLeaveToAncestor(dev
, from
, to
, mode
);
550 CoreEnterLeaveNonLinear(dev
, from
, to
, mode
);
552 EnterWindow(dev
, to
, mode
);
556 DeviceEnterLeaveEvents(DeviceIntPtr dev
,
557 int sourceid
, WindowPtr from
, WindowPtr to
, int mode
)
559 if (IsParent(from
, to
)) {
560 DeviceEnterLeaveEvent(dev
, sourceid
, XI_Leave
, mode
, NotifyInferior
,
562 DeviceEnterNotifies(dev
, sourceid
, from
, to
, mode
, NotifyVirtual
);
563 DeviceEnterLeaveEvent(dev
, sourceid
, XI_Enter
, mode
, NotifyAncestor
, to
,
566 else if (IsParent(to
, from
)) {
567 DeviceEnterLeaveEvent(dev
, sourceid
, XI_Leave
, mode
, NotifyAncestor
,
569 DeviceLeaveNotifies(dev
, sourceid
, from
, to
, mode
, NotifyVirtual
);
570 DeviceEnterLeaveEvent(dev
, sourceid
, XI_Enter
, mode
, NotifyInferior
, to
,
573 else { /* neither from nor to is descendent of the other */
574 WindowPtr common
= CommonAncestor(to
, from
);
576 /* common == NullWindow ==> different screens */
577 DeviceEnterLeaveEvent(dev
, sourceid
, XI_Leave
, mode
, NotifyNonlinear
,
579 DeviceLeaveNotifies(dev
, sourceid
, from
, common
, mode
,
580 NotifyNonlinearVirtual
);
581 DeviceEnterNotifies(dev
, sourceid
, common
, to
, mode
,
582 NotifyNonlinearVirtual
);
583 DeviceEnterLeaveEvent(dev
, sourceid
, XI_Enter
, mode
, NotifyNonlinear
,
589 * Figure out if enter/leave events are necessary and send them to the
590 * appropriate windows.
592 * @param fromWin Window the sprite moved out of.
593 * @param toWin Window the sprite moved into.
596 DoEnterLeaveEvents(DeviceIntPtr pDev
,
597 int sourceid
, WindowPtr fromWin
, WindowPtr toWin
, int mode
)
599 if (!IsPointerDevice(pDev
))
602 if (fromWin
== toWin
)
605 if (mode
!= XINotifyPassiveGrab
&& mode
!= XINotifyPassiveUngrab
)
606 CoreEnterLeaveEvents(pDev
, fromWin
, toWin
, mode
);
607 DeviceEnterLeaveEvents(pDev
, sourceid
, fromWin
, toWin
, mode
);
611 FixDeviceValuator(DeviceIntPtr dev
, deviceValuator
* ev
, ValuatorClassPtr v
,
614 int nval
= v
->numAxes
- first
;
616 ev
->type
= DeviceValuator
;
617 ev
->deviceid
= dev
->id
;
618 ev
->num_valuators
= nval
< 3 ? nval
: 3;
619 ev
->first_valuator
= first
;
620 switch (ev
->num_valuators
) {
622 ev
->valuator2
= v
->axisVal
[first
+ 2];
624 ev
->valuator1
= v
->axisVal
[first
+ 1];
626 ev
->valuator0
= v
->axisVal
[first
];
629 first
+= ev
->num_valuators
;
633 FixDeviceStateNotify(DeviceIntPtr dev
, deviceStateNotify
* ev
, KeyClassPtr k
,
634 ButtonClassPtr b
, ValuatorClassPtr v
, int first
)
636 ev
->type
= DeviceStateNotify
;
637 ev
->deviceid
= dev
->id
;
638 ev
->time
= currentTime
.milliseconds
;
639 ev
->classes_reported
= 0;
642 ev
->num_valuators
= 0;
645 ev
->classes_reported
|= (1 << ButtonClass
);
646 ev
->num_buttons
= b
->numButtons
;
647 memcpy((char *) ev
->buttons
, (char *) b
->down
, 4);
650 ev
->classes_reported
|= (1 << KeyClass
);
651 ev
->num_keys
= k
->xkbInfo
->desc
->max_key_code
-
652 k
->xkbInfo
->desc
->min_key_code
;
653 memmove((char *) &ev
->keys
[0], (char *) k
->down
, 4);
656 int nval
= v
->numAxes
- first
;
658 ev
->classes_reported
|= (1 << ValuatorClass
);
659 ev
->classes_reported
|= valuator_get_mode(dev
, 0) << ModeBitsShift
;
660 ev
->num_valuators
= nval
< 3 ? nval
: 3;
661 switch (ev
->num_valuators
) {
663 ev
->valuator2
= v
->axisVal
[first
+ 2];
665 ev
->valuator1
= v
->axisVal
[first
+ 1];
667 ev
->valuator0
= v
->axisVal
[first
];
675 DeliverStateNotifyEvent(DeviceIntPtr dev
, WindowPtr win
)
678 deviceStateNotify
*ev
, *sev
;
679 deviceKeyStateNotify
*kev
;
680 deviceButtonStateNotify
*bev
;
685 int nval
= 0, nkeys
= 0, nbuttons
= 0, first
= 0;
687 if (!(wOtherInputMasks(win
)) ||
688 !(wOtherInputMasks(win
)->inputEvents
[dev
->id
] & DeviceStateNotifyMask
))
691 if ((b
= dev
->button
) != NULL
) {
692 nbuttons
= b
->numButtons
;
696 if ((k
= dev
->key
) != NULL
) {
697 nkeys
= k
->xkbInfo
->desc
->max_key_code
- k
->xkbInfo
->desc
->min_key_code
;
704 if ((v
= dev
->valuator
) != NULL
) {
713 evcount
+= ((nval
- 7) / 3);
717 sev
= ev
= (deviceStateNotify
*) malloc(evcount
* sizeof(xEvent
));
718 FixDeviceStateNotify(dev
, ev
, NULL
, NULL
, NULL
, first
);
721 FixDeviceStateNotify(dev
, ev
++, NULL
, b
, v
, first
);
725 (ev
- 1)->deviceid
|= MORE_EVENTS
;
726 bev
= (deviceButtonStateNotify
*) ev
++;
727 bev
->type
= DeviceButtonStateNotify
;
728 bev
->deviceid
= dev
->id
;
729 memcpy((char *) &bev
->buttons
[4], (char *) &b
->down
[4],
733 (ev
- 1)->deviceid
|= MORE_EVENTS
;
734 FixDeviceValuator(dev
, (deviceValuator
*) ev
++, v
, first
);
741 FixDeviceStateNotify(dev
, ev
++, k
, NULL
, v
, first
);
745 (ev
- 1)->deviceid
|= MORE_EVENTS
;
746 kev
= (deviceKeyStateNotify
*) ev
++;
747 kev
->type
= DeviceKeyStateNotify
;
748 kev
->deviceid
= dev
->id
;
749 memmove((char *) &kev
->keys
[0], (char *) &k
->down
[4], 28);
752 (ev
- 1)->deviceid
|= MORE_EVENTS
;
753 FixDeviceValuator(dev
, (deviceValuator
*) ev
++, v
, first
);
760 FixDeviceStateNotify(dev
, ev
++, NULL
, NULL
, v
, first
);
764 (ev
- 1)->deviceid
|= MORE_EVENTS
;
765 FixDeviceValuator(dev
, (deviceValuator
*) ev
++, v
, first
);
771 DeliverEventsToWindow(dev
, win
, (xEvent
*) sev
, evcount
,
772 DeviceStateNotifyMask
, NullGrab
);
777 DeviceFocusEvent(DeviceIntPtr dev
, int type
, int mode
, int detail
,
781 xXIFocusInEvent
*xi2event
;
785 mouse
= IsFloating(dev
) ? dev
: GetMaster(dev
, MASTER_POINTER
);
788 btlen
= (mouse
->button
) ? bits_to_bytes(mouse
->button
->numButtons
) : 0;
789 btlen
= bytes_to_int32(btlen
);
790 len
= sizeof(xXIFocusInEvent
) + btlen
* 4;
792 xi2event
= calloc(1, len
);
793 xi2event
->type
= GenericEvent
;
794 xi2event
->extension
= IReqCode
;
795 xi2event
->evtype
= type
;
796 xi2event
->length
= bytes_to_int32(len
- sizeof(xEvent
));
797 xi2event
->buttons_len
= btlen
;
798 xi2event
->detail
= detail
;
799 xi2event
->time
= currentTime
.milliseconds
;
800 xi2event
->deviceid
= dev
->id
;
801 xi2event
->sourceid
= dev
->id
; /* a device doesn't change focus by itself */
802 xi2event
->mode
= mode
;
803 xi2event
->root_x
= double_to_fp1616(mouse
->spriteInfo
->sprite
->hot
.x
);
804 xi2event
->root_y
= double_to_fp1616(mouse
->spriteInfo
->sprite
->hot
.y
);
806 for (i
= 0; mouse
&& mouse
->button
&& i
< mouse
->button
->numButtons
; i
++)
807 if (BitIsOn(mouse
->button
->down
, i
))
808 SetBit(&xi2event
[1], mouse
->button
->map
[i
]);
811 xi2event
->mods
.base_mods
= dev
->key
->xkbInfo
->state
.base_mods
;
812 xi2event
->mods
.latched_mods
= dev
->key
->xkbInfo
->state
.latched_mods
;
813 xi2event
->mods
.locked_mods
= dev
->key
->xkbInfo
->state
.locked_mods
;
814 xi2event
->mods
.effective_mods
= dev
->key
->xkbInfo
->state
.mods
;
816 xi2event
->group
.base_group
= dev
->key
->xkbInfo
->state
.base_group
;
817 xi2event
->group
.latched_group
= dev
->key
->xkbInfo
->state
.latched_group
;
818 xi2event
->group
.locked_group
= dev
->key
->xkbInfo
->state
.locked_group
;
819 xi2event
->group
.effective_group
= dev
->key
->xkbInfo
->state
.group
;
822 FixUpEventFromWindow(dev
->spriteInfo
->sprite
, (xEvent
*) xi2event
, pWin
,
825 DeliverEventsToWindow(dev
, pWin
, (xEvent
*) xi2event
, 1,
826 GetEventFilter(dev
, (xEvent
*) xi2event
), NullGrab
);
831 event
= (deviceFocus
) {
834 .type
= (type
== XI_FocusIn
) ? DeviceFocusIn
: DeviceFocusOut
,
836 .window
= pWin
->drawable
.id
,
837 .time
= currentTime
.milliseconds
840 DeliverEventsToWindow(dev
, pWin
, (xEvent
*) &event
, 1,
841 DeviceFocusChangeMask
, NullGrab
);
843 if (event
.type
== DeviceFocusIn
)
844 DeliverStateNotifyEvent(dev
, pWin
);
848 * Send focus out events to all windows between 'child' and 'ancestor'.
849 * Events are sent running up the hierarchy.
852 DeviceFocusOutEvents(DeviceIntPtr dev
,
853 WindowPtr child
, WindowPtr ancestor
, int mode
, int detail
)
857 if (ancestor
== child
)
859 for (win
= child
->parent
; win
!= ancestor
; win
= win
->parent
)
860 DeviceFocusEvent(dev
, XI_FocusOut
, mode
, detail
, win
);
864 * Send enter notifies to all windows between 'ancestor' and 'child' (excluding
865 * both). Events are sent running up the window hierarchy. This function
869 DeviceFocusInEvents(DeviceIntPtr dev
,
870 WindowPtr ancestor
, WindowPtr child
, int mode
, int detail
)
872 WindowPtr parent
= child
->parent
;
874 if (ancestor
== parent
|| !parent
)
876 DeviceFocusInEvents(dev
, ancestor
, parent
, mode
, detail
);
877 DeviceFocusEvent(dev
, XI_FocusIn
, mode
, detail
, parent
);
881 * Send FocusIn events to all windows between 'ancestor' and 'child' (excluding
882 * both). Events are sent running down the window hierarchy. This function
886 CoreFocusInEvents(DeviceIntPtr dev
,
887 WindowPtr ancestor
, WindowPtr child
, int mode
, int detail
)
889 WindowPtr parent
= child
->parent
;
891 if (ancestor
== parent
)
893 CoreFocusInEvents(dev
, ancestor
, parent
, mode
, detail
);
896 A is above W, B is a descendant
898 Classically: The move generates an FocusIn on W with a detail of
899 Virtual or NonlinearVirtual
902 Case 3A: There is at least one other focus on W itself
903 F(W) doesn't change, so the event should be suppressed
904 Case 3B: Otherwise, if there is at least one other focus in a
906 F(W) stays on the same descendant, or changes to a different
907 descendant. The event should be suppressed.
909 F(W) moves from a window above W to a descendant. The detail may
910 need to be changed from Virtual to NonlinearVirtual depending
911 on the previous F(W). */
913 if (!HasFocus(parent
) && !FirstFocusChild(parent
))
914 CoreFocusEvent(dev
, FocusIn
, mode
, detail
, parent
);
918 CoreFocusOutEvents(DeviceIntPtr dev
,
919 WindowPtr child
, WindowPtr ancestor
, int mode
, int detail
)
923 if (ancestor
== child
)
926 for (win
= child
->parent
; win
!= ancestor
; win
= win
->parent
) {
928 A is a descendant of W, B is above W
930 Classically: A FocusOut is generated on W with a detail of Virtual
934 Case 3A: There is at least one other focus on W itself
935 F(W) doesn't change, the event should be suppressed.
936 Case 3B: Otherwise, if there is at least one other focus in a
938 F(W) stays on the same descendant, or changes to a different
939 descendant. The event should be suppressed.
941 F(W) changes from the descendant of W to a window above W.
942 The detail may need to be changed from Virtual to NonlinearVirtual
943 or vice-versa depending on the new P(W). */
945 /* If one window has a focus or a child with a focuspointer, skip some
947 if (HasFocus(win
) || FirstFocusChild(win
))
950 CoreFocusEvent(dev
, FocusOut
, mode
, detail
, win
);
955 * Send FocusOut(NotifyPointer) events from the current pointer window (which
956 * is a descendant of pwin_parent) up to (excluding) pwin_parent.
958 * NotifyPointer events are only sent for the device paired with dev.
960 * If the current pointer window is a descendant of 'exclude' or an ancestor of
961 * 'exclude', no events are sent. If the current pointer IS 'exclude', events
965 CoreFocusOutNotifyPointerEvents(DeviceIntPtr dev
,
966 WindowPtr pwin_parent
,
967 WindowPtr exclude
, int mode
, int inclusive
)
971 P
= PointerWin(GetMaster(dev
, POINTER_OR_FLOAT
));
975 if (!IsParent(pwin_parent
, P
))
976 if (!(pwin_parent
== P
&& inclusive
))
979 if (exclude
!= None
&& exclude
!= PointerRootWin
&&
980 (IsParent(exclude
, P
) || IsParent(P
, exclude
)))
983 stopAt
= (inclusive
) ? pwin_parent
->parent
: pwin_parent
;
985 for (; P
&& P
!= stopAt
; P
= P
->parent
)
986 CoreFocusEvent(dev
, FocusOut
, mode
, NotifyPointer
, P
);
990 * DO NOT CALL DIRECTLY.
991 * Recursion helper for CoreFocusInNotifyPointerEvents.
994 CoreFocusInRecurse(DeviceIntPtr dev
,
995 WindowPtr win
, WindowPtr stopAt
, int mode
, int inclusive
)
997 if ((!inclusive
&& win
== stopAt
) || !win
)
1000 CoreFocusInRecurse(dev
, win
->parent
, stopAt
, mode
, inclusive
);
1001 CoreFocusEvent(dev
, FocusIn
, mode
, NotifyPointer
, win
);
1005 * Send FocusIn(NotifyPointer) events from pwin_parent down to
1006 * including the current pointer window (which is a descendant of pwin_parent).
1008 * @param pwin The pointer window.
1009 * @param exclude If the pointer window is a child of 'exclude', no events are
1011 * @param inclusive If TRUE, pwin_parent will receive the event too.
1014 CoreFocusInNotifyPointerEvents(DeviceIntPtr dev
,
1015 WindowPtr pwin_parent
,
1016 WindowPtr exclude
, int mode
, int inclusive
)
1020 P
= PointerWin(GetMaster(dev
, POINTER_OR_FLOAT
));
1022 if (!P
|| P
== exclude
|| (pwin_parent
!= P
&& !IsParent(pwin_parent
, P
)))
1025 if (exclude
!= None
&& (IsParent(exclude
, P
) || IsParent(P
, exclude
)))
1028 CoreFocusInRecurse(dev
, P
, pwin_parent
, mode
, inclusive
);
1032 * Focus of dev moves from A to B and A neither a descendant of B nor is
1033 * B a descendant of A.
1036 CoreFocusNonLinear(DeviceIntPtr dev
, WindowPtr A
, WindowPtr B
, int mode
)
1038 WindowPtr X
= CommonAncestor(A
, B
);
1041 A is W, B is above W
1043 Classically: The change generates a FocusOut on W with a detail of
1044 Ancestor or Nonlinear
1047 Case 3A: There is at least one other focus on W itself
1048 F(W) doesn't change, the event should be suppressed
1049 Case 3B: Otherwise, if there is at least one other focus in a
1051 F(W) changes from W to a descendant of W. The detail field
1054 The focus window moves from W to a window above W.
1055 The detail may need to be changed from Ancestor to Nonlinear or
1056 vice versa depending on the the new F(W)
1060 WindowPtr child
= FirstFocusChild(A
);
1063 /* NotifyPointer P-A unless P is child or below */
1064 CoreFocusOutNotifyPointerEvents(dev
, A
, child
, mode
, FALSE
);
1065 CoreFocusEvent(dev
, FocusOut
, mode
, NotifyInferior
, A
);
1068 /* NotifyPointer P-A */
1069 CoreFocusOutNotifyPointerEvents(dev
, A
, None
, mode
, FALSE
);
1070 CoreFocusEvent(dev
, FocusOut
, mode
, NotifyNonlinear
, A
);
1074 CoreFocusOutEvents(dev
, A
, X
, mode
, NotifyNonlinearVirtual
);
1078 A is a descendant of W, B is a descendant of W
1080 Classically: No events are generated on W
1081 MPX: The focus window stays the same or moves to a different
1082 descendant of W. No events should be generated on W.
1084 Therefore, no event to X.
1087 CoreFocusInEvents(dev
, X
, B
, mode
, NotifyNonlinearVirtual
);
1092 Classically: The move generates an EnterNotify on W with a detail of
1093 Ancestor or Nonlinear
1096 Case 2A: There is at least one other focus on W itself
1097 F(W) doesn't change, so the event should be suppressed
1098 Case 2B: Otherwise, if there is at least one other focus in a
1100 F(W) moves from a descendant to W. detail is changed to Inferior.
1102 F(W) changes from a window above W to W itself.
1103 The detail may need to be changed from Ancestor to Nonlinear
1104 or vice-versa depending on the previous F(W). */
1107 WindowPtr child
= FirstFocusChild(B
);
1110 CoreFocusEvent(dev
, FocusIn
, mode
, NotifyInferior
, B
);
1111 /* NotifyPointer B-P unless P is child or below. */
1112 CoreFocusInNotifyPointerEvents(dev
, B
, child
, mode
, FALSE
);
1115 CoreFocusEvent(dev
, FocusIn
, mode
, NotifyNonlinear
, B
);
1116 /* NotifyPointer B-P unless P is child or below. */
1117 CoreFocusInNotifyPointerEvents(dev
, B
, None
, mode
, FALSE
);
1123 * Focus of dev moves from A to B and A is a descendant of B.
1126 CoreFocusToAncestor(DeviceIntPtr dev
, WindowPtr A
, WindowPtr B
, int mode
)
1129 A is W, B is above W
1131 Classically: The change generates a FocusOut on W with a detail of
1132 Ancestor or Nonlinear
1135 Case 3A: There is at least one other focus on W itself
1136 F(W) doesn't change, the event should be suppressed
1137 Case 3B: Otherwise, if there is at least one other focus in a
1139 F(W) changes from W to a descendant of W. The detail field
1142 The focus window moves from W to a window above W.
1143 The detail may need to be changed from Ancestor to Nonlinear or
1144 vice versa depending on the the new F(W)
1147 WindowPtr child
= FirstFocusChild(A
);
1150 /* NotifyPointer P-A unless P is child or below */
1151 CoreFocusOutNotifyPointerEvents(dev
, A
, child
, mode
, FALSE
);
1152 CoreFocusEvent(dev
, FocusOut
, mode
, NotifyInferior
, A
);
1155 CoreFocusEvent(dev
, FocusOut
, mode
, NotifyAncestor
, A
);
1158 CoreFocusOutEvents(dev
, A
, B
, mode
, NotifyVirtual
);
1161 A is a descendant of W, B is W
1163 Classically: A FocusOut is generated on W with a detail of
1167 Case 3A: There is at least one other focus on W itself
1168 F(W) doesn't change, the event should be suppressed
1170 F(W) changes from a descendant to W itself. */
1173 CoreFocusEvent(dev
, FocusIn
, mode
, NotifyInferior
, B
);
1174 /* NotifyPointer B-P unless P is A or below. */
1175 CoreFocusInNotifyPointerEvents(dev
, B
, A
, mode
, FALSE
);
1180 * Focus of dev moves from A to B and B is a descendant of A.
1183 CoreFocusToDescendant(DeviceIntPtr dev
, WindowPtr A
, WindowPtr B
, int mode
)
1186 A is W, B is a descendant of W
1188 Classically: A FocusOut is generated on W with a detail of
1192 Case 3A: There is at least one other focus on W itself
1193 F(W) doesn't change, the event should be suppressed
1195 F(W) changes from W to a descendant of W. */
1198 /* NotifyPointer P-A unless P is B or below */
1199 CoreFocusOutNotifyPointerEvents(dev
, A
, B
, mode
, FALSE
);
1200 CoreFocusEvent(dev
, FocusOut
, mode
, NotifyInferior
, A
);
1203 CoreFocusInEvents(dev
, A
, B
, mode
, NotifyVirtual
);
1208 Classically: The move generates an FocusIn on W with a detail of
1209 Ancestor or Nonlinear
1212 Case 2A: There is at least one other focus on W itself
1213 F(W) doesn't change, so the event should be suppressed
1214 Case 2B: Otherwise, if there is at least one other focus in a
1216 F(W) moves from a descendant to W. detail is changed to Inferior.
1218 F(W) changes from a window above W to W itself.
1219 The detail may need to be changed from Ancestor to Nonlinear
1220 or vice-versa depending on the previous F(W). */
1223 WindowPtr child
= FirstFocusChild(B
);
1226 CoreFocusEvent(dev
, FocusIn
, mode
, NotifyInferior
, B
);
1227 /* NotifyPointer B-P unless P is child or below. */
1228 CoreFocusInNotifyPointerEvents(dev
, B
, child
, mode
, FALSE
);
1231 CoreFocusEvent(dev
, FocusIn
, mode
, NotifyAncestor
, B
);
1236 HasOtherPointer(WindowPtr win
, DeviceIntPtr exclude
)
1240 for (i
= 0; i
< MAXDEVICES
; i
++)
1241 if (i
!= exclude
->id
&& PointerWindows
[i
] == win
)
1248 * Focus moves from PointerRoot to None or from None to PointerRoot.
1249 * Assumption: Neither A nor B are valid windows.
1252 CoreFocusPointerRootNoneSwitch(DeviceIntPtr dev
,
1253 WindowPtr A
, /* PointerRootWin or NoneWin */
1254 WindowPtr B
, /* NoneWin or PointerRootWin */
1259 int nscreens
= screenInfo
.numScreens
;
1262 if (!noPanoramiXExtension
)
1266 for (i
= 0; i
< nscreens
; i
++) {
1267 root
= screenInfo
.screens
[i
]->root
;
1268 if (!HasOtherPointer(root
, GetMaster(dev
, POINTER_OR_FLOAT
)) &&
1269 !FirstFocusChild(root
)) {
1270 /* If pointer was on PointerRootWin and changes to NoneWin, and
1271 * the pointer paired with dev is below the current root window,
1272 * do a NotifyPointer run. */
1273 if (dev
->focus
&& dev
->focus
->win
== PointerRootWin
&&
1274 B
!= PointerRootWin
) {
1275 WindowPtr ptrwin
= PointerWin(GetMaster(dev
, POINTER_OR_FLOAT
));
1277 if (ptrwin
&& IsParent(root
, ptrwin
))
1278 CoreFocusOutNotifyPointerEvents(dev
, root
, None
, mode
,
1281 CoreFocusEvent(dev
, FocusOut
, mode
,
1282 A
? NotifyPointerRoot
: NotifyDetailNone
, root
);
1283 CoreFocusEvent(dev
, FocusIn
, mode
,
1284 B
? NotifyPointerRoot
: NotifyDetailNone
, root
);
1285 if (B
== PointerRootWin
)
1286 CoreFocusInNotifyPointerEvents(dev
, root
, None
, mode
, TRUE
);
1293 * Focus moves from window A to PointerRoot or to None.
1294 * Assumption: A is a valid window and not PointerRoot or None.
1297 CoreFocusToPointerRootOrNone(DeviceIntPtr dev
, WindowPtr A
,
1298 WindowPtr B
, /* PointerRootWin or NoneWin */
1303 int nscreens
= screenInfo
.numScreens
;
1306 if (!noPanoramiXExtension
)
1311 WindowPtr child
= FirstFocusChild(A
);
1314 /* NotifyPointer P-A unless P is B or below */
1315 CoreFocusOutNotifyPointerEvents(dev
, A
, B
, mode
, FALSE
);
1316 CoreFocusEvent(dev
, FocusOut
, mode
, NotifyInferior
, A
);
1319 /* NotifyPointer P-A */
1320 CoreFocusOutNotifyPointerEvents(dev
, A
, None
, mode
, FALSE
);
1321 CoreFocusEvent(dev
, FocusOut
, mode
, NotifyNonlinear
, A
);
1325 /* NullWindow means we include the root window */
1326 CoreFocusOutEvents(dev
, A
, NullWindow
, mode
, NotifyNonlinearVirtual
);
1328 for (i
= 0; i
< nscreens
; i
++) {
1329 root
= screenInfo
.screens
[i
]->root
;
1330 if (!HasFocus(root
) && !FirstFocusChild(root
)) {
1331 CoreFocusEvent(dev
, FocusIn
, mode
,
1332 B
? NotifyPointerRoot
: NotifyDetailNone
, root
);
1333 if (B
== PointerRootWin
)
1334 CoreFocusInNotifyPointerEvents(dev
, root
, None
, mode
, TRUE
);
1340 * Focus moves from PointerRoot or None to a window B.
1341 * Assumption: B is a valid window and not PointerRoot or None.
1344 CoreFocusFromPointerRootOrNone(DeviceIntPtr dev
,
1345 WindowPtr A
, /* PointerRootWin or NoneWin */
1346 WindowPtr B
, int mode
)
1350 int nscreens
= screenInfo
.numScreens
;
1353 if (!noPanoramiXExtension
)
1357 for (i
= 0; i
< nscreens
; i
++) {
1358 root
= screenInfo
.screens
[i
]->root
;
1359 if (!HasFocus(root
) && !FirstFocusChild(root
)) {
1360 /* If pointer was on PointerRootWin and changes to NoneWin, and
1361 * the pointer paired with dev is below the current root window,
1362 * do a NotifyPointer run. */
1363 if (dev
->focus
&& dev
->focus
->win
== PointerRootWin
&&
1364 B
!= PointerRootWin
) {
1365 WindowPtr ptrwin
= PointerWin(GetMaster(dev
, POINTER_OR_FLOAT
));
1368 CoreFocusOutNotifyPointerEvents(dev
, root
, None
, mode
,
1371 CoreFocusEvent(dev
, FocusOut
, mode
,
1372 A
? NotifyPointerRoot
: NotifyDetailNone
, root
);
1376 root
= B
; /* get B's root window */
1377 while (root
->parent
)
1378 root
= root
->parent
;
1381 CoreFocusEvent(dev
, FocusIn
, mode
, NotifyNonlinearVirtual
, root
);
1382 CoreFocusInEvents(dev
, root
, B
, mode
, NotifyNonlinearVirtual
);
1386 WindowPtr child
= FirstFocusChild(B
);
1389 CoreFocusEvent(dev
, FocusIn
, mode
, NotifyInferior
, B
);
1390 /* NotifyPointer B-P unless P is child or below. */
1391 CoreFocusInNotifyPointerEvents(dev
, B
, child
, mode
, FALSE
);
1394 CoreFocusEvent(dev
, FocusIn
, mode
, NotifyNonlinear
, B
);
1395 /* NotifyPointer B-P unless P is child or below. */
1396 CoreFocusInNotifyPointerEvents(dev
, B
, None
, mode
, FALSE
);
1403 CoreFocusEvents(DeviceIntPtr dev
, WindowPtr from
, WindowPtr to
, int mode
)
1410 if (((to
== NullWindow
) || (to
== PointerRootWin
)) &&
1411 ((from
== NullWindow
) || (from
== PointerRootWin
)))
1412 CoreFocusPointerRootNoneSwitch(dev
, from
, to
, mode
);
1413 else if ((to
== NullWindow
) || (to
== PointerRootWin
))
1414 CoreFocusToPointerRootOrNone(dev
, from
, to
, mode
);
1415 else if ((from
== NullWindow
) || (from
== PointerRootWin
))
1416 CoreFocusFromPointerRootOrNone(dev
, from
, to
, mode
);
1417 else if (IsParent(from
, to
))
1418 CoreFocusToDescendant(dev
, from
, to
, mode
);
1419 else if (IsParent(to
, from
))
1420 CoreFocusToAncestor(dev
, from
, to
, mode
);
1422 CoreFocusNonLinear(dev
, from
, to
, mode
);
1424 SetFocusIn(dev
, to
);
1428 DeviceFocusEvents(DeviceIntPtr dev
, WindowPtr from
, WindowPtr to
, int mode
)
1430 int out
, in
; /* for holding details for to/from
1433 int nscreens
= screenInfo
.numScreens
;
1434 SpritePtr sprite
= dev
->spriteInfo
->sprite
;
1438 out
= (from
== NoneWin
) ? NotifyDetailNone
: NotifyPointerRoot
;
1439 in
= (to
== NoneWin
) ? NotifyDetailNone
: NotifyPointerRoot
;
1440 /* wrong values if neither, but then not referenced */
1443 if (!noPanoramiXExtension
)
1447 if ((to
== NullWindow
) || (to
== PointerRootWin
)) {
1448 if ((from
== NullWindow
) || (from
== PointerRootWin
)) {
1449 if (from
== PointerRootWin
)
1450 DeviceFocusOutEvents(dev
, sprite
->win
,
1451 GetCurrentRootWindow(dev
), mode
,
1453 /* Notify all the roots */
1454 for (i
= 0; i
< nscreens
; i
++)
1455 DeviceFocusEvent(dev
, XI_FocusOut
, mode
, out
,
1456 screenInfo
.screens
[i
]->root
);
1459 if (IsParent(from
, sprite
->win
))
1460 DeviceFocusOutEvents(dev
, sprite
->win
, from
, mode
,
1462 DeviceFocusEvent(dev
, XI_FocusOut
, mode
, NotifyNonlinear
, from
);
1463 /* next call catches the root too, if the screen changed */
1464 DeviceFocusOutEvents(dev
, from
, NullWindow
, mode
,
1465 NotifyNonlinearVirtual
);
1467 /* Notify all the roots */
1468 for (i
= 0; i
< nscreens
; i
++)
1469 DeviceFocusEvent(dev
, XI_FocusIn
, mode
, in
,
1470 screenInfo
.screens
[i
]->root
);
1471 if (to
== PointerRootWin
) {
1472 DeviceFocusInEvents(dev
, GetCurrentRootWindow(dev
), sprite
->win
,
1473 mode
, NotifyPointer
);
1474 DeviceFocusEvent(dev
, XI_FocusIn
, mode
, NotifyPointer
, sprite
->win
);
1478 if ((from
== NullWindow
) || (from
== PointerRootWin
)) {
1479 if (from
== PointerRootWin
)
1480 DeviceFocusOutEvents(dev
, sprite
->win
,
1481 GetCurrentRootWindow(dev
), mode
,
1483 for (i
= 0; i
< nscreens
; i
++)
1484 DeviceFocusEvent(dev
, XI_FocusOut
, mode
, out
,
1485 screenInfo
.screens
[i
]->root
);
1486 if (to
->parent
!= NullWindow
)
1487 DeviceFocusInEvents(dev
, GetCurrentRootWindow(dev
), to
, mode
,
1488 NotifyNonlinearVirtual
);
1489 DeviceFocusEvent(dev
, XI_FocusIn
, mode
, NotifyNonlinear
, to
);
1490 if (IsParent(to
, sprite
->win
))
1491 DeviceFocusInEvents(dev
, to
, sprite
->win
, mode
, NotifyPointer
);
1494 if (IsParent(to
, from
)) {
1495 DeviceFocusEvent(dev
, XI_FocusOut
, mode
, NotifyAncestor
, from
);
1496 DeviceFocusOutEvents(dev
, from
, to
, mode
, NotifyVirtual
);
1497 DeviceFocusEvent(dev
, XI_FocusIn
, mode
, NotifyInferior
, to
);
1498 if ((IsParent(to
, sprite
->win
)) &&
1499 (sprite
->win
!= from
) &&
1500 (!IsParent(from
, sprite
->win
)) &&
1501 (!IsParent(sprite
->win
, from
)))
1502 DeviceFocusInEvents(dev
, to
, sprite
->win
, mode
,
1505 else if (IsParent(from
, to
)) {
1506 if ((IsParent(from
, sprite
->win
)) &&
1507 (sprite
->win
!= from
) &&
1508 (!IsParent(to
, sprite
->win
)) &&
1509 (!IsParent(sprite
->win
, to
)))
1510 DeviceFocusOutEvents(dev
, sprite
->win
, from
, mode
,
1512 DeviceFocusEvent(dev
, XI_FocusOut
, mode
, NotifyInferior
, from
);
1513 DeviceFocusInEvents(dev
, from
, to
, mode
, NotifyVirtual
);
1514 DeviceFocusEvent(dev
, XI_FocusIn
, mode
, NotifyAncestor
, to
);
1517 /* neither from or to is child of other */
1518 WindowPtr common
= CommonAncestor(to
, from
);
1520 /* common == NullWindow ==> different screens */
1521 if (IsParent(from
, sprite
->win
))
1522 DeviceFocusOutEvents(dev
, sprite
->win
, from
, mode
,
1524 DeviceFocusEvent(dev
, XI_FocusOut
, mode
, NotifyNonlinear
, from
);
1525 if (from
->parent
!= NullWindow
)
1526 DeviceFocusOutEvents(dev
, from
, common
, mode
,
1527 NotifyNonlinearVirtual
);
1528 if (to
->parent
!= NullWindow
)
1529 DeviceFocusInEvents(dev
, common
, to
, mode
,
1530 NotifyNonlinearVirtual
);
1531 DeviceFocusEvent(dev
, XI_FocusIn
, mode
, NotifyNonlinear
, to
);
1532 if (IsParent(to
, sprite
->win
))
1533 DeviceFocusInEvents(dev
, to
, sprite
->win
, mode
,
1541 * Figure out if focus events are necessary and send them to the
1542 * appropriate windows.
1544 * @param from Window the focus moved out of.
1545 * @param to Window the focus moved into.
1548 DoFocusEvents(DeviceIntPtr pDev
, WindowPtr from
, WindowPtr to
, int mode
)
1550 if (!IsKeyboardDevice(pDev
))
1556 CoreFocusEvents(pDev
, from
, to
, mode
);
1557 DeviceFocusEvents(pDev
, from
, to
, mode
);