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