enterleave.c revision 7e31ba66
1/* 2 * Copyright © 2008 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 * 23 * Authors: Peter Hutterer 24 * 25 */ 26 27#ifdef HAVE_DIX_CONFIG_H 28#include <dix-config.h> 29#endif 30 31#include <X11/X.h> 32#include <X11/extensions/XI2.h> 33#include <X11/extensions/XIproto.h> 34#include <X11/extensions/XI2proto.h> 35#include "inputstr.h" 36#include "windowstr.h" 37#include "scrnintstr.h" 38#include "exglobals.h" 39#include "enterleave.h" 40#include "eventconvert.h" 41#include "xkbsrv.h" 42#include "inpututils.h" 43 44/** 45 * @file 46 * This file describes the model for sending core enter/leave events and 47 * focus in/out in the case of multiple pointers/keyboard foci. 48 * 49 * Since we can't send more than one Enter or Leave/Focus in or out event per 50 * window to a core client without confusing it, this is a rather complicated 51 * approach. 52 * 53 * For a full description of the enter/leave model from a window's 54 * perspective, see 55 * http://lists.freedesktop.org/archives/xorg/2008-August/037606.html 56 * 57 * For a full description of the focus in/out model from a window's 58 * perspective, see 59 * http://lists.freedesktop.org/archives/xorg/2008-December/041740.html 60 * 61 * Additional notes: 62 * - The core protocol spec says that "In a LeaveNotify event, if a child of the 63 * event window contains the initial position of the pointer, then the child 64 * component is set to that child. Otherwise, it is None. For an EnterNotify 65 * event, if a child of the event window contains the final pointer position, 66 * then the child component is set to that child. Otherwise, it is None." 67 * 68 * By inference, this means that only NotifyVirtual or NotifyNonlinearVirtual 69 * events may have a subwindow set to other than None. 70 * 71 * - NotifyPointer events may be sent if the focus changes from window A to 72 * B. The assumption used in this model is that NotifyPointer events are only 73 * sent for the pointer paired with the keyboard that is involved in the focus 74 * events. For example, if F(W) changes because of keyboard 2, then 75 * NotifyPointer events are only sent for pointer 2. 76 */ 77 78static WindowPtr PointerWindows[MAXDEVICES]; 79static WindowPtr FocusWindows[MAXDEVICES]; 80 81/** 82 * Return TRUE if 'win' has a pointer within its boundaries, excluding child 83 * window. 84 */ 85static BOOL 86HasPointer(DeviceIntPtr dev, WindowPtr win) 87{ 88 int i; 89 90 /* FIXME: The enter/leave model does not cater for grabbed devices. For 91 * now, a quickfix: if the device about to send an enter/leave event to 92 * a window is grabbed, assume there is no pointer in that window. 93 * Fixes fdo 27804. 94 * There isn't enough beer in my fridge to fix this properly. 95 */ 96 if (dev->deviceGrab.grab) 97 return FALSE; 98 99 for (i = 0; i < MAXDEVICES; i++) 100 if (PointerWindows[i] == win) 101 return TRUE; 102 103 return FALSE; 104} 105 106/** 107 * Return TRUE if at least one keyboard focus is set to 'win' (excluding 108 * descendants of win). 109 */ 110static BOOL 111HasFocus(WindowPtr win) 112{ 113 int i; 114 115 for (i = 0; i < MAXDEVICES; i++) 116 if (FocusWindows[i] == win) 117 return TRUE; 118 119 return FALSE; 120} 121 122/** 123 * Return the window the device dev is currently on. 124 */ 125static WindowPtr 126PointerWin(DeviceIntPtr dev) 127{ 128 return PointerWindows[dev->id]; 129} 130 131/** 132 * Search for the first window below 'win' that has a pointer directly within 133 * it's boundaries (excluding boundaries of its own descendants). 134 * 135 * @return The child window that has the pointer within its boundaries or 136 * NULL. 137 */ 138static WindowPtr 139FirstPointerChild(WindowPtr win) 140{ 141 int i; 142 143 for (i = 0; i < MAXDEVICES; i++) { 144 if (PointerWindows[i] && IsParent(win, PointerWindows[i])) 145 return PointerWindows[i]; 146 } 147 148 return NULL; 149} 150 151/** 152 * Search for the first window below 'win' that has a focus directly within 153 * it's boundaries (excluding boundaries of its own descendants). 154 * 155 * @return The child window that has the pointer within its boundaries or 156 * NULL. 157 */ 158static WindowPtr 159FirstFocusChild(WindowPtr win) 160{ 161 int i; 162 163 for (i = 0; i < MAXDEVICES; i++) { 164 if (FocusWindows[i] && FocusWindows[i] != PointerRootWin && 165 IsParent(win, FocusWindows[i])) 166 return FocusWindows[i]; 167 } 168 169 return NULL; 170} 171 172/** 173 * Set the presence flag for dev to mark that it is now in 'win'. 174 */ 175void 176EnterWindow(DeviceIntPtr dev, WindowPtr win, int mode) 177{ 178 PointerWindows[dev->id] = win; 179} 180 181/** 182 * Unset the presence flag for dev to mark that it is not in 'win' anymore. 183 */ 184void 185LeaveWindow(DeviceIntPtr dev) 186{ 187 PointerWindows[dev->id] = NULL; 188} 189 190/** 191 * Set the presence flag for dev to mark that it is now in 'win'. 192 */ 193void 194SetFocusIn(DeviceIntPtr dev, WindowPtr win) 195{ 196 FocusWindows[dev->id] = win; 197} 198 199/** 200 * Unset the presence flag for dev to mark that it is not in 'win' anymore. 201 */ 202void 203SetFocusOut(DeviceIntPtr dev) 204{ 205 FocusWindows[dev->id] = NULL; 206} 207 208/** 209 * Return the common ancestor of 'a' and 'b' (if one exists). 210 * @param a A window with the same ancestor as b. 211 * @param b A window with the same ancestor as a. 212 * @return The window that is the first ancestor of both 'a' and 'b', or the 213 * NullWindow if they do not have a common ancestor. 214 */ 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; 222} 223 224/** 225 * Send enter notifies to all windows between 'ancestor' and 'child' (excluding 226 * both). Events are sent running up the window hierarchy. This function 227 * recurses. 228 */ 229static void 230DeviceEnterNotifies(DeviceIntPtr dev, 231 int sourceid, 232 WindowPtr ancestor, WindowPtr child, int mode, int detail) 233{ 234 WindowPtr parent = child->parent; 235 236 if (ancestor == parent) 237 return; 238 DeviceEnterNotifies(dev, sourceid, ancestor, parent, mode, detail); 239 DeviceEnterLeaveEvent(dev, sourceid, XI_Enter, mode, detail, parent, 240 child->drawable.id); 241} 242 243/** 244 * Send enter notifies to all windows between 'ancestor' and 'child' (excluding 245 * both). Events are sent running down the window hierarchy. This function 246 * recurses. 247 */ 248static void 249CoreEnterNotifies(DeviceIntPtr dev, 250 WindowPtr ancestor, WindowPtr child, int mode, int detail) 251{ 252 WindowPtr parent = child->parent; 253 254 if (ancestor == parent) 255 return; 256 CoreEnterNotifies(dev, ancestor, parent, mode, detail); 257 258 /* Case 3: 259 A is above W, B is a descendant 260 261 Classically: The move generates an EnterNotify on W with a detail of 262 Virtual or NonlinearVirtual 263 264 MPX: 265 Case 3A: There is at least one other pointer on W itself 266 P(W) doesn't change, so the event should be suppressed 267 Case 3B: Otherwise, if there is at least one other pointer in a 268 descendant 269 P(W) stays on the same descendant, or changes to a different 270 descendant. The event should be suppressed. 271 Case 3C: Otherwise: 272 P(W) moves from a window above W to a descendant. The subwindow 273 field is set to the child containing the descendant. The detail 274 may need to be changed from Virtual to NonlinearVirtual depending 275 on the previous P(W). */ 276 277 if (!HasPointer(dev, parent) && !FirstPointerChild(parent)) 278 CoreEnterLeaveEvent(dev, EnterNotify, mode, detail, parent, 279 child->drawable.id); 280} 281 282static void 283CoreLeaveNotifies(DeviceIntPtr dev, 284 WindowPtr child, WindowPtr ancestor, int mode, int detail) 285{ 286 WindowPtr win; 287 288 if (ancestor == child) 289 return; 290 291 for (win = child->parent; win != ancestor; win = win->parent) { 292 /*Case 7: 293 A is a descendant of W, B is above W 294 295 Classically: A LeaveNotify is generated on W with a detail of Virtual 296 or NonlinearVirtual. 297 298 MPX: 299 Case 3A: There is at least one other pointer on W itself 300 P(W) doesn't change, the event should be suppressed. 301 Case 3B: Otherwise, if there is at least one other pointer in a 302 descendant 303 P(W) stays on the same descendant, or changes to a different 304 descendant. The event should be suppressed. 305 Case 3C: Otherwise: 306 P(W) changes from the descendant of W to a window above W. 307 The detail may need to be changed from Virtual to NonlinearVirtual 308 or vice-versa depending on the new P(W). */ 309 310 /* If one window has a pointer or a child with a pointer, skip some 311 * work and exit. */ 312 if (HasPointer(dev, win) || FirstPointerChild(win)) 313 return; 314 315 CoreEnterLeaveEvent(dev, LeaveNotify, mode, detail, win, 316 child->drawable.id); 317 318 child = win; 319 } 320} 321 322/** 323 * Send leave notifies to all windows between 'child' and 'ancestor'. 324 * Events are sent running up the hierarchy. 325 */ 326static void 327DeviceLeaveNotifies(DeviceIntPtr dev, 328 int sourceid, 329 WindowPtr child, WindowPtr ancestor, int mode, int detail) 330{ 331 WindowPtr win; 332 333 if (ancestor == child) 334 return; 335 for (win = child->parent; win != ancestor; win = win->parent) { 336 DeviceEnterLeaveEvent(dev, sourceid, XI_Leave, mode, detail, win, 337 child->drawable.id); 338 child = win; 339 } 340} 341 342/** 343 * Pointer dev moves from A to B and A neither a descendant of B nor is 344 * B a descendant of A. 345 */ 346static void 347CoreEnterLeaveNonLinear(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode) 348{ 349 WindowPtr X = CommonAncestor(A, B); 350 351 /* Case 4: 352 A is W, B is above W 353 354 Classically: The move generates a LeaveNotify on W with a detail of 355 Ancestor or Nonlinear 356 357 MPX: 358 Case 3A: There is at least one other pointer on W itself 359 P(W) doesn't change, the event should be suppressed 360 Case 3B: Otherwise, if there is at least one other pointer in a 361 descendant of W 362 P(W) changes from W to a descendant of W. The subwindow field 363 is set to the child containing the new P(W), the detail field 364 is set to Inferior 365 Case 3C: Otherwise: 366 The pointer window moves from W to a window above W. 367 The detail may need to be changed from Ancestor to Nonlinear or 368 vice versa depending on the the new P(W) 369 */ 370 371 if (!HasPointer(dev, A)) { 372 WindowPtr child = FirstPointerChild(A); 373 374 if (child) 375 CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyInferior, A, 376 None); 377 else 378 CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyNonlinear, A, 379 None); 380 } 381 382 CoreLeaveNotifies(dev, A, X, mode, NotifyNonlinearVirtual); 383 384 /* 385 Case 9: 386 A is a descendant of W, B is a descendant of W 387 388 Classically: No events are generated on W 389 MPX: The pointer window stays the same or moves to a different 390 descendant of W. No events should be generated on W. 391 392 Therefore, no event to X. 393 */ 394 395 CoreEnterNotifies(dev, X, B, mode, NotifyNonlinearVirtual); 396 397 /* Case 2: 398 A is above W, B=W 399 400 Classically: The move generates an EnterNotify on W with a detail of 401 Ancestor or Nonlinear 402 403 MPX: 404 Case 2A: There is at least one other pointer on W itself 405 P(W) doesn't change, so the event should be suppressed 406 Case 2B: Otherwise, if there is at least one other pointer in a 407 descendant 408 P(W) moves from a descendant to W. detail is changed to Inferior, 409 subwindow is set to the child containing the previous P(W) 410 Case 2C: Otherwise: 411 P(W) changes from a window above W to W itself. 412 The detail may need to be changed from Ancestor to Nonlinear 413 or vice-versa depending on the previous P(W). */ 414 415 if (!HasPointer(dev, B)) { 416 WindowPtr child = FirstPointerChild(B); 417 418 if (child) 419 CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyInferior, B, 420 None); 421 else 422 CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyNonlinear, B, 423 None); 424 } 425} 426 427/** 428 * Pointer dev moves from A to B and A is a descendant of B. 429 */ 430static void 431CoreEnterLeaveToAncestor(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode) 432{ 433 /* Case 4: 434 A is W, B is above W 435 436 Classically: The move generates a LeaveNotify on W with a detail of 437 Ancestor or Nonlinear 438 439 MPX: 440 Case 3A: There is at least one other pointer on W itself 441 P(W) doesn't change, the event should be suppressed 442 Case 3B: Otherwise, if there is at least one other pointer in a 443 descendant of W 444 P(W) changes from W to a descendant of W. The subwindow field 445 is set to the child containing the new P(W), the detail field 446 is set to Inferior 447 Case 3C: Otherwise: 448 The pointer window moves from W to a window above W. 449 The detail may need to be changed from Ancestor to Nonlinear or 450 vice versa depending on the the new P(W) 451 */ 452 if (!HasPointer(dev, A)) { 453 WindowPtr child = FirstPointerChild(A); 454 455 if (child) 456 CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyInferior, A, 457 None); 458 else 459 CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyAncestor, A, 460 None); 461 } 462 463 CoreLeaveNotifies(dev, A, B, mode, NotifyVirtual); 464 465 /* Case 8: 466 A is a descendant of W, B is W 467 468 Classically: A EnterNotify is generated on W with a detail of 469 NotifyInferior 470 471 MPX: 472 Case 3A: There is at least one other pointer on W itself 473 P(W) doesn't change, the event should be suppressed 474 Case 3B: Otherwise: 475 P(W) changes from a descendant to W itself. The subwindow 476 field should be set to the child containing the old P(W) <<< WRONG */ 477 478 if (!HasPointer(dev, B)) 479 CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyInferior, B, None); 480 481} 482 483/** 484 * Pointer dev moves from A to B and B is a descendant of A. 485 */ 486static void 487CoreEnterLeaveToDescendant(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode) 488{ 489 /* Case 6: 490 A is W, B is a descendant of W 491 492 Classically: A LeaveNotify is generated on W with a detail of 493 NotifyInferior 494 495 MPX: 496 Case 3A: There is at least one other pointer on W itself 497 P(W) doesn't change, the event should be suppressed 498 Case 3B: Otherwise: 499 P(W) changes from W to a descendant of W. The subwindow field 500 is set to the child containing the new P(W) <<< THIS IS WRONG */ 501 502 if (!HasPointer(dev, A)) 503 CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyInferior, A, None); 504 505 CoreEnterNotifies(dev, A, B, mode, NotifyVirtual); 506 507 /* Case 2: 508 A is above W, B=W 509 510 Classically: The move generates an EnterNotify on W with a detail of 511 Ancestor or Nonlinear 512 513 MPX: 514 Case 2A: There is at least one other pointer on W itself 515 P(W) doesn't change, so the event should be suppressed 516 Case 2B: Otherwise, if there is at least one other pointer in a 517 descendant 518 P(W) moves from a descendant to W. detail is changed to Inferior, 519 subwindow is set to the child containing the previous P(W) 520 Case 2C: Otherwise: 521 P(W) changes from a window above W to W itself. 522 The detail may need to be changed from Ancestor to Nonlinear 523 or vice-versa depending on the previous P(W). */ 524 525 if (!HasPointer(dev, B)) { 526 WindowPtr child = FirstPointerChild(B); 527 528 if (child) 529 CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyInferior, B, 530 None); 531 else 532 CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyAncestor, B, 533 None); 534 } 535} 536 537static void 538CoreEnterLeaveEvents(DeviceIntPtr dev, WindowPtr from, WindowPtr to, int mode) 539{ 540 if (!IsMaster(dev)) 541 return; 542 543 LeaveWindow(dev); 544 545 if (IsParent(from, to)) 546 CoreEnterLeaveToDescendant(dev, from, to, mode); 547 else if (IsParent(to, from)) 548 CoreEnterLeaveToAncestor(dev, from, to, mode); 549 else 550 CoreEnterLeaveNonLinear(dev, from, to, mode); 551 552 EnterWindow(dev, to, mode); 553} 554 555static void 556DeviceEnterLeaveEvents(DeviceIntPtr dev, 557 int sourceid, WindowPtr from, WindowPtr to, int mode) 558{ 559 if (IsParent(from, to)) { 560 DeviceEnterLeaveEvent(dev, sourceid, XI_Leave, mode, NotifyInferior, 561 from, None); 562 DeviceEnterNotifies(dev, sourceid, from, to, mode, NotifyVirtual); 563 DeviceEnterLeaveEvent(dev, sourceid, XI_Enter, mode, NotifyAncestor, to, 564 None); 565 } 566 else if (IsParent(to, from)) { 567 DeviceEnterLeaveEvent(dev, sourceid, XI_Leave, mode, NotifyAncestor, 568 from, None); 569 DeviceLeaveNotifies(dev, sourceid, from, to, mode, NotifyVirtual); 570 DeviceEnterLeaveEvent(dev, sourceid, XI_Enter, mode, NotifyInferior, to, 571 None); 572 } 573 else { /* neither from nor to is descendent of the other */ 574 WindowPtr common = CommonAncestor(to, from); 575 576 /* common == NullWindow ==> different screens */ 577 DeviceEnterLeaveEvent(dev, sourceid, XI_Leave, mode, NotifyNonlinear, 578 from, None); 579 DeviceLeaveNotifies(dev, sourceid, from, common, mode, 580 NotifyNonlinearVirtual); 581 DeviceEnterNotifies(dev, sourceid, common, to, mode, 582 NotifyNonlinearVirtual); 583 DeviceEnterLeaveEvent(dev, sourceid, XI_Enter, mode, NotifyNonlinear, 584 to, None); 585 } 586} 587 588/** 589 * Figure out if enter/leave events are necessary and send them to the 590 * appropriate windows. 591 * 592 * @param fromWin Window the sprite moved out of. 593 * @param toWin Window the sprite moved into. 594 */ 595void 596DoEnterLeaveEvents(DeviceIntPtr pDev, 597 int sourceid, WindowPtr fromWin, WindowPtr toWin, int mode) 598{ 599 if (!IsPointerDevice(pDev)) 600 return; 601 602 if (fromWin == toWin) 603 return; 604 605 if (mode != XINotifyPassiveGrab && mode != XINotifyPassiveUngrab) 606 CoreEnterLeaveEvents(pDev, fromWin, toWin, mode); 607 DeviceEnterLeaveEvents(pDev, sourceid, fromWin, toWin, mode); 608} 609 610static void 611FixDeviceValuator(DeviceIntPtr dev, deviceValuator * ev, ValuatorClassPtr v, 612 int first) 613{ 614 int nval = v->numAxes - first; 615 616 ev->type = DeviceValuator; 617 ev->deviceid = dev->id; 618 ev->num_valuators = nval < 3 ? nval : 3; 619 ev->first_valuator = first; 620 switch (ev->num_valuators) { 621 case 3: 622 ev->valuator2 = v->axisVal[first + 2]; 623 case 2: 624 ev->valuator1 = v->axisVal[first + 1]; 625 case 1: 626 ev->valuator0 = v->axisVal[first]; 627 break; 628 } 629 first += ev->num_valuators; 630} 631 632static void 633FixDeviceStateNotify(DeviceIntPtr dev, deviceStateNotify * ev, KeyClassPtr k, 634 ButtonClassPtr b, ValuatorClassPtr v, int first) 635{ 636 ev->type = DeviceStateNotify; 637 ev->deviceid = dev->id; 638 ev->time = currentTime.milliseconds; 639 ev->classes_reported = 0; 640 ev->num_keys = 0; 641 ev->num_buttons = 0; 642 ev->num_valuators = 0; 643 644 if (b) { 645 ev->classes_reported |= (1 << ButtonClass); 646 ev->num_buttons = b->numButtons; 647 memcpy((char *) ev->buttons, (char *) b->down, 4); 648 } 649 else if (k) { 650 ev->classes_reported |= (1 << KeyClass); 651 ev->num_keys = k->xkbInfo->desc->max_key_code - 652 k->xkbInfo->desc->min_key_code; 653 memmove((char *) &ev->keys[0], (char *) k->down, 4); 654 } 655 if (v) { 656 int nval = v->numAxes - first; 657 658 ev->classes_reported |= (1 << ValuatorClass); 659 ev->classes_reported |= valuator_get_mode(dev, 0) << ModeBitsShift; 660 ev->num_valuators = nval < 3 ? nval : 3; 661 switch (ev->num_valuators) { 662 case 3: 663 ev->valuator2 = v->axisVal[first + 2]; 664 case 2: 665 ev->valuator1 = v->axisVal[first + 1]; 666 case 1: 667 ev->valuator0 = v->axisVal[first]; 668 break; 669 } 670 } 671} 672 673 674static void 675DeliverStateNotifyEvent(DeviceIntPtr dev, WindowPtr win) 676{ 677 int evcount = 1; 678 deviceStateNotify *ev, *sev; 679 deviceKeyStateNotify *kev; 680 deviceButtonStateNotify *bev; 681 682 KeyClassPtr k; 683 ButtonClassPtr b; 684 ValuatorClassPtr v; 685 int nval = 0, nkeys = 0, nbuttons = 0, first = 0; 686 687 if (!(wOtherInputMasks(win)) || 688 !(wOtherInputMasks(win)->inputEvents[dev->id] & DeviceStateNotifyMask)) 689 return; 690 691 if ((b = dev->button) != NULL) { 692 nbuttons = b->numButtons; 693 if (nbuttons > 32) 694 evcount++; 695 } 696 if ((k = dev->key) != NULL) { 697 nkeys = k->xkbInfo->desc->max_key_code - k->xkbInfo->desc->min_key_code; 698 if (nkeys > 32) 699 evcount++; 700 if (nbuttons > 0) { 701 evcount++; 702 } 703 } 704 if ((v = dev->valuator) != NULL) { 705 nval = v->numAxes; 706 707 if (nval > 3) 708 evcount++; 709 if (nval > 6) { 710 if (!(k && b)) 711 evcount++; 712 if (nval > 9) 713 evcount += ((nval - 7) / 3); 714 } 715 } 716 717 sev = ev = xallocarray(evcount, sizeof(xEvent)); 718 FixDeviceStateNotify(dev, ev, NULL, NULL, NULL, first); 719 720 if (b != NULL) { 721 FixDeviceStateNotify(dev, ev++, NULL, b, v, first); 722 first += 3; 723 nval -= 3; 724 if (nbuttons > 32) { 725 (ev - 1)->deviceid |= MORE_EVENTS; 726 bev = (deviceButtonStateNotify *) ev++; 727 bev->type = DeviceButtonStateNotify; 728 bev->deviceid = dev->id; 729 memcpy((char *) &bev->buttons[4], (char *) &b->down[4], 730 DOWN_LENGTH - 4); 731 } 732 if (nval > 0) { 733 (ev - 1)->deviceid |= MORE_EVENTS; 734 FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); 735 first += 3; 736 nval -= 3; 737 } 738 } 739 740 if (k != NULL) { 741 FixDeviceStateNotify(dev, ev++, k, NULL, v, first); 742 first += 3; 743 nval -= 3; 744 if (nkeys > 32) { 745 (ev - 1)->deviceid |= MORE_EVENTS; 746 kev = (deviceKeyStateNotify *) ev++; 747 kev->type = DeviceKeyStateNotify; 748 kev->deviceid = dev->id; 749 memmove((char *) &kev->keys[0], (char *) &k->down[4], 28); 750 } 751 if (nval > 0) { 752 (ev - 1)->deviceid |= MORE_EVENTS; 753 FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); 754 first += 3; 755 nval -= 3; 756 } 757 } 758 759 while (nval > 0) { 760 FixDeviceStateNotify(dev, ev++, NULL, NULL, v, first); 761 first += 3; 762 nval -= 3; 763 if (nval > 0) { 764 (ev - 1)->deviceid |= MORE_EVENTS; 765 FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); 766 first += 3; 767 nval -= 3; 768 } 769 } 770 771 DeliverEventsToWindow(dev, win, (xEvent *) sev, evcount, 772 DeviceStateNotifyMask, NullGrab); 773 free(sev); 774} 775 776void 777DeviceFocusEvent(DeviceIntPtr dev, int type, int mode, int detail, 778 WindowPtr pWin) 779{ 780 deviceFocus event; 781 xXIFocusInEvent *xi2event; 782 DeviceIntPtr mouse; 783 int btlen, len, i; 784 785 mouse = IsFloating(dev) ? dev : GetMaster(dev, MASTER_POINTER); 786 787 /* XI 2 event */ 788 btlen = (mouse->button) ? bits_to_bytes(mouse->button->numButtons) : 0; 789 btlen = bytes_to_int32(btlen); 790 len = sizeof(xXIFocusInEvent) + btlen * 4; 791 792 xi2event = calloc(1, len); 793 xi2event->type = GenericEvent; 794 xi2event->extension = IReqCode; 795 xi2event->evtype = type; 796 xi2event->length = bytes_to_int32(len - sizeof(xEvent)); 797 xi2event->buttons_len = btlen; 798 xi2event->detail = detail; 799 xi2event->time = currentTime.milliseconds; 800 xi2event->deviceid = dev->id; 801 xi2event->sourceid = dev->id; /* a device doesn't change focus by itself */ 802 xi2event->mode = mode; 803 xi2event->root_x = double_to_fp1616(mouse->spriteInfo->sprite->hot.x); 804 xi2event->root_y = double_to_fp1616(mouse->spriteInfo->sprite->hot.y); 805 806 for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++) 807 if (BitIsOn(mouse->button->down, i)) 808 SetBit(&xi2event[1], mouse->button->map[i]); 809 810 if (dev->key) { 811 xi2event->mods.base_mods = dev->key->xkbInfo->state.base_mods; 812 xi2event->mods.latched_mods = dev->key->xkbInfo->state.latched_mods; 813 xi2event->mods.locked_mods = dev->key->xkbInfo->state.locked_mods; 814 xi2event->mods.effective_mods = dev->key->xkbInfo->state.mods; 815 816 xi2event->group.base_group = dev->key->xkbInfo->state.base_group; 817 xi2event->group.latched_group = dev->key->xkbInfo->state.latched_group; 818 xi2event->group.locked_group = dev->key->xkbInfo->state.locked_group; 819 xi2event->group.effective_group = dev->key->xkbInfo->state.group; 820 } 821 822 FixUpEventFromWindow(dev->spriteInfo->sprite, (xEvent *) xi2event, pWin, 823 None, FALSE); 824 825 DeliverEventsToWindow(dev, pWin, (xEvent *) xi2event, 1, 826 GetEventFilter(dev, (xEvent *) xi2event), NullGrab); 827 828 free(xi2event); 829 830 /* XI 1.x event */ 831 event = (deviceFocus) { 832 .deviceid = dev->id, 833 .mode = mode, 834 .type = (type == XI_FocusIn) ? DeviceFocusIn : DeviceFocusOut, 835 .detail = detail, 836 .window = pWin->drawable.id, 837 .time = currentTime.milliseconds 838 }; 839 840 DeliverEventsToWindow(dev, pWin, (xEvent *) &event, 1, 841 DeviceFocusChangeMask, NullGrab); 842 843 if (event.type == DeviceFocusIn) 844 DeliverStateNotifyEvent(dev, pWin); 845} 846 847/** 848 * Send focus out events to all windows between 'child' and 'ancestor'. 849 * Events are sent running up the hierarchy. 850 */ 851static void 852DeviceFocusOutEvents(DeviceIntPtr dev, 853 WindowPtr child, WindowPtr ancestor, int mode, int detail) 854{ 855 WindowPtr win; 856 857 if (ancestor == child) 858 return; 859 for (win = child->parent; win != ancestor; win = win->parent) 860 DeviceFocusEvent(dev, XI_FocusOut, mode, detail, win); 861} 862 863/** 864 * Send enter notifies to all windows between 'ancestor' and 'child' (excluding 865 * both). Events are sent running up the window hierarchy. This function 866 * recurses. 867 */ 868static void 869DeviceFocusInEvents(DeviceIntPtr dev, 870 WindowPtr ancestor, WindowPtr child, int mode, int detail) 871{ 872 WindowPtr parent = child->parent; 873 874 if (ancestor == parent || !parent) 875 return; 876 DeviceFocusInEvents(dev, ancestor, parent, mode, detail); 877 DeviceFocusEvent(dev, XI_FocusIn, mode, detail, parent); 878} 879 880/** 881 * Send FocusIn events to all windows between 'ancestor' and 'child' (excluding 882 * both). Events are sent running down the window hierarchy. This function 883 * recurses. 884 */ 885static void 886CoreFocusInEvents(DeviceIntPtr dev, 887 WindowPtr ancestor, WindowPtr child, int mode, int detail) 888{ 889 WindowPtr parent = child->parent; 890 891 if (ancestor == parent) 892 return; 893 CoreFocusInEvents(dev, ancestor, parent, mode, detail); 894 895 /* Case 3: 896 A is above W, B is a descendant 897 898 Classically: The move generates an FocusIn on W with a detail of 899 Virtual or NonlinearVirtual 900 901 MPX: 902 Case 3A: There is at least one other focus on W itself 903 F(W) doesn't change, so the event should be suppressed 904 Case 3B: Otherwise, if there is at least one other focus in a 905 descendant 906 F(W) stays on the same descendant, or changes to a different 907 descendant. The event should be suppressed. 908 Case 3C: Otherwise: 909 F(W) moves from a window above W to a descendant. The detail may 910 need to be changed from Virtual to NonlinearVirtual depending 911 on the previous F(W). */ 912 913 if (!HasFocus(parent) && !FirstFocusChild(parent)) 914 CoreFocusEvent(dev, FocusIn, mode, detail, parent); 915} 916 917static void 918CoreFocusOutEvents(DeviceIntPtr dev, 919 WindowPtr child, WindowPtr ancestor, int mode, int detail) 920{ 921 WindowPtr win; 922 923 if (ancestor == child) 924 return; 925 926 for (win = child->parent; win != ancestor; win = win->parent) { 927 /*Case 7: 928 A is a descendant of W, B is above W 929 930 Classically: A FocusOut is generated on W with a detail of Virtual 931 or NonlinearVirtual. 932 933 MPX: 934 Case 3A: There is at least one other focus on W itself 935 F(W) doesn't change, the event should be suppressed. 936 Case 3B: Otherwise, if there is at least one other focus in a 937 descendant 938 F(W) stays on the same descendant, or changes to a different 939 descendant. The event should be suppressed. 940 Case 3C: Otherwise: 941 F(W) changes from the descendant of W to a window above W. 942 The detail may need to be changed from Virtual to NonlinearVirtual 943 or vice-versa depending on the new P(W). */ 944 945 /* If one window has a focus or a child with a focuspointer, skip some 946 * work and exit. */ 947 if (HasFocus(win) || FirstFocusChild(win)) 948 return; 949 950 CoreFocusEvent(dev, FocusOut, mode, detail, win); 951 } 952} 953 954/** 955 * Send FocusOut(NotifyPointer) events from the current pointer window (which 956 * is a descendant of pwin_parent) up to (excluding) pwin_parent. 957 * 958 * NotifyPointer events are only sent for the device paired with dev. 959 * 960 * If the current pointer window is a descendant of 'exclude' or an ancestor of 961 * 'exclude', no events are sent. If the current pointer IS 'exclude', events 962 * are sent! 963 */ 964static void 965CoreFocusOutNotifyPointerEvents(DeviceIntPtr dev, 966 WindowPtr pwin_parent, 967 WindowPtr exclude, int mode, int inclusive) 968{ 969 WindowPtr P, stopAt; 970 971 P = PointerWin(GetMaster(dev, POINTER_OR_FLOAT)); 972 973 if (!P) 974 return; 975 if (!IsParent(pwin_parent, P)) 976 if (!(pwin_parent == P && inclusive)) 977 return; 978 979 if (exclude != None && exclude != PointerRootWin && 980 (IsParent(exclude, P) || IsParent(P, exclude))) 981 return; 982 983 stopAt = (inclusive) ? pwin_parent->parent : pwin_parent; 984 985 for (; P && P != stopAt; P = P->parent) 986 CoreFocusEvent(dev, FocusOut, mode, NotifyPointer, P); 987} 988 989/** 990 * DO NOT CALL DIRECTLY. 991 * Recursion helper for CoreFocusInNotifyPointerEvents. 992 */ 993static void 994CoreFocusInRecurse(DeviceIntPtr dev, 995 WindowPtr win, WindowPtr stopAt, int mode, int inclusive) 996{ 997 if ((!inclusive && win == stopAt) || !win) 998 return; 999 1000 CoreFocusInRecurse(dev, win->parent, stopAt, mode, inclusive); 1001 CoreFocusEvent(dev, FocusIn, mode, NotifyPointer, win); 1002} 1003 1004/** 1005 * Send FocusIn(NotifyPointer) events from pwin_parent down to 1006 * including the current pointer window (which is a descendant of pwin_parent). 1007 * 1008 * @param pwin The pointer window. 1009 * @param exclude If the pointer window is a child of 'exclude', no events are 1010 * sent. 1011 * @param inclusive If TRUE, pwin_parent will receive the event too. 1012 */ 1013static void 1014CoreFocusInNotifyPointerEvents(DeviceIntPtr dev, 1015 WindowPtr pwin_parent, 1016 WindowPtr exclude, int mode, int inclusive) 1017{ 1018 WindowPtr P; 1019 1020 P = PointerWin(GetMaster(dev, POINTER_OR_FLOAT)); 1021 1022 if (!P || P == exclude || (pwin_parent != P && !IsParent(pwin_parent, P))) 1023 return; 1024 1025 if (exclude != None && (IsParent(exclude, P) || IsParent(P, exclude))) 1026 return; 1027 1028 CoreFocusInRecurse(dev, P, pwin_parent, mode, inclusive); 1029} 1030 1031/** 1032 * Focus of dev moves from A to B and A neither a descendant of B nor is 1033 * B a descendant of A. 1034 */ 1035static void 1036CoreFocusNonLinear(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode) 1037{ 1038 WindowPtr X = CommonAncestor(A, B); 1039 1040 /* Case 4: 1041 A is W, B is above W 1042 1043 Classically: The change generates a FocusOut on W with a detail of 1044 Ancestor or Nonlinear 1045 1046 MPX: 1047 Case 3A: There is at least one other focus on W itself 1048 F(W) doesn't change, the event should be suppressed 1049 Case 3B: Otherwise, if there is at least one other focus in a 1050 descendant of W 1051 F(W) changes from W to a descendant of W. The detail field 1052 is set to Inferior 1053 Case 3C: Otherwise: 1054 The focus window moves from W to a window above W. 1055 The detail may need to be changed from Ancestor to Nonlinear or 1056 vice versa depending on the the new F(W) 1057 */ 1058 1059 if (!HasFocus(A)) { 1060 WindowPtr child = FirstFocusChild(A); 1061 1062 if (child) { 1063 /* NotifyPointer P-A unless P is child or below */ 1064 CoreFocusOutNotifyPointerEvents(dev, A, child, mode, FALSE); 1065 CoreFocusEvent(dev, FocusOut, mode, NotifyInferior, A); 1066 } 1067 else { 1068 /* NotifyPointer P-A */ 1069 CoreFocusOutNotifyPointerEvents(dev, A, None, mode, FALSE); 1070 CoreFocusEvent(dev, FocusOut, mode, NotifyNonlinear, A); 1071 } 1072 } 1073 1074 CoreFocusOutEvents(dev, A, X, mode, NotifyNonlinearVirtual); 1075 1076 /* 1077 Case 9: 1078 A is a descendant of W, B is a descendant of W 1079 1080 Classically: No events are generated on W 1081 MPX: The focus window stays the same or moves to a different 1082 descendant of W. No events should be generated on W. 1083 1084 Therefore, no event to X. 1085 */ 1086 1087 CoreFocusInEvents(dev, X, B, mode, NotifyNonlinearVirtual); 1088 1089 /* Case 2: 1090 A is above W, B=W 1091 1092 Classically: The move generates an EnterNotify on W with a detail of 1093 Ancestor or Nonlinear 1094 1095 MPX: 1096 Case 2A: There is at least one other focus on W itself 1097 F(W) doesn't change, so the event should be suppressed 1098 Case 2B: Otherwise, if there is at least one other focus in a 1099 descendant 1100 F(W) moves from a descendant to W. detail is changed to Inferior. 1101 Case 2C: Otherwise: 1102 F(W) changes from a window above W to W itself. 1103 The detail may need to be changed from Ancestor to Nonlinear 1104 or vice-versa depending on the previous F(W). */ 1105 1106 if (!HasFocus(B)) { 1107 WindowPtr child = FirstFocusChild(B); 1108 1109 if (child) { 1110 CoreFocusEvent(dev, FocusIn, mode, NotifyInferior, B); 1111 /* NotifyPointer B-P unless P is child or below. */ 1112 CoreFocusInNotifyPointerEvents(dev, B, child, mode, FALSE); 1113 } 1114 else { 1115 CoreFocusEvent(dev, FocusIn, mode, NotifyNonlinear, B); 1116 /* NotifyPointer B-P unless P is child or below. */ 1117 CoreFocusInNotifyPointerEvents(dev, B, None, mode, FALSE); 1118 } 1119 } 1120} 1121 1122/** 1123 * Focus of dev moves from A to B and A is a descendant of B. 1124 */ 1125static void 1126CoreFocusToAncestor(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode) 1127{ 1128 /* Case 4: 1129 A is W, B is above W 1130 1131 Classically: The change generates a FocusOut on W with a detail of 1132 Ancestor or Nonlinear 1133 1134 MPX: 1135 Case 3A: There is at least one other focus on W itself 1136 F(W) doesn't change, the event should be suppressed 1137 Case 3B: Otherwise, if there is at least one other focus in a 1138 descendant of W 1139 F(W) changes from W to a descendant of W. The detail field 1140 is set to Inferior 1141 Case 3C: Otherwise: 1142 The focus window moves from W to a window above W. 1143 The detail may need to be changed from Ancestor to Nonlinear or 1144 vice versa depending on the the new F(W) 1145 */ 1146 if (!HasFocus(A)) { 1147 WindowPtr child = FirstFocusChild(A); 1148 1149 if (child) { 1150 /* NotifyPointer P-A unless P is child or below */ 1151 CoreFocusOutNotifyPointerEvents(dev, A, child, mode, FALSE); 1152 CoreFocusEvent(dev, FocusOut, mode, NotifyInferior, A); 1153 } 1154 else 1155 CoreFocusEvent(dev, FocusOut, mode, NotifyAncestor, A); 1156 } 1157 1158 CoreFocusOutEvents(dev, A, B, mode, NotifyVirtual); 1159 1160 /* Case 8: 1161 A is a descendant of W, B is W 1162 1163 Classically: A FocusOut is generated on W with a detail of 1164 NotifyInferior 1165 1166 MPX: 1167 Case 3A: There is at least one other focus on W itself 1168 F(W) doesn't change, the event should be suppressed 1169 Case 3B: Otherwise: 1170 F(W) changes from a descendant to W itself. */ 1171 1172 if (!HasFocus(B)) { 1173 CoreFocusEvent(dev, FocusIn, mode, NotifyInferior, B); 1174 /* NotifyPointer B-P unless P is A or below. */ 1175 CoreFocusInNotifyPointerEvents(dev, B, A, mode, FALSE); 1176 } 1177} 1178 1179/** 1180 * Focus of dev moves from A to B and B is a descendant of A. 1181 */ 1182static void 1183CoreFocusToDescendant(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode) 1184{ 1185 /* Case 6: 1186 A is W, B is a descendant of W 1187 1188 Classically: A FocusOut is generated on W with a detail of 1189 NotifyInferior 1190 1191 MPX: 1192 Case 3A: There is at least one other focus on W itself 1193 F(W) doesn't change, the event should be suppressed 1194 Case 3B: Otherwise: 1195 F(W) changes from W to a descendant of W. */ 1196 1197 if (!HasFocus(A)) { 1198 /* NotifyPointer P-A unless P is B or below */ 1199 CoreFocusOutNotifyPointerEvents(dev, A, B, mode, FALSE); 1200 CoreFocusEvent(dev, FocusOut, mode, NotifyInferior, A); 1201 } 1202 1203 CoreFocusInEvents(dev, A, B, mode, NotifyVirtual); 1204 1205 /* Case 2: 1206 A is above W, B=W 1207 1208 Classically: The move generates an FocusIn on W with a detail of 1209 Ancestor or Nonlinear 1210 1211 MPX: 1212 Case 2A: There is at least one other focus on W itself 1213 F(W) doesn't change, so the event should be suppressed 1214 Case 2B: Otherwise, if there is at least one other focus in a 1215 descendant 1216 F(W) moves from a descendant to W. detail is changed to Inferior. 1217 Case 2C: Otherwise: 1218 F(W) changes from a window above W to W itself. 1219 The detail may need to be changed from Ancestor to Nonlinear 1220 or vice-versa depending on the previous F(W). */ 1221 1222 if (!HasFocus(B)) { 1223 WindowPtr child = FirstFocusChild(B); 1224 1225 if (child) { 1226 CoreFocusEvent(dev, FocusIn, mode, NotifyInferior, B); 1227 /* NotifyPointer B-P unless P is child or below. */ 1228 CoreFocusInNotifyPointerEvents(dev, B, child, mode, FALSE); 1229 } 1230 else 1231 CoreFocusEvent(dev, FocusIn, mode, NotifyAncestor, B); 1232 } 1233} 1234 1235static BOOL 1236HasOtherPointer(WindowPtr win, DeviceIntPtr exclude) 1237{ 1238 int i; 1239 1240 for (i = 0; i < MAXDEVICES; i++) 1241 if (i != exclude->id && PointerWindows[i] == win) 1242 return TRUE; 1243 1244 return FALSE; 1245} 1246 1247/** 1248 * Focus moves from PointerRoot to None or from None to PointerRoot. 1249 * Assumption: Neither A nor B are valid windows. 1250 */ 1251static void 1252CoreFocusPointerRootNoneSwitch(DeviceIntPtr dev, 1253 WindowPtr A, /* PointerRootWin or NoneWin */ 1254 WindowPtr B, /* NoneWin or PointerRootWin */ 1255 int mode) 1256{ 1257 WindowPtr root; 1258 int i; 1259 int nscreens = screenInfo.numScreens; 1260 1261#ifdef PANORAMIX 1262 if (!noPanoramiXExtension) 1263 nscreens = 1; 1264#endif 1265 1266 for (i = 0; i < nscreens; i++) { 1267 root = screenInfo.screens[i]->root; 1268 if (!HasOtherPointer(root, GetMaster(dev, POINTER_OR_FLOAT)) && 1269 !FirstFocusChild(root)) { 1270 /* If pointer was on PointerRootWin and changes to NoneWin, and 1271 * the pointer paired with dev is below the current root window, 1272 * do a NotifyPointer run. */ 1273 if (dev->focus && dev->focus->win == PointerRootWin && 1274 B != PointerRootWin) { 1275 WindowPtr ptrwin = PointerWin(GetMaster(dev, POINTER_OR_FLOAT)); 1276 1277 if (ptrwin && IsParent(root, ptrwin)) 1278 CoreFocusOutNotifyPointerEvents(dev, root, None, mode, 1279 TRUE); 1280 } 1281 CoreFocusEvent(dev, FocusOut, mode, 1282 A ? NotifyPointerRoot : NotifyDetailNone, root); 1283 CoreFocusEvent(dev, FocusIn, mode, 1284 B ? NotifyPointerRoot : NotifyDetailNone, root); 1285 if (B == PointerRootWin) 1286 CoreFocusInNotifyPointerEvents(dev, root, None, mode, TRUE); 1287 } 1288 1289 } 1290} 1291 1292/** 1293 * Focus moves from window A to PointerRoot or to None. 1294 * Assumption: A is a valid window and not PointerRoot or None. 1295 */ 1296static void 1297CoreFocusToPointerRootOrNone(DeviceIntPtr dev, WindowPtr A, 1298 WindowPtr B, /* PointerRootWin or NoneWin */ 1299 int mode) 1300{ 1301 WindowPtr root; 1302 int i; 1303 int nscreens = screenInfo.numScreens; 1304 1305#ifdef PANORAMIX 1306 if (!noPanoramiXExtension) 1307 nscreens = 1; 1308#endif 1309 1310 if (!HasFocus(A)) { 1311 WindowPtr child = FirstFocusChild(A); 1312 1313 if (child) { 1314 /* NotifyPointer P-A unless P is B or below */ 1315 CoreFocusOutNotifyPointerEvents(dev, A, B, mode, FALSE); 1316 CoreFocusEvent(dev, FocusOut, mode, NotifyInferior, A); 1317 } 1318 else { 1319 /* NotifyPointer P-A */ 1320 CoreFocusOutNotifyPointerEvents(dev, A, None, mode, FALSE); 1321 CoreFocusEvent(dev, FocusOut, mode, NotifyNonlinear, A); 1322 } 1323 } 1324 1325 /* NullWindow means we include the root window */ 1326 CoreFocusOutEvents(dev, A, NullWindow, mode, NotifyNonlinearVirtual); 1327 1328 for (i = 0; i < nscreens; i++) { 1329 root = screenInfo.screens[i]->root; 1330 if (!HasFocus(root) && !FirstFocusChild(root)) { 1331 CoreFocusEvent(dev, FocusIn, mode, 1332 B ? NotifyPointerRoot : NotifyDetailNone, root); 1333 if (B == PointerRootWin) 1334 CoreFocusInNotifyPointerEvents(dev, root, None, mode, TRUE); 1335 } 1336 } 1337} 1338 1339/** 1340 * Focus moves from PointerRoot or None to a window B. 1341 * Assumption: B is a valid window and not PointerRoot or None. 1342 */ 1343static void 1344CoreFocusFromPointerRootOrNone(DeviceIntPtr dev, 1345 WindowPtr A, /* PointerRootWin or NoneWin */ 1346 WindowPtr B, int mode) 1347{ 1348 WindowPtr root; 1349 int i; 1350 int nscreens = screenInfo.numScreens; 1351 1352#ifdef PANORAMIX 1353 if (!noPanoramiXExtension) 1354 nscreens = 1; 1355#endif 1356 1357 for (i = 0; i < nscreens; i++) { 1358 root = screenInfo.screens[i]->root; 1359 if (!HasFocus(root) && !FirstFocusChild(root)) { 1360 /* If pointer was on PointerRootWin and changes to NoneWin, and 1361 * the pointer paired with dev is below the current root window, 1362 * do a NotifyPointer run. */ 1363 if (dev->focus && dev->focus->win == PointerRootWin && 1364 B != PointerRootWin) { 1365 WindowPtr ptrwin = PointerWin(GetMaster(dev, POINTER_OR_FLOAT)); 1366 1367 if (ptrwin) 1368 CoreFocusOutNotifyPointerEvents(dev, root, None, mode, 1369 TRUE); 1370 } 1371 CoreFocusEvent(dev, FocusOut, mode, 1372 A ? NotifyPointerRoot : NotifyDetailNone, root); 1373 } 1374 } 1375 1376 root = B; /* get B's root window */ 1377 while (root->parent) 1378 root = root->parent; 1379 1380 if (B != root) { 1381 CoreFocusEvent(dev, FocusIn, mode, NotifyNonlinearVirtual, root); 1382 CoreFocusInEvents(dev, root, B, mode, NotifyNonlinearVirtual); 1383 } 1384 1385 if (!HasFocus(B)) { 1386 WindowPtr child = FirstFocusChild(B); 1387 1388 if (child) { 1389 CoreFocusEvent(dev, FocusIn, mode, NotifyInferior, B); 1390 /* NotifyPointer B-P unless P is child or below. */ 1391 CoreFocusInNotifyPointerEvents(dev, B, child, mode, FALSE); 1392 } 1393 else { 1394 CoreFocusEvent(dev, FocusIn, mode, NotifyNonlinear, B); 1395 /* NotifyPointer B-P unless P is child or below. */ 1396 CoreFocusInNotifyPointerEvents(dev, B, None, mode, FALSE); 1397 } 1398 } 1399 1400} 1401 1402static void 1403CoreFocusEvents(DeviceIntPtr dev, WindowPtr from, WindowPtr to, int mode) 1404{ 1405 if (!IsMaster(dev)) 1406 return; 1407 1408 SetFocusOut(dev); 1409 1410 if (((to == NullWindow) || (to == PointerRootWin)) && 1411 ((from == NullWindow) || (from == PointerRootWin))) 1412 CoreFocusPointerRootNoneSwitch(dev, from, to, mode); 1413 else if ((to == NullWindow) || (to == PointerRootWin)) 1414 CoreFocusToPointerRootOrNone(dev, from, to, mode); 1415 else if ((from == NullWindow) || (from == PointerRootWin)) 1416 CoreFocusFromPointerRootOrNone(dev, from, to, mode); 1417 else if (IsParent(from, to)) 1418 CoreFocusToDescendant(dev, from, to, mode); 1419 else if (IsParent(to, from)) 1420 CoreFocusToAncestor(dev, from, to, mode); 1421 else 1422 CoreFocusNonLinear(dev, from, to, mode); 1423 1424 SetFocusIn(dev, to); 1425} 1426 1427static void 1428DeviceFocusEvents(DeviceIntPtr dev, WindowPtr from, WindowPtr to, int mode) 1429{ 1430 int out, in; /* for holding details for to/from 1431 PointerRoot/None */ 1432 int i; 1433 int nscreens = screenInfo.numScreens; 1434 SpritePtr sprite = dev->spriteInfo->sprite; 1435 1436 if (from == to) 1437 return; 1438 out = (from == NoneWin) ? NotifyDetailNone : NotifyPointerRoot; 1439 in = (to == NoneWin) ? NotifyDetailNone : NotifyPointerRoot; 1440 /* wrong values if neither, but then not referenced */ 1441 1442#ifdef PANORAMIX 1443 if (!noPanoramiXExtension) 1444 nscreens = 1; 1445#endif 1446 1447 if ((to == NullWindow) || (to == PointerRootWin)) { 1448 if ((from == NullWindow) || (from == PointerRootWin)) { 1449 if (from == PointerRootWin) { 1450 DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyPointer, 1451 sprite->win); 1452 DeviceFocusOutEvents(dev, sprite->win, 1453 GetCurrentRootWindow(dev), mode, 1454 NotifyPointer); 1455 } 1456 /* Notify all the roots */ 1457 for (i = 0; i < nscreens; i++) 1458 DeviceFocusEvent(dev, XI_FocusOut, mode, out, 1459 screenInfo.screens[i]->root); 1460 } 1461 else { 1462 if (IsParent(from, sprite->win)) { 1463 DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyPointer, 1464 sprite->win); 1465 DeviceFocusOutEvents(dev, sprite->win, from, mode, 1466 NotifyPointer); 1467 } 1468 DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyNonlinear, from); 1469 /* next call catches the root too, if the screen changed */ 1470 DeviceFocusOutEvents(dev, from, NullWindow, mode, 1471 NotifyNonlinearVirtual); 1472 } 1473 /* Notify all the roots */ 1474 for (i = 0; i < nscreens; i++) 1475 DeviceFocusEvent(dev, XI_FocusIn, mode, in, 1476 screenInfo.screens[i]->root); 1477 if (to == PointerRootWin) { 1478 DeviceFocusInEvents(dev, GetCurrentRootWindow(dev), sprite->win, 1479 mode, NotifyPointer); 1480 DeviceFocusEvent(dev, XI_FocusIn, mode, NotifyPointer, sprite->win); 1481 } 1482 } 1483 else { 1484 if ((from == NullWindow) || (from == PointerRootWin)) { 1485 if (from == PointerRootWin) { 1486 DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyPointer, 1487 sprite->win); 1488 DeviceFocusOutEvents(dev, sprite->win, 1489 GetCurrentRootWindow(dev), mode, 1490 NotifyPointer); 1491 } 1492 for (i = 0; i < nscreens; i++) 1493 DeviceFocusEvent(dev, XI_FocusOut, mode, out, 1494 screenInfo.screens[i]->root); 1495 if (to->parent != NullWindow) 1496 DeviceFocusInEvents(dev, GetCurrentRootWindow(dev), to, mode, 1497 NotifyNonlinearVirtual); 1498 DeviceFocusEvent(dev, XI_FocusIn, mode, NotifyNonlinear, to); 1499 if (IsParent(to, sprite->win)) 1500 DeviceFocusInEvents(dev, to, sprite->win, mode, NotifyPointer); 1501 } 1502 else { 1503 if (IsParent(to, from)) { 1504 DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyAncestor, from); 1505 DeviceFocusOutEvents(dev, from, to, mode, NotifyVirtual); 1506 DeviceFocusEvent(dev, XI_FocusIn, mode, NotifyInferior, to); 1507 if ((IsParent(to, sprite->win)) && 1508 (sprite->win != from) && 1509 (!IsParent(from, sprite->win)) && 1510 (!IsParent(sprite->win, from))) 1511 DeviceFocusInEvents(dev, to, sprite->win, mode, 1512 NotifyPointer); 1513 } 1514 else if (IsParent(from, to)) { 1515 if ((IsParent(from, sprite->win)) && 1516 (sprite->win != from) && 1517 (!IsParent(to, sprite->win)) && 1518 (!IsParent(sprite->win, to))) { 1519 DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyPointer, 1520 sprite->win); 1521 DeviceFocusOutEvents(dev, sprite->win, from, mode, 1522 NotifyPointer); 1523 } 1524 DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyInferior, from); 1525 DeviceFocusInEvents(dev, from, to, mode, NotifyVirtual); 1526 DeviceFocusEvent(dev, XI_FocusIn, mode, NotifyAncestor, to); 1527 } 1528 else { 1529 /* neither from or to is child of other */ 1530 WindowPtr common = CommonAncestor(to, from); 1531 1532 /* common == NullWindow ==> different screens */ 1533 if (IsParent(from, sprite->win)) 1534 DeviceFocusOutEvents(dev, sprite->win, from, mode, 1535 NotifyPointer); 1536 DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyNonlinear, from); 1537 if (from->parent != NullWindow) 1538 DeviceFocusOutEvents(dev, from, common, mode, 1539 NotifyNonlinearVirtual); 1540 if (to->parent != NullWindow) 1541 DeviceFocusInEvents(dev, common, to, mode, 1542 NotifyNonlinearVirtual); 1543 DeviceFocusEvent(dev, XI_FocusIn, mode, NotifyNonlinear, to); 1544 if (IsParent(to, sprite->win)) 1545 DeviceFocusInEvents(dev, to, sprite->win, mode, 1546 NotifyPointer); 1547 } 1548 } 1549 } 1550} 1551 1552/** 1553 * Figure out if focus events are necessary and send them to the 1554 * appropriate windows. 1555 * 1556 * @param from Window the focus moved out of. 1557 * @param to Window the focus moved into. 1558 */ 1559void 1560DoFocusEvents(DeviceIntPtr pDev, WindowPtr from, WindowPtr to, int mode) 1561{ 1562 if (!IsKeyboardDevice(pDev)) 1563 return; 1564 1565 if (from == to && mode != NotifyGrab && mode != NotifyUngrab) 1566 return; 1567 1568 CoreFocusEvents(pDev, from, to, mode); 1569 DeviceFocusEvents(pDev, from, to, mode); 1570} 1571