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