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(¶m, 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 ¶m, (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