grabs.c revision 6747b715
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 27 28Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, 29 30 All Rights Reserved 31 32Permission to use, copy, modify, and distribute this software and its 33documentation for any purpose and without fee is hereby granted, 34provided that the above copyright notice appear in all copies and that 35both that copyright notice and this permission notice appear in 36supporting documentation, and that the name of Digital not be 37used in advertising or publicity pertaining to distribution of the 38software without specific, written prior permission. 39DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 40ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 41DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 42ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 43WHETHER IN AN action OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 44ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 45SOFTWARE. 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 64#define BITMASK(i) (((Mask)1) << ((i) & 31)) 65#define MASKIDX(i) ((i) >> 5) 66#define MASKWORD(buf, i) buf[MASKIDX(i)] 67#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i) 68#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i) 69#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i)) 70 71GrabPtr 72CreateGrab( 73 int client, 74 DeviceIntPtr device, 75 DeviceIntPtr modDevice, 76 WindowPtr window, 77 GrabType grabtype, 78 GrabMask *mask, 79 GrabParameters *param, 80 int type, 81 KeyCode keybut, /* key or button */ 82 WindowPtr confineTo, 83 CursorPtr cursor) 84{ 85 GrabPtr grab; 86 87 grab = calloc(1, sizeof(GrabRec)); 88 if (!grab) 89 return (GrabPtr)NULL; 90 grab->resource = FakeClientID(client); 91 grab->device = device; 92 grab->window = window; 93 grab->eventMask = mask->core; /* same for XI */ 94 grab->deviceMask = 0; 95 grab->ownerEvents = param->ownerEvents; 96 grab->keyboardMode = param->this_device_mode; 97 grab->pointerMode = param->other_devices_mode; 98 grab->modifiersDetail.exact = param->modifiers; 99 grab->modifiersDetail.pMask = NULL; 100 grab->modifierDevice = modDevice; 101 grab->type = type; 102 grab->grabtype = grabtype; 103 grab->detail.exact = keybut; 104 grab->detail.pMask = NULL; 105 grab->confineTo = confineTo; 106 grab->cursor = cursor; 107 grab->next = NULL; 108 109 if (grabtype == GRABTYPE_XI2) 110 memcpy(grab->xi2mask, mask->xi2mask, sizeof(mask->xi2mask)); 111 if (cursor) 112 cursor->refcnt++; 113 return grab; 114 115} 116 117static void 118FreeGrab(GrabPtr pGrab) 119{ 120 if (pGrab->modifiersDetail.pMask != NULL) 121 free(pGrab->modifiersDetail.pMask); 122 123 if (pGrab->detail.pMask != NULL) 124 free(pGrab->detail.pMask); 125 126 if (pGrab->cursor) 127 FreeCursor(pGrab->cursor, (Cursor)0); 128 129 free(pGrab); 130} 131 132int 133DeletePassiveGrab(pointer value, XID id) 134{ 135 GrabPtr g, prev; 136 GrabPtr pGrab = (GrabPtr)value; 137 138 /* it is OK if the grab isn't found */ 139 prev = 0; 140 for (g = (wPassiveGrabs (pGrab->window)); g; g = g->next) 141 { 142 if (pGrab == g) 143 { 144 if (prev) 145 prev->next = g->next; 146 else 147 if (!(pGrab->window->optional->passiveGrabs = g->next)) 148 CheckWindowOptionalNeed (pGrab->window); 149 break; 150 } 151 prev = g; 152 } 153 FreeGrab(pGrab); 154 return Success; 155} 156 157static Mask * 158DeleteDetailFromMask(Mask *pDetailMask, unsigned int detail) 159{ 160 Mask *mask; 161 int i; 162 163 mask = malloc(sizeof(Mask) * MasksPerDetailMask); 164 if (mask) 165 { 166 if (pDetailMask) 167 for (i = 0; i < MasksPerDetailMask; i++) 168 mask[i]= pDetailMask[i]; 169 else 170 for (i = 0; i < MasksPerDetailMask; i++) 171 mask[i]= ~0L; 172 BITCLEAR(mask, detail); 173 } 174 return mask; 175} 176 177static Bool 178IsInGrabMask( 179 DetailRec firstDetail, 180 DetailRec secondDetail, 181 unsigned int exception) 182{ 183 if (firstDetail.exact == exception) 184 { 185 if (firstDetail.pMask == NULL) 186 return TRUE; 187 188 /* (at present) never called with two non-null pMasks */ 189 if (secondDetail.exact == exception) 190 return FALSE; 191 192 if (GETBIT(firstDetail.pMask, secondDetail.exact)) 193 return TRUE; 194 } 195 196 return FALSE; 197} 198 199static Bool 200IdenticalExactDetails( 201 unsigned int firstExact, 202 unsigned int secondExact, 203 unsigned int exception) 204{ 205 if ((firstExact == exception) || (secondExact == exception)) 206 return FALSE; 207 208 if (firstExact == secondExact) 209 return TRUE; 210 211 return FALSE; 212} 213 214static Bool 215DetailSupersedesSecond( 216 DetailRec firstDetail, 217 DetailRec secondDetail, 218 unsigned int exception) 219{ 220 if (IsInGrabMask(firstDetail, secondDetail, exception)) 221 return TRUE; 222 223 if (IdenticalExactDetails(firstDetail.exact, secondDetail.exact, 224 exception)) 225 return TRUE; 226 227 return FALSE; 228} 229 230static Bool 231GrabSupersedesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab) 232{ 233 unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ? 234 (unsigned int)XIAnyModifier : 235 (unsigned int)AnyModifier; 236 if (!DetailSupersedesSecond(pFirstGrab->modifiersDetail, 237 pSecondGrab->modifiersDetail, 238 any_modifier)) 239 return FALSE; 240 241 if (DetailSupersedesSecond(pFirstGrab->detail, 242 pSecondGrab->detail, (unsigned int)AnyKey)) 243 return TRUE; 244 245 return FALSE; 246} 247 248/** 249 * Compares two grabs and returns TRUE if the first grab matches the second 250 * grab. 251 * 252 * A match is when 253 * - the devices set for the grab are equal (this is optional). 254 * - the event types for both grabs are equal. 255 * - XXX 256 * 257 * @param ignoreDevice TRUE if the device settings on the grabs are to be 258 * ignored. 259 * @return TRUE if the grabs match or FALSE otherwise. 260 */ 261Bool 262GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab, Bool ignoreDevice) 263{ 264 unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ? 265 (unsigned int)XIAnyModifier : 266 (unsigned int)AnyModifier; 267 268 if (pFirstGrab->grabtype != pSecondGrab->grabtype) 269 return FALSE; 270 271 if (pFirstGrab->grabtype == GRABTYPE_XI2) 272 { 273 if (pFirstGrab->device == inputInfo.all_devices || 274 pSecondGrab->device == inputInfo.all_devices) 275 { 276 /* do nothing */ 277 } else if (pFirstGrab->device == inputInfo.all_master_devices) 278 { 279 if (pSecondGrab->device != inputInfo.all_master_devices && 280 !IsMaster(pSecondGrab->device)) 281 return FALSE; 282 } else if (pSecondGrab->device == inputInfo.all_master_devices) 283 { 284 if (pFirstGrab->device != inputInfo.all_master_devices && 285 !IsMaster(pFirstGrab->device)) 286 return FALSE; 287 } else if (pSecondGrab->device != pFirstGrab->device) 288 return FALSE; 289 } else if (!ignoreDevice && 290 ((pFirstGrab->device != pSecondGrab->device) || 291 (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice))) 292 return FALSE; 293 294 if (pFirstGrab->type != pSecondGrab->type) 295 return FALSE; 296 297 if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) || 298 GrabSupersedesSecond(pSecondGrab, pFirstGrab)) 299 return TRUE; 300 301 if (DetailSupersedesSecond(pSecondGrab->detail, pFirstGrab->detail, 302 (unsigned int)AnyKey) 303 && 304 DetailSupersedesSecond(pFirstGrab->modifiersDetail, 305 pSecondGrab->modifiersDetail, 306 any_modifier)) 307 return TRUE; 308 309 if (DetailSupersedesSecond(pFirstGrab->detail, pSecondGrab->detail, 310 (unsigned int)AnyKey) 311 && 312 DetailSupersedesSecond(pSecondGrab->modifiersDetail, 313 pFirstGrab->modifiersDetail, 314 any_modifier)) 315 return TRUE; 316 317 return FALSE; 318} 319 320static Bool 321GrabsAreIdentical(GrabPtr pFirstGrab, GrabPtr pSecondGrab) 322{ 323 unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ? 324 (unsigned int)XIAnyModifier : 325 (unsigned int)AnyModifier; 326 327 if (pFirstGrab->grabtype != pSecondGrab->grabtype) 328 return FALSE; 329 330 if (pFirstGrab->device != pSecondGrab->device || 331 (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) || 332 (pFirstGrab->type != pSecondGrab->type)) 333 return FALSE; 334 335 if (!(DetailSupersedesSecond(pFirstGrab->detail, 336 pSecondGrab->detail, 337 (unsigned int)AnyKey) && 338 DetailSupersedesSecond(pSecondGrab->detail, 339 pFirstGrab->detail, 340 (unsigned int)AnyKey))) 341 return FALSE; 342 343 344 if (!(DetailSupersedesSecond(pFirstGrab->modifiersDetail, 345 pSecondGrab->modifiersDetail, 346 any_modifier) && 347 DetailSupersedesSecond(pSecondGrab->modifiersDetail, 348 pFirstGrab->modifiersDetail, 349 any_modifier))) 350 return FALSE; 351 352 return TRUE; 353} 354 355 356/** 357 * Prepend the new grab to the list of passive grabs on the window. 358 * Any previously existing grab that matches the new grab will be removed. 359 * Adding a new grab that would override another client's grab will result in 360 * a BadAccess. 361 * 362 * @return Success or X error code on failure. 363 */ 364int 365AddPassiveGrabToList(ClientPtr client, GrabPtr pGrab) 366{ 367 GrabPtr grab; 368 Mask access_mode = DixGrabAccess; 369 int rc; 370 371 for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) 372 { 373 if (GrabMatchesSecond(pGrab, grab, FALSE)) 374 { 375 if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource)) 376 { 377 FreeGrab(pGrab); 378 return BadAccess; 379 } 380 } 381 } 382 383 if (pGrab->keyboardMode == GrabModeSync||pGrab->pointerMode == GrabModeSync) 384 access_mode |= DixFreezeAccess; 385 rc = XaceHook(XACE_DEVICE_ACCESS, client, pGrab->device, access_mode); 386 if (rc != Success) 387 return rc; 388 389 /* Remove all grabs that match the new one exactly */ 390 for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) 391 { 392 if (GrabsAreIdentical(pGrab, grab)) 393 { 394 DeletePassiveGrabFromList(grab); 395 break; 396 } 397 } 398 399 if (!pGrab->window->optional && !MakeWindowOptional (pGrab->window)) 400 { 401 FreeGrab(pGrab); 402 return BadAlloc; 403 } 404 405 pGrab->next = pGrab->window->optional->passiveGrabs; 406 pGrab->window->optional->passiveGrabs = pGrab; 407 if (AddResource(pGrab->resource, RT_PASSIVEGRAB, (pointer)pGrab)) 408 return Success; 409 return BadAlloc; 410} 411 412/* the following is kinda complicated, because we need to be able to back out 413 * if any allocation fails 414 */ 415 416Bool 417DeletePassiveGrabFromList(GrabPtr pMinuendGrab) 418{ 419 GrabPtr grab; 420 GrabPtr *deletes, *adds; 421 Mask ***updates, **details; 422 int i, ndels, nadds, nups; 423 Bool ok; 424 unsigned int any_modifier; 425 unsigned int any_key; 426 427#define UPDATE(mask,exact) \ 428 if (!(details[nups] = DeleteDetailFromMask(mask, exact))) \ 429 ok = FALSE; \ 430 else \ 431 updates[nups++] = &(mask) 432 433 i = 0; 434 for (grab = wPassiveGrabs(pMinuendGrab->window); grab; grab = grab->next) 435 i++; 436 if (!i) 437 return TRUE; 438 deletes = malloc(i * sizeof(GrabPtr)); 439 adds = malloc(i * sizeof(GrabPtr)); 440 updates = malloc(i * sizeof(Mask **)); 441 details = malloc(i * sizeof(Mask *)); 442 if (!deletes || !adds || !updates || !details) 443 { 444 free(details); 445 free(updates); 446 free(adds); 447 free(deletes); 448 return FALSE; 449 } 450 451 any_modifier = (pMinuendGrab->grabtype == GRABTYPE_XI2) ? 452 (unsigned int)XIAnyModifier : (unsigned int)AnyModifier; 453 any_key = (pMinuendGrab->grabtype == GRABTYPE_XI2) ? 454 (unsigned int)XIAnyKeycode : (unsigned int)AnyKey; 455 ndels = nadds = nups = 0; 456 ok = TRUE; 457 for (grab = wPassiveGrabs(pMinuendGrab->window); 458 grab && ok; 459 grab = grab->next) 460 { 461 if ((CLIENT_BITS(grab->resource) != CLIENT_BITS(pMinuendGrab->resource)) || 462 !GrabMatchesSecond(grab, pMinuendGrab, 463 (grab->grabtype == GRABTYPE_CORE))) 464 continue; 465 if (GrabSupersedesSecond(pMinuendGrab, grab)) 466 { 467 deletes[ndels++] = grab; 468 } 469 else if ((grab->detail.exact == any_key) 470 && (grab->modifiersDetail.exact != any_modifier)) 471 { 472 UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); 473 } 474 else if ((grab->modifiersDetail.exact == any_modifier) 475 && (grab->detail.exact != any_key)) 476 { 477 UPDATE(grab->modifiersDetail.pMask, 478 pMinuendGrab->modifiersDetail.exact); 479 } 480 else if ((pMinuendGrab->detail.exact != any_key) 481 && (pMinuendGrab->modifiersDetail.exact != any_modifier)) 482 { 483 GrabPtr pNewGrab; 484 GrabParameters param; 485 486 UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); 487 488 memset(¶m, 0, sizeof(param)); 489 param.ownerEvents = grab->ownerEvents; 490 param.this_device_mode = grab->keyboardMode; 491 param.other_devices_mode = grab->pointerMode; 492 param.modifiers = any_modifier; 493 494 pNewGrab = CreateGrab(CLIENT_ID(grab->resource), grab->device, 495 grab->modifierDevice, grab->window, 496 grab->grabtype, 497 (GrabMask*)&grab->eventMask, 498 ¶m, (int)grab->type, 499 pMinuendGrab->detail.exact, 500 grab->confineTo, grab->cursor); 501 if (!pNewGrab) 502 ok = FALSE; 503 else if (!(pNewGrab->modifiersDetail.pMask = 504 DeleteDetailFromMask(grab->modifiersDetail.pMask, 505 pMinuendGrab->modifiersDetail.exact)) 506 || 507 (!pNewGrab->window->optional && 508 !MakeWindowOptional(pNewGrab->window))) 509 { 510 FreeGrab(pNewGrab); 511 ok = FALSE; 512 } 513 else if (!AddResource(pNewGrab->resource, RT_PASSIVEGRAB, 514 (pointer)pNewGrab)) 515 ok = FALSE; 516 else 517 adds[nadds++] = pNewGrab; 518 } 519 else if (pMinuendGrab->detail.exact == any_key) 520 { 521 UPDATE(grab->modifiersDetail.pMask, 522 pMinuendGrab->modifiersDetail.exact); 523 } 524 else 525 { 526 UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); 527 } 528 } 529 530 if (!ok) 531 { 532 for (i = 0; i < nadds; i++) 533 FreeResource(adds[i]->resource, RT_NONE); 534 for (i = 0; i < nups; i++) 535 free(details[i]); 536 } 537 else 538 { 539 for (i = 0; i < ndels; i++) 540 FreeResource(deletes[i]->resource, RT_NONE); 541 for (i = 0; i < nadds; i++) 542 { 543 grab = adds[i]; 544 grab->next = grab->window->optional->passiveGrabs; 545 grab->window->optional->passiveGrabs = grab; 546 } 547 for (i = 0; i < nups; i++) 548 { 549 free(*updates[i]); 550 *updates[i] = details[i]; 551 } 552 } 553 free(details); 554 free(updates); 555 free(adds); 556 free(deletes); 557 return ok; 558 559#undef UPDATE 560} 561