cursor.c revision 05b261ec
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
63typedef struct _GlyphShare {
64    FontPtr font;
65    unsigned short sourceChar;
66    unsigned short maskChar;
67    CursorBitsPtr bits;
68    struct _GlyphShare *next;
69} GlyphShare, *GlyphSharePtr;
70
71static GlyphSharePtr sharedGlyphs = (GlyphSharePtr)NULL;
72
73#ifdef XFIXES
74static CARD32	cursorSerial;
75#endif
76
77static void
78FreeCursorBits(CursorBitsPtr bits)
79{
80    if (--bits->refcnt > 0)
81	return;
82    xfree(bits->source);
83    xfree(bits->mask);
84#ifdef ARGB_CURSOR
85    xfree(bits->argb);
86#endif
87    if (bits->refcnt == 0)
88    {
89	GlyphSharePtr *prev, this;
90
91	for (prev = &sharedGlyphs;
92	     (this = *prev) && (this->bits != bits);
93	     prev = &this->next)
94	    ;
95	if (this)
96	{
97	    *prev = this->next;
98	    CloseFont(this->font, (Font)0);
99	    xfree(this);
100	}
101	xfree(bits);
102    }
103}
104
105/**
106 * To be called indirectly by DeleteResource; must use exactly two args.
107 *
108 *  \param value must conform to DeleteType
109 */
110_X_EXPORT int
111FreeCursor(pointer value, XID cid)
112{
113    int		nscr;
114    CursorPtr 	pCurs = (CursorPtr)value;
115
116    ScreenPtr	pscr;
117
118    if ( --pCurs->refcnt > 0)
119	return(Success);
120
121    for (nscr = 0; nscr < screenInfo.numScreens; nscr++)
122    {
123	pscr = screenInfo.screens[nscr];
124	(void)( *pscr->UnrealizeCursor)( pscr, pCurs);
125    }
126    FreeCursorBits(pCurs->bits);
127    xfree( pCurs);
128    return(Success);
129}
130
131
132/*
133 * We check for empty cursors so that we won't have to display them
134 */
135static void
136CheckForEmptyMask(CursorBitsPtr bits)
137{
138    unsigned char *msk = bits->mask;
139    int n = BitmapBytePad(bits->width) * bits->height;
140
141    bits->emptyMask = FALSE;
142    while(n--)
143	if(*(msk++) != 0) return;
144#ifdef ARGB_CURSOR
145    if (bits->argb)
146    {
147	CARD32 *argb = bits->argb;
148	int n = bits->width * bits->height;
149	while (n--)
150	    if (*argb++ & 0xff000000) return;
151    }
152#endif
153    bits->emptyMask = TRUE;
154}
155
156/**
157 * does nothing about the resource table, just creates the data structure.
158 * does not copy the src and mask bits
159 *
160 *  \param psrcbits  server-defined padding
161 *  \param pmaskbits server-defined padding
162 *  \param argb      no padding
163 */
164CursorPtr
165AllocCursorARGB(unsigned char *psrcbits, unsigned char *pmaskbits, CARD32 *argb,
166                CursorMetricPtr cm,
167                unsigned foreRed, unsigned foreGreen, unsigned foreBlue,
168                unsigned backRed, unsigned backGreen, unsigned backBlue)
169{
170    CursorBitsPtr  bits;
171    CursorPtr 	pCurs;
172    int		nscr;
173    ScreenPtr 	pscr;
174
175    pCurs = (CursorPtr)xalloc(sizeof(CursorRec) + sizeof(CursorBits));
176    if (!pCurs)
177    {
178	xfree(psrcbits);
179	xfree(pmaskbits);
180	return (CursorPtr)NULL;
181    }
182    bits = (CursorBitsPtr)((char *)pCurs + sizeof(CursorRec));
183    bits->source = psrcbits;
184    bits->mask = pmaskbits;
185#ifdef ARGB_CURSOR
186    bits->argb = argb;
187#endif
188    bits->width = cm->width;
189    bits->height = cm->height;
190    bits->xhot = cm->xhot;
191    bits->yhot = cm->yhot;
192    bits->refcnt = -1;
193    CheckForEmptyMask(bits);
194
195    pCurs->bits = bits;
196    pCurs->refcnt = 1;
197#ifdef XFIXES
198    pCurs->serialNumber = ++cursorSerial;
199    pCurs->name = None;
200#endif
201
202    pCurs->foreRed = foreRed;
203    pCurs->foreGreen = foreGreen;
204    pCurs->foreBlue = foreBlue;
205
206    pCurs->backRed = backRed;
207    pCurs->backGreen = backGreen;
208    pCurs->backBlue = backBlue;
209
210    /*
211     * realize the cursor for every screen
212     */
213    for (nscr = 0; nscr < screenInfo.numScreens; nscr++)
214    {
215	pscr = screenInfo.screens[nscr];
216        if (!( *pscr->RealizeCursor)( pscr, pCurs))
217	{
218	    while (--nscr >= 0)
219	    {
220		pscr = screenInfo.screens[nscr];
221		( *pscr->UnrealizeCursor)( pscr, pCurs);
222	    }
223	    FreeCursorBits(bits);
224	    xfree(pCurs);
225	    return (CursorPtr)NULL;
226	}
227    }
228    return pCurs;
229}
230
231/**
232 *
233 * \param psrcbits   server-defined padding
234 * \param pmaskbits  server-defined padding
235 */
236CursorPtr
237AllocCursor(unsigned char *psrcbits, unsigned char *pmaskbits,
238            CursorMetricPtr cm,
239            unsigned foreRed, unsigned foreGreen, unsigned foreBlue,
240            unsigned backRed, unsigned backGreen, unsigned backBlue)
241{
242    return AllocCursorARGB (psrcbits, pmaskbits, (CARD32 *) 0, cm,
243			    foreRed, foreGreen, foreBlue,
244			    backRed, backGreen, backBlue);
245}
246
247int
248AllocGlyphCursor(Font source, unsigned sourceChar, Font mask, unsigned maskChar,
249                unsigned foreRed, unsigned foreGreen, unsigned foreBlue,
250                unsigned backRed, unsigned backGreen, unsigned backBlue,
251                CursorPtr *ppCurs, ClientPtr client)
252{
253    FontPtr  sourcefont, maskfont;
254    unsigned char   *srcbits;
255    unsigned char   *mskbits;
256    CursorMetricRec cm;
257    int res;
258    CursorBitsPtr  bits;
259    CursorPtr 	pCurs;
260    int		nscr;
261    ScreenPtr 	pscr;
262    GlyphSharePtr pShare;
263
264    sourcefont = (FontPtr) SecurityLookupIDByType(client, source, RT_FONT,
265						  DixReadAccess);
266    maskfont = (FontPtr) SecurityLookupIDByType(client, mask, RT_FONT,
267						DixReadAccess);
268
269    if (!sourcefont)
270    {
271	client->errorValue = source;
272	return(BadFont);
273    }
274    if (!maskfont && (mask != None))
275    {
276	client->errorValue = mask;
277	return(BadFont);
278    }
279    if (sourcefont != maskfont)
280	pShare = (GlyphSharePtr)NULL;
281    else
282    {
283	for (pShare = sharedGlyphs;
284	     pShare &&
285	     ((pShare->font != sourcefont) ||
286	      (pShare->sourceChar != sourceChar) ||
287	      (pShare->maskChar != maskChar));
288	     pShare = pShare->next)
289	    ;
290    }
291    if (pShare)
292    {
293	pCurs = (CursorPtr)xalloc(sizeof(CursorRec));
294	if (!pCurs)
295	    return BadAlloc;
296	bits = pShare->bits;
297	bits->refcnt++;
298    }
299    else
300    {
301	if (!CursorMetricsFromGlyph(sourcefont, sourceChar, &cm))
302	{
303	    client->errorValue = sourceChar;
304	    return BadValue;
305	}
306	if (!maskfont)
307	{
308	    long n;
309	    unsigned char *mskptr;
310
311	    n = BitmapBytePad(cm.width)*(long)cm.height;
312	    mskptr = mskbits = (unsigned char *)xalloc(n);
313	    if (!mskptr)
314		return BadAlloc;
315	    while (--n >= 0)
316		*mskptr++ = ~0;
317	}
318	else
319	{
320	    if (!CursorMetricsFromGlyph(maskfont, maskChar, &cm))
321	    {
322		client->errorValue = maskChar;
323		return BadValue;
324	    }
325	    if ((res = ServerBitsFromGlyph(maskfont, maskChar, &cm, &mskbits)) != 0)
326		return res;
327	}
328	if ((res = ServerBitsFromGlyph(sourcefont, sourceChar, &cm, &srcbits)) != 0)
329	{
330	    xfree(mskbits);
331	    return res;
332	}
333	if (sourcefont != maskfont)
334	{
335	    pCurs = (CursorPtr)xalloc(sizeof(CursorRec) + sizeof(CursorBits));
336	    if (pCurs)
337		bits = (CursorBitsPtr)((char *)pCurs + sizeof(CursorRec));
338	    else
339		bits = (CursorBitsPtr)NULL;
340	}
341	else
342	{
343	    pCurs = (CursorPtr)xalloc(sizeof(CursorRec));
344	    if (pCurs)
345		bits = (CursorBitsPtr)xalloc(sizeof(CursorBits));
346	    else
347		bits = (CursorBitsPtr)NULL;
348	}
349	if (!bits)
350	{
351	    xfree(pCurs);
352	    xfree(mskbits);
353	    xfree(srcbits);
354	    return BadAlloc;
355	}
356	bits->source = srcbits;
357	bits->mask = mskbits;
358#ifdef ARGB_CURSOR
359	bits->argb = 0;
360#endif
361	bits->width = cm.width;
362	bits->height = cm.height;
363	bits->xhot = cm.xhot;
364	bits->yhot = cm.yhot;
365	if (sourcefont != maskfont)
366	    bits->refcnt = -1;
367	else
368	{
369	    bits->refcnt = 1;
370	    pShare = (GlyphSharePtr)xalloc(sizeof(GlyphShare));
371	    if (!pShare)
372	    {
373		FreeCursorBits(bits);
374		return BadAlloc;
375	    }
376	    pShare->font = sourcefont;
377	    sourcefont->refcnt++;
378	    pShare->sourceChar = sourceChar;
379	    pShare->maskChar = maskChar;
380	    pShare->bits = bits;
381	    pShare->next = sharedGlyphs;
382	    sharedGlyphs = pShare;
383	}
384    }
385    CheckForEmptyMask(bits);
386    pCurs->bits = bits;
387    pCurs->refcnt = 1;
388#ifdef XFIXES
389    pCurs->serialNumber = ++cursorSerial;
390    pCurs->name = None;
391#endif
392
393    pCurs->foreRed = foreRed;
394    pCurs->foreGreen = foreGreen;
395    pCurs->foreBlue = foreBlue;
396
397    pCurs->backRed = backRed;
398    pCurs->backGreen = backGreen;
399    pCurs->backBlue = backBlue;
400
401    /*
402     * realize the cursor for every screen
403     */
404    for (nscr = 0; nscr < screenInfo.numScreens; nscr++)
405    {
406	pscr = screenInfo.screens[nscr];
407        if (!( *pscr->RealizeCursor)( pscr, pCurs))
408	{
409	    while (--nscr >= 0)
410	    {
411		pscr = screenInfo.screens[nscr];
412		( *pscr->UnrealizeCursor)( pscr, pCurs);
413	    }
414	    FreeCursorBits(pCurs->bits);
415	    xfree(pCurs);
416	    return BadAlloc;
417	}
418    }
419    *ppCurs = pCurs;
420    return Success;
421}
422
423/** CreateRootCursor
424 *
425 * look up the name of a font
426 * open the font
427 * add the font to the resource table
428 * make a cursor from the glyphs
429 * add the cursor to the resource table
430 *************************************************************/
431
432CursorPtr
433CreateRootCursor(char *unused1, unsigned int unused2)
434{
435    CursorPtr 	curs;
436#ifdef NULL_ROOT_CURSOR
437    CursorMetricRec cm;
438#else
439    FontPtr 	cursorfont;
440    int	err;
441    XID		fontID;
442#endif
443
444#ifdef NULL_ROOT_CURSOR
445    cm.width = 0;
446    cm.height = 0;
447    cm.xhot = 0;
448    cm.yhot = 0;
449
450    curs = AllocCursor(NULL, NULL, &cm, 0, 0, 0, 0, 0, 0);
451
452    if (curs == NullCursor)
453        return NullCursor;
454#else
455    fontID = FakeClientID(0);
456    err = OpenFont(serverClient, fontID, FontLoadAll | FontOpenSync,
457	(unsigned)strlen(defaultCursorFont), defaultCursorFont);
458    if (err != Success)
459	return NullCursor;
460
461    cursorfont = (FontPtr)LookupIDByType(fontID, RT_FONT);
462    if (!cursorfont)
463	return NullCursor;
464    if (AllocGlyphCursor(fontID, 0, fontID, 1,
465			 0, 0, 0, ~0, ~0, ~0, &curs, serverClient) != Success)
466	return NullCursor;
467#endif
468
469    if (!AddResource(FakeClientID(0), RT_CURSOR, (pointer)curs))
470	return NullCursor;
471
472    return curs;
473}
474