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.
9 *
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.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see: <http://www.gnu.org/licenses/>
17 */
18
19 /*
20 *
21 * The png loader and PImageRGBtoPixel are from imlib2. The code is from raster
22 * (Carsten Haitzler) <raster@rasterman.com> <raster@valinux.com>
23 *
24 */
25
26 /* ---------------------------- included header files ---------------------- */
27
28 #include "config.h"
29
30 #include <stdio.h>
31 #include <signal.h>
32 #include <ctype.h>
33
34 #include <X11/Xlib.h>
35 #include <X11/Xmd.h>
36
37 #include <fvwmlib.h>
38 #include "System.h"
39 #include "Strings.h"
40 #include "Picture.h"
41 #include "PictureUtils.h"
42 #include "Graphics.h"
43 #include "ColorUtils.h"
44 #include "Fxpm.h"
45 #include "Fpng.h"
46 #include "Fsvg.h"
47 #include "FRenderInit.h"
48 #include "Fcursor.h"
49 #include "FImage.h"
50
51 /* ---------------------------- local definitions -------------------------- */
52 #define FIMAGE_CMD_ARGS \
53 Display *dpy, char *path, CARD32 **argb_data, int *width, int *height
54
55 #define FIMAGE_PASS_ARGS \
56 dpy, path, argb_data, width, height
57
58 typedef struct PImageLoader
59 {
60 char *extension;
61 #ifdef __STDC__
62 int (*func)(FIMAGE_CMD_ARGS);
63 #else
64 int (*func)();
65 #endif
66 } PImageLoader;
67
68 /* ---------------------------- local macros ------------------------------- */
69
70 /* ---------------------------- imports ------------------------------------ */
71
72 /* ---------------------------- included code files ------------------------ */
73
74 /* ---------------------------- local types -------------------------------- */
75
76 /* ---------------------------- forward declarations ----------------------- */
77
78 static Bool PImageLoadSvg(FIMAGE_CMD_ARGS);
79 static Bool PImageLoadPng(FIMAGE_CMD_ARGS);
80 static Bool PImageLoadXpm(FIMAGE_CMD_ARGS);
81
82 /* ---------------------------- local variables ---------------------------- */
83
84 PImageLoader Loaders[] =
85 {
86 { "xpm", PImageLoadXpm },
87 { "svg", PImageLoadSvg },
88 { "png", PImageLoadPng },
89 {NULL,0}
90 };
91
92 /* ---------------------------- exported variables (globals) --------------- */
93
94 /* ---------------------------- local functions ---------------------------- */
95
96 static
PImageLoadArgbDataFromFile(FIMAGE_CMD_ARGS)97 Bool PImageLoadArgbDataFromFile(FIMAGE_CMD_ARGS)
98 {
99 int done = 0, i = 0, tried = -1;
100 char *ext = NULL;
101
102 if (path == NULL)
103 return False;
104
105 if (strlen(path) > 3)
106 {
107 ext = path + strlen(path) - 3;
108 }
109 /* first try to load by extension */
110 while (!done && ext != NULL && Loaders[i].extension != NULL)
111 {
112 if (StrEquals(Loaders[i].extension, ext))
113 {
114 if (Loaders[i].func(FIMAGE_PASS_ARGS))
115 {
116 return True;
117 }
118 tried = i;
119 done = 1;
120 }
121 i++;
122 }
123
124 i = 0;
125 while (Loaders[i].extension != NULL)
126 {
127 if (i != tried && Loaders[i].func(FIMAGE_PASS_ARGS))
128 {
129 return True;
130 }
131 i++;
132 }
133
134 return False;
135 }
136
137 /*
138 *
139 * svg loader
140 *
141 */
142 static
PImageLoadSvg(FIMAGE_CMD_ARGS)143 Bool PImageLoadSvg(FIMAGE_CMD_ARGS)
144 {
145 char *allocated_path;
146 char *render_opts;
147 FRsvgHandle *rsvg;
148 FRsvgDimensionData dim;
149 CARD32 *data;
150 Fcairo_surface_t *surface;
151 Fcairo_t *cr;
152 int i;
153 int j;
154 int b1;
155 int b2;
156 int w = 0;
157 int h = 0;
158 int dw = 0;
159 int dh = 0;
160 int w_sgn = 1;
161 int h_sgn = 1;
162 double angle = 0;
163 double w_scale = 1;
164 double h_scale = 1;
165 double buf;
166 Bool transpose = False;
167 unsigned char a_value;
168 unsigned char r_value;
169 unsigned char g_value;
170 unsigned char b_value;
171
172 if (!USE_SVG)
173 {
174 fvwm_debug(__func__,
175 "[PImageLoadSvg]: Tried to load SVG file "
176 "when FVWM has not been compiled with SVG support.\n");
177 return False;
178 }
179
180 /* Separate rendering options from path */
181 render_opts = path = allocated_path = fxstrdup(path);
182 if (*path == ':' && (path = strchr(path + 1, ':')))
183 {
184 *path = 0;
185 path ++;
186 render_opts ++;
187 }
188 else
189 {
190 render_opts = "";
191 }
192
193 if (!(rsvg = Frsvg_handle_new_from_file(path, NULL)))
194 {
195 free(allocated_path);
196
197 return False;
198 }
199
200 /* Parsing of rendering options */
201 while (*render_opts)
202 {
203 i = 0;
204 switch (*render_opts)
205 {
206 case '!':
207 transpose = !transpose;
208 break;
209 case '*':
210 if (sscanf(render_opts, "*%lf%n", &buf, &i) >= 1)
211 {
212 switch (render_opts[i])
213 {
214 case 'x':
215 w_scale *= buf;
216 i ++;
217 break;
218 case 'y':
219 h_scale *= buf;
220 i ++;
221 break;
222 default:
223 w_scale *= buf;
224 h_scale *= buf;
225 }
226 }
227 break;
228 case '/':
229 if (sscanf(render_opts, "/%lf%n", &buf, &i) >= 1 &&
230 buf)
231 {
232 switch (render_opts[i])
233 {
234 case 'x':
235 w_scale /= buf;
236 i ++;
237 break;
238 case 'y':
239 h_scale /= buf;
240 i ++;
241 break;
242 default:
243 w_scale /= buf;
244 h_scale /= buf;
245 }
246 }
247 break;
248 case '@':
249 if (sscanf(render_opts, "@%lf%n", &buf, &i) >= 1)
250 {
251 angle += buf;
252 }
253 break;
254 default:
255 j = 0;
256 if (
257 sscanf(
258 render_opts, "%dx%n%d%n", &b1, &j, &b2,
259 &i) >= 2 &&
260 i > j)
261 {
262 w = b1;
263 h = b2;
264
265 if (w < 0 || (!w && render_opts[0] == '-'))
266 {
267 w *= (w_sgn = -1);
268 }
269 if (h < 0 || (!h && render_opts[j] == '-'))
270 {
271 h *= (h_sgn = -1);
272 }
273 }
274 else if (
275 sscanf(render_opts, "%d%d%n", &b1, &b2, &i) >=
276 2)
277 {
278 dw += b1;
279 dh += b2;
280 }
281 }
282 render_opts += i ? i : 1;
283 }
284 free(allocated_path);
285
286 /* Keep the original aspect ratio when either w or h is 0 */
287 Frsvg_handle_get_dimensions(rsvg, &dim);
288 if (!w && !h)
289 {
290 w = dim.width;
291 h = dim.height;
292 }
293 else if (!w)
294 {
295 w = h * dim.em / dim.ex;
296 }
297 else if (!h)
298 {
299 h = w * dim.ex / dim.em;
300 }
301
302 w_scale *= w;
303 h_scale *= h;
304
305 if (transpose)
306 {
307 b1 = w;
308 w = h;
309 h = b1;
310
311 b1 = w_sgn;
312 w_sgn = - h_sgn;
313 h_sgn = b1;
314
315 b1 = dw;
316 dw = - dh;
317 dh = b1;
318
319 angle += 90;
320 }
321
322 data = fxcalloc(1, w * h * sizeof(CARD32));
323 surface = Fcairo_image_surface_create_for_data((unsigned char *)data,
324 FCAIRO_FORMAT_ARGB32, w, h, w * sizeof(CARD32));
325 if (Fcairo_surface_status(surface) != FCAIRO_STATUS_SUCCESS)
326 {
327 Fg_object_unref(FG_OBJECT(rsvg));
328 free(data);
329 if (surface)
330 {
331 Fcairo_surface_destroy(surface);
332 }
333
334 return False;
335 }
336 cr = Fcairo_create(surface);
337 Fcairo_surface_destroy(surface);
338 if (Fcairo_status(cr) != FCAIRO_STATUS_SUCCESS)
339 {
340 Fg_object_unref(FG_OBJECT(rsvg));
341 free(data);
342 if (cr)
343 {
344 Fcairo_destroy(cr);
345 }
346
347 return False;
348 }
349
350 /* Affine transformations ...
351 * mirroring, rotation, scaling and translation */
352 Fcairo_translate(cr, .5 * w, .5 * h);
353 Fcairo_scale(cr, w_sgn, h_sgn);
354 Fcairo_translate(cr, dw, dh);
355 Fcairo_rotate(cr, angle * M_PI / 180);
356 Fcairo_scale(cr, w_scale, h_scale);
357 Fcairo_translate(cr, -.5, -.5);
358 Fcairo_scale(cr, 1 / dim.em, 1 / dim.ex);
359
360 Frsvg_handle_render_cairo(rsvg, cr);
361 Fg_object_unref(FG_OBJECT(rsvg));
362 Fcairo_destroy(cr);
363
364 /* Cairo gave us alpha prescaled RGB values, hence we need
365 * to rescale them for PImageCreatePixmapFromArgbData() */
366 for (i = 0; i < w * h; i++)
367 {
368 if ((a_value = (data[i] >> 030) & 0xff))
369 {
370 r_value = ((data[i] >> 020) & 0xff) * 0xff / a_value;
371 g_value = ((data[i] >> 010) & 0xff) * 0xff / a_value;
372 b_value = (data[i] & 0xff) * 0xff / a_value;
373
374 data[i] =
375 (a_value << 030) | (r_value << 020) |
376 (g_value << 010) | b_value;
377 }
378 }
379
380 *width = w;
381 *height = h;
382 *argb_data = data;
383
384 return True;
385 }
386
387 /*
388 *
389 * png loader
390 *
391 */
392 static
PImageLoadPng(FIMAGE_CMD_ARGS)393 Bool PImageLoadPng(FIMAGE_CMD_ARGS)
394 {
395 Fpng_uint_32 w32, h32;
396 Fpng_structp Fpng_ptr = NULL;
397 Fpng_infop Finfo_ptr = NULL;
398 CARD32 *data;
399 int w, h;
400 char hasa = 0, hasg = 0;
401 FILE *f;
402 int bit_depth;
403 int color_type;
404 int interlace_type;
405 unsigned char buf[FPNG_BYTES_TO_CHECK];
406 unsigned char **lines;
407 int i;
408
409 if (!PngSupport)
410 {
411 /* suppress compiler warning */
412 bit_depth = 0;
413
414 fvwm_debug(__func__,
415 "[PImageLoadPng]: Tried to load PNG file "
416 "when FVWM has not been compiled with PNG support.\n");
417
418 return False;
419 }
420 if (!(f = fopen(path, "rb")))
421 {
422 return False;
423 }
424 {
425 int n;
426
427 n = fread(buf, 1, FPNG_BYTES_TO_CHECK, f);
428 (void)n;
429 }
430 if (!Fpng_check_sig(buf, FPNG_BYTES_TO_CHECK))
431 {
432 fclose(f);
433 return False;
434 }
435 rewind(f);
436 Fpng_ptr = Fpng_create_read_struct(FPNG_LIBPNG_VER_STRING,
437 NULL, NULL, NULL);
438 if (!Fpng_ptr)
439 {
440 fclose(f);
441 return False;
442 }
443 Finfo_ptr = Fpng_create_info_struct(Fpng_ptr);
444 if (!Finfo_ptr)
445 {
446 Fpng_destroy_read_struct(&Fpng_ptr, NULL, NULL);
447 fclose(f);
448 return False;
449 }
450 #if 0
451 if (setjmp(Fpng_ptr->jmpbuf))
452 {
453 Fpng_destroy_read_struct(&Fpng_ptr, &Finfo_ptr, NULL);
454 fclose(f);
455 return False;
456 }
457 #endif
458 Fpng_init_io(Fpng_ptr, f);
459 Fpng_read_info(Fpng_ptr, Finfo_ptr);
460 Fpng_get_IHDR(
461 Fpng_ptr, Finfo_ptr, (Fpng_uint_32 *) (&w32),
462 (Fpng_uint_32 *) (&h32), &bit_depth, &color_type,
463 &interlace_type, NULL, NULL);
464 interlace_type = 0; /* not used */
465 *width = w = (int) w32;
466 *height = h = (int) h32;
467 if (color_type == FPNG_COLOR_TYPE_PALETTE)
468 {
469 Fpng_set_expand(Fpng_ptr);
470 }
471
472 /* TA: XXX: (2011-02-14) -- Happy Valentines Day.
473 *
474 * png_get_color_type() defined in libpng 1.5 now hides a data member
475 * to a struct:
476 *
477 * Finfo_ptr->color_type
478 *
479 * I'm not going to wrap this up in more #ifdef madness, but should
480 * this fail to build on much older libpng versions which we support
481 * (pre 1.3), then I might have to.
482 */
483 if (png_get_color_type(Fpng_ptr, Finfo_ptr) == FPNG_COLOR_TYPE_RGB_ALPHA)
484 {
485 hasa = 1;
486 }
487 if (png_get_color_type(Fpng_ptr, Finfo_ptr) == FPNG_COLOR_TYPE_GRAY_ALPHA)
488 {
489 hasa = 1;
490 hasg = 1;
491 }
492 if (png_get_color_type(Fpng_ptr, Finfo_ptr) == FPNG_COLOR_TYPE_GRAY)
493 {
494 hasg = 1;
495 }
496
497 if (hasa)
498 Fpng_set_expand(Fpng_ptr);
499 /* we want ARGB */
500 /* note form raster:
501 * thanks to mustapha for helping debug this on PPC Linux remotely by
502 * sending across screenshots all the time and me figuring out form them
503 * what the hell was up with the colors
504 * now png loading should work on big endian machines nicely */
505 #ifdef WORDS_BIGENDIAN
506 Fpng_set_swap_alpha(Fpng_ptr);
507 Fpng_set_filler(Fpng_ptr, 0xff, FPNG_FILLER_BEFORE);
508 #else
509 Fpng_set_bgr(Fpng_ptr);
510 Fpng_set_filler(Fpng_ptr, 0xff, FPNG_FILLER_AFTER);
511 #endif
512 /* 16bit color -> 8bit color */
513 Fpng_set_strip_16(Fpng_ptr);
514 /* pack all pixels to byte boundaires */
515 Fpng_set_packing(Fpng_ptr);
516 if (Fpng_get_valid(Fpng_ptr, Finfo_ptr, FPNG_INFO_tRNS))
517 {
518 Fpng_set_expand(Fpng_ptr);
519 }
520
521 data = fxmalloc(w * h * sizeof(CARD32));
522 lines = fxmalloc(h * sizeof(unsigned char *));
523
524 if (hasg)
525 {
526 Fpng_set_gray_to_rgb(Fpng_ptr);
527 if (Fpng_get_bit_depth(Fpng_ptr, Finfo_ptr) < 8)
528 {
529 Fpng_set_gray_1_2_4_to_8(Fpng_ptr);
530 }
531 }
532 for (i = 0; i < h; i++)
533 {
534 lines[i] = (unsigned char *)data + (i * w * sizeof(CARD32));
535 }
536 Fpng_read_image(Fpng_ptr, lines);
537 Fpng_read_end(Fpng_ptr, Finfo_ptr);
538 Fpng_destroy_read_struct(&Fpng_ptr, &Finfo_ptr, (png_infopp) NULL);
539 fclose(f);
540 free(lines);
541 *argb_data = data;
542
543 return True;
544 }
545
546 /*
547 *
548 * xpm loader
549 *
550 */
551 static
PImageLoadXpm(FIMAGE_CMD_ARGS)552 Bool PImageLoadXpm(FIMAGE_CMD_ARGS)
553 {
554 FxpmImage xpm_im;
555 FxpmColor *xpm_color;
556 XColor color;
557 CARD32 *colors;
558 CARD32 *data;
559 char *visual_color;
560 int i;
561 int w;
562 int h;
563 int rc;
564 #ifdef HAVE_SIGACTION
565 struct sigaction defaultHandler;
566 struct sigaction originalHandler;
567 #else
568 RETSIGTYPE (*originalHandler)(int);
569 #endif
570
571 if (!XpmSupport)
572 {
573 fvwm_debug(__func__,
574 "[PImageLoadXpm]: Tried to load XPM file "
575 "when FVWM has not been compiled with XPm Support.\n");
576 return False;
577 }
578 memset(&xpm_im, 0, sizeof(FxpmImage));
579
580 #ifdef HAVE_SIGACTION
581 sigemptyset(&defaultHandler.sa_mask);
582 defaultHandler.sa_flags = 0;
583 defaultHandler.sa_handler = SIG_DFL;
584 sigaction(SIGCHLD, &defaultHandler, &originalHandler);
585 #else
586 originalHandler = signal(SIGCHLD, SIG_DFL);
587 #endif
588
589
590 rc = FxpmReadFileToXpmImage(path, &xpm_im, NULL);
591
592 #ifdef HAVE_SIGACTION
593 sigaction(SIGCHLD, &originalHandler, NULL);
594 #else
595 signal(SIGCHLD, originalHandler);
596 #endif
597
598 if (rc != FxpmSuccess)
599 {
600 return False;
601 }
602
603 if (xpm_im.ncolors <= 0)
604 {
605 FxpmFreeXpmImage(&xpm_im);
606 return False;
607 }
608 colors = fxmalloc(xpm_im.ncolors * sizeof(CARD32));
609 for (i=0; i < xpm_im.ncolors; i++)
610 {
611 xpm_color = &xpm_im.colorTable[i];
612 if (xpm_color->c_color)
613 {
614 visual_color = xpm_color->c_color;
615 }
616 else if (xpm_color->g_color)
617 {
618 visual_color = xpm_color->g_color;
619 }
620 else if (xpm_color->g4_color)
621 {
622 visual_color = xpm_color->g4_color;
623 }
624 else
625 {
626 visual_color = xpm_color->m_color;
627 }
628 if (XParseColor(dpy, Pcmap, visual_color, &color))
629 {
630 colors[i] = 0xff000000 |
631 ((color.red << 8) & 0xff0000) |
632 ((color.green ) & 0xff00) |
633 ((color.blue >> 8) & 0xff);
634 }
635 else
636 {
637 colors[i] = 0;
638 }
639 }
640 *width = w = xpm_im.width;
641 *height = h = xpm_im.height;
642 data = fxmalloc(w * h * sizeof(CARD32));
643 for (i=0; i < w * h; i++)
644 {
645 data[i] = colors[xpm_im.data[i]];
646 }
647 free(colors);
648 *argb_data = data;
649
650 return True;
651 }
652
653 /*
654 *
655 * copy image to server
656 *
657 */
658 static
PImageCreatePixmapFromFImage(Display * dpy,Window win,FImage * fimage)659 Pixmap PImageCreatePixmapFromFImage(Display *dpy, Window win, FImage *fimage)
660 {
661 GC gc;
662 Pixmap pixmap;
663 int w;
664 int h;
665 int depth;
666
667 w = fimage->im->width;
668 h = fimage->im->height;
669 depth = fimage->im->depth;
670 pixmap = XCreatePixmap(dpy, win, w, h, depth);
671 if (depth == Pdepth)
672 {
673 gc = PictureDefaultGC(dpy, win);
674 }
675 else
676 {
677 gc = fvwmlib_XCreateGC(dpy, pixmap, 0, NULL);
678 }
679 FPutFImage(dpy, pixmap, gc, fimage, 0, 0, 0, 0, w, h);
680 if (depth != Pdepth)
681 {
682 XFreeGC(dpy, gc);
683 }
684
685 return pixmap;
686 }
687
688 /* ---------------------------- interface functions ------------------------ */
689
690 /*
691 *
692 * argb data to pixmaps
693 *
694 */
PImageCreatePixmapFromArgbData(Display * dpy,Window win,CARD32 * data,int start,int width,int height,Pixmap * pixmap,Pixmap * mask,Pixmap * alpha,int * nalloc_pixels,Pixel ** alloc_pixels,int * no_limit,FvwmPictureAttributes fpa)695 Bool PImageCreatePixmapFromArgbData(
696 Display *dpy, Window win, CARD32 *data, int start, int width,
697 int height, Pixmap *pixmap, Pixmap *mask, Pixmap *alpha,
698 int *nalloc_pixels, Pixel **alloc_pixels, int *no_limit,
699 FvwmPictureAttributes fpa)
700 {
701 FImage *fim;
702 FImage *m_fim = NULL;
703 FImage *a_fim = NULL;
704 XColor c;
705 int i;
706 int j;
707 int a;
708 PictureImageColorAllocator *pica = NULL;
709 int alpha_limit = PICTURE_ALPHA_LIMIT;
710 int alpha_depth = FRenderGetAlphaDepth();
711 Bool have_mask = False;
712 Bool have_alpha = False;
713
714 fim = FCreateFImage(
715 dpy, Pvisual, (fpa.mask & FPAM_MONOCHROME) ? 1 : Pdepth,
716 ZPixmap, width, height);
717 if (!fim)
718 {
719 return False;
720 }
721 if (mask)
722 {
723 m_fim = FCreateFImage(
724 dpy, Pvisual, 1, ZPixmap, width, height);
725 }
726 if (alpha && !(fpa.mask & FPAM_NO_ALPHA) && alpha_depth)
727 {
728 alpha_limit = 0;
729 a_fim = FCreateFImage(
730 dpy, Pvisual, alpha_depth, ZPixmap, width, height);
731 }
732 if (!(fpa.mask & FPAM_MONOCHROME))
733 {
734 c.flags = DoRed | DoGreen | DoBlue;
735 pica = PictureOpenImageColorAllocator(
736 dpy, Pcmap, width, height,
737 !!(fpa.mask & FPAM_NO_COLOR_LIMIT),
738 !!(fpa.mask & FPAM_NO_ALLOC_PIXELS),
739 !!(fpa.mask & FPAM_DITHER),
740 True);
741 }
742 data += start;
743 for (j = 0; j < height; j++)
744 {
745 for (i = 0; i < width; i++, data++)
746 {
747 a = (*data >> 030) & 0xff;
748 if (a > alpha_limit)
749 {
750 c.red = (*data >> 16) & 0xff;
751 c.green = (*data >> 8) & 0xff;
752 c.blue = (*data ) & 0xff;
753 if (pica)
754 {
755 PictureAllocColorImage(
756 dpy, pica, &c, i, j);
757 XPutPixel(fim->im, i, j, c.pixel);
758 }
759 /* Brightness threshold */
760 else if ((0x99 * c.red +
761 0x12D * c.green +
762 0x3A * c.blue) >> 16)
763 {
764 XPutPixel(fim->im, i, j, 1);
765 }
766 else
767 {
768 XPutPixel(fim->im, i, j, 0);
769 }
770 if (m_fim)
771 {
772 XPutPixel(m_fim->im, i, j, 1);
773 }
774 }
775 else if (m_fim != NULL)
776 {
777 XPutPixel(m_fim->im, i, j, 0);
778 have_mask = True;
779 }
780 if (a_fim != NULL)
781 {
782 XPutPixel(a_fim->im, i, j, a);
783 if (a > 0 && a < 0xff)
784 {
785 have_alpha = True;
786 }
787 }
788 }
789 }
790 if (pica)
791 {
792 PictureCloseImageColorAllocator(
793 dpy, pica, nalloc_pixels, alloc_pixels, no_limit);
794 }
795 *pixmap = PImageCreatePixmapFromFImage(dpy, win, fim);
796 if (have_alpha)
797 {
798 *alpha = PImageCreatePixmapFromFImage(dpy, win, a_fim);
799 }
800 else if (have_mask)
801 {
802 *mask = PImageCreatePixmapFromFImage(dpy, win, m_fim);
803 }
804 FDestroyFImage(dpy, fim);
805 if (m_fim)
806 {
807 FDestroyFImage(dpy, m_fim);
808 }
809 if (a_fim)
810 {
811 FDestroyFImage(dpy, a_fim);
812 }
813
814 return True;
815 }
816
817
818 /*
819 *
820 * the images loaders
821 *
822 */
823
PImageLoadPixmapFromFile(Display * dpy,Window win,char * path,Pixmap * pixmap,Pixmap * mask,Pixmap * alpha,int * width,int * height,int * depth,int * nalloc_pixels,Pixel ** alloc_pixels,int * no_limit,FvwmPictureAttributes fpa)824 Bool PImageLoadPixmapFromFile(
825 Display *dpy, Window win, char *path, Pixmap *pixmap, Pixmap *mask,
826 Pixmap *alpha, int *width, int *height, int *depth,
827 int *nalloc_pixels, Pixel **alloc_pixels,
828 int *no_limit, FvwmPictureAttributes fpa)
829 {
830 CARD32 *data;
831
832 if (PImageLoadArgbDataFromFile(dpy, path, &data, width, height))
833 {
834 *depth = (fpa.mask & FPAM_MONOCHROME) ? 1 : Pdepth;
835 if (PImageCreatePixmapFromArgbData(
836 dpy, win, data, 0, *width, *height, pixmap, mask,
837 alpha, nalloc_pixels, alloc_pixels, no_limit, fpa))
838 {
839 free(data);
840
841 return True;
842 }
843 free(data);
844 }
845 /* Bitmap fallback */
846 else if (
847 XReadBitmapFile(
848 dpy, win, path, (unsigned int *)width,
849 (unsigned int *)height, pixmap, NULL, NULL) ==
850 BitmapSuccess)
851 {
852 *depth = 1;
853 *mask = None;
854
855 return True;
856 }
857 pixmap = None;
858 mask = None;
859 alpha = None;
860 *width = *height = *depth = 0;
861 if (nalloc_pixels != NULL)
862 {
863 *nalloc_pixels = 0;
864 }
865 if (alloc_pixels != NULL)
866 {
867 *alloc_pixels = NULL;
868 }
869 return False;
870 }
871
PImageLoadFvwmPictureFromFile(Display * dpy,Window win,char * path,FvwmPictureAttributes fpa)872 FvwmPicture *PImageLoadFvwmPictureFromFile(
873 Display *dpy, Window win, char *path, FvwmPictureAttributes fpa)
874 {
875 FvwmPicture *p;
876 Pixmap pixmap = None;
877 Pixmap mask = None;
878 Pixmap alpha = None;
879 int width = 0, height = 0;
880 int depth = 0, no_limit;
881 int nalloc_pixels = 0;
882 Pixel *alloc_pixels = NULL;
883 char *real_path;
884
885 /* Remove any svg rendering options from real_path */
886 if (USE_SVG && *path == ':' &&
887 (real_path = strchr(path + 1, ':')))
888 {
889 real_path ++;
890 }
891 else
892 {
893 real_path = path;
894 }
895 if (!PImageLoadPixmapFromFile(
896 dpy, win, path, &pixmap, &mask, &alpha, &width, &height,
897 &depth, &nalloc_pixels, &alloc_pixels, &no_limit, fpa))
898 {
899 return NULL;
900 }
901
902 p = fxcalloc(1, sizeof(FvwmPicture));
903 p->count = 1;
904 p->name = path;
905 p->fpa_mask = fpa.mask;
906 p->next = NULL;
907 setFileStamp(&p->stamp, real_path);
908 p->picture = pixmap;
909 p->mask = mask;
910 p->alpha = alpha;
911 p->width = width;
912 p->height = height;
913 p->depth = depth;
914 p->nalloc_pixels = nalloc_pixels;
915 p->alloc_pixels = alloc_pixels;
916 p->no_limit = no_limit;
917 return p;
918 }
919
PImageLoadCursorFromFile(Display * dpy,Window win,char * path,int x_hot,int y_hot)920 Cursor PImageLoadCursorFromFile(
921 Display *dpy, Window win, char *path, int x_hot, int y_hot)
922 {
923 Cursor cursor = 0;
924 CARD32 *data;
925 int width;
926 int height;
927 int i;
928 FcursorImages *fcis;
929 FcursorImage *fci;
930
931 /* First try the Xcursor loader (animated cursors) */
932 if ((fcis = FcursorFilenameLoadImages(
933 path, FcursorGetDefaultSize(dpy))))
934 {
935 for (i = 0; i < fcis->nimage; i++)
936 {
937 if (x_hot < fcis->images[i]->width && x_hot >= 0 &&
938 y_hot < fcis->images[i]->height && y_hot >= 0)
939 {
940 fcis->images[i]->xhot = x_hot;
941 fcis->images[i]->yhot = y_hot;
942 }
943 }
944 cursor = FcursorImagesLoadCursor(dpy, fcis);
945 FcursorImagesDestroy(fcis);
946 }
947 /* Get cursor data from the regular image loader */
948 else if (PImageLoadArgbDataFromFile(dpy, path, &data, &width, &height))
949 {
950 Pixmap src;
951 Pixmap msk = None;
952 FvwmPictureAttributes fpa;
953
954 fpa.mask = FPAM_NO_ALPHA | FPAM_MONOCHROME;
955
956 /* Adjust the hot-spot if necessary */
957 if (
958 x_hot < 0 || x_hot >= width ||
959 y_hot < 0 || y_hot >= height)
960 {
961 FxpmImage xpm_im;
962 FxpmInfo xpm_info;
963
964 memset(&xpm_im, 0, sizeof(FxpmImage));
965 memset(&xpm_info, 0, sizeof(FxpmInfo));
966 if (FxpmReadFileToXpmImage(path, &xpm_im, &xpm_info)
967 == FxpmSuccess)
968 {
969 if (xpm_info.valuemask & FxpmHotspot)
970 {
971 x_hot = xpm_info.x_hotspot;
972 y_hot = xpm_info.y_hotspot;
973 }
974 FxpmFreeXpmImage(&xpm_im);
975 FxpmFreeXpmInfo(&xpm_info);
976 }
977 if (x_hot < 0 || x_hot >= width)
978 {
979 x_hot = width / 2;
980 }
981 if (y_hot < 0 || y_hot >= height)
982 {
983 y_hot = height / 2;
984 }
985 }
986 /* Use the Xcursor library to create the argb cursor */
987 if ((fci = FcursorImageCreate(width, height)))
988 {
989 unsigned char alpha;
990 unsigned char red;
991 unsigned char green;
992 unsigned char blue;
993
994 /* Xcursor expects alpha prescaled RGB values */
995 for (i = 0; i < width * height; i++)
996 {
997 alpha = ((data[i] >> 24) & 0xff);
998 red = ((data[i] >> 16) & 0xff) * alpha/0xff;
999 green = ((data[i] >> 8) & 0xff) * alpha/0xff;
1000 blue = ((data[i] ) & 0xff) * alpha/0xff;
1001
1002 data[i] =
1003 (alpha << 24) | (red << 16) |
1004 (green << 8) | blue;
1005 }
1006
1007 fci->xhot = x_hot;
1008 fci->yhot = y_hot;
1009 fci->delay = 0;
1010 fci->pixels = (FcursorPixel *)data;
1011 cursor = FcursorImageLoadCursor(dpy, fci);
1012 FcursorImageDestroy(fci);
1013 }
1014 /* Create monochrome cursor from argb data */
1015 else if (PImageCreatePixmapFromArgbData(
1016 dpy, win, data, 0, width, height,
1017 &src, &msk, 0, 0, 0, 0, fpa))
1018 {
1019 XColor c[2];
1020
1021 c[0].pixel = GetColor(DEFAULT_CURSOR_FORE_COLOR);
1022 c[1].pixel = GetColor(DEFAULT_CURSOR_BACK_COLOR);
1023 XQueryColors(dpy, Pcmap, c, 2);
1024 cursor = XCreatePixmapCursor(
1025 dpy, src, msk, &(c[0]), &(c[1]), x_hot, y_hot);
1026 XFreePixmap(dpy, src);
1027 XFreePixmap(dpy, msk);
1028 }
1029 free(data);
1030 }
1031
1032 return cursor;
1033 }
1034
1035 /* FIXME: Use color limit */
PImageLoadPixmapFromXpmData(Display * dpy,Window win,int color_limit,char ** data,Pixmap * pixmap,Pixmap * mask,int * width,int * height,int * depth)1036 Bool PImageLoadPixmapFromXpmData(
1037 Display *dpy, Window win, int color_limit,
1038 char **data,
1039 Pixmap *pixmap, Pixmap *mask,
1040 int *width, int *height, int *depth)
1041 {
1042 FxpmAttributes xpm_attributes;
1043
1044 if (!XpmSupport)
1045 {
1046 return False;
1047 }
1048 xpm_attributes.valuemask = FxpmCloseness |
1049 FxpmExtensions | FxpmVisual | FxpmColormap | FxpmDepth;
1050 xpm_attributes.closeness = 40000;
1051 xpm_attributes.visual = Pvisual;
1052 xpm_attributes.colormap = Pcmap;
1053 xpm_attributes.depth = Pdepth;
1054 /* suppress compiler warning if xpm library is not compiled in */
1055 xpm_attributes.width = 0;
1056 xpm_attributes.height = 0;
1057 if (
1058 FxpmCreatePixmapFromData(
1059 dpy, win, data, pixmap, mask, &xpm_attributes) !=
1060 FxpmSuccess)
1061 {
1062 return False;
1063 }
1064 *width = xpm_attributes.width;
1065 *height = xpm_attributes.height;
1066 *depth = Pdepth;
1067
1068 return True;
1069 }
1070