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