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