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