cursor.c revision 4642e01f
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 25 26Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 27 28 All Rights Reserved 29 30Permission to use, copy, modify, and distribute this software and its 31documentation for any purpose and without fee is hereby granted, 32provided that the above copyright notice appear in all copies and that 33both that copyright notice and this permission notice appear in 34supporting documentation, and that the name of Digital not be 35used in advertising or publicity pertaining to distribution of the 36software without specific, written prior permission. 37 38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 44SOFTWARE. 45 46******************************************************************/ 47 48 49 50#ifdef HAVE_DIX_CONFIG_H 51#include <dix-config.h> 52#endif 53 54#include <X11/X.h> 55#include <X11/Xmd.h> 56#include "servermd.h" 57#include "scrnintstr.h" 58#include "dixstruct.h" 59#include "cursorstr.h" 60#include "dixfontstr.h" 61#include "opaque.h" 62#include "inputstr.h" 63#include "xace.h" 64 65typedef struct _GlyphShare { 66 FontPtr font; 67 unsigned short sourceChar; 68 unsigned short maskChar; 69 CursorBitsPtr bits; 70 struct _GlyphShare *next; 71} GlyphShare, *GlyphSharePtr; 72 73static GlyphSharePtr sharedGlyphs = (GlyphSharePtr)NULL; 74 75#ifdef XFIXES 76static CARD32 cursorSerial; 77#endif 78 79static void 80FreeCursorBits(CursorBitsPtr bits) 81{ 82 if (--bits->refcnt > 0) 83 return; 84 xfree(bits->source); 85 xfree(bits->mask); 86#ifdef ARGB_CURSOR 87 xfree(bits->argb); 88#endif 89 if (bits->refcnt == 0) 90 { 91 GlyphSharePtr *prev, this; 92 93 for (prev = &sharedGlyphs; 94 (this = *prev) && (this->bits != bits); 95 prev = &this->next) 96 ; 97 if (this) 98 { 99 *prev = this->next; 100 CloseFont(this->font, (Font)0); 101 xfree(this); 102 } 103 dixFreePrivates(bits->devPrivates); 104 xfree(bits); 105 } 106} 107 108/** 109 * To be called indirectly by DeleteResource; must use exactly two args. 110 * 111 * \param value must conform to DeleteType 112 */ 113_X_EXPORT int 114FreeCursor(pointer value, XID cid) 115{ 116 int nscr; 117 CursorPtr pCurs = (CursorPtr)value; 118 119 ScreenPtr pscr; 120 DeviceIntPtr pDev = NULL; /* unused anyway */ 121 122 if ( --pCurs->refcnt != 0) 123 return(Success); 124 125 for (nscr = 0; nscr < screenInfo.numScreens; nscr++) 126 { 127 pscr = screenInfo.screens[nscr]; 128 (void)( *pscr->UnrealizeCursor)(pDev, pscr, pCurs); 129 } 130 dixFreePrivates(pCurs->devPrivates); 131 FreeCursorBits(pCurs->bits); 132 xfree( pCurs); 133 return(Success); 134} 135 136 137/* 138 * We check for empty cursors so that we won't have to display them 139 */ 140static void 141CheckForEmptyMask(CursorBitsPtr bits) 142{ 143 unsigned char *msk = bits->mask; 144 int n = BitmapBytePad(bits->width) * bits->height; 145 146 bits->emptyMask = FALSE; 147 while(n--) 148 if(*(msk++) != 0) return; 149#ifdef ARGB_CURSOR 150 if (bits->argb) 151 { 152 CARD32 *argb = bits->argb; 153 int n = bits->width * bits->height; 154 while (n--) 155 if (*argb++ & 0xff000000) return; 156 } 157#endif 158 bits->emptyMask = TRUE; 159} 160 161/** 162 * does nothing about the resource table, just creates the data structure. 163 * does not copy the src and mask bits 164 * 165 * \param psrcbits server-defined padding 166 * \param pmaskbits server-defined padding 167 * \param argb no padding 168 */ 169int 170AllocARGBCursor(unsigned char *psrcbits, unsigned char *pmaskbits, 171 CARD32 *argb, CursorMetricPtr cm, 172 unsigned foreRed, unsigned foreGreen, unsigned foreBlue, 173 unsigned backRed, unsigned backGreen, unsigned backBlue, 174 CursorPtr *ppCurs, ClientPtr client, XID cid) 175{ 176 CursorBitsPtr bits; 177 CursorPtr pCurs; 178 int rc, nscr; 179 ScreenPtr pscr; 180 DeviceIntPtr pDev; 181 182 *ppCurs = NULL; 183 pCurs = (CursorPtr)xcalloc(sizeof(CursorRec) + sizeof(CursorBits), 1); 184 if (!pCurs) 185 { 186 xfree(psrcbits); 187 xfree(pmaskbits); 188 return BadAlloc; 189 } 190 bits = (CursorBitsPtr)((char *)pCurs + sizeof(CursorRec)); 191 bits->source = psrcbits; 192 bits->mask = pmaskbits; 193#ifdef ARGB_CURSOR 194 bits->argb = argb; 195#endif 196 bits->width = cm->width; 197 bits->height = cm->height; 198 bits->xhot = cm->xhot; 199 bits->yhot = cm->yhot; 200 pCurs->refcnt = 1; 201 bits->devPrivates = NULL; 202 bits->refcnt = -1; 203 CheckForEmptyMask(bits); 204 pCurs->bits = bits; 205#ifdef XFIXES 206 pCurs->serialNumber = ++cursorSerial; 207 pCurs->name = None; 208#endif 209 210 pCurs->foreRed = foreRed; 211 pCurs->foreGreen = foreGreen; 212 pCurs->foreBlue = foreBlue; 213 214 pCurs->backRed = backRed; 215 pCurs->backGreen = backGreen; 216 pCurs->backBlue = backBlue; 217 218 pCurs->id = cid; 219 pCurs->devPrivates = NULL; 220 221 /* security creation/labeling check */ 222 rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, 223 pCurs, RT_NONE, NULL, DixCreateAccess); 224 if (rc != Success) { 225 dixFreePrivates(pCurs->devPrivates); 226 FreeCursorBits(bits); 227 xfree(pCurs); 228 return rc; 229 } 230 231 /* 232 * realize the cursor for every screen 233 * Do not change the refcnt, this will be changed when ChangeToCursor 234 * actually changes the sprite. 235 */ 236 for (nscr = 0; nscr < screenInfo.numScreens; nscr++) 237 { 238 pscr = screenInfo.screens[nscr]; 239 for (pDev = inputInfo.devices; pDev; pDev = pDev->next) 240 { 241 if (DevHasCursor(pDev)) 242 { 243 if (!( *pscr->RealizeCursor)(pDev, pscr, pCurs)) 244 { 245 /* Realize failed for device pDev on screen pscr. 246 * We have to assume that for all devices before, realize 247 * worked. We need to rollback all devices so far on the 248 * current screen and then all devices on previous 249 * screens. 250 */ 251 DeviceIntPtr pDevIt = inputInfo.devices; /*dev iterator*/ 252 while(pDevIt && pDevIt != pDev) 253 { 254 if (DevHasCursor(pDevIt)) 255 ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs); 256 pDevIt = pDevIt->next; 257 } 258 while (--nscr >= 0) 259 { 260 pscr = screenInfo.screens[nscr]; 261 /* now unrealize all devices on previous screens */ 262 pDevIt = inputInfo.devices; 263 while (pDevIt) 264 { 265 if (DevHasCursor(pDevIt)) 266 ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs); 267 pDevIt = pDevIt->next; 268 } 269 ( *pscr->UnrealizeCursor)(pDev, pscr, pCurs); 270 } 271 dixFreePrivates(pCurs->devPrivates); 272 FreeCursorBits(bits); 273 xfree(pCurs); 274 return BadAlloc; 275 } 276 } 277 } 278 } 279 *ppCurs = pCurs; 280 return rc; 281} 282 283int 284AllocGlyphCursor(Font source, unsigned sourceChar, Font mask, unsigned maskChar, 285 unsigned foreRed, unsigned foreGreen, unsigned foreBlue, 286 unsigned backRed, unsigned backGreen, unsigned backBlue, 287 CursorPtr *ppCurs, ClientPtr client, XID cid) 288{ 289 FontPtr sourcefont, maskfont; 290 unsigned char *srcbits; 291 unsigned char *mskbits; 292 CursorMetricRec cm; 293 int rc; 294 CursorBitsPtr bits; 295 CursorPtr pCurs; 296 int nscr; 297 ScreenPtr pscr; 298 GlyphSharePtr pShare; 299 DeviceIntPtr pDev; 300 301 rc = dixLookupResource((pointer *)&sourcefont, source, RT_FONT, client, 302 DixUseAccess); 303 if (rc != Success) 304 { 305 client->errorValue = source; 306 return (rc == BadValue) ? BadFont : rc; 307 } 308 rc = dixLookupResource((pointer *)&maskfont, mask, RT_FONT, client, 309 DixUseAccess); 310 if (rc != Success && mask != None) 311 { 312 client->errorValue = mask; 313 return (rc == BadValue) ? BadFont : rc; 314 } 315 if (sourcefont != maskfont) 316 pShare = (GlyphSharePtr)NULL; 317 else 318 { 319 for (pShare = sharedGlyphs; 320 pShare && 321 ((pShare->font != sourcefont) || 322 (pShare->sourceChar != sourceChar) || 323 (pShare->maskChar != maskChar)); 324 pShare = pShare->next) 325 ; 326 } 327 if (pShare) 328 { 329 pCurs = (CursorPtr)xcalloc(sizeof(CursorRec), 1); 330 if (!pCurs) 331 return BadAlloc; 332 bits = pShare->bits; 333 bits->refcnt++; 334 } 335 else 336 { 337 if (!CursorMetricsFromGlyph(sourcefont, sourceChar, &cm)) 338 { 339 client->errorValue = sourceChar; 340 return BadValue; 341 } 342 if (!maskfont) 343 { 344 long n; 345 unsigned char *mskptr; 346 347 n = BitmapBytePad(cm.width)*(long)cm.height; 348 mskptr = mskbits = (unsigned char *)xalloc(n); 349 if (!mskptr) 350 return BadAlloc; 351 while (--n >= 0) 352 *mskptr++ = ~0; 353 } 354 else 355 { 356 if (!CursorMetricsFromGlyph(maskfont, maskChar, &cm)) 357 { 358 client->errorValue = maskChar; 359 return BadValue; 360 } 361 if ((rc = ServerBitsFromGlyph(maskfont, maskChar, &cm, &mskbits))) 362 return rc; 363 } 364 if ((rc = ServerBitsFromGlyph(sourcefont, sourceChar, &cm, &srcbits))) 365 { 366 xfree(mskbits); 367 return rc; 368 } 369 if (sourcefont != maskfont) 370 { 371 pCurs = 372 (CursorPtr)xcalloc(sizeof(CursorRec) + sizeof(CursorBits), 1); 373 if (pCurs) 374 bits = (CursorBitsPtr)((char *)pCurs + sizeof(CursorRec)); 375 else 376 bits = (CursorBitsPtr)NULL; 377 } 378 else 379 { 380 pCurs = (CursorPtr)xcalloc(sizeof(CursorRec), 1); 381 if (pCurs) 382 bits = (CursorBitsPtr)xcalloc(sizeof(CursorBits), 1); 383 else 384 bits = (CursorBitsPtr)NULL; 385 } 386 if (!bits) 387 { 388 xfree(pCurs); 389 xfree(mskbits); 390 xfree(srcbits); 391 return BadAlloc; 392 } 393 bits->source = srcbits; 394 bits->mask = mskbits; 395#ifdef ARGB_CURSOR 396 bits->argb = 0; 397#endif 398 bits->width = cm.width; 399 bits->height = cm.height; 400 bits->xhot = cm.xhot; 401 bits->yhot = cm.yhot; 402 bits->devPrivates = NULL; 403 if (sourcefont != maskfont) 404 bits->refcnt = -1; 405 else 406 { 407 bits->refcnt = 1; 408 pShare = (GlyphSharePtr)xalloc(sizeof(GlyphShare)); 409 if (!pShare) 410 { 411 FreeCursorBits(bits); 412 return BadAlloc; 413 } 414 pShare->font = sourcefont; 415 sourcefont->refcnt++; 416 pShare->sourceChar = sourceChar; 417 pShare->maskChar = maskChar; 418 pShare->bits = bits; 419 pShare->next = sharedGlyphs; 420 sharedGlyphs = pShare; 421 } 422 } 423 424 CheckForEmptyMask(bits); 425 pCurs->bits = bits; 426 pCurs->refcnt = 1; 427#ifdef XFIXES 428 pCurs->serialNumber = ++cursorSerial; 429 pCurs->name = None; 430#endif 431 432 pCurs->foreRed = foreRed; 433 pCurs->foreGreen = foreGreen; 434 pCurs->foreBlue = foreBlue; 435 436 pCurs->backRed = backRed; 437 pCurs->backGreen = backGreen; 438 pCurs->backBlue = backBlue; 439 440 pCurs->id = cid; 441 pCurs->devPrivates = NULL; 442 443 /* security creation/labeling check */ 444 rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, 445 pCurs, RT_NONE, NULL, DixCreateAccess); 446 if (rc != Success) { 447 dixFreePrivates(pCurs->devPrivates); 448 FreeCursorBits(bits); 449 xfree(pCurs); 450 return rc; 451 } 452 453 /* 454 * realize the cursor for every screen 455 */ 456 for (nscr = 0; nscr < screenInfo.numScreens; nscr++) 457 { 458 pscr = screenInfo.screens[nscr]; 459 460 for (pDev = inputInfo.devices; pDev; pDev = pDev->next) 461 { 462 if (DevHasCursor(pDev)) 463 { 464 if (!( *pscr->RealizeCursor)(pDev, pscr, pCurs)) 465 { 466 /* Realize failed for device pDev on screen pscr. 467 * We have to assume that for all devices before, realize 468 * worked. We need to rollback all devices so far on the 469 * current screen and then all devices on previous 470 * screens. 471 */ 472 DeviceIntPtr pDevIt = inputInfo.devices; /*dev iterator*/ 473 while(pDevIt && pDevIt != pDev) 474 { 475 if (DevHasCursor(pDevIt)) 476 ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs); 477 pDevIt = pDevIt->next; 478 } 479 480 (*pscr->UnrealizeCursor)(inputInfo.pointer, pscr, pCurs); 481 482 while (--nscr >= 0) 483 { 484 pscr = screenInfo.screens[nscr]; 485 /* now unrealize all devices on previous screens */ 486 ( *pscr->UnrealizeCursor)(inputInfo.pointer, pscr, pCurs); 487 488 pDevIt = inputInfo.devices; 489 while (pDevIt) 490 { 491 if (DevHasCursor(pDevIt)) 492 ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs); 493 pDevIt = pDevIt->next; 494 } 495 ( *pscr->UnrealizeCursor)(pDev, pscr, pCurs); 496 } 497 dixFreePrivates(pCurs->devPrivates); 498 FreeCursorBits(bits); 499 xfree(pCurs); 500 return BadAlloc; 501 } 502 } 503 } 504 } 505 *ppCurs = pCurs; 506 return Success; 507} 508 509/** CreateRootCursor 510 * 511 * look up the name of a font 512 * open the font 513 * add the font to the resource table 514 * make a cursor from the glyphs 515 * add the cursor to the resource table 516 *************************************************************/ 517 518CursorPtr 519CreateRootCursor(char *unused1, unsigned int unused2) 520{ 521 CursorPtr curs; 522#ifdef NULL_ROOT_CURSOR 523 CursorMetricRec cm; 524#else 525 FontPtr cursorfont; 526 int err; 527 XID fontID; 528#endif 529 530#ifdef NULL_ROOT_CURSOR 531 cm.width = 0; 532 cm.height = 0; 533 cm.xhot = 0; 534 cm.yhot = 0; 535 536 AllocARGBCursor(NULL, NULL, NULL, &cm, 0, 0, 0, 0, 0, 0, 537 &curs, serverClient, (XID)0); 538 539 if (curs == NullCursor) 540 return NullCursor; 541#else 542 fontID = FakeClientID(0); 543 err = OpenFont(serverClient, fontID, FontLoadAll | FontOpenSync, 544 (unsigned)strlen(defaultCursorFont), defaultCursorFont); 545 if (err != Success) 546 return NullCursor; 547 548 cursorfont = (FontPtr)LookupIDByType(fontID, RT_FONT); 549 if (!cursorfont) 550 return NullCursor; 551 if (AllocGlyphCursor(fontID, 0, fontID, 1, 0, 0, 0, ~0, ~0, ~0, 552 &curs, serverClient, (XID)0) != Success) 553 return NullCursor; 554#endif 555 556 if (!AddResource(FakeClientID(0), RT_CURSOR, (pointer)curs)) 557 return NullCursor; 558 559 return curs; 560} 561