From 8d8e6882e8eee403d1d270b0aa81a16065802df7 Mon Sep 17 00:00:00 2001 From: Nikita Zlobin Date: Thu, 21 May 2020 02:36:01 +0500 Subject: [PATCH 01/11] style fix --- src/draw.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/draw.c b/src/draw.c index 14dfd8b..d7e3431 100644 --- a/src/draw.c +++ b/src/draw.c @@ -488,8 +488,7 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, else height += settings.separator_height; - if (settings.frame_width > 0) - { + if (settings.frame_width > 0) { cairo_set_source_rgb(c, cl->frame.r, cl->frame.g, cl->frame.b); draw_rounded_rect(c, x, y, width, height, corner_radius, first, last); cairo_fill(c); From 9833fbba1f6259de40828b213090eb9908861047 Mon Sep 17 00:00:00 2001 From: Nikita Zlobin Date: Thu, 21 May 2020 03:25:22 +0500 Subject: [PATCH 02/11] Limit frame stroke area --- src/draw.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/draw.c b/src/draw.c index d7e3431..6c78288 100644 --- a/src/draw.c +++ b/src/draw.c @@ -481,6 +481,12 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, cairo_t *c = cairo_create(srf); + /* stroke area doesn't intersect with main area */ + cairo_set_fill_rule(c, CAIRO_FILL_RULE_EVEN_ODD); + + /* for correct combination of adjacent areas */ + cairo_set_operator(c, CAIRO_OPERATOR_ADD); + if (first) height += settings.frame_width; if (last) @@ -489,9 +495,7 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, height += settings.separator_height; if (settings.frame_width > 0) { - cairo_set_source_rgb(c, cl->frame.r, cl->frame.g, cl->frame.b); draw_rounded_rect(c, x, y, width, height, corner_radius, first, last); - cairo_fill(c); /* adding frame */ x += settings.frame_width; @@ -508,12 +512,18 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, height -= settings.separator_height; radius_int = frame_internal_radius (corner_radius, settings.frame_width, height); + + draw_rounded_rect(c, x, y, width, height, radius_int, first, last); + cairo_set_source_rgb(c, cl->frame.r, cl->frame.g, cl->frame.b); + cairo_fill(c); } - cairo_set_source_rgb(c, cl->bg.r, cl->bg.g, cl->bg.b); draw_rounded_rect(c, x, y, width, height, radius_int, first, last); + cairo_set_source_rgb(c, cl->bg.r, cl->bg.g, cl->bg.b); cairo_fill(c); + cairo_set_operator(c, CAIRO_OPERATOR_OVER); + if ( settings.sep_color.type != SEP_FRAME && settings.separator_height > 0 && !last) { From 2e2b3e549fb24cb00512c3e9fdb3a9225c7a42ec Mon Sep 17 00:00:00 2001 From: Nikita Zlobin Date: Thu, 21 May 2020 15:27:00 +0500 Subject: [PATCH 03/11] RGBA color support --- src/draw.c | 30 +++++++++++++++++++----------- src/x11/x.h | 1 + 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/draw.c b/src/draw.c index 6c78288..44ddf42 100644 --- a/src/draw.c +++ b/src/draw.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "dunst.h" #include "icon.h" @@ -41,12 +42,13 @@ void draw_setup(void) pango_fdesc = pango_font_description_from_string(settings.font); } -static struct color hex_to_color(int hexValue) +static struct color hex_to_color(uint32_t hexValue) { struct color ret; - ret.r = ((hexValue >> 16) & 0xFF) / 255.0; - ret.g = ((hexValue >> 8) & 0xFF) / 255.0; - ret.b = ((hexValue) & 0xFF) / 255.0; + ret.r = ((hexValue >> 24) & 0xFF) / (double)0xFF; + ret.g = ((hexValue >> 16) & 0xFF) / (double)0xFF; + ret.b = ((hexValue >> 8) & 0xFF) / (double)0xFF; + ret.a = ((hexValue) & 0xFF) / (double)0xFF; return ret; } @@ -54,15 +56,21 @@ static struct color hex_to_color(int hexValue) static struct color string_to_color(const char *str) { char *end; - long int val = strtol(str+1, &end, 16); + uint32_t val = strtoul(str+1, &end, 16); if (*end != '\0' && *(end+1) != '\0') { LOG_W("Invalid color string: '%s'", str); } - return hex_to_color(val); + switch (strlen(str+1)) { + case 6: return hex_to_color((val << 8) | 0xFF); + case 8: return hex_to_color(val); + } + + LOG_W("Invalid color string: '%s'", str); + return hex_to_color(0xFF); } -static double color_apply_delta(double base, double delta) +static inline double color_apply_delta(double base, double delta) { base += delta; if (base > 1) @@ -514,12 +522,12 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, radius_int = frame_internal_radius (corner_radius, settings.frame_width, height); draw_rounded_rect(c, x, y, width, height, radius_int, first, last); - cairo_set_source_rgb(c, cl->frame.r, cl->frame.g, cl->frame.b); + cairo_set_source_rgba(c, cl->frame.r, cl->frame.g, cl->frame.b, cl->frame.a); cairo_fill(c); } draw_rounded_rect(c, x, y, width, height, radius_int, first, last); - cairo_set_source_rgb(c, cl->bg.r, cl->bg.g, cl->bg.b); + cairo_set_source_rgba(c, cl->bg.r, cl->bg.g, cl->bg.b, cl->bg.a); cairo_fill(c); cairo_set_operator(c, CAIRO_OPERATOR_OVER); @@ -528,7 +536,7 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, && settings.separator_height > 0 && !last) { struct color sep_color = layout_get_sepcolor(cl, cl_next); - cairo_set_source_rgb(c, sep_color.r, sep_color.g, sep_color.b); + cairo_set_source_rgba(c, sep_color.r, sep_color.g, sep_color.b, sep_color.a); cairo_rectangle(c, settings.frame_width, y + height, width, settings.separator_height); @@ -570,7 +578,7 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width) } cairo_move_to(c, text_x, text_y); - cairo_set_source_rgb(c, cl->fg.r, cl->fg.g, cl->fg.b); + cairo_set_source_rgba(c, cl->fg.r, cl->fg.g, cl->fg.b, cl->fg.a); pango_cairo_update_layout(c, cl->l); pango_cairo_show_layout(c, cl->l); diff --git a/src/x11/x.h b/src/x11/x.h index 3ed21e3..9874b7f 100644 --- a/src/x11/x.h +++ b/src/x11/x.h @@ -44,6 +44,7 @@ struct color { double r; double g; double b; + double a; }; extern struct x_context xctx; From 7226ef2c150c448019c474a97f40d635a429799c Mon Sep 17 00:00:00 2001 From: Nikita Zlobin Date: Thu, 21 May 2020 17:31:24 +0500 Subject: [PATCH 04/11] Support for different color config precisions (#RGB format) Support for #RGB is claimed in docs. --- src/draw.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/draw.c b/src/draw.c index 44ddf42..aac6ae7 100644 --- a/src/draw.c +++ b/src/draw.c @@ -34,6 +34,8 @@ struct window_x11 *win; PangoFontDescription *pango_fdesc; +#define UINT_MAX_N(bits) (1 << (bits-1) | (( 1 << (bits-1) ) - 1)) + void draw_setup(void) { x_setup(); @@ -42,13 +44,16 @@ void draw_setup(void) pango_fdesc = pango_font_description_from_string(settings.font); } -static struct color hex_to_color(uint32_t hexValue) +static struct color hex_to_color(uint32_t hexValue, int dpc) { + const int bpc = 4 * dpc; + const unsigned single_max = UINT_MAX_N(bpc); + struct color ret; - ret.r = ((hexValue >> 24) & 0xFF) / (double)0xFF; - ret.g = ((hexValue >> 16) & 0xFF) / (double)0xFF; - ret.b = ((hexValue >> 8) & 0xFF) / (double)0xFF; - ret.a = ((hexValue) & 0xFF) / (double)0xFF; + ret.r = ((hexValue >> 3 * bpc) & single_max) / (double)single_max; + ret.g = ((hexValue >> 2 * bpc) & single_max) / (double)single_max; + ret.b = ((hexValue >> 1 * bpc) & single_max) / (double)single_max; + ret.a = ((hexValue) & single_max) / (double)single_max; return ret; } @@ -62,12 +67,15 @@ static struct color string_to_color(const char *str) } switch (strlen(str+1)) { - case 6: return hex_to_color((val << 8) | 0xFF); - case 8: return hex_to_color(val); + case 3: return hex_to_color((val << 4) | 0xF, 1); + case 6: return hex_to_color((val << 8) | 0xFF, 2); + case 4: return hex_to_color(val, 1); + case 8: return hex_to_color(val, 2); } + /* return black on error */ LOG_W("Invalid color string: '%s'", str); - return hex_to_color(0xFF); + return hex_to_color(0xF, 1); } static inline double color_apply_delta(double base, double delta) From 1e36a6b4ac569527981e06db429f3e6cd8ac99b8 Mon Sep 17 00:00:00 2001 From: Nikita Zlobin Date: Thu, 21 May 2020 17:39:19 +0500 Subject: [PATCH 05/11] Support arbitrary hex color formats (16/32bits per component) It's unlikely that string_to_color() is faster, but at least is more flexible. Not sure if 8-digit per channel format is used. --- src/draw.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/src/draw.c b/src/draw.c index aac6ae7..8236c2b 100644 --- a/src/draw.c +++ b/src/draw.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "dunst.h" #include "icon.h" @@ -44,7 +45,7 @@ void draw_setup(void) pango_fdesc = pango_font_description_from_string(settings.font); } -static struct color hex_to_color(uint32_t hexValue, int dpc) +static struct color hex_to_color(uintmax_t hexValue, int dpc) { const int bpc = 4 * dpc; const unsigned single_max = UINT_MAX_N(bpc); @@ -60,20 +61,38 @@ static struct color hex_to_color(uint32_t hexValue, int dpc) static struct color string_to_color(const char *str) { - char *end; - uint32_t val = strtoul(str+1, &end, 16); - if (*end != '\0' && *(end+1) != '\0') { - LOG_W("Invalid color string: '%s'", str); - } + uintmax_t val; + unsigned clen; + { + int cn; - switch (strlen(str+1)) { - case 3: return hex_to_color((val << 4) | 0xF, 1); - case 6: return hex_to_color((val << 8) | 0xFF, 2); - case 4: return hex_to_color(val, 1); - case 8: return hex_to_color(val, 2); + /* accept 3 or 4 equal components */ { + char *end; + val = strtoumax(str+1, &end, 16); + if (errno == ERANGE || (end[0] != '\0' && end[1] != '\0')) + goto err; + + const int len = (end - (str+1)); + if (len % 3 == 0) cn = 3; + else if (len % 4 == 0) cn = 4; + else goto err; + clen = len / cn; + } + /* component length must be 2^n */ { + unsigned mask = 1; + while(mask < clen) mask <<= 1; + if (mask != clen) goto err; + } + /* turn 3-component to opaque 4-components */ { + const unsigned csize = clen * 4; + if (cn == 3) + val = (val << csize) | UINT_MAX_N(csize); + } } + return hex_to_color(val, clen); /* return black on error */ + err: LOG_W("Invalid color string: '%s'", str); return hex_to_color(0xF, 1); } From 6b28d57730a390264b4d0daea2d765f841ad90d8 Mon Sep 17 00:00:00 2001 From: Nikita Zlobin Date: Sat, 23 May 2020 02:06:07 +0500 Subject: [PATCH 06/11] Floating point color config formats --- src/draw.c | 74 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 25 deletions(-) diff --git a/src/draw.c b/src/draw.c index 8236c2b..34f081e 100644 --- a/src/draw.c +++ b/src/draw.c @@ -59,37 +59,61 @@ static struct color hex_to_color(uintmax_t hexValue, int dpc) return ret; } +static inline void color_clip(struct color * c) +{ + if (c->r > 1.0) c->r = 1.0; + if (c->g > 1.0) c->g = 1.0; + if (c->b > 1.0) c->b = 1.0; + if (c->a > 1.0) c->a = 1.0; +} + static struct color string_to_color(const char *str) { - uintmax_t val; - unsigned clen; + if (str[0] == '#') { + uintmax_t val; + unsigned clen; + { + int cn; + + /* accept 3 or 4 equal components */ { + char *end; + val = strtoumax(str+1, &end, 16); + if (errno == ERANGE || (end[0] != '\0' && end[1] != '\0')) + goto err; + + const int len = (end - (str+1)); + if (len % 3 == 0) cn = 3; + else if (len % 4 == 0) cn = 4; + else goto err; + clen = len / cn; + } + /* component length must be 2^n */ { + unsigned mask = 1; + while(mask < clen) mask <<= 1; + if (mask != clen) goto err; + } + /* turn 3-component to opaque 4-components */ { + const unsigned csize = clen * 4; + if (cn == 3) + val = (val << csize) | UINT_MAX_N(csize); + } + } + return hex_to_color(val, clen); + } + + /* rgba(fp, fp, fp, fp) */ { - int cn; - - /* accept 3 or 4 equal components */ { - char *end; - val = strtoumax(str+1, &end, 16); - if (errno == ERANGE || (end[0] != '\0' && end[1] != '\0')) - goto err; - - const int len = (end - (str+1)); - if (len % 3 == 0) cn = 3; - else if (len % 4 == 0) cn = 4; - else goto err; - clen = len / cn; + struct color col; + if (sscanf(str, "rgba ( %lf , %lf , %lf , %lf )", &col.r, &col.g, &col.b, &col.a) == 4) { + color_clip(&col); + return col; } - /* component length must be 2^n */ { - unsigned mask = 1; - while(mask < clen) mask <<= 1; - if (mask != clen) goto err; - } - /* turn 3-component to opaque 4-components */ { - const unsigned csize = clen * 4; - if (cn == 3) - val = (val << csize) | UINT_MAX_N(csize); + if (sscanf(str, "rgb ( %lf , %lf , %lf )", &col.r, &col.g, &col.b) == 3) { + color_clip(&col); + col.a = 1.0; + return col; } } - return hex_to_color(val, clen); /* return black on error */ err: From d45888a7856fe10d271fbe82f1941b6b844fa5da Mon Sep 17 00:00:00 2001 From: Nikita Zlobin Date: Sat, 23 May 2020 03:24:10 +0500 Subject: [PATCH 07/11] Don't mix separator with underlying content --- src/draw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/draw.c b/src/draw.c index 34f081e..56dbf89 100644 --- a/src/draw.c +++ b/src/draw.c @@ -581,7 +581,7 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, cairo_set_source_rgba(c, cl->bg.r, cl->bg.g, cl->bg.b, cl->bg.a); cairo_fill(c); - cairo_set_operator(c, CAIRO_OPERATOR_OVER); + cairo_set_operator(c, CAIRO_OPERATOR_SOURCE); if ( settings.sep_color.type != SEP_FRAME && settings.separator_height > 0 From 98debc663ab9dd51c212c12be54057aa1b5f2557 Mon Sep 17 00:00:00 2001 From: Nikita Zlobin Date: Tue, 26 May 2020 18:32:58 +0500 Subject: [PATCH 08/11] simplify UINT_MAX_N Probably I was too precatious, not relying to common rule about unsigned subtraction to minus. --- src/draw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/draw.c b/src/draw.c index 56dbf89..fb7548d 100644 --- a/src/draw.c +++ b/src/draw.c @@ -35,7 +35,7 @@ struct window_x11 *win; PangoFontDescription *pango_fdesc; -#define UINT_MAX_N(bits) (1 << (bits-1) | (( 1 << (bits-1) ) - 1)) +#define UINT_MAX_N(bits) ((1 << bits) - 1) void draw_setup(void) { From d110ba93e640aac59c72e62b6c9f84c79d47549e Mon Sep 17 00:00:00 2001 From: Nikita Zlobin Date: Tue, 26 May 2020 22:27:31 +0500 Subject: [PATCH 09/11] Revert "Floating point color config formats" This reverts commit 6b28d57730a390264b4d0daea2d765f841ad90d8. --- src/draw.c | 74 ++++++++++++++++++------------------------------------ 1 file changed, 25 insertions(+), 49 deletions(-) diff --git a/src/draw.c b/src/draw.c index fb7548d..e5f1ada 100644 --- a/src/draw.c +++ b/src/draw.c @@ -59,61 +59,37 @@ static struct color hex_to_color(uintmax_t hexValue, int dpc) return ret; } -static inline void color_clip(struct color * c) -{ - if (c->r > 1.0) c->r = 1.0; - if (c->g > 1.0) c->g = 1.0; - if (c->b > 1.0) c->b = 1.0; - if (c->a > 1.0) c->a = 1.0; -} - static struct color string_to_color(const char *str) { - if (str[0] == '#') { - uintmax_t val; - unsigned clen; - { - int cn; - - /* accept 3 or 4 equal components */ { - char *end; - val = strtoumax(str+1, &end, 16); - if (errno == ERANGE || (end[0] != '\0' && end[1] != '\0')) - goto err; - - const int len = (end - (str+1)); - if (len % 3 == 0) cn = 3; - else if (len % 4 == 0) cn = 4; - else goto err; - clen = len / cn; - } - /* component length must be 2^n */ { - unsigned mask = 1; - while(mask < clen) mask <<= 1; - if (mask != clen) goto err; - } - /* turn 3-component to opaque 4-components */ { - const unsigned csize = clen * 4; - if (cn == 3) - val = (val << csize) | UINT_MAX_N(csize); - } - } - return hex_to_color(val, clen); - } - - /* rgba(fp, fp, fp, fp) */ + uintmax_t val; + unsigned clen; { - struct color col; - if (sscanf(str, "rgba ( %lf , %lf , %lf , %lf )", &col.r, &col.g, &col.b, &col.a) == 4) { - color_clip(&col); - return col; + int cn; + + /* accept 3 or 4 equal components */ { + char *end; + val = strtoumax(str+1, &end, 16); + if (errno == ERANGE || (end[0] != '\0' && end[1] != '\0')) + goto err; + + const int len = (end - (str+1)); + if (len % 3 == 0) cn = 3; + else if (len % 4 == 0) cn = 4; + else goto err; + clen = len / cn; } - if (sscanf(str, "rgb ( %lf , %lf , %lf )", &col.r, &col.g, &col.b) == 3) { - color_clip(&col); - col.a = 1.0; - return col; + /* component length must be 2^n */ { + unsigned mask = 1; + while(mask < clen) mask <<= 1; + if (mask != clen) goto err; + } + /* turn 3-component to opaque 4-components */ { + const unsigned csize = clen * 4; + if (cn == 3) + val = (val << csize) | UINT_MAX_N(csize); } } + return hex_to_color(val, clen); /* return black on error */ err: From 6413a4d6f816832f4d78254508c3d8dd60476889 Mon Sep 17 00:00:00 2001 From: Nikita Zlobin Date: Tue, 26 May 2020 22:28:05 +0500 Subject: [PATCH 10/11] Revert "Support arbitrary hex color formats (16/32bits per component)" This reverts commit 1e36a6b4ac569527981e06db429f3e6cd8ac99b8. --- src/draw.c | 43 ++++++++++++------------------------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/src/draw.c b/src/draw.c index e5f1ada..8bce3c9 100644 --- a/src/draw.c +++ b/src/draw.c @@ -10,7 +10,6 @@ #include #include #include -#include #include "dunst.h" #include "icon.h" @@ -45,7 +44,7 @@ void draw_setup(void) pango_fdesc = pango_font_description_from_string(settings.font); } -static struct color hex_to_color(uintmax_t hexValue, int dpc) +static struct color hex_to_color(uint32_t hexValue, int dpc) { const int bpc = 4 * dpc; const unsigned single_max = UINT_MAX_N(bpc); @@ -61,38 +60,20 @@ static struct color hex_to_color(uintmax_t hexValue, int dpc) static struct color string_to_color(const char *str) { - uintmax_t val; - unsigned clen; - { - int cn; - - /* accept 3 or 4 equal components */ { - char *end; - val = strtoumax(str+1, &end, 16); - if (errno == ERANGE || (end[0] != '\0' && end[1] != '\0')) - goto err; - - const int len = (end - (str+1)); - if (len % 3 == 0) cn = 3; - else if (len % 4 == 0) cn = 4; - else goto err; - clen = len / cn; - } - /* component length must be 2^n */ { - unsigned mask = 1; - while(mask < clen) mask <<= 1; - if (mask != clen) goto err; - } - /* turn 3-component to opaque 4-components */ { - const unsigned csize = clen * 4; - if (cn == 3) - val = (val << csize) | UINT_MAX_N(csize); - } + char *end; + uint32_t val = strtoul(str+1, &end, 16); + if (*end != '\0' && *(end+1) != '\0') { + LOG_W("Invalid color string: '%s'", str); + } + + switch (strlen(str+1)) { + case 3: return hex_to_color((val << 4) | 0xF, 1); + case 6: return hex_to_color((val << 8) | 0xFF, 2); + case 4: return hex_to_color(val, 1); + case 8: return hex_to_color(val, 2); } - return hex_to_color(val, clen); /* return black on error */ - err: LOG_W("Invalid color string: '%s'", str); return hex_to_color(0xF, 1); } From 12bea049416444d028944d26b51e9e0b19bdaab0 Mon Sep 17 00:00:00 2001 From: Nikita Zlobin Date: Tue, 26 May 2020 22:41:19 +0500 Subject: [PATCH 11/11] optimization --- src/draw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/draw.c b/src/draw.c index 8bce3c9..931f36c 100644 --- a/src/draw.c +++ b/src/draw.c @@ -61,12 +61,12 @@ static struct color hex_to_color(uint32_t hexValue, int dpc) static struct color string_to_color(const char *str) { char *end; - uint32_t val = strtoul(str+1, &end, 16); - if (*end != '\0' && *(end+1) != '\0') { + uint_fast32_t val = strtoul(str+1, &end, 16); + if (end[0] != '\0' && end[1] != '\0') { LOG_W("Invalid color string: '%s'", str); } - switch (strlen(str+1)) { + switch (end - (str+1)) { case 3: return hex_to_color((val << 4) | 0xF, 1); case 6: return hex_to_color((val << 8) | 0xFF, 2); case 4: return hex_to_color(val, 1);