cursor.c revision 5a112b11
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;
64
65static DevPrivateKeyRec CursorScreenPrivateKeyRec;
66
67#define CursorScreenPrivateKey (&CursorScreenPrivateKeyRec)
68
69static 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
86typedef struct _CursorEvent *CursorEventPtr;
87
88typedef struct _CursorEvent {
89    CursorEventPtr next;
90    CARD32 eventMask;
91    ClientPtr pClient;
92    WindowPtr pWindow;
93    XID clientResource;
94} CursorEventRec;
95
96static 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
104typedef struct _CursorHideCountRec *CursorHideCountPtr;
105
106typedef 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
118typedef 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() */
131Bool CursorVisible = FALSE;
132Bool EnableCursor = TRUE;
133
134static CursorPtr
135CursorForDevice(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
146static CursorPtr
147CursorForClient(ClientPtr client)
148{
149    return CursorForDevice(PickPointer(client));
150}
151
152static Bool
153CursorDisplayCursor(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
194static Bool
195CursorCloseScreen(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
212static int
213XFixesSelectCursorInput(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
263int
264ProcXFixesSelectCursorInput(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
281static int
282GetBit(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
297int _X_COLD
298SProcXFixesSelectCursorInput(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
309void _X_COLD
310SXFixesCursorNotifyEvent(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
321static void
322CopyCursorToImage(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
361int
362ProcXFixesGetCursorImage(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
418int _X_COLD
419SProcXFixesGetCursorImage(ClientPtr client)
420{
421    REQUEST(xXFixesGetCursorImageReq);
422    swaps(&stuff->length);
423    return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
424}
425
426int
427ProcXFixesSetCursorName(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
446int _X_COLD
447SProcXFixesSetCursorName(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
458int
459ProcXFixesGetCursorName(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
495int _X_COLD
496SProcXFixesGetCursorName(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
506int
507ProcXFixesGetCursorImageAndName(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
575int _X_COLD
576SProcXFixesGetCursorImageAndName(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
588typedef Bool (*TestCursorFunc) (CursorPtr pOld, void *closure);
589
590typedef struct {
591    RESTYPE type;
592    TestCursorFunc testCursor;
593    CursorPtr pNew;
594    void *closure;
595} ReplaceCursorLookupRec, *ReplaceCursorLookupPtr;
596
597static const RESTYPE CursorRestypes[] = {
598    RT_WINDOW, RT_PASSIVEGRAB, RT_CURSOR
599};
600
601static Bool
602ReplaceCursorLookup(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
643static void
644ReplaceCursor(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 its argument */
674    WindowHasNewCursor(screenInfo.screens[0]->root);
675}
676
677static Bool
678TestForCursor(CursorPtr pCursor, void *closure)
679{
680    return (pCursor == (CursorPtr) closure);
681}
682
683int
684ProcXFixesChangeCursor(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
700int _X_COLD
701SProcXFixesChangeCursor(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
712static Bool
713TestForCursorName(CursorPtr pCursor, void *closure)
714{
715    Atom *pName = closure;
716
717    return pCursor->name == *pName;
718}
719
720int
721ProcXFixesChangeCursorByName(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
739int _X_COLD
740SProcXFixesChangeCursorByName(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 */
758static CursorHideCountPtr
759findCursorHideCount(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
773static int
774createCursorHideCount(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 */
803static void
804deleteCursorHideCount(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 */
831static void
832deleteCursorHideCountsForScreen(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
846int
847ProcXFixesHideCursor(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
899int _X_COLD
900SProcXFixesHideCursor(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
910int
911ProcXFixesShowCursor(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
950int _X_COLD
951SProcXFixesShowCursor(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
961static int
962CursorFreeClient(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
977static int
978CursorFreeHideCount(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
993static int
994CursorFreeWindow(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
1008int
1009ProcXFixesCreatePointerBarrier(ClientPtr client)
1010{
1011    REQUEST(xXFixesCreatePointerBarrierReq);
1012
1013    REQUEST_FIXED_SIZE(xXFixesCreatePointerBarrierReq,
1014                       pad_to_int32(stuff->num_devices * sizeof(CARD16)));
1015    LEGAL_NEW_RESOURCE(stuff->barrier, client);
1016
1017    return XICreatePointerBarrier(client, stuff);
1018}
1019
1020int _X_COLD
1021SProcXFixesCreatePointerBarrier(ClientPtr client)
1022{
1023    REQUEST(xXFixesCreatePointerBarrierReq);
1024    int i;
1025    CARD16 *in_devices = (CARD16 *) &stuff[1];
1026
1027    REQUEST_AT_LEAST_SIZE(xXFixesCreatePointerBarrierReq);
1028
1029    swaps(&stuff->length);
1030    swaps(&stuff->num_devices);
1031    REQUEST_FIXED_SIZE(xXFixesCreatePointerBarrierReq,
1032                       pad_to_int32(stuff->num_devices * sizeof(CARD16)));
1033
1034    swapl(&stuff->barrier);
1035    swapl(&stuff->window);
1036    swaps(&stuff->x1);
1037    swaps(&stuff->y1);
1038    swaps(&stuff->x2);
1039    swaps(&stuff->y2);
1040    swapl(&stuff->directions);
1041    for (i = 0; i < stuff->num_devices; i++) {
1042        swaps(in_devices + i);
1043    }
1044
1045    return ProcXFixesVector[stuff->xfixesReqType] (client);
1046}
1047
1048int
1049ProcXFixesDestroyPointerBarrier(ClientPtr client)
1050{
1051    REQUEST(xXFixesDestroyPointerBarrierReq);
1052
1053    REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq);
1054
1055    return XIDestroyPointerBarrier(client, stuff);
1056}
1057
1058int _X_COLD
1059SProcXFixesDestroyPointerBarrier(ClientPtr client)
1060{
1061    REQUEST(xXFixesDestroyPointerBarrierReq);
1062
1063    swaps(&stuff->length);
1064    REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq);
1065    swapl(&stuff->barrier);
1066    return ProcXFixesVector[stuff->xfixesReqType] (client);
1067}
1068
1069Bool
1070XFixesCursorInit(void)
1071{
1072    int i;
1073
1074    if (party_like_its_1989)
1075        CursorVisible = EnableCursor;
1076    else
1077        CursorVisible = FALSE;
1078
1079    if (!dixRegisterPrivateKey(&CursorScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
1080        return FALSE;
1081
1082    for (i = 0; i < screenInfo.numScreens; i++) {
1083        ScreenPtr pScreen = screenInfo.screens[i];
1084        CursorScreenPtr cs;
1085
1086        cs = (CursorScreenPtr) calloc(1, sizeof(CursorScreenRec));
1087        if (!cs)
1088            return FALSE;
1089        Wrap(cs, pScreen, CloseScreen, CursorCloseScreen);
1090        Wrap(cs, pScreen, DisplayCursor, CursorDisplayCursor);
1091        cs->pCursorHideCounts = NULL;
1092        SetCursorScreen(pScreen, cs);
1093    }
1094    CursorClientType = CreateNewResourceType(CursorFreeClient,
1095                                             "XFixesCursorClient");
1096    CursorHideCountType = CreateNewResourceType(CursorFreeHideCount,
1097                                                "XFixesCursorHideCount");
1098    CursorWindowType = CreateNewResourceType(CursorFreeWindow,
1099                                             "XFixesCursorWindow");
1100
1101    return CursorClientType && CursorHideCountType && CursorWindowType;
1102}
1103