xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

enterleave.c (52316B)


      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  * https://lists.freedesktop.org/archives/xorg/2008-December/041684.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[MAXDEVICES];
     79 static WindowPtr FocusWindows[MAXDEVICES];
     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 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  */
    110 static BOOL
    111 HasFocus(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  */
    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  * its 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 < 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  * its 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 < 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  */
    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;
    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;
    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;
    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_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  */
    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, EnterNotify, 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, 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  */
    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_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  */
    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, 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  */
    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, 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  */
    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, 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 
    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_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  */
    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 != XINotifyPassiveGrab && mode != XINotifyPassiveUngrab)
    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;
    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 << 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 
    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)) ||
    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 
    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     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  */
    851 static void
    852 DeviceFocusOutEvents(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  */
    868 static void
    869 DeviceFocusInEvents(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  */
    885 static void
    886 CoreFocusInEvents(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 
    917 static void
    918 CoreFocusOutEvents(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  */
    964 static void
    965 CoreFocusOutNotifyPointerEvents(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  */
    993 static void
    994 CoreFocusInRecurse(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  */
   1013 static void
   1014 CoreFocusInNotifyPointerEvents(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  */
   1035 static void
   1036 CoreFocusNonLinear(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  */
   1125 static void
   1126 CoreFocusToAncestor(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  */
   1182 static void
   1183 CoreFocusToDescendant(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 
   1235 static BOOL
   1236 HasOtherPointer(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  */
   1251 static void
   1252 CoreFocusPointerRootNoneSwitch(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  */
   1296 static void
   1297 CoreFocusToPointerRootOrNone(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  */
   1343 static void
   1344 CoreFocusFromPointerRootOrNone(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 
   1402 static void
   1403 CoreFocusEvents(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 
   1427 static void
   1428 DeviceFocusEvents(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  */
   1559 void
   1560 DoFocusEvents(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 }