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