cursor.c revision 4d939ec7
1/* 2 * Copyright © 2002 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that 7 * copyright notice and this permission notice appear in supporting 8 * documentation, and that the name of Keith Packard not be used in 9 * advertising or publicity pertaining to distribution of the software without 10 * specific, written prior permission. Keith Packard makes no 11 * representations about the suitability of this software for any purpose. It 12 * is provided "as is" without express or implied warranty. 13 * 14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20 * PERFORMANCE OF THIS SOFTWARE. 21 */ 22 23#include "xcursorint.h" 24#include <X11/Xlibint.h> 25#include <X11/Xutil.h> 26 27XcursorCursors * 28XcursorCursorsCreate (Display *dpy, int size) 29{ 30 XcursorCursors *cursors; 31 32 cursors = malloc (sizeof (XcursorCursors) + 33 (size_t) size * sizeof (Cursor)); 34 if (!cursors) 35 return NULL; 36 cursors->ref = 1; 37 cursors->dpy = dpy; 38 cursors->ncursor = 0; 39 cursors->cursors = (Cursor *) (cursors + 1); 40 return cursors; 41} 42 43void 44XcursorCursorsDestroy (XcursorCursors *cursors) 45{ 46 int n; 47 48 if (!cursors) 49 return; 50 51 --cursors->ref; 52 if (cursors->ref > 0) 53 return; 54 55 for (n = 0; n < cursors->ncursor; n++) 56 XFreeCursor (cursors->dpy, cursors->cursors[n]); 57 free (cursors); 58} 59 60XcursorAnimate * 61XcursorAnimateCreate (XcursorCursors *cursors) 62{ 63 XcursorAnimate *animate; 64 65 animate = malloc (sizeof (XcursorAnimate)); 66 if (!animate) 67 return NULL; 68 animate->cursors = cursors; 69 cursors->ref++; 70 animate->sequence = 0; 71 return animate; 72} 73 74void 75XcursorAnimateDestroy (XcursorAnimate *animate) 76{ 77 if (!animate) 78 return; 79 80 XcursorCursorsDestroy (animate->cursors); 81 free (animate); 82} 83 84Cursor 85XcursorAnimateNext (XcursorAnimate *animate) 86{ 87 Cursor cursor = animate->cursors->cursors[animate->sequence++]; 88 89 if (animate->sequence >= animate->cursors->ncursor) 90 animate->sequence = 0; 91 return cursor; 92} 93 94#if RENDER_MAJOR > 0 || RENDER_MINOR >= 5 95static int 96nativeByteOrder (void) 97{ 98 int x = 1; 99 100 return (*((char *) &x) == 1) ? LSBFirst : MSBFirst; 101} 102#endif 103 104static XcursorUInt 105_XcursorPixelBrightness (XcursorPixel p) 106{ 107 XcursorPixel alpha = p >> 24; 108 XcursorPixel r, g, b; 109 110 if (!alpha) 111 return 0; 112 r = ((p >> 8) & 0xff00) / alpha; 113 if (r > 0xff) r = 0xff; 114 g = ((p >> 0) & 0xff00) / alpha; 115 if (g > 0xff) g = 0xff; 116 b = ((p << 8) & 0xff00) / alpha; 117 if (b > 0xff) b = 0xff; 118 return (r * 153 + g * 301 + b * 58) >> 9; 119} 120 121static unsigned short 122_XcursorDivideAlpha (XcursorUInt value, XcursorUInt alpha) 123{ 124 if (!alpha) 125 return 0; 126 value = value * 255 / alpha; 127 if (value > 255) 128 value = 255; 129 return (unsigned short) (value | (value << 8)); 130} 131 132static void 133_XcursorPixelToColor (XcursorPixel p, XColor *color) 134{ 135 XcursorPixel alpha = p >> 24; 136 137 color->pixel = 0; 138 color->red = _XcursorDivideAlpha ((p >> 16) & 0xff, alpha); 139 color->green = _XcursorDivideAlpha ((p >> 8) & 0xff, alpha); 140 color->blue = _XcursorDivideAlpha ((p >> 0) & 0xff, alpha); 141 color->flags = DoRed|DoGreen|DoBlue; 142} 143 144#undef DEBUG_IMAGE 145#ifdef DEBUG_IMAGE 146static void 147_XcursorDumpImage (XImage *image) 148{ 149 FILE *f = fopen ("/tmp/images", "a"); 150 int x, y; 151 if (!f) 152 return; 153 fprintf (f, "%d x %x\n", image->width, image->height); 154 for (y = 0; y < image->height; y++) 155 { 156 for (x = 0; x < image->width; x++) 157 fprintf (f, "%c", XGetPixel (image, x, y) ? '*' : ' '); 158 fprintf (f, "\n"); 159 } 160 fflush (f); 161 fclose (f); 162} 163 164static void 165_XcursorDumpColor (XColor *color, char *name) 166{ 167 FILE *f = fopen ("/tmp/images", "a"); 168 fprintf (f, "%s: %x %x %x\n", name, 169 color->red, color->green, color->blue); 170 fflush (f); 171 fclose (f); 172} 173#endif 174 175static int 176_XcursorCompareRed (const void *a, const void *b) 177{ 178 const XcursorPixel *ap = a, *bp = b; 179 180 return (int) (((*ap >> 16) & 0xff) - ((*bp >> 16) & 0xff)); 181} 182 183static int 184_XcursorCompareGreen (const void *a, const void *b) 185{ 186 const XcursorPixel *ap = a, *bp = b; 187 188 return (int) (((*ap >> 8) & 0xff) - ((*bp >> 8) & 0xff)); 189} 190 191static int 192_XcursorCompareBlue (const void *a, const void *b) 193{ 194 const XcursorPixel *ap = a, *bp = b; 195 196 return (int) (((*ap >> 0) & 0xff) - ((*bp >> 0) & 0xff)); 197} 198 199#define ScaledPixels(c,n) ((c)/(XcursorPixel)(n)) 200 201static XcursorPixel 202_XcursorAverageColor (XcursorPixel *pixels, int npixels) 203{ 204 XcursorPixel p; 205 XcursorPixel red, green, blue; 206 int n = npixels; 207 208 if (n < 1) 209 return 0; 210 211 blue = green = red = 0; 212 while (n--) 213 { 214 p = *pixels++; 215 red += (p >> 16) & 0xff; 216 green += (p >> 8) & 0xff; 217 blue += (p >> 0) & 0xff; 218 } 219 return (0xffU << 24) 220 | (ScaledPixels(red, npixels) << 16) 221 | (ScaledPixels(green, npixels) << 8) 222 | ScaledPixels(blue, npixels); 223} 224 225typedef struct XcursorCoreCursor { 226 XImage *src_image; 227 XImage *msk_image; 228 XColor on_color; 229 XColor off_color; 230} XcursorCoreCursor; 231 232static Bool 233_XcursorHeckbertMedianCut (const XcursorImage *image, XcursorCoreCursor *core) 234{ 235 XImage *src_image = core->src_image, *msk_image = core->msk_image; 236 unsigned int npixels = image->width * image->height; 237 int ncolors; 238 int n; 239 XcursorPixel *po, *pn, *pc; 240 XcursorPixel p; 241 XcursorPixel red, green, blue, alpha; 242 XcursorPixel max_red, min_red, max_green, min_green, max_blue, min_blue; 243 XcursorPixel *temp, *pixels, *colors; 244 int split; 245 XcursorPixel leftColor, centerColor, rightColor; 246 int (*compare) (const void *, const void *); 247 int x, y; 248 249 /* 250 * Temp space for converted image and converted colors 251 */ 252 temp = malloc (npixels * sizeof (XcursorPixel) * 2); 253 if (!temp) 254 return False; 255 256 pixels = temp; 257 colors = pixels + npixels; 258 259 /* 260 * Convert to 2-value alpha and build 261 * array of opaque color values and an 262 */ 263 po = image->pixels; 264 pn = pixels; 265 pc = colors; 266 max_blue = max_green = max_red = 0; 267 min_blue = min_green = min_red = 255; 268 n = (int) npixels; 269 while (n--) 270 { 271 p = *po++; 272 alpha = (p >> 24) & 0xff; 273 red = (p >> 16) & 0xff; 274 green = (p >> 8) & 0xff; 275 blue = (p >> 0) & 0xff; 276 if (alpha >= 0x80) 277 { 278 red = red * 255 / alpha; 279 green = green * 255 / alpha; 280 blue = blue * 255 / alpha; 281 if (red < min_red) min_red = red; 282 if (red > max_red) max_red = red; 283 if (green < min_green) min_green = green; 284 if (green > max_green) max_green = green; 285 if (blue < min_blue) min_blue = blue; 286 if (blue > max_blue) max_blue = blue; 287 p = ((0xffU << 24) | (red << 16) | 288 (green << 8) | (blue << 0)); 289 *pc++ = p; 290 } 291 else 292 p = 0; 293 *pn++ = p; 294 } 295 ncolors = (int) (pc - colors); 296 297 /* 298 * Compute longest dimension and sort 299 */ 300 if ((max_green - min_green) >= (max_red - min_red) && 301 (max_green - min_green) >= (max_blue - min_blue)) 302 compare = _XcursorCompareGreen; 303 else if ((max_red - min_red) >= (max_blue - min_blue)) 304 compare = _XcursorCompareRed; 305 else 306 compare = _XcursorCompareBlue; 307 qsort (colors, (size_t) ncolors, sizeof (XcursorPixel), compare); 308 /* 309 * Compute average colors on both sides of the cut 310 */ 311 split = ncolors >> 1; 312 leftColor = _XcursorAverageColor (colors, split); 313 centerColor = colors[split]; 314 rightColor = _XcursorAverageColor (colors + split, ncolors - split); 315 /* 316 * Select best color for each pixel 317 */ 318 pn = pixels; 319 for (y = 0; (unsigned) y < image->height; y++) 320 for (x = 0; (unsigned) x < image->width; x++) 321 { 322 p = *pn++; 323 if (p & 0xff000000) 324 { 325 XPutPixel (msk_image, x, y, 1); 326 if ((*compare) (&p, ¢erColor) >= 0) 327 XPutPixel (src_image, x, y, 0); 328 else 329 XPutPixel (src_image, x, y, 1); 330 } 331 else 332 { 333 XPutPixel (msk_image, x, y, 0); 334 XPutPixel (src_image, x, y, 0); 335 } 336 } 337 free (temp); 338 _XcursorPixelToColor (rightColor, &core->off_color); 339 _XcursorPixelToColor (leftColor, &core->on_color); 340 return True; 341} 342 343#if 0 344#define DITHER_DIM 4 345static XcursorPixel orderedDither[4][4] = { 346 { 1, 9, 3, 11 }, 347 { 13, 5, 15, 7 }, 348 { 4, 12, 2, 10 }, 349 { 16, 8, 14, 6 } 350}; 351#else 352#define DITHER_DIM 2 353static XcursorPixel orderedDither[2][2] = { 354 { 1, 3, }, 355 { 4, 2, }, 356}; 357#endif 358 359#define DITHER_SIZE ((sizeof orderedDither / sizeof orderedDither[0][0]) + 1) 360 361static Bool 362_XcursorBayerOrderedDither (const XcursorImage *image, XcursorCoreCursor *core) 363{ 364 int x, y; 365 XcursorPixel *pixel, p; 366 XcursorPixel a, i, d; 367 368 pixel = image->pixels; 369 for (y = 0; (unsigned) y < image->height; y++) 370 for (x = 0; (unsigned) x < image->width; x++) 371 { 372 p = *pixel++; 373 a = (XcursorPixel) (((p >> 24) * DITHER_SIZE + 127) / 255); 374 i = (XcursorPixel) ((_XcursorPixelBrightness (p) * DITHER_SIZE + 127) / 255); 375 d = orderedDither[y&(DITHER_DIM-1)][x&(DITHER_DIM-1)]; 376 if (a > d) 377 { 378 XPutPixel (core->msk_image, x, y, 1); 379 if (i > d) 380 XPutPixel (core->src_image, x, y, 0); /* white */ 381 else 382 XPutPixel (core->src_image, x, y, 1); /* black */ 383 } 384 else 385 { 386 XPutPixel (core->msk_image, x, y, 0); 387 XPutPixel (core->src_image, x, y, 0); 388 } 389 } 390 core->on_color.red = 0; 391 core->on_color.green = 0; 392 core->on_color.blue = 0; 393 core->off_color.red = 0xffff; 394 core->off_color.green = 0xffff; 395 core->off_color.blue = 0xffff; 396 return True; 397} 398 399static Bool 400_XcursorFloydSteinberg (const XcursorImage *image, XcursorCoreCursor *core) 401{ 402 int *aPicture, *iPicture, *aP, *iP; 403 XcursorPixel *pixel, p; 404 int aR, iR, aA, iA; 405 unsigned int npixels = image->width * image->height; 406 int n; 407 int right = 1; 408 int belowLeft = (int) (image->width - 1); 409 int below = (int) image->width; 410 int belowRight = (int) (image->width + 1); 411 int iError, aError; 412 int iErrorRight, aErrorRight; 413 int iErrorBelowLeft, aErrorBelowLeft; 414 int iErrorBelow, aErrorBelow; 415 int iErrorBelowRight, aErrorBelowRight; 416 int x, y; 417 int max_inten, min_inten, mean_inten; 418 419 iPicture = malloc (npixels * sizeof (int) * 2); 420 if (!iPicture) 421 return False; 422 aPicture = iPicture + npixels; 423 424 /* 425 * Compute raw gray and alpha arrays 426 */ 427 pixel = image->pixels; 428 iP = iPicture; 429 aP = aPicture; 430 n = (int) npixels; 431 max_inten = 0; 432 min_inten = 0xff; 433 while (n-- > 0) 434 { 435 p = *pixel++; 436 *aP++ = (int) (p >> 24); 437 iR = (int) _XcursorPixelBrightness (p); 438 if (iR > max_inten) max_inten = iR; 439 if (iR < min_inten) min_inten = iR; 440 *iP++ = iR; 441 } 442 /* 443 * Draw the image while diffusing the error 444 */ 445 iP = iPicture; 446 aP = aPicture; 447 mean_inten = (max_inten + min_inten + 1) >> 1; 448 for (y = 0; (unsigned) y < image->height; y++) 449 for (x = 0; (unsigned) x < image->width; x++) 450 { 451 aR = *aP; 452 iR = *iP; 453 if (aR >= 0x80) 454 { 455 XPutPixel (core->msk_image, x, y, 1); 456 aA = 0xff; 457 } 458 else 459 { 460 XPutPixel (core->msk_image, x, y, 0); 461 aA = 0x00; 462 } 463 if (iR >= mean_inten) 464 { 465 XPutPixel (core->src_image, x, y, 0); 466 iA = max_inten; 467 } 468 else 469 { 470 XPutPixel (core->src_image, x, y, 1); 471 iA = min_inten; 472 } 473 iError = iR - iA; 474 aError = aR - aA; 475 iErrorRight = (iError * 7) >> 4; 476 iErrorBelowLeft = (iError * 3) >> 4; 477 iErrorBelow = (iError * 5) >> 4; 478 iErrorBelowRight = (iError - iErrorRight - 479 iErrorBelowLeft - iErrorBelow); 480 aErrorRight = (aError * 7) >> 4; 481 aErrorBelowLeft = (aError * 3) >> 4; 482 aErrorBelow = (aError * 5) >> 4; 483 aErrorBelowRight = (aError - aErrorRight - 484 aErrorBelowLeft - aErrorBelow); 485 if (x < ((int)image->width - 1)) 486 { 487 iP[right] += iErrorRight; 488 aP[right] += aErrorRight; 489 } 490 if (y < ((int)image->height - 1)) 491 { 492 if (x) 493 { 494 iP[belowLeft] += iErrorBelowLeft; 495 aP[belowLeft] += aErrorBelowLeft; 496 } 497 iP[below] += iErrorBelow; 498 aP[below] += aErrorBelow; 499 if (x < ((int)image->width - 1)) 500 { 501 iP[belowRight] += iErrorBelowRight; 502 aP[belowRight] += aErrorBelowRight; 503 } 504 } 505 aP++; 506 iP++; 507 } 508 free (iPicture); 509 core->on_color.red = 510 core->on_color.green = 511 core->on_color.blue = (unsigned short) (min_inten | min_inten << 8); 512 core->off_color.red = 513 core->off_color.green = 514 core->off_color.blue = (unsigned short) (max_inten | max_inten << 8); 515 return True; 516} 517 518static Bool 519_XcursorThreshold (const XcursorImage *image, XcursorCoreCursor *core) 520{ 521 XcursorPixel *pixel, p; 522 int x, y; 523 524 /* 525 * Draw the image, picking black for dark pixels and white for light 526 */ 527 pixel = image->pixels; 528 for (y = 0; (unsigned) y < image->height; y++) 529 for (x = 0; (unsigned) x < image->width; x++) 530 { 531 p = *pixel++; 532 if ((p >> 24) >= 0x80) 533 { 534 XPutPixel (core->msk_image, x, y, 1); 535 if (_XcursorPixelBrightness (p) > 0x80) 536 XPutPixel (core->src_image, x, y, 0); 537 else 538 XPutPixel (core->src_image, x, y, 1); 539 } 540 else 541 { 542 XPutPixel (core->msk_image, x, y, 0); 543 XPutPixel (core->src_image, x, y, 0); 544 } 545 } 546 core->on_color.red = 547 core->on_color.green = 548 core->on_color.blue = 0; 549 core->off_color.red = 550 core->off_color.green = 551 core->off_color.blue = 0xffff; 552 return True; 553} 554 555Cursor 556XcursorImageLoadCursor (Display *dpy, const XcursorImage *image) 557{ 558 Cursor cursor; 559 560#if RENDER_MAJOR > 0 || RENDER_MINOR >= 5 561 if (XcursorSupportsARGB (dpy)) 562 { 563 XImage ximage; 564 int screen = DefaultScreen (dpy); 565 Pixmap pixmap; 566 Picture picture; 567 GC gc; 568 XRenderPictFormat *format; 569 570 ximage.width = (int) image->width; 571 ximage.height = (int) image->height; 572 ximage.xoffset = 0; 573 ximage.format = ZPixmap; 574 ximage.data = (char *) image->pixels; 575 ximage.byte_order = nativeByteOrder (); 576 ximage.bitmap_unit = 32; 577 ximage.bitmap_bit_order = ximage.byte_order; 578 ximage.bitmap_pad = 32; 579 ximage.depth = 32; 580 ximage.bits_per_pixel = 32; 581 ximage.bytes_per_line = (int) (image->width * 4); 582 ximage.red_mask = 0xff0000; 583 ximage.green_mask = 0x00ff00; 584 ximage.blue_mask = 0x0000ff; 585 ximage.obdata = NULL; 586 if (!XInitImage (&ximage)) 587 return None; 588 pixmap = XCreatePixmap (dpy, RootWindow (dpy, screen), 589 image->width, image->height, 32); 590 gc = XCreateGC (dpy, pixmap, 0, NULL); 591 XPutImage (dpy, pixmap, gc, &ximage, 592 0, 0, 0, 0, image->width, image->height); 593 XFreeGC (dpy, gc); 594 format = XRenderFindStandardFormat (dpy, PictStandardARGB32); 595 picture = XRenderCreatePicture (dpy, pixmap, format, 0, NULL); 596 XFreePixmap (dpy, pixmap); 597 cursor = XRenderCreateCursor (dpy, picture, 598 image->xhot, image->yhot); 599 XRenderFreePicture (dpy, picture); 600 } 601 else 602#endif 603 { 604 XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); 605 int screen = DefaultScreen (dpy); 606 XcursorCoreCursor core; 607 Pixmap src_pixmap, msk_pixmap; 608 GC gc; 609 XGCValues gcv; 610 611 if (!info) 612 return 0; 613 614 core.src_image = XCreateImage (dpy, NULL, 1, ZPixmap, 615 0, NULL, image->width, image->height, 616 32, 0); 617 core.src_image->data = Xmalloc (image->height * 618 (unsigned) core.src_image->bytes_per_line); 619 core.msk_image = XCreateImage (dpy, NULL, 1, ZPixmap, 620 0, NULL, image->width, image->height, 621 32, 0); 622 core.msk_image->data = Xmalloc (image->height * 623 (unsigned) core.msk_image->bytes_per_line); 624 625 switch (info->dither) { 626 case XcursorDitherThreshold: 627 if (!_XcursorThreshold (image, &core)) 628 return 0; 629 break; 630 case XcursorDitherMedian: 631 if (!_XcursorHeckbertMedianCut (image, &core)) 632 return 0; 633 break; 634 case XcursorDitherOrdered: 635 if (!_XcursorBayerOrderedDither (image, &core)) 636 return 0; 637 break; 638 case XcursorDitherDiffuse: 639 if (!_XcursorFloydSteinberg (image, &core)) 640 return 0; 641 break; 642 default: 643 return 0; 644 } 645 646 /* 647 * Create the cursor 648 */ 649 src_pixmap = XCreatePixmap (dpy, RootWindow (dpy, screen), 650 image->width, image->height, 1); 651 msk_pixmap = XCreatePixmap (dpy, RootWindow (dpy, screen), 652 image->width, image->height, 1); 653 gcv.foreground = 1; 654 gcv.background = 0; 655 gc = XCreateGC (dpy, src_pixmap, 656 GCForeground|GCBackground, 657 &gcv); 658 XPutImage (dpy, src_pixmap, gc, core.src_image, 659 0, 0, 0, 0, image->width, image->height); 660 661 XPutImage (dpy, msk_pixmap, gc, core.msk_image, 662 0, 0, 0, 0, image->width, image->height); 663 XFreeGC (dpy, gc); 664 665#ifdef DEBUG_IMAGE 666 _XcursorDumpColor (&core.on_color, "on_color"); 667 _XcursorDumpColor (&core.off_color, "off_color"); 668 _XcursorDumpImage (core.src_image); 669 _XcursorDumpImage (core.msk_image); 670#endif 671 XDestroyImage (core.src_image); 672 XDestroyImage (core.msk_image); 673 674 cursor = XCreatePixmapCursor (dpy, src_pixmap, msk_pixmap, 675 &core.on_color, &core.off_color, 676 image->xhot, image->yhot); 677 XFreePixmap (dpy, src_pixmap); 678 XFreePixmap (dpy, msk_pixmap); 679 } 680 return cursor; 681} 682 683XcursorCursors * 684XcursorImagesLoadCursors (Display *dpy, const XcursorImages *images) 685{ 686 XcursorCursors *cursors = XcursorCursorsCreate (dpy, images->nimage); 687 int n; 688 689 if (!cursors) 690 return NULL; 691 for (n = 0; n < images->nimage; n++) 692 { 693 cursors->cursors[n] = XcursorImageLoadCursor (dpy, images->images[n]); 694 if (!cursors->cursors[n]) 695 { 696 XcursorCursorsDestroy (cursors); 697 return NULL; 698 } 699 cursors->ncursor++; 700 } 701 return cursors; 702} 703 704Cursor 705XcursorImagesLoadCursor (Display *dpy, const XcursorImages *images) 706{ 707 Cursor cursor; 708 if (images->nimage == 1 || !XcursorSupportsAnim (dpy)) 709 cursor = XcursorImageLoadCursor (dpy, images->images[0]); 710 else 711 { 712 XcursorCursors *cursors = XcursorImagesLoadCursors (dpy, images); 713 XAnimCursor *anim; 714 int n; 715 716 if (!cursors) 717 return 0; 718 anim = malloc ((size_t) cursors->ncursor * sizeof (XAnimCursor)); 719 if (!anim) 720 { 721 XcursorCursorsDestroy (cursors); 722 return 0; 723 } 724 for (n = 0; n < cursors->ncursor; n++) 725 { 726 anim[n].cursor = cursors->cursors[n]; 727 anim[n].delay = images->images[n]->delay; 728 } 729 cursor = XRenderCreateAnimCursor (dpy, cursors->ncursor, anim); 730 XcursorCursorsDestroy(cursors); 731 free (anim); 732 } 733#if defined HAVE_XFIXES && XFIXES_MAJOR >= 2 734 if (images->name) 735 XFixesSetCursorName (dpy, cursor, images->name); 736#endif 737 return cursor; 738} 739 740 741Cursor 742XcursorFilenameLoadCursor (Display *dpy, const char *file) 743{ 744 int size = XcursorGetDefaultSize (dpy); 745 XcursorImages *images = XcursorFilenameLoadImages (file, size); 746 Cursor cursor; 747 748 if (!images) 749 return None; 750 cursor = XcursorImagesLoadCursor (dpy, images); 751 XcursorImagesDestroy (images); 752 return cursor; 753} 754 755XcursorCursors * 756XcursorFilenameLoadCursors (Display *dpy, const char *file) 757{ 758 int size = XcursorGetDefaultSize (dpy); 759 XcursorImages *images = XcursorFilenameLoadImages (file, size); 760 XcursorCursors *cursors; 761 762 if (!images) 763 return NULL; 764 cursors = XcursorImagesLoadCursors (dpy, images); 765 XcursorImagesDestroy (images); 766 return cursors; 767} 768 769/* 770 * Stolen from XCreateGlyphCursor (which we cruelly override) 771 */ 772 773Cursor 774_XcursorCreateGlyphCursor(Display *dpy, 775 Font source_font, 776 Font mask_font, 777 unsigned int source_char, 778 unsigned int mask_char, 779 XColor _Xconst *foreground, 780 XColor _Xconst *background) 781{ 782 Cursor cid; 783 register xCreateGlyphCursorReq *req; 784 785 LockDisplay(dpy); 786 GetReq(CreateGlyphCursor, req); 787 cid = req->cid = (CARD32) XAllocID(dpy); 788 req->source = (CARD32) source_font; 789 req->mask = (CARD32) mask_font; 790 req->sourceChar = (CARD16) source_char; 791 req->maskChar = (CARD16) mask_char; 792 req->foreRed = foreground->red; 793 req->foreGreen = foreground->green; 794 req->foreBlue = foreground->blue; 795 req->backRed = background->red; 796 req->backGreen = background->green; 797 req->backBlue = background->blue; 798 UnlockDisplay(dpy); 799 SyncHandle(); 800 return (cid); 801} 802 803/* 804 * Stolen from XCreateFontCursor (which we cruelly override) 805 */ 806 807Cursor 808_XcursorCreateFontCursor (Display *dpy, unsigned int shape) 809{ 810#define DATA(c) { 0UL, c, c, c, 0, 0 } 811 static XColor _Xconst foreground = DATA(0); /* black */ 812 static XColor _Xconst background = DATA(65535); /* white */ 813#undef DATA 814 815 /* 816 * the cursor font contains the shape glyph followed by the mask 817 * glyph; so character position 0 contains a shape, 1 the mask for 0, 818 * 2 a shape, etc. <X11/cursorfont.h> contains hash define names 819 * for all of these. 820 */ 821 822 if (dpy->cursor_font == None) 823 { 824 dpy->cursor_font = XLoadFont (dpy, CURSORFONT); 825 if (dpy->cursor_font == None) 826 return None; 827 } 828 829 return _XcursorCreateGlyphCursor (dpy, dpy->cursor_font, dpy->cursor_font, 830 shape, shape + 1, &foreground, &background); 831} 832 833