xref: /OK3568_Linux_fs/external/xserver/xfixes/cursor.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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