diff --git a/Makefile.in b/Makefile.in index f29a06e..e3ab8a8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -27,6 +27,7 @@ src/systray.c \ src/tag.c \ src/util.c \ src/viwmfs.c \ +src/color.c \ src/wmfs.c # flags diff --git a/src/barwin.c b/src/barwin.c index 13ce885..49f7eb8 100644 --- a/src/barwin.c +++ b/src/barwin.c @@ -82,10 +82,10 @@ barwin_create(Window parent, { bw->bord = True; - CWIN(bw->border.left, bw->win, 0, 0, SHADH, h, 0, CWBackPixel, color_enlight(bg), &at); - CWIN(bw->border.top, bw->win, 0, 0, w, SHADH, 0, CWBackPixel, color_enlight(bg), &at); - CWIN(bw->border.bottom, bw->win, 0, h - SHADH, w, SHADH, 0, CWBackPixel, SHADC, &at); - CWIN(bw->border.right, bw->win, w - SHADH, 0, SHADH, h, 0, CWBackPixel, SHADC, &at); + CWIN(bw->border.left, bw->win, 0, 0, SHADH, h, 0, CWBackPixel, bg, &at); + CWIN(bw->border.top, bw->win, 0, 0, w, SHADH, 0, CWBackPixel, bg, &at); + CWIN(bw->border.bottom, bw->win, 0, h - SHADH, w, SHADH, 0, CWBackPixel, bg, &at); + CWIN(bw->border.right, bw->win, w - SHADH, 0, SHADH, h, 0, CWBackPixel, bg, &at); } /* Property */ @@ -95,8 +95,8 @@ barwin_create(Window parent, bw->geo.height = h; bw->bg = bg; bw->fg = fg; - bw->border.light = color_enlight(bg); - bw->border.dark = SHADC; + bw->border.light = color_shade(bg, conf.colors.bar_light_shade); + bw->border.dark = color_shade(bg, conf.colors.bar_dark_shade); bw->stipple = stipple; bw->stipple_color = -1; @@ -299,10 +299,10 @@ barwin_refresh_color(BarWindow *bw) if(bw->bord) { - XSetWindowBackground(dpy, bw->border.left, bw->border.light); - XSetWindowBackground(dpy, bw->border.top, bw->border.light); - XSetWindowBackground(dpy, bw->border.bottom, bw->border.dark); - XSetWindowBackground(dpy, bw->border.right, bw->border.dark); + XSetWindowBackground(dpy, bw->border.left, color_shade(bw->bg, conf.colors.bar_light_shade)); + XSetWindowBackground(dpy, bw->border.top, color_shade(bw->bg, conf.colors.bar_light_shade)); + XSetWindowBackground(dpy, bw->border.bottom, color_shade(bw->bg, conf.colors.bar_dark_shade)); + XSetWindowBackground(dpy, bw->border.right, color_shade(bw->bg, conf.colors.bar_dark_shade)); XClearWindow(dpy, bw->border.left); XClearWindow(dpy, bw->border.top); diff --git a/src/color.c b/src/color.c new file mode 100644 index 0000000..cd77454 --- /dev/null +++ b/src/color.c @@ -0,0 +1,229 @@ +/* +* color.c +* Copyright © 2011 Brian Mock +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following disclaimer +* in the documentation and/or other materials provided with the +* distribution. +* * Neither the name of the nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "wmfs.h" + +static void color_unpack_rgb(uint, uint*, uint*, uint*); +static void color_rgb_to_hsl(uint, uint, uint, double*, double*, double*); +static void color_hsl_to_rgb(double, double, double, uint*, uint*, uint*); +static double color_clamp(double, double, double); +static uint color_pack_rgb(uint, uint, uint); + +/** Shades a color by the amount. This works by converting a packed RGB + * color to HSL, adding the amount to the lightness, + * and then converting back to RGB. 1.0 is max lightness, 0.0 is min lightness. + * \param shadeVal the amount to shade the lightness by. + * \return the shaded color + */ +uint +color_shade(uint rgb, double shadeVal) +{ + uint r, g, b; + double h, s, l; + + color_unpack_rgb(rgb, &r, &g, &b); + color_rgb_to_hsl(r, g, b, &h, &s, &l); + + l += shadeVal; + + l = color_clamp(l, 0, 1); + + color_hsl_to_rgb(h, s, l, &r, &g, &b); + rgb = color_pack_rgb(r, g, b); + + return rgb; +} + +/** Clamp a number x within the range [a, b]. + * \param x the number which to clamp + * \param a the lowest possible value + * \param b the highest possible value + * \return the clamped number + */ +static double +color_clamp(double x, double a, double b) +{ + if(x < a) + return a; + else if(x > b) + return b; + else + return x; +} + +/** Pack a triplet of RGB values into a single uint + * \param r the red value + * \param g the green value + * \param b the blue value + * \return the packed RGB value + */ +static uint +color_pack_rgb(uint r, uint g, uint b) +{ + return (r << 16) | (g << 8) | b; +} + +/** Unpack an RGB uint into three separate values + * \param rgb the packed color + * \param r a pointer to a uint where the red value will be stored + * \param g a pointer to a uint where the green value will be stored + * \param b a pointer to a uint where the blue value will be stored + */ +static void +color_unpack_rgb(uint rgb, uint *r, uint *g, uint *b) +{ + *r = (rgb >> 16) & 0xFF; + *g = (rgb >> 8) & 0xFF; + *b = rgb & 0xFF; +} + +/** Convert unpacked RGB values into HSL, storing in the doubles referenced + * by the pointers h, s, l + */ +static void +color_rgb_to_hsl(uint xr, uint xg, uint xb, double *h, double *s, double *l) +{ + double r = xr/255.0; + double g = xg/255.0; + double b = xb/255.0; + + double v; + double m; + double vm; + double r2, g2, b2; + + *h = 0; + *s = 0; + *l = 0; + + /* v is max(r, g, b) + * m is min(r, g, b) + */ + v = r > g ? r : g; + v = v > b ? v : b; + m = r < g ? r : g; + m = m < b ? m : b; + + *l = (m + v)/2.0; + + if(*l <= 0.0) + return; + + vm = v - m; + *s = vm; + + if(*s > 0.0) + *s /= (*l <= 0.5) ? (v + m) : (2.0 - v - m); + else + return; + + r2 = (v - r)/vm; + g2 = (v - g)/vm; + b2 = (v - b)/vm; + + if(r == v) + *h = (g == m ? 5.0 + b2 : 1.0 - g2); + else if(g == v) + *h = (b == m ? 1.0 + r2 : 3.0 - b2); + else + *h = (r == m ? 3.0 + g2 : 5.0 - r2); + + *h /= 6.0; +} + +/** Convert h, s, l values to RGB and store them in the three uint + * referenced by the last three parameters. + */ +static void +color_hsl_to_rgb(double h, double sl, double l, uint *rx, uint *gx, uint *bx) +{ + double v; + double r,g,b; + + r = l; + g = l; + b = l; + v = (l <= 0.5) ? (l * (1.0 + sl)) : (l + sl - l * sl); + if(v > 0) + { + double m; + double sv; + int sextant; + double fract, vsf, mid1, mid2; + + m = l + l - v; + sv = (v - m ) / v; + h *= 6.0; + sextant = (int) h; + fract = h - sextant; + vsf = v * sv * fract; + mid1 = m + vsf; + mid2 = v - vsf; + switch(sextant) + { + case 0: + r = v; + g = mid1; + b = m; + break; + case 1: + r = mid2; + g = v; + b = m; + break; + case 2: + r = m; + g = v; + b = mid1; + break; + case 3: + r = m; + g = mid2; + b = v; + break; + case 4: + r = mid1; + g = m; + b = v; + break; + case 5: + r = v; + g = m; + b = mid2; + break; + } + } + + *rx = r * 255.0; + *gx = g * 255.0; + *bx = b * 255.0; +} diff --git a/src/config.c b/src/config.c index 264b87f..2d7c74d 100644 --- a/src/config.c +++ b/src/config.c @@ -203,6 +203,9 @@ conf_bar_section(void) conf.colors.bar = getcolor((barbg = fetch_opt_first(bar, "#000000", "bg").str)); conf.colors.text = fetch_opt_first(bar, "#ffffff", "fg").str; + conf.colors.bar_light_shade = fetch_opt_first(bar, "0.25", "light_shade").fnum; + conf.colors.bar_dark_shade = fetch_opt_first(bar, "-0.25", "dark_shade").fnum; + mouse = fetch_section(bar, "mouse"); if ((conf.bars.nmouse = fetch_section_count(mouse)) > 0) @@ -301,6 +304,9 @@ conf_client_section(void) conf.client.default_open_screen = fetch_opt_first(sec, "-1", "default_open_screen").num; conf.client.new_client_get_mouse = fetch_opt_first(sec, "false", "new_client_get_mouse").bool; + conf.colors.client_light_shade = fetch_opt_first(sec, "0.25", "light_shade").fnum; + conf.colors.client_dark_shade = fetch_opt_first(sec, "-0.25", "dark_shade").fnum; + mouse = fetch_section(sec, "mouse"); if((conf.client.nmouse = fetch_section_count(mouse)) > 0) @@ -789,12 +795,12 @@ conf_keybind_section(void) void init_conf(void) { - if (get_conf(conf.confpath) == -1) + if(get_conf(conf.confpath) == -1) { warnx("parsing configuration file (%s) failed.", conf.confpath); sprintf(conf.confpath, "%s/wmfs/wmfsrc", XDG_CONFIG_DIR); warnx("Use the default configuration (%s).", conf.confpath); - if (get_conf(conf.confpath) == -1) + if(get_conf(conf.confpath) == -1) errx(1, "parsing configuration file (%s) failed.", conf.confpath); } diff --git a/src/frame.c b/src/frame.c index 9dd8f52..22d7ff8 100644 --- a/src/frame.c +++ b/src/frame.c @@ -118,10 +118,10 @@ frame_create(Client *c) /* Border (for shadow) */ if(conf.client.border_shadow) { - CWIN(c->left, c->frame, 0, 0, SHADH, c->frame_geo.height, 0, CWBackPixel, color_enlight(c->colors.frame), &at); - CWIN(c->top, c->frame, 0, 0, c->frame_geo.width, SHADH, 0, CWBackPixel, color_enlight(c->colors.frame), &at); - CWIN(c->bottom, c->frame, 0, c->frame_geo.height - SHADH, c->frame_geo.width, SHADH, 0, CWBackPixel, SHADC, &at); - CWIN(c->right, c->frame, c->frame_geo.width - SHADH, 0, SHADH, c->frame_geo.height, 0, CWBackPixel, SHADC, &at); + CWIN(c->left, c->frame, 0, 0, SHADH, c->frame_geo.height, 0, CWBackPixel, c->colors.frame, &at); + CWIN(c->top, c->frame, 0, 0, c->frame_geo.width, SHADH, 0, CWBackPixel, c->colors.frame, &at); + CWIN(c->bottom, c->frame, 0, c->frame_geo.height - SHADH, c->frame_geo.width, SHADH, 0, CWBackPixel, c->colors.frame, &at); + CWIN(c->right, c->frame, c->frame_geo.width - SHADH, 0, SHADH, c->frame_geo.height, 0, CWBackPixel, c->colors.frame, &at); } /* Reparent window with the frame */ @@ -258,10 +258,10 @@ frame_update(Client *c) if(conf.client.border_shadow) { - XSetWindowBackground(dpy, c->left, color_enlight(c->colors.frame)); - XSetWindowBackground(dpy, c->top, color_enlight(c->colors.frame)); - XSetWindowBackground(dpy, c->right, SHADC); - XSetWindowBackground(dpy, c->bottom, SHADC); + XSetWindowBackground(dpy, c->left, color_shade(c->colors.frame, conf.colors.client_light_shade)); + XSetWindowBackground(dpy, c->top, color_shade(c->colors.frame, conf.colors.client_light_shade)); + XSetWindowBackground(dpy, c->right, color_shade(c->colors.frame, conf.colors.client_dark_shade)); + XSetWindowBackground(dpy, c->bottom, color_shade(c->colors.frame, conf.colors.client_dark_shade)); XClearWindow(dpy, c->left); XClearWindow(dpy, c->top); diff --git a/src/structs.h b/src/structs.h index 1ee0aa9..cf540f2 100644 --- a/src/structs.h +++ b/src/structs.h @@ -410,6 +410,10 @@ typedef struct uint tagbord; char *layout_fg; uint layout_bg; + float client_light_shade; + float client_dark_shade; + float bar_light_shade; + float bar_dark_shade; } colors; struct { diff --git a/src/util.c b/src/util.c index 59cbe61..cbc1382 100644 --- a/src/util.c +++ b/src/util.c @@ -142,21 +142,6 @@ getcolor(char *color) return xcolor.pixel; } -/** Enlight an hexadecimal color - * \param col Color - * \return The clarified color -*/ -ulong -color_enlight(ulong col) -{ - if((col + 0x330000) < 0xffffff - && (col + 0x003300) < 0xffffff - && (col + 0x000033) < 0xffffff) - return col + 0x333333; - else - return col; -} - /** Set the window WM State * \param win Window target * \param state WM State diff --git a/src/wmfs.h b/src/wmfs.h index e7955e5..46b6c47 100644 --- a/src/wmfs.h +++ b/src/wmfs.h @@ -86,7 +86,6 @@ #define INFOBARH ((conf.bars.height > 0) ? conf.bars.height : (font->height * 1.5)) #define FHINFOBAR ((font->height - font->descent) + (INFOBARH - font->height) / 2) #define SHADH (1) -#define SHADC (0x000000) /* 'Cause i don't know how darken a color yet */ #define BORDH conf.client.borderheight #define TBARH ((conf.titlebar.height < BORDH) ? BORDH : conf.titlebar.height) #define RESHW (6 * (BORDH)) @@ -233,6 +232,9 @@ void frame_update(Client *c); /* config.c */ void init_conf(void); +/* color.c */ +uint color_shade(uint, double); + /* event.c */ void buttonpress(XButtonEvent *ev); void configureevent(XConfigureRequestEvent *ev); @@ -289,7 +291,6 @@ void *xrealloc(void *, size_t, size_t); #define zrealloc(ptr, size) xrealloc((ptr), 1, (size)) char *xstrdup(const char *); int xasprintf(char **, const char *, ...); -ulong color_enlight(ulong col); long getcolor(char *color); void setwinstate(Window win, long state); /* Conf usage {{{ */ diff --git a/wmfsrc b/wmfsrc index 0f7d3c2..9b76d00 100644 --- a/wmfsrc +++ b/wmfsrc @@ -26,6 +26,9 @@ border = true #height = "-1" + light_shade = 0.10 + dark_shade = -0.10 + [systray] # Enable/disable systray active = true @@ -189,6 +192,9 @@ # Modifier for mouse use modifier = "Alt" + light_shade = 0.10 + dark_shade = -0.10 + # *DEPRECATED* but works, see [rules] section # Set automatic free or max client # autofree = "xterm|MPlayer"