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 free(pGrab->modifiersDetail.pMask); 121 free(pGrab->detail.pMask); 122 123 if (pGrab->cursor) 124 FreeCursor(pGrab->cursor, (Cursor)0); 125 126 free(pGrab); 127} 128 129int 130DeletePassiveGrab(pointer value, XID id) 131{ 132 GrabPtr g, prev; 133 GrabPtr pGrab = (GrabPtr)value; 134 135 /* it is OK if the grab isn't found */ 136 prev = 0; 137 for (g = (wPassiveGrabs (pGrab->window)); g; g = g->next) 138 { 139 if (pGrab == g) 140 { 141 if (prev) 142 prev->next = g->next; 143 else 144 if (!(pGrab->window->optional->passiveGrabs = g->next)) 145 CheckWindowOptionalNeed (pGrab->window); 146 break; 147 } 148 prev = g; 149 } 150 FreeGrab(pGrab); 151 return Success; 152} 153 154static Mask * 155DeleteDetailFromMask(Mask *pDetailMask, unsigned int detail) 156{ 157 Mask *mask; 158 int i; 159 160 mask = malloc(sizeof(Mask) * MasksPerDetailMask); 161 if (mask) 162 { 163 if (pDetailMask) 164 for (i = 0; i < MasksPerDetailMask; i++) 165 mask[i]= pDetailMask[i]; 166 else 167 for (i = 0; i < MasksPerDetailMask; i++) 168 mask[i]= ~0L; 169 BITCLEAR(mask, detail); 170 } 171 return mask; 172} 173 174static Bool 175IsInGrabMask( 176 DetailRec firstDetail, 177 DetailRec secondDetail, 178 unsigned int exception) 179{ 180 if (firstDetail.exact == exception) 181 { 182 if (firstDetail.pMask == NULL) 183 return TRUE; 184 185 /* (at present) never called with two non-null pMasks */ 186 if (secondDetail.exact == exception) 187 return FALSE; 188 189 if (GETBIT(firstDetail.pMask, secondDetail.exact)) 190 return TRUE; 191 } 192 193 return FALSE; 194} 195 196static Bool 197IdenticalExactDetails( 198 unsigned int firstExact, 199 unsigned int secondExact, 200 unsigned int exception) 201{ 202 if ((firstExact == exception) || (secondExact == exception)) 203 return FALSE; 204 205 if (firstExact == secondExact) 206 return TRUE; 207 208 return FALSE; 209} 210 211static Bool 212DetailSupersedesSecond( 213 DetailRec firstDetail, 214 DetailRec secondDetail, 215 unsigned int exception) 216{ 217 if (IsInGrabMask(firstDetail, secondDetail, exception)) 218 return TRUE; 219 220 if (IdenticalExactDetails(firstDetail.exact, secondDetail.exact, 221 exception)) 222 return TRUE; 223 224 return FALSE; 225} 226 227static Bool 228GrabSupersedesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab) 229{ 230 unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ? 231 (unsigned int)XIAnyModifier : 232 (unsigned int)AnyModifier; 233 if (!DetailSupersedesSecond(pFirstGrab->modifiersDetail, 234 pSecondGrab->modifiersDetail, 235 any_modifier)) 236 return FALSE; 237 238 if (DetailSupersedesSecond(pFirstGrab->detail, 239 pSecondGrab->detail, (unsigned int)AnyKey)) 240 return TRUE; 241 242 return FALSE; 243} 244 245/** 246 * Compares two grabs and returns TRUE if the first grab matches the second 247 * grab. 248 * 249 * A match is when 250 * - the devices set for the grab are equal (this is optional). 251 * - the event types for both grabs are equal. 252 * - XXX 253 * 254 * @param ignoreDevice TRUE if the device settings on the grabs are to be 255 * ignored. 256 * @return TRUE if the grabs match or FALSE otherwise. 257 */ 258Bool 259GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab, Bool ignoreDevice) 260{ 261 unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ? 262 (unsigned int)XIAnyModifier : 263 (unsigned int)AnyModifier; 264 265 if (pFirstGrab->grabtype != pSecondGrab->grabtype) 266 return FALSE; 267 268 if (pFirstGrab->grabtype == GRABTYPE_XI2) 269 { 270 if (pFirstGrab->device == inputInfo.all_devices || 271 pSecondGrab->device == inputInfo.all_devices) 272 { 273 /* do nothing */ 274 } else if (pFirstGrab->device == inputInfo.all_master_devices) 275 { 276 if (pSecondGrab->device != inputInfo.all_master_devices && 277 !IsMaster(pSecondGrab->device)) 278 return FALSE; 279 } else if (pSecondGrab->device == inputInfo.all_master_devices) 280 { 281 if (pFirstGrab->device != inputInfo.all_master_devices && 282 !IsMaster(pFirstGrab->device)) 283 return FALSE; 284 } else if (pSecondGrab->device != pFirstGrab->device) 285 return FALSE; 286 } else if (!ignoreDevice && 287 ((pFirstGrab->device != pSecondGrab->device) || 288 (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice))) 289 return FALSE; 290 291 if (pFirstGrab->type != pSecondGrab->type) 292 return FALSE; 293 294 if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) || 295 GrabSupersedesSecond(pSecondGrab, pFirstGrab)) 296 return TRUE; 297 298 if (DetailSupersedesSecond(pSecondGrab->detail, pFirstGrab->detail, 299 (unsigned int)AnyKey) 300 && 301 DetailSupersedesSecond(pFirstGrab->modifiersDetail, 302 pSecondGrab->modifiersDetail, 303 any_modifier)) 304 return TRUE; 305 306 if (DetailSupersedesSecond(pFirstGrab->detail, pSecondGrab->detail, 307 (unsigned int)AnyKey) 308 && 309 DetailSupersedesSecond(pSecondGrab->modifiersDetail, 310 pFirstGrab->modifiersDetail, 311 any_modifier)) 312 return TRUE; 313 314 return FALSE; 315} 316 317static Bool 318GrabsAreIdentical(GrabPtr pFirstGrab, GrabPtr pSecondGrab) 319{ 320 unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ? 321 (unsigned int)XIAnyModifier : 322 (unsigned int)AnyModifier; 323 324 if (pFirstGrab->grabtype != pSecondGrab->grabtype) 325 return FALSE; 326 327 if (pFirstGrab->device != pSecondGrab->device || 328 (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) || 329 (pFirstGrab->type != pSecondGrab->type)) 330 return FALSE; 331 332 if (!(DetailSupersedesSecond(pFirstGrab->detail, 333 pSecondGrab->detail, 334 (unsigned int)AnyKey) && 335 DetailSupersedesSecond(pSecondGrab->detail, 336 pFirstGrab->detail, 337 (unsigned int)AnyKey))) 338 return FALSE; 339 340 341 if (!(DetailSupersedesSecond(pFirstGrab->modifiersDetail, 342 pSecondGrab->modifiersDetail, 343 any_modifier) && 344 DetailSupersedesSecond(pSecondGrab->modifiersDetail, 345 pFirstGrab->modifiersDetail, 346 any_modifier))) 347 return FALSE; 348 349 return TRUE; 350} 351 352 353/** 354 * Prepend the new grab to the list of passive grabs on the window. 355 * Any previously existing grab that matches the new grab will be removed. 356 * Adding a new grab that would override another client's grab will result in 357 * a BadAccess. 358 * 359 * @return Success or X error code on failure. 360 */ 361int 362AddPassiveGrabToList(ClientPtr client, GrabPtr pGrab) 363{ 364 GrabPtr grab; 365 Mask access_mode = DixGrabAccess; 366 int rc; 367 368 for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) 369 { 370 if (GrabMatchesSecond(pGrab, grab, FALSE)) 371 { 372 if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource)) 373 { 374 FreeGrab(pGrab); 375 return BadAccess; 376 } 377 } 378 } 379 380 if (pGrab->keyboardMode == GrabModeSync||pGrab->pointerMode == GrabModeSync) 381 access_mode |= DixFreezeAccess; 382 rc = XaceHook(XACE_DEVICE_ACCESS, client, pGrab->device, access_mode); 383 if (rc != Success) 384 return rc; 385 386 /* Remove all grabs that match the new one exactly */ 387 for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) 388 { 389 if (GrabsAreIdentical(pGrab, grab)) 390 { 391 DeletePassiveGrabFromList(grab); 392 break; 393 } 394 } 395 396 if (!pGrab->window->optional && !MakeWindowOptional (pGrab->window)) 397 { 398 FreeGrab(pGrab); 399 return BadAlloc; 400 } 401 402 pGrab->next = pGrab->window->optional->passiveGrabs; 403 pGrab->window->optional->passiveGrabs = pGrab; 404 if (AddResource(pGrab->resource, RT_PASSIVEGRAB, (pointer)pGrab)) 405 return Success; 406 return BadAlloc; 407} 408 409/* the following is kinda complicated, because we need to be able to back out 410 * if any allocation fails 411 */ 412 413Bool 414DeletePassiveGrabFromList(GrabPtr pMinuendGrab) 415{ 416 GrabPtr grab; 417 GrabPtr *deletes, *adds; 418 Mask ***updates, **details; 419 int i, ndels, nadds, nups; 420 Bool ok; 421 unsigned int any_modifier; 422 unsigned int any_key; 423 424#define UPDATE(mask,exact) \ 425 if (!(details[nups] = DeleteDetailFromMask(mask, exact))) \ 426 ok = FALSE; \ 427 else \ 428 updates[nups++] = &(mask) 429 430 i = 0; 431 for (grab = wPassiveGrabs(pMinuendGrab->window); grab; grab = grab->next) 432 i++; 433 if (!i) 434 return TRUE; 435 deletes = malloc(i * sizeof(GrabPtr)); 436 adds = malloc(i * sizeof(GrabPtr)); 437 updates = malloc(i * sizeof(Mask **)); 438 details = malloc(i * sizeof(Mask *)); 439 if (!deletes || !adds || !updates || !details) 440 { 441 free(details); 442 free(updates); 443 free(adds); 444 free(deletes); 445 return FALSE; 446 } 447 448 any_modifier = (pMinuendGrab->grabtype == GRABTYPE_XI2) ? 449 (unsigned int)XIAnyModifier : (unsigned int)AnyModifier; 450 any_key = (pMinuendGrab->grabtype == GRABTYPE_XI2) ? 451 (unsigned int)XIAnyKeycode : (unsigned int)AnyKey; 452 ndels = nadds = nups = 0; 453 ok = TRUE; 454 for (grab = wPassiveGrabs(pMinuendGrab->window); 455 grab && ok; 456 grab = grab->next) 457 { 458 if ((CLIENT_BITS(grab->resource) != CLIENT_BITS(pMinuendGrab->resource)) || 459 !GrabMatchesSecond(grab, pMinuendGrab, 460 (grab->grabtype == GRABTYPE_CORE))) 461 continue; 462 if (GrabSupersedesSecond(pMinuendGrab, grab)) 463 { 464 deletes[ndels++] = grab; 465 } 466 else if ((grab->detail.exact == any_key) 467 && (grab->modifiersDetail.exact != any_modifier)) 468 { 469 UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); 470 } 471 else if ((grab->modifiersDetail.exact == any_modifier) 472 && (grab->detail.exact != any_key)) 473 { 474 UPDATE(grab->modifiersDetail.pMask, 475 pMinuendGrab->modifiersDetail.exact); 476 } 477 else if ((pMinuendGrab->detail.exact != any_key) 478 && (pMinuendGrab->modifiersDetail.exact != any_modifier)) 479 { 480 GrabPtr pNewGrab; 481 GrabParameters param; 482 483 UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); 484 485 memset(¶m, 0, sizeof(param)); 486 param.ownerEvents = grab->ownerEvents; 487 param.this_device_mode = grab->keyboardMode; 488 param.other_devices_mode = grab->pointerMode; 489 param.modifiers = any_modifier; 490 491 pNewGrab = CreateGrab(CLIENT_ID(grab->resource), grab->device, 492 grab->modifierDevice, grab->window, 493 grab->grabtype, 494 (GrabMask*)&grab->eventMask, 495 ¶m, (int)grab->type, 496 pMinuendGrab->detail.exact, 497 grab->confineTo, grab->cursor); 498 if (!pNewGrab) 499 ok = FALSE; 500 else if (!(pNewGrab->modifiersDetail.pMask = 501 DeleteDetailFromMask(grab->modifiersDetail.pMask, 502 pMinuendGrab->modifiersDetail.exact)) 503 || 504 (!pNewGrab->window->optional && 505 !MakeWindowOptional(pNewGrab->window))) 506 { 507 FreeGrab(pNewGrab); 508 ok = FALSE; 509 } 510 else if (!AddResource(pNewGrab->resource, RT_PASSIVEGRAB, 511 (pointer)pNewGrab)) 512 ok = FALSE; 513 else 514 adds[nadds++] = pNewGrab; 515 } 516 else if (pMinuendGrab->detail.exact == any_key) 517 { 518 UPDATE(grab->modifiersDetail.pMask, 519 pMinuendGrab->modifiersDetail.exact); 520 } 521 else 522 { 523 UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); 524 } 525 } 526 527 if (!ok) 528 { 529 for (i = 0; i < nadds; i++) 530 FreeResource(adds[i]->resource, RT_NONE); 531 for (i = 0; i < nups; i++) 532 free(details[i]); 533 } 534 else 535 { 536 for (i = 0; i < ndels; i++) 537 FreeResource(deletes[i]->resource, RT_NONE); 538 for (i = 0; i < nadds; i++) 539 { 540 grab = adds[i]; 541 grab->next = grab->window->optional->passiveGrabs; 542 grab->window->optional->passiveGrabs = grab; 543 } 544 for (i = 0; i < nups; i++) 545 { 546 free(*updates[i]); 547 *updates[i] = details[i]; 548 } 549 } 550 free(details); 551 free(updates); 552 free(adds); 553 free(deletes); 554 return ok; 555 556#undef UPDATE 557} 558