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