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