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
PrintDeviceGrabInfo(DeviceIntPtr dev)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
UngrabAllDevices(Bool kill_client)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
AllocGrab(const GrabPtr src)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
CreateGrab(int client,DeviceIntPtr device,DeviceIntPtr modDevice,WindowPtr window,enum InputLevel grabtype,GrabMask * mask,GrabParameters * param,int type,KeyCode keybut,WindowPtr confineTo,CursorPtr cursor)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
FreeGrab(GrabPtr pGrab)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
CopyGrab(GrabPtr dst,const GrabPtr src)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
DeletePassiveGrab(void * value,XID id)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 *
DeleteDetailFromMask(Mask * pDetailMask,unsigned int detail)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
IsInGrabMask(DetailRec firstDetail,DetailRec secondDetail,unsigned int exception)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
IdenticalExactDetails(unsigned int firstExact,unsigned int secondExact,unsigned int exception)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
DetailSupersedesSecond(DetailRec firstDetail,DetailRec secondDetail,unsigned int exception)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
GrabSupersedesSecond(GrabPtr pFirstGrab,GrabPtr pSecondGrab)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
GrabMatchesSecond(GrabPtr pFirstGrab,GrabPtr pSecondGrab,Bool ignoreDevice)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
GrabsAreIdentical(GrabPtr pFirstGrab,GrabPtr pSecondGrab)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
AddPassiveGrabToList(ClientPtr client,GrabPtr pGrab)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
DeletePassiveGrabFromList(GrabPtr pMinuendGrab)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
GrabIsPointerGrab(GrabPtr grab)707 GrabIsPointerGrab(GrabPtr grab)
708 {
709     return (grab->type == ButtonPress ||
710             grab->type == DeviceButtonPress || grab->type == XI_ButtonPress);
711 }
712 
713 Bool
GrabIsKeyboardGrab(GrabPtr grab)714 GrabIsKeyboardGrab(GrabPtr grab)
715 {
716     return (grab->type == KeyPress ||
717             grab->type == DeviceKeyPress || grab->type == XI_KeyPress);
718 }
719