CMD_EwwmhBaseStruts: Use EWMH_UpdateWorkArea() and not separate function calls
[fvwm.git] / libs / PictureImageLoader.c
blobcb7b8d26dde8cde37db7ce509ca03949d4eba82b
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);
462 /* TA: XXX: (2011-02-14) -- Happy Valentines Day.
464 * png_get_color_type() defined in libpng 1.5 now hides a data member
465 * to a struct:
467 * Finfo_ptr->color_type
469 * I'm not going to wrap this up in more #ifdef madness, but should
470 * this fail to build on much older libpng versions which we support
471 * (pre 1.3), then I might have to.
473 if (png_get_color_type(Fpng_ptr, Finfo_ptr) == FPNG_COLOR_TYPE_RGB_ALPHA)
475 hasa = 1;
477 if (png_get_color_type(Fpng_ptr, Finfo_ptr) == FPNG_COLOR_TYPE_GRAY_ALPHA)
479 hasa = 1;
480 hasg = 1;
482 if (png_get_color_type(Fpng_ptr, Finfo_ptr) == FPNG_COLOR_TYPE_GRAY)
484 hasg = 1;
487 if (hasa)
488 Fpng_set_expand(Fpng_ptr);
489 /* we want ARGB */
490 /* note form raster:
491 * thanks to mustapha for helping debug this on PPC Linux remotely by
492 * sending across screenshots all the time and me figuring out form them
493 * what the hell was up with the colors
494 * now png loading should work on big endian machines nicely */
495 #ifdef WORDS_BIGENDIAN
496 Fpng_set_swap_alpha(Fpng_ptr);
497 Fpng_set_filler(Fpng_ptr, 0xff, FPNG_FILLER_BEFORE);
498 #else
499 Fpng_set_bgr(Fpng_ptr);
500 Fpng_set_filler(Fpng_ptr, 0xff, FPNG_FILLER_AFTER);
501 #endif
502 /* 16bit color -> 8bit color */
503 Fpng_set_strip_16(Fpng_ptr);
504 /* pack all pixels to byte boundaires */
505 Fpng_set_packing(Fpng_ptr);
506 if (Fpng_get_valid(Fpng_ptr, Finfo_ptr, FPNG_INFO_tRNS))
508 Fpng_set_expand(Fpng_ptr);
511 data = (CARD32 *)safemalloc(w * h * sizeof(CARD32));
512 lines = (unsigned char **) safemalloc(h * sizeof(unsigned char *));
514 if (hasg)
516 Fpng_set_gray_to_rgb(Fpng_ptr);
517 if (Fpng_get_bit_depth(Fpng_ptr, Finfo_ptr) < 8)
519 Fpng_set_gray_1_2_4_to_8(Fpng_ptr);
522 for (i = 0; i < h; i++)
524 lines[i] = (unsigned char *)data + (i * w * sizeof(CARD32));
526 Fpng_read_image(Fpng_ptr, lines);
527 Fpng_read_end(Fpng_ptr, Finfo_ptr);
528 Fpng_destroy_read_struct(&Fpng_ptr, &Finfo_ptr, (png_infopp) NULL);
529 fclose(f);
530 free(lines);
531 *argb_data = data;
533 return True;
538 * xpm loader
541 static
542 Bool PImageLoadXpm(FIMAGE_CMD_ARGS)
544 FxpmImage xpm_im;
545 FxpmColor *xpm_color;
546 XColor color;
547 CARD32 *colors;
548 CARD32 *data;
549 char *visual_color;
550 int i;
551 int w;
552 int h;
553 int rc;
554 #ifdef HAVE_SIGACTION
555 struct sigaction defaultHandler;
556 struct sigaction originalHandler;
557 #else
558 RETSIGTYPE (*originalHandler)(int);
559 #endif
561 if (!XpmSupport)
563 return False;
565 memset(&xpm_im, 0, sizeof(FxpmImage));
567 #ifdef HAVE_SIGACTION
568 sigemptyset(&defaultHandler.sa_mask);
569 defaultHandler.sa_flags = 0;
570 defaultHandler.sa_handler = SIG_DFL;
571 sigaction(SIGCHLD, &defaultHandler, &originalHandler);
572 #else
573 originalHandler = signal(SIGCHLD, SIG_DFL);
574 #endif
577 rc = FxpmReadFileToXpmImage(path, &xpm_im, NULL);
579 #ifdef HAVE_SIGACTION
580 sigaction(SIGCHLD, &originalHandler, NULL);
581 #else
582 signal(SIGCHLD, originalHandler);
583 #endif
585 if (rc != FxpmSuccess)
587 return False;
590 if (xpm_im.ncolors <= 0)
592 FxpmFreeXpmImage(&xpm_im);
593 return False;
595 colors = (CARD32 *)safemalloc(xpm_im.ncolors * sizeof(CARD32));
596 for (i=0; i < xpm_im.ncolors; i++)
598 xpm_color = &xpm_im.colorTable[i];
599 if (xpm_color->c_color)
601 visual_color = xpm_color->c_color;
603 else if (xpm_color->g_color)
605 visual_color = xpm_color->g_color;
607 else if (xpm_color->g4_color)
609 visual_color = xpm_color->g4_color;
611 else
613 visual_color = xpm_color->m_color;
615 if (XParseColor(dpy, Pcmap, visual_color, &color))
617 colors[i] = 0xff000000 |
618 ((color.red << 8) & 0xff0000) |
619 ((color.green ) & 0xff00) |
620 ((color.blue >> 8) & 0xff);
622 else
624 colors[i] = 0;
627 *width = w = xpm_im.width;
628 *height = h = xpm_im.height;
629 data = (CARD32 *)safemalloc(w * h * sizeof(CARD32));
630 for (i=0; i < w * h; i++)
632 data[i] = colors[xpm_im.data[i]];
634 free(colors);
635 *argb_data = data;
637 return True;
642 * copy image to server
645 static
646 Pixmap PImageCreatePixmapFromFImage(Display *dpy, Window win, FImage *fimage)
648 GC gc;
649 Pixmap pixmap;
650 int w;
651 int h;
652 int depth;
653 int must_free_gc;
655 w = fimage->im->width;
656 h = fimage->im->height;
657 depth = fimage->im->depth;
658 pixmap = XCreatePixmap(dpy, win, w, h, depth);
659 if (depth == Pdepth)
661 gc = PictureDefaultGC(dpy, win);
662 must_free_gc = 0;
664 else
666 gc = fvwmlib_XCreateGC(dpy, pixmap, 0, NULL);
667 must_free_gc = 1;
669 FPutFImage(dpy, pixmap, gc, fimage, 0, 0, 0, 0, w, h);
670 if (depth != Pdepth)
672 XFreeGC(dpy, gc);
675 return pixmap;
678 /* ---------------------------- interface functions ------------------------ */
682 * argb data to pixmaps
685 Bool PImageCreatePixmapFromArgbData(
686 Display *dpy, Window win, CARD32 *data, int start, int width,
687 int height, Pixmap *pixmap, Pixmap *mask, Pixmap *alpha,
688 int *nalloc_pixels, Pixel **alloc_pixels, int *no_limit,
689 FvwmPictureAttributes fpa)
691 FImage *fim;
692 FImage *m_fim = NULL;
693 FImage *a_fim = NULL;
694 XColor c;
695 int i;
696 int j;
697 int a;
698 PictureImageColorAllocator *pica = NULL;
699 int alpha_limit = PICTURE_ALPHA_LIMIT;
700 int alpha_depth = FRenderGetAlphaDepth();
701 Bool have_mask = False;
702 Bool have_alpha = False;
704 fim = FCreateFImage(
705 dpy, Pvisual, (fpa.mask & FPAM_MONOCHROME) ? 1 : Pdepth,
706 ZPixmap, width, height);
707 if (!fim)
709 return False;
711 if (mask)
713 m_fim = FCreateFImage(
714 dpy, Pvisual, 1, ZPixmap, width, height);
716 if (alpha && !(fpa.mask & FPAM_NO_ALPHA) && alpha_depth)
718 alpha_limit = 0;
719 a_fim = FCreateFImage(
720 dpy, Pvisual, alpha_depth, ZPixmap, width, height);
722 if (!(fpa.mask & FPAM_MONOCHROME))
724 c.flags = DoRed | DoGreen | DoBlue;
725 pica = PictureOpenImageColorAllocator(
726 dpy, Pcmap, width, height,
727 !!(fpa.mask & FPAM_NO_COLOR_LIMIT),
728 !!(fpa.mask & FPAM_NO_ALLOC_PIXELS),
729 !!(fpa.mask & FPAM_DITHER),
730 True);
732 data += start;
733 for (j = 0; j < height; j++)
735 for (i = 0; i < width; i++, data++)
737 a = (*data >> 030) & 0xff;
738 if (a > alpha_limit)
740 c.red = (*data >> 16) & 0xff;
741 c.green = (*data >> 8) & 0xff;
742 c.blue = (*data ) & 0xff;
743 if (pica)
745 PictureAllocColorImage(
746 dpy, pica, &c, i, j);
747 XPutPixel(fim->im, i, j, c.pixel);
749 /* Brightness threshold */
750 else if ((0x99 * c.red +
751 0x12D * c.green +
752 0x3A * c.blue) >> 16)
754 XPutPixel(fim->im, i, j, 1);
756 else
758 XPutPixel(fim->im, i, j, 0);
760 if (m_fim)
762 XPutPixel(m_fim->im, i, j, 1);
765 else if (m_fim != NULL)
767 XPutPixel(m_fim->im, i, j, 0);
768 have_mask = True;
770 if (a_fim != NULL)
772 XPutPixel(a_fim->im, i, j, a);
773 if (a > 0 && a < 0xff)
775 have_alpha = True;
780 if (pica)
782 PictureCloseImageColorAllocator(
783 dpy, pica, nalloc_pixels, alloc_pixels, no_limit);
785 *pixmap = PImageCreatePixmapFromFImage(dpy, win, fim);
786 if (have_alpha)
788 *alpha = PImageCreatePixmapFromFImage(dpy, win, a_fim);
790 else if (have_mask)
792 *mask = PImageCreatePixmapFromFImage(dpy, win, m_fim);
794 FDestroyFImage(dpy, fim);
795 if (m_fim)
797 FDestroyFImage(dpy, m_fim);
799 if (a_fim)
801 FDestroyFImage(dpy, a_fim);
804 return True;
810 * the images loaders
814 Bool PImageLoadPixmapFromFile(
815 Display *dpy, Window win, char *path, Pixmap *pixmap, Pixmap *mask,
816 Pixmap *alpha, int *width, int *height, int *depth,
817 int *nalloc_pixels, Pixel **alloc_pixels,
818 int *no_limit, FvwmPictureAttributes fpa)
820 CARD32 *data;
822 if (PImageLoadArgbDataFromFile(dpy, path, &data, width, height))
824 *depth = (fpa.mask & FPAM_MONOCHROME) ? 1 : Pdepth;
825 if (PImageCreatePixmapFromArgbData(
826 dpy, win, data, 0, *width, *height, pixmap, mask,
827 alpha, nalloc_pixels, alloc_pixels, no_limit, fpa))
829 free(data);
831 return True;
833 free(data);
835 /* Bitmap fallback */
836 else if (
837 XReadBitmapFile(
838 dpy, win, path, (unsigned int *)width,
839 (unsigned int *)height, pixmap, NULL, NULL) ==
840 BitmapSuccess)
842 *depth = 1;
843 *mask = None;
845 return True;
847 pixmap = None;
848 mask = None;
849 alpha = None;
850 *width = *height = *depth = 0;
851 if (nalloc_pixels != NULL)
853 *nalloc_pixels = 0;
855 if (alloc_pixels != NULL)
857 *alloc_pixels = NULL;
859 return False;
862 FvwmPicture *PImageLoadFvwmPictureFromFile(
863 Display *dpy, Window win, char *path, FvwmPictureAttributes fpa)
865 FvwmPicture *p;
866 Pixmap pixmap = None;
867 Pixmap mask = None;
868 Pixmap alpha = None;
869 int width = 0, height = 0;
870 int depth = 0, no_limit;
871 int nalloc_pixels = 0;
872 Pixel *alloc_pixels = NULL;
873 char *real_path;
875 /* Remove any svg rendering options from real_path */
876 if (USE_SVG && *path == ':' &&
877 (real_path = strchr(path + 1, ':')))
879 real_path ++;
881 else
883 real_path = path;
885 if (!PImageLoadPixmapFromFile(
886 dpy, win, path, &pixmap, &mask, &alpha, &width, &height,
887 &depth, &nalloc_pixels, &alloc_pixels, &no_limit, fpa))
889 return NULL;
892 p = (FvwmPicture*)safemalloc(sizeof(FvwmPicture));
893 memset(p, 0, sizeof(FvwmPicture));
894 p->count = 1;
895 p->name = path;
896 p->fpa_mask = fpa.mask;
897 p->next = NULL;
898 setFileStamp(&p->stamp, real_path);
899 p->picture = pixmap;
900 p->mask = mask;
901 p->alpha = alpha;
902 p->width = width;
903 p->height = height;
904 p->depth = depth;
905 p->nalloc_pixels = nalloc_pixels;
906 p->alloc_pixels = alloc_pixels;
907 p->no_limit = no_limit;
908 return p;
911 Cursor PImageLoadCursorFromFile(
912 Display *dpy, Window win, char *path, int x_hot, int y_hot)
914 Cursor cursor = 0;
915 CARD32 *data;
916 int width;
917 int height;
918 int i;
919 FcursorImages *fcis;
920 FcursorImage *fci;
922 /* First try the Xcursor loader (animated cursors) */
923 if ((fcis = FcursorFilenameLoadImages(
924 path, FcursorGetDefaultSize(dpy))))
926 for (i = 0; i < fcis->nimage; i++)
928 if (x_hot < fcis->images[i]->width && x_hot >= 0 &&
929 y_hot < fcis->images[i]->height && y_hot >= 0)
931 fcis->images[i]->xhot = x_hot;
932 fcis->images[i]->yhot = y_hot;
935 cursor = FcursorImagesLoadCursor(dpy, fcis);
936 FcursorImagesDestroy(fcis);
938 /* Get cursor data from the regular image loader */
939 else if (PImageLoadArgbDataFromFile(dpy, path, &data, &width, &height))
941 Pixmap src;
942 Pixmap msk = None;
943 FvwmPictureAttributes fpa;
945 fpa.mask = FPAM_NO_ALPHA | FPAM_MONOCHROME;
947 /* Adjust the hot-spot if necessary */
948 if (
949 x_hot < 0 || x_hot >= width ||
950 y_hot < 0 || y_hot >= height)
952 FxpmImage xpm_im;
953 FxpmInfo xpm_info;
955 memset(&xpm_im, 0, sizeof(FxpmImage));
956 memset(&xpm_info, 0, sizeof(FxpmInfo));
957 if (FxpmReadFileToXpmImage(path, &xpm_im, &xpm_info)
958 == FxpmSuccess)
960 if (xpm_info.valuemask & FxpmHotspot)
962 x_hot = xpm_info.x_hotspot;
963 y_hot = xpm_info.y_hotspot;
965 FxpmFreeXpmImage(&xpm_im);
966 FxpmFreeXpmInfo(&xpm_info);
968 if (x_hot < 0 || x_hot >= width)
970 x_hot = width / 2;
972 if (y_hot < 0 || y_hot >= height)
974 y_hot = height / 2;
977 /* Use the Xcursor library to create the argb cursor */
978 if ((fci = FcursorImageCreate(width, height)))
980 unsigned char alpha;
981 unsigned char red;
982 unsigned char green;
983 unsigned char blue;
985 /* Xcursor expects alpha prescaled RGB values */
986 for (i = 0; i < width * height; i++)
988 alpha = ((data[i] >> 24) & 0xff);
989 red = ((data[i] >> 16) & 0xff) * alpha/0xff;
990 green = ((data[i] >> 8) & 0xff) * alpha/0xff;
991 blue = ((data[i] ) & 0xff) * alpha/0xff;
993 data[i] =
994 (alpha << 24) | (red << 16) |
995 (green << 8) | blue;
998 fci->xhot = x_hot;
999 fci->yhot = y_hot;
1000 fci->delay = 0;
1001 fci->pixels = (FcursorPixel *)data;
1002 cursor = FcursorImageLoadCursor(dpy, fci);
1003 FcursorImageDestroy(fci);
1005 /* Create monochrome cursor from argb data */
1006 else if (PImageCreatePixmapFromArgbData(
1007 dpy, win, data, 0, width, height,
1008 &src, &msk, 0, 0, 0, 0, fpa))
1010 XColor c[2];
1012 c[0].pixel = GetColor(DEFAULT_CURSOR_FORE_COLOR);
1013 c[1].pixel = GetColor(DEFAULT_CURSOR_BACK_COLOR);
1014 XQueryColors(dpy, Pcmap, c, 2);
1015 cursor = XCreatePixmapCursor(
1016 dpy, src, msk, &(c[0]), &(c[1]), x_hot, y_hot);
1017 XFreePixmap(dpy, src);
1018 XFreePixmap(dpy, msk);
1020 free(data);
1023 return cursor;
1026 /* FIXME: Use color limit */
1027 Bool PImageLoadPixmapFromXpmData(
1028 Display *dpy, Window win, int color_limit,
1029 char **data,
1030 Pixmap *pixmap, Pixmap *mask,
1031 int *width, int *height, int *depth)
1033 FxpmAttributes xpm_attributes;
1035 if (!XpmSupport)
1037 return False;
1039 xpm_attributes.valuemask = FxpmCloseness |
1040 FxpmExtensions | FxpmVisual | FxpmColormap | FxpmDepth;
1041 xpm_attributes.closeness = 40000;
1042 xpm_attributes.visual = Pvisual;
1043 xpm_attributes.colormap = Pcmap;
1044 xpm_attributes.depth = Pdepth;
1045 /* suppress compiler warning if xpm library is not compiled in */
1046 xpm_attributes.width = 0;
1047 xpm_attributes.height = 0;
1048 if (
1049 FxpmCreatePixmapFromData(
1050 dpy, win, data, pixmap, mask, &xpm_attributes) !=
1051 FxpmSuccess)
1053 return False;
1055 *width = xpm_attributes.width;
1056 *height = xpm_attributes.height;
1057 *depth = Pdepth;
1059 return True;