1 /*
2 * rimage.c: Interface to wraster lib (conversion of RImage)
3 *
4 * Written by: Ullrich Hafner
5 *
6 * Copyright (C) 1999 Ullrich Hafner <hafner@bigfoot.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
21 */
22
23 /*
24 * $Date: 2000/10/16 18:24:42 $
25 * $Author: hafner $
26 * $Revision: 1.12 $
27 * $State: Exp $
28 */
29
30 #include "config.h"
31
32 #if defined(PREVIEWS) && !defined(CONVERT)
33
34 #if HAVE_STDLIB_H
35 # include <stdlib.h>
36 #endif /* not HAVE_STDLIB_H */
37 #if HAVE_STRING_H
38 # include <string.h>
39 #else /* not HAVE_STRING_H */
40 # include <strings.h>
41 #endif /* not HAVE_STRING_H */
42 #include <stdio.h>
43 #include <gtk/gtk.h>
44 #include <gdk/gdkx.h>
45 #include <assert.h>
46 #include "proplist_t.h"
47 #include <wraster.h>
48
49 #include "window.h"
50 #include "rimage.h"
51 #include "error.h"
52
53
54 /*****************************************************************************
55
56 global and local variables
57
58 *****************************************************************************/
59
60 static RContext *rc = NULL;
61 extern GtkWidget *main_window;
62
63 /*****************************************************************************
64
65 prototypes
66
67 *****************************************************************************/
68
69 #ifdef HAVE_LIBWMFUN
70 RImage *
71 bilinear (int argc, char **argv, int width, int height, int relief);
72 RImage *
73 fade (int argc, char **argv, int width, int height, int relief);
74 RImage *
75 waves (int argc, char **argv, int width, int height, int relief);
76 void
77 initWindowMaker (Display *d, Colormap c);
78 #endif /* HAVE_LIBWMFUN */
79 static RColor *
80 get_background_color (void);
81 static RImage *
82 rimage_load (const char *filename, int width, int height);
83 static GtkWidget *
84 rimage_2_preview (RImage *image, GtkWidget *preview, bool_t bevel);
85
86 /*****************************************************************************
87
88 public code
89
90 *****************************************************************************/
91
92 void
init_wraster_lib(void)93 init_wraster_lib (void)
94 {
95 if (!rc)
96 {
97 RContextAttributes rattr;
98
99 rattr.flags = 0;
100 rc = RCreateContext (GDK_DISPLAY (), DefaultScreen (GDK_DISPLAY ()),
101 &rattr);
102 #ifdef HAVE_LIBWMFUN
103 initWindowMaker (GDK_DISPLAY (), rc->cmap);
104 #endif /* HAVE_LIBWMFUN */
105 }
106 }
107
108 /* We need this wrapper function since gdk_parse_color() no longer
109 * understands "rgb:RR/GG/BB".
110 */
111 gboolean
make_color(const gchar * spec,GdkColor * color)112 make_color(const gchar *spec, GdkColor *color)
113 {
114 gboolean result;
115 gchar * newspec = g_strdup (spec);
116
117 if (strncmp(spec, "rgb:", 4) == 0) {
118 const char * red_posn = spec + 4, * green_posn, * blue_posn;
119 int red_len, green_len, blue_len;
120
121 green_posn = strchr(red_posn, '/');
122 if (!green_posn) return FALSE;
123 red_len = green_posn - red_posn;
124 green_posn++;
125
126 blue_posn = strchr(green_posn, '/');
127 if (!blue_posn) return FALSE;
128 green_len = blue_posn - green_posn;
129 blue_posn++;
130 blue_len = strlen(spec) - (blue_posn - spec);
131
132 if (red_len != green_len || green_len != blue_len ||
133 red_len < 1 || red_len > 4)
134 return FALSE;
135
136 newspec = malloc(3 * red_len + 2);
137 strcpy(newspec, "#");
138 strncat(newspec, red_posn, red_len);
139 strncat(newspec, green_posn, red_len);
140 strncat(newspec, blue_posn, red_len);
141 }
142
143 result = gdk_color_parse (newspec, color);
144 if (newspec != spec)
145 free (newspec);
146 return result;
147 }
148
149 GtkWidget *
make_image(const char * filename,int width,int height,GtkWidget * preview)150 make_image (const char *filename, int width, int height, GtkWidget *preview)
151 {
152 RImage *rimage = rimage_load (filename, width, height);
153
154 preview = rimage_2_preview (rimage, preview, FALSE);
155 RReleaseImage (rimage);
156
157 return preview;
158 }
159
160 GtkWidget *
make_gradient(proplist_t array,unsigned width,unsigned height,gtype_e type,GtkWidget * preview)161 make_gradient (proplist_t array, unsigned width, unsigned height,
162 gtype_e type, GtkWidget *preview)
163 {
164 if (!array || !WMIsPLArray (array) || WMGetPropListItemCount (array) < 3)
165 return make_image (PKGDATADIR "/black.xpm", width, height, preview);
166 else
167 {
168 unsigned n = WMGetPropListItemCount (array);
169 unsigned start = n == 3 ? 1 : 2;
170 RColor **colors = Calloc (n + 1, sizeof (RColor *));
171 unsigned k;
172
173 for (k = start; k < n; k++)
174 {
175 GdkColor c;
176
177 if (!make_color (WMGetFromPLString (WMGetFromPLArray (array, k)), &c))
178 c.red = c.green = c.blue = 65535; /* white */
179
180 colors [k - start] = Calloc (1, sizeof (RColor)) ;
181 colors [k - start]->red = c.red >> 8;
182 colors [k - start]->green = c.green >> 8;
183 colors [k - start]->blue = c.blue >> 8;
184 }
185 colors [k - start] = NULL;
186
187 {
188 RImage *rimage;
189
190 if (n == 3)
191 rimage
192 = RRenderGradient (width, height, colors [0], colors [1],
193 type == HGRADIENT ? RHorizontalGradient
194 : (type == VGRADIENT ? RVerticalGradient
195 : RDiagonalGradient));
196 else
197 rimage
198 = RRenderMultiGradient (width, height, colors,
199 type == HGRADIENT ? RHorizontalGradient
200 : (type == VGRADIENT ? RVerticalGradient
201 : RDiagonalGradient));
202 preview = rimage_2_preview (rimage, preview,
203 TRUE && rimage->height < 100);
204 RReleaseImage (rimage);
205 }
206
207 for (k = start; k < n; k++)
208 Free (colors [k - start]);
209 Free (colors);
210
211 return preview;
212 }
213 }
214
215 GtkWidget *
make_solid(const char * color,unsigned width,unsigned height,GtkWidget * preview)216 make_solid (const char *color, unsigned width, unsigned height,
217 GtkWidget *preview)
218 {
219 if (!preview)
220 {
221 preview = gtk_preview_new (GTK_PREVIEW_COLOR);
222 gtk_preview_size (GTK_PREVIEW (preview), width, height);
223 }
224 else
225 {
226 width = GTK_WIDGET (preview)->requisition.width;
227 height = GTK_WIDGET (preview)->requisition.height;
228 }
229 {
230 guchar *row = Calloc (width * 3, sizeof (guchar));
231 unsigned x, y;
232 GdkColor c;
233
234 if (!make_color (color, &c))
235 c.red = c.green = c.blue = 65535; /* white */
236 for (y = 0; y < height; y++)
237 {
238 guchar *ptr = row;
239 for (x = 0; x < width; x++)
240 {
241 *ptr++ = c.red >> 8;
242 *ptr++ = c.green >> 8;
243 *ptr++ = c.blue >> 8;
244 }
245 gtk_preview_draw_row (GTK_PREVIEW (preview), row, 0, y, width);
246 }
247 Free (row);
248 }
249 gtk_widget_draw (preview, NULL);
250
251 return preview;
252 }
253
254 GtkWidget *
make_textured_gradient(const char * filename,proplist_t array,unsigned width,unsigned height,gtype_e type,GtkWidget * preview)255 make_textured_gradient (const char *filename, proplist_t array,
256 unsigned width, unsigned height,
257 gtype_e type, GtkWidget *preview)
258 {
259 if (!filename || WMGetPropListItemCount (array) != 5)
260 return make_image (PKGDATADIR "/black.xpm", width, height, preview);
261 else
262 {
263 GdkColor c1, c2;
264 RColor r1, r2;
265 int opacity = strtol (WMGetFromPLString (WMGetFromPLArray (array, 2)),
266 NULL, 10);
267 RImage *gradient, *image, *tiled;
268
269 if (!make_color (WMGetFromPLString (WMGetFromPLArray (array, 3)), &c1))
270 c1.red = c1.green = c1.blue = 65535; /* white */
271 if (!make_color (WMGetFromPLString (WMGetFromPLArray (array, 4)), &c2))
272 c2.red = c2.green = c2.blue = 65535; /* white */
273 r1.red = c1.red >> 8;
274 r1.green = c1.green >> 8;
275 r1.blue = c1.blue >> 8;
276
277 r2.red = c2.red >> 8;
278 r2.green = c2.green >> 8;
279 r2.blue = c2.blue >> 8;
280
281 if (!preview)
282 {
283 preview = gtk_preview_new (GTK_PREVIEW_COLOR);
284 gtk_preview_size (GTK_PREVIEW (preview), width, height);
285 }
286 else
287 {
288 width = GTK_WIDGET (preview)->requisition.width;
289 height = GTK_WIDGET (preview)->requisition.height;
290 }
291
292 gradient = RRenderGradient (width, height, &r1, &r2,
293 type == HGRADIENT ? RHorizontalGradient
294 : (type == VGRADIENT ? RVerticalGradient
295 : RDiagonalGradient));
296
297 image = rimage_load (filename, -1, -1);
298 tiled = RMakeTiledImage (image, width, height);
299 RReleaseImage (image);
300
301 if (tiled)
302 {
303 RCombineImagesWithOpaqueness (tiled, gradient, opacity);
304 RReleaseImage (gradient);
305
306 preview = rimage_2_preview (tiled, preview, FALSE);
307 RReleaseImage (tiled);
308 }
309 else
310 {
311 preview = rimage_2_preview (gradient, preview, FALSE);
312 RReleaseImage (gradient);
313 }
314 return preview;
315 }
316 }
317
318 #ifdef HAVE_INTERWOVEN_GRADIENT
319
320 GtkWidget *
make_igradient(proplist_t array,unsigned width,unsigned height,GtkWidget * preview)321 make_igradient (proplist_t array, unsigned width, unsigned height,
322 GtkWidget *preview)
323 {
324 if (WMGetPropListItemCount (array) != 7)
325 return make_image (PKGDATADIR "/black.xpm", width, height, preview);
326 else
327 {
328 GdkColor from1, to1, from2, to2;
329 RColor r1 [2], r2 [2];
330 int thickness1 = strtol (WMGetFromPLString (WMGetFromPLArray (array,
331 3)),
332 NULL, 10);
333 int thickness2 = strtol (WMGetFromPLString (WMGetFromPLArray (array,
334 6)),
335 NULL, 10);
336 RImage *gradient;
337
338 if (!make_color (WMGetFromPLString (WMGetFromPLArray (array, 1)),
339 &from1))
340 from1.red = from1.green = from1.blue = 65535; /* white */
341 if (!make_color (WMGetFromPLString (WMGetFromPLArray (array, 2)), &to1))
342 to1.red = to1.green = to1.blue = 65535; /* white */
343 if (!make_color (WMGetFromPLString (WMGetFromPLArray (array, 4)),
344 &from2))
345 from2.red = from2.green = from2.blue = 65535; /* white */
346 if (!make_color (WMGetFromPLString (WMGetFromPLArray (array, 5)), &to2))
347 to2.red = to2.green = to2.blue = 65535; /* white */
348
349 r1 [0].red = from1.red >> 8;
350 r1 [0].green = from1.green >> 8;
351 r1 [0].blue = from1.blue >> 8;
352
353 r1 [1].red = to1.red >> 8;
354 r1 [1].green = to1.green >> 8;
355 r1 [1].blue = to1.blue >> 8;
356
357 r2 [0].red = from2.red >> 8;
358 r2 [0].green = from2.green >> 8;
359 r2 [0].blue = from2.blue >> 8;
360
361 r2 [1].red = to2.red >> 8;
362 r2 [1].green = to2.green >> 8;
363 r2 [1].blue = to2.blue >> 8;
364
365 if (!preview)
366 {
367 preview = gtk_preview_new (GTK_PREVIEW_COLOR);
368 gtk_preview_size (GTK_PREVIEW (preview), width, height);
369 }
370 else
371 {
372 width = GTK_WIDGET (preview)->requisition.width;
373 height = GTK_WIDGET (preview)->requisition.height;
374 }
375
376 gradient = RRenderInterwovenGradient (width, height,
377 r1, thickness1,
378 r2, thickness2);
379
380 if (gradient)
381 {
382 preview = rimage_2_preview (gradient, preview,
383 gradient->height < 100);
384 RReleaseImage (gradient);
385 }
386 else
387 preview = make_image (PKGDATADIR "/black.xpm",
388 width, height, preview);
389
390 return preview;
391 }
392 }
393
394 #endif /* HAVE_INTERWOVEN_GRADIENT */
395
396 #ifdef HAVE_LIBWMFUN
397 GtkWidget *
make_wmfun(proplist_t array,unsigned width,unsigned height,GtkWidget * preview)398 make_wmfun (proplist_t array, unsigned width, unsigned height,
399 GtkWidget *preview)
400 {
401 unsigned n = WMGetPropListItemCount (array);
402 const char *library = n > 2
403 ? WMGetFromPLString (WMGetFromPLArray (array, 1)) : NULL;
404 const char *type = n > 2
405 ? WMGetFromPLString (WMGetFromPLArray (array, 0)) : NULL;
406 if (!array || !WMIsPLArray (array) || !library || !type ||
407 !strcaseeq (type, "function") || !strncaseeq (library, "libwmfun",
408 strlen ("libwmfun")))
409 return make_image (PKGDATADIR "/black.xpm", width, height, preview);
410 else
411 {
412 unsigned n = WMGetPropListItemCount (array);
413 char **argv = Calloc (n + 2, sizeof (char *));
414 char *function = WMGetFromPLString (WMGetFromPLArray (array, 2));
415 unsigned k;
416 unsigned argc;
417 RImage *image;
418
419 for (k = 2, argc = 0; k < n; k++)
420 argv [argc++] = WMGetFromPLString (WMGetFromPLArray (array, k));
421 argv [argc] = NULL;
422
423 if ((strcaseeq (function, "bilinear")))
424 image = bilinear (argc, argv, width, height, 0);
425 else if ((strcaseeq (function, "fade")))
426 image = fade (argc, argv, width, height, 0);
427 else if ((strcaseeq (function, "waves")))
428 image = waves (argc, argv, width, height, 0);
429 else
430 image = NULL;
431
432 if (image)
433 {
434 preview = rimage_2_preview (image, preview, image->height < 100);
435 RReleaseImage (image);
436 }
437 else
438 preview = make_image (PKGDATADIR "/black.xpm",
439 width, height, preview);
440 Free (argv);
441 return preview;
442 }
443 }
444 #endif /* HAVE_LIBWMFUN */
445
446 /*****************************************************************************
447
448 private code
449
450 *****************************************************************************/
451
452 static RImage *
rimage_load(const char * filename,int width,int height)453 rimage_load (const char *filename, int width, int height)
454 {
455 char *path = get_pixmap_path (filename);
456
457 if (!path)
458 return rimage_load (PKGDATADIR "/black.xpm", width, height);
459 else
460 {
461 RImage *image;
462
463 image = RLoadImage (rc, path, 0);
464 if (!image || !image->width || !image->height)
465 return rimage_load (PKGDATADIR "/black.xpm", width, height);
466 if (height > 0 || width > 0) /* enforce scaling */
467 {
468 if (height <= 0)
469 height = image->height;
470 if (width <= 0)
471 width = image->width;
472
473 if (streq (filename, PKGDATADIR "/black.xpm"))
474 {
475 RImage *scaled = RScaleImage (image, width, height);
476 RReleaseImage (image);
477 image = scaled;
478 }
479 else if (image->width > (unsigned) width
480 || image->height > (unsigned) height)
481 {
482 RImage *scaled;
483
484 if (height * image->width > width * image->height)
485 height = width * image->height / image->width;
486 else
487 width = height * image->width / image->height;
488
489 scaled = RScaleImage (image, max (width, 22), max (height, 22));
490 RReleaseImage (image);
491 image = scaled;
492 }
493 }
494 Free (path);
495 return image;
496 }
497 }
498
499 static GtkWidget *
rimage_2_preview(RImage * image,GtkWidget * preview,bool_t bevel)500 rimage_2_preview (RImage *image, GtkWidget *preview, bool_t bevel)
501 {
502 assert (image && image->width && image->height);
503
504 #ifdef HAVE_WRASTER_0_20
505 {
506 guchar *row;
507 unsigned x, y;
508 unsigned x0, y0, width, height;
509 RColor *bg = get_background_color ();
510 unsigned char *ptr = image->data;
511
512 if (bevel)
513 RBevelImage (image, RBEV_RAISED2);
514 if (!preview)
515 {
516 preview = gtk_preview_new (GTK_PREVIEW_COLOR);
517 gtk_preview_size (GTK_PREVIEW (preview), image->width, image->height);
518 width = image->width;
519 height = image->height;
520 x0 = y0 = 0;
521 }
522 else
523 {
524 width = GTK_WIDGET (preview)->requisition.width;
525 height = GTK_WIDGET (preview)->requisition.height;
526
527 assert (image->width <= width && image->height <= height);
528
529 x0 = (width - image->width) / 2;
530 y0 = (height - image->height) / 2;
531 }
532
533 row = Calloc (width * 3, sizeof (guchar));
534 {
535 guchar *pixel = row;
536
537 for (x = 0; x < width; x++)
538 {
539 *pixel++ = bg->red;
540 *pixel++ = bg->green;
541 *pixel++ = bg->blue;
542 }
543 }
544 for (y = 0; y < height; y++)
545 gtk_preview_draw_row (GTK_PREVIEW (preview), row, 0, y, width);
546
547 for (y = 0; y < image->height; y++)
548 {
549 guchar *pixel = row;
550
551 for (x = 0; x < image->width; x++)
552 if (image->format == RRGBAFormat)
553 {
554 unsigned int r = *ptr++;
555 unsigned int g = *ptr++;
556 unsigned int b = *ptr++;
557 unsigned int a = *ptr++;
558 unsigned int na = 255 - a;
559
560 *pixel++ = (bg->red * na + r * a) / 256;
561 *pixel++ = (bg->green * na + g * a) / 256;
562 *pixel++ = (bg->blue * na + b * a) / 256;
563 }
564 else
565 {
566 *pixel++ = *ptr++;
567 *pixel++ = *ptr++;
568 *pixel++ = *ptr++;
569 }
570
571 gtk_preview_draw_row (GTK_PREVIEW (preview), row, x0, y0 + y,
572 image->width);
573 }
574 Free (row);
575 gtk_widget_draw (preview, NULL);
576 return preview;
577 }
578 #else /* old wraster of wmaker < 0.62.0 */
579 {
580 guchar *row;
581 unsigned x, y;
582 unsigned char *r, *g, *b, *a;
583 unsigned x0, y0, width, height;
584 RColor *bg = get_background_color ();
585
586 r = image->data [0];
587 g = image->data [1];
588 b = image->data [2];
589 a = image->data [3];
590
591 if (bevel)
592 RBevelImage (image, RBEV_RAISED2);
593 if (!preview)
594 {
595 preview = gtk_preview_new (GTK_PREVIEW_COLOR);
596 gtk_preview_size (GTK_PREVIEW (preview), image->width, image->height);
597 width = image->width;
598 height = image->height;
599 x0 = y0 = 0;
600 }
601 else
602 {
603 width = GTK_WIDGET (preview)->requisition.width;
604 height = GTK_WIDGET (preview)->requisition.height;
605
606 assert (image->width <= width && image->height <= height);
607
608 x0 = (width - image->width) / 2;
609 y0 = (height - image->height) / 2;
610 }
611
612 row = Calloc (width * 3, sizeof (guchar));
613 {
614 guchar *pixel = row;
615
616 for (x = 0; x < width; x++)
617 {
618 *pixel++ = bg->red;
619 *pixel++ = bg->green;
620 *pixel++ = bg->blue;
621 }
622 }
623 for (y = 0; y < height; y++)
624 gtk_preview_draw_row (GTK_PREVIEW (preview), row, 0, y, width);
625
626 for (y = 0; y < image->height; y++)
627 {
628 guchar *pixel = row;
629
630 for (x = 0; x < image->width; x++)
631 if (!a || *a++)
632 {
633 *pixel++ = *r++;
634 *pixel++ = *g++;
635 *pixel++ = *b++;
636 }
637 else
638 {
639 *pixel++ = bg->red;
640 *pixel++ = bg->green;
641 *pixel++ = bg->blue;
642 r++;
643 g++;
644 b++;
645 }
646
647 gtk_preview_draw_row (GTK_PREVIEW (preview), row, x0, y0 + y,
648 image->width);
649 }
650 Free (row);
651 gtk_widget_draw (preview, NULL);
652 return preview;
653 }
654 #endif
655 }
656
657 static RColor *
get_background_color(void)658 get_background_color (void)
659 {
660 static RColor *background = NULL;
661
662 if (!background)
663 {
664 background = Calloc (1, sizeof (RColor));
665
666 if (main_window && main_window->style)
667 {
668 background->red
669 = main_window->style->bg [GTK_STATE_NORMAL].red >> 8;
670 background->green
671 = main_window->style->bg [GTK_STATE_NORMAL].green >> 8;
672 background->blue
673 = main_window->style->bg [GTK_STATE_NORMAL].blue >> 8;
674 }
675 else
676 {
677 background->red = 0xa8;
678 background->green = 0xa8;
679 background->blue = 0xa8;
680 }
681 }
682 return background;
683 }
684
685 #endif /* defined(PREVIEWS) && !defined(CONVERT) */
686