1 /***********************************************************
2 
3 Copyright 1987, 1998  The Open Group
4 
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24 
25 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
26 
27                         All Rights Reserved
28 
29 Permission to use, copy, modify, and distribute this software and its
30 documentation for any purpose and without fee is hereby granted,
31 provided that the above copyright notice appear in all copies and that
32 both that copyright notice and this permission notice appear in
33 supporting documentation, and that the name of Digital not be
34 used in advertising or publicity pertaining to distribution of the
35 software without specific, written prior permission.
36 
37 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43 SOFTWARE.
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 
62 typedef struct _GlyphShare {
63     FontPtr font;
64     unsigned short sourceChar;
65     unsigned short maskChar;
66     CursorBitsPtr bits;
67     struct _GlyphShare *next;
68 } GlyphShare, *GlyphSharePtr;
69 
70 static GlyphSharePtr sharedGlyphs = (GlyphSharePtr) NULL;
71 
72 DevScreenPrivateKeyRec cursorScreenDevPriv;
73 
74 static CARD32 cursorSerial;
75 
76 static void
FreeCursorBits(CursorBitsPtr bits)77 FreeCursorBits(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  */
104 int
FreeCursor(void * value,XID cid)105 FreeCursor(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 
130 CursorPtr
RefCursor(CursorPtr cursor)131 RefCursor(CursorPtr cursor)
132 {
133     if (cursor)
134         cursor->refcnt++;
135     return cursor;
136 }
137 
138 CursorPtr
UnrefCursor(CursorPtr cursor)139 UnrefCursor(CursorPtr cursor)
140 {
141     if (cursor)
142         cursor->refcnt--;
143     return cursor;
144 }
145 
146 int
CursorRefCount(const CursorPtr cursor)147 CursorRefCount(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  */
156 static void
CheckForEmptyMask(CursorBitsPtr bits)157 CheckForEmptyMask(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  */
184 static int
RealizeCursorAllScreens(CursorPtr pCurs)185 RealizeCursorAllScreens(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  */
237 int
AllocARGBCursor(unsigned char * psrcbits,unsigned char * pmaskbits,CARD32 * argb,CursorMetricPtr cm,unsigned foreRed,unsigned foreGreen,unsigned foreBlue,unsigned backRed,unsigned backGreen,unsigned backBlue,CursorPtr * ppCurs,ClientPtr client,XID cid)238 AllocARGBCursor(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 
324 int
AllocGlyphCursor(Font source,unsigned sourceChar,Font mask,unsigned maskChar,unsigned foreRed,unsigned foreGreen,unsigned foreBlue,unsigned backRed,unsigned backGreen,unsigned backBlue,CursorPtr * ppCurs,ClientPtr client,XID cid)325 AllocGlyphCursor(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 
490 CursorPtr
CreateRootCursor(char * unused1,unsigned int unused2)491 CreateRootCursor(char *unused1, unsigned int unused2)
492 {
493     CursorPtr curs;
494     FontPtr cursorfont;
495     int err;
496     XID fontID;
497 
498     fontID = FakeClientID(0);
499     err = OpenFont(serverClient, fontID, FontLoadAll | FontOpenSync,
500                    (unsigned) strlen(defaultCursorFont), defaultCursorFont);
501     if (err != Success)
502         return NullCursor;
503 
504     err = dixLookupResourceByType((void **) &cursorfont, fontID, RT_FONT,
505                                   serverClient, DixReadAccess);
506     if (err != Success)
507         return NullCursor;
508     if (AllocGlyphCursor(fontID, 0, fontID, 1, 0, 0, 0, ~0, ~0, ~0,
509                          &curs, serverClient, (XID) 0) != Success)
510         return NullCursor;
511 
512     if (!AddResource(FakeClientID(0), RT_CURSOR, (void *) curs))
513         return NullCursor;
514 
515     return curs;
516 }
517