1 /*
2 * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3 * Copyright (C) 2004-2021 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 "config.h"
25
26 #include <X11/Xlib.h>
27
28 #include "E.h"
29 #include "backgrounds.h"
30 #include "conf.h"
31 #include "desktops.h"
32 #include "eimage.h"
33 #include "emodule.h"
34 #include "iclass.h"
35 #include "list.h"
36 #include "tclass.h"
37 #include "xwin.h"
38
39 #define ENABLE_DESTROY 0 /* Broken */
40
41 struct _imagestate {
42 char *im_file;
43 char *real_file;
44 char got_colors;
45 char unloadable;
46 char transparent;
47 char pixmapfillstyle;
48 char bevelstyle;
49 char rotate;
50 EImage *im;
51 EImageBorder *border;
52 unsigned int bg, hi, lo, hihi, lolo;
53 unsigned int bg_pixel, hi_pixel, lo_pixel, hihi_pixel, lolo_pixel;
54 };
55
56 typedef struct {
57 ImageState *normal;
58 ImageState *hilited;
59 ImageState *clicked;
60 ImageState *disabled;
61 } ImageStateArray;
62
63 struct _imageclass {
64 dlist_t list;
65 char *name;
66 ImageStateArray norm, active, sticky, sticky_active;
67 EImageBorder padding;
68 unsigned int ref_count;
69 };
70
71 static LIST_HEAD(iclass_list);
72
73 static ImageClass *ImageclassGetFallback(void);
74
75 EImage *
ThemeImageLoad(const char * file)76 ThemeImageLoad(const char *file)
77 {
78 EImage *im;
79 char *f;
80
81 if (!file)
82 return NULL;
83
84 if (file[0] == '/')
85 {
86 im = EImageLoad(file);
87 return im;
88 }
89
90 f = ThemeFileFind(file, FILE_TYPE_IMAGE);
91 if (f)
92 {
93 im = EImageLoad(f);
94 Efree(f);
95 return im;
96 }
97
98 return NULL;
99 }
100
101 static void
ImagestateColorsSetGray(ImageState * is,unsigned int hihi,unsigned int hi,unsigned int bg,unsigned int lo,unsigned int lolo)102 ImagestateColorsSetGray(ImageState * is,
103 unsigned int hihi, unsigned int hi,
104 unsigned int bg, unsigned int lo, unsigned int lolo)
105 {
106 if (!is)
107 return;
108 COLOR32_FROM_RGB(is->hihi, hihi, hihi, hihi);
109 COLOR32_FROM_RGB(is->hi, hi, hi, hi);
110 COLOR32_FROM_RGB(is->bg, bg, bg, bg);
111 COLOR32_FROM_RGB(is->lo, lo, lo, lo);
112 COLOR32_FROM_RGB(is->lolo, lolo, lolo, lolo);
113 }
114
115 static ImageState *
ImagestateCreate(const char * file)116 ImagestateCreate(const char *file)
117 {
118 ImageState *is;
119
120 is = ECALLOC(ImageState, 1);
121 if (!is)
122 return NULL;
123
124 is->pixmapfillstyle = FILL_STRETCH;
125 ImagestateColorsSetGray(is, 255, 200, 160, 120, 64);
126 is->bevelstyle = BEVEL_NONE;
127 is->im_file = Estrdup(file);
128
129 return is;
130 }
131
132 static ImageState *
ImagestateCreateX(unsigned int hihi,unsigned int hi,unsigned int lo,unsigned int lolo,unsigned int bg_r,unsigned int bg_g,unsigned int bg_b)133 ImagestateCreateX(unsigned int hihi, unsigned int hi,
134 unsigned int lo, unsigned int lolo,
135 unsigned int bg_r, unsigned int bg_g, unsigned int bg_b)
136 {
137 ImageState *is;
138
139 is = ImagestateCreate(NULL);
140 if (!is)
141 return NULL;
142
143 ImagestateColorsSetGray(is, hihi, hi, 0, lo, lolo);
144 COLOR32_FROM_RGB(is->bg, bg_r, bg_g, bg_b);
145 is->bevelstyle = BEVEL_AMIGA;
146
147 return is;
148 }
149
150 static void
ImagestateDestroy(ImageState * is)151 ImagestateDestroy(ImageState * is)
152 {
153 if (!is)
154 return;
155
156 Efree(is->im_file);
157 Efree(is->real_file);
158
159 if (is->im)
160 EImageFree(is->im);
161
162 Efree(is->border);
163
164 Efree(is);
165 }
166
167 static ImageState *
ImagestateSet(ImageState ** isp,const char * name)168 ImagestateSet(ImageState ** isp, const char *name)
169 {
170 ImageState *is;
171
172 is = ImagestateCreate(name);
173
174 if (*isp)
175 ImagestateDestroy(*isp);
176 *isp = is;
177
178 return is;
179 }
180
181 static void
ImagestateColorsAlloc(ImageState * is)182 ImagestateColorsAlloc(ImageState * is)
183 {
184 if (!is || is->got_colors)
185 return;
186
187 is->bg_pixel = EAllocColor(WinGetCmap(VROOT), is->bg);
188 is->hi_pixel = EAllocColor(WinGetCmap(VROOT), is->hi);
189 is->lo_pixel = EAllocColor(WinGetCmap(VROOT), is->lo);
190 is->hihi_pixel = EAllocColor(WinGetCmap(VROOT), is->hihi);
191 is->lolo_pixel = EAllocColor(WinGetCmap(VROOT), is->lolo);
192
193 is->got_colors = 1;
194 }
195
196 static void
ImagestateRealize(ImageState * is)197 ImagestateRealize(ImageState * is)
198 {
199 if (!is)
200 return;
201 if (is->im) /* Image is already loaded */
202 return;
203
204 if (!is->real_file)
205 {
206 if (!is->im_file)
207 return; /* No file - quit */
208 /* not loaded, load and setup */
209 is->real_file = ThemeFileFind(is->im_file, FILE_TYPE_IMAGE);
210 }
211 if (is->real_file)
212 {
213 if (is->rotate && !Conf.memory_paranoia)
214 is->im = EImageLoadOrientate(is->real_file, is->rotate);
215 else
216 is->im = EImageLoad(is->real_file);
217 }
218 if (!is->im)
219 {
220 #define S(s) ((s) ? (s) : "(null)")
221 Eprintf
222 ("%s: Hmmm... is->im is NULL (im_file=%s real_file=%s)\n", __func__,
223 S(is->im_file), S(is->real_file));
224 EFREE_NULL(is->real_file);
225 return;
226 }
227
228 EFREE_NULL(is->im_file);
229
230 EImageCheckAlpha(is->im);
231
232 if (is->border)
233 EImageSetBorder(is->im, is->border);
234
235 #if 0 /* To be implemented? */
236 if (is->colmod)
237 {
238 Imlib_set_image_red_curve(pImlib_Context, is->im, is->colmod->red.map);
239 Imlib_set_image_green_curve(pImlib_Context, is->im,
240 is->colmod->green.map);
241 Imlib_set_image_blue_curve(pImlib_Context, is->im,
242 is->colmod->blue.map);
243 }
244 #endif
245 }
246
247 static ImageClass *
ImageclassCreate(const char * name)248 ImageclassCreate(const char *name)
249 {
250 ImageClass *ic;
251
252 ic = ECALLOC(ImageClass, 1);
253 if (!ic)
254 return NULL;
255
256 LIST_PREPEND(ImageClass, &iclass_list, ic);
257
258 ic->name = Estrdup(name);
259
260 return ic;
261 }
262
263 #if ENABLE_DESTROY
264 static void
FreeImageStateArray(ImageStateArray * isa)265 FreeImageStateArray(ImageStateArray * isa)
266 {
267 ImagestateDestroy(isa->normal);
268 ImagestateDestroy(isa->hilited);
269 ImagestateDestroy(isa->clicked);
270 ImagestateDestroy(isa->disabled);
271 }
272
273 static void
ImageclassDestroy(ImageClass * ic)274 ImageclassDestroy(ImageClass * ic)
275 {
276 if (!ic)
277 return;
278
279 if (ic->ref_count > 0)
280 {
281 DialogOK("ImageClass Error!", _("%u references remain"), ic->ref_count);
282 return;
283 }
284
285 LIST_REMOVE(ImageClass, &iclass_list, ic);
286
287 Efree(ic->name);
288
289 FreeImageStateArray(&(ic->norm));
290 FreeImageStateArray(&(ic->active));
291 FreeImageStateArray(&(ic->sticky));
292 FreeImageStateArray(&(ic->sticky_active));
293
294 Efree(ic);
295 }
296 #endif /* ENABLE_DESTROY */
297
298 ImageClass *
ImageclassAlloc(const char * name,int fallback)299 ImageclassAlloc(const char *name, int fallback)
300 {
301 ImageClass *ic;
302
303 if (!name || !name[0])
304 return NULL;
305
306 ic = ImageclassFind(name, fallback);
307 if (ic)
308 ic->ref_count++;
309
310 return ic;
311 }
312
313 void
ImageclassFree(ImageClass * ic)314 ImageclassFree(ImageClass * ic)
315 {
316 if (ic)
317 ic->ref_count--;
318 }
319
320 const char *
ImageclassGetName(ImageClass * ic)321 ImageclassGetName(ImageClass * ic)
322 {
323 return (ic) ? ic->name : NULL;
324 }
325
326 EImageBorder *
ImageclassGetPadding(ImageClass * ic)327 ImageclassGetPadding(ImageClass * ic)
328 {
329 return (ic) ? &(ic->padding) : NULL;
330 }
331
332 static int
_ImageclassMatchName(const void * data,const void * match)333 _ImageclassMatchName(const void *data, const void *match)
334 {
335 return strcmp(((const ImageClass *)data)->name, (const char *)match);
336 }
337
338 ImageClass *
ImageclassFind(const char * name,int fallback)339 ImageclassFind(const char *name, int fallback)
340 {
341 ImageClass *ic = NULL;
342
343 if (name)
344 ic = LIST_FIND(ImageClass, &iclass_list, _ImageclassMatchName, name);
345 if (ic || !fallback)
346 return ic;
347
348 #if 0
349 Eprintf("%s: Get fallback (%s)\n", __func__, name);
350 #endif
351 return ImageclassGetFallback();
352 }
353
354 #define ISTATE_SET_STATE(which, fallback) \
355 if (!ic->which) ic->which = ic->fallback;
356
357 static void
ImageclassPopulate(ImageClass * ic)358 ImageclassPopulate(ImageClass * ic)
359 {
360 if (!ic || !ic->norm.normal)
361 return;
362
363 ISTATE_SET_STATE(norm.hilited, norm.normal);
364 ISTATE_SET_STATE(norm.clicked, norm.normal);
365 ISTATE_SET_STATE(norm.disabled, norm.normal);
366
367 ISTATE_SET_STATE(active.normal, norm.normal);
368 ISTATE_SET_STATE(active.hilited, active.normal);
369 ISTATE_SET_STATE(active.clicked, active.normal);
370 ISTATE_SET_STATE(active.disabled, active.normal);
371
372 ISTATE_SET_STATE(sticky.normal, norm.normal);
373 ISTATE_SET_STATE(sticky.hilited, sticky.normal);
374 ISTATE_SET_STATE(sticky.clicked, sticky.normal);
375 ISTATE_SET_STATE(sticky.disabled, sticky.normal);
376
377 ISTATE_SET_STATE(sticky_active.normal, norm.normal);
378 ISTATE_SET_STATE(sticky_active.hilited, sticky_active.normal);
379 ISTATE_SET_STATE(sticky_active.clicked, sticky_active.normal);
380 ISTATE_SET_STATE(sticky_active.disabled, sticky_active.normal);
381 }
382
383 int
ImageclassConfigLoad(FILE * fs)384 ImageclassConfigLoad(FILE * fs)
385 {
386 int err = 0;
387 char s[FILEPATH_LEN_MAX];
388 char s2[FILEPATH_LEN_MAX];
389 char *p2;
390 int i1;
391 ImageClass *ic = NULL;
392 ImageState *is = NULL;
393 int l, r, t, b;
394
395 while (GetLine(s, sizeof(s), fs))
396 {
397 i1 = ConfigParseline1(s, s2, &p2, NULL);
398
399 /* ic not needed */
400 switch (i1)
401 {
402 case CONFIG_CLOSE:
403 ImageclassPopulate(ic);
404 goto done;
405 case CONFIG_COLORMOD:
406 case ICLASS_COLORMOD:
407 continue;
408 case CONFIG_CLASSNAME:
409 if (ImageclassFind(s2, 0))
410 {
411 SkipTillEnd(fs);
412 goto done;
413 }
414 ic = ImageclassCreate(s2);
415 continue;
416 }
417
418 /* ic needed */
419 if (!ic)
420 break;
421
422 switch (i1)
423 {
424 case CONFIG_INHERIT:
425 {
426 ImageClass *ic2;
427
428 ic2 = ImageclassFind(s2, 0);
429 if (!ic2)
430 goto not_ok;
431 ic->norm = ic2->norm;
432 ic->active = ic2->active;
433 ic->sticky = ic2->sticky;
434 ic->sticky_active = ic2->sticky_active;
435 ic->padding = ic2->padding;
436 }
437 continue;
438 case ICLASS_PADDING:
439 l = r = t = b = 0;
440 sscanf(p2, "%i %i %i %i", &l, &r, &t, &b);
441 ic->padding.left = l;
442 ic->padding.right = r;
443 ic->padding.top = t;
444 ic->padding.bottom = b;
445 continue;
446 case CONFIG_DESKTOP:
447 /* don't ask... --mandrake */
448 case ICLASS_NORMAL:
449 is = ImagestateSet(&ic->norm.normal, s2);
450 continue;
451 case ICLASS_CLICKED:
452 is = ImagestateSet(&ic->norm.clicked, s2);
453 continue;
454 case ICLASS_HILITED:
455 is = ImagestateSet(&ic->norm.hilited, s2);
456 continue;
457 case ICLASS_DISABLED:
458 is = ImagestateSet(&ic->norm.disabled, s2);
459 continue;
460 case ICLASS_STICKY_NORMAL:
461 is = ImagestateSet(&ic->sticky.normal, s2);
462 continue;
463 case ICLASS_STICKY_CLICKED:
464 is = ImagestateSet(&ic->sticky.clicked, s2);
465 continue;
466 case ICLASS_STICKY_HILITED:
467 is = ImagestateSet(&ic->sticky.hilited, s2);
468 continue;
469 case ICLASS_STICKY_DISABLED:
470 is = ImagestateSet(&ic->sticky.disabled, s2);
471 continue;
472 case ICLASS_ACTIVE_NORMAL:
473 is = ImagestateSet(&ic->active.normal, s2);
474 continue;
475 case ICLASS_ACTIVE_CLICKED:
476 is = ImagestateSet(&ic->active.clicked, s2);
477 continue;
478 case ICLASS_ACTIVE_HILITED:
479 is = ImagestateSet(&ic->active.hilited, s2);
480 continue;
481 case ICLASS_ACTIVE_DISABLED:
482 is = ImagestateSet(&ic->active.disabled, s2);
483 continue;
484 case ICLASS_STICKY_ACTIVE_NORMAL:
485 is = ImagestateSet(&ic->sticky_active.normal, s2);
486 continue;
487 case ICLASS_STICKY_ACTIVE_CLICKED:
488 is = ImagestateSet(&ic->sticky_active.clicked, s2);
489 continue;
490 case ICLASS_STICKY_ACTIVE_HILITED:
491 is = ImagestateSet(&ic->sticky_active.hilited, s2);
492 continue;
493 case ICLASS_STICKY_ACTIVE_DISABLED:
494 is = ImagestateSet(&ic->sticky_active.disabled, s2);
495 continue;
496 }
497
498 /* is needed */
499 if (!is)
500 break;
501
502 switch (i1)
503 {
504 case ICLASS_LRTB:
505 if (!is->border)
506 is->border = EMALLOC(EImageBorder, 1);
507 l = r = t = b = 0;
508 sscanf(p2, "%i %i %i %i", &l, &r, &t, &b);
509 is->border->left = l;
510 is->border->right = r;
511 is->border->top = t;
512 is->border->bottom = b;
513 /* Hmmm... imlib2 works better with this */
514 is->border->right++;
515 is->border->bottom++;
516 continue;
517 case ICLASS_FILLRULE:
518 is->pixmapfillstyle = atoi(s2);
519 continue;
520 case ICLASS_TRANSPARENT:
521 is->transparent = strtoul(s2, NULL, 0);
522 continue;
523 case ICLASS_ROTATE: /* flip goes here too */
524 is->rotate = strtoul(s2, NULL, 0);
525 continue;
526 case ICLASS_BEVEL:
527 {
528 int n, bevel;
529
530 n = sscanf(p2, "%i %i %i %i %i %i",
531 &bevel, &is->hihi, &is->hi, &is->bg, &is->lo,
532 &is->lolo);
533 if (n < 6)
534 goto not_ok;
535 is->bevelstyle = bevel;
536 }
537 continue;
538 default:
539 goto not_ok;
540 }
541 }
542 not_ok:
543 err = -1;
544
545 done:
546 return err;
547 }
548
549 ImageClass *
ImageclassCreateSimple(const char * name,const char * image)550 ImageclassCreateSimple(const char *name, const char *image)
551 {
552 ImageClass *ic;
553
554 ic = ImageclassCreate(name);
555 if (!ic)
556 return NULL;
557
558 ic->norm.normal = ImagestateCreate(image);
559 ic->norm.normal->unloadable = 1;
560 ImageclassPopulate(ic);
561
562 ImagestateRealize(ic->norm.normal);
563
564 return ic;
565 }
566
567 static ImageState *
ImageclassGetImageState1(ImageStateArray * pisa,int state)568 ImageclassGetImageState1(ImageStateArray * pisa, int state)
569 {
570 ImageState *is;
571
572 switch (state)
573 {
574 case STATE_NORMAL:
575 is = pisa->normal;
576 break;
577 case STATE_HILITED:
578 is = pisa->hilited;
579 break;
580 case STATE_CLICKED:
581 is = pisa->clicked;
582 break;
583 case STATE_DISABLED:
584 is = pisa->disabled;
585 break;
586 default:
587 is = NULL;
588 break;
589 }
590
591 return is;
592 }
593
594 ImageState *
ImageclassGetImageState(ImageClass * ic,int state,int active,int sticky)595 ImageclassGetImageState(ImageClass * ic, int state, int active, int sticky)
596 {
597 ImageState *is;
598
599 if (active)
600 {
601 if (sticky)
602 is = ImageclassGetImageState1(&ic->sticky_active, state);
603 else
604 is = ImageclassGetImageState1(&ic->active, state);
605 }
606 else
607 {
608 if (sticky)
609 is = ImageclassGetImageState1(&ic->sticky, state);
610 else
611 is = ImageclassGetImageState1(&ic->norm, state);
612 }
613
614 return is;
615 }
616
617 EImage *
ImageclassGetImage(ImageClass * ic,int active,int sticky,int state)618 ImageclassGetImage(ImageClass * ic, int active, int sticky, int state)
619 {
620 EImage *im;
621 ImageState *is;
622
623 if (!ic)
624 return NULL;
625
626 is = ImageclassGetImageState(ic, state, active, sticky);
627 if (!is)
628 return NULL;
629
630 if (!is->im)
631 ImagestateRealize(is);
632
633 im = is->im;
634 if (!im)
635 return NULL;
636 is->im = NULL;
637
638 return im;
639 }
640
641 char *
ImageclassGetFile(ImageClass * ic)642 ImageclassGetFile(ImageClass * ic)
643 {
644 ImageState *is;
645
646 if (!ic)
647 return NULL;
648
649 is = ImageclassGetImageState(ic, STATE_NORMAL, 0, 0);
650 if (!is || !is->im_file)
651 return NULL;
652
653 return ThemeFileFind(is->im_file, FILE_TYPE_IMAGE);
654 }
655
656 EImage *
ImageclassGetImageBlended(ImageClass * ic,Win win __UNUSED__,int w,int h,int active,int sticky,int state)657 ImageclassGetImageBlended(ImageClass * ic, Win win __UNUSED__, int w, int h,
658 int active, int sticky, int state)
659 {
660 ImageState *is;
661 EImage *im, *bg;
662
663 if (!ic)
664 return NULL;
665
666 is = ImageclassGetImageState(ic, state, active, sticky);
667 if (!is)
668 return NULL;
669
670 if (!is->im)
671 ImagestateRealize(is);
672 im = is->im;
673 if (!im)
674 return NULL;
675
676 if (is->pixmapfillstyle == FILL_STRETCH)
677 {
678 bg = EImageCreateScaled(im, 0, 0, 0, 0, w, h);
679 }
680 else
681 {
682 int iw, ih, tw, th;
683
684 EImageGetSize(im, &iw, &ih);
685
686 tw = w;
687 th = h;
688 if (is->pixmapfillstyle & FILL_TILE_H)
689 tw = iw;
690 if (is->pixmapfillstyle & FILL_TILE_V)
691 th = ih;
692
693 bg = EImageCreate(w, h);
694 EImageTile(bg, im, 0, tw, th, 0, 0, w, h, 0, 0);
695 }
696
697 if ((is->unloadable) || (Conf.memory_paranoia))
698 {
699 EImageFree(is->im);
700 is->im = NULL;
701 }
702
703 return bg;
704 }
705
706 static void
ImagestateMakePmapMask(ImageState * is,Win win,PmapMask * pmm,int pmapflags __UNUSED__,int w,int h)707 ImagestateMakePmapMask(ImageState * is, Win win, PmapMask * pmm,
708 int pmapflags __UNUSED__, int w, int h)
709 {
710 if (is->pixmapfillstyle == FILL_STRETCH)
711 {
712 pmm->type = 1;
713 pmm->pmap = pmm->mask = NoXID;
714 pmm->w = w;
715 pmm->h = h;
716 EImageRenderPixmaps(is->im, win, EIMAGE_ANTI_ALIAS, &pmm->pmap,
717 &pmm->mask, w, h);
718 }
719 else
720 {
721 int ww, hh, cw, ch, pw, ph;
722
723 EImageGetSize(is->im, &ww, &hh);
724
725 pw = w;
726 ph = h;
727 if (is->pixmapfillstyle & FILL_TILE_H)
728 pw = ww;
729 if (is->pixmapfillstyle & FILL_TILE_V)
730 ph = hh;
731 if (is->pixmapfillstyle & FILL_INT_TILE_H)
732 {
733 cw = w / ww;
734 if (cw * ww < w)
735 cw++;
736 if (cw < 1)
737 cw = 1;
738 pw = w / cw;
739 }
740 if (is->pixmapfillstyle & FILL_INT_TILE_V)
741 {
742 ch = h / hh;
743 if (ch * hh < h)
744 ch++;
745 if (ch < 1)
746 ch = 1;
747 ph = h / ch;
748 }
749 pmm->type = 1;
750 pmm->pmap = pmm->mask = NoXID;
751 pmm->w = pw;
752 pmm->h = ph;
753 EImageRenderPixmaps(is->im, win, EIMAGE_ANTI_ALIAS, &pmm->pmap,
754 &pmm->mask, pw, ph);
755 }
756 }
757
758 #define LINE(x1, y1, x2, y2) \
759 XDrawLine(disp, win, gc, x + (x1), y + (y1), x + (x2), y + (y2))
760 #define RECT(x, y, w, h) \
761 XDrawRectangle(disp, win, gc, x, y, w, h);
762
763 static void
ImagestateDrawBevel(ImageState * is,EX_Drawable win,int x,int y,int w,int h)764 ImagestateDrawBevel(ImageState * is, EX_Drawable win,
765 int x, int y, int w, int h)
766 {
767 GC gc;
768
769 gc = EXCreateGC(win, 0, NULL);
770
771 ImagestateColorsAlloc(is);
772
773 switch (is->bevelstyle)
774 {
775 case BEVEL_AMIGA:
776 XSetForeground(disp, gc, is->hihi_pixel);
777 LINE(0, 0, w - 2, 0);
778 LINE(0, 0, 0, h - 2);
779 XSetForeground(disp, gc, is->lolo_pixel);
780 LINE(1, h - 1, w - 1, h - 1);
781 LINE(w - 1, 1, w - 1, h - 1);
782 break;
783 case BEVEL_MOTIF:
784 XSetForeground(disp, gc, is->hi_pixel);
785 LINE(0, 0, w - 1, 0);
786 LINE(0, 0, 0, h - 1);
787 LINE(1, 1, w - 2, 1);
788 LINE(1, 1, 1, h - 2);
789 XSetForeground(disp, gc, is->lo_pixel);
790 LINE(0, h - 1, w - 1, h - 1);
791 LINE(w - 1, 1, w - 1, h - 1);
792 LINE(1, h - 2, w - 2, h - 2);
793 LINE(w - 2, 2, w - 2, h - 2);
794 break;
795 case BEVEL_NEXT:
796 XSetForeground(disp, gc, is->hihi_pixel);
797 LINE(0, 0, w - 1, 0);
798 LINE(0, 0, 0, h - 1);
799 XSetForeground(disp, gc, is->hi_pixel);
800 LINE(1, 1, w - 2, 1);
801 LINE(1, 1, 1, h - 2);
802 XSetForeground(disp, gc, is->lolo_pixel);
803 LINE(1, h - 1, w - 1, h - 1);
804 LINE(w - 1, 1, w - 1, h - 1);
805 XSetForeground(disp, gc, is->lo_pixel);
806 LINE(2, h - 2, w - 2, h - 2);
807 LINE(w - 2, 2, w - 2, h - 2);
808 break;
809 case BEVEL_DOUBLE:
810 XSetForeground(disp, gc, is->hi_pixel);
811 LINE(0, 0, w - 2, 0);
812 LINE(0, 0, 0, h - 2);
813 XSetForeground(disp, gc, is->lo_pixel);
814 LINE(1, 1, w - 3, 1);
815 LINE(1, 1, 1, h - 3);
816 XSetForeground(disp, gc, is->lo_pixel);
817 LINE(1, h - 1, w - 1, h - 1);
818 LINE(w - 1, 1, w - 1, h - 1);
819 XSetForeground(disp, gc, is->hi_pixel);
820 LINE(2, h - 2, w - 2, h - 2);
821 LINE(w - 2, 2, w - 2, h - 2);
822 break;
823 case BEVEL_WIDEDOUBLE:
824 XSetForeground(disp, gc, is->hihi_pixel);
825 LINE(0, 0, w - 1, 0);
826 LINE(0, 0, 0, h - 1);
827 XSetForeground(disp, gc, is->hi_pixel);
828 LINE(1, 1, w - 2, 1);
829 LINE(1, 1, 1, h - 2);
830 LINE(3, h - 4, w - 4, h - 4);
831 LINE(w - 4, 3, w - 4, h - 4);
832 XSetForeground(disp, gc, is->lolo_pixel);
833 LINE(1, h - 1, w - 1, h - 1);
834 LINE(w - 1, 1, w - 1, h - 1);
835 XSetForeground(disp, gc, is->lo_pixel);
836 LINE(2, h - 2, w - 2, h - 2);
837 LINE(w - 2, 2, w - 2, h - 2);
838 LINE(3, 3, w - 4, 3);
839 LINE(3, 3, 3, h - 4);
840 break;
841 case BEVEL_THINPOINT:
842 XSetForeground(disp, gc, is->hi_pixel);
843 LINE(0, 0, w - 2, 0);
844 LINE(0, 0, 0, h - 2);
845 XSetForeground(disp, gc, is->lo_pixel);
846 LINE(1, h - 1, w - 1, h - 1);
847 LINE(w - 1, 1, w - 1, h - 1);
848 XSetForeground(disp, gc, is->hihi_pixel);
849 LINE(0, 0, 1, 0);
850 LINE(0, 0, 0, 1);
851 XSetForeground(disp, gc, is->lolo_pixel);
852 LINE(w - 2, h - 1, w - 1, h - 1);
853 LINE(w - 1, h - 2, w - 1, h - 1);
854 break;
855 case BEVEL_THICKPOINT:
856 XSetForeground(disp, gc, is->hi_pixel);
857 RECT(x, y, w - 1, h - 1);
858 break;
859 default:
860 break;
861 }
862
863 EXFreeGC(gc);
864 }
865
866 static void
ImagestateDrawNoImg(ImageState * is,EX_Drawable draw,int x,int y,int w,int h)867 ImagestateDrawNoImg(ImageState * is, EX_Drawable draw, int x, int y, int w,
868 int h)
869 {
870 ImagestateColorsAlloc(is);
871
872 EXFillAreaSolid(draw, x, y, w, h, is->bg_pixel);
873 if (is->bevelstyle != BEVEL_NONE)
874 ImagestateDrawBevel(is, draw, x, y, w, h);
875 }
876
877 void
ITApply(Win win,ImageClass * ic,ImageState * is,int state,int active,int sticky,TextClass * tc,TextState * ts,const char * text,int flags)878 ITApply(Win win, ImageClass * ic, ImageState * is,
879 int state, int active, int sticky,
880 TextClass * tc, TextState * ts, const char *text, int flags)
881 {
882 int w, h;
883
884 if (!win || !ic)
885 return;
886
887 w = WinGetW(win);
888 h = WinGetH(win);
889 if (w <= 0 || h <= 0)
890 return;
891
892 if (!is)
893 is = ImageclassGetImageState(ic, state, active, sticky);
894 if (!is)
895 return;
896
897 if (tc && text)
898 {
899 if (!ts)
900 ts = TextclassGetTextState(tc, state, active, sticky);
901 }
902
903 if (!is->im)
904 ImagestateRealize(is);
905
906 /* Imlib2 will not render pixmaps with dimensions > 8192 */
907 if (is->im && w <= 8192 && h <= 8192)
908 {
909 PmapMask pmm;
910
911 ImagestateMakePmapMask(is, win, &pmm, IC_FLAG_MAKE_MASK, w, h);
912
913 if (pmm.pmap)
914 {
915 EX_Pixmap pmap = pmm.pmap;
916
917 if ((ts && text) || (is->bevelstyle != BEVEL_NONE) ||
918 (flags & ITA_BGPMAP))
919 {
920 if (pmm.type != 0)
921 {
922 pmap = EGetWindowBackgroundPixmap(win);
923 EXCopyAreaTiled(pmm.pmap, NoXID, pmap, 0, 0, w, h, 0, 0);
924 }
925
926 if (is->bevelstyle != BEVEL_NONE)
927 ImagestateDrawBevel(is, pmap, 0, 0, w, h);
928
929 if (ts && text)
930 TextstateTextDraw(ts, win, pmap, text, 0, 0, w, h,
931 &(ic->padding), 0,
932 TextclassGetJustification(tc),
933 flags & ITA_JUSTV);
934 }
935
936 /* Set window pixmap */
937 if (pmap == pmm.pmap)
938 ESetWindowBackgroundPixmap(win, pmap, 0);
939
940 if (pmm.w == w && pmm.h == h)
941 EShapeSetMask(win, 0, 0, pmm.mask);
942 else if (pmm.mask)
943 EShapeSetMaskTiled(win, 0, 0, pmm.mask, w, h);
944 }
945
946 PmapMaskFree(&pmm);
947
948 if ((is->unloadable) || (Conf.memory_paranoia))
949 {
950 EImageFree(is->im);
951 is->im = NULL;
952 }
953 }
954 else
955 {
956 ImagestateColorsAlloc(is);
957
958 if (is->bevelstyle == BEVEL_NONE && !text)
959 {
960 ESetWindowBackground(win, is->bg_pixel);
961 }
962 else
963 {
964 EX_Pixmap pmap;
965
966 pmap = EGetWindowBackgroundPixmap(win);
967 ImagestateDrawNoImg(is, pmap, 0, 0, w, h);
968 if (ts && text)
969 TextstateTextDraw(ts, win, pmap, text, 0, 0, w, h,
970 &(ic->padding), 0,
971 TextclassGetJustification(tc),
972 flags & ITA_JUSTV);
973 }
974 }
975 EClearWindow(win);
976 }
977
978 void
ImageclassApply(ImageClass * ic,Win win,int active,int sticky,int state)979 ImageclassApply(ImageClass * ic, Win win, int active, int sticky, int state)
980 {
981 ITApply(win, ic, NULL, state, active, sticky, NULL, NULL, NULL, 0);
982 }
983
984 static void
PmapMaskTile(PmapMask * pmm,Win win,unsigned int w,unsigned int h)985 PmapMaskTile(PmapMask * pmm, Win win, unsigned int w, unsigned int h)
986 {
987 EX_Pixmap pmap, mask;
988
989 pmap = ECreatePixmap(win, w, h, 0);
990 if (pmap == NoXID)
991 return;
992 EXCopyAreaTiled(pmm->pmap, NoXID, pmap, 0, 0, w, h, 0, 0);
993
994 mask = NoXID;
995 if (pmm->mask != NoXID)
996 mask = ECreatePixmap(win, w, h, 1);
997 if (mask != NoXID)
998 EXCopyAreaTiled(pmm->mask, NoXID, mask, 0, 0, w, h, 0, 0);
999
1000 PmapMaskFree(pmm);
1001 pmm->type = 0;
1002 pmm->w = w;
1003 pmm->h = h;
1004 pmm->pmap = pmap;
1005 pmm->mask = mask;
1006 }
1007
1008 void
ImageclassApplyCopy(ImageClass * ic,Win win,int w,int h,int active,int sticky,int state,PmapMask * pmm,int pmapflags)1009 ImageclassApplyCopy(ImageClass * ic, Win win, int w, int h,
1010 int active, int sticky, int state,
1011 PmapMask * pmm, int pmapflags)
1012 {
1013 ImageState *is;
1014
1015 if (!pmm)
1016 return;
1017
1018 pmm->type = 0;
1019 pmm->pmap = pmm->mask = 0;
1020
1021 if ((!ic) || (!win) || (w <= 0) || (h <= 0))
1022 return;
1023
1024 is = ImageclassGetImageState(ic, state, active, sticky);
1025 if (!is)
1026 return;
1027
1028 if (!is->im)
1029 ImagestateRealize(is);
1030
1031 /* Imlib2 will not render pixmaps with dimensions > 8192 */
1032 if (is->im && w <= 8192 && h <= 8192)
1033 {
1034 ImagestateMakePmapMask(is, win, pmm, pmapflags, w, h);
1035
1036 if ((pmapflags & IC_FLAG_FULL_SIZE) && pmm->pmap &&
1037 (pmm->w != w || pmm->h != h))
1038 {
1039 /* Create new full sized pixmaps and fill them with the */
1040 /* pmap and mask tiles */
1041 PmapMaskTile(pmm, win, w, h);
1042 }
1043
1044 if ((is->unloadable) || (Conf.memory_paranoia))
1045 {
1046 EImageFree(is->im);
1047 is->im = NULL;
1048 }
1049 }
1050 else
1051 {
1052 if (pmm->pmap)
1053 Eprintf("%s: Hmm... pmm->pmap already set\n", __func__);
1054
1055 pmm->type = 0;
1056 pmm->pmap = ECreatePixmap(win, w, h, 0);
1057 pmm->mask = 0;
1058
1059 ImagestateDrawNoImg(is, pmm->pmap, 0, 0, w, h);
1060 /* FIXME - No text */
1061 }
1062 }
1063
1064 void
ImageclassApplySimple(ImageClass * ic,Win win,EX_Drawable draw,int state,int x,int y,int w,int h)1065 ImageclassApplySimple(ImageClass * ic, Win win, EX_Drawable draw, int state,
1066 int x, int y, int w, int h)
1067 {
1068 EImage *im;
1069
1070 if (!ic)
1071 return;
1072
1073 im = ImageclassGetImage(ic, 0, 0, state);
1074 if (im)
1075 {
1076 EImageRenderOnDrawable(im, win, draw, 0, x, y, w, h);
1077 EImageFree(im);
1078 }
1079 else
1080 {
1081 ImageState *is;
1082
1083 is = ImageclassGetImageState(ic, state, 0, 0);
1084 if (!is)
1085 return;
1086
1087 ImagestateDrawNoImg(is, draw, x, y, w, h);
1088 }
1089 }
1090
1091 static ImageClass *
ImageclassGetFallback(void)1092 ImageclassGetFallback(void)
1093 {
1094 ImageClass *ic;
1095
1096 ic = ImageclassFind("__fb_ic", 0);
1097 if (ic)
1098 return ic;
1099
1100 /* Create fallback imageclass */
1101 ic = ImageclassCreate("__fb_ic");
1102 if (!ic)
1103 return ic;
1104
1105 ic->norm.normal = ImagestateCreateX(255, 255, 0, 0, 160, 160, 160);
1106 ic->norm.hilited = ImagestateCreateX(255, 255, 0, 0, 192, 192, 192);
1107 ic->norm.clicked = ImagestateCreateX(0, 0, 255, 255, 192, 192, 192);
1108 ic->active.normal = ImagestateCreateX(255, 255, 0, 0, 180, 140, 160);
1109 ic->active.hilited = ImagestateCreateX(255, 255, 0, 0, 230, 190, 210);
1110 ic->active.clicked = ImagestateCreateX(0, 0, 255, 255, 230, 190, 210);
1111
1112 ic->padding.left = 4;
1113 ic->padding.right = 4;
1114 ic->padding.top = 4;
1115 ic->padding.bottom = 4;
1116
1117 ImageclassPopulate(ic);
1118
1119 return ic;
1120 }
1121
1122 ImageClass *
ImageclassGetBlack(void)1123 ImageclassGetBlack(void)
1124 {
1125 ImageClass *ic;
1126
1127 ic = ImageclassFind("__BLACK", 0);
1128 if (ic)
1129 return ic;
1130
1131 /* Create all black image class for filler borders */
1132 ic = ImageclassCreate("__BLACK");
1133 if (!ic)
1134 return ic;
1135
1136 ic->norm.normal = ImagestateCreate(NULL);
1137 ImagestateColorsSetGray(ic->norm.normal, 0, 0, 0, 0, 0);
1138
1139 ImageclassPopulate(ic);
1140
1141 return ic;
1142 }
1143
1144 /*
1145 * Imageclass Module
1146 */
1147
1148 static void
ImageclassIpc(const char * params)1149 ImageclassIpc(const char *params)
1150 {
1151 char param1[1024];
1152 char param2[1024];
1153 int l;
1154 const char *p;
1155 ImageClass *ic;
1156
1157 if (!params)
1158 {
1159 IpcPrintf("Please specify...\n");
1160 return;
1161 }
1162
1163 p = params;
1164 l = 0;
1165 param1[0] = param2[0] = '\0';
1166 sscanf(p, "%1000s %1000s %n", param1, param2, &l);
1167 p += l;
1168
1169 if (!strncmp(param1, "list", 2))
1170 {
1171 LIST_FOR_EACH(ImageClass, &iclass_list, ic) IpcPrintf("%s\n", ic->name);
1172 return;
1173 }
1174
1175 if (!param1[0])
1176 {
1177 IpcPrintf("ImageClass not specified\n");
1178 return;
1179 }
1180
1181 if (!strcmp(param2, "free_pixmap"))
1182 {
1183 EX_Pixmap pmap;
1184
1185 pmap = (EX_Pixmap) strtol(p, NULL, 0);
1186 EImagePixmapsFree(pmap, NoXID);
1187 return;
1188 }
1189
1190 ic = ImageclassFind(param1, 0);
1191 if (!ic)
1192 {
1193 IpcPrintf("ImageClass not found: %s\n", param1);
1194 return;
1195 }
1196
1197 if (!strcmp(param2, "get_padding"))
1198 {
1199 IpcPrintf("%i %i %i %i\n",
1200 ic->padding.left, ic->padding.right,
1201 ic->padding.top, ic->padding.bottom);
1202 }
1203 else if (!strcmp(param2, "get_image_size"))
1204 {
1205 ImagestateRealize(ic->norm.normal);
1206 if (ic->norm.normal->im)
1207 {
1208 int w, h;
1209
1210 EImageGetSize(ic->norm.normal->im, &w, &h);
1211 EImageFree(ic->norm.normal->im);
1212 IpcPrintf("%i %i\n", w, h);
1213 }
1214 }
1215 else if (!strcmp(param2, "apply"))
1216 {
1217 EX_Window xwin;
1218 Win win;
1219 char state[20];
1220 int st, w, h;
1221
1222 /* 3:xwin 4:state 5:w 6:h */
1223 xwin = NoXID;
1224 state[0] = '\0';
1225 w = h = -1;
1226 sscanf(p, "%x %16s %d %d", &xwin, state, &w, &h);
1227
1228 win = ECreateWinFromXwin(xwin);
1229 if (!win)
1230 return;
1231
1232 if (!strcmp(state, "normal"))
1233 st = STATE_NORMAL;
1234 else if (!strcmp(state, "hilited"))
1235 st = STATE_HILITED;
1236 else if (!strcmp(state, "clicked"))
1237 st = STATE_CLICKED;
1238 else if (!strcmp(state, "disabled"))
1239 st = STATE_DISABLED;
1240 else
1241 st = STATE_NORMAL;
1242
1243 ImageclassApply(ic, win, 0, 0, st);
1244 EDestroyWin(win);
1245 }
1246 else if (!strcmp(param2, "apply_copy"))
1247 {
1248 EX_Window xwin;
1249 Win win;
1250 char state[20];
1251 int st, w, h;
1252 PmapMask pmm;
1253
1254 /* 3:xwin 4:state 5:w 6:h */
1255 xwin = NoXID;
1256 state[0] = '\0';
1257 w = h = -1;
1258 sscanf(p, "%x %16s %d %d", &xwin, state, &w, &h);
1259
1260 win = ECreateWinFromXwin(xwin);
1261 if (!win)
1262 return;
1263
1264 if (!strcmp(state, "normal"))
1265 st = STATE_NORMAL;
1266 else if (!strcmp(state, "hilited"))
1267 st = STATE_HILITED;
1268 else if (!strcmp(state, "clicked"))
1269 st = STATE_CLICKED;
1270 else if (!strcmp(state, "disabled"))
1271 st = STATE_DISABLED;
1272 else
1273 st = STATE_NORMAL;
1274
1275 if (w < 0 || h < 0)
1276 {
1277 IpcPrintf("Error: missing width and/or height\n");
1278 return;
1279 }
1280
1281 ImageclassApplyCopy(ic, win, w, h, 0, 0, st, &pmm,
1282 IC_FLAG_MAKE_MASK | IC_FLAG_FULL_SIZE);
1283 IpcPrintf("0x%08x 0x%08x\n", pmm.pmap, pmm.mask);
1284 EDestroyWin(win);
1285 }
1286 else if (!strcmp(param2, "query"))
1287 {
1288 IpcPrintf("ImageClass %s found\n", ic->name);
1289 }
1290 else if (!strcmp(param2, "ref_count"))
1291 {
1292 IpcPrintf("%u references remain\n", ic->ref_count);
1293 }
1294 else
1295 {
1296 IpcPrintf("Error: unknown operation specified\n");
1297 }
1298 }
1299
1300 static const IpcItem ImageclassIpcArray[] = {
1301 {
1302 ImageclassIpc,
1303 "imageclass", "ic",
1304 "List imageclasses, apply an imageclass",
1305 NULL}
1306 ,
1307 };
1308
1309 /*
1310 * Module descriptor
1311 */
1312 extern const EModule ModImageclass;
1313
1314 const EModule ModImageclass = {
1315 "imageclass", "ic",
1316 NULL,
1317 MOD_ITEMS(ImageclassIpcArray),
1318 {0, NULL}
1319 };
1320