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