cursor.c revision 4642e01f
1/***********************************************************
2
3Copyright 1987, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25
26Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
27
28                        All Rights Reserved
29
30Permission to use, copy, modify, and distribute this software and its
31documentation for any purpose and without fee is hereby granted,
32provided that the above copyright notice appear in all copies and that
33both that copyright notice and this permission notice appear in
34supporting documentation, and that the name of Digital not be
35used in advertising or publicity pertaining to distribution of the
36software without specific, written prior permission.
37
38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44SOFTWARE.
45
46******************************************************************/
47
48
49
50#ifdef HAVE_DIX_CONFIG_H
51#include <dix-config.h>
52#endif
53
54#include <X11/X.h>
55#include <X11/Xmd.h>
56#include "servermd.h"
57#include "scrnintstr.h"
58#include "dixstruct.h"
59#include "cursorstr.h"
60#include "dixfontstr.h"
61#include "opaque.h"
62#include "inputstr.h"
63#include "xace.h"
64
65typedef struct _GlyphShare {
66    FontPtr font;
67    unsigned short sourceChar;
68    unsigned short maskChar;
69    CursorBitsPtr bits;
70    struct _GlyphShare *next;
71} GlyphShare, *GlyphSharePtr;
72
73static GlyphSharePtr sharedGlyphs = (GlyphSharePtr)NULL;
74
75#ifdef XFIXES
76static CARD32	cursorSerial;
77#endif
78
79static void
80FreeCursorBits(CursorBitsPtr bits)
81{
82    if (--bits->refcnt > 0)
83	return;
84    xfree(bits->source);
85    xfree(bits->mask);
86#ifdef ARGB_CURSOR
87    xfree(bits->argb);
88#endif
89    if (bits->refcnt == 0)
90    {
91	GlyphSharePtr *prev, this;
92
93	for (prev = &sharedGlyphs;
94	     (this = *prev) && (this->bits != bits);
95	     prev = &this->next)
96	    ;
97	if (this)
98	{
99	    *prev = this->next;
100	    CloseFont(this->font, (Font)0);
101	    xfree(this);
102	}
103	dixFreePrivates(bits->devPrivates);
104	xfree(bits);
105    }
106}
107
108/**
109 * To be called indirectly by DeleteResource; must use exactly two args.
110 *
111 *  \param value must conform to DeleteType
112 */
113_X_EXPORT int
114FreeCursor(pointer value, XID cid)
115{
116    int		nscr;
117    CursorPtr 	pCurs = (CursorPtr)value;
118
119    ScreenPtr	pscr;
120    DeviceIntPtr pDev = NULL; /* unused anyway */
121
122    if ( --pCurs->refcnt != 0)
123	return(Success);
124
125    for (nscr = 0; nscr < screenInfo.numScreens; nscr++)
126    {
127	pscr = screenInfo.screens[nscr];
128        (void)( *pscr->UnrealizeCursor)(pDev, pscr, pCurs);
129    }
130    dixFreePrivates(pCurs->devPrivates);
131    FreeCursorBits(pCurs->bits);
132    xfree( pCurs);
133    return(Success);
134}
135
136
137/*
138 * We check for empty cursors so that we won't have to display them
139 */
140static void
141CheckForEmptyMask(CursorBitsPtr bits)
142{
143    unsigned char *msk = bits->mask;
144    int n = BitmapBytePad(bits->width) * bits->height;
145
146    bits->emptyMask = FALSE;
147    while(n--)
148	if(*(msk++) != 0) return;
149#ifdef ARGB_CURSOR
150    if (bits->argb)
151    {
152	CARD32 *argb = bits->argb;
153	int n = bits->width * bits->height;
154	while (n--)
155	    if (*argb++ & 0xff000000) return;
156    }
157#endif
158    bits->emptyMask = TRUE;
159}
160
161/**
162 * does nothing about the resource table, just creates the data structure.
163 * does not copy the src and mask bits
164 *
165 *  \param psrcbits  server-defined padding
166 *  \param pmaskbits server-defined padding
167 *  \param argb      no padding
168 */
169int
170AllocARGBCursor(unsigned char *psrcbits, unsigned char *pmaskbits,
171		CARD32 *argb, CursorMetricPtr cm,
172		unsigned foreRed, unsigned foreGreen, unsigned foreBlue,
173		unsigned backRed, unsigned backGreen, unsigned backBlue,
174		CursorPtr *ppCurs, ClientPtr client, XID cid)
175{
176    CursorBitsPtr  bits;
177    CursorPtr 	pCurs;
178    int		rc, nscr;
179    ScreenPtr 	pscr;
180    DeviceIntPtr pDev;
181
182    *ppCurs = NULL;
183    pCurs = (CursorPtr)xcalloc(sizeof(CursorRec) + sizeof(CursorBits), 1);
184    if (!pCurs)
185    {
186	xfree(psrcbits);
187	xfree(pmaskbits);
188	return BadAlloc;
189    }
190    bits = (CursorBitsPtr)((char *)pCurs + sizeof(CursorRec));
191    bits->source = psrcbits;
192    bits->mask = pmaskbits;
193#ifdef ARGB_CURSOR
194    bits->argb = argb;
195#endif
196    bits->width = cm->width;
197    bits->height = cm->height;
198    bits->xhot = cm->xhot;
199    bits->yhot = cm->yhot;
200    pCurs->refcnt = 1;
201    bits->devPrivates = NULL;
202    bits->refcnt = -1;
203    CheckForEmptyMask(bits);
204    pCurs->bits = bits;
205#ifdef XFIXES
206    pCurs->serialNumber = ++cursorSerial;
207    pCurs->name = None;
208#endif
209
210    pCurs->foreRed = foreRed;
211    pCurs->foreGreen = foreGreen;
212    pCurs->foreBlue = foreBlue;
213
214    pCurs->backRed = backRed;
215    pCurs->backGreen = backGreen;
216    pCurs->backBlue = backBlue;
217
218    pCurs->id = cid;
219    pCurs->devPrivates = NULL;
220
221    /* security creation/labeling check */
222    rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR,
223		  pCurs, RT_NONE, NULL, DixCreateAccess);
224    if (rc != Success) {
225	dixFreePrivates(pCurs->devPrivates);
226	FreeCursorBits(bits);
227	xfree(pCurs);
228	return rc;
229    }
230
231    /*
232     * realize the cursor for every screen
233     * Do not change the refcnt, this will be changed when ChangeToCursor
234     * actually changes the sprite.
235     */
236    for (nscr = 0; nscr < screenInfo.numScreens; nscr++)
237    {
238        pscr = screenInfo.screens[nscr];
239        for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
240        {
241            if (DevHasCursor(pDev))
242            {
243                if (!( *pscr->RealizeCursor)(pDev, pscr, pCurs))
244                {
245                    /* Realize failed for device pDev on screen pscr.
246                     * We have to assume that for all devices before, realize
247                     * worked. We need to rollback all devices so far on the
248                     * current screen and then all devices on previous
249                     * screens.
250                     */
251                    DeviceIntPtr pDevIt = inputInfo.devices; /*dev iterator*/
252                    while(pDevIt && pDevIt != pDev)
253                    {
254                        if (DevHasCursor(pDevIt))
255                            ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs);
256                        pDevIt = pDevIt->next;
257                    }
258                    while (--nscr >= 0)
259                    {
260                        pscr = screenInfo.screens[nscr];
261                        /* now unrealize all devices on previous screens */
262                        pDevIt = inputInfo.devices;
263                        while (pDevIt)
264                        {
265                            if (DevHasCursor(pDevIt))
266                                ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs);
267                            pDevIt = pDevIt->next;
268                        }
269                        ( *pscr->UnrealizeCursor)(pDev, pscr, pCurs);
270                    }
271                    dixFreePrivates(pCurs->devPrivates);
272                    FreeCursorBits(bits);
273                    xfree(pCurs);
274                    return BadAlloc;
275                }
276            }
277        }
278    }
279    *ppCurs = pCurs;
280    return rc;
281}
282
283int
284AllocGlyphCursor(Font source, unsigned sourceChar, Font mask, unsigned maskChar,
285                unsigned foreRed, unsigned foreGreen, unsigned foreBlue,
286                unsigned backRed, unsigned backGreen, unsigned backBlue,
287		CursorPtr *ppCurs, ClientPtr client, XID cid)
288{
289    FontPtr  sourcefont, maskfont;
290    unsigned char   *srcbits;
291    unsigned char   *mskbits;
292    CursorMetricRec cm;
293    int rc;
294    CursorBitsPtr  bits;
295    CursorPtr 	pCurs;
296    int		nscr;
297    ScreenPtr 	pscr;
298    GlyphSharePtr pShare;
299    DeviceIntPtr pDev;
300
301    rc = dixLookupResource((pointer *)&sourcefont, source, RT_FONT, client,
302			   DixUseAccess);
303    if (rc != Success)
304    {
305	client->errorValue = source;
306	return (rc == BadValue) ? BadFont : rc;
307    }
308    rc = dixLookupResource((pointer *)&maskfont, mask, RT_FONT, client,
309			   DixUseAccess);
310    if (rc != Success && mask != None)
311    {
312	client->errorValue = mask;
313	return (rc == BadValue) ? BadFont : rc;
314    }
315    if (sourcefont != maskfont)
316	pShare = (GlyphSharePtr)NULL;
317    else
318    {
319	for (pShare = sharedGlyphs;
320	     pShare &&
321	     ((pShare->font != sourcefont) ||
322	      (pShare->sourceChar != sourceChar) ||
323	      (pShare->maskChar != maskChar));
324	     pShare = pShare->next)
325	    ;
326    }
327    if (pShare)
328    {
329	pCurs = (CursorPtr)xcalloc(sizeof(CursorRec), 1);
330	if (!pCurs)
331	    return BadAlloc;
332	bits = pShare->bits;
333	bits->refcnt++;
334    }
335    else
336    {
337	if (!CursorMetricsFromGlyph(sourcefont, sourceChar, &cm))
338	{
339	    client->errorValue = sourceChar;
340	    return BadValue;
341	}
342	if (!maskfont)
343	{
344	    long n;
345	    unsigned char *mskptr;
346
347	    n = BitmapBytePad(cm.width)*(long)cm.height;
348	    mskptr = mskbits = (unsigned char *)xalloc(n);
349	    if (!mskptr)
350		return BadAlloc;
351	    while (--n >= 0)
352		*mskptr++ = ~0;
353	}
354	else
355	{
356	    if (!CursorMetricsFromGlyph(maskfont, maskChar, &cm))
357	    {
358		client->errorValue = maskChar;
359		return BadValue;
360	    }
361	    if ((rc = ServerBitsFromGlyph(maskfont, maskChar, &cm, &mskbits)))
362		return rc;
363	}
364	if ((rc = ServerBitsFromGlyph(sourcefont, sourceChar, &cm, &srcbits)))
365	{
366	    xfree(mskbits);
367	    return rc;
368	}
369	if (sourcefont != maskfont)
370	{
371	    pCurs =
372                (CursorPtr)xcalloc(sizeof(CursorRec) + sizeof(CursorBits), 1);
373	    if (pCurs)
374		bits = (CursorBitsPtr)((char *)pCurs + sizeof(CursorRec));
375	    else
376		bits = (CursorBitsPtr)NULL;
377	}
378	else
379	{
380	    pCurs = (CursorPtr)xcalloc(sizeof(CursorRec), 1);
381	    if (pCurs)
382		bits = (CursorBitsPtr)xcalloc(sizeof(CursorBits), 1);
383	    else
384		bits = (CursorBitsPtr)NULL;
385	}
386	if (!bits)
387	{
388	    xfree(pCurs);
389	    xfree(mskbits);
390	    xfree(srcbits);
391	    return BadAlloc;
392	}
393	bits->source = srcbits;
394	bits->mask = mskbits;
395#ifdef ARGB_CURSOR
396	bits->argb = 0;
397#endif
398	bits->width = cm.width;
399	bits->height = cm.height;
400	bits->xhot = cm.xhot;
401	bits->yhot = cm.yhot;
402	bits->devPrivates = NULL;
403	if (sourcefont != maskfont)
404	    bits->refcnt = -1;
405	else
406	{
407	    bits->refcnt = 1;
408	    pShare = (GlyphSharePtr)xalloc(sizeof(GlyphShare));
409	    if (!pShare)
410	    {
411		FreeCursorBits(bits);
412		return BadAlloc;
413	    }
414	    pShare->font = sourcefont;
415	    sourcefont->refcnt++;
416	    pShare->sourceChar = sourceChar;
417	    pShare->maskChar = maskChar;
418	    pShare->bits = bits;
419	    pShare->next = sharedGlyphs;
420	    sharedGlyphs = pShare;
421	}
422    }
423
424    CheckForEmptyMask(bits);
425    pCurs->bits = bits;
426    pCurs->refcnt = 1;
427#ifdef XFIXES
428    pCurs->serialNumber = ++cursorSerial;
429    pCurs->name = None;
430#endif
431
432    pCurs->foreRed = foreRed;
433    pCurs->foreGreen = foreGreen;
434    pCurs->foreBlue = foreBlue;
435
436    pCurs->backRed = backRed;
437    pCurs->backGreen = backGreen;
438    pCurs->backBlue = backBlue;
439
440    pCurs->id = cid;
441    pCurs->devPrivates = NULL;
442
443    /* security creation/labeling check */
444    rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR,
445		  pCurs, RT_NONE, NULL, DixCreateAccess);
446    if (rc != Success) {
447	dixFreePrivates(pCurs->devPrivates);
448	FreeCursorBits(bits);
449	xfree(pCurs);
450	return rc;
451    }
452
453    /*
454     * realize the cursor for every screen
455     */
456    for (nscr = 0; nscr < screenInfo.numScreens; nscr++)
457    {
458        pscr = screenInfo.screens[nscr];
459
460        for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
461        {
462            if (DevHasCursor(pDev))
463            {
464                if (!( *pscr->RealizeCursor)(pDev, pscr, pCurs))
465                {
466                    /* Realize failed for device pDev on screen pscr.
467                     * We have to assume that for all devices before, realize
468                     * worked. We need to rollback all devices so far on the
469                     * current screen and then all devices on previous
470                     * screens.
471                     */
472                    DeviceIntPtr pDevIt = inputInfo.devices; /*dev iterator*/
473                    while(pDevIt && pDevIt != pDev)
474                    {
475                        if (DevHasCursor(pDevIt))
476                            ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs);
477                        pDevIt = pDevIt->next;
478                    }
479
480                    (*pscr->UnrealizeCursor)(inputInfo.pointer, pscr, pCurs);
481
482                    while (--nscr >= 0)
483                    {
484                        pscr = screenInfo.screens[nscr];
485                        /* now unrealize all devices on previous screens */
486                        ( *pscr->UnrealizeCursor)(inputInfo.pointer, pscr, pCurs);
487
488                        pDevIt = inputInfo.devices;
489                        while (pDevIt)
490                        {
491                            if (DevHasCursor(pDevIt))
492                                ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs);
493                            pDevIt = pDevIt->next;
494                        }
495                        ( *pscr->UnrealizeCursor)(pDev, pscr, pCurs);
496                    }
497                    dixFreePrivates(pCurs->devPrivates);
498                    FreeCursorBits(bits);
499                    xfree(pCurs);
500                    return BadAlloc;
501                }
502            }
503        }
504    }
505    *ppCurs = pCurs;
506    return Success;
507}
508
509/** CreateRootCursor
510 *
511 * look up the name of a font
512 * open the font
513 * add the font to the resource table
514 * make a cursor from the glyphs
515 * add the cursor to the resource table
516 *************************************************************/
517
518CursorPtr
519CreateRootCursor(char *unused1, unsigned int unused2)
520{
521    CursorPtr 	curs;
522#ifdef NULL_ROOT_CURSOR
523    CursorMetricRec cm;
524#else
525    FontPtr 	cursorfont;
526    int	err;
527    XID		fontID;
528#endif
529
530#ifdef NULL_ROOT_CURSOR
531    cm.width = 0;
532    cm.height = 0;
533    cm.xhot = 0;
534    cm.yhot = 0;
535
536    AllocARGBCursor(NULL, NULL, NULL, &cm, 0, 0, 0, 0, 0, 0,
537		    &curs, serverClient, (XID)0);
538
539    if (curs == NullCursor)
540        return NullCursor;
541#else
542    fontID = FakeClientID(0);
543    err = OpenFont(serverClient, fontID, FontLoadAll | FontOpenSync,
544	(unsigned)strlen(defaultCursorFont), defaultCursorFont);
545    if (err != Success)
546	return NullCursor;
547
548    cursorfont = (FontPtr)LookupIDByType(fontID, RT_FONT);
549    if (!cursorfont)
550	return NullCursor;
551    if (AllocGlyphCursor(fontID, 0, fontID, 1, 0, 0, 0, ~0, ~0, ~0,
552			 &curs, serverClient, (XID)0) != Success)
553	return NullCursor;
554#endif
555
556    if (!AddResource(FakeClientID(0), RT_CURSOR, (pointer)curs))
557	return NullCursor;
558
559    return curs;
560}
561