grabs.c revision ed6184df
1/*
2
3Copyright 1987, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
28
29                        All Rights Reserved
30
31Permission to use, copy, modify, and distribute this software and its
32documentation for any purpose and without fee is hereby granted,
33provided that the above copyright notice appear in all copies and that
34both that copyright notice and this permission notice appear in
35supporting documentation, and that the name of Digital not be
36used in advertising or publicity pertaining to distribution of the
37software without specific, written prior permission.
38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42WHETHER IN AN action OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44SOFTWARE.
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
73void
74PrintDeviceGrabInfo(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
168void
169UngrabAllDevices(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
191GrabPtr
192AllocGrab(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
212GrabPtr
213CreateGrab(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
252void
253FreeGrab(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
267Bool
268CopyGrab(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
318int
319DeletePassiveGrab(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
340static Mask *
341DeleteDetailFromMask(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
359static Bool
360IsInGrabMask(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
378static Bool
379IdenticalExactDetails(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
391static Bool
392DetailSupersedesSecond(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
404static Bool
405GrabSupersedesSecond(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 */
433Bool
434GrabMatchesSecond(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
489static Bool
490GrabsAreIdentical(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 */
528int
529AddPassiveGrabToList(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
575Bool
576DeletePassiveGrabFromList(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
706Bool
707GrabIsPointerGrab(GrabPtr grab)
708{
709    return (grab->type == ButtonPress ||
710            grab->type == DeviceButtonPress || grab->type == XI_ButtonPress);
711}
712
713Bool
714GrabIsKeyboardGrab(GrabPtr grab)
715{
716    return (grab->type == KeyPress ||
717            grab->type == DeviceKeyPress || grab->type == XI_KeyPress);
718}
719
720Bool
721GrabIsGestureGrab(GrabPtr grab)
722{
723    return (grab->type == XI_GesturePinchBegin ||
724            grab->type == XI_GestureSwipeBegin);
725}
726