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