cursor.c revision 5a112b11
1/* 2 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. 3 * Copyright 2010 Red Hat, Inc. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 * 24 * Copyright © 2002 Keith Packard 25 * 26 * Permission to use, copy, modify, distribute, and sell this software and its 27 * documentation for any purpose is hereby granted without fee, provided that 28 * the above copyright notice appear in all copies and that both that 29 * copyright notice and this permission notice appear in supporting 30 * documentation, and that the name of Keith Packard not be used in 31 * advertising or publicity pertaining to distribution of the software without 32 * specific, written prior permission. Keith Packard makes no 33 * representations about the suitability of this software for any purpose. It 34 * is provided "as is" without express or implied warranty. 35 * 36 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 37 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 38 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 39 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 40 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 41 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 42 * PERFORMANCE OF THIS SOFTWARE. 43 */ 44 45#ifdef HAVE_DIX_CONFIG_H 46#include <dix-config.h> 47#endif 48 49#include "xfixesint.h" 50#include "scrnintstr.h" 51#include "cursorstr.h" 52#include "dixevents.h" 53#include "servermd.h" 54#include "mipointer.h" 55#include "inputstr.h" 56#include "windowstr.h" 57#include "xace.h" 58#include "list.h" 59#include "xibarriers.h" 60 61static RESTYPE CursorClientType; 62static RESTYPE CursorHideCountType; 63static RESTYPE CursorWindowType; 64 65static DevPrivateKeyRec CursorScreenPrivateKeyRec; 66 67#define CursorScreenPrivateKey (&CursorScreenPrivateKeyRec) 68 69static void deleteCursorHideCountsForScreen(ScreenPtr pScreen); 70 71#define VERIFY_CURSOR(pCursor, cursor, client, access) \ 72 do { \ 73 int err; \ 74 err = dixLookupResourceByType((void **) &pCursor, cursor, \ 75 RT_CURSOR, client, access); \ 76 if (err != Success) { \ 77 client->errorValue = cursor; \ 78 return err; \ 79 } \ 80 } while (0) 81 82/* 83 * There is a global list of windows selecting for cursor events 84 */ 85 86typedef struct _CursorEvent *CursorEventPtr; 87 88typedef struct _CursorEvent { 89 CursorEventPtr next; 90 CARD32 eventMask; 91 ClientPtr pClient; 92 WindowPtr pWindow; 93 XID clientResource; 94} CursorEventRec; 95 96static CursorEventPtr cursorEvents; 97 98/* 99 * Each screen has a list of clients which have requested 100 * that the cursor be hid, and the number of times each 101 * client has requested. 102*/ 103 104typedef struct _CursorHideCountRec *CursorHideCountPtr; 105 106typedef struct _CursorHideCountRec { 107 CursorHideCountPtr pNext; 108 ClientPtr pClient; 109 ScreenPtr pScreen; 110 int hideCount; 111 XID resource; 112} CursorHideCountRec; 113 114/* 115 * Wrap DisplayCursor to catch cursor change events 116 */ 117 118typedef struct _CursorScreen { 119 DisplayCursorProcPtr DisplayCursor; 120 CloseScreenProcPtr CloseScreen; 121 CursorHideCountPtr pCursorHideCounts; 122} CursorScreenRec, *CursorScreenPtr; 123 124#define GetCursorScreen(s) ((CursorScreenPtr)dixLookupPrivate(&(s)->devPrivates, CursorScreenPrivateKey)) 125#define GetCursorScreenIfSet(s) GetCursorScreen(s) 126#define SetCursorScreen(s,p) dixSetPrivate(&(s)->devPrivates, CursorScreenPrivateKey, p) 127#define Wrap(as,s,elt,func) (((as)->elt = (s)->elt), (s)->elt = func) 128#define Unwrap(as,s,elt,backup) (((backup) = (s)->elt), (s)->elt = (as)->elt) 129 130/* The cursor doesn't show up until the first XDefineCursor() */ 131Bool CursorVisible = FALSE; 132Bool EnableCursor = TRUE; 133 134static CursorPtr 135CursorForDevice(DeviceIntPtr pDev) 136{ 137 if (pDev && pDev->spriteInfo && pDev->spriteInfo->sprite) { 138 if (pDev->spriteInfo->anim.pCursor) 139 return pDev->spriteInfo->anim.pCursor; 140 return pDev->spriteInfo->sprite->current; 141 } 142 143 return NULL; 144} 145 146static CursorPtr 147CursorForClient(ClientPtr client) 148{ 149 return CursorForDevice(PickPointer(client)); 150} 151 152static Bool 153CursorDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) 154{ 155 CursorScreenPtr cs = GetCursorScreen(pScreen); 156 CursorPtr pOldCursor = CursorForDevice(pDev); 157 Bool ret; 158 DisplayCursorProcPtr backupProc; 159 160 Unwrap(cs, pScreen, DisplayCursor, backupProc); 161 162 CursorVisible = CursorVisible && EnableCursor; 163 164 if (cs->pCursorHideCounts != NULL || !CursorVisible) { 165 ret = (*pScreen->DisplayCursor) (pDev, pScreen, NullCursor); 166 } 167 else { 168 ret = (*pScreen->DisplayCursor) (pDev, pScreen, pCursor); 169 } 170 171 if (pCursor != pOldCursor) { 172 CursorEventPtr e; 173 174 UpdateCurrentTimeIf(); 175 for (e = cursorEvents; e; e = e->next) { 176 if ((e->eventMask & XFixesDisplayCursorNotifyMask)) { 177 xXFixesCursorNotifyEvent ev = { 178 .type = XFixesEventBase + XFixesCursorNotify, 179 .subtype = XFixesDisplayCursorNotify, 180 .window = e->pWindow->drawable.id, 181 .cursorSerial = pCursor ? pCursor->serialNumber : 0, 182 .timestamp = currentTime.milliseconds, 183 .name = pCursor ? pCursor->name : None 184 }; 185 WriteEventsToClient(e->pClient, 1, (xEvent *) &ev); 186 } 187 } 188 } 189 Wrap(cs, pScreen, DisplayCursor, backupProc); 190 191 return ret; 192} 193 194static Bool 195CursorCloseScreen(ScreenPtr pScreen) 196{ 197 CursorScreenPtr cs = GetCursorScreen(pScreen); 198 Bool ret; 199 _X_UNUSED CloseScreenProcPtr close_proc; 200 _X_UNUSED DisplayCursorProcPtr display_proc; 201 202 Unwrap(cs, pScreen, CloseScreen, close_proc); 203 Unwrap(cs, pScreen, DisplayCursor, display_proc); 204 deleteCursorHideCountsForScreen(pScreen); 205 ret = (*pScreen->CloseScreen) (pScreen); 206 free(cs); 207 return ret; 208} 209 210#define CursorAllEvents (XFixesDisplayCursorNotifyMask) 211 212static int 213XFixesSelectCursorInput(ClientPtr pClient, WindowPtr pWindow, CARD32 eventMask) 214{ 215 CursorEventPtr *prev, e; 216 void *val; 217 int rc; 218 219 for (prev = &cursorEvents; (e = *prev); prev = &e->next) { 220 if (e->pClient == pClient && e->pWindow == pWindow) { 221 break; 222 } 223 } 224 if (!eventMask) { 225 if (e) { 226 FreeResource(e->clientResource, 0); 227 } 228 return Success; 229 } 230 if (!e) { 231 e = (CursorEventPtr) malloc(sizeof(CursorEventRec)); 232 if (!e) 233 return BadAlloc; 234 235 e->next = 0; 236 e->pClient = pClient; 237 e->pWindow = pWindow; 238 e->clientResource = FakeClientID(pClient->index); 239 240 /* 241 * Add a resource hanging from the window to 242 * catch window destroy 243 */ 244 rc = dixLookupResourceByType(&val, pWindow->drawable.id, 245 CursorWindowType, serverClient, 246 DixGetAttrAccess); 247 if (rc != Success) 248 if (!AddResource(pWindow->drawable.id, CursorWindowType, 249 (void *) pWindow)) { 250 free(e); 251 return BadAlloc; 252 } 253 254 if (!AddResource(e->clientResource, CursorClientType, (void *) e)) 255 return BadAlloc; 256 257 *prev = e; 258 } 259 e->eventMask = eventMask; 260 return Success; 261} 262 263int 264ProcXFixesSelectCursorInput(ClientPtr client) 265{ 266 REQUEST(xXFixesSelectCursorInputReq); 267 WindowPtr pWin; 268 int rc; 269 270 REQUEST_SIZE_MATCH(xXFixesSelectCursorInputReq); 271 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 272 if (rc != Success) 273 return rc; 274 if (stuff->eventMask & ~CursorAllEvents) { 275 client->errorValue = stuff->eventMask; 276 return BadValue; 277 } 278 return XFixesSelectCursorInput(client, pWin, stuff->eventMask); 279} 280 281static int 282GetBit(unsigned char *line, int x) 283{ 284 unsigned char mask; 285 286 if (screenInfo.bitmapBitOrder == LSBFirst) 287 mask = (1 << (x & 7)); 288 else 289 mask = (0x80 >> (x & 7)); 290 /* XXX assumes byte order is host byte order */ 291 line += (x >> 3); 292 if (*line & mask) 293 return 1; 294 return 0; 295} 296 297int _X_COLD 298SProcXFixesSelectCursorInput(ClientPtr client) 299{ 300 REQUEST(xXFixesSelectCursorInputReq); 301 REQUEST_SIZE_MATCH(xXFixesSelectCursorInputReq); 302 303 swaps(&stuff->length); 304 swapl(&stuff->window); 305 swapl(&stuff->eventMask); 306 return (*ProcXFixesVector[stuff->xfixesReqType]) (client); 307} 308 309void _X_COLD 310SXFixesCursorNotifyEvent(xXFixesCursorNotifyEvent * from, 311 xXFixesCursorNotifyEvent * to) 312{ 313 to->type = from->type; 314 cpswaps(from->sequenceNumber, to->sequenceNumber); 315 cpswapl(from->window, to->window); 316 cpswapl(from->cursorSerial, to->cursorSerial); 317 cpswapl(from->timestamp, to->timestamp); 318 cpswapl(from->name, to->name); 319} 320 321static void 322CopyCursorToImage(CursorPtr pCursor, CARD32 *image) 323{ 324 int width = pCursor->bits->width; 325 int height = pCursor->bits->height; 326 int npixels = width * height; 327 328 if (pCursor->bits->argb) 329 memcpy(image, pCursor->bits->argb, npixels * sizeof(CARD32)); 330 else 331 { 332 unsigned char *srcLine = pCursor->bits->source; 333 unsigned char *mskLine = pCursor->bits->mask; 334 int stride = BitmapBytePad(width); 335 int x, y; 336 CARD32 fg, bg; 337 338 fg = (0xff000000 | 339 ((pCursor->foreRed & 0xff00) << 8) | 340 (pCursor->foreGreen & 0xff00) | (pCursor->foreBlue >> 8)); 341 bg = (0xff000000 | 342 ((pCursor->backRed & 0xff00) << 8) | 343 (pCursor->backGreen & 0xff00) | (pCursor->backBlue >> 8)); 344 for (y = 0; y < height; y++) { 345 for (x = 0; x < width; x++) { 346 if (GetBit(mskLine, x)) { 347 if (GetBit(srcLine, x)) 348 *image++ = fg; 349 else 350 *image++ = bg; 351 } 352 else 353 *image++ = 0; 354 } 355 srcLine += stride; 356 mskLine += stride; 357 } 358 } 359} 360 361int 362ProcXFixesGetCursorImage(ClientPtr client) 363{ 364/* REQUEST(xXFixesGetCursorImageReq); */ 365 xXFixesGetCursorImageReply *rep; 366 CursorPtr pCursor; 367 CARD32 *image; 368 int npixels, width, height, rc, x, y; 369 370 REQUEST_SIZE_MATCH(xXFixesGetCursorImageReq); 371 pCursor = CursorForClient(client); 372 if (!pCursor) 373 return BadCursor; 374 rc = XaceHook(XACE_RESOURCE_ACCESS, client, pCursor->id, RT_CURSOR, 375 pCursor, RT_NONE, NULL, DixReadAccess); 376 if (rc != Success) 377 return rc; 378 GetSpritePosition(PickPointer(client), &x, &y); 379 width = pCursor->bits->width; 380 height = pCursor->bits->height; 381 npixels = width * height; 382 rep = calloc(sizeof(xXFixesGetCursorImageReply) + npixels * sizeof(CARD32), 383 1); 384 if (!rep) 385 return BadAlloc; 386 387 rep->type = X_Reply; 388 rep->sequenceNumber = client->sequence; 389 rep->length = npixels; 390 rep->width = width; 391 rep->height = height; 392 rep->x = x; 393 rep->y = y; 394 rep->xhot = pCursor->bits->xhot; 395 rep->yhot = pCursor->bits->yhot; 396 rep->cursorSerial = pCursor->serialNumber; 397 398 image = (CARD32 *) (rep + 1); 399 CopyCursorToImage(pCursor, image); 400 if (client->swapped) { 401 swaps(&rep->sequenceNumber); 402 swapl(&rep->length); 403 swaps(&rep->x); 404 swaps(&rep->y); 405 swaps(&rep->width); 406 swaps(&rep->height); 407 swaps(&rep->xhot); 408 swaps(&rep->yhot); 409 swapl(&rep->cursorSerial); 410 SwapLongs(image, npixels); 411 } 412 WriteToClient(client, 413 sizeof(xXFixesGetCursorImageReply) + (npixels << 2), rep); 414 free(rep); 415 return Success; 416} 417 418int _X_COLD 419SProcXFixesGetCursorImage(ClientPtr client) 420{ 421 REQUEST(xXFixesGetCursorImageReq); 422 swaps(&stuff->length); 423 return (*ProcXFixesVector[stuff->xfixesReqType]) (client); 424} 425 426int 427ProcXFixesSetCursorName(ClientPtr client) 428{ 429 CursorPtr pCursor; 430 char *tchar; 431 432 REQUEST(xXFixesSetCursorNameReq); 433 Atom atom; 434 435 REQUEST_FIXED_SIZE(xXFixesSetCursorNameReq, stuff->nbytes); 436 VERIFY_CURSOR(pCursor, stuff->cursor, client, DixSetAttrAccess); 437 tchar = (char *) &stuff[1]; 438 atom = MakeAtom(tchar, stuff->nbytes, TRUE); 439 if (atom == BAD_RESOURCE) 440 return BadAlloc; 441 442 pCursor->name = atom; 443 return Success; 444} 445 446int _X_COLD 447SProcXFixesSetCursorName(ClientPtr client) 448{ 449 REQUEST(xXFixesSetCursorNameReq); 450 451 swaps(&stuff->length); 452 REQUEST_AT_LEAST_SIZE(xXFixesSetCursorNameReq); 453 swapl(&stuff->cursor); 454 swaps(&stuff->nbytes); 455 return (*ProcXFixesVector[stuff->xfixesReqType]) (client); 456} 457 458int 459ProcXFixesGetCursorName(ClientPtr client) 460{ 461 CursorPtr pCursor; 462 xXFixesGetCursorNameReply reply; 463 464 REQUEST(xXFixesGetCursorNameReq); 465 const char *str; 466 int len; 467 468 REQUEST_SIZE_MATCH(xXFixesGetCursorNameReq); 469 VERIFY_CURSOR(pCursor, stuff->cursor, client, DixGetAttrAccess); 470 if (pCursor->name) 471 str = NameForAtom(pCursor->name); 472 else 473 str = ""; 474 len = strlen(str); 475 476 reply = (xXFixesGetCursorNameReply) { 477 .type = X_Reply, 478 .sequenceNumber = client->sequence, 479 .length = bytes_to_int32(len), 480 .atom = pCursor->name, 481 .nbytes = len 482 }; 483 if (client->swapped) { 484 swaps(&reply.sequenceNumber); 485 swapl(&reply.length); 486 swapl(&reply.atom); 487 swaps(&reply.nbytes); 488 } 489 WriteReplyToClient(client, sizeof(xXFixesGetCursorNameReply), &reply); 490 WriteToClient(client, len, str); 491 492 return Success; 493} 494 495int _X_COLD 496SProcXFixesGetCursorName(ClientPtr client) 497{ 498 REQUEST(xXFixesGetCursorNameReq); 499 500 swaps(&stuff->length); 501 REQUEST_SIZE_MATCH(xXFixesGetCursorNameReq); 502 swapl(&stuff->cursor); 503 return (*ProcXFixesVector[stuff->xfixesReqType]) (client); 504} 505 506int 507ProcXFixesGetCursorImageAndName(ClientPtr client) 508{ 509/* REQUEST(xXFixesGetCursorImageAndNameReq); */ 510 xXFixesGetCursorImageAndNameReply *rep; 511 CursorPtr pCursor; 512 CARD32 *image; 513 int npixels; 514 const char *name; 515 int nbytes, nbytesRound; 516 int width, height; 517 int rc, x, y; 518 519 REQUEST_SIZE_MATCH(xXFixesGetCursorImageAndNameReq); 520 pCursor = CursorForClient(client); 521 if (!pCursor) 522 return BadCursor; 523 rc = XaceHook(XACE_RESOURCE_ACCESS, client, pCursor->id, RT_CURSOR, 524 pCursor, RT_NONE, NULL, DixReadAccess | DixGetAttrAccess); 525 if (rc != Success) 526 return rc; 527 GetSpritePosition(PickPointer(client), &x, &y); 528 width = pCursor->bits->width; 529 height = pCursor->bits->height; 530 npixels = width * height; 531 name = pCursor->name ? NameForAtom(pCursor->name) : ""; 532 nbytes = strlen(name); 533 nbytesRound = pad_to_int32(nbytes); 534 rep = calloc(sizeof(xXFixesGetCursorImageAndNameReply) + 535 npixels * sizeof(CARD32) + nbytesRound, 1); 536 if (!rep) 537 return BadAlloc; 538 539 rep->type = X_Reply; 540 rep->sequenceNumber = client->sequence; 541 rep->length = npixels + bytes_to_int32(nbytesRound); 542 rep->width = width; 543 rep->height = height; 544 rep->x = x; 545 rep->y = y; 546 rep->xhot = pCursor->bits->xhot; 547 rep->yhot = pCursor->bits->yhot; 548 rep->cursorSerial = pCursor->serialNumber; 549 rep->cursorName = pCursor->name; 550 rep->nbytes = nbytes; 551 552 image = (CARD32 *) (rep + 1); 553 CopyCursorToImage(pCursor, image); 554 memcpy((image + npixels), name, nbytes); 555 if (client->swapped) { 556 swaps(&rep->sequenceNumber); 557 swapl(&rep->length); 558 swaps(&rep->x); 559 swaps(&rep->y); 560 swaps(&rep->width); 561 swaps(&rep->height); 562 swaps(&rep->xhot); 563 swaps(&rep->yhot); 564 swapl(&rep->cursorSerial); 565 swapl(&rep->cursorName); 566 swaps(&rep->nbytes); 567 SwapLongs(image, npixels); 568 } 569 WriteToClient(client, sizeof(xXFixesGetCursorImageAndNameReply) + 570 (npixels << 2) + nbytesRound, rep); 571 free(rep); 572 return Success; 573} 574 575int _X_COLD 576SProcXFixesGetCursorImageAndName(ClientPtr client) 577{ 578 REQUEST(xXFixesGetCursorImageAndNameReq); 579 swaps(&stuff->length); 580 return (*ProcXFixesVector[stuff->xfixesReqType]) (client); 581} 582 583/* 584 * Find every cursor reference in the system, ask testCursor 585 * whether it should be replaced with a reference to pCursor. 586 */ 587 588typedef Bool (*TestCursorFunc) (CursorPtr pOld, void *closure); 589 590typedef struct { 591 RESTYPE type; 592 TestCursorFunc testCursor; 593 CursorPtr pNew; 594 void *closure; 595} ReplaceCursorLookupRec, *ReplaceCursorLookupPtr; 596 597static const RESTYPE CursorRestypes[] = { 598 RT_WINDOW, RT_PASSIVEGRAB, RT_CURSOR 599}; 600 601static Bool 602ReplaceCursorLookup(void *value, XID id, void *closure) 603{ 604 ReplaceCursorLookupPtr rcl = (ReplaceCursorLookupPtr) closure; 605 WindowPtr pWin; 606 GrabPtr pGrab; 607 CursorPtr pCursor = 0, *pCursorRef = 0; 608 XID cursor = 0; 609 610 switch (rcl->type) { 611 case RT_WINDOW: 612 pWin = (WindowPtr) value; 613 if (pWin->optional) { 614 pCursorRef = &pWin->optional->cursor; 615 pCursor = *pCursorRef; 616 } 617 break; 618 case RT_PASSIVEGRAB: 619 pGrab = (GrabPtr) value; 620 pCursorRef = &pGrab->cursor; 621 pCursor = *pCursorRef; 622 break; 623 case RT_CURSOR: 624 pCursorRef = 0; 625 pCursor = (CursorPtr) value; 626 cursor = id; 627 break; 628 } 629 if (pCursor && pCursor != rcl->pNew) { 630 if ((*rcl->testCursor) (pCursor, rcl->closure)) { 631 CursorPtr curs = RefCursor(rcl->pNew); 632 /* either redirect reference or update resource database */ 633 if (pCursorRef) 634 *pCursorRef = curs; 635 else 636 ChangeResourceValue(id, RT_CURSOR, curs); 637 FreeCursor(pCursor, cursor); 638 } 639 } 640 return FALSE; /* keep walking */ 641} 642 643static void 644ReplaceCursor(CursorPtr pCursor, TestCursorFunc testCursor, void *closure) 645{ 646 int clientIndex; 647 int resIndex; 648 ReplaceCursorLookupRec rcl; 649 650 /* 651 * Cursors exist only in the resource database, windows and grabs. 652 * All of these are always pointed at by the resource database. Walk 653 * the whole thing looking for cursors 654 */ 655 rcl.testCursor = testCursor; 656 rcl.pNew = pCursor; 657 rcl.closure = closure; 658 659 /* for each client */ 660 for (clientIndex = 0; clientIndex < currentMaxClients; clientIndex++) { 661 if (!clients[clientIndex]) 662 continue; 663 for (resIndex = 0; resIndex < ARRAY_SIZE(CursorRestypes); resIndex++) { 664 rcl.type = CursorRestypes[resIndex]; 665 /* 666 * This function walks the entire client resource database 667 */ 668 LookupClientResourceComplex(clients[clientIndex], 669 rcl.type, 670 ReplaceCursorLookup, (void *) &rcl); 671 } 672 } 673 /* this "knows" that WindowHasNewCursor doesn't depend on its argument */ 674 WindowHasNewCursor(screenInfo.screens[0]->root); 675} 676 677static Bool 678TestForCursor(CursorPtr pCursor, void *closure) 679{ 680 return (pCursor == (CursorPtr) closure); 681} 682 683int 684ProcXFixesChangeCursor(ClientPtr client) 685{ 686 CursorPtr pSource, pDestination; 687 688 REQUEST(xXFixesChangeCursorReq); 689 690 REQUEST_SIZE_MATCH(xXFixesChangeCursorReq); 691 VERIFY_CURSOR(pSource, stuff->source, client, 692 DixReadAccess | DixGetAttrAccess); 693 VERIFY_CURSOR(pDestination, stuff->destination, client, 694 DixWriteAccess | DixSetAttrAccess); 695 696 ReplaceCursor(pSource, TestForCursor, (void *) pDestination); 697 return Success; 698} 699 700int _X_COLD 701SProcXFixesChangeCursor(ClientPtr client) 702{ 703 REQUEST(xXFixesChangeCursorReq); 704 705 swaps(&stuff->length); 706 REQUEST_SIZE_MATCH(xXFixesChangeCursorReq); 707 swapl(&stuff->source); 708 swapl(&stuff->destination); 709 return (*ProcXFixesVector[stuff->xfixesReqType]) (client); 710} 711 712static Bool 713TestForCursorName(CursorPtr pCursor, void *closure) 714{ 715 Atom *pName = closure; 716 717 return pCursor->name == *pName; 718} 719 720int 721ProcXFixesChangeCursorByName(ClientPtr client) 722{ 723 CursorPtr pSource; 724 Atom name; 725 char *tchar; 726 727 REQUEST(xXFixesChangeCursorByNameReq); 728 729 REQUEST_FIXED_SIZE(xXFixesChangeCursorByNameReq, stuff->nbytes); 730 VERIFY_CURSOR(pSource, stuff->source, client, 731 DixReadAccess | DixGetAttrAccess); 732 tchar = (char *) &stuff[1]; 733 name = MakeAtom(tchar, stuff->nbytes, FALSE); 734 if (name) 735 ReplaceCursor(pSource, TestForCursorName, &name); 736 return Success; 737} 738 739int _X_COLD 740SProcXFixesChangeCursorByName(ClientPtr client) 741{ 742 REQUEST(xXFixesChangeCursorByNameReq); 743 744 swaps(&stuff->length); 745 REQUEST_AT_LEAST_SIZE(xXFixesChangeCursorByNameReq); 746 swapl(&stuff->source); 747 swaps(&stuff->nbytes); 748 return (*ProcXFixesVector[stuff->xfixesReqType]) (client); 749} 750 751/* 752 * Routines for manipulating the per-screen hide counts list. 753 * This list indicates which clients have requested cursor hiding 754 * for that screen. 755 */ 756 757/* Return the screen's hide-counts list element for the given client */ 758static CursorHideCountPtr 759findCursorHideCount(ClientPtr pClient, ScreenPtr pScreen) 760{ 761 CursorScreenPtr cs = GetCursorScreen(pScreen); 762 CursorHideCountPtr pChc; 763 764 for (pChc = cs->pCursorHideCounts; pChc != NULL; pChc = pChc->pNext) { 765 if (pChc->pClient == pClient) { 766 return pChc; 767 } 768 } 769 770 return NULL; 771} 772 773static int 774createCursorHideCount(ClientPtr pClient, ScreenPtr pScreen) 775{ 776 CursorScreenPtr cs = GetCursorScreen(pScreen); 777 CursorHideCountPtr pChc; 778 779 pChc = (CursorHideCountPtr) malloc(sizeof(CursorHideCountRec)); 780 if (pChc == NULL) { 781 return BadAlloc; 782 } 783 pChc->pClient = pClient; 784 pChc->pScreen = pScreen; 785 pChc->hideCount = 1; 786 pChc->resource = FakeClientID(pClient->index); 787 pChc->pNext = cs->pCursorHideCounts; 788 cs->pCursorHideCounts = pChc; 789 790 /* 791 * Create a resource for this element so it can be deleted 792 * when the client goes away. 793 */ 794 if (!AddResource(pChc->resource, CursorHideCountType, (void *) pChc)) 795 return BadAlloc; 796 797 return Success; 798} 799 800/* 801 * Delete the given hide-counts list element from its screen list. 802 */ 803static void 804deleteCursorHideCount(CursorHideCountPtr pChcToDel, ScreenPtr pScreen) 805{ 806 CursorScreenPtr cs = GetCursorScreen(pScreen); 807 CursorHideCountPtr pChc, pNext; 808 CursorHideCountPtr pChcLast = NULL; 809 810 pChc = cs->pCursorHideCounts; 811 while (pChc != NULL) { 812 pNext = pChc->pNext; 813 if (pChc == pChcToDel) { 814 free(pChc); 815 if (pChcLast == NULL) { 816 cs->pCursorHideCounts = pNext; 817 } 818 else { 819 pChcLast->pNext = pNext; 820 } 821 return; 822 } 823 pChcLast = pChc; 824 pChc = pNext; 825 } 826} 827 828/* 829 * Delete all the hide-counts list elements for this screen. 830 */ 831static void 832deleteCursorHideCountsForScreen(ScreenPtr pScreen) 833{ 834 CursorScreenPtr cs = GetCursorScreen(pScreen); 835 CursorHideCountPtr pChc, pTmp; 836 837 pChc = cs->pCursorHideCounts; 838 while (pChc != NULL) { 839 pTmp = pChc->pNext; 840 FreeResource(pChc->resource, 0); 841 pChc = pTmp; 842 } 843 cs->pCursorHideCounts = NULL; 844} 845 846int 847ProcXFixesHideCursor(ClientPtr client) 848{ 849 WindowPtr pWin; 850 CursorHideCountPtr pChc; 851 852 REQUEST(xXFixesHideCursorReq); 853 int ret; 854 855 REQUEST_SIZE_MATCH(xXFixesHideCursorReq); 856 857 ret = dixLookupResourceByType((void **) &pWin, stuff->window, RT_WINDOW, 858 client, DixGetAttrAccess); 859 if (ret != Success) { 860 client->errorValue = stuff->window; 861 return ret; 862 } 863 864 /* 865 * Has client hidden the cursor before on this screen? 866 * If so, just increment the count. 867 */ 868 869 pChc = findCursorHideCount(client, pWin->drawable.pScreen); 870 if (pChc != NULL) { 871 pChc->hideCount++; 872 return Success; 873 } 874 875 /* 876 * This is the first time this client has hid the cursor 877 * for this screen. 878 */ 879 ret = XaceHook(XACE_SCREEN_ACCESS, client, pWin->drawable.pScreen, 880 DixHideAccess); 881 if (ret != Success) 882 return ret; 883 884 ret = createCursorHideCount(client, pWin->drawable.pScreen); 885 886 if (ret == Success) { 887 DeviceIntPtr dev; 888 889 for (dev = inputInfo.devices; dev; dev = dev->next) { 890 if (IsMaster(dev) && IsPointerDevice(dev)) 891 CursorDisplayCursor(dev, pWin->drawable.pScreen, 892 CursorForDevice(dev)); 893 } 894 } 895 896 return ret; 897} 898 899int _X_COLD 900SProcXFixesHideCursor(ClientPtr client) 901{ 902 REQUEST(xXFixesHideCursorReq); 903 904 swaps(&stuff->length); 905 REQUEST_SIZE_MATCH(xXFixesHideCursorReq); 906 swapl(&stuff->window); 907 return (*ProcXFixesVector[stuff->xfixesReqType]) (client); 908} 909 910int 911ProcXFixesShowCursor(ClientPtr client) 912{ 913 WindowPtr pWin; 914 CursorHideCountPtr pChc; 915 int rc; 916 917 REQUEST(xXFixesShowCursorReq); 918 919 REQUEST_SIZE_MATCH(xXFixesShowCursorReq); 920 921 rc = dixLookupResourceByType((void **) &pWin, stuff->window, RT_WINDOW, 922 client, DixGetAttrAccess); 923 if (rc != Success) { 924 client->errorValue = stuff->window; 925 return rc; 926 } 927 928 /* 929 * Has client hidden the cursor on this screen? 930 * If not, generate an error. 931 */ 932 pChc = findCursorHideCount(client, pWin->drawable.pScreen); 933 if (pChc == NULL) { 934 return BadMatch; 935 } 936 937 rc = XaceHook(XACE_SCREEN_ACCESS, client, pWin->drawable.pScreen, 938 DixShowAccess); 939 if (rc != Success) 940 return rc; 941 942 pChc->hideCount--; 943 if (pChc->hideCount <= 0) { 944 FreeResource(pChc->resource, 0); 945 } 946 947 return Success; 948} 949 950int _X_COLD 951SProcXFixesShowCursor(ClientPtr client) 952{ 953 REQUEST(xXFixesShowCursorReq); 954 955 swaps(&stuff->length); 956 REQUEST_SIZE_MATCH(xXFixesShowCursorReq); 957 swapl(&stuff->window); 958 return (*ProcXFixesVector[stuff->xfixesReqType]) (client); 959} 960 961static int 962CursorFreeClient(void *data, XID id) 963{ 964 CursorEventPtr old = (CursorEventPtr) data; 965 CursorEventPtr *prev, e; 966 967 for (prev = &cursorEvents; (e = *prev); prev = &e->next) { 968 if (e == old) { 969 *prev = e->next; 970 free(e); 971 break; 972 } 973 } 974 return 1; 975} 976 977static int 978CursorFreeHideCount(void *data, XID id) 979{ 980 CursorHideCountPtr pChc = (CursorHideCountPtr) data; 981 ScreenPtr pScreen = pChc->pScreen; 982 DeviceIntPtr dev; 983 984 deleteCursorHideCount(pChc, pChc->pScreen); 985 for (dev = inputInfo.devices; dev; dev = dev->next) { 986 if (IsMaster(dev) && IsPointerDevice(dev)) 987 CursorDisplayCursor(dev, pScreen, CursorForDevice(dev)); 988 } 989 990 return 1; 991} 992 993static int 994CursorFreeWindow(void *data, XID id) 995{ 996 WindowPtr pWindow = (WindowPtr) data; 997 CursorEventPtr e, next; 998 999 for (e = cursorEvents; e; e = next) { 1000 next = e->next; 1001 if (e->pWindow == pWindow) { 1002 FreeResource(e->clientResource, 0); 1003 } 1004 } 1005 return 1; 1006} 1007 1008int 1009ProcXFixesCreatePointerBarrier(ClientPtr client) 1010{ 1011 REQUEST(xXFixesCreatePointerBarrierReq); 1012 1013 REQUEST_FIXED_SIZE(xXFixesCreatePointerBarrierReq, 1014 pad_to_int32(stuff->num_devices * sizeof(CARD16))); 1015 LEGAL_NEW_RESOURCE(stuff->barrier, client); 1016 1017 return XICreatePointerBarrier(client, stuff); 1018} 1019 1020int _X_COLD 1021SProcXFixesCreatePointerBarrier(ClientPtr client) 1022{ 1023 REQUEST(xXFixesCreatePointerBarrierReq); 1024 int i; 1025 CARD16 *in_devices = (CARD16 *) &stuff[1]; 1026 1027 REQUEST_AT_LEAST_SIZE(xXFixesCreatePointerBarrierReq); 1028 1029 swaps(&stuff->length); 1030 swaps(&stuff->num_devices); 1031 REQUEST_FIXED_SIZE(xXFixesCreatePointerBarrierReq, 1032 pad_to_int32(stuff->num_devices * sizeof(CARD16))); 1033 1034 swapl(&stuff->barrier); 1035 swapl(&stuff->window); 1036 swaps(&stuff->x1); 1037 swaps(&stuff->y1); 1038 swaps(&stuff->x2); 1039 swaps(&stuff->y2); 1040 swapl(&stuff->directions); 1041 for (i = 0; i < stuff->num_devices; i++) { 1042 swaps(in_devices + i); 1043 } 1044 1045 return ProcXFixesVector[stuff->xfixesReqType] (client); 1046} 1047 1048int 1049ProcXFixesDestroyPointerBarrier(ClientPtr client) 1050{ 1051 REQUEST(xXFixesDestroyPointerBarrierReq); 1052 1053 REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq); 1054 1055 return XIDestroyPointerBarrier(client, stuff); 1056} 1057 1058int _X_COLD 1059SProcXFixesDestroyPointerBarrier(ClientPtr client) 1060{ 1061 REQUEST(xXFixesDestroyPointerBarrierReq); 1062 1063 swaps(&stuff->length); 1064 REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq); 1065 swapl(&stuff->barrier); 1066 return ProcXFixesVector[stuff->xfixesReqType] (client); 1067} 1068 1069Bool 1070XFixesCursorInit(void) 1071{ 1072 int i; 1073 1074 if (party_like_its_1989) 1075 CursorVisible = EnableCursor; 1076 else 1077 CursorVisible = FALSE; 1078 1079 if (!dixRegisterPrivateKey(&CursorScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) 1080 return FALSE; 1081 1082 for (i = 0; i < screenInfo.numScreens; i++) { 1083 ScreenPtr pScreen = screenInfo.screens[i]; 1084 CursorScreenPtr cs; 1085 1086 cs = (CursorScreenPtr) calloc(1, sizeof(CursorScreenRec)); 1087 if (!cs) 1088 return FALSE; 1089 Wrap(cs, pScreen, CloseScreen, CursorCloseScreen); 1090 Wrap(cs, pScreen, DisplayCursor, CursorDisplayCursor); 1091 cs->pCursorHideCounts = NULL; 1092 SetCursorScreen(pScreen, cs); 1093 } 1094 CursorClientType = CreateNewResourceType(CursorFreeClient, 1095 "XFixesCursorClient"); 1096 CursorHideCountType = CreateNewResourceType(CursorFreeHideCount, 1097 "XFixesCursorHideCount"); 1098 CursorWindowType = CreateNewResourceType(CursorFreeWindow, 1099 "XFixesCursorWindow"); 1100 1101 return CursorClientType && CursorHideCountType && CursorWindowType; 1102} 1103