grabs.c revision 4642e01f
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#define NEED_EVENTS 56#include <X11/Xproto.h> 57#include "windowstr.h" 58#include "inputstr.h" 59#include "cursorstr.h" 60#include "dixgrabs.h" 61#include "xace.h" 62 63#define BITMASK(i) (((Mask)1) << ((i) & 31)) 64#define MASKIDX(i) ((i) >> 5) 65#define MASKWORD(buf, i) buf[MASKIDX(i)] 66#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i) 67#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i) 68#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i)) 69 70GrabPtr 71CreateGrab( 72 int client, 73 DeviceIntPtr device, 74 WindowPtr window, 75 Mask eventMask, 76 Bool ownerEvents, Bool keyboardMode, Bool pointerMode, 77 DeviceIntPtr modDevice, 78 unsigned short modifiers, 79 int type, 80 KeyCode keybut, /* key or button */ 81 WindowPtr confineTo, 82 CursorPtr cursor) 83{ 84 GrabPtr grab; 85 86 grab = (GrabPtr)xalloc(sizeof(GrabRec)); 87 if (!grab) 88 return (GrabPtr)NULL; 89 grab->resource = FakeClientID(client); 90 grab->device = device; 91 grab->coreGrab = (type < LASTEvent); 92 grab->window = window; 93 grab->eventMask = eventMask; 94 grab->deviceMask = 0; 95 grab->ownerEvents = ownerEvents; 96 grab->keyboardMode = keyboardMode; 97 grab->pointerMode = pointerMode; 98 grab->modifiersDetail.exact = modifiers; 99 grab->modifiersDetail.pMask = NULL; 100 grab->modifierDevice = modDevice; 101 grab->coreMods = ((modDevice == inputInfo.keyboard) || 102 (modDevice == inputInfo.pointer)); 103 grab->type = type; 104 grab->detail.exact = keybut; 105 grab->detail.pMask = NULL; 106 grab->confineTo = confineTo; 107 grab->cursor = cursor; 108 grab->genericMasks = NULL; 109 grab->next = NULL; 110 if (cursor) 111 cursor->refcnt++; 112 return grab; 113 114} 115 116static void 117FreeGrab(GrabPtr pGrab) 118{ 119 if (pGrab->modifiersDetail.pMask != NULL) 120 xfree(pGrab->modifiersDetail.pMask); 121 122 if (pGrab->detail.pMask != NULL) 123 xfree(pGrab->detail.pMask); 124 125 if (pGrab->cursor) 126 FreeCursor(pGrab->cursor, (Cursor)0); 127 128 xfree(pGrab); 129} 130 131int 132DeletePassiveGrab(pointer value, XID id) 133{ 134 GrabPtr g, prev; 135 GrabPtr pGrab = (GrabPtr)value; 136 137 /* it is OK if the grab isn't found */ 138 prev = 0; 139 for (g = (wPassiveGrabs (pGrab->window)); g; g = g->next) 140 { 141 if (pGrab == g) 142 { 143 if (prev) 144 prev->next = g->next; 145 else 146 if (!(pGrab->window->optional->passiveGrabs = g->next)) 147 CheckWindowOptionalNeed (pGrab->window); 148 break; 149 } 150 prev = g; 151 } 152 FreeGrab(pGrab); 153 return Success; 154} 155 156static Mask * 157DeleteDetailFromMask(Mask *pDetailMask, unsigned short detail) 158{ 159 Mask *mask; 160 int i; 161 162 mask = (Mask *)xalloc(sizeof(Mask) * MasksPerDetailMask); 163 if (mask) 164 { 165 if (pDetailMask) 166 for (i = 0; i < MasksPerDetailMask; i++) 167 mask[i]= pDetailMask[i]; 168 else 169 for (i = 0; i < MasksPerDetailMask; i++) 170 mask[i]= ~0L; 171 BITCLEAR(mask, detail); 172 } 173 return mask; 174} 175 176static Bool 177IsInGrabMask( 178 DetailRec firstDetail, 179 DetailRec secondDetail, 180 unsigned short exception) 181{ 182 if (firstDetail.exact == exception) 183 { 184 if (firstDetail.pMask == NULL) 185 return TRUE; 186 187 /* (at present) never called with two non-null pMasks */ 188 if (secondDetail.exact == exception) 189 return FALSE; 190 191 if (GETBIT(firstDetail.pMask, secondDetail.exact)) 192 return TRUE; 193 } 194 195 return FALSE; 196} 197 198static Bool 199IdenticalExactDetails( 200 unsigned short firstExact, 201 unsigned short secondExact, 202 unsigned short exception) 203{ 204 if ((firstExact == exception) || (secondExact == exception)) 205 return FALSE; 206 207 if (firstExact == secondExact) 208 return TRUE; 209 210 return FALSE; 211} 212 213static Bool 214DetailSupersedesSecond( 215 DetailRec firstDetail, 216 DetailRec secondDetail, 217 unsigned short exception) 218{ 219 if (IsInGrabMask(firstDetail, secondDetail, exception)) 220 return TRUE; 221 222 if (IdenticalExactDetails(firstDetail.exact, secondDetail.exact, 223 exception)) 224 return TRUE; 225 226 return FALSE; 227} 228 229static Bool 230GrabSupersedesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab) 231{ 232 if (!DetailSupersedesSecond(pFirstGrab->modifiersDetail, 233 pSecondGrab->modifiersDetail, 234 (unsigned short)AnyModifier)) 235 return FALSE; 236 237 if (DetailSupersedesSecond(pFirstGrab->detail, 238 pSecondGrab->detail, (unsigned short)AnyKey)) 239 return TRUE; 240 241 return FALSE; 242} 243 244/** 245 * Compares two grabs and returns TRUE if the first grab matches the second 246 * grab. 247 * 248 * A match is when 249 * - the devices set for the grab are equal (this is optional). 250 * - the event types for both grabs are equal. 251 * - XXX 252 * 253 * @param ignoreDevice TRUE if the device settings on the grabs are to be 254 * ignored. 255 * @return TRUE if the grabs match or FALSE otherwise. 256 */ 257Bool 258GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab, Bool ignoreDevice) 259{ 260 if (!ignoreDevice && 261 ((pFirstGrab->device != pSecondGrab->device) || 262 (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice))) 263 return FALSE; 264 265 if (pFirstGrab->type != pSecondGrab->type) 266 return FALSE; 267 268 if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) || 269 GrabSupersedesSecond(pSecondGrab, pFirstGrab)) 270 return TRUE; 271 272 if (DetailSupersedesSecond(pSecondGrab->detail, pFirstGrab->detail, 273 (unsigned short)AnyKey) 274 && 275 DetailSupersedesSecond(pFirstGrab->modifiersDetail, 276 pSecondGrab->modifiersDetail, 277 (unsigned short)AnyModifier)) 278 return TRUE; 279 280 if (DetailSupersedesSecond(pFirstGrab->detail, pSecondGrab->detail, 281 (unsigned short)AnyKey) 282 && 283 DetailSupersedesSecond(pSecondGrab->modifiersDetail, 284 pFirstGrab->modifiersDetail, 285 (unsigned short)AnyModifier)) 286 return TRUE; 287 288 return FALSE; 289} 290 291static Bool 292GrabsAreIdentical(GrabPtr pFirstGrab, GrabPtr pSecondGrab) 293{ 294 if (pFirstGrab->device != pSecondGrab->device || 295 (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) || 296 (pFirstGrab->type != pSecondGrab->type)) 297 return FALSE; 298 299 if (!(DetailSupersedesSecond(pFirstGrab->detail, 300 pSecondGrab->detail, 301 (unsigned short)AnyKey) && 302 DetailSupersedesSecond(pSecondGrab->detail, 303 pFirstGrab->detail, 304 (unsigned short)AnyKey))) 305 return FALSE; 306 307 if (!(DetailSupersedesSecond(pFirstGrab->modifiersDetail, 308 pSecondGrab->modifiersDetail, 309 (unsigned short)AnyModifier) && 310 DetailSupersedesSecond(pSecondGrab->modifiersDetail, 311 pFirstGrab->modifiersDetail, 312 (unsigned short)AnyModifier))) 313 return FALSE; 314 315 return TRUE; 316} 317 318 319/** 320 * Prepend the new grab to the list of passive grabs on the window. 321 * Any previously existing grab that matches the new grab will be removed. 322 * Adding a new grab that would override another client's grab will result in 323 * a BadAccess. 324 * 325 * @return Success or X error code on failure. 326 */ 327int 328AddPassiveGrabToList(ClientPtr client, GrabPtr pGrab) 329{ 330 GrabPtr grab; 331 Mask access_mode = DixGrabAccess; 332 int rc; 333 334 for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) 335 { 336 if (GrabMatchesSecond(pGrab, grab, FALSE)) 337 { 338 if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource)) 339 { 340 FreeGrab(pGrab); 341 return BadAccess; 342 } 343 } 344 } 345 346 if (pGrab->keyboardMode == GrabModeSync||pGrab->pointerMode == GrabModeSync) 347 access_mode |= DixFreezeAccess; 348 rc = XaceHook(XACE_DEVICE_ACCESS, client, pGrab->device, access_mode); 349 if (rc != Success) 350 return rc; 351 352 /* Remove all grabs that match the new one exactly */ 353 for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) 354 { 355 if (GrabsAreIdentical(pGrab, grab)) 356 { 357 DeletePassiveGrabFromList(grab); 358 break; 359 } 360 } 361 362 if (!pGrab->window->optional && !MakeWindowOptional (pGrab->window)) 363 { 364 FreeGrab(pGrab); 365 return BadAlloc; 366 } 367 368 pGrab->next = pGrab->window->optional->passiveGrabs; 369 pGrab->window->optional->passiveGrabs = pGrab; 370 if (AddResource(pGrab->resource, RT_PASSIVEGRAB, (pointer)pGrab)) 371 return Success; 372 return BadAlloc; 373} 374 375/* the following is kinda complicated, because we need to be able to back out 376 * if any allocation fails 377 */ 378 379Bool 380DeletePassiveGrabFromList(GrabPtr pMinuendGrab) 381{ 382 GrabPtr grab; 383 GrabPtr *deletes, *adds; 384 Mask ***updates, **details; 385 int i, ndels, nadds, nups; 386 Bool ok; 387 388#define UPDATE(mask,exact) \ 389 if (!(details[nups] = DeleteDetailFromMask(mask, exact))) \ 390 ok = FALSE; \ 391 else \ 392 updates[nups++] = &(mask) 393 394 i = 0; 395 for (grab = wPassiveGrabs(pMinuendGrab->window); grab; grab = grab->next) 396 i++; 397 if (!i) 398 return TRUE; 399 deletes = (GrabPtr *)xalloc(i * sizeof(GrabPtr)); 400 adds = (GrabPtr *)xalloc(i * sizeof(GrabPtr)); 401 updates = (Mask ***)xalloc(i * sizeof(Mask **)); 402 details = (Mask **)xalloc(i * sizeof(Mask *)); 403 if (!deletes || !adds || !updates || !details) 404 { 405 if (details) xfree(details); 406 if (updates) xfree(updates); 407 if (adds) xfree(adds); 408 if (deletes) xfree(deletes); 409 return FALSE; 410 } 411 ndels = nadds = nups = 0; 412 ok = TRUE; 413 for (grab = wPassiveGrabs(pMinuendGrab->window); 414 grab && ok; 415 grab = grab->next) 416 { 417 if ((CLIENT_BITS(grab->resource) != CLIENT_BITS(pMinuendGrab->resource)) || 418 !GrabMatchesSecond(grab, pMinuendGrab, (grab->coreGrab))) 419 continue; 420 if (GrabSupersedesSecond(pMinuendGrab, grab)) 421 { 422 deletes[ndels++] = grab; 423 } 424 else if ((grab->detail.exact == AnyKey) 425 && (grab->modifiersDetail.exact != AnyModifier)) 426 { 427 UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); 428 } 429 else if ((grab->modifiersDetail.exact == AnyModifier) 430 && (grab->detail.exact != AnyKey)) 431 { 432 UPDATE(grab->modifiersDetail.pMask, 433 pMinuendGrab->modifiersDetail.exact); 434 } 435 else if ((pMinuendGrab->detail.exact != AnyKey) 436 && (pMinuendGrab->modifiersDetail.exact != AnyModifier)) 437 { 438 GrabPtr pNewGrab; 439 440 UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); 441 442 pNewGrab = CreateGrab(CLIENT_ID(grab->resource), grab->device, 443 grab->window, (Mask)grab->eventMask, 444 (Bool)grab->ownerEvents, 445 (Bool)grab->keyboardMode, 446 (Bool)grab->pointerMode, 447 grab->modifierDevice, 448 AnyModifier, (int)grab->type, 449 pMinuendGrab->detail.exact, 450 grab->confineTo, grab->cursor); 451 if (!pNewGrab) 452 ok = FALSE; 453 else if (!(pNewGrab->modifiersDetail.pMask = 454 DeleteDetailFromMask(grab->modifiersDetail.pMask, 455 pMinuendGrab->modifiersDetail.exact)) 456 || 457 (!pNewGrab->window->optional && 458 !MakeWindowOptional(pNewGrab->window))) 459 { 460 FreeGrab(pNewGrab); 461 ok = FALSE; 462 } 463 else if (!AddResource(pNewGrab->resource, RT_PASSIVEGRAB, 464 (pointer)pNewGrab)) 465 ok = FALSE; 466 else 467 adds[nadds++] = pNewGrab; 468 } 469 else if (pMinuendGrab->detail.exact == AnyKey) 470 { 471 UPDATE(grab->modifiersDetail.pMask, 472 pMinuendGrab->modifiersDetail.exact); 473 } 474 else 475 { 476 UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); 477 } 478 } 479 480 if (!ok) 481 { 482 for (i = 0; i < nadds; i++) 483 FreeResource(adds[i]->resource, RT_NONE); 484 for (i = 0; i < nups; i++) 485 xfree(details[i]); 486 } 487 else 488 { 489 for (i = 0; i < ndels; i++) 490 FreeResource(deletes[i]->resource, RT_NONE); 491 for (i = 0; i < nadds; i++) 492 { 493 grab = adds[i]; 494 grab->next = grab->window->optional->passiveGrabs; 495 grab->window->optional->passiveGrabs = grab; 496 } 497 for (i = 0; i < nups; i++) 498 { 499 xfree(*updates[i]); 500 *updates[i] = details[i]; 501 } 502 } 503 xfree(details); 504 xfree(updates); 505 xfree(adds); 506 xfree(deletes); 507 return ok; 508 509#undef UPDATE 510} 511