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