File: | dix/enterleave.c |
Location: | line 629, column 5 |
Description: | Value stored to 'first' is never read |
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 | |
78 | static WindowPtr PointerWindows[MAXDEVICES40]; |
79 | static WindowPtr FocusWindows[MAXDEVICES40]; |
80 | |
81 | /** |
82 | * Return TRUE if 'win' has a pointer within its boundaries, excluding child |
83 | * window. |
84 | */ |
85 | static BOOL |
86 | HasPointer(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 | */ |
110 | static BOOL |
111 | HasFocus(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 | */ |
125 | static WindowPtr |
126 | PointerWin(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 | */ |
138 | static WindowPtr |
139 | FirstPointerChild(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 | */ |
158 | static WindowPtr |
159 | FirstFocusChild(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 | */ |
175 | void |
176 | EnterWindow(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 | */ |
184 | void |
185 | LeaveWindow(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 | */ |
193 | void |
194 | SetFocusIn(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 | */ |
202 | void |
203 | SetFocusOut(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 | */ |
215 | static WindowPtr |
216 | CommonAncestor(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 | */ |
229 | static void |
230 | DeviceEnterNotifies(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 | */ |
248 | static void |
249 | CoreEnterNotifies(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 | |
282 | static void |
283 | CoreLeaveNotifies(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 | */ |
326 | static void |
327 | DeviceLeaveNotifies(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 | */ |
346 | static void |
347 | CoreEnterLeaveNonLinear(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 | */ |
430 | static void |
431 | CoreEnterLeaveToAncestor(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 | */ |
486 | static void |
487 | CoreEnterLeaveToDescendant(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 | |
537 | static void |
538 | CoreEnterLeaveEvents(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 | |
555 | static void |
556 | DeviceEnterLeaveEvents(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 | */ |
595 | void |
596 | DoEnterLeaveEvents(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 | |
610 | static void |
611 | FixDeviceValuator(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 | |
632 | static void |
633 | FixDeviceStateNotify(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 | |
674 | static void |
675 | DeliverStateNotifyEvent(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 | |
776 | void |
777 | DeviceFocusEvent(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 | */ |
852 | static void |
853 | DeviceFocusOutEvents(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 | */ |
869 | static void |
870 | DeviceFocusInEvents(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 | */ |
886 | static void |
887 | CoreFocusInEvents(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 | |
918 | static void |
919 | CoreFocusOutEvents(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 | */ |
965 | static void |
966 | CoreFocusOutNotifyPointerEvents(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 | */ |
994 | static void |
995 | CoreFocusInRecurse(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 | */ |
1014 | static void |
1015 | CoreFocusInNotifyPointerEvents(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 | */ |
1036 | static void |
1037 | CoreFocusNonLinear(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 | */ |
1126 | static void |
1127 | CoreFocusToAncestor(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 | */ |
1183 | static void |
1184 | CoreFocusToDescendant(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 | |
1236 | static BOOL |
1237 | HasOtherPointer(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 | */ |
1252 | static void |
1253 | CoreFocusPointerRootNoneSwitch(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 | */ |
1297 | static void |
1298 | CoreFocusToPointerRootOrNone(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 | */ |
1344 | static void |
1345 | CoreFocusFromPointerRootOrNone(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 | |
1403 | static void |
1404 | CoreFocusEvents(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 | |
1428 | static void |
1429 | DeviceFocusEvents(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 | */ |
1560 | void |
1561 | DoFocusEvents(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 | } |