Imported Upstream version 1.15.1
[deb_xorg-server.git] / dix / enterleave.c
CommitLineData
a09e091a
JB
1/*
2 * Copyright © 2008 Red Hat, Inc.
3 *
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:
10 *
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
13 * Software.
14 *
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.
22 *
23 * Authors: Peter Hutterer
24 *
25 */
26
27#ifdef HAVE_DIX_CONFIG_H
28#include <dix-config.h>
29#endif
30
31#include <X11/X.h>
32#include <X11/extensions/XI2.h>
33#include <X11/extensions/XIproto.h>
34#include <X11/extensions/XI2proto.h>
35#include "inputstr.h"
36#include "windowstr.h"
37#include "scrnintstr.h"
38#include "exglobals.h"
39#include "enterleave.h"
40#include "eventconvert.h"
41#include "xkbsrv.h"
42#include "inpututils.h"
43
44/**
45 * @file
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.
48 *
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
51 * approach.
52 *
53 * For a full description of the enter/leave model from a window's
54 * perspective, see
55 * http://lists.freedesktop.org/archives/xorg/2008-August/037606.html
56 *
57 * For a full description of the focus in/out model from a window's
58 * perspective, see
59 * http://lists.freedesktop.org/archives/xorg/2008-December/041740.html
60 *
61 * Additional notes:
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."
67 *
68 * By inference, this means that only NotifyVirtual or NotifyNonlinearVirtual
69 * events may have a subwindow set to other than None.
70 *
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.
76 */
77
78static WindowPtr PointerWindows[MAXDEVICES];
79static WindowPtr FocusWindows[MAXDEVICES];
80
81/**
82 * Return TRUE if 'win' has a pointer within its boundaries, excluding child
83 * window.
84 */
85static BOOL
86HasPointer(DeviceIntPtr dev, WindowPtr win)
87{
88 int i;
89
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.
93 * Fixes fdo 27804.
94 * There isn't enough beer in my fridge to fix this properly.
95 */
96 if (dev->deviceGrab.grab)
97 return FALSE;
98
99 for (i = 0; i < MAXDEVICES; i++)
100 if (PointerWindows[i] == win)
101 return TRUE;
102
103 return FALSE;
104}
105
106/**
107 * Return TRUE if at least one keyboard focus is set to 'win' (excluding
108 * descendants of win).
109 */
110static BOOL
111HasFocus(WindowPtr win)
112{
113 int i;
114
115 for (i = 0; i < MAXDEVICES; i++)
116 if (FocusWindows[i] == win)
117 return TRUE;
118
119 return FALSE;
120}
121
122/**
123 * Return the window the device dev is currently on.
124 */
125static WindowPtr
126PointerWin(DeviceIntPtr dev)
127{
128 return PointerWindows[dev->id];
129}
130
131/**
132 * Search for the first window below 'win' that has a pointer directly within
133 * it's boundaries (excluding boundaries of its own descendants).
134 *
135 * @return The child window that has the pointer within its boundaries or
136 * NULL.
137 */
138static WindowPtr
139FirstPointerChild(WindowPtr win)
140{
141 int i;
142
143 for (i = 0; i < MAXDEVICES; i++) {
144 if (PointerWindows[i] && IsParent(win, PointerWindows[i]))
145 return PointerWindows[i];
146 }
147
148 return NULL;
149}
150
151/**
152 * Search for the first window below 'win' that has a focus directly within
153 * it's boundaries (excluding boundaries of its own descendants).
154 *
155 * @return The child window that has the pointer within its boundaries or
156 * NULL.
157 */
158static WindowPtr
159FirstFocusChild(WindowPtr win)
160{
161 int i;
162
163 for (i = 0; i < MAXDEVICES; i++) {
164 if (FocusWindows[i] && FocusWindows[i] != PointerRootWin &&
165 IsParent(win, FocusWindows[i]))
166 return FocusWindows[i];
167 }
168
169 return NULL;
170}
171
172/**
173 * Set the presence flag for dev to mark that it is now in 'win'.
174 */
175void
176EnterWindow(DeviceIntPtr dev, WindowPtr win, int mode)
177{
178 PointerWindows[dev->id] = win;
179}
180
181/**
182 * Unset the presence flag for dev to mark that it is not in 'win' anymore.
183 */
184void
185LeaveWindow(DeviceIntPtr dev)
186{
187 PointerWindows[dev->id] = NULL;
188}
189
190/**
191 * Set the presence flag for dev to mark that it is now in 'win'.
192 */
193void
194SetFocusIn(DeviceIntPtr dev, WindowPtr win)
195{
196 FocusWindows[dev->id] = win;
197}
198
199/**
200 * Unset the presence flag for dev to mark that it is not in 'win' anymore.
201 */
202void
203SetFocusOut(DeviceIntPtr dev)
204{
205 FocusWindows[dev->id] = NULL;
206}
207
208/**
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.
214 */
215WindowPtr
216CommonAncestor(WindowPtr a, WindowPtr b)
217{
218 for (b = b->parent; b; b = b->parent)
219 if (IsParent(b, a))
220 return b;
221 return NullWindow;
222}
223
224/**
225 * Send enter notifies to all windows between 'ancestor' and 'child' (excluding
226 * both). Events are sent running up the window hierarchy. This function
227 * recurses.
228 */
229static void
230DeviceEnterNotifies(DeviceIntPtr dev,
231 int sourceid,
232 WindowPtr ancestor, WindowPtr child, int mode, int detail)
233{
234 WindowPtr parent = child->parent;
235
236 if (ancestor == parent)
237 return;
238 DeviceEnterNotifies(dev, sourceid, ancestor, parent, mode, detail);
239 DeviceEnterLeaveEvent(dev, sourceid, XI_Enter, mode, detail, parent,
240 child->drawable.id);
241}
242
243/**
244 * Send enter notifies to all windows between 'ancestor' and 'child' (excluding
245 * both). Events are sent running down the window hierarchy. This function
246 * recurses.
247 */
248static void
249CoreEnterNotifies(DeviceIntPtr dev,
250 WindowPtr ancestor, WindowPtr child, int mode, int detail)
251{
252 WindowPtr parent = child->parent;
253
254 if (ancestor == parent)
255 return;
256 CoreEnterNotifies(dev, ancestor, parent, mode, detail);
257
258 /* Case 3:
259 A is above W, B is a descendant
260
261 Classically: The move generates an EnterNotify on W with a detail of
262 Virtual or NonlinearVirtual
263
264 MPX:
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
268 descendant
269 P(W) stays on the same descendant, or changes to a different
270 descendant. The event should be suppressed.
271 Case 3C: Otherwise:
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). */
276
277 if (!HasPointer(dev, parent) && !FirstPointerChild(parent))
278 CoreEnterLeaveEvent(dev, EnterNotify, mode, detail, parent,
279 child->drawable.id);
280}
281
282static void
283CoreLeaveNotifies(DeviceIntPtr dev,
284 WindowPtr child, WindowPtr ancestor, int mode, int detail)
285{
286 WindowPtr win;
287
288 if (ancestor == child)
289 return;
290
291 for (win = child->parent; win != ancestor; win = win->parent) {
292 /*Case 7:
293 A is a descendant of W, B is above W
294
295 Classically: A LeaveNotify is generated on W with a detail of Virtual
296 or NonlinearVirtual.
297
298 MPX:
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
302 descendant
303 P(W) stays on the same descendant, or changes to a different
304 descendant. The event should be suppressed.
305 Case 3C: Otherwise:
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). */
309
310 /* If one window has a pointer or a child with a pointer, skip some
311 * work and exit. */
312 if (HasPointer(dev, win) || FirstPointerChild(win))
313 return;
314
315 CoreEnterLeaveEvent(dev, LeaveNotify, mode, detail, win,
316 child->drawable.id);
317
318 child = win;
319 }
320}
321
322/**
323 * Send leave notifies to all windows between 'child' and 'ancestor'.
324 * Events are sent running up the hierarchy.
325 */
326static void
327DeviceLeaveNotifies(DeviceIntPtr dev,
328 int sourceid,
329 WindowPtr child, WindowPtr ancestor, int mode, int detail)
330{
331 WindowPtr win;
332
333 if (ancestor == child)
334 return;
335 for (win = child->parent; win != ancestor; win = win->parent) {
336 DeviceEnterLeaveEvent(dev, sourceid, XI_Leave, mode, detail, win,
337 child->drawable.id);
338 child = win;
339 }
340}
341
342/**
343 * Pointer dev moves from A to B and A neither a descendant of B nor is
344 * B a descendant of A.
345 */
346static void
347CoreEnterLeaveNonLinear(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode)
348{
349 WindowPtr X = CommonAncestor(A, B);
350
351 /* Case 4:
352 A is W, B is above W
353
354 Classically: The move generates a LeaveNotify on W with a detail of
355 Ancestor or Nonlinear
356
357 MPX:
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
361 descendant of W
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
364 is set to Inferior
365 Case 3C: Otherwise:
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)
369 */
370
371 if (!HasPointer(dev, A)) {
372 WindowPtr child = FirstPointerChild(A);
373
374 if (child)
375 CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyInferior, A,
376 None);
377 else
378 CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyNonlinear, A,
379 None);
380 }
381
382 CoreLeaveNotifies(dev, A, X, mode, NotifyNonlinearVirtual);
383
384 /*
385 Case 9:
386 A is a descendant of W, B is a descendant of W
387
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.
391
392 Therefore, no event to X.
393 */
394
395 CoreEnterNotifies(dev, X, B, mode, NotifyNonlinearVirtual);
396
397 /* Case 2:
398 A is above W, B=W
399
400 Classically: The move generates an EnterNotify on W with a detail of
401 Ancestor or Nonlinear
402
403 MPX:
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
407 descendant
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)
410 Case 2C: Otherwise:
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). */
414
415 if (!HasPointer(dev, B)) {
416 WindowPtr child = FirstPointerChild(B);
417
418 if (child)
419 CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyInferior, B,
420 None);
421 else
422 CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyNonlinear, B,
423 None);
424 }
425}
426
427/**
428 * Pointer dev moves from A to B and A is a descendant of B.
429 */
430static void
431CoreEnterLeaveToAncestor(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode)
432{
433 /* Case 4:
434 A is W, B is above W
435
436 Classically: The move generates a LeaveNotify on W with a detail of
437 Ancestor or Nonlinear
438
439 MPX:
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
443 descendant of W
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
446 is set to Inferior
447 Case 3C: Otherwise:
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)
451 */
452 if (!HasPointer(dev, A)) {
453 WindowPtr child = FirstPointerChild(A);
454
455 if (child)
456 CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyInferior, A,
457 None);
458 else
459 CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyAncestor, A,
460 None);
461 }
462
463 CoreLeaveNotifies(dev, A, B, mode, NotifyVirtual);
464
465 /* Case 8:
466 A is a descendant of W, B is W
467
468 Classically: A EnterNotify is generated on W with a detail of
469 NotifyInferior
470
471 MPX:
472 Case 3A: There is at least one other pointer on W itself
473 P(W) doesn't change, the event should be suppressed
474 Case 3B: Otherwise:
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 */
477
478 if (!HasPointer(dev, B))
479 CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyInferior, B, None);
480
481}
482
483/**
484 * Pointer dev moves from A to B and B is a descendant of A.
485 */
486static void
487CoreEnterLeaveToDescendant(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode)
488{
489 /* Case 6:
490 A is W, B is a descendant of W
491
492 Classically: A LeaveNotify is generated on W with a detail of
493 NotifyInferior
494
495 MPX:
496 Case 3A: There is at least one other pointer on W itself
497 P(W) doesn't change, the event should be suppressed
498 Case 3B: Otherwise:
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 */
501
502 if (!HasPointer(dev, A))
503 CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyInferior, A, None);
504
505 CoreEnterNotifies(dev, A, B, mode, NotifyVirtual);
506
507 /* Case 2:
508 A is above W, B=W
509
510 Classically: The move generates an EnterNotify on W with a detail of
511 Ancestor or Nonlinear
512
513 MPX:
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
517 descendant
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)
520 Case 2C: Otherwise:
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). */
524
525 if (!HasPointer(dev, B)) {
526 WindowPtr child = FirstPointerChild(B);
527
528 if (child)
529 CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyInferior, B,
530 None);
531 else
532 CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyAncestor, B,
533 None);
534 }
535}
536
537static void
538CoreEnterLeaveEvents(DeviceIntPtr dev, WindowPtr from, WindowPtr to, int mode)
539{
540 if (!IsMaster(dev))
541 return;
542
543 LeaveWindow(dev);
544
545 if (IsParent(from, to))
546 CoreEnterLeaveToDescendant(dev, from, to, mode);
547 else if (IsParent(to, from))
548 CoreEnterLeaveToAncestor(dev, from, to, mode);
549 else
550 CoreEnterLeaveNonLinear(dev, from, to, mode);
551
552 EnterWindow(dev, to, mode);
553}
554
555static void
556DeviceEnterLeaveEvents(DeviceIntPtr dev,
557 int sourceid, WindowPtr from, WindowPtr to, int mode)
558{
559 if (IsParent(from, to)) {
560 DeviceEnterLeaveEvent(dev, sourceid, XI_Leave, mode, NotifyInferior,
561 from, None);
562 DeviceEnterNotifies(dev, sourceid, from, to, mode, NotifyVirtual);
563 DeviceEnterLeaveEvent(dev, sourceid, XI_Enter, mode, NotifyAncestor, to,
564 None);
565 }
566 else if (IsParent(to, from)) {
567 DeviceEnterLeaveEvent(dev, sourceid, XI_Leave, mode, NotifyAncestor,
568 from, None);
569 DeviceLeaveNotifies(dev, sourceid, from, to, mode, NotifyVirtual);
570 DeviceEnterLeaveEvent(dev, sourceid, XI_Enter, mode, NotifyInferior, to,
571 None);
572 }
573 else { /* neither from nor to is descendent of the other */
574 WindowPtr common = CommonAncestor(to, from);
575
576 /* common == NullWindow ==> different screens */
577 DeviceEnterLeaveEvent(dev, sourceid, XI_Leave, mode, NotifyNonlinear,
578 from, None);
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,
584 to, None);
585 }
586}
587
588/**
589 * Figure out if enter/leave events are necessary and send them to the
590 * appropriate windows.
591 *
592 * @param fromWin Window the sprite moved out of.
593 * @param toWin Window the sprite moved into.
594 */
595void
596DoEnterLeaveEvents(DeviceIntPtr pDev,
597 int sourceid, WindowPtr fromWin, WindowPtr toWin, int mode)
598{
599 if (!IsPointerDevice(pDev))
600 return;
601
602 if (fromWin == toWin)
603 return;
604
605 if (mode != XINotifyPassiveGrab && mode != XINotifyPassiveUngrab)
606 CoreEnterLeaveEvents(pDev, fromWin, toWin, mode);
607 DeviceEnterLeaveEvents(pDev, sourceid, fromWin, toWin, mode);
608}
609
610static void
611FixDeviceValuator(DeviceIntPtr dev, deviceValuator * ev, ValuatorClassPtr v,
612 int first)
613{
614 int nval = v->numAxes - first;
615
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) {
621 case 3:
622 ev->valuator2 = v->axisVal[first + 2];
623 case 2:
624 ev->valuator1 = v->axisVal[first + 1];
625 case 1:
626 ev->valuator0 = v->axisVal[first];
627 break;
628 }
629 first += ev->num_valuators;
630}
631
632static void
633FixDeviceStateNotify(DeviceIntPtr dev, deviceStateNotify * ev, KeyClassPtr k,
634 ButtonClassPtr b, ValuatorClassPtr v, int first)
635{
636 ev->type = DeviceStateNotify;
637 ev->deviceid = dev->id;
638 ev->time = currentTime.milliseconds;
639 ev->classes_reported = 0;
640 ev->num_keys = 0;
641 ev->num_buttons = 0;
642 ev->num_valuators = 0;
643
644 if (b) {
645 ev->classes_reported |= (1 << ButtonClass);
646 ev->num_buttons = b->numButtons;
647 memcpy((char *) ev->buttons, (char *) b->down, 4);
648 }
649 else if (k) {
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);
654 }
655 if (v) {
656 int nval = v->numAxes - first;
657
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) {
662 case 3:
663 ev->valuator2 = v->axisVal[first + 2];
664 case 2:
665 ev->valuator1 = v->axisVal[first + 1];
666 case 1:
667 ev->valuator0 = v->axisVal[first];
668 break;
669 }
670 }
671}
672
673
674static void
675DeliverStateNotifyEvent(DeviceIntPtr dev, WindowPtr win)
676{
677 int evcount = 1;
678 deviceStateNotify *ev, *sev;
679 deviceKeyStateNotify *kev;
680 deviceButtonStateNotify *bev;
681
682 KeyClassPtr k;
683 ButtonClassPtr b;
684 ValuatorClassPtr v;
685 int nval = 0, nkeys = 0, nbuttons = 0, first = 0;
686
687 if (!(wOtherInputMasks(win)) ||
688 !(wOtherInputMasks(win)->inputEvents[dev->id] & DeviceStateNotifyMask))
689 return;
690
691 if ((b = dev->button) != NULL) {
692 nbuttons = b->numButtons;
693 if (nbuttons > 32)
694 evcount++;
695 }
696 if ((k = dev->key) != NULL) {
697 nkeys = k->xkbInfo->desc->max_key_code - k->xkbInfo->desc->min_key_code;
698 if (nkeys > 32)
699 evcount++;
700 if (nbuttons > 0) {
701 evcount++;
702 }
703 }
704 if ((v = dev->valuator) != NULL) {
705 nval = v->numAxes;
706
707 if (nval > 3)
708 evcount++;
709 if (nval > 6) {
710 if (!(k && b))
711 evcount++;
712 if (nval > 9)
713 evcount += ((nval - 7) / 3);
714 }
715 }
716
717 sev = ev = (deviceStateNotify *) malloc(evcount * sizeof(xEvent));
718 FixDeviceStateNotify(dev, ev, NULL, NULL, NULL, first);
719
720 if (b != NULL) {
721 FixDeviceStateNotify(dev, ev++, NULL, b, v, first);
722 first += 3;
723 nval -= 3;
724 if (nbuttons > 32) {
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],
730 DOWN_LENGTH - 4);
731 }
732 if (nval > 0) {
733 (ev - 1)->deviceid |= MORE_EVENTS;
734 FixDeviceValuator(dev, (deviceValuator *) ev++, v, first);
735 first += 3;
736 nval -= 3;
737 }
738 }
739
740 if (k != NULL) {
741 FixDeviceStateNotify(dev, ev++, k, NULL, v, first);
742 first += 3;
743 nval -= 3;
744 if (nkeys > 32) {
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);
750 }
751 if (nval > 0) {
752 (ev - 1)->deviceid |= MORE_EVENTS;
753 FixDeviceValuator(dev, (deviceValuator *) ev++, v, first);
754 first += 3;
755 nval -= 3;
756 }
757 }
758
759 while (nval > 0) {
760 FixDeviceStateNotify(dev, ev++, NULL, NULL, v, first);
761 first += 3;
762 nval -= 3;
763 if (nval > 0) {
764 (ev - 1)->deviceid |= MORE_EVENTS;
765 FixDeviceValuator(dev, (deviceValuator *) ev++, v, first);
766 first += 3;
767 nval -= 3;
768 }
769 }
770
771 DeliverEventsToWindow(dev, win, (xEvent *) sev, evcount,
772 DeviceStateNotifyMask, NullGrab);
773 free(sev);
774}
775
776void
777DeviceFocusEvent(DeviceIntPtr dev, int type, int mode, int detail,
778 WindowPtr pWin)
779{
780 deviceFocus event;
781 xXIFocusInEvent *xi2event;
782 DeviceIntPtr mouse;
783 int btlen, len, i;
784
785 mouse = IsFloating(dev) ? dev : GetMaster(dev, MASTER_POINTER);
786
787 /* XI 2 event */
788 btlen = (mouse->button) ? bits_to_bytes(mouse->button->numButtons) : 0;
789 btlen = bytes_to_int32(btlen);
790 len = sizeof(xXIFocusInEvent) + btlen * 4;
791
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);
805
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]);
809
810 if (dev->key) {
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;
815
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;
820 }
821
822 FixUpEventFromWindow(dev->spriteInfo->sprite, (xEvent *) xi2event, pWin,
823 None, FALSE);
824
825 DeliverEventsToWindow(dev, pWin, (xEvent *) xi2event, 1,
826 GetEventFilter(dev, (xEvent *) xi2event), NullGrab);
827
828 free(xi2event);
829
830 /* XI 1.x event */
831 event = (deviceFocus) {
832 .deviceid = dev->id,
833 .mode = mode,
834 .type = (type == XI_FocusIn) ? DeviceFocusIn : DeviceFocusOut,
835 .detail = detail,
836 .window = pWin->drawable.id,
837 .time = currentTime.milliseconds
838 };
839
840 DeliverEventsToWindow(dev, pWin, (xEvent *) &event, 1,
841 DeviceFocusChangeMask, NullGrab);
842
843 if (event.type == DeviceFocusIn)
844 DeliverStateNotifyEvent(dev, pWin);
845}
846
847/**
848 * Send focus out events to all windows between 'child' and 'ancestor'.
849 * Events are sent running up the hierarchy.
850 */
851static void
852DeviceFocusOutEvents(DeviceIntPtr dev,
853 WindowPtr child, WindowPtr ancestor, int mode, int detail)
854{
855 WindowPtr win;
856
857 if (ancestor == child)
858 return;
859 for (win = child->parent; win != ancestor; win = win->parent)
860 DeviceFocusEvent(dev, XI_FocusOut, mode, detail, win);
861}
862
863/**
864 * Send enter notifies to all windows between 'ancestor' and 'child' (excluding
865 * both). Events are sent running up the window hierarchy. This function
866 * recurses.
867 */
868static void
869DeviceFocusInEvents(DeviceIntPtr dev,
870 WindowPtr ancestor, WindowPtr child, int mode, int detail)
871{
872 WindowPtr parent = child->parent;
873
874 if (ancestor == parent || !parent)
875 return;
876 DeviceFocusInEvents(dev, ancestor, parent, mode, detail);
877 DeviceFocusEvent(dev, XI_FocusIn, mode, detail, parent);
878}
879
880/**
881 * Send FocusIn events to all windows between 'ancestor' and 'child' (excluding
882 * both). Events are sent running down the window hierarchy. This function
883 * recurses.
884 */
885static void
886CoreFocusInEvents(DeviceIntPtr dev,
887 WindowPtr ancestor, WindowPtr child, int mode, int detail)
888{
889 WindowPtr parent = child->parent;
890
891 if (ancestor == parent)
892 return;
893 CoreFocusInEvents(dev, ancestor, parent, mode, detail);
894
895 /* Case 3:
896 A is above W, B is a descendant
897
898 Classically: The move generates an FocusIn on W with a detail of
899 Virtual or NonlinearVirtual
900
901 MPX:
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
905 descendant
906 F(W) stays on the same descendant, or changes to a different
907 descendant. The event should be suppressed.
908 Case 3C: Otherwise:
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). */
912
913 if (!HasFocus(parent) && !FirstFocusChild(parent))
914 CoreFocusEvent(dev, FocusIn, mode, detail, parent);
915}
916
917static void
918CoreFocusOutEvents(DeviceIntPtr dev,
919 WindowPtr child, WindowPtr ancestor, int mode, int detail)
920{
921 WindowPtr win;
922
923 if (ancestor == child)
924 return;
925
926 for (win = child->parent; win != ancestor; win = win->parent) {
927 /*Case 7:
928 A is a descendant of W, B is above W
929
930 Classically: A FocusOut is generated on W with a detail of Virtual
931 or NonlinearVirtual.
932
933 MPX:
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
937 descendant
938 F(W) stays on the same descendant, or changes to a different
939 descendant. The event should be suppressed.
940 Case 3C: Otherwise:
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). */
944
945 /* If one window has a focus or a child with a focuspointer, skip some
946 * work and exit. */
947 if (HasFocus(win) || FirstFocusChild(win))
948 return;
949
950 CoreFocusEvent(dev, FocusOut, mode, detail, win);
951 }
952}
953
954/**
955 * Send FocusOut(NotifyPointer) events from the current pointer window (which
956 * is a descendant of pwin_parent) up to (excluding) pwin_parent.
957 *
958 * NotifyPointer events are only sent for the device paired with dev.
959 *
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
962 * are sent!
963 */
964static void
965CoreFocusOutNotifyPointerEvents(DeviceIntPtr dev,
966 WindowPtr pwin_parent,
967 WindowPtr exclude, int mode, int inclusive)
968{
969 WindowPtr P, stopAt;
970
971 P = PointerWin(GetMaster(dev, POINTER_OR_FLOAT));
972
973 if (!P)
974 return;
975 if (!IsParent(pwin_parent, P))
976 if (!(pwin_parent == P && inclusive))
977 return;
978
979 if (exclude != None && exclude != PointerRootWin &&
980 (IsParent(exclude, P) || IsParent(P, exclude)))
981 return;
982
983 stopAt = (inclusive) ? pwin_parent->parent : pwin_parent;
984
985 for (; P && P != stopAt; P = P->parent)
986 CoreFocusEvent(dev, FocusOut, mode, NotifyPointer, P);
987}
988
989/**
990 * DO NOT CALL DIRECTLY.
991 * Recursion helper for CoreFocusInNotifyPointerEvents.
992 */
993static void
994CoreFocusInRecurse(DeviceIntPtr dev,
995 WindowPtr win, WindowPtr stopAt, int mode, int inclusive)
996{
997 if ((!inclusive && win == stopAt) || !win)
998 return;
999
1000 CoreFocusInRecurse(dev, win->parent, stopAt, mode, inclusive);
1001 CoreFocusEvent(dev, FocusIn, mode, NotifyPointer, win);
1002}
1003
1004/**
1005 * Send FocusIn(NotifyPointer) events from pwin_parent down to
1006 * including the current pointer window (which is a descendant of pwin_parent).
1007 *
1008 * @param pwin The pointer window.
1009 * @param exclude If the pointer window is a child of 'exclude', no events are
1010 * sent.
1011 * @param inclusive If TRUE, pwin_parent will receive the event too.
1012 */
1013static void
1014CoreFocusInNotifyPointerEvents(DeviceIntPtr dev,
1015 WindowPtr pwin_parent,
1016 WindowPtr exclude, int mode, int inclusive)
1017{
1018 WindowPtr P;
1019
1020 P = PointerWin(GetMaster(dev, POINTER_OR_FLOAT));
1021
1022 if (!P || P == exclude || (pwin_parent != P && !IsParent(pwin_parent, P)))
1023 return;
1024
1025 if (exclude != None && (IsParent(exclude, P) || IsParent(P, exclude)))
1026 return;
1027
1028 CoreFocusInRecurse(dev, P, pwin_parent, mode, inclusive);
1029}
1030
1031/**
1032 * Focus of dev moves from A to B and A neither a descendant of B nor is
1033 * B a descendant of A.
1034 */
1035static void
1036CoreFocusNonLinear(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode)
1037{
1038 WindowPtr X = CommonAncestor(A, B);
1039
1040 /* Case 4:
1041 A is W, B is above W
1042
1043 Classically: The change generates a FocusOut on W with a detail of
1044 Ancestor or Nonlinear
1045
1046 MPX:
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
1050 descendant of W
1051 F(W) changes from W to a descendant of W. The detail field
1052 is set to Inferior
1053 Case 3C: Otherwise:
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)
1057 */
1058
1059 if (!HasFocus(A)) {
1060 WindowPtr child = FirstFocusChild(A);
1061
1062 if (child) {
1063 /* NotifyPointer P-A unless P is child or below */
1064 CoreFocusOutNotifyPointerEvents(dev, A, child, mode, FALSE);
1065 CoreFocusEvent(dev, FocusOut, mode, NotifyInferior, A);
1066 }
1067 else {
1068 /* NotifyPointer P-A */
1069 CoreFocusOutNotifyPointerEvents(dev, A, None, mode, FALSE);
1070 CoreFocusEvent(dev, FocusOut, mode, NotifyNonlinear, A);
1071 }
1072 }
1073
1074 CoreFocusOutEvents(dev, A, X, mode, NotifyNonlinearVirtual);
1075
1076 /*
1077 Case 9:
1078 A is a descendant of W, B is a descendant of W
1079
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.
1083
1084 Therefore, no event to X.
1085 */
1086
1087 CoreFocusInEvents(dev, X, B, mode, NotifyNonlinearVirtual);
1088
1089 /* Case 2:
1090 A is above W, B=W
1091
1092 Classically: The move generates an EnterNotify on W with a detail of
1093 Ancestor or Nonlinear
1094
1095 MPX:
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
1099 descendant
1100 F(W) moves from a descendant to W. detail is changed to Inferior.
1101 Case 2C: Otherwise:
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). */
1105
1106 if (!HasFocus(B)) {
1107 WindowPtr child = FirstFocusChild(B);
1108
1109 if (child) {
1110 CoreFocusEvent(dev, FocusIn, mode, NotifyInferior, B);
1111 /* NotifyPointer B-P unless P is child or below. */
1112 CoreFocusInNotifyPointerEvents(dev, B, child, mode, FALSE);
1113 }
1114 else {
1115 CoreFocusEvent(dev, FocusIn, mode, NotifyNonlinear, B);
1116 /* NotifyPointer B-P unless P is child or below. */
1117 CoreFocusInNotifyPointerEvents(dev, B, None, mode, FALSE);
1118 }
1119 }
1120}
1121
1122/**
1123 * Focus of dev moves from A to B and A is a descendant of B.
1124 */
1125static void
1126CoreFocusToAncestor(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode)
1127{
1128 /* Case 4:
1129 A is W, B is above W
1130
1131 Classically: The change generates a FocusOut on W with a detail of
1132 Ancestor or Nonlinear
1133
1134 MPX:
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
1138 descendant of W
1139 F(W) changes from W to a descendant of W. The detail field
1140 is set to Inferior
1141 Case 3C: Otherwise:
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)
1145 */
1146 if (!HasFocus(A)) {
1147 WindowPtr child = FirstFocusChild(A);
1148
1149 if (child) {
1150 /* NotifyPointer P-A unless P is child or below */
1151 CoreFocusOutNotifyPointerEvents(dev, A, child, mode, FALSE);
1152 CoreFocusEvent(dev, FocusOut, mode, NotifyInferior, A);
1153 }
1154 else
1155 CoreFocusEvent(dev, FocusOut, mode, NotifyAncestor, A);
1156 }
1157
1158 CoreFocusOutEvents(dev, A, B, mode, NotifyVirtual);
1159
1160 /* Case 8:
1161 A is a descendant of W, B is W
1162
1163 Classically: A FocusOut is generated on W with a detail of
1164 NotifyInferior
1165
1166 MPX:
1167 Case 3A: There is at least one other focus on W itself
1168 F(W) doesn't change, the event should be suppressed
1169 Case 3B: Otherwise:
1170 F(W) changes from a descendant to W itself. */
1171
1172 if (!HasFocus(B)) {
1173 CoreFocusEvent(dev, FocusIn, mode, NotifyInferior, B);
1174 /* NotifyPointer B-P unless P is A or below. */
1175 CoreFocusInNotifyPointerEvents(dev, B, A, mode, FALSE);
1176 }
1177}
1178
1179/**
1180 * Focus of dev moves from A to B and B is a descendant of A.
1181 */
1182static void
1183CoreFocusToDescendant(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode)
1184{
1185 /* Case 6:
1186 A is W, B is a descendant of W
1187
1188 Classically: A FocusOut is generated on W with a detail of
1189 NotifyInferior
1190
1191 MPX:
1192 Case 3A: There is at least one other focus on W itself
1193 F(W) doesn't change, the event should be suppressed
1194 Case 3B: Otherwise:
1195 F(W) changes from W to a descendant of W. */
1196
1197 if (!HasFocus(A)) {
1198 /* NotifyPointer P-A unless P is B or below */
1199 CoreFocusOutNotifyPointerEvents(dev, A, B, mode, FALSE);
1200 CoreFocusEvent(dev, FocusOut, mode, NotifyInferior, A);
1201 }
1202
1203 CoreFocusInEvents(dev, A, B, mode, NotifyVirtual);
1204
1205 /* Case 2:
1206 A is above W, B=W
1207
1208 Classically: The move generates an FocusIn on W with a detail of
1209 Ancestor or Nonlinear
1210
1211 MPX:
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
1215 descendant
1216 F(W) moves from a descendant to W. detail is changed to Inferior.
1217 Case 2C: Otherwise:
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). */
1221
1222 if (!HasFocus(B)) {
1223 WindowPtr child = FirstFocusChild(B);
1224
1225 if (child) {
1226 CoreFocusEvent(dev, FocusIn, mode, NotifyInferior, B);
1227 /* NotifyPointer B-P unless P is child or below. */
1228 CoreFocusInNotifyPointerEvents(dev, B, child, mode, FALSE);
1229 }
1230 else
1231 CoreFocusEvent(dev, FocusIn, mode, NotifyAncestor, B);
1232 }
1233}
1234
1235static BOOL
1236HasOtherPointer(WindowPtr win, DeviceIntPtr exclude)
1237{
1238 int i;
1239
1240 for (i = 0; i < MAXDEVICES; i++)
1241 if (i != exclude->id && PointerWindows[i] == win)
1242 return TRUE;
1243
1244 return FALSE;
1245}
1246
1247/**
1248 * Focus moves from PointerRoot to None or from None to PointerRoot.
1249 * Assumption: Neither A nor B are valid windows.
1250 */
1251static void
1252CoreFocusPointerRootNoneSwitch(DeviceIntPtr dev,
1253 WindowPtr A, /* PointerRootWin or NoneWin */
1254 WindowPtr B, /* NoneWin or PointerRootWin */
1255 int mode)
1256{
1257 WindowPtr root;
1258 int i;
1259 int nscreens = screenInfo.numScreens;
1260
1261#ifdef PANORAMIX
1262 if (!noPanoramiXExtension)
1263 nscreens = 1;
1264#endif
1265
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));
1276
1277 if (ptrwin && IsParent(root, ptrwin))
1278 CoreFocusOutNotifyPointerEvents(dev, root, None, mode,
1279 TRUE);
1280 }
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);
1287 }
1288
1289 }
1290}
1291
1292/**
1293 * Focus moves from window A to PointerRoot or to None.
1294 * Assumption: A is a valid window and not PointerRoot or None.
1295 */
1296static void
1297CoreFocusToPointerRootOrNone(DeviceIntPtr dev, WindowPtr A,
1298 WindowPtr B, /* PointerRootWin or NoneWin */
1299 int mode)
1300{
1301 WindowPtr root;
1302 int i;
1303 int nscreens = screenInfo.numScreens;
1304
1305#ifdef PANORAMIX
1306 if (!noPanoramiXExtension)
1307 nscreens = 1;
1308#endif
1309
1310 if (!HasFocus(A)) {
1311 WindowPtr child = FirstFocusChild(A);
1312
1313 if (child) {
1314 /* NotifyPointer P-A unless P is B or below */
1315 CoreFocusOutNotifyPointerEvents(dev, A, B, mode, FALSE);
1316 CoreFocusEvent(dev, FocusOut, mode, NotifyInferior, A);
1317 }
1318 else {
1319 /* NotifyPointer P-A */
1320 CoreFocusOutNotifyPointerEvents(dev, A, None, mode, FALSE);
1321 CoreFocusEvent(dev, FocusOut, mode, NotifyNonlinear, A);
1322 }
1323 }
1324
1325 /* NullWindow means we include the root window */
1326 CoreFocusOutEvents(dev, A, NullWindow, mode, NotifyNonlinearVirtual);
1327
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);
1335 }
1336 }
1337}
1338
1339/**
1340 * Focus moves from PointerRoot or None to a window B.
1341 * Assumption: B is a valid window and not PointerRoot or None.
1342 */
1343static void
1344CoreFocusFromPointerRootOrNone(DeviceIntPtr dev,
1345 WindowPtr A, /* PointerRootWin or NoneWin */
1346 WindowPtr B, int mode)
1347{
1348 WindowPtr root;
1349 int i;
1350 int nscreens = screenInfo.numScreens;
1351
1352#ifdef PANORAMIX
1353 if (!noPanoramiXExtension)
1354 nscreens = 1;
1355#endif
1356
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));
1366
1367 if (ptrwin)
1368 CoreFocusOutNotifyPointerEvents(dev, root, None, mode,
1369 TRUE);
1370 }
1371 CoreFocusEvent(dev, FocusOut, mode,
1372 A ? NotifyPointerRoot : NotifyDetailNone, root);
1373 }
1374 }
1375
1376 root = B; /* get B's root window */
1377 while (root->parent)
1378 root = root->parent;
1379
1380 if (B != root) {
1381 CoreFocusEvent(dev, FocusIn, mode, NotifyNonlinearVirtual, root);
1382 CoreFocusInEvents(dev, root, B, mode, NotifyNonlinearVirtual);
1383 }
1384
1385 if (!HasFocus(B)) {
1386 WindowPtr child = FirstFocusChild(B);
1387
1388 if (child) {
1389 CoreFocusEvent(dev, FocusIn, mode, NotifyInferior, B);
1390 /* NotifyPointer B-P unless P is child or below. */
1391 CoreFocusInNotifyPointerEvents(dev, B, child, mode, FALSE);
1392 }
1393 else {
1394 CoreFocusEvent(dev, FocusIn, mode, NotifyNonlinear, B);
1395 /* NotifyPointer B-P unless P is child or below. */
1396 CoreFocusInNotifyPointerEvents(dev, B, None, mode, FALSE);
1397 }
1398 }
1399
1400}
1401
1402static void
1403CoreFocusEvents(DeviceIntPtr dev, WindowPtr from, WindowPtr to, int mode)
1404{
1405 if (!IsMaster(dev))
1406 return;
1407
1408 SetFocusOut(dev);
1409
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);
1421 else
1422 CoreFocusNonLinear(dev, from, to, mode);
1423
1424 SetFocusIn(dev, to);
1425}
1426
1427static void
1428DeviceFocusEvents(DeviceIntPtr dev, WindowPtr from, WindowPtr to, int mode)
1429{
1430 int out, in; /* for holding details for to/from
1431 PointerRoot/None */
1432 int i;
1433 int nscreens = screenInfo.numScreens;
1434 SpritePtr sprite = dev->spriteInfo->sprite;
1435
1436 if (from == to)
1437 return;
1438 out = (from == NoneWin) ? NotifyDetailNone : NotifyPointerRoot;
1439 in = (to == NoneWin) ? NotifyDetailNone : NotifyPointerRoot;
1440 /* wrong values if neither, but then not referenced */
1441
1442#ifdef PANORAMIX
1443 if (!noPanoramiXExtension)
1444 nscreens = 1;
1445#endif
1446
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,
1452 NotifyPointer);
1453 /* Notify all the roots */
1454 for (i = 0; i < nscreens; i++)
1455 DeviceFocusEvent(dev, XI_FocusOut, mode, out,
1456 screenInfo.screens[i]->root);
1457 }
1458 else {
1459 if (IsParent(from, sprite->win))
1460 DeviceFocusOutEvents(dev, sprite->win, from, mode,
1461 NotifyPointer);
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);
1466 }
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);
1475 }
1476 }
1477 else {
1478 if ((from == NullWindow) || (from == PointerRootWin)) {
1479 if (from == PointerRootWin)
1480 DeviceFocusOutEvents(dev, sprite->win,
1481 GetCurrentRootWindow(dev), mode,
1482 NotifyPointer);
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);
1492 }
1493 else {
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,
1503 NotifyPointer);
1504 }
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,
1511 NotifyPointer);
1512 DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyInferior, from);
1513 DeviceFocusInEvents(dev, from, to, mode, NotifyVirtual);
1514 DeviceFocusEvent(dev, XI_FocusIn, mode, NotifyAncestor, to);
1515 }
1516 else {
1517 /* neither from or to is child of other */
1518 WindowPtr common = CommonAncestor(to, from);
1519
1520 /* common == NullWindow ==> different screens */
1521 if (IsParent(from, sprite->win))
1522 DeviceFocusOutEvents(dev, sprite->win, from, mode,
1523 NotifyPointer);
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,
1534 NotifyPointer);
1535 }
1536 }
1537 }
1538}
1539
1540/**
1541 * Figure out if focus events are necessary and send them to the
1542 * appropriate windows.
1543 *
1544 * @param from Window the focus moved out of.
1545 * @param to Window the focus moved into.
1546 */
1547void
1548DoFocusEvents(DeviceIntPtr pDev, WindowPtr from, WindowPtr to, int mode)
1549{
1550 if (!IsKeyboardDevice(pDev))
1551 return;
1552
1553 if (from == to)
1554 return;
1555
1556 CoreFocusEvents(pDev, from, to, mode);
1557 DeviceFocusEvents(pDev, from, to, mode);
1558}