3 * Around 12/20/99 we did the 3rd rewrite of the shadow/hilite stuff.
4 * (That I know about (dje).
5 * The first stuff I saw just applied a percentage.
6 * Then we got some code from SCWM.
7 * This stuff comes from "Visual.c" which is part of Lesstif.
8 * Here's their copyright:
10 * Copyright (C) 1995 Free Software Foundation, Inc.
12 * This file is part of the GNU LessTif Library.
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Library General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with this library; if not, write to the Free
26 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 * The routine at the bottom "pixel_to_color_string" was not from Lesstif.
31 * Port by Dan Espen, no additional copyright
34 #include "config.h" /* must be first */
37 #include <X11/Xproto.h> /* for X functions in general */
38 #include "fvwmlib.h" /* prototype GetShadow GetHilit */
41 #include "PictureBase.h"
42 #include "PictureUtils.h"
43 #include "ColorUtils.h"
45 #define PCT_BRIGHTNESS (6 * 0xffff / 100)
47 /* How much lighter/darker to make things in default routine */
49 #define PCT_DARK_BOTTOM 70 /* lighter (less dark, actually) */
50 #define PCT_DARK_TOP 50 /* lighter */
51 #define PCT_LIGHT_BOTTOM 55 /* darker */
52 #define PCT_LIGHT_TOP 80 /* darker */
53 #define PCT_MEDIUM_BOTTOM_BASE 40 /* darker */
54 #define PCT_MEDIUM_BOTTOM_RANGE 25
55 #define PCT_MEDIUM_TOP_BASE 60 /* lighter */
56 #define PCT_MEDIUM_TOP_RANGE -30
58 /* The "brightness" of an RGB color. The "right" way seems to use
59 * empirical values like the default thresholds below, but it boils down
60 * to red is twice as bright as blue and green is thrice blue.
63 #define BRIGHTNESS(r,g,b) (2*(int)(r) + 3*(int)(g) + 1*(int)(b))
65 /* From Xm.h on Solaris */
66 #define XmDEFAULT_DARK_THRESHOLD 15
67 #define XmDEFAULT_LIGHT_THRESHOLD 85
71 /**** This part is the old fvwm way to calculate colours. Still used for
72 **** 'medium' brigness colours. */
73 #define DARKNESS_FACTOR 0.5
74 #define BRIGHTNESS_FACTOR 1.4
76 #define HALF_SCALE (SCALE / 2)
78 R_MAX_G_MIN
, R_MAX_B_MIN
,
79 G_MAX_B_MIN
, G_MAX_R_MIN
,
80 B_MAX_R_MIN
, B_MAX_G_MIN
83 color_mult (unsigned short *red
,
84 unsigned short *green
,
85 unsigned short *blue
, double k
)
87 if (*red
== *green
&& *red
== *blue
) {
90 temp
= k
* (double) (*red
);
94 *red
= (unsigned short)(temp
);
98 /* Non-zero saturation */
104 MinMaxState min_max_state
;
115 min_max_state
= R_MAX_G_MIN
;
119 min_max_state
= R_MAX_B_MIN
;
125 min_max_state
= B_MAX_G_MIN
;
133 min_max_state
= G_MAX_B_MIN
;
137 min_max_state
= G_MAX_R_MIN
;
143 min_max_state
= B_MAX_R_MIN
;
152 if (l
<= HALF_SCALE
) {
155 s
= 2.0 * SCALE
- (max
+ min
);
168 if (l
<= HALF_SCALE
) {
171 max
= s
* SCALE
+ l
- s
* l
;
176 middle
= min
+ delta
* a
;
178 switch (min_max_state
) {
211 *red
= (unsigned short) r
;
212 *green
= (unsigned short) g
;
213 *blue
= (unsigned short) b
;
216 /**** End of original fvwm code. ****/
218 static XColor
*GetShadowOrHiliteColor(
219 Pixel background
, float light
, float dark
, float factor
)
222 unsigned int red
, green
, blue
;
224 memset(&color
, 0, sizeof(color
));
225 color
.pixel
= background
;
226 XQueryColor(Pdpy
, Pcmap
, &color
);
231 brightness
= BRIGHTNESS(red
, green
, blue
);
232 /* For "dark" backgrounds, make everything a fixed %age lighter */
233 if (brightness
< XmDEFAULT_DARK_THRESHOLD
* PCT_BRIGHTNESS
)
235 color
.red
= (unsigned short)
236 (0xffff - ((0xffff - red
) * dark
+ 50) / 100);
237 color
.green
= (unsigned short)
238 (0xffff - ((0xffff - green
) * dark
+ 50) / 100);
239 color
.blue
= (unsigned short)
240 (0xffff - ((0xffff - blue
) * dark
+ 50) / 100);
242 /* For "light" background, make everything a fixed %age darker */
243 else if (brightness
> XmDEFAULT_LIGHT_THRESHOLD
* PCT_BRIGHTNESS
)
246 (unsigned short)((red
* light
+ 50) / 100);
248 (unsigned short)((green
* light
+ 50) / 100);
250 (unsigned short)((blue
* light
+ 50) / 100);
252 /* For "medium" background, select is a fixed %age darker;
253 * top (lighter) and bottom (darker) are a variable %age
254 * based on the background's brightness
258 color_mult(&color
.red
, &color
.green
, &color
.blue
, factor
);
264 XColor
*GetShadowColor(Pixel background
)
266 return GetShadowOrHiliteColor(
267 background
, PCT_LIGHT_BOTTOM
, PCT_DARK_BOTTOM
, DARKNESS_FACTOR
);
270 Pixel
GetShadow(Pixel background
)
274 colorp
= GetShadowColor(background
);
275 PictureAllocColor(Pdpy
, Pcmap
, colorp
, True
);
276 if (colorp
->pixel
== background
)
278 colorp
->pixel
= PictureGetNextColor(colorp
->pixel
, 1);
280 return colorp
->pixel
;
283 XColor
*GetHiliteColor(Pixel background
)
285 return GetShadowOrHiliteColor(
286 background
, PCT_LIGHT_TOP
, PCT_DARK_TOP
, BRIGHTNESS_FACTOR
);
289 Pixel
GetHilite(Pixel background
)
293 colorp
= GetHiliteColor(background
);
294 PictureAllocColor(Pdpy
, Pcmap
, colorp
, True
);
295 if (colorp
->pixel
== background
)
297 colorp
->pixel
= PictureGetNextColor(colorp
->pixel
, -1);
299 return colorp
->pixel
;
302 XColor
*GetForeShadowColor(Pixel foreground
, Pixel background
)
309 memset(&color
, 0, sizeof(color
));
310 memset(&bg_color
, 0, sizeof(bg_color
));
311 color
.pixel
= foreground
;
312 bg_color
.pixel
= background
;
313 XQueryColor(Pdpy
, Pcmap
, &color
);
314 XQueryColor(Pdpy
, Pcmap
, &bg_color
);
318 bg
[0] = bg_color
.red
;
319 bg
[1]= bg_color
.green
;
320 bg
[2] = bg_color
.blue
;
324 if (fg
[i
] - bg
[i
] < 8192 && fg
[i
] - bg
[i
] > -8192)
330 result
[i
] = (int)((5 * bg
[i
] - fg
[i
]) / 4);
331 if (fg
[i
] < bg
[i
] || result
[i
] < 0)
333 result
[i
] = (int)((3 * bg
[i
] + fg
[i
]) / 4);
337 color
.red
= result
[0];
338 color
.green
= result
[1];
339 color
.blue
= result
[2];
344 Pixel
GetForeShadow(Pixel foreground
, Pixel background
)
348 colorp
= GetForeShadowColor(foreground
, background
);
349 PictureAllocColor(Pdpy
, Pcmap
, colorp
, True
);
350 if (colorp
->pixel
== background
)
352 colorp
->pixel
= PictureGetNextColor(colorp
->pixel
, 1);
354 return colorp
->pixel
;
357 XColor
*GetTintedColor(Pixel in
, Pixel tint
, int percent
)
361 memset(&color
, 0, sizeof(color
));
362 memset(&tint_color
, 0, sizeof(tint_color
));
364 XQueryColor(Pdpy
, Pcmap
, &color
);
365 tint_color
.pixel
= tint
;
366 XQueryColor(Pdpy
, Pcmap
, &tint_color
);
368 color
.red
= (unsigned short)
369 (((100-percent
)*color
.red
+ tint_color
.red
* percent
) / 100);
370 color
.green
= (unsigned short)
371 (((100-percent
)*color
.green
+ tint_color
.green
* percent
) /
373 color
.blue
= (unsigned short)
374 (((100-percent
)*color
.blue
+ tint_color
.blue
* percent
) / 100);
378 Pixel
GetTintedPixel(Pixel in
, Pixel tint
, int percent
)
382 colorp
= GetTintedColor(in
, tint
, percent
);
383 PictureAllocColor(Pdpy
, Pcmap
, colorp
, True
);
384 return colorp
->pixel
;
387 /* This function converts the colour stored in a colorcell (pixel) into the
388 * string representation of a colour. The output is printed at the
389 * address 'output'. It is either in rgb format ("rgb:rrrr/gggg/bbbb") if
390 * use_hash is False or in hash notation ("#rrrrggggbbbb") if use_hash is true.
391 * The return value is the number of characters used by the string. The
392 * rgb values of the output are undefined if the colorcell is invalid. The
393 * memory area pointed at by 'output' must be at least 64 bytes (in case of
394 * future extensions and multibyte characters).*/
395 int pixel_to_color_string(
396 Display
*dpy
, Colormap cmap
, Pixel pixel
, char *output
, Bool use_hash
)
406 XQueryColor(dpy
, cmap
, &color
);
410 output
, "rgb:%04x/%04x/%04x%n", (int)color
.red
,
411 (int)color
.green
, (int)color
.blue
, &n
);
416 output
, "#%04x%04x%04x%n", (int)color
.red
,
417 (int)color
.green
, (int)color
.blue
, &n
);
423 static char *colorset_names
[] =
432 Pixel
GetSimpleColor(char *name
)
435 Bool is_illegal_rgb
= False
;
437 memset(&color
, 0, sizeof(color
));
438 /* This is necessary because some X servers coredump when presented a
439 * malformed rgb colour name. */
440 if (name
&& strncasecmp(name
, "rgb:", 4) == 0)
445 for (i
= 0, s
= name
+ 4; *s
; s
++)
451 is_illegal_rgb
= True
;
456 fprintf(stderr
, "Illegal RGB format \"%s\"\n", name
);
458 else if (!XParseColor (Pdpy
, Pcmap
, name
, &color
))
460 fprintf(stderr
, "Cannot parse color \"%s\"\n",
461 name
? name
: "<blank>");
463 else if (!PictureAllocColor(Pdpy
, Pcmap
, &color
, True
))
465 fprintf(stderr
, "Cannot allocate color \"%s\"\n", name
);
470 Pixel
GetColor(char *name
)
478 switch ((i
= GetTokenIndex(name
, colorset_names
, -1, &rest
)))
484 if (!isdigit(*rest
) || (*rest
== '0' && *(rest
+ 1) != 0))
486 /* not a non-negative integer without leading zeros */
488 "Invalid colorset number in color '%s'\n",
492 sscanf(rest
, "%d%n", &cs
, &n
);
493 if (*(rest
+ n
) != ']')
496 "No closing brace after '%d' in color '%s'\n",
500 if (*(rest
+ n
+ 1) != 0)
502 fprintf(stderr
, "Trailing characters after brace in"
503 " color '%s'\n", name
);
510 color
.pixel
= Colorset
[cs
].fg
;
513 color
.pixel
= Colorset
[cs
].bg
;
516 color
.pixel
= Colorset
[cs
].hilite
;
519 color
.pixel
= Colorset
[cs
].shadow
;
522 if (!PictureAllocColor(Pdpy
, Pcmap
, &color
, True
))
524 fprintf(stderr
, "Cannot allocate color %d from"
525 " colorset %d\n", i
, cs
);
534 return GetSimpleColor(name
);
537 /* Allocates the color from the input Pixel again */
538 Pixel
fvwmlib_clone_color(Pixel p
)
543 XQueryColor(Pdpy
, Pcmap
, &c
);
544 if (!PictureAllocColor(Pdpy
, Pcmap
, &c
, True
))
546 fprintf(stderr
, "Cannot allocate clone Pixel %d\n", (int)p
);
553 /* Free an array of colours (n colours), never free black */
554 void fvwmlib_free_colors(Display
*dpy
, Pixel
*pixels
, int n
, Bool no_limit
)
558 /* We don't ever free black - dirty hack to allow freeing colours at
561 for (i
= 0; i
< n
; i
++)
566 dpy
, Pcmap
, pixels
+ i
, 1, 0, no_limit
);
573 /* Copy one color and reallocate it */
574 void fvwmlib_copy_color(
575 Display
*dpy
, Pixel
*dst_color
, Pixel
*src_color
, Bool do_free_dest
,
580 fvwmlib_free_colors(dpy
, dst_color
, 1, True
);
584 *dst_color
= fvwmlib_clone_color(*src_color
);