Bug Summary

File:dix/enterleave.c
Location:line 629, column 5
Description:Value stored to 'first' is never read

Annotated Source Code

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_H1
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[MAXDEVICES40];
79static WindowPtr FocusWindows[MAXDEVICES40];
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 FALSE0;
98
99 for (i = 0; i < MAXDEVICES40; i++)
100 if (PointerWindows[i] == win)
101 return TRUE1;
102
103 return FALSE0;
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 < MAXDEVICES40; i++)
116 if (FocusWindows[i] == win)
117 return TRUE1;
118
119 return FALSE0;
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 < MAXDEVICES40; i++) {
144 if (PointerWindows[i] && IsParent(win, PointerWindows[i]))
145 return PointerWindows[i];
146 }
147
148 return NULL((void*)0);
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 < MAXDEVICES40; i++) {
164 if (FocusWindows[i] && FocusWindows[i] != PointerRootWin((WindowPtr)1L) &&
165 IsParent(win, FocusWindows[i]))
166 return FocusWindows[i];
167 }
168
169 return NULL((void*)0);
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((void*)0);
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((void*)0);
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 */
215static WindowPtr
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((WindowPtr) 0);
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_Enter7, 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, EnterNotify7, 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, LeaveNotify8, 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_Leave8, 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, LeaveNotify8, mode, NotifyInferior2, A,
376 None0L);
377 else
378 CoreEnterLeaveEvent(dev, LeaveNotify8, mode, NotifyNonlinear3, A,
379 None0L);
380 }
381
382 CoreLeaveNotifies(dev, A, X, mode, NotifyNonlinearVirtual4);
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, NotifyNonlinearVirtual4);
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, EnterNotify7, mode, NotifyInferior2, B,
420 None0L);
421 else
422 CoreEnterLeaveEvent(dev, EnterNotify7, mode, NotifyNonlinear3, B,
423 None0L);
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, LeaveNotify8, mode, NotifyInferior2, A,
457 None0L);
458 else
459 CoreEnterLeaveEvent(dev, LeaveNotify8, mode, NotifyAncestor0, A,
460 None0L);
461 }
462
463 CoreLeaveNotifies(dev, A, B, mode, NotifyVirtual1);
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, EnterNotify7, mode, NotifyInferior2, B, None0L);
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, LeaveNotify8, mode, NotifyInferior2, A, None0L);
504
505 CoreEnterNotifies(dev, A, B, mode, NotifyVirtual1);
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, EnterNotify7, mode, NotifyInferior2, B,
530 None0L);
531 else
532 CoreEnterLeaveEvent(dev, EnterNotify7, mode, NotifyAncestor0, B,
533 None0L);
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_Leave8, mode, NotifyInferior2,
561 from, None0L);
562 DeviceEnterNotifies(dev, sourceid, from, to, mode, NotifyVirtual1);
563 DeviceEnterLeaveEvent(dev, sourceid, XI_Enter7, mode, NotifyAncestor0, to,
564 None0L);
565 }
566 else if (IsParent(to, from)) {
567 DeviceEnterLeaveEvent(dev, sourceid, XI_Leave8, mode, NotifyAncestor0,
568 from, None0L);
569 DeviceLeaveNotifies(dev, sourceid, from, to, mode, NotifyVirtual1);
570 DeviceEnterLeaveEvent(dev, sourceid, XI_Enter7, mode, NotifyInferior2, to,
571 None0L);
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_Leave8, mode, NotifyNonlinear3,
578 from, None0L);
579 DeviceLeaveNotifies(dev, sourceid, from, common, mode,
580 NotifyNonlinearVirtual4);
581 DeviceEnterNotifies(dev, sourceid, common, to, mode,
582 NotifyNonlinearVirtual4);
583 DeviceEnterLeaveEvent(dev, sourceid, XI_Enter7, mode, NotifyNonlinear3,
584 to, None0L);
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 != XINotifyPassiveGrab4 && mode != XINotifyPassiveUngrab5)
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;
Value stored to 'first' is never read
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 << ButtonClass1);
646 ev->num_buttons = b->numButtons;
647 memcpy((char *) ev->buttons, (char *) b->down, 4)__builtin___memcpy_chk ((char *) ev->buttons, (char *) b->
down, 4, __builtin_object_size ((char *) ev->buttons, 0))
;
648 }
649 else if (k) {
650 ev->classes_reported |= (1 << KeyClass0);
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)__builtin___memmove_chk ((char *) &ev->keys[0], (char *
) k->down, 4, __builtin_object_size ((char *) &ev->
keys[0], 0))
;
654 }
655 if (v) {
656 int nval = v->numAxes - first;
657
658 ev->classes_reported |= (1 << ValuatorClass2);
659 ev->classes_reported |= valuator_get_mode(dev, 0) << ModeBitsShift6;
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)((win)->optional ? (win)->optional->inputMasks : ((void
*)0))
) ||
688 !(wOtherInputMasks(win)((win)->optional ? (win)->optional->inputMasks : ((void
*)0))
->inputEvents[dev->id] & DeviceStateNotifyMask))
689 return;
690
691 if ((b = dev->button) != NULL((void*)0)) {
692 nbuttons = b->numButtons;
693 if (nbuttons > 32)
694 evcount++;
695 }
696 if ((k = dev->key) != NULL((void*)0)) {
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((void*)0)) {
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 = xallocarray(evcount, sizeof(xEvent))xreallocarray(((void*)0), (evcount), (sizeof(xEvent)));
718 FixDeviceStateNotify(dev, ev, NULL((void*)0), NULL((void*)0), NULL((void*)0), first);
719
720 if (b != NULL((void*)0)) {
721 FixDeviceStateNotify(dev, ev++, NULL((void*)0), b, v, first);
722 first += 3;
723 nval -= 3;
724 if (nbuttons > 32) {
725 (ev - 1)->deviceid |= MORE_EVENTS0x80;
726 bev = (deviceButtonStateNotify *) ev++;
727 bev->type = DeviceButtonStateNotify;
728 bev->deviceid = dev->id;
729 memcpy((char *) &bev->buttons[4], (char *) &b->down[4],__builtin___memcpy_chk ((char *) &bev->buttons[4], (char
*) &b->down[4], (256/8) - 4, __builtin_object_size ((
char *) &bev->buttons[4], 0))
730 DOWN_LENGTH - 4)__builtin___memcpy_chk ((char *) &bev->buttons[4], (char
*) &b->down[4], (256/8) - 4, __builtin_object_size ((
char *) &bev->buttons[4], 0))
;
731 }
732 if (nval > 0) {
733 (ev - 1)->deviceid |= MORE_EVENTS0x80;
734 FixDeviceValuator(dev, (deviceValuator *) ev++, v, first);
735 first += 3;
736 nval -= 3;
737 }
738 }
739
740 if (k != NULL((void*)0)) {
741 FixDeviceStateNotify(dev, ev++, k, NULL((void*)0), v, first);
742 first += 3;
743 nval -= 3;
744 if (nkeys > 32) {
745 (ev - 1)->deviceid |= MORE_EVENTS0x80;
746 kev = (deviceKeyStateNotify *) ev++;
747 kev->type = DeviceKeyStateNotify;
748 kev->deviceid = dev->id;
749 memmove((char *) &kev->keys[0], (char *) &k->down[4], 28)__builtin___memmove_chk ((char *) &kev->keys[0], (char
*) &k->down[4], 28, __builtin_object_size ((char *) &
kev->keys[0], 0))
;
750 }
751 if (nval > 0) {
752 (ev - 1)->deviceid |= MORE_EVENTS0x80;
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((void*)0), NULL((void*)0), v, first);
761 first += 3;
762 nval -= 3;
763 if (nval > 0) {
764 (ev - 1)->deviceid |= MORE_EVENTS0x80;
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((GrabPtr)((void*)0)));
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 UpdateCurrentTimeIf();
786 mouse = IsFloating(dev) ? dev : GetMaster(dev, MASTER_POINTER1);
787
788 /* XI 2 event */
789 btlen = (mouse->button) ? bits_to_bytes(mouse->button->numButtons) : 0;
790 btlen = bytes_to_int32(btlen);
791 len = sizeof(xXIFocusInEvent) + btlen * 4;
792
793 xi2event = calloc(1, len);
794 xi2event->type = GenericEvent35;
795 xi2event->extension = IReqCode;
796 xi2event->evtype = type;
797 xi2event->length = bytes_to_int32(len - sizeof(xEvent));
798 xi2event->buttons_len = btlen;
799 xi2event->detail = detail;
800 xi2event->time = currentTime.milliseconds;
801 xi2event->deviceid = dev->id;
802 xi2event->sourceid = dev->id; /* a device doesn't change focus by itself */
803 xi2event->mode = mode;
804 xi2event->root_x = double_to_fp1616(mouse->spriteInfo->sprite->hot.x);
805 xi2event->root_y = double_to_fp1616(mouse->spriteInfo->sprite->hot.y);
806
807 for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++)
808 if (BitIsOn(mouse->button->down, i)(!!(((const BYTE *) (mouse->button->down))[(i)>>3
] & (1 << ((i) & 7))))
)
809 SetBit(&xi2event[1], mouse->button->map[i])(((BYTE *) (&xi2event[1]))[(mouse->button->map[i])>>
3] |= (1 << ((mouse->button->map[i]) & 7)))
;
810
811 if (dev->key) {
812 xi2event->mods.base_mods = dev->key->xkbInfo->state.base_mods;
813 xi2event->mods.latched_mods = dev->key->xkbInfo->state.latched_mods;
814 xi2event->mods.locked_mods = dev->key->xkbInfo->state.locked_mods;
815 xi2event->mods.effective_mods = dev->key->xkbInfo->state.mods;
816
817 xi2event->group.base_group = dev->key->xkbInfo->state.base_group;
818 xi2event->group.latched_group = dev->key->xkbInfo->state.latched_group;
819 xi2event->group.locked_group = dev->key->xkbInfo->state.locked_group;
820 xi2event->group.effective_group = dev->key->xkbInfo->state.group;
821 }
822
823 FixUpEventFromWindow(dev->spriteInfo->sprite, (xEvent *) xi2event, pWin,
824 None0L, FALSE0);
825
826 DeliverEventsToWindow(dev, pWin, (xEvent *) xi2event, 1,
827 GetEventFilter(dev, (xEvent *) xi2event), NullGrab((GrabPtr)((void*)0)));
828
829 free(xi2event);
830
831 /* XI 1.x event */
832 event = (deviceFocus) {
833 .deviceid = dev->id,
834 .mode = mode,
835 .type = (type == XI_FocusIn9) ? DeviceFocusIn : DeviceFocusOut,
836 .detail = detail,
837 .window = pWin->drawable.id,
838 .time = currentTime.milliseconds
839 };
840
841 DeliverEventsToWindow(dev, pWin, (xEvent *) &event, 1,
842 DeviceFocusChangeMask, NullGrab((GrabPtr)((void*)0)));
843
844 if (event.type == DeviceFocusIn)
845 DeliverStateNotifyEvent(dev, pWin);
846}
847
848/**
849 * Send focus out events to all windows between 'child' and 'ancestor'.
850 * Events are sent running up the hierarchy.
851 */
852static void
853DeviceFocusOutEvents(DeviceIntPtr dev,
854 WindowPtr child, WindowPtr ancestor, int mode, int detail)
855{
856 WindowPtr win;
857
858 if (ancestor == child)
859 return;
860 for (win = child->parent; win != ancestor; win = win->parent)
861 DeviceFocusEvent(dev, XI_FocusOut10, mode, detail, win);
862}
863
864/**
865 * Send enter notifies to all windows between 'ancestor' and 'child' (excluding
866 * both). Events are sent running up the window hierarchy. This function
867 * recurses.
868 */
869static void
870DeviceFocusInEvents(DeviceIntPtr dev,
871 WindowPtr ancestor, WindowPtr child, int mode, int detail)
872{
873 WindowPtr parent = child->parent;
874
875 if (ancestor == parent || !parent)
876 return;
877 DeviceFocusInEvents(dev, ancestor, parent, mode, detail);
878 DeviceFocusEvent(dev, XI_FocusIn9, mode, detail, parent);
879}
880
881/**
882 * Send FocusIn events to all windows between 'ancestor' and 'child' (excluding
883 * both). Events are sent running down the window hierarchy. This function
884 * recurses.
885 */
886static void
887CoreFocusInEvents(DeviceIntPtr dev,
888 WindowPtr ancestor, WindowPtr child, int mode, int detail)
889{
890 WindowPtr parent = child->parent;
891
892 if (ancestor == parent)
893 return;
894 CoreFocusInEvents(dev, ancestor, parent, mode, detail);
895
896 /* Case 3:
897 A is above W, B is a descendant
898
899 Classically: The move generates an FocusIn on W with a detail of
900 Virtual or NonlinearVirtual
901
902 MPX:
903 Case 3A: There is at least one other focus on W itself
904 F(W) doesn't change, so the event should be suppressed
905 Case 3B: Otherwise, if there is at least one other focus in a
906 descendant
907 F(W) stays on the same descendant, or changes to a different
908 descendant. The event should be suppressed.
909 Case 3C: Otherwise:
910 F(W) moves from a window above W to a descendant. The detail may
911 need to be changed from Virtual to NonlinearVirtual depending
912 on the previous F(W). */
913
914 if (!HasFocus(parent) && !FirstFocusChild(parent))
915 CoreFocusEvent(dev, FocusIn9, mode, detail, parent);
916}
917
918static void
919CoreFocusOutEvents(DeviceIntPtr dev,
920 WindowPtr child, WindowPtr ancestor, int mode, int detail)
921{
922 WindowPtr win;
923
924 if (ancestor == child)
925 return;
926
927 for (win = child->parent; win != ancestor; win = win->parent) {
928 /*Case 7:
929 A is a descendant of W, B is above W
930
931 Classically: A FocusOut is generated on W with a detail of Virtual
932 or NonlinearVirtual.
933
934 MPX:
935 Case 3A: There is at least one other focus on W itself
936 F(W) doesn't change, the event should be suppressed.
937 Case 3B: Otherwise, if there is at least one other focus in a
938 descendant
939 F(W) stays on the same descendant, or changes to a different
940 descendant. The event should be suppressed.
941 Case 3C: Otherwise:
942 F(W) changes from the descendant of W to a window above W.
943 The detail may need to be changed from Virtual to NonlinearVirtual
944 or vice-versa depending on the new P(W). */
945
946 /* If one window has a focus or a child with a focuspointer, skip some
947 * work and exit. */
948 if (HasFocus(win) || FirstFocusChild(win))
949 return;
950
951 CoreFocusEvent(dev, FocusOut10, mode, detail, win);
952 }
953}
954
955/**
956 * Send FocusOut(NotifyPointer) events from the current pointer window (which
957 * is a descendant of pwin_parent) up to (excluding) pwin_parent.
958 *
959 * NotifyPointer events are only sent for the device paired with dev.
960 *
961 * If the current pointer window is a descendant of 'exclude' or an ancestor of
962 * 'exclude', no events are sent. If the current pointer IS 'exclude', events
963 * are sent!
964 */
965static void
966CoreFocusOutNotifyPointerEvents(DeviceIntPtr dev,
967 WindowPtr pwin_parent,
968 WindowPtr exclude, int mode, int inclusive)
969{
970 WindowPtr P, stopAt;
971
972 P = PointerWin(GetMaster(dev, POINTER_OR_FLOAT6));
973
974 if (!P)
975 return;
976 if (!IsParent(pwin_parent, P))
977 if (!(pwin_parent == P && inclusive))
978 return;
979
980 if (exclude != None0L && exclude != PointerRootWin((WindowPtr)1L) &&
981 (IsParent(exclude, P) || IsParent(P, exclude)))
982 return;
983
984 stopAt = (inclusive) ? pwin_parent->parent : pwin_parent;
985
986 for (; P && P != stopAt; P = P->parent)
987 CoreFocusEvent(dev, FocusOut10, mode, NotifyPointer5, P);
988}
989
990/**
991 * DO NOT CALL DIRECTLY.
992 * Recursion helper for CoreFocusInNotifyPointerEvents.
993 */
994static void
995CoreFocusInRecurse(DeviceIntPtr dev,
996 WindowPtr win, WindowPtr stopAt, int mode, int inclusive)
997{
998 if ((!inclusive && win == stopAt) || !win)
999 return;
1000
1001 CoreFocusInRecurse(dev, win->parent, stopAt, mode, inclusive);
1002 CoreFocusEvent(dev, FocusIn9, mode, NotifyPointer5, win);
1003}
1004
1005/**
1006 * Send FocusIn(NotifyPointer) events from pwin_parent down to
1007 * including the current pointer window (which is a descendant of pwin_parent).
1008 *
1009 * @param pwin The pointer window.
1010 * @param exclude If the pointer window is a child of 'exclude', no events are
1011 * sent.
1012 * @param inclusive If TRUE, pwin_parent will receive the event too.
1013 */
1014static void
1015CoreFocusInNotifyPointerEvents(DeviceIntPtr dev,
1016 WindowPtr pwin_parent,
1017 WindowPtr exclude, int mode, int inclusive)
1018{
1019 WindowPtr P;
1020
1021 P = PointerWin(GetMaster(dev, POINTER_OR_FLOAT6));
1022
1023 if (!P || P == exclude || (pwin_parent != P && !IsParent(pwin_parent, P)))
1024 return;
1025
1026 if (exclude != None0L && (IsParent(exclude, P) || IsParent(P, exclude)))
1027 return;
1028
1029 CoreFocusInRecurse(dev, P, pwin_parent, mode, inclusive);
1030}
1031
1032/**
1033 * Focus of dev moves from A to B and A neither a descendant of B nor is
1034 * B a descendant of A.
1035 */
1036static void
1037CoreFocusNonLinear(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode)
1038{
1039 WindowPtr X = CommonAncestor(A, B);
1040
1041 /* Case 4:
1042 A is W, B is above W
1043
1044 Classically: The change generates a FocusOut on W with a detail of
1045 Ancestor or Nonlinear
1046
1047 MPX:
1048 Case 3A: There is at least one other focus on W itself
1049 F(W) doesn't change, the event should be suppressed
1050 Case 3B: Otherwise, if there is at least one other focus in a
1051 descendant of W
1052 F(W) changes from W to a descendant of W. The detail field
1053 is set to Inferior
1054 Case 3C: Otherwise:
1055 The focus window moves from W to a window above W.
1056 The detail may need to be changed from Ancestor to Nonlinear or
1057 vice versa depending on the the new F(W)
1058 */
1059
1060 if (!HasFocus(A)) {
1061 WindowPtr child = FirstFocusChild(A);
1062
1063 if (child) {
1064 /* NotifyPointer P-A unless P is child or below */
1065 CoreFocusOutNotifyPointerEvents(dev, A, child, mode, FALSE0);
1066 CoreFocusEvent(dev, FocusOut10, mode, NotifyInferior2, A);
1067 }
1068 else {
1069 /* NotifyPointer P-A */
1070 CoreFocusOutNotifyPointerEvents(dev, A, None0L, mode, FALSE0);
1071 CoreFocusEvent(dev, FocusOut10, mode, NotifyNonlinear3, A);
1072 }
1073 }
1074
1075 CoreFocusOutEvents(dev, A, X, mode, NotifyNonlinearVirtual4);
1076
1077 /*
1078 Case 9:
1079 A is a descendant of W, B is a descendant of W
1080
1081 Classically: No events are generated on W
1082 MPX: The focus window stays the same or moves to a different
1083 descendant of W. No events should be generated on W.
1084
1085 Therefore, no event to X.
1086 */
1087
1088 CoreFocusInEvents(dev, X, B, mode, NotifyNonlinearVirtual4);
1089
1090 /* Case 2:
1091 A is above W, B=W
1092
1093 Classically: The move generates an EnterNotify on W with a detail of
1094 Ancestor or Nonlinear
1095
1096 MPX:
1097 Case 2A: There is at least one other focus on W itself
1098 F(W) doesn't change, so the event should be suppressed
1099 Case 2B: Otherwise, if there is at least one other focus in a
1100 descendant
1101 F(W) moves from a descendant to W. detail is changed to Inferior.
1102 Case 2C: Otherwise:
1103 F(W) changes from a window above W to W itself.
1104 The detail may need to be changed from Ancestor to Nonlinear
1105 or vice-versa depending on the previous F(W). */
1106
1107 if (!HasFocus(B)) {
1108 WindowPtr child = FirstFocusChild(B);
1109
1110 if (child) {
1111 CoreFocusEvent(dev, FocusIn9, mode, NotifyInferior2, B);
1112 /* NotifyPointer B-P unless P is child or below. */
1113 CoreFocusInNotifyPointerEvents(dev, B, child, mode, FALSE0);
1114 }
1115 else {
1116 CoreFocusEvent(dev, FocusIn9, mode, NotifyNonlinear3, B);
1117 /* NotifyPointer B-P unless P is child or below. */
1118 CoreFocusInNotifyPointerEvents(dev, B, None0L, mode, FALSE0);
1119 }
1120 }
1121}
1122
1123/**
1124 * Focus of dev moves from A to B and A is a descendant of B.
1125 */
1126static void
1127CoreFocusToAncestor(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode)
1128{
1129 /* Case 4:
1130 A is W, B is above W
1131
1132 Classically: The change generates a FocusOut on W with a detail of
1133 Ancestor or Nonlinear
1134
1135 MPX:
1136 Case 3A: There is at least one other focus on W itself
1137 F(W) doesn't change, the event should be suppressed
1138 Case 3B: Otherwise, if there is at least one other focus in a
1139 descendant of W
1140 F(W) changes from W to a descendant of W. The detail field
1141 is set to Inferior
1142 Case 3C: Otherwise:
1143 The focus window moves from W to a window above W.
1144 The detail may need to be changed from Ancestor to Nonlinear or
1145 vice versa depending on the the new F(W)
1146 */
1147 if (!HasFocus(A)) {
1148 WindowPtr child = FirstFocusChild(A);
1149
1150 if (child) {
1151 /* NotifyPointer P-A unless P is child or below */
1152 CoreFocusOutNotifyPointerEvents(dev, A, child, mode, FALSE0);
1153 CoreFocusEvent(dev, FocusOut10, mode, NotifyInferior2, A);
1154 }
1155 else
1156 CoreFocusEvent(dev, FocusOut10, mode, NotifyAncestor0, A);
1157 }
1158
1159 CoreFocusOutEvents(dev, A, B, mode, NotifyVirtual1);
1160
1161 /* Case 8:
1162 A is a descendant of W, B is W
1163
1164 Classically: A FocusOut is generated on W with a detail of
1165 NotifyInferior
1166
1167 MPX:
1168 Case 3A: There is at least one other focus on W itself
1169 F(W) doesn't change, the event should be suppressed
1170 Case 3B: Otherwise:
1171 F(W) changes from a descendant to W itself. */
1172
1173 if (!HasFocus(B)) {
1174 CoreFocusEvent(dev, FocusIn9, mode, NotifyInferior2, B);
1175 /* NotifyPointer B-P unless P is A or below. */
1176 CoreFocusInNotifyPointerEvents(dev, B, A, mode, FALSE0);
1177 }
1178}
1179
1180/**
1181 * Focus of dev moves from A to B and B is a descendant of A.
1182 */
1183static void
1184CoreFocusToDescendant(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode)
1185{
1186 /* Case 6:
1187 A is W, B is a descendant of W
1188
1189 Classically: A FocusOut is generated on W with a detail of
1190 NotifyInferior
1191
1192 MPX:
1193 Case 3A: There is at least one other focus on W itself
1194 F(W) doesn't change, the event should be suppressed
1195 Case 3B: Otherwise:
1196 F(W) changes from W to a descendant of W. */
1197
1198 if (!HasFocus(A)) {
1199 /* NotifyPointer P-A unless P is B or below */
1200 CoreFocusOutNotifyPointerEvents(dev, A, B, mode, FALSE0);
1201 CoreFocusEvent(dev, FocusOut10, mode, NotifyInferior2, A);
1202 }
1203
1204 CoreFocusInEvents(dev, A, B, mode, NotifyVirtual1);
1205
1206 /* Case 2:
1207 A is above W, B=W
1208
1209 Classically: The move generates an FocusIn on W with a detail of
1210 Ancestor or Nonlinear
1211
1212 MPX:
1213 Case 2A: There is at least one other focus on W itself
1214 F(W) doesn't change, so the event should be suppressed
1215 Case 2B: Otherwise, if there is at least one other focus in a
1216 descendant
1217 F(W) moves from a descendant to W. detail is changed to Inferior.
1218 Case 2C: Otherwise:
1219 F(W) changes from a window above W to W itself.
1220 The detail may need to be changed from Ancestor to Nonlinear
1221 or vice-versa depending on the previous F(W). */
1222
1223 if (!HasFocus(B)) {
1224 WindowPtr child = FirstFocusChild(B);
1225
1226 if (child) {
1227 CoreFocusEvent(dev, FocusIn9, mode, NotifyInferior2, B);
1228 /* NotifyPointer B-P unless P is child or below. */
1229 CoreFocusInNotifyPointerEvents(dev, B, child, mode, FALSE0);
1230 }
1231 else
1232 CoreFocusEvent(dev, FocusIn9, mode, NotifyAncestor0, B);
1233 }
1234}
1235
1236static BOOL
1237HasOtherPointer(WindowPtr win, DeviceIntPtr exclude)
1238{
1239 int i;
1240
1241 for (i = 0; i < MAXDEVICES40; i++)
1242 if (i != exclude->id && PointerWindows[i] == win)
1243 return TRUE1;
1244
1245 return FALSE0;
1246}
1247
1248/**
1249 * Focus moves from PointerRoot to None or from None to PointerRoot.
1250 * Assumption: Neither A nor B are valid windows.
1251 */
1252static void
1253CoreFocusPointerRootNoneSwitch(DeviceIntPtr dev,
1254 WindowPtr A, /* PointerRootWin or NoneWin */
1255 WindowPtr B, /* NoneWin or PointerRootWin */
1256 int mode)
1257{
1258 WindowPtr root;
1259 int i;
1260 int nscreens = screenInfo.numScreens;
1261
1262#ifdef PANORAMIX1
1263 if (!noPanoramiXExtension)
1264 nscreens = 1;
1265#endif
1266
1267 for (i = 0; i < nscreens; i++) {
1268 root = screenInfo.screens[i]->root;
1269 if (!HasOtherPointer(root, GetMaster(dev, POINTER_OR_FLOAT6)) &&
1270 !FirstFocusChild(root)) {
1271 /* If pointer was on PointerRootWin and changes to NoneWin, and
1272 * the pointer paired with dev is below the current root window,
1273 * do a NotifyPointer run. */
1274 if (dev->focus && dev->focus->win == PointerRootWin((WindowPtr)1L) &&
1275 B != PointerRootWin((WindowPtr)1L)) {
1276 WindowPtr ptrwin = PointerWin(GetMaster(dev, POINTER_OR_FLOAT6));
1277
1278 if (ptrwin && IsParent(root, ptrwin))
1279 CoreFocusOutNotifyPointerEvents(dev, root, None0L, mode,
1280 TRUE1);
1281 }
1282 CoreFocusEvent(dev, FocusOut10, mode,
1283 A ? NotifyPointerRoot6 : NotifyDetailNone7, root);
1284 CoreFocusEvent(dev, FocusIn9, mode,
1285 B ? NotifyPointerRoot6 : NotifyDetailNone7, root);
1286 if (B == PointerRootWin((WindowPtr)1L))
1287 CoreFocusInNotifyPointerEvents(dev, root, None0L, mode, TRUE1);
1288 }
1289
1290 }
1291}
1292
1293/**
1294 * Focus moves from window A to PointerRoot or to None.
1295 * Assumption: A is a valid window and not PointerRoot or None.
1296 */
1297static void
1298CoreFocusToPointerRootOrNone(DeviceIntPtr dev, WindowPtr A,
1299 WindowPtr B, /* PointerRootWin or NoneWin */
1300 int mode)
1301{
1302 WindowPtr root;
1303 int i;
1304 int nscreens = screenInfo.numScreens;
1305
1306#ifdef PANORAMIX1
1307 if (!noPanoramiXExtension)
1308 nscreens = 1;
1309#endif
1310
1311 if (!HasFocus(A)) {
1312 WindowPtr child = FirstFocusChild(A);
1313
1314 if (child) {
1315 /* NotifyPointer P-A unless P is B or below */
1316 CoreFocusOutNotifyPointerEvents(dev, A, B, mode, FALSE0);
1317 CoreFocusEvent(dev, FocusOut10, mode, NotifyInferior2, A);
1318 }
1319 else {
1320 /* NotifyPointer P-A */
1321 CoreFocusOutNotifyPointerEvents(dev, A, None0L, mode, FALSE0);
1322 CoreFocusEvent(dev, FocusOut10, mode, NotifyNonlinear3, A);
1323 }
1324 }
1325
1326 /* NullWindow means we include the root window */
1327 CoreFocusOutEvents(dev, A, NullWindow((WindowPtr) 0), mode, NotifyNonlinearVirtual4);
1328
1329 for (i = 0; i < nscreens; i++) {
1330 root = screenInfo.screens[i]->root;
1331 if (!HasFocus(root) && !FirstFocusChild(root)) {
1332 CoreFocusEvent(dev, FocusIn9, mode,
1333 B ? NotifyPointerRoot6 : NotifyDetailNone7, root);
1334 if (B == PointerRootWin((WindowPtr)1L))
1335 CoreFocusInNotifyPointerEvents(dev, root, None0L, mode, TRUE1);
1336 }
1337 }
1338}
1339
1340/**
1341 * Focus moves from PointerRoot or None to a window B.
1342 * Assumption: B is a valid window and not PointerRoot or None.
1343 */
1344static void
1345CoreFocusFromPointerRootOrNone(DeviceIntPtr dev,
1346 WindowPtr A, /* PointerRootWin or NoneWin */
1347 WindowPtr B, int mode)
1348{
1349 WindowPtr root;
1350 int i;
1351 int nscreens = screenInfo.numScreens;
1352
1353#ifdef PANORAMIX1
1354 if (!noPanoramiXExtension)
1355 nscreens = 1;
1356#endif
1357
1358 for (i = 0; i < nscreens; i++) {
1359 root = screenInfo.screens[i]->root;
1360 if (!HasFocus(root) && !FirstFocusChild(root)) {
1361 /* If pointer was on PointerRootWin and changes to NoneWin, and
1362 * the pointer paired with dev is below the current root window,
1363 * do a NotifyPointer run. */
1364 if (dev->focus && dev->focus->win == PointerRootWin((WindowPtr)1L) &&
1365 B != PointerRootWin((WindowPtr)1L)) {
1366 WindowPtr ptrwin = PointerWin(GetMaster(dev, POINTER_OR_FLOAT6));
1367
1368 if (ptrwin)
1369 CoreFocusOutNotifyPointerEvents(dev, root, None0L, mode,
1370 TRUE1);
1371 }
1372 CoreFocusEvent(dev, FocusOut10, mode,
1373 A ? NotifyPointerRoot6 : NotifyDetailNone7, root);
1374 }
1375 }
1376
1377 root = B; /* get B's root window */
1378 while (root->parent)
1379 root = root->parent;
1380
1381 if (B != root) {
1382 CoreFocusEvent(dev, FocusIn9, mode, NotifyNonlinearVirtual4, root);
1383 CoreFocusInEvents(dev, root, B, mode, NotifyNonlinearVirtual4);
1384 }
1385
1386 if (!HasFocus(B)) {
1387 WindowPtr child = FirstFocusChild(B);
1388
1389 if (child) {
1390 CoreFocusEvent(dev, FocusIn9, mode, NotifyInferior2, B);
1391 /* NotifyPointer B-P unless P is child or below. */
1392 CoreFocusInNotifyPointerEvents(dev, B, child, mode, FALSE0);
1393 }
1394 else {
1395 CoreFocusEvent(dev, FocusIn9, mode, NotifyNonlinear3, B);
1396 /* NotifyPointer B-P unless P is child or below. */
1397 CoreFocusInNotifyPointerEvents(dev, B, None0L, mode, FALSE0);
1398 }
1399 }
1400
1401}
1402
1403static void
1404CoreFocusEvents(DeviceIntPtr dev, WindowPtr from, WindowPtr to, int mode)
1405{
1406 if (!IsMaster(dev))
1407 return;
1408
1409 SetFocusOut(dev);
1410
1411 if (((to == NullWindow((WindowPtr) 0)) || (to == PointerRootWin((WindowPtr)1L))) &&
1412 ((from == NullWindow((WindowPtr) 0)) || (from == PointerRootWin((WindowPtr)1L))))
1413 CoreFocusPointerRootNoneSwitch(dev, from, to, mode);
1414 else if ((to == NullWindow((WindowPtr) 0)) || (to == PointerRootWin((WindowPtr)1L)))
1415 CoreFocusToPointerRootOrNone(dev, from, to, mode);
1416 else if ((from == NullWindow((WindowPtr) 0)) || (from == PointerRootWin((WindowPtr)1L)))
1417 CoreFocusFromPointerRootOrNone(dev, from, to, mode);
1418 else if (IsParent(from, to))
1419 CoreFocusToDescendant(dev, from, to, mode);
1420 else if (IsParent(to, from))
1421 CoreFocusToAncestor(dev, from, to, mode);
1422 else
1423 CoreFocusNonLinear(dev, from, to, mode);
1424
1425 SetFocusIn(dev, to);
1426}
1427
1428static void
1429DeviceFocusEvents(DeviceIntPtr dev, WindowPtr from, WindowPtr to, int mode)
1430{
1431 int out, in; /* for holding details for to/from
1432 PointerRoot/None */
1433 int i;
1434 int nscreens = screenInfo.numScreens;
1435 SpritePtr sprite = dev->spriteInfo->sprite;
1436
1437 if (from == to)
1438 return;
1439 out = (from == NoneWin((WindowPtr)0L)) ? NotifyDetailNone7 : NotifyPointerRoot6;
1440 in = (to == NoneWin((WindowPtr)0L)) ? NotifyDetailNone7 : NotifyPointerRoot6;
1441 /* wrong values if neither, but then not referenced */
1442
1443#ifdef PANORAMIX1
1444 if (!noPanoramiXExtension)
1445 nscreens = 1;
1446#endif
1447
1448 if ((to == NullWindow((WindowPtr) 0)) || (to == PointerRootWin((WindowPtr)1L))) {
1449 if ((from == NullWindow((WindowPtr) 0)) || (from == PointerRootWin((WindowPtr)1L))) {
1450 if (from == PointerRootWin((WindowPtr)1L)) {
1451 DeviceFocusEvent(dev, XI_FocusOut10, mode, NotifyPointer5,
1452 sprite->win);
1453 DeviceFocusOutEvents(dev, sprite->win,
1454 GetCurrentRootWindow(dev), mode,
1455 NotifyPointer5);
1456 }
1457 /* Notify all the roots */
1458 for (i = 0; i < nscreens; i++)
1459 DeviceFocusEvent(dev, XI_FocusOut10, mode, out,
1460 screenInfo.screens[i]->root);
1461 }
1462 else {
1463 if (IsParent(from, sprite->win)) {
1464 DeviceFocusEvent(dev, XI_FocusOut10, mode, NotifyPointer5,
1465 sprite->win);
1466 DeviceFocusOutEvents(dev, sprite->win, from, mode,
1467 NotifyPointer5);
1468 }
1469 DeviceFocusEvent(dev, XI_FocusOut10, mode, NotifyNonlinear3, from);
1470 /* next call catches the root too, if the screen changed */
1471 DeviceFocusOutEvents(dev, from, NullWindow((WindowPtr) 0), mode,
1472 NotifyNonlinearVirtual4);
1473 }
1474 /* Notify all the roots */
1475 for (i = 0; i < nscreens; i++)
1476 DeviceFocusEvent(dev, XI_FocusIn9, mode, in,
1477 screenInfo.screens[i]->root);
1478 if (to == PointerRootWin((WindowPtr)1L)) {
1479 DeviceFocusInEvents(dev, GetCurrentRootWindow(dev), sprite->win,
1480 mode, NotifyPointer5);
1481 DeviceFocusEvent(dev, XI_FocusIn9, mode, NotifyPointer5, sprite->win);
1482 }
1483 }
1484 else {
1485 if ((from == NullWindow((WindowPtr) 0)) || (from == PointerRootWin((WindowPtr)1L))) {
1486 if (from == PointerRootWin((WindowPtr)1L)) {
1487 DeviceFocusEvent(dev, XI_FocusOut10, mode, NotifyPointer5,
1488 sprite->win);
1489 DeviceFocusOutEvents(dev, sprite->win,
1490 GetCurrentRootWindow(dev), mode,
1491 NotifyPointer5);
1492 }
1493 for (i = 0; i < nscreens; i++)
1494 DeviceFocusEvent(dev, XI_FocusOut10, mode, out,
1495 screenInfo.screens[i]->root);
1496 if (to->parent != NullWindow((WindowPtr) 0))
1497 DeviceFocusInEvents(dev, GetCurrentRootWindow(dev), to, mode,
1498 NotifyNonlinearVirtual4);
1499 DeviceFocusEvent(dev, XI_FocusIn9, mode, NotifyNonlinear3, to);
1500 if (IsParent(to, sprite->win))
1501 DeviceFocusInEvents(dev, to, sprite->win, mode, NotifyPointer5);
1502 }
1503 else {
1504 if (IsParent(to, from)) {
1505 DeviceFocusEvent(dev, XI_FocusOut10, mode, NotifyAncestor0, from);
1506 DeviceFocusOutEvents(dev, from, to, mode, NotifyVirtual1);
1507 DeviceFocusEvent(dev, XI_FocusIn9, mode, NotifyInferior2, to);
1508 if ((IsParent(to, sprite->win)) &&
1509 (sprite->win != from) &&
1510 (!IsParent(from, sprite->win)) &&
1511 (!IsParent(sprite->win, from)))
1512 DeviceFocusInEvents(dev, to, sprite->win, mode,
1513 NotifyPointer5);
1514 }
1515 else if (IsParent(from, to)) {
1516 if ((IsParent(from, sprite->win)) &&
1517 (sprite->win != from) &&
1518 (!IsParent(to, sprite->win)) &&
1519 (!IsParent(sprite->win, to))) {
1520 DeviceFocusEvent(dev, XI_FocusOut10, mode, NotifyPointer5,
1521 sprite->win);
1522 DeviceFocusOutEvents(dev, sprite->win, from, mode,
1523 NotifyPointer5);
1524 }
1525 DeviceFocusEvent(dev, XI_FocusOut10, mode, NotifyInferior2, from);
1526 DeviceFocusInEvents(dev, from, to, mode, NotifyVirtual1);
1527 DeviceFocusEvent(dev, XI_FocusIn9, mode, NotifyAncestor0, to);
1528 }
1529 else {
1530 /* neither from or to is child of other */
1531 WindowPtr common = CommonAncestor(to, from);
1532
1533 /* common == NullWindow ==> different screens */
1534 if (IsParent(from, sprite->win))
1535 DeviceFocusOutEvents(dev, sprite->win, from, mode,
1536 NotifyPointer5);
1537 DeviceFocusEvent(dev, XI_FocusOut10, mode, NotifyNonlinear3, from);
1538 if (from->parent != NullWindow((WindowPtr) 0))
1539 DeviceFocusOutEvents(dev, from, common, mode,
1540 NotifyNonlinearVirtual4);
1541 if (to->parent != NullWindow((WindowPtr) 0))
1542 DeviceFocusInEvents(dev, common, to, mode,
1543 NotifyNonlinearVirtual4);
1544 DeviceFocusEvent(dev, XI_FocusIn9, mode, NotifyNonlinear3, to);
1545 if (IsParent(to, sprite->win))
1546 DeviceFocusInEvents(dev, to, sprite->win, mode,
1547 NotifyPointer5);
1548 }
1549 }
1550 }
1551}
1552
1553/**
1554 * Figure out if focus events are necessary and send them to the
1555 * appropriate windows.
1556 *
1557 * @param from Window the focus moved out of.
1558 * @param to Window the focus moved into.
1559 */
1560void
1561DoFocusEvents(DeviceIntPtr pDev, WindowPtr from, WindowPtr to, int mode)
1562{
1563 if (!IsKeyboardDevice(pDev))
1564 return;
1565
1566 if (from == to)
1567 return;
1568
1569 CoreFocusEvents(pDev, from, to, mode);
1570 DeviceFocusEvents(pDev, from, to, mode);
1571}