chiark / gitweb /
Imported Upstream version 1.0.0
[e16] / src / iclass.c
1 /*
2  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3  * Copyright (C) 2004-2009 Kim Woelders
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to
7  * deal in the Software without restriction, including without limitation the
8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9  * sell copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies of the Software, its documentation and marketing & publicity
14  * materials, and acknowledgment shall be given in the documentation, materials
15  * and software packages that this Software was used.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include "E.h"
25 #include "backgrounds.h"
26 #include "conf.h"
27 #include "desktops.h"
28 #include "e16-ecore_list.h"
29 #include "eimage.h"
30 #include "emodule.h"
31 #include "iclass.h"
32 #include "tclass.h"
33 #include "xwin.h"
34
35 #define ENABLE_DESTROY 0        /* Broken */
36
37 struct _imagestate {
38    char               *im_file;
39    char               *real_file;
40    char                got_colors;
41    char                unloadable;
42    char                transparent;
43    char                pixmapfillstyle;
44    char                bevelstyle;
45    char                rotate;
46    EImage             *im;
47    EImageBorder       *border;
48    EColor              bg, hi, lo, hihi, lolo;
49 };
50
51 typedef struct {
52    ImageState         *normal;
53    ImageState         *hilited;
54    ImageState         *clicked;
55    ImageState         *disabled;
56 } ImageStateArray;
57
58 struct _imageclass {
59    char               *name;
60    ImageStateArray     norm, active, sticky, sticky_active;
61    EImageBorder        padding;
62    unsigned int        ref_count;
63 };
64
65 static Ecore_List  *iclass_list = NULL;
66
67 static ImageClass  *ImageclassGetFallback(void);
68
69 #ifdef ENABLE_THEME_TRANSPARENCY
70
71 static EImageColorModifier *icm = NULL;
72 static unsigned char gray[256];
73 static unsigned char alpha[256];
74
75 static int          prev_alpha = -1;
76
77 int
78 TransparencyEnabled(void)
79 {
80    return Conf.trans.alpha;
81 }
82
83 int
84 TransparencyUpdateNeeded(void)
85 {
86    return Conf.trans.alpha || prev_alpha;
87 }
88
89 static void
90 TransparencyMakeColorModifier(void)
91 {
92    int                 i;
93
94    for (i = 0; i < 256; i++)
95      {
96         gray[i] = i;
97         alpha[i] = 255 - Conf.trans.alpha;
98      }
99
100    if (icm == NULL)
101       icm = EImageColorModifierCreate();
102    EImageColorModifierSetTables(icm, gray, gray, gray, alpha);
103 }
104
105 void
106 TransparencySet(int transparency)
107 {
108    int                 changed;
109
110    if (transparency < 0)
111       transparency = 0;
112    else if (transparency > 255)
113       transparency = 255;
114
115    /*  This will render the initial startup stuff correctly since !changed  */
116    if (prev_alpha == -1)
117      {
118         prev_alpha = Conf.trans.alpha = transparency;
119         changed = -1;
120      }
121    else
122      {
123         changed = Conf.trans.alpha != transparency;
124         prev_alpha = Conf.trans.alpha;
125         Conf.trans.alpha = transparency;
126      }
127
128    if (!changed)
129       return;
130
131    /* Generate the color modifier tables */
132    TransparencyMakeColorModifier();
133
134    if (changed < 0)
135       return;
136
137    if (prev_alpha == 0)
138      {
139         /* Hack to get tiled backgrounds regenerated at full size */
140         BackgroundsInvalidate(1);
141      }
142    ModulesSignal(ESIGNAL_THEME_TRANS_CHANGE, NULL);
143 }
144
145 #endif /* ENABLE_THEME_TRANSPARENCY */
146
147 EImage             *
148 ThemeImageLoad(const char *file)
149 {
150    EImage             *im;
151    char               *f;
152
153    if (!file)
154       return NULL;
155
156    if (file[0] == '/')
157      {
158         im = EImageLoad(file);
159         return im;
160      }
161
162    f = ThemeFileFind(file);
163    if (f)
164      {
165         im = EImageLoad(f);
166         Efree(f);
167         return im;
168      }
169
170    return NULL;
171 }
172
173 static void
174 ImagestateColorsSetGray(ImageState * is,
175                         unsigned int hihi, unsigned int hi,
176                         unsigned int bg, unsigned int lo, unsigned int lolo)
177 {
178    SET_COLOR(&(is->hihi), hihi, hihi, hihi);
179    SET_COLOR(&(is->hi), hi, hi, hi);
180    SET_COLOR(&(is->bg), bg, bg, bg);
181    SET_COLOR(&(is->lo), lo, lo, lo);
182    SET_COLOR(&(is->lolo), lolo, lolo, lolo);
183 }
184
185 static ImageState  *
186 ImagestateCreate(const char *file)
187 {
188    ImageState         *is;
189
190    is = ECALLOC(ImageState, 1);
191    if (!is)
192       return NULL;
193
194    is->pixmapfillstyle = FILL_STRETCH;
195    ImagestateColorsSetGray(is, 255, 200, 160, 120, 64);
196    is->bevelstyle = BEVEL_NONE;
197    is->im_file = Estrdup(file);
198
199    return is;
200 }
201
202 #if ENABLE_DESTROY
203 static void
204 ImagestateDestroy(ImageState * is)
205 {
206    if (!is)
207       return;
208
209    Efree(is->im_file);
210    Efree(is->real_file);
211
212    if (is->im)
213       EImageFree(is->im);
214
215    Efree(is->border);
216
217    Efree(is);
218 }
219
220 static void
221 FreeImageStateArray(ImageStateArray * isa)
222 {
223    ImagestateDestroy(isa->normal);
224    ImagestateDestroy(isa->hilited);
225    ImagestateDestroy(isa->clicked);
226    ImagestateDestroy(isa->disabled);
227 }
228 #endif /* ENABLE_DESTROY */
229
230 static void
231 ImagestateColorsAlloc(ImageState * is)
232 {
233    if (!is || is->got_colors)
234       return;
235
236    EAllocColor(WinGetCmap(VROOT), &is->bg);
237    EAllocColor(WinGetCmap(VROOT), &is->hi);
238    EAllocColor(WinGetCmap(VROOT), &is->lo);
239    EAllocColor(WinGetCmap(VROOT), &is->hihi);
240    EAllocColor(WinGetCmap(VROOT), &is->lolo);
241
242    is->got_colors = 1;
243 }
244
245 static void
246 ImagestateRealize(ImageState * is)
247 {
248    if (!is)
249       return;
250    if (is->im)                  /* Image is already loaded */
251       return;
252
253    if (!is->real_file)
254      {
255         if (!is->im_file)
256            return;              /* No file - quit */
257         /* not loaded, load and setup */
258         is->real_file = ThemeFileFind(is->im_file);
259      }
260    if (is->real_file)
261      {
262         is->im = EImageLoad(is->real_file);
263         if (is->im && is->rotate)
264            EImageOrientate(is->im, is->rotate);
265      }
266    if (!is->im)
267      {
268 #define S(s) ((s) ? (s) : "(null)")
269         Eprintf
270            ("ImagestateRealize: Hmmm... is->im is NULL (im_file=%s real_file=%s)\n",
271             S(is->im_file), S(is->real_file));
272         Efree(is->real_file);
273         is->real_file = NULL;
274         return;
275      }
276
277    Efree(is->im_file);          /* We no longer need the file */
278    is->im_file = NULL;
279
280    EImageCheckAlpha(is->im);
281
282    if (is->border)
283       EImageSetBorder(is->im, is->border);
284
285 #if 0                           /* To be implemented? */
286    if (is->colmod)
287      {
288         Imlib_set_image_red_curve(pImlib_Context, is->im, is->colmod->red.map);
289         Imlib_set_image_green_curve(pImlib_Context, is->im,
290                                     is->colmod->green.map);
291         Imlib_set_image_blue_curve(pImlib_Context, is->im,
292                                    is->colmod->blue.map);
293      }
294 #endif
295 }
296
297 static ImageClass  *
298 ImageclassCreate(const char *name)
299 {
300    ImageClass         *ic;
301
302    ic = ECALLOC(ImageClass, 1);
303    if (!ic)
304       return NULL;
305
306    if (!iclass_list)
307       iclass_list = ecore_list_new();
308    ecore_list_prepend(iclass_list, ic);
309
310    ic->name = Estrdup(name);
311    ic->norm.normal = ic->norm.hilited = ic->norm.clicked = ic->norm.disabled =
312       NULL;
313    ic->active.normal = ic->active.hilited = ic->active.clicked =
314       ic->active.disabled = NULL;
315    ic->sticky.normal = ic->sticky.hilited = ic->sticky.clicked =
316       ic->sticky.disabled = NULL;
317    ic->sticky_active.normal = ic->sticky_active.hilited =
318       ic->sticky_active.clicked = ic->sticky_active.disabled = NULL;
319    ic->padding.left = 0;
320    ic->padding.right = 0;
321    ic->padding.top = 0;
322    ic->padding.bottom = 0;
323    ic->ref_count = 0;
324
325    return ic;
326 }
327
328 #if ENABLE_DESTROY
329 static void
330 ImageclassDestroy(ImageClass * ic)
331 {
332    if (!ic)
333       return;
334
335    if (ic->ref_count > 0)
336      {
337         DialogOK("ImageClass Error!", _("%u references remain\n"),
338                  ic->ref_count);
339         return;
340      }
341
342    ecore_list_node_remove(iclass_list, ic);
343
344    Efree(ic->name);
345
346    FreeImageStateArray(&(ic->norm));
347    FreeImageStateArray(&(ic->active));
348    FreeImageStateArray(&(ic->sticky));
349    FreeImageStateArray(&(ic->sticky_active));
350
351    Efree(ic);
352 }
353 #endif /* ENABLE_DESTROY */
354
355 ImageClass         *
356 ImageclassAlloc(const char *name, int fallback)
357 {
358    ImageClass         *ic;
359
360    if (!name || !name[0])
361       return NULL;
362
363    ic = ImageclassFind(name, fallback);
364    if (ic)
365       ic->ref_count++;
366
367    return ic;
368 }
369
370 void
371 ImageclassFree(ImageClass * ic)
372 {
373    if (ic)
374       ic->ref_count--;
375 }
376
377 const char         *
378 ImageclassGetName(ImageClass * ic)
379 {
380    return (ic) ? ic->name : NULL;
381 }
382
383 EImageBorder       *
384 ImageclassGetPadding(ImageClass * ic)
385 {
386    return (ic) ? &(ic->padding) : NULL;
387 }
388
389 static int
390 _ImageclassMatchName(const void *data, const void *match)
391 {
392    return strcmp(((const ImageClass *)data)->name, (const char *)match);
393 }
394
395 ImageClass         *
396 ImageclassFind(const char *name, int fallback)
397 {
398    ImageClass         *ic = NULL;
399
400    if (name)
401       ic = (ImageClass *) ecore_list_find(iclass_list, _ImageclassMatchName,
402                                           name);
403    if (ic || !fallback)
404       return ic;
405
406 #if 0
407    Eprintf("%s: Get fallback (%s)\n", __func__, name);
408 #endif
409    return ImageclassGetFallback();
410 }
411
412 #define ISTATE_SET_STATE(which, fallback) \
413    if (!ic->which) ic->which = ic->fallback;
414
415 static void
416 ImageclassPopulate(ImageClass * ic)
417 {
418    if (!ic)
419       return;
420
421    if (!ic->norm.normal)
422       return;
423
424    ISTATE_SET_STATE(norm.hilited, norm.normal);
425    ISTATE_SET_STATE(norm.clicked, norm.normal);
426    ISTATE_SET_STATE(norm.disabled, norm.normal);
427
428    ISTATE_SET_STATE(active.normal, norm.normal);
429    ISTATE_SET_STATE(active.hilited, active.normal);
430    ISTATE_SET_STATE(active.clicked, active.normal);
431    ISTATE_SET_STATE(active.disabled, active.normal);
432
433    ISTATE_SET_STATE(sticky.normal, norm.normal);
434    ISTATE_SET_STATE(sticky.hilited, sticky.normal);
435    ISTATE_SET_STATE(sticky.clicked, sticky.normal);
436    ISTATE_SET_STATE(sticky.disabled, sticky.normal);
437
438    ISTATE_SET_STATE(sticky_active.normal, norm.normal);
439    ISTATE_SET_STATE(sticky_active.hilited, sticky_active.normal);
440    ISTATE_SET_STATE(sticky_active.clicked, sticky_active.normal);
441    ISTATE_SET_STATE(sticky_active.disabled, sticky_active.normal);
442 }
443
444 int
445 ImageclassConfigLoad(FILE * fs)
446 {
447    int                 err = 0;
448    char                s[FILEPATH_LEN_MAX];
449    char                s2[FILEPATH_LEN_MAX];
450    char               *p2;
451    int                 i1;
452    ImageClass         *ic = NULL;
453    ImageState         *is = NULL;
454    int                 l, r, t, b;
455
456    while (GetLine(s, sizeof(s), fs))
457      {
458         i1 = ConfigParseline1(s, s2, &p2, NULL);
459
460         /* ic not needed */
461         switch (i1)
462           {
463           case CONFIG_CLOSE:
464              ImageclassPopulate(ic);
465              goto done;
466           case CONFIG_COLORMOD:
467           case ICLASS_COLORMOD:
468              continue;
469           case CONFIG_CLASSNAME:
470           case ICLASS_NAME:
471              if (ImageclassFind(s2, 0))
472                {
473                   SkipTillEnd(fs);
474                   goto done;
475                }
476              ic = ImageclassCreate(s2);
477              continue;
478           }
479
480         /* ic needed */
481         if (!ic)
482            break;
483
484         switch (i1)
485           {
486           case CONFIG_INHERIT:
487              {
488                 ImageClass         *ic2;
489
490                 ic2 = ImageclassFind(s2, 0);
491                 if (!ic2)
492                    goto not_ok;
493                 ic->norm = ic2->norm;
494                 ic->active = ic2->active;
495                 ic->sticky = ic2->sticky;
496                 ic->sticky_active = ic2->sticky_active;
497                 ic->padding = ic2->padding;
498              }
499              break;
500           case ICLASS_PADDING:
501              l = r = t = b = 0;
502              sscanf(p2, "%i %i %i %i", &l, &r, &t, &b);
503              ic->padding.left = l;
504              ic->padding.right = r;
505              ic->padding.top = t;
506              ic->padding.bottom = b;
507              continue;
508           case CONFIG_DESKTOP:
509              /* don't ask... --mandrake */
510           case ICLASS_NORMAL:
511              ic->norm.normal = is = ImagestateCreate(s2);
512              continue;
513           case ICLASS_CLICKED:
514              ic->norm.clicked = is = ImagestateCreate(s2);
515              continue;
516           case ICLASS_HILITED:
517              ic->norm.hilited = is = ImagestateCreate(s2);
518              continue;
519           case ICLASS_DISABLED:
520              ic->norm.disabled = is = ImagestateCreate(s2);
521              continue;
522           case ICLASS_STICKY_NORMAL:
523              ic->sticky.normal = is = ImagestateCreate(s2);
524              continue;
525           case ICLASS_STICKY_CLICKED:
526              ic->sticky.clicked = is = ImagestateCreate(s2);
527              continue;
528           case ICLASS_STICKY_HILITED:
529              ic->sticky.hilited = is = ImagestateCreate(s2);
530              continue;
531           case ICLASS_STICKY_DISABLED:
532              ic->sticky.disabled = is = ImagestateCreate(s2);
533              continue;
534           case ICLASS_ACTIVE_NORMAL:
535              ic->active.normal = is = ImagestateCreate(s2);
536              continue;
537           case ICLASS_ACTIVE_CLICKED:
538              ic->active.clicked = is = ImagestateCreate(s2);
539              continue;
540           case ICLASS_ACTIVE_HILITED:
541              ic->active.hilited = is = ImagestateCreate(s2);
542              continue;
543           case ICLASS_ACTIVE_DISABLED:
544              ic->active.disabled = is = ImagestateCreate(s2);
545              continue;
546           case ICLASS_STICKY_ACTIVE_NORMAL:
547              ic->sticky_active.normal = is = ImagestateCreate(s2);
548              continue;
549           case ICLASS_STICKY_ACTIVE_CLICKED:
550              ic->sticky_active.clicked = is = ImagestateCreate(s2);
551              continue;
552           case ICLASS_STICKY_ACTIVE_HILITED:
553              ic->sticky_active.hilited = is = ImagestateCreate(s2);
554              continue;
555           case ICLASS_STICKY_ACTIVE_DISABLED:
556              ic->sticky_active.disabled = is = ImagestateCreate(s2);
557              continue;
558           }
559
560         /* is needed */
561         if (!is)
562            break;
563
564         switch (i1)
565           {
566           case ICLASS_LRTB:
567              is->border = EMALLOC(EImageBorder, 1);
568              l = r = t = b = 0;
569              sscanf(p2, "%i %i %i %i", &l, &r, &t, &b);
570              is->border->left = l;
571              is->border->right = r;
572              is->border->top = t;
573              is->border->bottom = b;
574              /* Hmmm... imlib2 works better with this */
575              is->border->right++;
576              is->border->bottom++;
577              continue;
578           case ICLASS_FILLRULE:
579              is->pixmapfillstyle = atoi(s2);
580              continue;
581           case ICLASS_TRANSPARENT:
582              is->transparent = strtoul(s2, NULL, 0);
583              continue;
584           case ICLASS_ROTATE:   /* flip goes here too */
585              is->rotate = strtoul(s2, NULL, 0);
586              continue;
587           case ICLASS_BEVEL:
588 #define _R(x) (((x) >> 16) & 0xff)
589 #define _G(x) (((x) >>  8) & 0xff)
590 #define _B(x) (((x)      ) & 0xff)
591 #define INT_TO_COLOR(xc, rgb) \
592     do { (&(xc))->red = _R(rgb); (&(xc))->green = _G(rgb); (&(xc))->blue = _B(rgb); } while(0)
593              {
594                 int                 n, bevel, hihi, hi, bg, lo, lolo;
595
596                 n = sscanf(p2, "%i %i %i %i %i %i",
597                            &bevel, &hihi, &hi, &bg, &lo, &lolo);
598                 if (n < 6)
599                    goto not_ok;
600                 is->bevelstyle = bevel;
601                 INT_TO_COLOR(is->hihi, hihi);
602                 INT_TO_COLOR(is->hi, hi);
603                 INT_TO_COLOR(is->bg, bg);
604                 INT_TO_COLOR(is->lo, lo);
605                 INT_TO_COLOR(is->lolo, lolo);
606              }
607              break;
608           default:
609              goto not_ok;
610           }
611      }
612  not_ok:
613    err = -1;
614
615  done:
616    return err;
617 }
618
619 ImageClass         *
620 ImageclassCreateSimple(const char *name, const char *image)
621 {
622    ImageClass         *ic;
623
624    ic = ImageclassCreate(name);
625    if (!ic)
626       return NULL;
627
628    ic->norm.normal = ImagestateCreate(image);
629    ic->norm.normal->unloadable = 1;
630    ImageclassPopulate(ic);
631
632    ImagestateRealize(ic->norm.normal);
633
634    return ic;
635 }
636
637 #ifdef ENABLE_THEME_TRANSPARENCY
638 int
639 ImageclassIsTransparent(ImageClass * ic)
640 {
641    return ic && ic->norm.normal && ic->norm.normal->transparent;
642 }
643 #endif
644
645 static ImageState  *
646 ImageclassGetImageState1(ImageStateArray * pisa, int state)
647 {
648    ImageState         *is;
649
650    switch (state)
651      {
652      case STATE_NORMAL:
653         is = pisa->normal;
654         break;
655      case STATE_HILITED:
656         is = pisa->hilited;
657         break;
658      case STATE_CLICKED:
659         is = pisa->clicked;
660         break;
661      case STATE_DISABLED:
662         is = pisa->disabled;
663         break;
664      default:
665         is = NULL;
666         break;
667      }
668
669    return is;
670 }
671
672 ImageState         *
673 ImageclassGetImageState(ImageClass * ic, int state, int active, int sticky)
674 {
675    ImageState         *is;
676
677    if (active)
678      {
679         if (sticky)
680            is = ImageclassGetImageState1(&ic->sticky_active, state);
681         else
682            is = ImageclassGetImageState1(&ic->active, state);
683      }
684    else
685      {
686         if (sticky)
687            is = ImageclassGetImageState1(&ic->sticky, state);
688         else
689            is = ImageclassGetImageState1(&ic->norm, state);
690      }
691
692    return is;
693 }
694
695 EImage             *
696 ImageclassGetImage(ImageClass * ic, int active, int sticky, int state)
697 {
698    EImage             *im;
699    ImageState         *is;
700
701    if (!ic)
702       return NULL;
703
704    is = ImageclassGetImageState(ic, state, active, sticky);
705    if (!is)
706       return NULL;
707
708    if (is->im == NULL)
709       ImagestateRealize(is);
710
711    im = is->im;
712    if (!im)
713       return NULL;
714    is->im = NULL;
715
716    return im;
717 }
718
719 #ifdef ENABLE_TRANSPARENCY
720 static int
721 pt_type_to_flags(int image_type)
722 {
723    int                 flags;
724
725    if (Conf.trans.alpha == 0)
726       return ICLASS_ATTR_OPAQUE;
727
728    switch (image_type)
729      {
730      default:
731      case ST_SOLID:
732      case ST_BUTTON:
733         flags = ICLASS_ATTR_OPAQUE;
734         break;
735      case ST_BORDER:
736         flags = Conf.trans.border;
737         break;
738      case ST_WIDGET:
739         flags = Conf.trans.widget;
740         break;
741      case ST_ICONBOX:
742         flags = Conf.trans.iconbox;
743         break;
744      case ST_MENU:
745         flags = Conf.trans.menu;
746         break;
747      case ST_MENU_ITEM:
748         flags = Conf.trans.menu_item;
749         break;
750      case ST_TOOLTIP:
751         flags = Conf.trans.tooltip;
752         break;
753      case ST_DIALOG:
754         flags = Conf.trans.dialog;
755         break;
756      case ST_HILIGHT:
757         flags = Conf.trans.hilight;
758         break;
759      case ST_PAGER:
760         flags = Conf.trans.pager;
761         break;
762      case ST_WARPLIST:
763         flags = Conf.trans.warplist;
764         break;
765      }
766    if (flags != ICLASS_ATTR_OPAQUE)
767       flags |= ICLASS_ATTR_USE_CM;
768
769    return flags;
770 }
771
772 static EImage      *
773 pt_get_bg_image(Win win, int w, int h, int use_root)
774 {
775    EImage             *ii = NULL;
776    Win                 cr;
777    Drawable            bg;
778    int                 xx, yy;
779
780    bg = DeskGetBackgroundPixmap(DesksGetCurrent());
781    if (use_root || bg == None)
782      {
783         cr = VROOT;
784         bg = WinGetXwin(VROOT);
785      }
786    else
787      {
788         cr = EoGetWin(DesksGetCurrent());
789      }
790    ETranslateCoordinates(win, cr, 0, 0, &xx, &yy, NULL);
791 #if 0
792    Eprintf("pt_get_bg_image %#lx %d %d %d %d\n", win, xx, yy, w, h);
793 #endif
794    if (xx < WinGetW(VROOT) && yy < WinGetH(VROOT) && xx + w >= 0 && yy + h >= 0)
795      {
796         /* Create the background base image */
797         ii = EImageGrabDrawable(bg, None, xx, yy, w, h, !EServerIsGrabbed());
798      }
799
800    return ii;
801 }
802
803 #endif
804
805 EImage             *
806 ImageclassGetImageBlended(ImageClass * ic, Win win, int w, int h, int active,
807                           int sticky, int state, int image_type)
808 {
809    ImageState         *is;
810    EImage             *im, *bg;
811    int                 flags;
812
813    if (!ic)
814       return NULL;
815
816    is = ImageclassGetImageState(ic, state, active, sticky);
817    if (!is)
818       return NULL;
819
820    if (is->im == NULL)
821       ImagestateRealize(is);
822    im = is->im;
823    if (!im)
824       return NULL;
825
826 #ifdef ENABLE_TRANSPARENCY
827    flags = pt_type_to_flags(image_type);
828    if (flags != ICLASS_ATTR_OPAQUE)
829      {
830         bg = pt_get_bg_image(win, w, h, flags & ICLASS_ATTR_GLASS);
831         if (bg)
832           {
833              /* FIXME - Tiling not implemented */
834              EImageBlendCM(bg, im, (flags & ICLASS_ATTR_USE_CM) ? icm : NULL);
835              goto done;
836           }
837      }
838 #else
839    flags = image_type;
840    win = None;
841 #endif
842
843    if (is->pixmapfillstyle == FILL_STRETCH)
844      {
845         bg = EImageCreateScaled(im, 0, 0, 0, 0, w, h);
846      }
847    else
848      {
849         int                 iw, ih, tw, th;
850
851         EImageGetSize(im, &iw, &ih);
852
853         tw = w;
854         th = h;
855         if (is->pixmapfillstyle & FILL_TILE_H)
856            tw = iw;
857         if (is->pixmapfillstyle & FILL_TILE_V)
858            th = ih;
859
860         bg = EImageCreate(w, h);
861         EImageTile(bg, im, 0, tw, th, 0, 0, w, h, 0, 0);
862      }
863
864 #ifdef ENABLE_TRANSPARENCY
865  done:
866 #endif
867    if ((is->unloadable) || (Conf.memory_paranoia))
868      {
869         EImageFree(is->im);
870         is->im = NULL;
871      }
872
873    return bg;
874 }
875
876 static void
877 ImagestateMakePmapMask(ImageState * is, Win win, PmapMask * pmm,
878                        int pmapflags, int w, int h, int image_type)
879 {
880 #ifdef ENABLE_TRANSPARENCY
881    EImage             *ii = NULL;
882    int                 flags;
883    Pixmap              pmap, mask;
884
885    flags = pt_type_to_flags(image_type);
886
887    /*
888     * is->transparent flags:
889     *   0x01: Use desktop background pixmap as base
890     *   0x02: Use root window as base (use only for transients, if at all)
891     *   0x04: Don't apply image mask to result
892     */
893    if (is->transparent && EImageHasAlpha(is->im))
894       flags = is->transparent;
895
896    if (flags != ICLASS_ATTR_OPAQUE)
897      {
898         ii = pt_get_bg_image(win, w, h, flags & ICLASS_ATTR_GLASS);
899      }
900    else
901      {
902 #if 0
903         Eprintf("ImagestateMakePmapMask %#lx %d %d\n", win, w, h);
904 #endif
905      }
906
907    if (ii)
908      {
909         EImageBlendCM(ii, is->im, (flags & ICLASS_ATTR_USE_CM) ? icm : NULL);
910
911         pmm->type = 0;
912         pmm->pmap = pmap = ECreatePixmap(win, w, h, 0);
913         pmm->mask = None;
914         pmm->w = w;
915         pmm->h = h;
916         EImageRenderOnDrawable(ii, win, pmap, 0, 0, 0, w, h);
917
918         if ((pmapflags & IC_FLAG_MAKE_MASK) && !(flags & ICLASS_ATTR_NO_CLIP))
919           {
920              if (EImageHasAlpha(is->im))
921                {
922                   /* Make the scaled clip mask to be used */
923                   EImageRenderPixmaps(is->im, win, EIMAGE_ANTI_ALIAS, &pmap,
924                                       &mask, w, h);
925
926                   /* Replace the mask with the correct one */
927                   pmm->mask = EXCreatePixmapCopy(mask, w, h, 1);
928
929                   EImagePixmapsFree(pmap, mask);
930                }
931           }
932         EImageDecache(ii);
933      }
934    else
935 #else
936    pmapflags = 0;
937    image_type = 0;
938 #endif /* ENABLE_TRANSPARENCY */
939    if (is->pixmapfillstyle == FILL_STRETCH)
940      {
941         pmm->type = 1;
942         pmm->pmap = pmm->mask = None;
943         pmm->w = w;
944         pmm->h = h;
945         EImageRenderPixmaps(is->im, win, EIMAGE_ANTI_ALIAS, &pmm->pmap,
946                             &pmm->mask, w, h);
947      }
948    else
949      {
950         int                 ww, hh, cw, ch, pw, ph;
951
952         EImageGetSize(is->im, &ww, &hh);
953
954         pw = w;
955         ph = h;
956         if (is->pixmapfillstyle & FILL_TILE_H)
957            pw = ww;
958         if (is->pixmapfillstyle & FILL_TILE_V)
959            ph = hh;
960         if (is->pixmapfillstyle & FILL_INT_TILE_H)
961           {
962              cw = w / ww;
963              if (cw * ww < w)
964                 cw++;
965              if (cw < 1)
966                 cw = 1;
967              pw = w / cw;
968           }
969         if (is->pixmapfillstyle & FILL_INT_TILE_V)
970           {
971              ch = h / hh;
972              if (ch * hh < h)
973                 ch++;
974              if (ch < 1)
975                 ch = 1;
976              ph = h / ch;
977           }
978         pmm->type = 1;
979         pmm->pmap = pmm->mask = None;
980         pmm->w = pw;
981         pmm->h = ph;
982         EImageRenderPixmaps(is->im, win, EIMAGE_ANTI_ALIAS, &pmm->pmap,
983                             &pmm->mask, pw, ph);
984      }
985 }
986
987 #define LINE(x1, y1, x2, y2) \
988    XDrawLine(disp, win, gc, x + (x1), y + (y1), x + (x2), y + (y2))
989 #define RECT(x, y, w, h) \
990         XDrawRectangle(disp, win, gc, x, y, w, h);
991
992 static void
993 ImagestateDrawBevel(ImageState * is, Drawable win, GC gc,
994                     int x, int y, int w, int h)
995 {
996    ImagestateColorsAlloc(is);
997
998    switch (is->bevelstyle)
999      {
1000      case BEVEL_AMIGA:
1001         XSetForeground(disp, gc, is->hihi.pixel);
1002         LINE(0, 0, w - 2, 0);
1003         LINE(0, 0, 0, h - 2);
1004         XSetForeground(disp, gc, is->lolo.pixel);
1005         LINE(1, h - 1, w - 1, h - 1);
1006         LINE(w - 1, 1, w - 1, h - 1);
1007         break;
1008      case BEVEL_MOTIF:
1009         XSetForeground(disp, gc, is->hi.pixel);
1010         LINE(0, 0, w - 1, 0);
1011         LINE(0, 0, 0, h - 1);
1012         LINE(1, 1, w - 2, 1);
1013         LINE(1, 1, 1, h - 2);
1014         XSetForeground(disp, gc, is->lo.pixel);
1015         LINE(0, h - 1, w - 1, h - 1);
1016         LINE(w - 1, 1, w - 1, h - 1);
1017         LINE(1, h - 2, w - 2, h - 2);
1018         LINE(w - 2, 2, w - 2, h - 2);
1019         break;
1020      case BEVEL_NEXT:
1021         XSetForeground(disp, gc, is->hihi.pixel);
1022         LINE(0, 0, w - 1, 0);
1023         LINE(0, 0, 0, h - 1);
1024         XSetForeground(disp, gc, is->hi.pixel);
1025         LINE(1, 1, w - 2, 1);
1026         LINE(1, 1, 1, h - 2);
1027         XSetForeground(disp, gc, is->lolo.pixel);
1028         LINE(1, h - 1, w - 1, h - 1);
1029         LINE(w - 1, 1, w - 1, h - 1);
1030         XSetForeground(disp, gc, is->lo.pixel);
1031         LINE(2, h - 2, w - 2, h - 2);
1032         LINE(w - 2, 2, w - 2, h - 2);
1033         break;
1034      case BEVEL_DOUBLE:
1035         XSetForeground(disp, gc, is->hi.pixel);
1036         LINE(0, 0, w - 2, 0);
1037         LINE(0, 0, 0, h - 2);
1038         XSetForeground(disp, gc, is->lo.pixel);
1039         LINE(1, 1, w - 3, 1);
1040         LINE(1, 1, 1, h - 3);
1041         XSetForeground(disp, gc, is->lo.pixel);
1042         LINE(1, h - 1, w - 1, h - 1);
1043         LINE(w - 1, 1, w - 1, h - 1);
1044         XSetForeground(disp, gc, is->hi.pixel);
1045         LINE(2, h - 2, w - 2, h - 2);
1046         LINE(w - 2, 2, w - 2, h - 2);
1047         break;
1048      case BEVEL_WIDEDOUBLE:
1049         XSetForeground(disp, gc, is->hihi.pixel);
1050         LINE(0, 0, w - 1, 0);
1051         LINE(0, 0, 0, h - 1);
1052         XSetForeground(disp, gc, is->hi.pixel);
1053         LINE(1, 1, w - 2, 1);
1054         LINE(1, 1, 1, h - 2);
1055         LINE(3, h - 4, w - 4, h - 4);
1056         LINE(w - 4, 3, w - 4, h - 4);
1057         XSetForeground(disp, gc, is->lolo.pixel);
1058         LINE(1, h - 1, w - 1, h - 1);
1059         LINE(w - 1, 1, w - 1, h - 1);
1060         XSetForeground(disp, gc, is->lo.pixel);
1061         LINE(2, h - 2, w - 2, h - 2);
1062         LINE(w - 2, 2, w - 2, h - 2);
1063         LINE(3, 3, w - 4, 3);
1064         LINE(3, 3, 3, h - 4);
1065         break;
1066      case BEVEL_THINPOINT:
1067         XSetForeground(disp, gc, is->hi.pixel);
1068         LINE(0, 0, w - 2, 0);
1069         LINE(0, 0, 0, h - 2);
1070         XSetForeground(disp, gc, is->lo.pixel);
1071         LINE(1, h - 1, w - 1, h - 1);
1072         LINE(w - 1, 1, w - 1, h - 1);
1073         XSetForeground(disp, gc, is->hihi.pixel);
1074         LINE(0, 0, 1, 0);
1075         LINE(0, 0, 0, 1);
1076         XSetForeground(disp, gc, is->lolo.pixel);
1077         LINE(w - 2, h - 1, w - 1, h - 1);
1078         LINE(w - 1, h - 2, w - 1, h - 1);
1079         break;
1080      case BEVEL_THICKPOINT:
1081         XSetForeground(disp, gc, is->hi.pixel);
1082         RECT(x, y, w - 1, h - 1);
1083         break;
1084      default:
1085         break;
1086      }
1087 }
1088
1089 static void
1090 ImagestateDrawNoImg(ImageState * is, Drawable draw, int x, int y, int w, int h)
1091 {
1092    GC                  gc;
1093
1094    ImagestateColorsAlloc(is);
1095
1096    gc = EXCreateGC(draw, 0, NULL);
1097    XSetFillStyle(disp, gc, FillSolid);
1098    XSetForeground(disp, gc, is->bg.pixel);
1099    XFillRectangle(disp, draw, gc, x, y, w, h);
1100    if (is->bevelstyle != BEVEL_NONE)
1101       ImagestateDrawBevel(is, draw, gc, x, y, w, h);
1102    EXFreeGC(gc);
1103 }
1104
1105 void
1106 ITApply(Win win, ImageClass * ic, ImageState * is,
1107         int state, int active, int sticky, int image_type,
1108         TextClass * tc, TextState * ts, const char *text, int flags)
1109 {
1110    int                 w, h;
1111
1112    if (win == NULL || !ic)
1113       return;
1114
1115    w = WinGetW(win);
1116    h = WinGetH(win);
1117    if (w <= 0 || h <= 0)
1118       return;
1119
1120    if (!is)
1121       is = ImageclassGetImageState(ic, state, active, sticky);
1122    if (!is)
1123       return;
1124
1125    if (tc && text)
1126      {
1127         if (!ts)
1128            ts = TextclassGetTextState(tc, state, active, sticky);
1129      }
1130
1131    if (is->im == NULL)
1132       ImagestateRealize(is);
1133
1134    /* Imlib2 will not render pixmaps with dimensions > 8192 */
1135    if (is->im && w <= 8192 && h <= 8192)
1136      {
1137         PmapMask            pmm;
1138
1139         ImagestateMakePmapMask(is, win, &pmm, IC_FLAG_MAKE_MASK, w, h,
1140                                image_type);
1141
1142         if (pmm.pmap)
1143           {
1144              Pixmap              pmap = pmm.pmap;
1145
1146              if ((ts && text) || (is->bevelstyle != BEVEL_NONE))
1147                {
1148                   if (pmm.type != 0)
1149                     {
1150                        pmap = EGetWindowBackgroundPixmap(win);
1151                        EXCopyAreaTiled(pmm.pmap, None, pmap, 0, 0, w, h, 0, 0);
1152                     }
1153
1154                   if (is->bevelstyle != BEVEL_NONE)
1155                     {
1156                        GC                  gc;
1157
1158                        gc = EXCreateGC(WinGetXwin(win), 0, NULL);
1159                        Eprintf("%s: bevel=%d\n", __func__, is->bevelstyle);
1160                        ImagestateDrawBevel(is, pmap, gc, 0, 0, w, h);
1161                        EXFreeGC(gc);
1162                     }
1163
1164                   if (ts && text)
1165                      TextstateTextDraw(ts, win, pmap, text, 0, 0, w, h,
1166                                        &(ic->padding), 0,
1167                                        TextclassGetJustification(tc), flags);
1168                }
1169
1170              /* Set window pixmap */
1171              if (pmap == pmm.pmap)
1172                {
1173                   ESetWindowBackgroundPixmap(win, pmap);
1174                   EFreeWindowBackgroundPixmap(win);
1175                }
1176
1177              if (pmm.w == w && pmm.h == h)
1178                 EShapeSetMask(win, 0, 0, pmm.mask);
1179              else if (pmm.mask)
1180                 EShapeSetMaskTiled(win, 0, 0, pmm.mask, w, h);
1181           }
1182
1183         FreePmapMask(&pmm);
1184
1185         if ((is->unloadable) || (Conf.memory_paranoia))
1186           {
1187              EImageFree(is->im);
1188              is->im = NULL;
1189           }
1190      }
1191    else
1192      {
1193         ImagestateColorsAlloc(is);
1194
1195         if (is->bevelstyle == BEVEL_NONE && !text)
1196           {
1197              ESetWindowBackground(win, is->bg.pixel);
1198           }
1199         else
1200           {
1201              Pixmap              pmap;
1202
1203              pmap = EGetWindowBackgroundPixmap(win);
1204              ImagestateDrawNoImg(is, pmap, 0, 0, w, h);
1205              if (ts && text)
1206                 TextstateTextDraw(ts, win, pmap, text, 0, 0, w, h,
1207                                   &(ic->padding), 0,
1208                                   TextclassGetJustification(tc), flags);
1209           }
1210      }
1211    EClearWindow(win);
1212 }
1213
1214 void
1215 ImageclassApply(ImageClass * ic, Win win, int active, int sticky, int state,
1216                 int image_type)
1217 {
1218    ITApply(win, ic, NULL, state, active, sticky, image_type, NULL, NULL, NULL,
1219            0);
1220 }
1221
1222 static void
1223 PmapMaskTile(PmapMask * pmm, Win win, unsigned int w, unsigned int h)
1224 {
1225    Pixmap              pmap, mask;
1226
1227    pmap = ECreatePixmap(win, w, h, 0);
1228    if (pmap == None)
1229       return;
1230    EXCopyAreaTiled(pmm->pmap, None, pmap, 0, 0, w, h, 0, 0);
1231
1232    mask = None;
1233    if (pmm->mask != None)
1234       mask = ECreatePixmap(win, w, h, 1);
1235    if (mask != None)
1236       EXCopyAreaTiled(pmm->mask, None, mask, 0, 0, w, h, 0, 0);
1237
1238    FreePmapMask(pmm);
1239    pmm->type = 0;
1240    pmm->w = w;
1241    pmm->h = h;
1242    pmm->pmap = pmap;
1243    pmm->mask = mask;
1244 }
1245
1246 void
1247 ImageclassApplyCopy(ImageClass * ic, Win win, int w, int h,
1248                     int active, int sticky, int state,
1249                     PmapMask * pmm, int pmapflags, int image_type)
1250 {
1251    ImageState         *is;
1252
1253    if (pmm == NULL)
1254       return;
1255
1256    pmm->type = 0;
1257    pmm->pmap = pmm->mask = 0;
1258
1259    if ((!ic) || (!win) || (w <= 0) || (h <= 0))
1260       return;
1261
1262    is = ImageclassGetImageState(ic, state, active, sticky);
1263    if (!is)
1264       return;
1265
1266    if (is->im == NULL)
1267       ImagestateRealize(is);
1268
1269    /* Imlib2 will not render pixmaps with dimensions > 8192 */
1270    if (is->im && w <= 8192 && h <= 8192)
1271      {
1272         ImagestateMakePmapMask(is, win, pmm, pmapflags, w, h, image_type);
1273
1274         if ((pmapflags & IC_FLAG_FULL_SIZE) && pmm->pmap &&
1275             (pmm->w != w || pmm->h != h))
1276           {
1277              /* Create new full sized pixmaps and fill them with the */
1278              /* pmap and mask tiles                                  */
1279              PmapMaskTile(pmm, win, w, h);
1280           }
1281
1282         if ((is->unloadable) || (Conf.memory_paranoia))
1283           {
1284              EImageFree(is->im);
1285              is->im = NULL;
1286           }
1287      }
1288    else
1289      {
1290         if (pmm->pmap)
1291            Eprintf("ImageclassApplyCopy: Hmm... pmm->pmap already set\n");
1292
1293         pmm->type = 0;
1294         pmm->pmap = ECreatePixmap(win, w, h, 0);
1295         pmm->mask = 0;
1296
1297         ImagestateDrawNoImg(is, pmm->pmap, 0, 0, w, h);
1298         /* FIXME - No text */
1299      }
1300 }
1301
1302 void
1303 ImageclassApplySimple(ImageClass * ic, Win win, Drawable draw, int state,
1304                       int x, int y, int w, int h)
1305 {
1306    EImage             *im;
1307
1308    if (!ic)
1309       return;
1310
1311    im = ImageclassGetImage(ic, 0, 0, state);
1312    if (im)
1313      {
1314         EImageRenderOnDrawable(im, win, draw, 0, x, y, w, h);
1315         EImageFree(im);
1316      }
1317    else
1318      {
1319         ImageState         *is;
1320
1321         is = ImageclassGetImageState(ic, state, 0, 0);
1322         if (!is)
1323            return;
1324
1325         ImagestateDrawNoImg(is, draw, x, y, w, h);
1326      }
1327 }
1328
1329 static ImageClass  *
1330 ImageclassGetFallback(void)
1331 {
1332    ImageClass         *ic;
1333
1334    ic = ImageclassFind("__fb_ic", 0);
1335    if (ic)
1336       return ic;
1337
1338    /* Create fallback imageclass */
1339    ic = ImageclassCreate("__fb_ic");
1340    if (!ic)
1341       return ic;
1342
1343    ic->norm.normal = ImagestateCreate(NULL);
1344    ImagestateColorsSetGray(ic->norm.normal, 255, 255, 160, 0, 0);
1345    ic->norm.normal->bevelstyle = BEVEL_AMIGA;
1346
1347    ic->norm.hilited = ImagestateCreate(NULL);
1348    ImagestateColorsSetGray(ic->norm.hilited, 255, 255, 192, 0, 0);
1349    ic->norm.hilited->bevelstyle = BEVEL_AMIGA;
1350
1351    ic->norm.clicked = ImagestateCreate(NULL);
1352    ImagestateColorsSetGray(ic->norm.clicked, 0, 0, 192, 255, 255);
1353    ic->norm.clicked->bevelstyle = BEVEL_AMIGA;
1354
1355    ic->active.normal = ImagestateCreate(NULL);
1356    ImagestateColorsSetGray(ic->active.normal, 255, 255, 0, 0, 0);
1357    SET_COLOR(&(ic->active.normal->bg), 180, 140, 160);
1358    ic->active.normal->bevelstyle = BEVEL_AMIGA;
1359
1360    ic->active.hilited = ImagestateCreate(NULL);
1361    ImagestateColorsSetGray(ic->active.hilited, 255, 255, 0, 0, 0);
1362    SET_COLOR(&(ic->active.hilited->bg), 230, 190, 210);
1363    ic->active.hilited->bevelstyle = BEVEL_AMIGA;
1364
1365    ic->active.clicked = ImagestateCreate(NULL);
1366    ImagestateColorsSetGray(ic->active.clicked, 0, 0, 0, 255, 255);
1367    SET_COLOR(&(ic->active.clicked->bg), 230, 190, 210);
1368    ic->active.clicked->bevelstyle = BEVEL_AMIGA;
1369
1370    ic->padding.left = 4;
1371    ic->padding.right = 4;
1372    ic->padding.top = 4;
1373    ic->padding.bottom = 4;
1374
1375    ImageclassPopulate(ic);
1376
1377    return ic;
1378 }
1379
1380 ImageClass         *
1381 ImageclassGetBlack(void)
1382 {
1383    ImageClass         *ic;
1384
1385    ic = ImageclassFind("__BLACK", 0);
1386    if (ic)
1387       return ic;
1388
1389    /* Create all black image class for filler borders */
1390    ic = ImageclassCreate("__BLACK");
1391    if (!ic)
1392       return ic;
1393
1394    ic->norm.normal = ImagestateCreate(NULL);
1395    ImagestateColorsSetGray(ic->norm.normal, 0, 0, 0, 0, 0);
1396
1397    ImageclassPopulate(ic);
1398
1399    return ic;
1400 }
1401
1402 /*
1403  * Imageclass Module
1404  */
1405
1406 static void
1407 ImageclassIpc(const char *params)
1408 {
1409    char                param1[1024];
1410    char                param2[1024];
1411    int                 l;
1412    const char         *p;
1413    ImageClass         *ic;
1414
1415    if (!params)
1416      {
1417         IpcPrintf("Please specify...\n");
1418         return;
1419      }
1420
1421    p = params;
1422    l = 0;
1423    param1[0] = param2[0] = '\0';
1424    sscanf(p, "%1000s %1000s %n", param1, param2, &l);
1425    p += l;
1426
1427    if (!strncmp(param1, "list", 2))
1428      {
1429         ECORE_LIST_FOR_EACH(iclass_list, ic) IpcPrintf("%s\n", ic->name);
1430         return;
1431      }
1432
1433    if (!param1[0])
1434      {
1435         IpcPrintf("ImageClass not specified\n");
1436         return;
1437      }
1438
1439    if (!strcmp(param2, "create"))
1440      {
1441         /* Not implemented */
1442         return;
1443      }
1444    else if (!strcmp(param2, "free_pixmap"))
1445      {
1446         Pixmap              pmap;
1447
1448         pmap = (Pixmap) strtol(p, NULL, 0);
1449         EImagePixmapsFree(pmap, None);
1450         return;
1451      }
1452
1453    ic = ImageclassFind(param1, 0);
1454    if (!ic)
1455      {
1456         IpcPrintf("ImageClass not found: %s\n", param1);
1457         return;
1458      }
1459
1460    if (!strcmp(param2, "delete"))
1461      {
1462 #if ENABLE_DESTROY
1463         ImageclassDestroy(ic);
1464 #endif
1465      }
1466    else if (!strcmp(param2, "modify"))
1467      {
1468         /* Not implemented */
1469      }
1470    else if (!strcmp(param2, "get_padding"))
1471      {
1472         IpcPrintf("%i %i %i %i\n",
1473                   ic->padding.left, ic->padding.right,
1474                   ic->padding.top, ic->padding.bottom);
1475      }
1476    else if (!strcmp(param2, "get_image_size"))
1477      {
1478         ImagestateRealize(ic->norm.normal);
1479         if (ic->norm.normal->im)
1480           {
1481              int                 w, h;
1482
1483              EImageGetSize(ic->norm.normal->im, &w, &h);
1484              EImageFree(ic->norm.normal->im);
1485              IpcPrintf("%i %i\n", w, h);
1486           }
1487      }
1488    else if (!strcmp(param2, "apply"))
1489      {
1490         Window              xwin;
1491         Win                 win;
1492         char                state[20];
1493         int                 st, w, h;
1494
1495         /* 3:xwin 4:state 5:w 6:h */
1496         xwin = None;
1497         state[0] = '\0';
1498         w = h = -1;
1499         sscanf(p, "%lx %16s %d %d", &xwin, state, &w, &h);
1500
1501         win = ECreateWinFromXwin(xwin);
1502         if (!win)
1503            return;
1504
1505         if (!strcmp(state, "normal"))
1506            st = STATE_NORMAL;
1507         else if (!strcmp(state, "hilited"))
1508            st = STATE_HILITED;
1509         else if (!strcmp(state, "clicked"))
1510            st = STATE_CLICKED;
1511         else if (!strcmp(state, "disabled"))
1512            st = STATE_DISABLED;
1513         else
1514            st = STATE_NORMAL;
1515
1516         ImageclassApply(ic, win, 0, 0, st, ST_SOLID);
1517         EDestroyWin(win);
1518      }
1519    else if (!strcmp(param2, "apply_copy"))
1520      {
1521         Window              xwin;
1522         Win                 win;
1523         char                state[20];
1524         int                 st, w, h;
1525         PmapMask            pmm;
1526
1527         /* 3:xwin 4:state 5:w 6:h */
1528         xwin = None;
1529         state[0] = '\0';
1530         w = h = -1;
1531         sscanf(p, "%lx %16s %d %d", &xwin, state, &w, &h);
1532
1533         win = ECreateWinFromXwin(xwin);
1534         if (!win)
1535            return;
1536
1537         if (!strcmp(state, "normal"))
1538            st = STATE_NORMAL;
1539         else if (!strcmp(state, "hilited"))
1540            st = STATE_HILITED;
1541         else if (!strcmp(state, "clicked"))
1542            st = STATE_CLICKED;
1543         else if (!strcmp(state, "disabled"))
1544            st = STATE_DISABLED;
1545         else
1546            st = STATE_NORMAL;
1547
1548         if (w < 0 || h < 0)
1549           {
1550              IpcPrintf("Error:  missing width and/or height\n");
1551              return;
1552           }
1553
1554         ImageclassApplyCopy(ic, win, w, h, 0, 0, st, &pmm,
1555                             IC_FLAG_MAKE_MASK | IC_FLAG_FULL_SIZE, ST_SOLID);
1556         IpcPrintf("0x%08lx 0x%08lx\n", pmm.pmap, pmm.mask);
1557         EDestroyWin(win);
1558      }
1559    else if (!strcmp(param2, "query"))
1560      {
1561         IpcPrintf("ImageClass %s found\n", ic->name);
1562      }
1563    else if (!strcmp(param2, "ref_count"))
1564      {
1565         IpcPrintf("%u references remain\n", ic->ref_count);
1566      }
1567    else
1568      {
1569         IpcPrintf("Error: unknown operation specified\n");
1570      }
1571 }
1572
1573 static const IpcItem ImageclassIpcArray[] = {
1574    {
1575     ImageclassIpc,
1576     "imageclass", "ic",
1577     "List imageclasses, apply an imageclass",
1578     NULL}
1579    ,
1580 };
1581 #define N_IPC_FUNCS (sizeof(ImageclassIpcArray)/sizeof(IpcItem))
1582
1583 /*
1584  * Module descriptor
1585  */
1586 extern const EModule ModImageclass;
1587 const EModule       ModImageclass = {
1588    "imageclass", "ic",
1589    NULL,
1590    {N_IPC_FUNCS, ImageclassIpcArray}
1591    ,
1592    {0, NULL}
1593 };