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