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