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