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
++)
1190 XDestroyImage(image
);
1192 if (mask_image
!= None
)
1194 XDestroyImage(mask_image
);
1198 do_set_default_background
= True
;
1202 /* look them all up, XQueryColors() can't
1203 * handle more than 256 */
1204 for (i
= 0; i
< k
; i
+= 256)
1207 dpy
, Pcmap
, &colors
[i
],
1210 /* calculate average, add overflows in a double
1211 * .red is short, red is long */
1212 for (i
= 0; i
< k
; i
++)
1215 red
+= colors
[i
].red
;
1218 dred
+= (double)tred
;
1219 red
= colors
[i
].red
;
1222 green
+= colors
[i
].green
;
1225 dgreen
+= (double)tgreen
;
1226 green
= colors
[i
].green
;
1229 blue
+= colors
[i
].blue
;
1232 dblue
+= (double)tblue
;
1233 blue
= colors
[i
].blue
;
1240 color
.red
= dred
/ k
;
1241 color
.green
= dgreen
/ k
;
1242 color
.blue
= dblue
/ k
;
1244 Pixel old_bg
= cs
->bg
;
1247 dpy
, Pcmap
, &cs
->bg
, 1, 0,
1250 dpy
, Pcmap
, &color
, True
);
1251 cs
->bg
= color
.pixel
;
1252 if (old_bg
!= cs
->bg
)
1254 have_pixels_changed
= True
;
1260 else if ((cs
->color_flags
& BG_SUPPLIED
) && bg
!= NULL
)
1262 /* user specified colour */
1263 Pixel old_bg
= cs
->bg
;
1265 PictureFreeColors(dpy
, Pcmap
, &cs
->bg
, 1, 0, True
);
1266 cs
->bg
= GetColor(bg
);
1267 if (old_bg
!= cs
->bg
)
1269 have_pixels_changed
= True
;
1271 } /* user specified */
1272 else if (bg
== NULL
&& has_bg_changed
)
1275 do_set_default_background
= True
;
1277 if (do_set_default_background
)
1279 Pixel old_bg
= cs
->bg
;
1281 PictureFreeColors(dpy
, Pcmap
, &cs
->bg
, 1, 0, True
);
1282 cs
->bg
= GetColor(white
);
1283 if (old_bg
!= cs
->bg
)
1285 have_pixels_changed
= True
;
1287 has_bg_changed
= True
;
1292 /* save the bg color for tinting */
1293 cs
->bg_saved
= cs
->bg
;
1295 } /* has_bg_changed */
1299 * ---------- setup the bg tint colour ----------
1301 if (has_bg_tint_changed
&& cs
->bg_tint_percent
> 0 && bg_tint
!= NULL
)
1303 PictureFreeColors(dpy
, Pcmap
, &cs
->bg_tint
, 1, 0, True
);
1304 cs
->bg_tint
= GetColor(bg_tint
);
1308 * ---------- tint the bg colour ----------
1310 if (has_bg_tint_changed
|| (has_bg_changed
&& cs
->bg_tint_percent
> 0))
1312 if (cs
->bg_tint_percent
== 0)
1314 Pixel old_bg
= cs
->bg
;
1316 PictureFreeColors(dpy
, Pcmap
, &cs
->bg
, 1, 0, True
);
1317 cs
->bg
= cs
->bg_saved
;
1318 if (old_bg
!= cs
->bg
)
1320 have_pixels_changed
= True
;
1321 has_bg_changed
= True
;
1326 Pixel old_bg
= cs
->bg
;
1328 PictureFreeColors(dpy
, Pcmap
, &cs
->bg
, 1, 0, True
);
1329 cs
->bg
= GetTintedPixel(
1330 cs
->bg_saved
, cs
->bg_tint
, cs
->bg_tint_percent
);
1331 if (old_bg
!= cs
->bg
)
1333 have_pixels_changed
= True
;
1334 has_bg_changed
= True
;
1340 * ---------- setup the fg tint colour ----------
1342 if (has_fg_tint_changed
&& cs
->fg_tint_percent
> 0 && fg_tint
!= NULL
)
1344 PictureFreeColors(dpy
, Pcmap
, &cs
->fg_tint
, 1, 0, True
);
1345 cs
->fg_tint
= GetColor(fg_tint
);
1349 * ---------- change the foreground colour ----------
1351 if (has_fg_changed
||
1352 (has_bg_changed
&& (cs
->color_flags
& FG_CONTRAST
)))
1354 if (cs
->color_flags
& FG_CONTRAST
)
1356 Pixel old_fg
= cs
->fg
;
1358 /* calculate contrasting foreground color */
1359 color
.pixel
= cs
->bg
;
1360 XQueryColor(dpy
, Pcmap
, &color
);
1361 color
.red
= (color
.red
> 32767) ? 0 : 65535;
1362 color
.green
= (color
.green
> 32767) ? 0 : 65535;
1363 color
.blue
= (color
.blue
> 32767) ? 0 : 65535;
1365 PictureFreeColors(dpy
, Pcmap
, &cs
->fg
, 1, 0, True
);
1366 PictureAllocColor(dpy
, Pcmap
, &color
, True
);
1367 cs
->fg
= color
.pixel
;
1368 if (old_fg
!= cs
->fg
)
1370 have_pixels_changed
= True
;
1374 else if ((cs
->color_flags
& FG_SUPPLIED
) && fg
!= NULL
)
1376 /* user specified colour */
1377 Pixel old_fg
= cs
->fg
;
1379 PictureFreeColors(dpy
, Pcmap
, &cs
->fg
, 1, 0, True
);
1380 cs
->fg
= GetColor(fg
);
1381 if (old_fg
!= cs
->fg
)
1383 have_pixels_changed
= True
;
1386 } /* user specified */
1387 else if (fg
== NULL
)
1390 Pixel old_fg
= cs
->fg
;
1392 PictureFreeColors(dpy
, Pcmap
, &cs
->fg
, 1, 0, True
);
1393 cs
->fg
= GetColor(black
);
1394 if (old_fg
!= cs
->fg
)
1396 have_pixels_changed
= True
;
1401 /* save the fg color for tinting */
1402 cs
->fg_saved
= cs
->fg
;
1404 } /* has_fg_changed */
1407 * ---------- tint the foreground colour ----------
1409 if (has_fg_tint_changed
|| (has_fg_changed
&& cs
->fg_tint_percent
> 0))
1411 if (cs
->fg_tint_percent
== 0)
1414 Pixel old_fg
= cs
->fg
;
1416 PictureFreeColors(dpy
, Pcmap
, &cs
->fg
, 1, 0, True
);
1417 cs
->fg
= cs
->fg_saved
;
1418 if (old_fg
!= cs
->fg
)
1420 have_pixels_changed
= True
;
1426 Pixel old_fg
= cs
->fg
;
1428 PictureFreeColors(dpy
, Pcmap
, &cs
->fg
, 1, 0, True
);
1429 cs
->fg
= GetTintedPixel(
1430 cs
->fg_saved
, cs
->fg_tint
,
1431 cs
->fg_tint_percent
);
1432 if (old_fg
!= cs
->fg
)
1434 have_pixels_changed
= True
;
1442 * ---------- change the hilight colour ----------
1444 if (has_hi_changed
||
1445 (has_bg_changed
&& !(cs
->color_flags
& HI_SUPPLIED
)))
1448 if ((cs
->color_flags
& HI_SUPPLIED
) && hi
!= NULL
)
1450 /* user specified colour */
1451 Pixel old_hilite
= cs
->hilite
;
1453 PictureFreeColors(dpy
, Pcmap
, &cs
->hilite
, 1, 0, True
);
1454 cs
->hilite
= GetColor(hi
);
1455 if (old_hilite
!= cs
->hilite
)
1457 have_pixels_changed
= True
;
1459 } /* user specified */
1460 else if (hi
== NULL
)
1462 Pixel old_hilite
= cs
->hilite
;
1464 PictureFreeColors(dpy
, Pcmap
, &cs
->hilite
, 1, 0, True
);
1465 cs
->hilite
= GetHilite(cs
->bg
);
1466 if (old_hilite
!= cs
->hilite
)
1468 have_pixels_changed
= True
;
1471 } /* has_hi_changed */
1474 * ---------- change the shadow colour ----------
1476 if (has_sh_changed
||
1477 (has_bg_changed
&& !(cs
->color_flags
& SH_SUPPLIED
)))
1480 if ((cs
->color_flags
& SH_SUPPLIED
) && sh
!= NULL
)
1482 /* user specified colour */
1483 Pixel old_shadow
= cs
->shadow
;
1485 PictureFreeColors(dpy
, Pcmap
, &cs
->shadow
, 1, 0, True
);
1486 cs
->shadow
= GetColor(sh
);
1487 if (old_shadow
!= cs
->shadow
)
1489 have_pixels_changed
= True
;
1491 } /* user specified */
1492 else if (sh
== NULL
)
1494 Pixel old_shadow
= cs
->shadow
;
1496 PictureFreeColors(dpy
, Pcmap
, &cs
->shadow
, 1, 0, True
);
1497 cs
->shadow
= GetShadow(cs
->bg
);
1498 if (old_shadow
!= cs
->shadow
)
1500 have_pixels_changed
= True
;
1503 } /* has_sh_changed */
1506 * ---------- change the shadow foreground colour ----------
1508 if (has_fgsh_changed
||
1509 ((has_fg_changed
|| has_bg_changed
) &&
1510 !(cs
->color_flags
& FGSH_SUPPLIED
)))
1512 has_fgsh_changed
= 1;
1513 if ((cs
->color_flags
& FGSH_SUPPLIED
) && fgsh
!= NULL
)
1515 /* user specified colour */
1516 Pixel old_fgsh
= cs
->fgsh
;
1518 PictureFreeColors(dpy
, Pcmap
, &cs
->fgsh
, 1, 0, True
);
1519 cs
->fgsh
= GetColor(fgsh
);
1520 if (old_fgsh
!= cs
->fgsh
)
1522 have_pixels_changed
= True
;
1524 } /* user specified */
1525 else if (fgsh
== NULL
)
1527 Pixel old_fgsh
= cs
->fgsh
;
1529 PictureFreeColors(dpy
, Pcmap
, &cs
->fgsh
, 1, 0, True
);
1530 cs
->fgsh
= GetForeShadow(cs
->fg
, cs
->bg
);
1531 if (old_fgsh
!= cs
->fgsh
)
1533 have_pixels_changed
= True
;
1536 } /* has_fgsh_changed */
1539 * ------- the pixmap is a bitmap: create here cs->pixmap -------
1541 if (cs
->picture
!= None
&& pixmap_is_a_bitmap
&&
1542 (has_pixmap_changed
|| has_bg_changed
))
1544 cs
->pixmap
= XCreatePixmap(
1545 dpy
, win
, cs
->width
, cs
->height
, Pdepth
);
1546 XSetBackground(dpy
, gc
, cs
->bg
);
1547 XSetForeground(dpy
, gc
, cs
->fg
);
1548 reset_cs_pixmap(cs
, gc
);
1552 * ------- change the masked out parts of the background pixmap -------
1554 if (cs
->pixmap
!= None
&& cs
->pixmap
!= ParentRelative
&&
1555 (!CSETS_IS_TRANSPARENT_ROOT(cs
)||
1556 cs
->allows_buffered_transparency
) &&
1557 (cs
->mask
!= None
|| cs
->alpha_pixmap
!= None
||
1558 cs
->image_alpha_percent
< 100 || cs
->tint_percent
> 0) &&
1559 (has_pixmap_changed
|| has_bg_changed
|| has_image_alpha_changed
1560 || has_tint_changed
))
1562 /* Now that we know the background colour we can update the
1563 * pixmap background. */
1564 FvwmRenderAttributes fra
;
1565 Pixmap temp
, mask
, alpha
;
1567 memset(&fra
, 0, sizeof(fra
));
1568 temp
= XCreatePixmap(dpy
, win
, cs
->width
, cs
->height
, Pdepth
);
1569 if (cs
->picture
!= NULL
)
1571 mask
= cs
->picture
->mask
;
1572 alpha
= cs
->picture
->alpha
;
1579 XSetForeground(dpy
, gc
, cs
->bg
);
1581 dpy
, temp
, gc
, 0, 0, cs
->width
, cs
->height
);
1583 fra
.mask
= FRAM_HAVE_ADDED_ALPHA
| FRAM_HAVE_TINT
;
1584 fra
.added_alpha_percent
= cs
->image_alpha_percent
;
1585 fra
.tint
= cs
->tint
;
1586 fra
.tint_percent
= cs
->tint_percent
;
1587 PGraphicsRenderPixmaps(
1588 dpy
, win
, cs
->pixmap
, mask
, alpha
, Pdepth
, &fra
,
1589 temp
, gc
, Scr
.MonoGC
, Scr
.AlphaGC
,
1590 0, 0, cs
->width
, cs
->height
,
1591 0, 0, cs
->width
, cs
->height
, False
);
1592 if (cs
->pixmap
!= root_pic
.pixmap
)
1594 add_to_junk(cs
->pixmap
);
1597 has_pixmap_changed
= True
;
1598 if (CSETS_IS_TRANSPARENT_ROOT(cs
))
1600 cs
->pixmap_type
= PIXMAP_ROOT_PIXMAP_TRAN
;
1602 } /* has_pixmap_changed */
1606 * ---------- change the icon tint colour ----------
1608 if (has_icon_tint_changed
)
1610 /* user specified colour */
1611 if (icon_tint
!= NULL
)
1613 Pixel old_tint
= cs
->icon_tint
;
1615 dpy
, Pcmap
, &cs
->icon_tint
, 1, 0, True
);
1616 cs
->icon_tint
= GetColor(icon_tint
);
1617 if (old_tint
!= cs
->icon_tint
)
1619 has_icon_pixels_changed
= True
;
1625 Pixel old_tint
= cs
->icon_tint
;
1627 dpy
, Pcmap
, &cs
->icon_tint
, 1, 0, True
);
1628 cs
->icon_tint
= GetColor(black
);
1629 if (old_tint
!= cs
->icon_tint
)
1631 has_icon_pixels_changed
= True
;
1637 * ---------- send new colorset to fvwm and clean up ----------
1639 /* make sure the server has this to avoid races */
1642 /* inform modules of the change */
1643 if (have_pixels_changed
|| has_pixmap_changed
|| has_shape_changed
||
1644 has_fg_alpha_changed
|| has_icon_pixels_changed
)
1646 BroadcastColorset(n
);
1689 * alloc_colorset() grows the size of the Colorset array to include set n
1690 * colorset_t *Colorset will be altered
1691 * returns the address of the member
1693 void alloc_colorset(int n
)
1695 /* do nothing if it already exists */
1702 Colorset
= (colorset_t
*)saferealloc(
1703 (char *)Colorset
, (n
+ 1) * sizeof(colorset_t
));
1705 &Colorset
[nColorsets
], 0,
1706 (n
+ 1 - nColorsets
) * sizeof(colorset_t
));
1710 update_root_pixmap(0);
1713 /* initialize new colorsets to black on gray */
1714 while (nColorsets
<= n
)
1716 colorset_t
*ncs
= &Colorset
[nColorsets
];
1718 if (PictureUseBWOnly())
1720 char g_bits
[] = {0x0a, 0x05, 0x0a, 0x05,
1721 0x08, 0x02, 0x08, 0x02,
1722 0x01, 0x02, 0x04, 0x08};
1723 /* monochrome monitors get black on white */
1724 /* with a gray pixmap background */
1725 ncs
->fg
= GetColor(black
);
1726 ncs
->bg
= GetColor(white
);
1727 ncs
->hilite
= GetColor(white
);
1728 ncs
->shadow
= GetColor(black
);
1729 ncs
->fgsh
= GetColor(white
);
1730 ncs
->tint
= GetColor(black
);
1731 ncs
->icon_tint
= GetColor(black
);
1732 ncs
->pixmap
= XCreatePixmapFromBitmapData(
1733 dpy
, Scr
.NoFocusWin
,
1734 &g_bits
[4 * (nColorsets
% 3)], 4, 4,
1735 PictureBlackPixel(), PictureWhitePixel(),
1742 ncs
->fg
= GetColor(black
);
1743 ncs
->bg
= GetColor(gray
);
1744 ncs
->hilite
= GetHilite(ncs
->bg
);
1745 ncs
->shadow
= GetShadow(ncs
->bg
);
1746 ncs
->fgsh
= GetForeShadow(ncs
->fg
, ncs
->bg
);
1747 ncs
->tint
= GetColor(black
);
1748 ncs
->icon_tint
= GetColor(black
);
1750 ncs
->fg_tint
= ncs
->bg_tint
= GetColor(black
);
1751 /* set flags for fg contrast, bg average */
1752 /* in case just a pixmap is given */
1753 ncs
->color_flags
= FG_CONTRAST
| BG_AVERAGE
;
1754 ncs
->fg_saved
= ncs
->fg
;
1755 ncs
->fg_alpha_percent
= 100;
1756 ncs
->image_alpha_percent
= 100;
1757 ncs
->icon_alpha_percent
= 100;
1758 ncs
->tint_percent
= 0;
1759 ncs
->icon_tint_percent
= 0;
1760 ncs
->fg_tint_percent
= ncs
->bg_tint_percent
= 0;
1761 ncs
->dither
= (PictureDitherByDefault())? True
:False
;
1766 void update_root_transparent_colorset(Atom prop
)
1771 root_pic
.old_pixmap
= root_pic
.pixmap
;
1772 update_root_pixmap(prop
);
1774 if (!root_pic
.pixmap
)
1779 for (i
=0; i
< nColorsets
; i
++)
1781 Bool root_trans
= False
;
1783 if (cs
->is_maybe_root_transparent
&&
1784 cs
->allows_buffered_transparency
)
1786 parse_colorset(i
, "RootTransparent buffer");
1789 else if (cs
->is_maybe_root_transparent
)
1791 parse_colorset(i
, "RootTransparent");
1796 update_fvwm_colorset(i
);
1801 /* ---------------------------- builtin commands ---------------------------- */
1803 void CMD_ReadWriteColors(F_CMD_ARGS
)
1805 fvwm_msg(WARN
, "CMD_ReadWriteColors", "ReadWriteColors is obsolete");
1810 void CMD_Colorset(F_CMD_ARGS
)
1815 if (GetIntegerArguments(action
, &token
, &n
, 1) != 1)
1827 parse_colorset(n
, token
);
1828 update_fvwm_colorset(n
);
1833 void CMD_CleanupColorsets(F_CMD_ARGS
)
1835 cleanup_colorsets();