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