Restructure how we look for Read files slightly.
[fvwm.git] / libs / PictureImageLoader.c
blobbf05b2245ba7ea6ac1aa39a3e2c1539cf1eea3e9
1 /* -*-c-*- */
2 /* Copyright (C) 1993, Robert Nation
3 * Copyright (C) 1999 Carsten Haitzler and various contributors (imlib2)
4 * Copyright (C) 2002 Olivier Chapuis */
5 /* This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * The png loader and PImageRGBtoPixel are from imlib2. The code is from raster
23 * (Carsten Haitzler) <raster@rasterman.com> <raster@valinux.com>
27 /* ---------------------------- included header files ---------------------- */
29 #include "config.h"
31 #include <stdio.h>
32 #include <signal.h>
33 #include <ctype.h>
35 #include <X11/Xlib.h>
36 #include <X11/Xmd.h>
38 #include <fvwmlib.h>
39 #include "System.h"
40 #include "Strings.h"
41 #include "Picture.h"
42 #include "PictureUtils.h"
43 #include "Graphics.h"
44 #include "ColorUtils.h"
45 #include "Fxpm.h"
46 #include "Fpng.h"
47 #include "Fsvg.h"
48 #include "FRenderInit.h"
49 #include "Fcursor.h"
50 #include "FImage.h"
52 /* ---------------------------- local definitions -------------------------- */
53 #define FIMAGE_CMD_ARGS \
54 Display *dpy, char *path, CARD32 **argb_data, int *width, int *height
56 #define FIMAGE_PASS_ARGS \
57 dpy, path, argb_data, width, height
59 typedef struct PImageLoader
61 char *extension;
62 #ifdef __STDC__
63 int (*func)(FIMAGE_CMD_ARGS);
64 #else
65 int (*func)();
66 #endif
67 } PImageLoader;
69 /* ---------------------------- local macros ------------------------------- */
71 /* ---------------------------- imports ------------------------------------ */
73 /* ---------------------------- included code files ------------------------ */
75 /* ---------------------------- local types -------------------------------- */
77 /* ---------------------------- forward declarations ----------------------- */
79 static Bool PImageLoadSvg(FIMAGE_CMD_ARGS);
80 static Bool PImageLoadPng(FIMAGE_CMD_ARGS);
81 static Bool PImageLoadXpm(FIMAGE_CMD_ARGS);
83 /* ---------------------------- local variables ---------------------------- */
85 PImageLoader Loaders[] =
87 { "xpm", PImageLoadXpm },
88 { "svg", PImageLoadSvg },
89 { "png", PImageLoadPng },
90 {NULL,0}
93 /* ---------------------------- exported variables (globals) --------------- */
95 /* ---------------------------- local functions ---------------------------- */
97 static
98 Bool PImageLoadArgbDataFromFile(FIMAGE_CMD_ARGS)
100 int done = 0, i = 0, tried = -1;
101 char *ext = NULL;
103 if (path == NULL)
104 return False;
106 if (strlen(path) > 3)
108 ext = path + strlen(path) - 3;
110 /* first try to load by extension */
111 while (!done && ext != NULL && Loaders[i].extension != NULL)
113 if (StrEquals(Loaders[i].extension, ext))
115 if (Loaders[i].func(FIMAGE_PASS_ARGS))
117 return True;
119 tried = i;
120 done = 1;
122 i++;
125 i = 0;
126 while (Loaders[i].extension != NULL)
128 if (i != tried && Loaders[i].func(FIMAGE_PASS_ARGS))
130 return True;
132 i++;
135 return False;
140 * svg loader
143 static
144 Bool PImageLoadSvg(FIMAGE_CMD_ARGS)
146 char *allocated_path;
147 char *render_opts;
148 FRsvgHandle *rsvg;
149 FRsvgDimensionData dim;
150 CARD32 *data;
151 Fcairo_surface_t *surface;
152 Fcairo_t *cr;
153 int i;
154 int j;
155 int b1;
156 int b2;
157 int w = 0;
158 int h = 0;
159 int dw = 0;
160 int dh = 0;
161 int w_sgn = 1;
162 int h_sgn = 1;
163 double angle = 0;
164 double w_scale = 1;
165 double h_scale = 1;
166 double buf;
167 Bool transpose = False;
168 unsigned char a_value;
169 unsigned char r_value;
170 unsigned char g_value;
171 unsigned char b_value;
173 if (!USE_SVG)
175 return False;
178 /* Separate rendering options from path */
179 render_opts = path = allocated_path = safestrdup(path);
180 if (*path == ':' && (path = strchr(path + 1, ':')))
182 *path = 0;
183 path ++;
184 render_opts ++;
186 else
188 render_opts = "";
191 if (!(rsvg = Frsvg_handle_new_from_file(path, NULL)))
193 free(allocated_path);
195 return False;
198 /* Parsing of rendering options */
199 while (*render_opts)
201 i = 0;
202 switch (*render_opts)
204 case '!':
205 transpose = !transpose;
206 break;
207 case '*':
208 if (sscanf(render_opts, "*%lf%n", &buf, &i) >= 1)
210 switch (render_opts[i])
212 case 'x':
213 w_scale *= buf;
214 i ++;
215 break;
216 case 'y':
217 h_scale *= buf;
218 i ++;
219 break;
220 default:
221 w_scale *= buf;
222 h_scale *= buf;
225 break;
226 case '/':
227 if (sscanf(render_opts, "/%lf%n", &buf, &i) >= 1 &&
228 buf)
230 switch (render_opts[i])
232 case 'x':
233 w_scale /= buf;
234 i ++;
235 break;
236 case 'y':
237 h_scale /= buf;
238 i ++;
239 break;
240 default:
241 w_scale /= buf;
242 h_scale /= buf;
245 break;
246 case '@':
247 if (sscanf(render_opts, "@%lf%n", &buf, &i) >= 1)
249 angle += buf;
251 break;
252 default:
253 j = 0;
254 if (
255 sscanf(
256 render_opts, "%dx%n%d%n", &b1, &j, &b2,
257 &i) >= 2 &&
258 i > j)
260 w = b1;
261 h = b2;
263 if (w < 0 || (!w && render_opts[0] == '-'))
265 w *= (w_sgn = -1);
267 if (h < 0 || (!h && render_opts[j] == '-'))
269 h *= (h_sgn = -1);
272 else if (
273 sscanf(render_opts, "%d%d%n", &b1, &b2, &i) >=
276 dw += b1;
277 dh += b2;
280 render_opts += i ? i : 1;
282 free(allocated_path);
284 /* Keep the original aspect ratio when either w or h is 0 */
285 Frsvg_handle_get_dimensions(rsvg, &dim);
286 if (!w && !h)
288 w = dim.width;
289 h = dim.height;
291 else if (!w)
293 w = h * dim.em / dim.ex;
295 else if (!h)
297 h = w * dim.ex / dim.em;
300 w_scale *= w;
301 h_scale *= h;
303 if (transpose)
305 b1 = w;
306 w = h;
307 h = b1;
309 b1 = w_sgn;
310 w_sgn = - h_sgn;
311 h_sgn = b1;
313 b1 = dw;
314 dw = - dh;
315 dh = b1;
317 angle += 90;
320 data = (CARD32 *)safemalloc(w * h * sizeof(CARD32));
321 memset(data, 0, w * h * sizeof(CARD32));
322 surface = Fcairo_image_surface_create_for_data((unsigned char *)data,
323 FCAIRO_FORMAT_ARGB32, w, h, w * sizeof(CARD32));
324 if (Fcairo_surface_status(surface) != FCAIRO_STATUS_SUCCESS)
326 Fg_object_unref(FG_OBJECT(rsvg));
327 free(data);
328 if (surface)
330 Fcairo_surface_destroy(surface);
333 return False;
335 cr = Fcairo_create(surface);
336 Fcairo_surface_destroy(surface);
337 if (Fcairo_status(cr) != FCAIRO_STATUS_SUCCESS)
339 Fg_object_unref(FG_OBJECT(rsvg));
340 free(data);
341 if (cr)
343 Fcairo_destroy(cr);
346 return False;
349 /* Affine transformations ...
350 * mirroring, rotation, scaling and translation */
351 Fcairo_translate(cr, .5 * w, .5 * h);
352 Fcairo_scale(cr, w_sgn, h_sgn);
353 Fcairo_translate(cr, dw, dh);
354 Fcairo_rotate(cr, angle * M_PI / 180);
355 Fcairo_scale(cr, w_scale, h_scale);
356 Fcairo_translate(cr, -.5, -.5);
357 Fcairo_scale(cr, 1 / dim.em, 1 / dim.ex);
359 Frsvg_handle_render_cairo(rsvg, cr);
360 Fg_object_unref(FG_OBJECT(rsvg));
361 Fcairo_destroy(cr);
363 /* Cairo gave us alpha prescaled RGB values, hence we need
364 * to rescale them for PImageCreatePixmapFromArgbData() */
365 for (i = 0; i < w * h; i++)
367 if ((a_value = (data[i] >> 030) & 0xff))
369 r_value = ((data[i] >> 020) & 0xff) * 0xff / a_value;
370 g_value = ((data[i] >> 010) & 0xff) * 0xff / a_value;
371 b_value = (data[i] & 0xff) * 0xff / a_value;
373 data[i] =
374 (a_value << 030) | (r_value << 020) |
375 (g_value << 010) | b_value;
379 *width = w;
380 *height = h;
381 *argb_data = data;
383 return True;
388 * png loader
391 static
392 Bool PImageLoadPng(FIMAGE_CMD_ARGS)
394 Fpng_uint_32 w32, h32;
395 Fpng_structp Fpng_ptr = NULL;
396 Fpng_infop Finfo_ptr = NULL;
397 CARD32 *data;
398 int w, h;
399 char hasa = 0, hasg = 0;
400 FILE *f;
401 int bit_depth;
402 int color_type;
403 int interlace_type;
404 unsigned char buf[FPNG_BYTES_TO_CHECK];
405 unsigned char **lines;
406 int i;
408 if (!PngSupport)
410 /* suppress compiler warning */
411 bit_depth = 0;
413 return False;
415 if (!(f = fopen(path, "rb")))
417 return False;
419 fread(buf, 1, FPNG_BYTES_TO_CHECK, f);
420 if (!Fpng_check_sig(buf, FPNG_BYTES_TO_CHECK))
422 fclose(f);
423 return False;
425 rewind(f);
426 Fpng_ptr = Fpng_create_read_struct(FPNG_LIBPNG_VER_STRING,
427 NULL, NULL, NULL);
428 if (!Fpng_ptr)
430 fclose(f);
431 return False;
433 Finfo_ptr = Fpng_create_info_struct(Fpng_ptr);
434 if (!Finfo_ptr)
436 Fpng_destroy_read_struct(&Fpng_ptr, NULL, NULL);
437 fclose(f);
438 return False;
440 #if 0
441 if (setjmp(Fpng_ptr->jmpbuf))
443 Fpng_destroy_read_struct(&Fpng_ptr, &Finfo_ptr, NULL);
444 fclose(f);
445 return False;
447 #endif
448 Fpng_init_io(Fpng_ptr, f);
449 Fpng_read_info(Fpng_ptr, Finfo_ptr);
450 Fpng_get_IHDR(
451 Fpng_ptr, Finfo_ptr, (Fpng_uint_32 *) (&w32),
452 (Fpng_uint_32 *) (&h32), &bit_depth, &color_type,
453 &interlace_type, NULL, NULL);
454 interlace_type = 0; /* not used */
455 *width = w = (int) w32;
456 *height = h = (int) h32;
457 if (color_type == FPNG_COLOR_TYPE_PALETTE)
459 Fpng_set_expand(Fpng_ptr);
461 if (Finfo_ptr->color_type == FPNG_COLOR_TYPE_RGB_ALPHA)
463 hasa = 1;
465 if (Finfo_ptr->color_type == FPNG_COLOR_TYPE_GRAY_ALPHA)
467 hasa = 1;
468 hasg = 1;
470 if (Finfo_ptr->color_type == FPNG_COLOR_TYPE_GRAY)
472 hasg = 1;
474 if (hasa)
475 Fpng_set_expand(Fpng_ptr);
476 /* we want ARGB */
477 /* note form raster:
478 * thanks to mustapha for helping debug this on PPC Linux remotely by
479 * sending across screenshots all the time and me figuring out form them
480 * what the hell was up with the colors
481 * now png loading should work on big endian machines nicely */
482 #ifdef WORDS_BIGENDIAN
483 Fpng_set_swap_alpha(Fpng_ptr);
484 Fpng_set_filler(Fpng_ptr, 0xff, FPNG_FILLER_BEFORE);
485 #else
486 Fpng_set_bgr(Fpng_ptr);
487 Fpng_set_filler(Fpng_ptr, 0xff, FPNG_FILLER_AFTER);
488 #endif
489 /* 16bit color -> 8bit color */
490 Fpng_set_strip_16(Fpng_ptr);
491 /* pack all pixels to byte boundaires */
492 Fpng_set_packing(Fpng_ptr);
493 if (Fpng_get_valid(Fpng_ptr, Finfo_ptr, FPNG_INFO_tRNS))
495 Fpng_set_expand(Fpng_ptr);
498 data = (CARD32 *)safemalloc(w * h * sizeof(CARD32));
499 lines = (unsigned char **) safemalloc(h * sizeof(unsigned char *));
501 if (hasg)
503 Fpng_set_gray_to_rgb(Fpng_ptr);
504 if (Fpng_get_bit_depth(Fpng_ptr, Finfo_ptr) < 8)
506 Fpng_set_gray_1_2_4_to_8(Fpng_ptr);
509 for (i = 0; i < h; i++)
511 lines[i] = (unsigned char *)data + (i * w * sizeof(CARD32));
513 Fpng_read_image(Fpng_ptr, lines);
514 Fpng_read_end(Fpng_ptr, Finfo_ptr);
515 Fpng_destroy_read_struct(&Fpng_ptr, &Finfo_ptr, (png_infopp) NULL);
516 fclose(f);
517 free(lines);
518 *argb_data = data;
520 return True;
525 * xpm loader
528 static
529 Bool PImageLoadXpm(FIMAGE_CMD_ARGS)
531 FxpmImage xpm_im;
532 FxpmColor *xpm_color;
533 XColor color;
534 CARD32 *colors;
535 CARD32 *data;
536 char *visual_color;
537 int i;
538 int w;
539 int h;
540 int rc;
541 #ifdef HAVE_SIGACTION
542 struct sigaction defaultHandler;
543 struct sigaction originalHandler;
544 #else
545 RETSIGTYPE (*originalHandler)(int);
546 #endif
548 if (!XpmSupport)
550 return False;
552 memset(&xpm_im, 0, sizeof(FxpmImage));
554 #ifdef HAVE_SIGACTION
555 sigemptyset(&defaultHandler.sa_mask);
556 defaultHandler.sa_flags = 0;
557 defaultHandler.sa_handler = SIG_DFL;
558 sigaction(SIGCHLD, &defaultHandler, &originalHandler);
559 #else
560 originalHandler = signal(SIGCHLD, SIG_DFL);
561 #endif
564 rc = FxpmReadFileToXpmImage(path, &xpm_im, NULL);
566 #ifdef HAVE_SIGACTION
567 sigaction(SIGCHLD, &originalHandler, NULL);
568 #else
569 signal(SIGCHLD, originalHandler);
570 #endif
572 if (rc != FxpmSuccess)
574 return False;
577 if (xpm_im.ncolors <= 0)
579 FxpmFreeXpmImage(&xpm_im);
580 return False;
582 colors = (CARD32 *)safemalloc(xpm_im.ncolors * sizeof(CARD32));
583 for (i=0; i < xpm_im.ncolors; i++)
585 xpm_color = &xpm_im.colorTable[i];
586 if (xpm_color->c_color)
588 visual_color = xpm_color->c_color;
590 else if (xpm_color->g_color)
592 visual_color = xpm_color->g_color;
594 else if (xpm_color->g4_color)
596 visual_color = xpm_color->g4_color;
598 else
600 visual_color = xpm_color->m_color;
602 if (XParseColor(dpy, Pcmap, visual_color, &color))
604 colors[i] = 0xff000000 |
605 ((color.red << 8) & 0xff0000) |
606 ((color.green ) & 0xff00) |
607 ((color.blue >> 8) & 0xff);
609 else
611 colors[i] = 0;
614 *width = w = xpm_im.width;
615 *height = h = xpm_im.height;
616 data = (CARD32 *)safemalloc(w * h * sizeof(CARD32));
617 for (i=0; i < w * h; i++)
619 data[i] = colors[xpm_im.data[i]];
621 free(colors);
622 *argb_data = data;
624 return True;
629 * copy image to server
632 static
633 Pixmap PImageCreatePixmapFromFImage(Display *dpy, Window win, FImage *fimage)
635 GC gc;
636 Pixmap pixmap;
637 int w;
638 int h;
639 int depth;
640 int must_free_gc;
642 w = fimage->im->width;
643 h = fimage->im->height;
644 depth = fimage->im->depth;
645 pixmap = XCreatePixmap(dpy, win, w, h, depth);
646 if (depth == Pdepth)
648 gc = PictureDefaultGC(dpy, win);
649 must_free_gc = 0;
651 else
653 gc = fvwmlib_XCreateGC(dpy, pixmap, 0, NULL);
654 must_free_gc = 1;
656 FPutFImage(dpy, pixmap, gc, fimage, 0, 0, 0, 0, w, h);
657 if (depth != Pdepth)
659 XFreeGC(dpy, gc);
662 return pixmap;
665 /* ---------------------------- interface functions ------------------------ */
669 * argb data to pixmaps
672 Bool PImageCreatePixmapFromArgbData(
673 Display *dpy, Window win, CARD32 *data, int start, int width,
674 int height, Pixmap *pixmap, Pixmap *mask, Pixmap *alpha,
675 int *nalloc_pixels, Pixel **alloc_pixels, int *no_limit,
676 FvwmPictureAttributes fpa)
678 FImage *fim;
679 FImage *m_fim = NULL;
680 FImage *a_fim = NULL;
681 XColor c;
682 int i;
683 int j;
684 int a;
685 PictureImageColorAllocator *pica = NULL;
686 int alpha_limit = PICTURE_ALPHA_LIMIT;
687 int alpha_depth = FRenderGetAlphaDepth();
688 Bool have_mask = False;
689 Bool have_alpha = False;
691 fim = FCreateFImage(
692 dpy, Pvisual, (fpa.mask & FPAM_MONOCHROME) ? 1 : Pdepth,
693 ZPixmap, width, height);
694 if (!fim)
696 return False;
698 if (mask)
700 m_fim = FCreateFImage(
701 dpy, Pvisual, 1, ZPixmap, width, height);
703 if (alpha && !(fpa.mask & FPAM_NO_ALPHA) && alpha_depth)
705 alpha_limit = 0;
706 a_fim = FCreateFImage(
707 dpy, Pvisual, alpha_depth, ZPixmap, width, height);
709 if (!(fpa.mask & FPAM_MONOCHROME))
711 c.flags = DoRed | DoGreen | DoBlue;
712 pica = PictureOpenImageColorAllocator(
713 dpy, Pcmap, width, height,
714 !!(fpa.mask & FPAM_NO_COLOR_LIMIT),
715 !!(fpa.mask & FPAM_NO_ALLOC_PIXELS),
716 !!(fpa.mask & FPAM_DITHER),
717 True);
719 data += start;
720 for (j = 0; j < height; j++)
722 for (i = 0; i < width; i++, data++)
724 a = (*data >> 030) & 0xff;
725 if (a > alpha_limit)
727 c.red = (*data >> 16) & 0xff;
728 c.green = (*data >> 8) & 0xff;
729 c.blue = (*data ) & 0xff;
730 if (pica)
732 PictureAllocColorImage(
733 dpy, pica, &c, i, j);
734 XPutPixel(fim->im, i, j, c.pixel);
736 /* Brightness threshold */
737 else if ((0x99 * c.red +
738 0x12D * c.green +
739 0x3A * c.blue) >> 16)
741 XPutPixel(fim->im, i, j, 1);
743 else
745 XPutPixel(fim->im, i, j, 0);
747 if (m_fim)
749 XPutPixel(m_fim->im, i, j, 1);
752 else if (m_fim != NULL)
754 XPutPixel(m_fim->im, i, j, 0);
755 have_mask = True;
757 if (a_fim != NULL)
759 XPutPixel(a_fim->im, i, j, a);
760 if (a > 0 && a < 0xff)
762 have_alpha = True;
767 if (pica)
769 PictureCloseImageColorAllocator(
770 dpy, pica, nalloc_pixels, alloc_pixels, no_limit);
772 *pixmap = PImageCreatePixmapFromFImage(dpy, win, fim);
773 if (have_alpha)
775 *alpha = PImageCreatePixmapFromFImage(dpy, win, a_fim);
777 else if (have_mask)
779 *mask = PImageCreatePixmapFromFImage(dpy, win, m_fim);
781 FDestroyFImage(dpy, fim);
782 if (m_fim)
784 FDestroyFImage(dpy, m_fim);
786 if (a_fim)
788 FDestroyFImage(dpy, a_fim);
791 return True;
797 * the images loaders
801 Bool PImageLoadPixmapFromFile(
802 Display *dpy, Window win, char *path, Pixmap *pixmap, Pixmap *mask,
803 Pixmap *alpha, int *width, int *height, int *depth,
804 int *nalloc_pixels, Pixel **alloc_pixels,
805 int *no_limit, FvwmPictureAttributes fpa)
807 CARD32 *data;
809 if (PImageLoadArgbDataFromFile(dpy, path, &data, width, height))
811 *depth = (fpa.mask & FPAM_MONOCHROME) ? 1 : Pdepth;
812 if (PImageCreatePixmapFromArgbData(
813 dpy, win, data, 0, *width, *height, pixmap, mask,
814 alpha, nalloc_pixels, alloc_pixels, no_limit, fpa))
816 free(data);
818 return True;
820 free(data);
822 /* Bitmap fallback */
823 else if (
824 XReadBitmapFile(
825 dpy, win, path, (unsigned int *)width,
826 (unsigned int *)height, pixmap, NULL, NULL) ==
827 BitmapSuccess)
829 *depth = 1;
830 *mask = None;
832 return True;
834 pixmap = None;
835 mask = None;
836 alpha = None;
837 *width = *height = *depth = 0;
838 if (nalloc_pixels != NULL)
840 *nalloc_pixels = 0;
842 if (alloc_pixels != NULL)
844 *alloc_pixels = NULL;
846 return False;
849 FvwmPicture *PImageLoadFvwmPictureFromFile(
850 Display *dpy, Window win, char *path, FvwmPictureAttributes fpa)
852 FvwmPicture *p;
853 Pixmap pixmap = None;
854 Pixmap mask = None;
855 Pixmap alpha = None;
856 int width = 0, height = 0;
857 int depth = 0, no_limit;
858 int nalloc_pixels = 0;
859 Pixel *alloc_pixels = NULL;
860 char *real_path;
862 /* Remove any svg rendering options from real_path */
863 if (USE_SVG && *path == ':' &&
864 (real_path = strchr(path + 1, ':')))
866 real_path ++;
868 else
870 real_path = path;
872 if (!PImageLoadPixmapFromFile(
873 dpy, win, path, &pixmap, &mask, &alpha, &width, &height,
874 &depth, &nalloc_pixels, &alloc_pixels, &no_limit, fpa))
876 return NULL;
879 p = (FvwmPicture*)safemalloc(sizeof(FvwmPicture));
880 memset(p, 0, sizeof(FvwmPicture));
881 p->count = 1;
882 p->name = path;
883 p->fpa_mask = fpa.mask;
884 p->next = NULL;
885 setFileStamp(&p->stamp, real_path);
886 p->picture = pixmap;
887 p->mask = mask;
888 p->alpha = alpha;
889 p->width = width;
890 p->height = height;
891 p->depth = depth;
892 p->nalloc_pixels = nalloc_pixels;
893 p->alloc_pixels = alloc_pixels;
894 p->no_limit = no_limit;
895 return p;
898 Cursor PImageLoadCursorFromFile(
899 Display *dpy, Window win, char *path, int x_hot, int y_hot)
901 Cursor cursor = 0;
902 CARD32 *data;
903 int width;
904 int height;
905 int i;
906 FcursorImages *fcis;
907 FcursorImage *fci;
909 /* First try the Xcursor loader (animated cursors) */
910 if ((fcis = FcursorFilenameLoadImages(
911 path, FcursorGetDefaultSize(dpy))))
913 for (i = 0; i < fcis->nimage; i++)
915 if (x_hot < fcis->images[i]->width && x_hot >= 0 &&
916 y_hot < fcis->images[i]->height && y_hot >= 0)
918 fcis->images[i]->xhot = x_hot;
919 fcis->images[i]->yhot = y_hot;
922 cursor = FcursorImagesLoadCursor(dpy, fcis);
923 FcursorImagesDestroy(fcis);
925 /* Get cursor data from the regular image loader */
926 else if (PImageLoadArgbDataFromFile(dpy, path, &data, &width, &height))
928 Pixmap src;
929 Pixmap msk = None;
930 FvwmPictureAttributes fpa;
932 fpa.mask = FPAM_NO_ALPHA | FPAM_MONOCHROME;
934 /* Adjust the hot-spot if necessary */
935 if (
936 x_hot < 0 || x_hot >= width ||
937 y_hot < 0 || y_hot >= height)
939 FxpmImage xpm_im;
940 FxpmInfo xpm_info;
942 memset(&xpm_im, 0, sizeof(FxpmImage));
943 memset(&xpm_info, 0, sizeof(FxpmInfo));
944 if (FxpmReadFileToXpmImage(path, &xpm_im, &xpm_info)
945 == FxpmSuccess)
947 if (xpm_info.valuemask & FxpmHotspot)
949 x_hot = xpm_info.x_hotspot;
950 y_hot = xpm_info.y_hotspot;
952 FxpmFreeXpmImage(&xpm_im);
953 FxpmFreeXpmInfo(&xpm_info);
955 if (x_hot < 0 || x_hot >= width)
957 x_hot = width / 2;
959 if (y_hot < 0 || y_hot >= height)
961 y_hot = height / 2;
964 /* Use the Xcursor library to create the argb cursor */
965 if ((fci = FcursorImageCreate(width, height)))
967 unsigned char alpha;
968 unsigned char red;
969 unsigned char green;
970 unsigned char blue;
972 /* Xcursor expects alpha prescaled RGB values */
973 for (i = 0; i < width * height; i++)
975 alpha = ((data[i] >> 24) & 0xff);
976 red = ((data[i] >> 16) & 0xff) * alpha/0xff;
977 green = ((data[i] >> 8) & 0xff) * alpha/0xff;
978 blue = ((data[i] ) & 0xff) * alpha/0xff;
980 data[i] =
981 (alpha << 24) | (red << 16) |
982 (green << 8) | blue;
985 fci->xhot = x_hot;
986 fci->yhot = y_hot;
987 fci->delay = 0;
988 fci->pixels = (FcursorPixel *)data;
989 cursor = FcursorImageLoadCursor(dpy, fci);
990 FcursorImageDestroy(fci);
992 /* Create monochrome cursor from argb data */
993 else if (PImageCreatePixmapFromArgbData(
994 dpy, win, data, 0, width, height,
995 &src, &msk, 0, 0, 0, 0, fpa))
997 XColor c[2];
999 c[0].pixel = GetColor(DEFAULT_CURSOR_FORE_COLOR);
1000 c[1].pixel = GetColor(DEFAULT_CURSOR_BACK_COLOR);
1001 XQueryColors(dpy, Pcmap, c, 2);
1002 cursor = XCreatePixmapCursor(
1003 dpy, src, msk, &(c[0]), &(c[1]), x_hot, y_hot);
1004 XFreePixmap(dpy, src);
1005 XFreePixmap(dpy, msk);
1007 free(data);
1010 return cursor;
1013 /* FIXME: Use color limit */
1014 Bool PImageLoadPixmapFromXpmData(
1015 Display *dpy, Window win, int color_limit,
1016 char **data,
1017 Pixmap *pixmap, Pixmap *mask,
1018 int *width, int *height, int *depth)
1020 FxpmAttributes xpm_attributes;
1022 if (!XpmSupport)
1024 return False;
1026 xpm_attributes.valuemask = FxpmCloseness |
1027 FxpmExtensions | FxpmVisual | FxpmColormap | FxpmDepth;
1028 xpm_attributes.closeness = 40000;
1029 xpm_attributes.visual = Pvisual;
1030 xpm_attributes.colormap = Pcmap;
1031 xpm_attributes.depth = Pdepth;
1032 /* suppress compiler warning if xpm library is not compiled in */
1033 xpm_attributes.width = 0;
1034 xpm_attributes.height = 0;
1035 if (
1036 FxpmCreatePixmapFromData(
1037 dpy, win, data, pixmap, mask, &xpm_attributes) !=
1038 FxpmSuccess)
1040 return False;
1042 *width = xpm_attributes.width;
1043 *height = xpm_attributes.height;
1044 *depth = Pdepth;
1046 return True;