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