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