2 /* Copyright (C) 2002 the late Joey Shutup.
4 * http://www.streetmap.co.uk/streetmap.dll?postcode2map?BS24+9TZ
6 * No guarantees or warranties or anything are provided or implied in any way
7 * whatsoever. Use this program at your own risk. Permission to use this
8 * program for any purpose is given, as long as the copyright is kept intact.
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 /* ---------------------------- included header files ---------------------- */
31 #include <X11/Xatom.h>
33 #include "libs/fvwmlib.h"
34 #include "libs/Parse.h"
35 #include "libs/PictureBase.h"
36 #include "libs/FShape.h"
37 #include "libs/ColorUtils.h"
38 #include "libs/Picture.h"
39 #include "libs/PictureUtils.h"
40 #include "libs/Graphics.h"
41 #include "libs/PictureGraphics.h"
42 #include "libs/FRenderInit.h"
43 #include "libs/Strings.h"
44 #include "libs/Grab.h"
49 #include "functions.h"
53 #include "module_interface.h"
54 #include "execcontext.h"
57 /* ---------------------------- local definitions -------------------------- */
59 /* ---------------------------- local macros ------------------------------- */
61 /* ---------------------------- imports ------------------------------------ */
63 extern int nColorsets
; /* in libs/Colorset.c */
65 /* ---------------------------- included code files ------------------------ */
67 /* ---------------------------- local types -------------------------------- */
69 /* When fvwm destroys pixmaps it puts them on a list and only destroys them
70 * after some period of inactivity. This is necessary because changing colorset
71 * options rapidly may result in a module redrawing itself due to the first
72 * change while the second change is happening. If the module renders something
73 * with the colorset affected by the second change there is a chance it may
74 * reference pixmaps that FvwmTheme has destroyed, bad things would happen */
77 struct junklist
*prev
;
89 /* ---------------------------- forward declarations ----------------------- */
91 /* ---------------------------- local variables ---------------------------- */
93 static char *black
= "black";
94 static char *white
= "white";
95 static char *gray
= "gray";
97 static struct junklist
*junk
= NULL
;
98 static Bool cleanup_scheduled
= False
;
99 static struct root_pic root_pic
= {None
, None
, 0, 0};
101 static char *csetopts
[] =
123 /* these strings are used inside the cases in the switch below! */
128 /* these strings are used inside the cases in the switch below! */
133 /* switch off pixmaps and gradients */
135 /* switch off shape */
138 /* Make the background transparent, copies the root window background */
142 /* tint for the Pixmap or the gradient */
144 "PixmapTint", /* ~ Tint */
145 "ImageTint", /* ~ Tint */
146 "TintMask", /* ~ Tint (backward compatibility) */
147 "NoTint", /* ~ Tint without argument */
152 /* Dither the Pixmap or the gradient */
156 /* alpha for the Pixmap or the gradient */
158 "PixmapAlpha", /* ~ Alpha */
159 "ImageAlpha", /* ~ Alpha */
171 /* ---------------------------- exported variables (globals) --------------- */
173 /* ---------------------------- local functions ---------------------------- */
175 Pixmap
get_root_pixmap(Atom prop
)
179 unsigned long length
, after
;
180 unsigned char *reteval
= NULL
;
184 ret
= XGetWindowProperty(
185 dpy
, Scr
.Root
, prop
, 0L, 1L, False
, XA_PIXMAP
,
186 &type
, &format
, &length
, &after
, &reteval
);
188 ret
== Success
&& type
== XA_PIXMAP
&& format
== 32 &&
189 length
== 1 && after
== 0)
191 pix
= (Pixmap
)(*(long *)reteval
);
200 void update_root_pixmap(Atom prop
)
202 static Atom a_rootpix
= None
;
208 if (a_rootpix
== None
)
210 a_rootpix
= XInternAtom(dpy
,"_XROOTPMAP_ID", False
);
215 pix
= get_root_pixmap(prop
);
216 if (pix
&& !XGetGeometry(
217 dpy
, pix
, &dummy
, (int *)&dummy
, (int *)&dummy
,
218 (unsigned int *)&w
, (unsigned int *)&h
,
219 (unsigned int *)&dummy
, (unsigned int *)&dummy
))
226 pix
= get_root_pixmap(a_rootpix
);
227 if (pix
&& !XGetGeometry(
228 dpy
, pix
, &dummy
, (int *)&dummy
, (int *)&dummy
,
229 (unsigned int *)&w
, (unsigned int *)&h
,
230 (unsigned int *)&dummy
, (unsigned int *)&dummy
))
235 root_pic
.pixmap
= pix
;
239 fprintf(stderr
,"Get New Root Pixmap: 0x%lx %i,%i\n",
240 root_pic
.pixmap
, w
, h
);
244 static void add_to_junk(Pixmap pixmap
)
246 struct junklist
*oldjunk
= junk
;
248 junk
= (struct junklist
*)safemalloc(sizeof(struct junklist
));
249 junk
->prev
= oldjunk
;
250 junk
->pixmap
= pixmap
;
251 if (!cleanup_scheduled
)
253 const exec_context_t
*exc
;
255 exc
= exc_create_null_context();
256 CMD_Schedule(NULL
, exc
, "3000 CleanupColorsets");
257 exc_destroy_context(exc
);
258 cleanup_scheduled
= True
;
264 static char *get_simple_color(
265 char *string
, char **color
, colorset_t
*cs
, int supplied_color
,
266 int special_flag
, char *special_string
)
275 rest
= GetNextToken(string
, color
);
278 if (special_string
&& StrEquals(*color
, special_string
))
282 cs
->color_flags
|= special_flag
;
283 cs
->color_flags
&= ~supplied_color
;
287 cs
->color_flags
|= supplied_color
;
288 cs
->color_flags
&= ~special_flag
;
293 cs
->color_flags
&= ~(supplied_color
| special_flag
);
299 static void SafeDestroyPicture(Display
*dpy
, FvwmPicture
*picture
)
301 /* have to subvert destroy picture so that it doesn't free pixmaps,
302 * these are added to the junk list to be cleaned up after a timeout */
303 if (picture
->count
< 2)
305 if (picture
->picture
)
307 add_to_junk(picture
->picture
);
308 picture
->picture
= None
;
312 add_to_junk(picture
->mask
);
313 picture
->mask
= None
;
317 add_to_junk(picture
->alpha
);
318 picture
->alpha
= None
;
321 /* all that this will now do is free the colors and the name */
322 PDestroyFvwmPicture(dpy
, picture
);
327 static void free_colorset_background(colorset_t
*cs
, Bool do_free_args
)
329 if (cs
->picture
!= NULL
)
331 if (cs
->picture
->picture
!= cs
->pixmap
)
333 add_to_junk(cs
->pixmap
);
335 SafeDestroyPicture(dpy
, cs
->picture
);
338 cs
->alpha_pixmap
= None
; /* alaways equal to picture->alpha */
340 if (cs
->pixmap
&& cs
->pixmap
!= ParentRelative
&&
341 cs
->pixmap
!= root_pic
.pixmap
&& cs
->pixmap
!= root_pic
.old_pixmap
)
343 add_to_junk(cs
->pixmap
);
348 add_to_junk(cs
->mask
);
351 if (cs
->alpha_pixmap
)
353 add_to_junk(cs
->alpha_pixmap
);
354 cs
->alpha_pixmap
= None
;
356 if (cs
->pixels
&& cs
->nalloc_pixels
)
359 dpy
, Pcmap
, cs
->pixels
, cs
->nalloc_pixels
, 0, False
);
362 cs
->nalloc_pixels
= 0;
366 if (cs
->pixmap_args
!= NULL
)
368 free(cs
->pixmap_args
);
369 cs
->pixmap_args
= NULL
;
371 if (cs
->gradient_args
!= NULL
)
373 free(cs
->gradient_args
);
374 cs
->gradient_args
= NULL
;
376 cs
->is_maybe_root_transparent
= False
;
381 static void reset_cs_pixmap(colorset_t
*cs
, GC gc
)
383 if (Pdepth
== cs
->picture
->depth
)
385 XCopyArea(dpy
, cs
->picture
->picture
, cs
->pixmap
, gc
,
386 0, 0, cs
->width
, cs
->height
, 0, 0);
390 XCopyPlane(dpy
, cs
->picture
->picture
, cs
->pixmap
, gc
,
391 0, 0, cs
->width
, cs
->height
, 0, 0, 1);
397 static void parse_pixmap(
398 Window win
, GC gc
, colorset_t
*cs
, Bool
*pixmap_is_a_bitmap
)
400 static char *name
= "parse_colorset(pixmap)";
401 FvwmPictureAttributes fpa
;
407 fpa
.mask
= FPAM_DITHER
;
411 if (!cs
->pixmap_args
)
416 cs
->picture
= PCacheFvwmPicture(dpy
, win
, NULL
, cs
->pixmap_args
, fpa
);
417 if (cs
->picture
== NULL
)
419 fvwm_msg(ERR
, name
, "can't load picture %s", cs
->pixmap_args
);
422 if (cs
->picture
->depth
!= Pdepth
)
424 *pixmap_is_a_bitmap
= True
;
425 cs
->pixmap
= None
; /* build cs->pixmap later */
427 /* copy the picture pixmap into the public structure */
428 cs
->width
= cs
->picture
->width
;
429 cs
->height
= cs
->picture
->height
;
430 cs
->alpha_pixmap
= cs
->picture
->alpha
;
432 if (!*pixmap_is_a_bitmap
)
434 cs
->pixmap
= XCreatePixmap(dpy
, win
,
435 cs
->width
, cs
->height
,
437 XSetClipMask(dpy
, gc
, cs
->picture
->mask
);
438 XCopyArea(dpy
, cs
->picture
->picture
, cs
->pixmap
, gc
,
439 0, 0, cs
->width
, cs
->height
, 0, 0);
440 XSetClipMask(dpy
, gc
, None
);
444 if (cs
->picture
->mask
!= None
)
446 /* make an inverted copy of the mask */
447 cs
->mask
= XCreatePixmap(dpy
, win
,
448 cs
->width
, cs
->height
,
452 XCopyArea(dpy
, cs
->picture
->mask
, cs
->mask
,
454 0, 0, cs
->width
, cs
->height
, 0, 0);
455 /* Invert the mask. We use it to draw the
457 XSetFunction(dpy
, Scr
.MonoGC
, GXinvert
);
458 XFillRectangle(dpy
, cs
->mask
, Scr
.MonoGC
,
459 0, 0, cs
->width
, cs
->height
);
460 XSetFunction(dpy
, Scr
.MonoGC
, GXcopy
);
466 static void parse_shape(Window win
, colorset_t
*cs
, int i
, char *args
,
467 int *has_shape_changed
)
470 static char *name
= "parse_colorset(shape)";
471 FvwmPicture
*picture
;
472 FvwmPictureAttributes fpa
;
474 if (!FHaveShapeExtension
)
476 cs
->shape_mask
= None
;
481 token
= PeekToken(args
, &args
);
482 *has_shape_changed
= True
;
485 add_to_junk(cs
->shape_mask
);
486 cs
->shape_mask
= None
;
490 if (csetopts
[i
][0] == 'T')
492 cs
->shape_type
= SHAPE_TILED
;
494 else if (csetopts
[i
][0] == 'A')
496 cs
->shape_type
= SHAPE_STRETCH_ASPECT
;
500 cs
->shape_type
= SHAPE_STRETCH
;
502 fpa
.mask
= FPAM_NO_ALPHA
;
504 /* try to load the shape mask */
510 /* load the shape mask */
511 picture
= PCacheFvwmPicture(dpy
, win
, NULL
, token
, fpa
);
514 fvwm_msg(ERR
, name
, "can't load picture %s", token
);
516 else if (picture
->depth
!= 1 && picture
->mask
== None
)
518 fvwm_msg(ERR
, name
, "shape pixmap must be of depth 1");
519 SafeDestroyPicture(dpy
, picture
);
525 /* okay, we have what we want */
526 if (picture
->mask
!= None
)
528 mask
= picture
->mask
;
532 mask
= picture
->picture
;
534 cs
->shape_width
= picture
->width
;
535 cs
->shape_height
= picture
->height
;
539 cs
->shape_mask
= XCreatePixmap(
540 dpy
, mask
, picture
->width
, picture
->height
, 1);
541 if (cs
->shape_mask
!= None
)
543 XCopyPlane(dpy
, mask
, cs
->shape_mask
,
544 Scr
.MonoGC
, 0, 0, picture
->width
,
545 picture
->height
, 0, 0, 1);
551 SafeDestroyPicture(dpy
, picture
);
557 static void parse_simple_tint(
558 colorset_t
*cs
, char *args
, char **tint
, int supplied_color
,
559 int *changed
, int *percent
, char *cmd
)
562 static char *name
= "parse_colorset (tint)";
565 rest
= get_simple_color(args
, tint
, cs
, supplied_color
, 0, NULL
);
566 if (!(cs
->color_flags
& supplied_color
))
568 /* restore to default */
571 cs
->color_flags
&= ~(supplied_color
);
573 else if (!GetIntegerArguments(rest
, NULL
, percent
, 1))
576 "%s must have two arguments a color and an integer",
585 else if (*percent
< 0)
591 /* ---------------------------- interface functions ------------------------ */
593 void cleanup_colorsets(void)
595 struct junklist
*oldjunk
= junk
;
599 XFreePixmap(dpy
, junk
->pixmap
);
604 cleanup_scheduled
= False
;
607 /* translate a colorset spec into a colorset structure */
608 void parse_colorset(int n
, char *line
)
626 char *fg_tint
= NULL
;
627 char *bg_tint
= NULL
;
628 char *icon_tint
= NULL
;
629 Bool have_pixels_changed
= False
;
630 Bool has_icon_pixels_changed
= False
;
631 Bool has_fg_changed
= False
;
632 Bool has_bg_changed
= False
;
633 Bool has_sh_changed
= False
;
634 Bool has_hi_changed
= False
;
635 Bool has_fgsh_changed
= False
;
636 Bool has_fg_alpha_changed
= False
;
637 Bool has_tint_changed
= False
;
638 Bool has_fg_tint_changed
= False
;
639 Bool has_bg_tint_changed
= False
;
640 Bool has_icon_tint_changed
= False
;
641 Bool has_pixmap_changed
= False
;
642 Bool has_shape_changed
= False
;
643 Bool has_image_alpha_changed
= False
;
644 Bool pixmap_is_a_bitmap
= False
;
645 Bool do_reload_pixmap
= False
;
646 Bool is_server_grabbed
= False
;
649 static char *name
= "parse_colorset";
650 Window win
= Scr
.NoFocusWin
;
653 /* initialize statics */
656 gc
= fvwmlib_XCreateGC(dpy
, win
, 0, &xgcv
);
659 /* make sure it exists and has sensible contents */
663 /*** Parse the options ***/
664 while (line
&& *line
)
666 /* Read next option specification delimited by a comma or \0.
668 line
= GetQuotedString(
669 line
, &optstring
, ",", NULL
, NULL
, NULL
);
672 args
= GetNextToken(optstring
, &option
);
679 switch((i
= GetTokenIndex(option
, csetopts
, 0, NULL
)))
681 case 0: /* Foreground */
685 args
, &fg
, cs
, FG_SUPPLIED
, FG_CONTRAST
,
687 has_fg_changed
= True
;
689 case 3: /* Background */
693 args
, &bg
, cs
, BG_SUPPLIED
, BG_AVERAGE
,
695 has_bg_changed
= True
;
697 case 6: /* Hilight */
700 get_simple_color(args
, &hi
, cs
, HI_SUPPLIED
, 0, NULL
);
701 has_hi_changed
= True
;
706 get_simple_color(args
, &sh
, cs
, SH_SUPPLIED
, 0, NULL
);
707 has_sh_changed
= True
;
711 args
, &fgsh
, cs
, FGSH_SUPPLIED
, 0,NULL
);
712 has_fgsh_changed
= True
;
714 case 13: /* fg_alpha */
715 case 14: /* fgAlpha */
716 if (GetIntegerArguments(args
, NULL
, &tmp
, 1))
727 if (tmp
!= cs
->fg_alpha_percent
)
729 cs
->fg_alpha_percent
= tmp
;
730 has_fg_alpha_changed
= True
;
733 case 15: /* TiledPixmap */
734 case 16: /* Pixmap */
735 case 17: /* AspectPixmap */
736 has_pixmap_changed
= True
;
737 free_colorset_background(cs
, True
);
738 tmp_str
= PeekToken(args
, &args
);
741 CopyString(&cs
->pixmap_args
, tmp_str
);
742 do_reload_pixmap
= True
;
743 cs
->gradient_type
= 0;
745 if (csetopts
[i
][0] == 'T')
747 cs
->pixmap_type
= PIXMAP_TILED
;
749 else if (csetopts
[i
][0] == 'A')
751 cs
->pixmap_type
= PIXMAP_STRETCH_ASPECT
;
755 cs
->pixmap_type
= PIXMAP_STRETCH
;
758 /* the pixmap is build later */
761 case 19: /* TiledShape */
762 case 20: /* AspectShape */
763 parse_shape(win
, cs
, i
, args
, &has_shape_changed
);
766 has_pixmap_changed
= True
;
767 free_colorset_background(cs
, True
);
769 case 22: /* NoShape */
770 has_shape_changed
= True
;
773 add_to_junk(cs
->shape_mask
);
774 cs
->shape_mask
= None
;
777 case 23: /* Transparent */
779 /* This is only allowable when the root depth == fvwm
780 * visual depth otherwise bad match errors happen,
781 * it may be even more restrictive but my tests (on
782 * exceed 6.2) show that only == depth is necessary */
784 if (Pdepth
!= DefaultDepth(dpy
, (DefaultScreen(dpy
))))
787 ERR
, name
, "can't do Transparent "
788 "when root_depth!=fvwm_depth");
791 has_pixmap_changed
= True
;
792 free_colorset_background(cs
, True
);
793 cs
->pixmap
= ParentRelative
;
794 cs
->pixmap_type
= PIXMAP_STRETCH
;
796 case 24: /* RootTransparent */
797 if (Pdepth
!= DefaultDepth(dpy
, (DefaultScreen(dpy
))))
800 ERR
, name
, "can't do RootTransparent "
801 "when root_depth!=fvwm_depth");
804 free_colorset_background(cs
, True
);
805 has_pixmap_changed
= True
;
806 cs
->pixmap_type
= PIXMAP_ROOT_PIXMAP_PURE
;
807 do_reload_pixmap
= True
;
808 tmp_str
= PeekToken(args
, &args
);
809 if (StrEquals(tmp_str
, "buffer"))
811 cs
->allows_buffered_transparency
= True
;
815 cs
->allows_buffered_transparency
= False
;
817 cs
->is_maybe_root_transparent
= True
;
820 case 26: /* PixmapTint */
821 case 27: /* ImageTint */
822 case 28: /* TintMask */
824 cs
, args
, &tint
, TINT_SUPPLIED
,
825 &has_tint_changed
, &percent
, "tint");
826 if (has_tint_changed
)
828 cs
->tint_percent
= percent
;
831 case 29: /* NoTint */
832 has_tint_changed
= True
;
833 cs
->tint_percent
= 0;
834 cs
->color_flags
&= ~TINT_SUPPLIED
;
836 case 30: /* fgTint */
838 cs
, args
, &fg_tint
, FG_TINT_SUPPLIED
,
839 &has_fg_tint_changed
, &percent
, "fgTint");
840 if (has_fg_tint_changed
)
842 cs
->fg_tint_percent
= percent
;
845 case 31: /* bgTint */
847 cs
, args
, &bg_tint
, BG_TINT_SUPPLIED
,
848 &has_bg_tint_changed
, &percent
, "bgTint");
849 if (has_bg_tint_changed
)
851 cs
->bg_tint_percent
= percent
;
854 case 32: /* dither */
855 if (cs
->pixmap_args
|| cs
->gradient_args
)
857 has_pixmap_changed
= True
;
858 do_reload_pixmap
= True
;
862 case 33: /* nodither */
863 if (cs
->pixmap_args
|| cs
->gradient_args
)
865 has_pixmap_changed
= True
;
866 do_reload_pixmap
= True
;
871 case 35: /* PixmapAlpha */
872 case 36: /* ImageAlpha */
873 if (GetIntegerArguments(args
, NULL
, &tmp
, 1))
884 if (tmp
!= cs
->image_alpha_percent
)
886 has_image_alpha_changed
= True
;
887 cs
->image_alpha_percent
= tmp
;
890 /* dither icon is not dynamic (yet) maybe a bad opt: default
892 case 37: /* ditherIcon */
893 cs
->do_dither_icon
= True
;
895 case 38: /* DoNotDitherIcon */
896 cs
->do_dither_icon
= False
;
898 case 39: /* IconTint */
900 cs
, args
, &icon_tint
, ICON_TINT_SUPPLIED
,
901 &has_icon_tint_changed
, &percent
, "IconTint");
902 if (has_icon_tint_changed
)
904 cs
->icon_tint_percent
= percent
;
905 has_icon_pixels_changed
= True
;
908 case 40: /* NoIconTint */
909 has_icon_tint_changed
= True
;
910 if (cs
->icon_tint_percent
!= 0)
912 has_icon_pixels_changed
= True
;
914 cs
->icon_tint_percent
= 0;
916 case 41: /* IconAlpha */
917 if (GetIntegerArguments(args
, NULL
, &tmp
, 1))
928 if (tmp
!= cs
->icon_alpha_percent
)
930 has_icon_pixels_changed
= True
;
931 cs
->icon_alpha_percent
= tmp
;
935 /* test for ?Gradient */
936 if (option
[0] && StrEquals(&option
[1], "Gradient"))
938 cs
->gradient_type
= toupper(option
[0]);
939 if (!IsGradientTypeSupported(cs
->gradient_type
))
941 has_pixmap_changed
= True
;
942 free_colorset_background(cs
, True
);
943 CopyString(&cs
->gradient_args
, args
);
944 do_reload_pixmap
= True
;
945 if (cs
->gradient_type
== V_GRADIENT
)
947 cs
->pixmap_type
= PIXMAP_STRETCH_Y
;
949 else if (cs
->gradient_type
== H_GRADIENT
)
950 cs
->pixmap_type
= PIXMAP_STRETCH_X
;
952 cs
->pixmap_type
= PIXMAP_STRETCH
;
957 WARN
, name
, "bad colorset pixmap "
958 "specifier %s %s", option
, line
);
970 } /* while (line && *line) */
973 * ---------- change the "pixmap" tint colour ----------
975 if (has_tint_changed
)
977 /* user specified colour */
980 Pixel old_tint
= cs
->tint
;
981 PictureFreeColors(dpy
, Pcmap
, &cs
->tint
, 1, 0, True
);
982 cs
->tint
= GetColor(tint
);
983 if (old_tint
!= cs
->tint
)
985 have_pixels_changed
= True
;
988 else if (tint
== NULL
)
991 Pixel old_tint
= cs
->tint
;
992 PictureFreeColors(dpy
, Pcmap
, &cs
->tint
, 1, 0, True
);
993 cs
->tint
= GetColor(black
);
994 if (old_tint
!= cs
->tint
)
996 have_pixels_changed
= True
;
1002 * reload the gradient if the tint or the alpha have changed.
1003 * Do this too if we need to recompute the bg average and the
1004 * gradient is tinted (perforemence issue).
1006 if ((has_tint_changed
|| has_image_alpha_changed
||
1007 (has_bg_changed
&& (cs
->color_flags
& BG_AVERAGE
) &&
1008 cs
->tint_percent
> 0)) && cs
->gradient_args
)
1010 do_reload_pixmap
= True
;
1014 * reset the pixmap if the tint or the alpha has changed
1016 if (!do_reload_pixmap
&&
1017 (has_tint_changed
|| has_image_alpha_changed
||
1018 (has_bg_changed
&& cs
->alpha_pixmap
!= None
)))
1020 if (cs
->pixmap_type
== PIXMAP_ROOT_PIXMAP_PURE
||
1021 cs
->pixmap_type
== PIXMAP_ROOT_PIXMAP_TRAN
)
1023 do_reload_pixmap
= True
;
1025 else if (cs
->picture
!= NULL
&& cs
->pixmap
)
1027 XSetClipMask(dpy
, gc
, cs
->picture
->mask
);
1028 reset_cs_pixmap(cs
, gc
);
1029 XSetClipMask(dpy
, gc
, None
);
1030 has_pixmap_changed
= True
;
1035 * (re)build the pixmap or the gradient
1037 if (do_reload_pixmap
)
1039 free_colorset_background(cs
, False
);
1040 has_pixmap_changed
= True
;
1041 if (cs
->pixmap_type
== PIXMAP_ROOT_PIXMAP_PURE
||
1042 cs
->pixmap_type
== PIXMAP_ROOT_PIXMAP_TRAN
)
1044 cs
->pixmap_type
= 0;
1045 if (root_pic
.pixmap
)
1047 cs
->pixmap
= root_pic
.pixmap
;
1048 cs
->width
= root_pic
.width
;
1049 cs
->height
= root_pic
.height
;
1050 cs
->pixmap_type
= PIXMAP_ROOT_PIXMAP_PURE
;
1052 fprintf(stderr
,"Cset %i LoadRoot 0x%lx\n",
1057 else if (cs
->pixmap_args
)
1059 parse_pixmap(win
, gc
, cs
, &pixmap_is_a_bitmap
);
1061 else if (cs
->gradient_args
)
1063 cs
->pixmap
= CreateGradientPixmapFromString(
1064 dpy
, win
, gc
, cs
->gradient_type
,
1065 cs
->gradient_args
, &w
, &h
, &cs
->pixels
,
1066 &cs
->nalloc_pixels
, cs
->dither
);
1070 has_pixmap_changed
= True
;
1073 if (cs
->picture
!= NULL
&& cs
->picture
->depth
!= Pdepth
)
1075 pixmap_is_a_bitmap
= True
;
1079 * ---------- change the background colour ----------
1081 if (has_bg_changed
||
1082 (has_pixmap_changed
&& (cs
->color_flags
& BG_AVERAGE
) &&
1083 cs
->pixmap
!= None
&&
1084 cs
->pixmap
!= ParentRelative
&&
1085 !pixmap_is_a_bitmap
))
1087 Bool do_set_default_background
= False
;
1088 Pixmap average_pix
= None
;
1090 if (cs
->color_flags
& BG_AVERAGE
)
1092 if (cs
->picture
!= NULL
&& cs
->picture
->picture
!= None
)
1094 average_pix
= cs
->picture
->picture
;
1096 else if (cs
->pixmap
!= ParentRelative
)
1098 average_pix
= cs
->pixmap
;
1101 if (average_pix
== root_pic
.pixmap
)
1108 is_server_grabbed
= True
;
1110 dpy
, average_pix
, &dummy
,
1111 (int *)&dummy
, (int *)&dummy
,
1112 (unsigned int *)&w
, (unsigned int *)&h
,
1113 (unsigned int *)&dummy
,
1114 (unsigned int *)&dummy
))
1120 if (w
!= cs
->width
|| h
!= cs
->height
)
1125 if (average_pix
== None
)
1127 MyXUngrabServer(dpy
);
1128 is_server_grabbed
= False
;
1133 /* note: no average for bitmap */
1134 if ((cs
->color_flags
& BG_AVERAGE
) && average_pix
)
1136 /* calculate average background color */
1139 XImage
*mask_image
= None
;
1140 unsigned int i
, j
, k
= 0;
1141 unsigned long red
= 0, blue
= 0, green
= 0;
1142 unsigned long tred
, tblue
, tgreen
;
1143 double dred
= 0.0, dblue
= 0.0, dgreen
= 0.0;
1145 has_bg_changed
= True
;
1146 /* create an array to store all the pixmap colors in */
1147 /* Note: this may allocate a lot of memory:
1148 * cs->width * cs->height * 12 and then the rest of the
1149 * procedure can take a lot of times */
1150 colors
= (XColor
*)safemalloc(
1151 cs
->width
* cs
->height
* sizeof(XColor
));
1152 /* get the pixmap and mask into an image */
1154 dpy
, average_pix
, 0, 0, cs
->width
, cs
->height
,
1155 AllPlanes
, ZPixmap
);
1156 if (cs
->mask
!= None
)
1158 mask_image
= XGetImage(
1159 dpy
, cs
->mask
, 0, 0, cs
->width
,
1160 cs
->height
, AllPlanes
, ZPixmap
);
1162 if (is_server_grabbed
== True
)
1164 MyXUngrabServer(dpy
);
1166 if (image
!= None
&& mask_image
!= None
)
1168 /* only fetch the pixels that are not masked
1170 for (i
= 0; i
< cs
->width
; i
++)
1172 for (j
= 0; j
< cs
->height
; j
++)
1191 ERR
, "parse_colorset",
1192 "error reading root background");
1196 XDestroyImage(image
);
1198 if (mask_image
!= None
)
1200 XDestroyImage(mask_image
);
1204 do_set_default_background
= True
;
1208 /* look them all up, XQueryColors() can't
1209 * handle more than 256 */
1210 for (i
= 0; i
< k
; i
+= 256)
1213 dpy
, Pcmap
, &colors
[i
],
1216 /* calculate average, add overflows in a double
1217 * .red is short, red is long */
1218 for (i
= 0; i
< k
; i
++)
1221 red
+= colors
[i
].red
;
1224 dred
+= (double)tred
;
1225 red
= colors
[i
].red
;
1228 green
+= colors
[i
].green
;
1231 dgreen
+= (double)tgreen
;
1232 green
= colors
[i
].green
;
1235 blue
+= colors
[i
].blue
;
1238 dblue
+= (double)tblue
;
1239 blue
= colors
[i
].blue
;
1246 color
.red
= dred
/ k
;
1247 color
.green
= dgreen
/ k
;
1248 color
.blue
= dblue
/ k
;
1250 Pixel old_bg
= cs
->bg
;
1253 dpy
, Pcmap
, &cs
->bg
, 1, 0,
1256 dpy
, Pcmap
, &color
, True
);
1257 cs
->bg
= color
.pixel
;
1258 if (old_bg
!= cs
->bg
)
1260 have_pixels_changed
= True
;
1266 else if ((cs
->color_flags
& BG_SUPPLIED
) && bg
!= NULL
)
1268 /* user specified colour */
1269 Pixel old_bg
= cs
->bg
;
1271 PictureFreeColors(dpy
, Pcmap
, &cs
->bg
, 1, 0, True
);
1272 cs
->bg
= GetColor(bg
);
1273 if (old_bg
!= cs
->bg
)
1275 have_pixels_changed
= True
;
1277 } /* user specified */
1278 else if (bg
== NULL
&& has_bg_changed
)
1281 do_set_default_background
= True
;
1283 if (do_set_default_background
)
1285 Pixel old_bg
= cs
->bg
;
1287 PictureFreeColors(dpy
, Pcmap
, &cs
->bg
, 1, 0, True
);
1288 cs
->bg
= GetColor(white
);
1289 if (old_bg
!= cs
->bg
)
1291 have_pixels_changed
= True
;
1293 has_bg_changed
= True
;
1298 /* save the bg color for tinting */
1299 cs
->bg_saved
= cs
->bg
;
1301 } /* has_bg_changed */
1305 * ---------- setup the bg tint colour ----------
1307 if (has_bg_tint_changed
&& cs
->bg_tint_percent
> 0 && bg_tint
!= NULL
)
1309 PictureFreeColors(dpy
, Pcmap
, &cs
->bg_tint
, 1, 0, True
);
1310 cs
->bg_tint
= GetColor(bg_tint
);
1314 * ---------- tint the bg colour ----------
1316 if (has_bg_tint_changed
|| (has_bg_changed
&& cs
->bg_tint_percent
> 0))
1318 if (cs
->bg_tint_percent
== 0)
1320 Pixel old_bg
= cs
->bg
;
1322 PictureFreeColors(dpy
, Pcmap
, &cs
->bg
, 1, 0, True
);
1323 cs
->bg
= cs
->bg_saved
;
1324 if (old_bg
!= cs
->bg
)
1326 have_pixels_changed
= True
;
1327 has_bg_changed
= True
;
1332 Pixel old_bg
= cs
->bg
;
1334 PictureFreeColors(dpy
, Pcmap
, &cs
->bg
, 1, 0, True
);
1335 cs
->bg
= GetTintedPixel(
1336 cs
->bg_saved
, cs
->bg_tint
, cs
->bg_tint_percent
);
1337 if (old_bg
!= cs
->bg
)
1339 have_pixels_changed
= True
;
1340 has_bg_changed
= True
;
1346 * ---------- setup the fg tint colour ----------
1348 if (has_fg_tint_changed
&& cs
->fg_tint_percent
> 0 && fg_tint
!= NULL
)
1350 PictureFreeColors(dpy
, Pcmap
, &cs
->fg_tint
, 1, 0, True
);
1351 cs
->fg_tint
= GetColor(fg_tint
);
1355 * ---------- change the foreground colour ----------
1357 if (has_fg_changed
||
1358 (has_bg_changed
&& (cs
->color_flags
& FG_CONTRAST
)))
1360 if (cs
->color_flags
& FG_CONTRAST
)
1362 Pixel old_fg
= cs
->fg
;
1364 /* calculate contrasting foreground color */
1365 color
.pixel
= cs
->bg
;
1366 XQueryColor(dpy
, Pcmap
, &color
);
1367 color
.red
= (color
.red
> 32767) ? 0 : 65535;
1368 color
.green
= (color
.green
> 32767) ? 0 : 65535;
1369 color
.blue
= (color
.blue
> 32767) ? 0 : 65535;
1371 PictureFreeColors(dpy
, Pcmap
, &cs
->fg
, 1, 0, True
);
1372 PictureAllocColor(dpy
, Pcmap
, &color
, True
);
1373 cs
->fg
= color
.pixel
;
1374 if (old_fg
!= cs
->fg
)
1376 have_pixels_changed
= True
;
1380 else if ((cs
->color_flags
& FG_SUPPLIED
) && fg
!= NULL
)
1382 /* user specified colour */
1383 Pixel old_fg
= cs
->fg
;
1385 PictureFreeColors(dpy
, Pcmap
, &cs
->fg
, 1, 0, True
);
1386 cs
->fg
= GetColor(fg
);
1387 if (old_fg
!= cs
->fg
)
1389 have_pixels_changed
= True
;
1392 } /* user specified */
1393 else if (fg
== NULL
)
1396 Pixel old_fg
= cs
->fg
;
1398 PictureFreeColors(dpy
, Pcmap
, &cs
->fg
, 1, 0, True
);
1399 cs
->fg
= GetColor(black
);
1400 if (old_fg
!= cs
->fg
)
1402 have_pixels_changed
= True
;
1407 /* save the fg color for tinting */
1408 cs
->fg_saved
= cs
->fg
;
1410 } /* has_fg_changed */
1413 * ---------- tint the foreground colour ----------
1415 if (has_fg_tint_changed
|| (has_fg_changed
&& cs
->fg_tint_percent
> 0))
1417 if (cs
->fg_tint_percent
== 0)
1420 Pixel old_fg
= cs
->fg
;
1422 PictureFreeColors(dpy
, Pcmap
, &cs
->fg
, 1, 0, True
);
1423 cs
->fg
= cs
->fg_saved
;
1424 if (old_fg
!= cs
->fg
)
1426 have_pixels_changed
= True
;
1432 Pixel old_fg
= cs
->fg
;
1434 PictureFreeColors(dpy
, Pcmap
, &cs
->fg
, 1, 0, True
);
1435 cs
->fg
= GetTintedPixel(
1436 cs
->fg_saved
, cs
->fg_tint
,
1437 cs
->fg_tint_percent
);
1438 if (old_fg
!= cs
->fg
)
1440 have_pixels_changed
= True
;
1448 * ---------- change the hilight colour ----------
1450 if (has_hi_changed
||
1451 (has_bg_changed
&& !(cs
->color_flags
& HI_SUPPLIED
)))
1454 if ((cs
->color_flags
& HI_SUPPLIED
) && hi
!= NULL
)
1456 /* user specified colour */
1457 Pixel old_hilite
= cs
->hilite
;
1459 PictureFreeColors(dpy
, Pcmap
, &cs
->hilite
, 1, 0, True
);
1460 cs
->hilite
= GetColor(hi
);
1461 if (old_hilite
!= cs
->hilite
)
1463 have_pixels_changed
= True
;
1465 } /* user specified */
1466 else if (hi
== NULL
)
1468 Pixel old_hilite
= cs
->hilite
;
1470 PictureFreeColors(dpy
, Pcmap
, &cs
->hilite
, 1, 0, True
);
1471 cs
->hilite
= GetHilite(cs
->bg
);
1472 if (old_hilite
!= cs
->hilite
)
1474 have_pixels_changed
= True
;
1477 } /* has_hi_changed */
1480 * ---------- change the shadow colour ----------
1482 if (has_sh_changed
||
1483 (has_bg_changed
&& !(cs
->color_flags
& SH_SUPPLIED
)))
1486 if ((cs
->color_flags
& SH_SUPPLIED
) && sh
!= NULL
)
1488 /* user specified colour */
1489 Pixel old_shadow
= cs
->shadow
;
1491 PictureFreeColors(dpy
, Pcmap
, &cs
->shadow
, 1, 0, True
);
1492 cs
->shadow
= GetColor(sh
);
1493 if (old_shadow
!= cs
->shadow
)
1495 have_pixels_changed
= True
;
1497 } /* user specified */
1498 else if (sh
== NULL
)
1500 Pixel old_shadow
= cs
->shadow
;
1502 PictureFreeColors(dpy
, Pcmap
, &cs
->shadow
, 1, 0, True
);
1503 cs
->shadow
= GetShadow(cs
->bg
);
1504 if (old_shadow
!= cs
->shadow
)
1506 have_pixels_changed
= True
;
1509 } /* has_sh_changed */
1512 * ---------- change the shadow foreground colour ----------
1514 if (has_fgsh_changed
||
1515 ((has_fg_changed
|| has_bg_changed
) &&
1516 !(cs
->color_flags
& FGSH_SUPPLIED
)))
1518 has_fgsh_changed
= 1;
1519 if ((cs
->color_flags
& FGSH_SUPPLIED
) && fgsh
!= NULL
)
1521 /* user specified colour */
1522 Pixel old_fgsh
= cs
->fgsh
;
1524 PictureFreeColors(dpy
, Pcmap
, &cs
->fgsh
, 1, 0, True
);
1525 cs
->fgsh
= GetColor(fgsh
);
1526 if (old_fgsh
!= cs
->fgsh
)
1528 have_pixels_changed
= True
;
1530 } /* user specified */
1531 else if (fgsh
== NULL
)
1533 Pixel old_fgsh
= cs
->fgsh
;
1535 PictureFreeColors(dpy
, Pcmap
, &cs
->fgsh
, 1, 0, True
);
1536 cs
->fgsh
= GetForeShadow(cs
->fg
, cs
->bg
);
1537 if (old_fgsh
!= cs
->fgsh
)
1539 have_pixels_changed
= True
;
1542 } /* has_fgsh_changed */
1545 * ------- the pixmap is a bitmap: create here cs->pixmap -------
1547 if (cs
->picture
!= None
&& pixmap_is_a_bitmap
&&
1548 (has_pixmap_changed
|| has_bg_changed
))
1550 cs
->pixmap
= XCreatePixmap(
1551 dpy
, win
, cs
->width
, cs
->height
, Pdepth
);
1552 XSetBackground(dpy
, gc
, cs
->bg
);
1553 XSetForeground(dpy
, gc
, cs
->fg
);
1554 reset_cs_pixmap(cs
, gc
);
1558 * ------- change the masked out parts of the background pixmap -------
1560 if (cs
->pixmap
!= None
&& cs
->pixmap
!= ParentRelative
&&
1561 (!CSETS_IS_TRANSPARENT_ROOT(cs
)||
1562 cs
->allows_buffered_transparency
) &&
1563 (cs
->mask
!= None
|| cs
->alpha_pixmap
!= None
||
1564 cs
->image_alpha_percent
< 100 || cs
->tint_percent
> 0) &&
1565 (has_pixmap_changed
|| has_bg_changed
|| has_image_alpha_changed
1566 || has_tint_changed
))
1568 /* Now that we know the background colour we can update the
1569 * pixmap background. */
1570 FvwmRenderAttributes fra
;
1571 Pixmap temp
, mask
, alpha
;
1573 memset(&fra
, 0, sizeof(fra
));
1574 temp
= XCreatePixmap(dpy
, win
, cs
->width
, cs
->height
, Pdepth
);
1575 if (cs
->picture
!= NULL
)
1577 mask
= cs
->picture
->mask
;
1578 alpha
= cs
->picture
->alpha
;
1585 XSetForeground(dpy
, gc
, cs
->bg
);
1587 dpy
, temp
, gc
, 0, 0, cs
->width
, cs
->height
);
1589 fra
.mask
= FRAM_HAVE_ADDED_ALPHA
| FRAM_HAVE_TINT
;
1590 fra
.added_alpha_percent
= cs
->image_alpha_percent
;
1591 fra
.tint
= cs
->tint
;
1592 fra
.tint_percent
= cs
->tint_percent
;
1593 PGraphicsRenderPixmaps(
1594 dpy
, win
, cs
->pixmap
, mask
, alpha
, Pdepth
, &fra
,
1595 temp
, gc
, Scr
.MonoGC
, Scr
.AlphaGC
,
1596 0, 0, cs
->width
, cs
->height
,
1597 0, 0, cs
->width
, cs
->height
, False
);
1598 if (cs
->pixmap
!= root_pic
.pixmap
)
1600 add_to_junk(cs
->pixmap
);
1603 has_pixmap_changed
= True
;
1604 if (CSETS_IS_TRANSPARENT_ROOT(cs
))
1606 cs
->pixmap_type
= PIXMAP_ROOT_PIXMAP_TRAN
;
1608 } /* has_pixmap_changed */
1612 * ---------- change the icon tint colour ----------
1614 if (has_icon_tint_changed
)
1616 /* user specified colour */
1617 if (icon_tint
!= NULL
)
1619 Pixel old_tint
= cs
->icon_tint
;
1621 dpy
, Pcmap
, &cs
->icon_tint
, 1, 0, True
);
1622 cs
->icon_tint
= GetColor(icon_tint
);
1623 if (old_tint
!= cs
->icon_tint
)
1625 has_icon_pixels_changed
= True
;
1631 Pixel old_tint
= cs
->icon_tint
;
1633 dpy
, Pcmap
, &cs
->icon_tint
, 1, 0, True
);
1634 cs
->icon_tint
= GetColor(black
);
1635 if (old_tint
!= cs
->icon_tint
)
1637 has_icon_pixels_changed
= True
;
1643 * ---------- send new colorset to fvwm and clean up ----------
1645 /* make sure the server has this to avoid races */
1648 /* inform modules of the change */
1649 if (have_pixels_changed
|| has_pixmap_changed
|| has_shape_changed
||
1650 has_fg_alpha_changed
|| has_icon_pixels_changed
)
1652 BroadcastColorset(n
);
1695 * alloc_colorset() grows the size of the Colorset array to include set n
1696 * colorset_t *Colorset will be altered
1697 * returns the address of the member
1699 void alloc_colorset(int n
)
1701 /* do nothing if it already exists */
1708 Colorset
= (colorset_t
*)saferealloc(
1709 (char *)Colorset
, (n
+ 1) * sizeof(colorset_t
));
1711 &Colorset
[nColorsets
], 0,
1712 (n
+ 1 - nColorsets
) * sizeof(colorset_t
));
1716 update_root_pixmap(0);
1719 /* initialize new colorsets to black on gray */
1720 while (nColorsets
<= n
)
1722 colorset_t
*ncs
= &Colorset
[nColorsets
];
1724 if (PictureUseBWOnly())
1726 char g_bits
[] = {0x0a, 0x05, 0x0a, 0x05,
1727 0x08, 0x02, 0x08, 0x02,
1728 0x01, 0x02, 0x04, 0x08};
1729 /* monochrome monitors get black on white */
1730 /* with a gray pixmap background */
1731 ncs
->fg
= GetColor(black
);
1732 ncs
->bg
= GetColor(white
);
1733 ncs
->hilite
= GetColor(white
);
1734 ncs
->shadow
= GetColor(black
);
1735 ncs
->fgsh
= GetColor(white
);
1736 ncs
->tint
= GetColor(black
);
1737 ncs
->icon_tint
= GetColor(black
);
1738 ncs
->pixmap
= XCreatePixmapFromBitmapData(
1739 dpy
, Scr
.NoFocusWin
,
1740 &g_bits
[4 * (nColorsets
% 3)], 4, 4,
1741 PictureBlackPixel(), PictureWhitePixel(),
1748 ncs
->fg
= GetColor(black
);
1749 ncs
->bg
= GetColor(gray
);
1750 ncs
->hilite
= GetHilite(ncs
->bg
);
1751 ncs
->shadow
= GetShadow(ncs
->bg
);
1752 ncs
->fgsh
= GetForeShadow(ncs
->fg
, ncs
->bg
);
1753 ncs
->tint
= GetColor(black
);
1754 ncs
->icon_tint
= GetColor(black
);
1756 ncs
->fg_tint
= ncs
->bg_tint
= GetColor(black
);
1757 /* set flags for fg contrast, bg average */
1758 /* in case just a pixmap is given */
1759 ncs
->color_flags
= FG_CONTRAST
| BG_AVERAGE
;
1760 ncs
->fg_saved
= ncs
->fg
;
1761 ncs
->fg_alpha_percent
= 100;
1762 ncs
->image_alpha_percent
= 100;
1763 ncs
->icon_alpha_percent
= 100;
1764 ncs
->tint_percent
= 0;
1765 ncs
->icon_tint_percent
= 0;
1766 ncs
->fg_tint_percent
= ncs
->bg_tint_percent
= 0;
1767 ncs
->dither
= (PictureDitherByDefault())? True
:False
;
1772 void update_root_transparent_colorset(Atom prop
)
1777 root_pic
.old_pixmap
= root_pic
.pixmap
;
1778 update_root_pixmap(prop
);
1780 if (!root_pic
.pixmap
)
1785 for (i
=0; i
< nColorsets
; i
++)
1787 Bool root_trans
= False
;
1789 if (cs
->is_maybe_root_transparent
&&
1790 cs
->allows_buffered_transparency
)
1792 parse_colorset(i
, "RootTransparent buffer");
1795 else if (cs
->is_maybe_root_transparent
)
1797 parse_colorset(i
, "RootTransparent");
1802 update_fvwm_colorset(i
);
1807 /* ---------------------------- builtin commands ---------------------------- */
1809 void CMD_ReadWriteColors(F_CMD_ARGS
)
1811 fvwm_msg(WARN
, "CMD_ReadWriteColors", "ReadWriteColors is obsolete");
1816 void CMD_Colorset(F_CMD_ARGS
)
1821 if (GetIntegerArguments(action
, &token
, &n
, 1) != 1)
1833 parse_colorset(n
, token
);
1834 update_fvwm_colorset(n
);
1839 void CMD_CleanupColorsets(F_CMD_ARGS
)
1841 cleanup_colorsets();