xserver

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

grabs.c (23117B)


      1 /*
      2 
      3 Copyright 1987, 1998  The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included
     12 in all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 OTHER DEALINGS IN THE SOFTWARE.
     21 
     22 Except as contained in this notice, the name of The Open Group shall
     23 not be used in advertising or otherwise to promote the sale, use or
     24 other dealings in this Software without prior written authorization
     25 from The Open Group.
     26 
     27 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
     28 
     29                         All Rights Reserved
     30 
     31 Permission to use, copy, modify, and distribute this software and its
     32 documentation for any purpose and without fee is hereby granted,
     33 provided that the above copyright notice appear in all copies and that
     34 both that copyright notice and this permission notice appear in
     35 supporting documentation, and that the name of Digital not be
     36 used in advertising or publicity pertaining to distribution of the
     37 software without specific, written prior permission.
     38 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
     39 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
     40 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
     41 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
     42 WHETHER IN AN action OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
     43 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     44 SOFTWARE.
     45 
     46 */
     47 
     48 #ifdef HAVE_DIX_CONFIG_H
     49 #include <dix-config.h>
     50 #endif
     51 
     52 #include <X11/X.h>
     53 #include "misc.h"
     54 #include <X11/Xproto.h>
     55 #include <X11/extensions/XI2.h>
     56 #include "windowstr.h"
     57 #include "inputstr.h"
     58 #include "cursorstr.h"
     59 #include "dixgrabs.h"
     60 #include "xace.h"
     61 #include "exevents.h"
     62 #include "exglobals.h"
     63 #include "inpututils.h"
     64 #include "client.h"
     65 
     66 #define BITMASK(i) (((Mask)1) << ((i) & 31))
     67 #define MASKIDX(i) ((i) >> 5)
     68 #define MASKWORD(buf, i) buf[MASKIDX(i)]
     69 #define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i)
     70 #define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i)
     71 #define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i))
     72 
     73 void
     74 PrintDeviceGrabInfo(DeviceIntPtr dev)
     75 {
     76     ClientPtr client;
     77     LocalClientCredRec *lcc;
     78     int i, j;
     79     GrabInfoPtr devGrab = &dev->deviceGrab;
     80     GrabPtr grab = devGrab->grab;
     81     Bool clientIdPrinted = FALSE;
     82 
     83     ErrorF("Active grab 0x%lx (%s) on device '%s' (%d):\n",
     84            (unsigned long) grab->resource,
     85            (grab->grabtype == XI2) ? "xi2" :
     86            ((grab->grabtype == CORE) ? "core" : "xi1"), dev->name, dev->id);
     87 
     88     client = clients[CLIENT_ID(grab->resource)];
     89     if (client) {
     90         pid_t clientpid = GetClientPid(client);
     91         const char *cmdname = GetClientCmdName(client);
     92         const char *cmdargs = GetClientCmdArgs(client);
     93 
     94         if ((clientpid > 0) && (cmdname != NULL)) {
     95             ErrorF("      client pid %ld %s %s\n",
     96                    (long) clientpid, cmdname, cmdargs ? cmdargs : "");
     97             clientIdPrinted = TRUE;
     98         }
     99         else if (GetLocalClientCreds(client, &lcc) != -1) {
    100             ErrorF("      client pid %ld uid %ld gid %ld\n",
    101                    (lcc->fieldsSet & LCC_PID_SET) ? (long) lcc->pid : 0,
    102                    (lcc->fieldsSet & LCC_UID_SET) ? (long) lcc->euid : 0,
    103                    (lcc->fieldsSet & LCC_GID_SET) ? (long) lcc->egid : 0);
    104             FreeLocalClientCreds(lcc);
    105             clientIdPrinted = TRUE;
    106         }
    107     }
    108     if (!clientIdPrinted) {
    109         ErrorF("      (no client information available for client %d)\n",
    110                CLIENT_ID(grab->resource));
    111     }
    112 
    113     /* XXX is this even correct? */
    114     if (devGrab->sync.other)
    115         ErrorF("      grab ID 0x%lx from paired device\n",
    116                (unsigned long) devGrab->sync.other->resource);
    117 
    118     ErrorF("      at %ld (from %s grab)%s (device %s, state %d)\n",
    119            (unsigned long) devGrab->grabTime.milliseconds,
    120            devGrab->fromPassiveGrab ? "passive" : "active",
    121            devGrab->implicitGrab ? " (implicit)" : "",
    122            devGrab->sync.frozen ? "frozen" : "thawed", devGrab->sync.state);
    123 
    124     if (grab->grabtype == CORE) {
    125         ErrorF("        core event mask 0x%lx\n",
    126                (unsigned long) grab->eventMask);
    127     }
    128     else if (grab->grabtype == XI) {
    129         ErrorF("      xi1 event mask 0x%lx\n",
    130                devGrab->implicitGrab ? (unsigned long) grab->deviceMask :
    131                (unsigned long) grab->eventMask);
    132     }
    133     else if (grab->grabtype == XI2) {
    134         for (i = 0; i < xi2mask_num_masks(grab->xi2mask); i++) {
    135             const unsigned char *mask;
    136             int print;
    137 
    138             print = 0;
    139             for (j = 0; j < XI2MASKSIZE; j++) {
    140                 mask = xi2mask_get_one_mask(grab->xi2mask, i);
    141                 if (mask[j]) {
    142                     print = 1;
    143                     break;
    144                 }
    145             }
    146             if (!print)
    147                 continue;
    148             ErrorF("      xi2 event mask for device %d: 0x", dev->id);
    149             for (j = 0; j < xi2mask_mask_size(grab->xi2mask); j++)
    150                 ErrorF("%x", mask[j]);
    151             ErrorF("\n");
    152         }
    153     }
    154 
    155     if (devGrab->fromPassiveGrab) {
    156         ErrorF("      passive grab type %d, detail 0x%x, "
    157                "activating key %d\n", grab->type, grab->detail.exact,
    158                devGrab->activatingKey);
    159     }
    160 
    161     ErrorF("      owner-events %s, kb %d ptr %d, confine %lx, cursor 0x%lx\n",
    162            grab->ownerEvents ? "true" : "false",
    163            grab->keyboardMode, grab->pointerMode,
    164            grab->confineTo ? (unsigned long) grab->confineTo->drawable.id : 0,
    165            grab->cursor ? (unsigned long) grab->cursor->id : 0);
    166 }
    167 
    168 void
    169 UngrabAllDevices(Bool kill_client)
    170 {
    171     DeviceIntPtr dev;
    172     ClientPtr client;
    173 
    174     ErrorF("Ungrabbing all devices%s; grabs listed below:\n",
    175            kill_client ? " and killing their owners" : "");
    176 
    177     for (dev = inputInfo.devices; dev; dev = dev->next) {
    178         if (!dev->deviceGrab.grab)
    179             continue;
    180         PrintDeviceGrabInfo(dev);
    181         client = clients[CLIENT_ID(dev->deviceGrab.grab->resource)];
    182         if (!kill_client || !client || client->clientGone)
    183             dev->deviceGrab.DeactivateGrab(dev);
    184         if (kill_client)
    185             CloseDownClient(client);
    186     }
    187 
    188     ErrorF("End list of ungrabbed devices\n");
    189 }
    190 
    191 GrabPtr
    192 AllocGrab(const GrabPtr src)
    193 {
    194     GrabPtr grab = calloc(1, sizeof(GrabRec));
    195 
    196     if (grab) {
    197         grab->xi2mask = xi2mask_new();
    198         if (!grab->xi2mask) {
    199             free(grab);
    200             grab = NULL;
    201         }
    202         else if (src && !CopyGrab(grab, src)) {
    203             free(grab->xi2mask);
    204             free(grab);
    205             grab = NULL;
    206         }
    207     }
    208 
    209     return grab;
    210 }
    211 
    212 GrabPtr
    213 CreateGrab(int client, DeviceIntPtr device, DeviceIntPtr modDevice,
    214            WindowPtr window, enum InputLevel grabtype, GrabMask *mask,
    215            GrabParameters *param, int type,
    216            KeyCode keybut,        /* key or button */
    217            WindowPtr confineTo, CursorPtr cursor)
    218 {
    219     GrabPtr grab;
    220 
    221     grab = AllocGrab(NULL);
    222     if (!grab)
    223         return (GrabPtr) NULL;
    224     grab->resource = FakeClientID(client);
    225     grab->device = device;
    226     grab->window = window;
    227     if (grabtype == CORE || grabtype == XI)
    228         grab->eventMask = mask->core;       /* same for XI */
    229     else
    230         grab->eventMask = 0;
    231     grab->deviceMask = 0;
    232     grab->ownerEvents = param->ownerEvents;
    233     grab->keyboardMode = param->this_device_mode;
    234     grab->pointerMode = param->other_devices_mode;
    235     grab->modifiersDetail.exact = param->modifiers;
    236     grab->modifiersDetail.pMask = NULL;
    237     grab->modifierDevice = modDevice;
    238     grab->type = type;
    239     grab->grabtype = grabtype;
    240     grab->detail.exact = keybut;
    241     grab->detail.pMask = NULL;
    242     grab->confineTo = confineTo;
    243     grab->cursor = RefCursor(cursor);
    244     grab->next = NULL;
    245 
    246     if (grabtype == XI2)
    247         xi2mask_merge(grab->xi2mask, mask->xi2mask);
    248     return grab;
    249 
    250 }
    251 
    252 void
    253 FreeGrab(GrabPtr pGrab)
    254 {
    255     BUG_RETURN(!pGrab);
    256 
    257     free(pGrab->modifiersDetail.pMask);
    258     free(pGrab->detail.pMask);
    259 
    260     if (pGrab->cursor)
    261         FreeCursor(pGrab->cursor, (Cursor) 0);
    262 
    263     xi2mask_free(&pGrab->xi2mask);
    264     free(pGrab);
    265 }
    266 
    267 Bool
    268 CopyGrab(GrabPtr dst, const GrabPtr src)
    269 {
    270     Mask *mdetails_mask = NULL;
    271     Mask *details_mask = NULL;
    272     XI2Mask *xi2mask;
    273 
    274     if (src->modifiersDetail.pMask) {
    275         int len = MasksPerDetailMask * sizeof(Mask);
    276 
    277         mdetails_mask = malloc(len);
    278         if (!mdetails_mask)
    279             return FALSE;
    280         memcpy(mdetails_mask, src->modifiersDetail.pMask, len);
    281     }
    282 
    283     if (src->detail.pMask) {
    284         int len = MasksPerDetailMask * sizeof(Mask);
    285 
    286         details_mask = malloc(len);
    287         if (!details_mask) {
    288             free(mdetails_mask);
    289             return FALSE;
    290         }
    291         memcpy(details_mask, src->detail.pMask, len);
    292     }
    293 
    294     if (!dst->xi2mask) {
    295         xi2mask = xi2mask_new();
    296         if (!xi2mask) {
    297             free(mdetails_mask);
    298             free(details_mask);
    299             return FALSE;
    300         }
    301     }
    302     else {
    303         xi2mask = dst->xi2mask;
    304         xi2mask_zero(xi2mask, -1);
    305     }
    306 
    307     *dst = *src;
    308     dst->modifiersDetail.pMask = mdetails_mask;
    309     dst->detail.pMask = details_mask;
    310     dst->xi2mask = xi2mask;
    311     dst->cursor = RefCursor(src->cursor);
    312 
    313     xi2mask_merge(dst->xi2mask, src->xi2mask);
    314 
    315     return TRUE;
    316 }
    317 
    318 int
    319 DeletePassiveGrab(void *value, XID id)
    320 {
    321     GrabPtr g, prev;
    322     GrabPtr pGrab = (GrabPtr) value;
    323 
    324     /* it is OK if the grab isn't found */
    325     prev = 0;
    326     for (g = (wPassiveGrabs(pGrab->window)); g; g = g->next) {
    327         if (pGrab == g) {
    328             if (prev)
    329                 prev->next = g->next;
    330             else if (!(pGrab->window->optional->passiveGrabs = g->next))
    331                 CheckWindowOptionalNeed(pGrab->window);
    332             break;
    333         }
    334         prev = g;
    335     }
    336     FreeGrab(pGrab);
    337     return Success;
    338 }
    339 
    340 static Mask *
    341 DeleteDetailFromMask(Mask *pDetailMask, unsigned int detail)
    342 {
    343     Mask *mask;
    344     int i;
    345 
    346     mask = malloc(sizeof(Mask) * MasksPerDetailMask);
    347     if (mask) {
    348         if (pDetailMask)
    349             for (i = 0; i < MasksPerDetailMask; i++)
    350                 mask[i] = pDetailMask[i];
    351         else
    352             for (i = 0; i < MasksPerDetailMask; i++)
    353                 mask[i] = ~0L;
    354         BITCLEAR(mask, detail);
    355     }
    356     return mask;
    357 }
    358 
    359 static Bool
    360 IsInGrabMask(DetailRec firstDetail,
    361              DetailRec secondDetail, unsigned int exception)
    362 {
    363     if (firstDetail.exact == exception) {
    364         if (firstDetail.pMask == NULL)
    365             return TRUE;
    366 
    367         /* (at present) never called with two non-null pMasks */
    368         if (secondDetail.exact == exception)
    369             return FALSE;
    370 
    371         if (GETBIT(firstDetail.pMask, secondDetail.exact))
    372             return TRUE;
    373     }
    374 
    375     return FALSE;
    376 }
    377 
    378 static Bool
    379 IdenticalExactDetails(unsigned int firstExact,
    380                       unsigned int secondExact, unsigned int exception)
    381 {
    382     if ((firstExact == exception) || (secondExact == exception))
    383         return FALSE;
    384 
    385     if (firstExact == secondExact)
    386         return TRUE;
    387 
    388     return FALSE;
    389 }
    390 
    391 static Bool
    392 DetailSupersedesSecond(DetailRec firstDetail,
    393                        DetailRec secondDetail, unsigned int exception)
    394 {
    395     if (IsInGrabMask(firstDetail, secondDetail, exception))
    396         return TRUE;
    397 
    398     if (IdenticalExactDetails(firstDetail.exact, secondDetail.exact, exception))
    399         return TRUE;
    400 
    401     return FALSE;
    402 }
    403 
    404 static Bool
    405 GrabSupersedesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
    406 {
    407     unsigned int any_modifier = (pFirstGrab->grabtype == XI2) ?
    408         (unsigned int) XIAnyModifier : (unsigned int) AnyModifier;
    409     if (!DetailSupersedesSecond(pFirstGrab->modifiersDetail,
    410                                 pSecondGrab->modifiersDetail, any_modifier))
    411         return FALSE;
    412 
    413     if (DetailSupersedesSecond(pFirstGrab->detail,
    414                                pSecondGrab->detail, (unsigned int) AnyKey))
    415         return TRUE;
    416 
    417     return FALSE;
    418 }
    419 
    420 /**
    421  * Compares two grabs and returns TRUE if the first grab matches the second
    422  * grab.
    423  *
    424  * A match is when
    425  *  - the devices set for the grab are equal (this is optional).
    426  *  - the event types for both grabs are equal.
    427  *  - XXX
    428  *
    429  * @param ignoreDevice TRUE if the device settings on the grabs are to be
    430  * ignored.
    431  * @return TRUE if the grabs match or FALSE otherwise.
    432  */
    433 Bool
    434 GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab, Bool ignoreDevice)
    435 {
    436     unsigned int any_modifier = (pFirstGrab->grabtype == XI2) ?
    437         (unsigned int) XIAnyModifier : (unsigned int) AnyModifier;
    438 
    439     if (pFirstGrab->grabtype != pSecondGrab->grabtype)
    440         return FALSE;
    441 
    442     if (pFirstGrab->grabtype == XI2) {
    443         if (pFirstGrab->device == inputInfo.all_devices ||
    444             pSecondGrab->device == inputInfo.all_devices) {
    445             /* do nothing */
    446         }
    447         else if (pFirstGrab->device == inputInfo.all_master_devices) {
    448             if (pSecondGrab->device != inputInfo.all_master_devices &&
    449                 !IsMaster(pSecondGrab->device))
    450                 return FALSE;
    451         }
    452         else if (pSecondGrab->device == inputInfo.all_master_devices) {
    453             if (pFirstGrab->device != inputInfo.all_master_devices &&
    454                 !IsMaster(pFirstGrab->device))
    455                 return FALSE;
    456         }
    457         else if (pSecondGrab->device != pFirstGrab->device)
    458             return FALSE;
    459     }
    460     else if (!ignoreDevice &&
    461              ((pFirstGrab->device != pSecondGrab->device) ||
    462               (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice)))
    463         return FALSE;
    464 
    465     if (pFirstGrab->type != pSecondGrab->type)
    466         return FALSE;
    467 
    468     if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) ||
    469         GrabSupersedesSecond(pSecondGrab, pFirstGrab))
    470         return TRUE;
    471 
    472     if (DetailSupersedesSecond(pSecondGrab->detail, pFirstGrab->detail,
    473                                (unsigned int) AnyKey)
    474         &&
    475         DetailSupersedesSecond(pFirstGrab->modifiersDetail,
    476                                pSecondGrab->modifiersDetail, any_modifier))
    477         return TRUE;
    478 
    479     if (DetailSupersedesSecond(pFirstGrab->detail, pSecondGrab->detail,
    480                                (unsigned int) AnyKey)
    481         &&
    482         DetailSupersedesSecond(pSecondGrab->modifiersDetail,
    483                                pFirstGrab->modifiersDetail, any_modifier))
    484         return TRUE;
    485 
    486     return FALSE;
    487 }
    488 
    489 static Bool
    490 GrabsAreIdentical(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
    491 {
    492     unsigned int any_modifier = (pFirstGrab->grabtype == XI2) ?
    493         (unsigned int) XIAnyModifier : (unsigned int) AnyModifier;
    494 
    495     if (pFirstGrab->grabtype != pSecondGrab->grabtype)
    496         return FALSE;
    497 
    498     if (pFirstGrab->device != pSecondGrab->device ||
    499         (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) ||
    500         (pFirstGrab->type != pSecondGrab->type))
    501         return FALSE;
    502 
    503     if (!(DetailSupersedesSecond(pFirstGrab->detail,
    504                                  pSecondGrab->detail,
    505                                  (unsigned int) AnyKey) &&
    506           DetailSupersedesSecond(pSecondGrab->detail,
    507                                  pFirstGrab->detail, (unsigned int) AnyKey)))
    508         return FALSE;
    509 
    510     if (!(DetailSupersedesSecond(pFirstGrab->modifiersDetail,
    511                                  pSecondGrab->modifiersDetail,
    512                                  any_modifier) &&
    513           DetailSupersedesSecond(pSecondGrab->modifiersDetail,
    514                                  pFirstGrab->modifiersDetail, any_modifier)))
    515         return FALSE;
    516 
    517     return TRUE;
    518 }
    519 
    520 /**
    521  * Prepend the new grab to the list of passive grabs on the window.
    522  * Any previously existing grab that matches the new grab will be removed.
    523  * Adding a new grab that would override another client's grab will result in
    524  * a BadAccess.
    525  *
    526  * @return Success or X error code on failure.
    527  */
    528 int
    529 AddPassiveGrabToList(ClientPtr client, GrabPtr pGrab)
    530 {
    531     GrabPtr grab;
    532     Mask access_mode = DixGrabAccess;
    533     int rc;
    534 
    535     for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) {
    536         if (GrabMatchesSecond(pGrab, grab, (pGrab->grabtype == CORE))) {
    537             if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource)) {
    538                 FreeGrab(pGrab);
    539                 return BadAccess;
    540             }
    541         }
    542     }
    543 
    544     if (pGrab->keyboardMode == GrabModeSync ||
    545         pGrab->pointerMode == GrabModeSync)
    546         access_mode |= DixFreezeAccess;
    547     rc = XaceHook(XACE_DEVICE_ACCESS, client, pGrab->device, access_mode);
    548     if (rc != Success)
    549         return rc;
    550 
    551     /* Remove all grabs that match the new one exactly */
    552     for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) {
    553         if (GrabsAreIdentical(pGrab, grab)) {
    554             DeletePassiveGrabFromList(grab);
    555             break;
    556         }
    557     }
    558 
    559     if (!pGrab->window->optional && !MakeWindowOptional(pGrab->window)) {
    560         FreeGrab(pGrab);
    561         return BadAlloc;
    562     }
    563 
    564     pGrab->next = pGrab->window->optional->passiveGrabs;
    565     pGrab->window->optional->passiveGrabs = pGrab;
    566     if (AddResource(pGrab->resource, RT_PASSIVEGRAB, (void *) pGrab))
    567         return Success;
    568     return BadAlloc;
    569 }
    570 
    571 /* the following is kinda complicated, because we need to be able to back out
    572  * if any allocation fails
    573  */
    574 
    575 Bool
    576 DeletePassiveGrabFromList(GrabPtr pMinuendGrab)
    577 {
    578     GrabPtr grab;
    579     GrabPtr *deletes, *adds;
    580     Mask ***updates, **details;
    581     int i, ndels, nadds, nups;
    582     Bool ok;
    583     unsigned int any_modifier;
    584     unsigned int any_key;
    585 
    586 #define UPDATE(mask,exact) \
    587 	if (!(details[nups] = DeleteDetailFromMask(mask, exact))) \
    588 	  ok = FALSE; \
    589 	else \
    590 	  updates[nups++] = &(mask)
    591 
    592     i = 0;
    593     for (grab = wPassiveGrabs(pMinuendGrab->window); grab; grab = grab->next)
    594         i++;
    595     if (!i)
    596         return TRUE;
    597     deletes = xallocarray(i, sizeof(GrabPtr));
    598     adds = xallocarray(i, sizeof(GrabPtr));
    599     updates = xallocarray(i, sizeof(Mask **));
    600     details = xallocarray(i, sizeof(Mask *));
    601     if (!deletes || !adds || !updates || !details) {
    602         free(details);
    603         free(updates);
    604         free(adds);
    605         free(deletes);
    606         return FALSE;
    607     }
    608 
    609     any_modifier = (pMinuendGrab->grabtype == XI2) ?
    610         (unsigned int) XIAnyModifier : (unsigned int) AnyModifier;
    611     any_key = (pMinuendGrab->grabtype == XI2) ?
    612         (unsigned int) XIAnyKeycode : (unsigned int) AnyKey;
    613     ndels = nadds = nups = 0;
    614     ok = TRUE;
    615     for (grab = wPassiveGrabs(pMinuendGrab->window);
    616          grab && ok; grab = grab->next) {
    617         if ((CLIENT_BITS(grab->resource) != CLIENT_BITS(pMinuendGrab->resource))
    618             || !GrabMatchesSecond(grab, pMinuendGrab, (grab->grabtype == CORE)))
    619             continue;
    620         if (GrabSupersedesSecond(pMinuendGrab, grab)) {
    621             deletes[ndels++] = grab;
    622         }
    623         else if ((grab->detail.exact == any_key)
    624                  && (grab->modifiersDetail.exact != any_modifier)) {
    625             UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
    626         }
    627         else if ((grab->modifiersDetail.exact == any_modifier)
    628                  && (grab->detail.exact != any_key)) {
    629             UPDATE(grab->modifiersDetail.pMask,
    630                    pMinuendGrab->modifiersDetail.exact);
    631         }
    632         else if ((pMinuendGrab->detail.exact != any_key)
    633                  && (pMinuendGrab->modifiersDetail.exact != any_modifier)) {
    634             GrabPtr pNewGrab;
    635             GrabParameters param;
    636 
    637             UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
    638 
    639             memset(&param, 0, sizeof(param));
    640             param.ownerEvents = grab->ownerEvents;
    641             param.this_device_mode = grab->keyboardMode;
    642             param.other_devices_mode = grab->pointerMode;
    643             param.modifiers = any_modifier;
    644 
    645             pNewGrab = CreateGrab(CLIENT_ID(grab->resource), grab->device,
    646                                   grab->modifierDevice, grab->window,
    647                                   grab->grabtype,
    648                                   (GrabMask *) &grab->eventMask,
    649                                   &param, (int) grab->type,
    650                                   pMinuendGrab->detail.exact,
    651                                   grab->confineTo, grab->cursor);
    652             if (!pNewGrab)
    653                 ok = FALSE;
    654             else if (!(pNewGrab->modifiersDetail.pMask =
    655                        DeleteDetailFromMask(grab->modifiersDetail.pMask,
    656                                             pMinuendGrab->modifiersDetail.
    657                                             exact))
    658                      || (!pNewGrab->window->optional &&
    659                          !MakeWindowOptional(pNewGrab->window))) {
    660                 FreeGrab(pNewGrab);
    661                 ok = FALSE;
    662             }
    663             else if (!AddResource(pNewGrab->resource, RT_PASSIVEGRAB,
    664                                   (void *) pNewGrab))
    665                 ok = FALSE;
    666             else
    667                 adds[nadds++] = pNewGrab;
    668         }
    669         else if (pMinuendGrab->detail.exact == any_key) {
    670             UPDATE(grab->modifiersDetail.pMask,
    671                    pMinuendGrab->modifiersDetail.exact);
    672         }
    673         else {
    674             UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
    675         }
    676     }
    677 
    678     if (!ok) {
    679         for (i = 0; i < nadds; i++)
    680             FreeResource(adds[i]->resource, RT_NONE);
    681         for (i = 0; i < nups; i++)
    682             free(details[i]);
    683     }
    684     else {
    685         for (i = 0; i < ndels; i++)
    686             FreeResource(deletes[i]->resource, RT_NONE);
    687         for (i = 0; i < nadds; i++) {
    688             grab = adds[i];
    689             grab->next = grab->window->optional->passiveGrabs;
    690             grab->window->optional->passiveGrabs = grab;
    691         }
    692         for (i = 0; i < nups; i++) {
    693             free(*updates[i]);
    694             *updates[i] = details[i];
    695         }
    696     }
    697     free(details);
    698     free(updates);
    699     free(adds);
    700     free(deletes);
    701     return ok;
    702 
    703 #undef UPDATE
    704 }
    705 
    706 Bool
    707 GrabIsPointerGrab(GrabPtr grab)
    708 {
    709     return (grab->type == ButtonPress ||
    710             grab->type == DeviceButtonPress || grab->type == XI_ButtonPress);
    711 }
    712 
    713 Bool
    714 GrabIsKeyboardGrab(GrabPtr grab)
    715 {
    716     return (grab->type == KeyPress ||
    717             grab->type == DeviceKeyPress || grab->type == XI_KeyPress);
    718 }
    719 
    720 Bool
    721 GrabIsGestureGrab(GrabPtr grab)
    722 {
    723     return (grab->type == XI_GesturePinchBegin ||
    724             grab->type == XI_GestureSwipeBegin);
    725 }