Imported Upstream version 1.15.1
[deb_xorg-server.git] / dix / grabs.c
CommitLineData
a09e091a
JB
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 }
203
204 if (src && !CopyGrab(grab, src)) {
205 free(grab->xi2mask);
206 free(grab);
207 grab = NULL;
208 }
209
210 return grab;
211}
212
213GrabPtr
214CreateGrab(int client, DeviceIntPtr device, DeviceIntPtr modDevice,
215 WindowPtr window, enum InputLevel grabtype, GrabMask *mask,
216 GrabParameters *param, int type,
217 KeyCode keybut, /* key or button */
218 WindowPtr confineTo, CursorPtr cursor)
219{
220 GrabPtr grab;
221
222 grab = AllocGrab(NULL);
223 if (!grab)
224 return (GrabPtr) NULL;
225 grab->resource = FakeClientID(client);
226 grab->device = device;
227 grab->window = window;
228 if (grabtype == CORE || grabtype == XI)
229 grab->eventMask = mask->core; /* same for XI */
230 else
231 grab->eventMask = 0;
232 grab->deviceMask = 0;
233 grab->ownerEvents = param->ownerEvents;
234 grab->keyboardMode = param->this_device_mode;
235 grab->pointerMode = param->other_devices_mode;
236 grab->modifiersDetail.exact = param->modifiers;
237 grab->modifiersDetail.pMask = NULL;
238 grab->modifierDevice = modDevice;
239 grab->type = type;
240 grab->grabtype = grabtype;
241 grab->detail.exact = keybut;
242 grab->detail.pMask = NULL;
243 grab->confineTo = confineTo;
244 grab->cursor = RefCursor(cursor);
245 grab->next = NULL;
246
247 if (grabtype == XI2)
248 xi2mask_merge(grab->xi2mask, mask->xi2mask);
249 return grab;
250
251}
252
253void
254FreeGrab(GrabPtr pGrab)
255{
256 BUG_RETURN(!pGrab);
257
258 free(pGrab->modifiersDetail.pMask);
259 free(pGrab->detail.pMask);
260
261 if (pGrab->cursor)
262 FreeCursor(pGrab->cursor, (Cursor) 0);
263
264 xi2mask_free(&pGrab->xi2mask);
265 free(pGrab);
266}
267
268Bool
269CopyGrab(GrabPtr dst, const GrabPtr src)
270{
271 Mask *mdetails_mask = NULL;
272 Mask *details_mask = NULL;
273 XI2Mask *xi2mask;
274
275 if (src->modifiersDetail.pMask) {
276 int len = MasksPerDetailMask * sizeof(Mask);
277
278 mdetails_mask = malloc(len);
279 if (!mdetails_mask)
280 return FALSE;
281 memcpy(mdetails_mask, src->modifiersDetail.pMask, len);
282 }
283
284 if (src->detail.pMask) {
285 int len = MasksPerDetailMask * sizeof(Mask);
286
287 details_mask = malloc(len);
288 if (!details_mask) {
289 free(mdetails_mask);
290 return FALSE;
291 }
292 memcpy(details_mask, src->detail.pMask, len);
293 }
294
295 if (!dst->xi2mask) {
296 xi2mask = xi2mask_new();
297 if (!xi2mask) {
298 free(mdetails_mask);
299 free(details_mask);
300 return FALSE;
301 }
302 }
303 else {
304 xi2mask = dst->xi2mask;
305 xi2mask_zero(xi2mask, -1);
306 }
307
308 *dst = *src;
309 dst->modifiersDetail.pMask = mdetails_mask;
310 dst->detail.pMask = details_mask;
311 dst->xi2mask = xi2mask;
312 dst->cursor = RefCursor(src->cursor);
313
314 xi2mask_merge(dst->xi2mask, src->xi2mask);
315
316 return TRUE;
317}
318
319int
320DeletePassiveGrab(pointer value, XID id)
321{
322 GrabPtr g, prev;
323 GrabPtr pGrab = (GrabPtr) value;
324
325 /* it is OK if the grab isn't found */
326 prev = 0;
327 for (g = (wPassiveGrabs(pGrab->window)); g; g = g->next) {
328 if (pGrab == g) {
329 if (prev)
330 prev->next = g->next;
331 else if (!(pGrab->window->optional->passiveGrabs = g->next))
332 CheckWindowOptionalNeed(pGrab->window);
333 break;
334 }
335 prev = g;
336 }
337 FreeGrab(pGrab);
338 return Success;
339}
340
341static Mask *
342DeleteDetailFromMask(Mask *pDetailMask, unsigned int detail)
343{
344 Mask *mask;
345 int i;
346
347 mask = malloc(sizeof(Mask) * MasksPerDetailMask);
348 if (mask) {
349 if (pDetailMask)
350 for (i = 0; i < MasksPerDetailMask; i++)
351 mask[i] = pDetailMask[i];
352 else
353 for (i = 0; i < MasksPerDetailMask; i++)
354 mask[i] = ~0L;
355 BITCLEAR(mask, detail);
356 }
357 return mask;
358}
359
360static Bool
361IsInGrabMask(DetailRec firstDetail,
362 DetailRec secondDetail, unsigned int exception)
363{
364 if (firstDetail.exact == exception) {
365 if (firstDetail.pMask == NULL)
366 return TRUE;
367
368 /* (at present) never called with two non-null pMasks */
369 if (secondDetail.exact == exception)
370 return FALSE;
371
372 if (GETBIT(firstDetail.pMask, secondDetail.exact))
373 return TRUE;
374 }
375
376 return FALSE;
377}
378
379static Bool
380IdenticalExactDetails(unsigned int firstExact,
381 unsigned int secondExact, unsigned int exception)
382{
383 if ((firstExact == exception) || (secondExact == exception))
384 return FALSE;
385
386 if (firstExact == secondExact)
387 return TRUE;
388
389 return FALSE;
390}
391
392static Bool
393DetailSupersedesSecond(DetailRec firstDetail,
394 DetailRec secondDetail, unsigned int exception)
395{
396 if (IsInGrabMask(firstDetail, secondDetail, exception))
397 return TRUE;
398
399 if (IdenticalExactDetails(firstDetail.exact, secondDetail.exact, exception))
400 return TRUE;
401
402 return FALSE;
403}
404
405static Bool
406GrabSupersedesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
407{
408 unsigned int any_modifier = (pFirstGrab->grabtype == XI2) ?
409 (unsigned int) XIAnyModifier : (unsigned int) AnyModifier;
410 if (!DetailSupersedesSecond(pFirstGrab->modifiersDetail,
411 pSecondGrab->modifiersDetail, any_modifier))
412 return FALSE;
413
414 if (DetailSupersedesSecond(pFirstGrab->detail,
415 pSecondGrab->detail, (unsigned int) AnyKey))
416 return TRUE;
417
418 return FALSE;
419}
420
421/**
422 * Compares two grabs and returns TRUE if the first grab matches the second
423 * grab.
424 *
425 * A match is when
426 * - the devices set for the grab are equal (this is optional).
427 * - the event types for both grabs are equal.
428 * - XXX
429 *
430 * @param ignoreDevice TRUE if the device settings on the grabs are to be
431 * ignored.
432 * @return TRUE if the grabs match or FALSE otherwise.
433 */
434Bool
435GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab, Bool ignoreDevice)
436{
437 unsigned int any_modifier = (pFirstGrab->grabtype == XI2) ?
438 (unsigned int) XIAnyModifier : (unsigned int) AnyModifier;
439
440 if (pFirstGrab->grabtype != pSecondGrab->grabtype)
441 return FALSE;
442
443 if (pFirstGrab->grabtype == XI2) {
444 if (pFirstGrab->device == inputInfo.all_devices ||
445 pSecondGrab->device == inputInfo.all_devices) {
446 /* do nothing */
447 }
448 else if (pFirstGrab->device == inputInfo.all_master_devices) {
449 if (pSecondGrab->device != inputInfo.all_master_devices &&
450 !IsMaster(pSecondGrab->device))
451 return FALSE;
452 }
453 else if (pSecondGrab->device == inputInfo.all_master_devices) {
454 if (pFirstGrab->device != inputInfo.all_master_devices &&
455 !IsMaster(pFirstGrab->device))
456 return FALSE;
457 }
458 else if (pSecondGrab->device != pFirstGrab->device)
459 return FALSE;
460 }
461 else if (!ignoreDevice &&
462 ((pFirstGrab->device != pSecondGrab->device) ||
463 (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice)))
464 return FALSE;
465
466 if (pFirstGrab->type != pSecondGrab->type)
467 return FALSE;
468
469 if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) ||
470 GrabSupersedesSecond(pSecondGrab, pFirstGrab))
471 return TRUE;
472
473 if (DetailSupersedesSecond(pSecondGrab->detail, pFirstGrab->detail,
474 (unsigned int) AnyKey)
475 &&
476 DetailSupersedesSecond(pFirstGrab->modifiersDetail,
477 pSecondGrab->modifiersDetail, any_modifier))
478 return TRUE;
479
480 if (DetailSupersedesSecond(pFirstGrab->detail, pSecondGrab->detail,
481 (unsigned int) AnyKey)
482 &&
483 DetailSupersedesSecond(pSecondGrab->modifiersDetail,
484 pFirstGrab->modifiersDetail, any_modifier))
485 return TRUE;
486
487 return FALSE;
488}
489
490static Bool
491GrabsAreIdentical(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
492{
493 unsigned int any_modifier = (pFirstGrab->grabtype == XI2) ?
494 (unsigned int) XIAnyModifier : (unsigned int) AnyModifier;
495
496 if (pFirstGrab->grabtype != pSecondGrab->grabtype)
497 return FALSE;
498
499 if (pFirstGrab->device != pSecondGrab->device ||
500 (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) ||
501 (pFirstGrab->type != pSecondGrab->type))
502 return FALSE;
503
504 if (!(DetailSupersedesSecond(pFirstGrab->detail,
505 pSecondGrab->detail,
506 (unsigned int) AnyKey) &&
507 DetailSupersedesSecond(pSecondGrab->detail,
508 pFirstGrab->detail, (unsigned int) AnyKey)))
509 return FALSE;
510
511 if (!(DetailSupersedesSecond(pFirstGrab->modifiersDetail,
512 pSecondGrab->modifiersDetail,
513 any_modifier) &&
514 DetailSupersedesSecond(pSecondGrab->modifiersDetail,
515 pFirstGrab->modifiersDetail, any_modifier)))
516 return FALSE;
517
518 return TRUE;
519}
520
521/**
522 * Prepend the new grab to the list of passive grabs on the window.
523 * Any previously existing grab that matches the new grab will be removed.
524 * Adding a new grab that would override another client's grab will result in
525 * a BadAccess.
526 *
527 * @return Success or X error code on failure.
528 */
529int
530AddPassiveGrabToList(ClientPtr client, GrabPtr pGrab)
531{
532 GrabPtr grab;
533 Mask access_mode = DixGrabAccess;
534 int rc;
535
536 for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) {
537 if (GrabMatchesSecond(pGrab, grab, (pGrab->grabtype == CORE))) {
538 if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource)) {
539 FreeGrab(pGrab);
540 return BadAccess;
541 }
542 }
543 }
544
545 if (pGrab->keyboardMode == GrabModeSync ||
546 pGrab->pointerMode == GrabModeSync)
547 access_mode |= DixFreezeAccess;
548 rc = XaceHook(XACE_DEVICE_ACCESS, client, pGrab->device, access_mode);
549 if (rc != Success)
550 return rc;
551
552 /* Remove all grabs that match the new one exactly */
553 for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) {
554 if (GrabsAreIdentical(pGrab, grab)) {
555 DeletePassiveGrabFromList(grab);
556 break;
557 }
558 }
559
560 if (!pGrab->window->optional && !MakeWindowOptional(pGrab->window)) {
561 FreeGrab(pGrab);
562 return BadAlloc;
563 }
564
565 pGrab->next = pGrab->window->optional->passiveGrabs;
566 pGrab->window->optional->passiveGrabs = pGrab;
567 if (AddResource(pGrab->resource, RT_PASSIVEGRAB, (pointer) pGrab))
568 return Success;
569 return BadAlloc;
570}
571
572/* the following is kinda complicated, because we need to be able to back out
573 * if any allocation fails
574 */
575
576Bool
577DeletePassiveGrabFromList(GrabPtr pMinuendGrab)
578{
579 GrabPtr grab;
580 GrabPtr *deletes, *adds;
581 Mask ***updates, **details;
582 int i, ndels, nadds, nups;
583 Bool ok;
584 unsigned int any_modifier;
585 unsigned int any_key;
586
587#define UPDATE(mask,exact) \
588 if (!(details[nups] = DeleteDetailFromMask(mask, exact))) \
589 ok = FALSE; \
590 else \
591 updates[nups++] = &(mask)
592
593 i = 0;
594 for (grab = wPassiveGrabs(pMinuendGrab->window); grab; grab = grab->next)
595 i++;
596 if (!i)
597 return TRUE;
598 deletes = malloc(i * sizeof(GrabPtr));
599 adds = malloc(i * sizeof(GrabPtr));
600 updates = malloc(i * sizeof(Mask **));
601 details = malloc(i * sizeof(Mask *));
602 if (!deletes || !adds || !updates || !details) {
603 free(details);
604 free(updates);
605 free(adds);
606 free(deletes);
607 return FALSE;
608 }
609
610 any_modifier = (pMinuendGrab->grabtype == XI2) ?
611 (unsigned int) XIAnyModifier : (unsigned int) AnyModifier;
612 any_key = (pMinuendGrab->grabtype == XI2) ?
613 (unsigned int) XIAnyKeycode : (unsigned int) AnyKey;
614 ndels = nadds = nups = 0;
615 ok = TRUE;
616 for (grab = wPassiveGrabs(pMinuendGrab->window);
617 grab && ok; grab = grab->next) {
618 if ((CLIENT_BITS(grab->resource) != CLIENT_BITS(pMinuendGrab->resource))
619 || !GrabMatchesSecond(grab, pMinuendGrab, (grab->grabtype == CORE)))
620 continue;
621 if (GrabSupersedesSecond(pMinuendGrab, grab)) {
622 deletes[ndels++] = grab;
623 }
624 else if ((grab->detail.exact == any_key)
625 && (grab->modifiersDetail.exact != any_modifier)) {
626 UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
627 }
628 else if ((grab->modifiersDetail.exact == any_modifier)
629 && (grab->detail.exact != any_key)) {
630 UPDATE(grab->modifiersDetail.pMask,
631 pMinuendGrab->modifiersDetail.exact);
632 }
633 else if ((pMinuendGrab->detail.exact != any_key)
634 && (pMinuendGrab->modifiersDetail.exact != any_modifier)) {
635 GrabPtr pNewGrab;
636 GrabParameters param;
637
638 UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
639
640 memset(&param, 0, sizeof(param));
641 param.ownerEvents = grab->ownerEvents;
642 param.this_device_mode = grab->keyboardMode;
643 param.other_devices_mode = grab->pointerMode;
644 param.modifiers = any_modifier;
645
646 pNewGrab = CreateGrab(CLIENT_ID(grab->resource), grab->device,
647 grab->modifierDevice, grab->window,
648 grab->grabtype,
649 (GrabMask *) &grab->eventMask,
650 &param, (int) grab->type,
651 pMinuendGrab->detail.exact,
652 grab->confineTo, grab->cursor);
653 if (!pNewGrab)
654 ok = FALSE;
655 else if (!(pNewGrab->modifiersDetail.pMask =
656 DeleteDetailFromMask(grab->modifiersDetail.pMask,
657 pMinuendGrab->modifiersDetail.
658 exact))
659 || (!pNewGrab->window->optional &&
660 !MakeWindowOptional(pNewGrab->window))) {
661 FreeGrab(pNewGrab);
662 ok = FALSE;
663 }
664 else if (!AddResource(pNewGrab->resource, RT_PASSIVEGRAB,
665 (pointer) pNewGrab))
666 ok = FALSE;
667 else
668 adds[nadds++] = pNewGrab;
669 }
670 else if (pMinuendGrab->detail.exact == any_key) {
671 UPDATE(grab->modifiersDetail.pMask,
672 pMinuendGrab->modifiersDetail.exact);
673 }
674 else {
675 UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
676 }
677 }
678
679 if (!ok) {
680 for (i = 0; i < nadds; i++)
681 FreeResource(adds[i]->resource, RT_NONE);
682 for (i = 0; i < nups; i++)
683 free(details[i]);
684 }
685 else {
686 for (i = 0; i < ndels; i++)
687 FreeResource(deletes[i]->resource, RT_NONE);
688 for (i = 0; i < nadds; i++) {
689 grab = adds[i];
690 grab->next = grab->window->optional->passiveGrabs;
691 grab->window->optional->passiveGrabs = grab;
692 }
693 for (i = 0; i < nups; i++) {
694 free(*updates[i]);
695 *updates[i] = details[i];
696 }
697 }
698 free(details);
699 free(updates);
700 free(adds);
701 free(deletes);
702 return ok;
703
704#undef UPDATE
705}
706
707Bool
708GrabIsPointerGrab(GrabPtr grab)
709{
710 return (grab->type == ButtonPress ||
711 grab->type == DeviceButtonPress || grab->type == XI_ButtonPress);
712}
713
714Bool
715GrabIsKeyboardGrab(GrabPtr grab)
716{
717 return (grab->type == KeyPress ||
718 grab->type == DeviceKeyPress || grab->type == XI_KeyPress);
719}