cursor.c revision 6e78d31f
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 REQUEST_SIZE_MATCH(xXFixesSelectCursorInputReq); 284 285 swaps(&stuff->length); 286 swapl(&stuff->window); 287 swapl(&stuff->eventMask); 288 return (*ProcXFixesVector[stuff->xfixesReqType]) (client); 289} 290 291void 292SXFixesCursorNotifyEvent(xXFixesCursorNotifyEvent * from, 293 xXFixesCursorNotifyEvent * to) 294{ 295 to->type = from->type; 296 cpswaps(from->sequenceNumber, to->sequenceNumber); 297 cpswapl(from->window, to->window); 298 cpswapl(from->cursorSerial, to->cursorSerial); 299 cpswapl(from->timestamp, to->timestamp); 300 cpswapl(from->name, to->name); 301} 302 303static void 304CopyCursorToImage(CursorPtr pCursor, CARD32 *image) 305{ 306 int width = pCursor->bits->width; 307 int height = pCursor->bits->height; 308 int npixels = width * height; 309 310 if (pCursor->bits->argb) 311 memcpy(image, pCursor->bits->argb, npixels * sizeof(CARD32)); 312 else 313 { 314 unsigned char *srcLine = pCursor->bits->source; 315 unsigned char *mskLine = pCursor->bits->mask; 316 int stride = BitmapBytePad(width); 317 int x, y; 318 CARD32 fg, bg; 319 320 fg = (0xff000000 | 321 ((pCursor->foreRed & 0xff00) << 8) | 322 (pCursor->foreGreen & 0xff00) | (pCursor->foreBlue >> 8)); 323 bg = (0xff000000 | 324 ((pCursor->backRed & 0xff00) << 8) | 325 (pCursor->backGreen & 0xff00) | (pCursor->backBlue >> 8)); 326 for (y = 0; y < height; y++) { 327 for (x = 0; x < width; x++) { 328 if (GetBit(mskLine, x)) { 329 if (GetBit(srcLine, x)) 330 *image++ = fg; 331 else 332 *image++ = bg; 333 } 334 else 335 *image++ = 0; 336 } 337 srcLine += stride; 338 mskLine += stride; 339 } 340 } 341} 342 343int 344ProcXFixesGetCursorImage(ClientPtr client) 345{ 346/* REQUEST(xXFixesGetCursorImageReq); */ 347 xXFixesGetCursorImageReply *rep; 348 CursorPtr pCursor; 349 CARD32 *image; 350 int npixels, width, height, rc, x, y; 351 352 REQUEST_SIZE_MATCH(xXFixesGetCursorImageReq); 353 pCursor = CursorCurrent[PickPointer(client)->id]; 354 if (!pCursor) 355 return BadCursor; 356 rc = XaceHook(XACE_RESOURCE_ACCESS, client, pCursor->id, RT_CURSOR, 357 pCursor, RT_NONE, NULL, DixReadAccess); 358 if (rc != Success) 359 return rc; 360 GetSpritePosition(PickPointer(client), &x, &y); 361 width = pCursor->bits->width; 362 height = pCursor->bits->height; 363 npixels = width * height; 364 rep = calloc(sizeof(xXFixesGetCursorImageReply) + npixels * sizeof(CARD32), 365 1); 366 if (!rep) 367 return BadAlloc; 368 369 rep->type = X_Reply; 370 rep->sequenceNumber = client->sequence; 371 rep->length = npixels; 372 rep->width = width; 373 rep->height = height; 374 rep->x = x; 375 rep->y = y; 376 rep->xhot = pCursor->bits->xhot; 377 rep->yhot = pCursor->bits->yhot; 378 rep->cursorSerial = pCursor->serialNumber; 379 380 image = (CARD32 *) (rep + 1); 381 CopyCursorToImage(pCursor, image); 382 if (client->swapped) { 383 swaps(&rep->sequenceNumber); 384 swapl(&rep->length); 385 swaps(&rep->x); 386 swaps(&rep->y); 387 swaps(&rep->width); 388 swaps(&rep->height); 389 swaps(&rep->xhot); 390 swaps(&rep->yhot); 391 swapl(&rep->cursorSerial); 392 SwapLongs(image, npixels); 393 } 394 WriteToClient(client, 395 sizeof(xXFixesGetCursorImageReply) + (npixels << 2), rep); 396 free(rep); 397 return Success; 398} 399 400int 401SProcXFixesGetCursorImage(ClientPtr client) 402{ 403 REQUEST(xXFixesGetCursorImageReq); 404 swaps(&stuff->length); 405 return (*ProcXFixesVector[stuff->xfixesReqType]) (client); 406} 407 408int 409ProcXFixesSetCursorName(ClientPtr client) 410{ 411 CursorPtr pCursor; 412 char *tchar; 413 414 REQUEST(xXFixesSetCursorNameReq); 415 Atom atom; 416 417 REQUEST_FIXED_SIZE(xXFixesSetCursorNameReq, stuff->nbytes); 418 VERIFY_CURSOR(pCursor, stuff->cursor, client, DixSetAttrAccess); 419 tchar = (char *) &stuff[1]; 420 atom = MakeAtom(tchar, stuff->nbytes, TRUE); 421 if (atom == BAD_RESOURCE) 422 return BadAlloc; 423 424 pCursor->name = atom; 425 return Success; 426} 427 428int 429SProcXFixesSetCursorName(ClientPtr client) 430{ 431 REQUEST(xXFixesSetCursorNameReq); 432 433 swaps(&stuff->length); 434 REQUEST_AT_LEAST_SIZE(xXFixesSetCursorNameReq); 435 swapl(&stuff->cursor); 436 swaps(&stuff->nbytes); 437 return (*ProcXFixesVector[stuff->xfixesReqType]) (client); 438} 439 440int 441ProcXFixesGetCursorName(ClientPtr client) 442{ 443 CursorPtr pCursor; 444 xXFixesGetCursorNameReply reply; 445 446 REQUEST(xXFixesGetCursorNameReq); 447 const char *str; 448 int len; 449 450 REQUEST_SIZE_MATCH(xXFixesGetCursorNameReq); 451 VERIFY_CURSOR(pCursor, stuff->cursor, client, DixGetAttrAccess); 452 if (pCursor->name) 453 str = NameForAtom(pCursor->name); 454 else 455 str = ""; 456 len = strlen(str); 457 458 reply = (xXFixesGetCursorNameReply) { 459 .type = X_Reply, 460 .sequenceNumber = client->sequence, 461 .length = bytes_to_int32(len), 462 .atom = pCursor->name, 463 .nbytes = len 464 }; 465 if (client->swapped) { 466 swaps(&reply.sequenceNumber); 467 swapl(&reply.length); 468 swapl(&reply.atom); 469 swaps(&reply.nbytes); 470 } 471 WriteReplyToClient(client, sizeof(xXFixesGetCursorNameReply), &reply); 472 WriteToClient(client, len, str); 473 474 return Success; 475} 476 477int 478SProcXFixesGetCursorName(ClientPtr client) 479{ 480 REQUEST(xXFixesGetCursorNameReq); 481 482 swaps(&stuff->length); 483 REQUEST_SIZE_MATCH(xXFixesGetCursorNameReq); 484 swapl(&stuff->cursor); 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 const char *name; 497 int nbytes, nbytesRound; 498 int width, height; 499 int rc, x, y; 500 501 REQUEST_SIZE_MATCH(xXFixesGetCursorImageAndNameReq); 502 pCursor = CursorCurrent[PickPointer(client)->id]; 503 if (!pCursor) 504 return BadCursor; 505 rc = XaceHook(XACE_RESOURCE_ACCESS, client, pCursor->id, RT_CURSOR, 506 pCursor, RT_NONE, NULL, DixReadAccess | DixGetAttrAccess); 507 if (rc != Success) 508 return rc; 509 GetSpritePosition(PickPointer(client), &x, &y); 510 width = pCursor->bits->width; 511 height = pCursor->bits->height; 512 npixels = width * height; 513 name = pCursor->name ? NameForAtom(pCursor->name) : ""; 514 nbytes = strlen(name); 515 nbytesRound = pad_to_int32(nbytes); 516 rep = calloc(sizeof(xXFixesGetCursorImageAndNameReply) + 517 npixels * sizeof(CARD32) + nbytesRound, 1); 518 if (!rep) 519 return BadAlloc; 520 521 rep->type = X_Reply; 522 rep->sequenceNumber = client->sequence; 523 rep->length = npixels + bytes_to_int32(nbytesRound); 524 rep->width = width; 525 rep->height = height; 526 rep->x = x; 527 rep->y = y; 528 rep->xhot = pCursor->bits->xhot; 529 rep->yhot = pCursor->bits->yhot; 530 rep->cursorSerial = pCursor->serialNumber; 531 rep->cursorName = pCursor->name; 532 rep->nbytes = nbytes; 533 534 image = (CARD32 *) (rep + 1); 535 CopyCursorToImage(pCursor, image); 536 memcpy((image + npixels), name, nbytes); 537 if (client->swapped) { 538 swaps(&rep->sequenceNumber); 539 swapl(&rep->length); 540 swaps(&rep->x); 541 swaps(&rep->y); 542 swaps(&rep->width); 543 swaps(&rep->height); 544 swaps(&rep->xhot); 545 swaps(&rep->yhot); 546 swapl(&rep->cursorSerial); 547 swapl(&rep->cursorName); 548 swaps(&rep->nbytes); 549 SwapLongs(image, npixels); 550 } 551 WriteToClient(client, sizeof(xXFixesGetCursorImageAndNameReply) + 552 (npixels << 2) + nbytesRound, rep); 553 free(rep); 554 return Success; 555} 556 557int 558SProcXFixesGetCursorImageAndName(ClientPtr client) 559{ 560 REQUEST(xXFixesGetCursorImageAndNameReq); 561 swaps(&stuff->length); 562 return (*ProcXFixesVector[stuff->xfixesReqType]) (client); 563} 564 565/* 566 * Find every cursor reference in the system, ask testCursor 567 * whether it should be replaced with a reference to pCursor. 568 */ 569 570typedef Bool (*TestCursorFunc) (CursorPtr pOld, void *closure); 571 572typedef struct { 573 RESTYPE type; 574 TestCursorFunc testCursor; 575 CursorPtr pNew; 576 void *closure; 577} ReplaceCursorLookupRec, *ReplaceCursorLookupPtr; 578 579static const RESTYPE CursorRestypes[] = { 580 RT_WINDOW, RT_PASSIVEGRAB, RT_CURSOR 581}; 582 583#define NUM_CURSOR_RESTYPES (sizeof (CursorRestypes) / sizeof (CursorRestypes[0])) 584 585static Bool 586ReplaceCursorLookup(void *value, XID id, void *closure) 587{ 588 ReplaceCursorLookupPtr rcl = (ReplaceCursorLookupPtr) closure; 589 WindowPtr pWin; 590 GrabPtr pGrab; 591 CursorPtr pCursor = 0, *pCursorRef = 0; 592 XID cursor = 0; 593 594 switch (rcl->type) { 595 case RT_WINDOW: 596 pWin = (WindowPtr) value; 597 if (pWin->optional) { 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 if ((*rcl->testCursor) (pCursor, rcl->closure)) { 615 CursorPtr curs = RefCursor(rcl->pNew); 616 /* either redirect reference or update resource database */ 617 if (pCursorRef) 618 *pCursorRef = curs; 619 else 620 ChangeResourceValue(id, RT_CURSOR, curs); 621 FreeCursor(pCursor, cursor); 622 } 623 } 624 return FALSE; /* keep walking */ 625} 626 627static void 628ReplaceCursor(CursorPtr pCursor, TestCursorFunc testCursor, void *closure) 629{ 630 int clientIndex; 631 int resIndex; 632 ReplaceCursorLookupRec rcl; 633 634 /* 635 * Cursors exist only in the resource database, windows and grabs. 636 * All of these are always pointed at by the resource database. Walk 637 * the whole thing looking for cursors 638 */ 639 rcl.testCursor = testCursor; 640 rcl.pNew = pCursor; 641 rcl.closure = closure; 642 643 /* for each client */ 644 for (clientIndex = 0; clientIndex < currentMaxClients; clientIndex++) { 645 if (!clients[clientIndex]) 646 continue; 647 for (resIndex = 0; resIndex < NUM_CURSOR_RESTYPES; resIndex++) { 648 rcl.type = CursorRestypes[resIndex]; 649 /* 650 * This function walks the entire client resource database 651 */ 652 LookupClientResourceComplex(clients[clientIndex], 653 rcl.type, 654 ReplaceCursorLookup, (void *) &rcl); 655 } 656 } 657 /* this "knows" that WindowHasNewCursor doesn't depend on it's argument */ 658 WindowHasNewCursor(screenInfo.screens[0]->root); 659} 660 661static Bool 662TestForCursor(CursorPtr pCursor, void *closure) 663{ 664 return (pCursor == (CursorPtr) closure); 665} 666 667int 668ProcXFixesChangeCursor(ClientPtr client) 669{ 670 CursorPtr pSource, pDestination; 671 672 REQUEST(xXFixesChangeCursorReq); 673 674 REQUEST_SIZE_MATCH(xXFixesChangeCursorReq); 675 VERIFY_CURSOR(pSource, stuff->source, client, 676 DixReadAccess | DixGetAttrAccess); 677 VERIFY_CURSOR(pDestination, stuff->destination, client, 678 DixWriteAccess | DixSetAttrAccess); 679 680 ReplaceCursor(pSource, TestForCursor, (void *) pDestination); 681 return Success; 682} 683 684int 685SProcXFixesChangeCursor(ClientPtr client) 686{ 687 REQUEST(xXFixesChangeCursorReq); 688 689 swaps(&stuff->length); 690 REQUEST_SIZE_MATCH(xXFixesChangeCursorReq); 691 swapl(&stuff->source); 692 swapl(&stuff->destination); 693 return (*ProcXFixesVector[stuff->xfixesReqType]) (client); 694} 695 696static Bool 697TestForCursorName(CursorPtr pCursor, void *closure) 698{ 699 Atom *pName = closure; 700 701 return pCursor->name == *pName; 702} 703 704int 705ProcXFixesChangeCursorByName(ClientPtr client) 706{ 707 CursorPtr pSource; 708 Atom name; 709 char *tchar; 710 711 REQUEST(xXFixesChangeCursorByNameReq); 712 713 REQUEST_FIXED_SIZE(xXFixesChangeCursorByNameReq, stuff->nbytes); 714 VERIFY_CURSOR(pSource, stuff->source, client, 715 DixReadAccess | DixGetAttrAccess); 716 tchar = (char *) &stuff[1]; 717 name = MakeAtom(tchar, stuff->nbytes, FALSE); 718 if (name) 719 ReplaceCursor(pSource, TestForCursorName, &name); 720 return Success; 721} 722 723int 724SProcXFixesChangeCursorByName(ClientPtr client) 725{ 726 REQUEST(xXFixesChangeCursorByNameReq); 727 728 swaps(&stuff->length); 729 REQUEST_AT_LEAST_SIZE(xXFixesChangeCursorByNameReq); 730 swapl(&stuff->source); 731 swaps(&stuff->nbytes); 732 return (*ProcXFixesVector[stuff->xfixesReqType]) (client); 733} 734 735/* 736 * Routines for manipulating the per-screen hide counts list. 737 * This list indicates which clients have requested cursor hiding 738 * for that screen. 739 */ 740 741/* Return the screen's hide-counts list element for the given client */ 742static CursorHideCountPtr 743findCursorHideCount(ClientPtr pClient, ScreenPtr pScreen) 744{ 745 CursorScreenPtr cs = GetCursorScreen(pScreen); 746 CursorHideCountPtr pChc; 747 748 for (pChc = cs->pCursorHideCounts; pChc != NULL; pChc = pChc->pNext) { 749 if (pChc->pClient == pClient) { 750 return pChc; 751 } 752 } 753 754 return NULL; 755} 756 757static int 758createCursorHideCount(ClientPtr pClient, ScreenPtr pScreen) 759{ 760 CursorScreenPtr cs = GetCursorScreen(pScreen); 761 CursorHideCountPtr pChc; 762 763 pChc = (CursorHideCountPtr) malloc(sizeof(CursorHideCountRec)); 764 if (pChc == NULL) { 765 return BadAlloc; 766 } 767 pChc->pClient = pClient; 768 pChc->pScreen = pScreen; 769 pChc->hideCount = 1; 770 pChc->resource = FakeClientID(pClient->index); 771 pChc->pNext = cs->pCursorHideCounts; 772 cs->pCursorHideCounts = pChc; 773 774 /* 775 * Create a resource for this element so it can be deleted 776 * when the client goes away. 777 */ 778 if (!AddResource(pChc->resource, CursorHideCountType, (void *) pChc)) 779 return BadAlloc; 780 781 return Success; 782} 783 784/* 785 * Delete the given hide-counts list element from its screen list. 786 */ 787static void 788deleteCursorHideCount(CursorHideCountPtr pChcToDel, ScreenPtr pScreen) 789{ 790 CursorScreenPtr cs = GetCursorScreen(pScreen); 791 CursorHideCountPtr pChc, pNext; 792 CursorHideCountPtr pChcLast = NULL; 793 794 pChc = cs->pCursorHideCounts; 795 while (pChc != NULL) { 796 pNext = pChc->pNext; 797 if (pChc == pChcToDel) { 798 free(pChc); 799 if (pChcLast == NULL) { 800 cs->pCursorHideCounts = pNext; 801 } 802 else { 803 pChcLast->pNext = pNext; 804 } 805 return; 806 } 807 pChcLast = pChc; 808 pChc = pNext; 809 } 810} 811 812/* 813 * Delete all the hide-counts list elements for this screen. 814 */ 815static void 816deleteCursorHideCountsForScreen(ScreenPtr pScreen) 817{ 818 CursorScreenPtr cs = GetCursorScreen(pScreen); 819 CursorHideCountPtr pChc, pTmp; 820 821 pChc = cs->pCursorHideCounts; 822 while (pChc != NULL) { 823 pTmp = pChc->pNext; 824 FreeResource(pChc->resource, 0); 825 pChc = pTmp; 826 } 827 cs->pCursorHideCounts = NULL; 828} 829 830int 831ProcXFixesHideCursor(ClientPtr client) 832{ 833 WindowPtr pWin; 834 CursorHideCountPtr pChc; 835 836 REQUEST(xXFixesHideCursorReq); 837 int ret; 838 839 REQUEST_SIZE_MATCH(xXFixesHideCursorReq); 840 841 ret = dixLookupResourceByType((void **) &pWin, stuff->window, RT_WINDOW, 842 client, DixGetAttrAccess); 843 if (ret != Success) { 844 client->errorValue = stuff->window; 845 return ret; 846 } 847 848 /* 849 * Has client hidden the cursor before on this screen? 850 * If so, just increment the count. 851 */ 852 853 pChc = findCursorHideCount(client, pWin->drawable.pScreen); 854 if (pChc != NULL) { 855 pChc->hideCount++; 856 return Success; 857 } 858 859 /* 860 * This is the first time this client has hid the cursor 861 * for this screen. 862 */ 863 ret = XaceHook(XACE_SCREEN_ACCESS, client, pWin->drawable.pScreen, 864 DixHideAccess); 865 if (ret != Success) 866 return ret; 867 868 ret = createCursorHideCount(client, pWin->drawable.pScreen); 869 870 if (ret == Success) { 871 DeviceIntPtr dev; 872 873 for (dev = inputInfo.devices; dev; dev = dev->next) { 874 if (IsMaster(dev) && IsPointerDevice(dev)) 875 CursorDisplayCursor(dev, pWin->drawable.pScreen, 876 CursorCurrent[dev->id]); 877 } 878 } 879 880 return ret; 881} 882 883int 884SProcXFixesHideCursor(ClientPtr client) 885{ 886 REQUEST(xXFixesHideCursorReq); 887 888 swaps(&stuff->length); 889 REQUEST_SIZE_MATCH(xXFixesHideCursorReq); 890 swapl(&stuff->window); 891 return (*ProcXFixesVector[stuff->xfixesReqType]) (client); 892} 893 894int 895ProcXFixesShowCursor(ClientPtr client) 896{ 897 WindowPtr pWin; 898 CursorHideCountPtr pChc; 899 int rc; 900 901 REQUEST(xXFixesShowCursorReq); 902 903 REQUEST_SIZE_MATCH(xXFixesShowCursorReq); 904 905 rc = dixLookupResourceByType((void **) &pWin, stuff->window, RT_WINDOW, 906 client, DixGetAttrAccess); 907 if (rc != Success) { 908 client->errorValue = stuff->window; 909 return rc; 910 } 911 912 /* 913 * Has client hidden the cursor on this screen? 914 * If not, generate an error. 915 */ 916 pChc = findCursorHideCount(client, pWin->drawable.pScreen); 917 if (pChc == NULL) { 918 return BadMatch; 919 } 920 921 rc = XaceHook(XACE_SCREEN_ACCESS, client, pWin->drawable.pScreen, 922 DixShowAccess); 923 if (rc != Success) 924 return rc; 925 926 pChc->hideCount--; 927 if (pChc->hideCount <= 0) { 928 FreeResource(pChc->resource, 0); 929 } 930 931 return Success; 932} 933 934int 935SProcXFixesShowCursor(ClientPtr client) 936{ 937 REQUEST(xXFixesShowCursorReq); 938 939 swaps(&stuff->length); 940 REQUEST_SIZE_MATCH(xXFixesShowCursorReq); 941 swapl(&stuff->window); 942 return (*ProcXFixesVector[stuff->xfixesReqType]) (client); 943} 944 945static int 946CursorFreeClient(void *data, XID id) 947{ 948 CursorEventPtr old = (CursorEventPtr) data; 949 CursorEventPtr *prev, e; 950 951 for (prev = &cursorEvents; (e = *prev); prev = &e->next) { 952 if (e == old) { 953 *prev = e->next; 954 free(e); 955 break; 956 } 957 } 958 return 1; 959} 960 961static int 962CursorFreeHideCount(void *data, XID id) 963{ 964 CursorHideCountPtr pChc = (CursorHideCountPtr) data; 965 ScreenPtr pScreen = pChc->pScreen; 966 DeviceIntPtr dev; 967 968 deleteCursorHideCount(pChc, pChc->pScreen); 969 for (dev = inputInfo.devices; dev; dev = dev->next) { 970 if (IsMaster(dev) && IsPointerDevice(dev)) 971 CursorDisplayCursor(dev, pScreen, CursorCurrent[dev->id]); 972 } 973 974 return 1; 975} 976 977static int 978CursorFreeWindow(void *data, XID id) 979{ 980 WindowPtr pWindow = (WindowPtr) data; 981 CursorEventPtr e, next; 982 983 for (e = cursorEvents; e; e = next) { 984 next = e->next; 985 if (e->pWindow == pWindow) { 986 FreeResource(e->clientResource, 0); 987 } 988 } 989 return 1; 990} 991 992int 993ProcXFixesCreatePointerBarrier(ClientPtr client) 994{ 995 REQUEST(xXFixesCreatePointerBarrierReq); 996 997 REQUEST_FIXED_SIZE(xXFixesCreatePointerBarrierReq, pad_to_int32(stuff->num_devices)); 998 LEGAL_NEW_RESOURCE(stuff->barrier, client); 999 1000 return XICreatePointerBarrier(client, stuff); 1001} 1002 1003int 1004SProcXFixesCreatePointerBarrier(ClientPtr client) 1005{ 1006 REQUEST(xXFixesCreatePointerBarrierReq); 1007 int i; 1008 CARD16 *in_devices = (CARD16 *) &stuff[1]; 1009 1010 REQUEST_AT_LEAST_SIZE(xXFixesCreatePointerBarrierReq); 1011 1012 swaps(&stuff->length); 1013 swaps(&stuff->num_devices); 1014 REQUEST_FIXED_SIZE(xXFixesCreatePointerBarrierReq, pad_to_int32(stuff->num_devices)); 1015 1016 swapl(&stuff->barrier); 1017 swapl(&stuff->window); 1018 swaps(&stuff->x1); 1019 swaps(&stuff->y1); 1020 swaps(&stuff->x2); 1021 swaps(&stuff->y2); 1022 swapl(&stuff->directions); 1023 for (i = 0; i < stuff->num_devices; i++) { 1024 swaps(in_devices + i); 1025 } 1026 1027 return ProcXFixesVector[stuff->xfixesReqType] (client); 1028} 1029 1030int 1031ProcXFixesDestroyPointerBarrier(ClientPtr client) 1032{ 1033 REQUEST(xXFixesDestroyPointerBarrierReq); 1034 1035 REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq); 1036 1037 return XIDestroyPointerBarrier(client, stuff); 1038} 1039 1040int 1041SProcXFixesDestroyPointerBarrier(ClientPtr client) 1042{ 1043 REQUEST(xXFixesDestroyPointerBarrierReq); 1044 1045 swaps(&stuff->length); 1046 REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq); 1047 swapl(&stuff->barrier); 1048 return ProcXFixesVector[stuff->xfixesReqType] (client); 1049} 1050 1051Bool 1052XFixesCursorInit(void) 1053{ 1054 int i; 1055 1056 if (party_like_its_1989) 1057 CursorVisible = EnableCursor; 1058 else 1059 CursorVisible = FALSE; 1060 1061 if (!dixRegisterPrivateKey(&CursorScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) 1062 return FALSE; 1063 1064 for (i = 0; i < screenInfo.numScreens; i++) { 1065 ScreenPtr pScreen = screenInfo.screens[i]; 1066 CursorScreenPtr cs; 1067 1068 cs = (CursorScreenPtr) calloc(1, sizeof(CursorScreenRec)); 1069 if (!cs) 1070 return FALSE; 1071 Wrap(cs, pScreen, CloseScreen, CursorCloseScreen); 1072 Wrap(cs, pScreen, DisplayCursor, CursorDisplayCursor); 1073 cs->pCursorHideCounts = NULL; 1074 SetCursorScreen(pScreen, cs); 1075 } 1076 CursorClientType = CreateNewResourceType(CursorFreeClient, 1077 "XFixesCursorClient"); 1078 CursorHideCountType = CreateNewResourceType(CursorFreeHideCount, 1079 "XFixesCursorHideCount"); 1080 CursorWindowType = CreateNewResourceType(CursorFreeWindow, 1081 "XFixesCursorWindow"); 1082 1083 return CursorClientType && CursorHideCountType && CursorWindowType; 1084} 1085