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