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