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