Imported Upstream version 1.15.1
[deb_xorg-server.git] / dix / cursor.c
CommitLineData
a09e091a
JB
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#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 */
106int
107FreeCursor(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
132CursorPtr
133RefCursor(CursorPtr cursor)
134{
135 if (cursor)
136 cursor->refcnt++;
137 return cursor;
138}
139
140CursorPtr
141UnrefCursor(CursorPtr cursor)
142{
143 if (cursor)
144 cursor->refcnt--;
145 return cursor;
146}
147
148int
149CursorRefCount(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 */
158static void
159CheckForEmptyMask(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 */
188static int
189RealizeCursorAllScreens(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 */
241int
242AllocARGBCursor(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
307int
308AllocGlyphCursor(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
475CursorPtr
476CreateRootCursor(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}