diff --git a/config.h b/config.h index c5f2577..06670f2 100644 --- a/config.h +++ b/config.h @@ -6,10 +6,13 @@ struct settings defaults = { .markup = MARKUP_NO, .colors_norm.bg = "#1793D1", .colors_norm.fg = "#DDDDDD", +.colors_norm.highlight = "#1745d1", .colors_crit.bg = "#ffaaaa", .colors_crit.fg = "#000000", +.colors_crit.highlight = "#ff6666", .colors_low.bg = "#aaaaff", .colors_low.fg = "#000000", +.colors_low.highlight = "#7f7fff", .format = "%s %b", /* default format */ .timeouts = { S2US(10), S2US(10), S2US(0) }, /* low, normal, critical */ @@ -110,6 +113,15 @@ struct settings defaults = { .mouse_right_click = (enum mouse_action []){MOUSE_CLOSE_ALL, -1}, +.progress_bar_height = 10, + +.progress_bar_min_width = 150, + +.progress_bar_max_width = 300, + +.progress_bar_frame_width = 1, + +.no_progress_bar = false, }; struct rule default_rules[] = { diff --git a/src/draw.c b/src/draw.c index 6a23f43..6019ec3 100644 --- a/src/draw.c +++ b/src/draw.c @@ -23,6 +23,7 @@ struct colored_layout { PangoLayout *l; struct color fg; struct color bg; + struct color highlight; struct color frame; char *text; PangoAttrList *attr; @@ -166,6 +167,11 @@ static bool have_dynamic_width(void) return (settings.geometry.width_set && settings.geometry.w == 0); } +static bool have_progress_bar(const struct notification *n) +{ + return (n->progress >= 0 && settings.no_progress_bar == false); +} + static struct dimensions calculate_dimensions(GSList *layouts) { struct dimensions dim = { 0 }; @@ -237,6 +243,11 @@ static struct dimensions calculate_dimensions(GSList *layouts) text_width = MAX(w, text_width); } + if (have_progress_bar(cl->n)){ + dim.h += settings.progress_bar_height + settings.padding; + dim.w = MAX(dim.w, settings.progress_bar_min_width); + } + dim.corner_radius = MIN(dim.corner_radius, h/2); } @@ -299,6 +310,7 @@ static struct colored_layout *layout_init_shared(cairo_t *c, const struct notifi cl->fg = string_to_color(n->colors.fg); cl->bg = string_to_color(n->colors.bg); + cl->highlight = string_to_color(n->colors.highlight); cl->frame = string_to_color(n->colors.frame); cl->n = n; @@ -354,7 +366,12 @@ static struct colored_layout *layout_from_notification(cairo_t *c, struct notifi pango_layout_get_pixel_size(cl->l, NULL, &(n->displayed_height)); if (cl->icon) n->displayed_height = MAX(cairo_image_surface_get_height(cl->icon), n->displayed_height); - n->displayed_height = MAX(settings.notification_height, n->displayed_height + settings.padding * 2); + n->displayed_height = n->displayed_height + settings.padding * 2; + + // progress bar + if (have_progress_bar(n)) n->displayed_height += settings.progress_bar_height + settings.padding; + + n->displayed_height = MAX(settings.notification_height, n->displayed_height); n->first_render = false; return cl; @@ -397,11 +414,16 @@ static int layout_get_height(struct colored_layout *cl) { int h; int h_icon = 0; + int h_progress_bar = 0; pango_layout_get_pixel_size(cl->l, NULL, &h); if (cl->icon) h_icon = cairo_image_surface_get_height(cl->icon); + if (have_progress_bar(cl->n)){ + h_progress_bar = settings.progress_bar_height + settings.padding; + } - return MAX(h, h_icon); + int res = MAX(h, h_icon) + h_progress_bar; + return res; } /* Attempt to make internal radius more organic. @@ -563,11 +585,15 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, static void render_content(cairo_t *c, struct colored_layout *cl, int width) { const int h = layout_get_height(cl); + int h_without_progress_bar = h; + if (have_progress_bar(cl->n)){ + h_without_progress_bar -= settings.progress_bar_height + settings.padding; + } int h_text; pango_layout_get_pixel_size(cl->l, NULL, &h_text); int text_x = settings.h_padding, - text_y = settings.padding + h / 2 - h_text / 2; + text_y = settings.padding + h_without_progress_bar / 2 - h_text / 2; // text positioning if (cl->icon) { @@ -575,7 +601,7 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width) if (settings.vertical_alignment == VERTICAL_TOP) { text_y = settings.padding; } else if (settings.vertical_alignment == VERTICAL_BOTTOM) { - text_y = h + settings.padding - h_text; + text_y = h_without_progress_bar + settings.padding - h_text; if (text_y < 0) text_y = settings.padding; } // else VERTICAL_CENTER @@ -597,14 +623,14 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width) unsigned int image_width = cairo_image_surface_get_width(cl->icon), image_height = cairo_image_surface_get_height(cl->icon), image_x = width - settings.h_padding - image_width, - image_y = settings.padding + h/2 - image_height/2; + image_y = settings.padding + h_without_progress_bar/2 - image_height/2; // vertical alignment if (settings.vertical_alignment == VERTICAL_TOP) { image_y = settings.padding; } else if (settings.vertical_alignment == VERTICAL_BOTTOM) { - image_y = h + settings.padding - image_height; - if (image_y < settings.padding || image_y > h) + image_y = h_without_progress_bar + settings.padding - image_height; + if (image_y < settings.padding || image_y > h_without_progress_bar) image_y = settings.padding; } // else VERTICAL_CENTER @@ -618,6 +644,38 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width) cairo_fill(c); } + // progress bar positioning + if (have_progress_bar(cl->n)){ + int progress = cl->n->progress; + unsigned int frame_width = settings.progress_bar_frame_width, + progress_width = MIN(width - 2 * settings.h_padding, settings.progress_bar_max_width), + progress_height = settings.progress_bar_height - frame_width, + frame_x = settings.h_padding, + frame_y = settings.padding + h - settings.progress_bar_height, + progress_width_without_frame = progress_width - 2 * frame_width, + progress_width_1 = progress_width_without_frame * progress / 100, + progress_width_2 = progress_width_without_frame - progress_width_1, + x_bar_1 = frame_x + frame_width, + x_bar_2 = x_bar_1 + progress_width_1; + + double half_frame_width = frame_width / 2.0; + + // draw progress bar + // Note: the bar could be drawn a bit smaller, because the frame is drawn on top + // left side + cairo_set_source_rgba(c, cl->highlight.r, cl->highlight.g, cl->highlight.b, cl->highlight.a); + cairo_rectangle(c, x_bar_1, frame_y, progress_width_1, progress_height); + cairo_fill(c); + // right side + cairo_set_source_rgba(c, cl->bg.r, cl->bg.g, cl->bg.b, cl->bg.a); + cairo_rectangle(c, x_bar_2, frame_y, progress_width_2, progress_height); + cairo_fill(c); + // border + cairo_set_source_rgba(c, cl->frame.r, cl->frame.g, cl->frame.b, cl->frame.a); + cairo_rectangle(c, frame_x + half_frame_width, frame_y + half_frame_width, progress_width - frame_width, progress_height); + cairo_set_line_width(c, frame_width); + cairo_stroke(c); + } } static struct dimensions layout_render(cairo_surface_t *srf, diff --git a/src/notification.c b/src/notification.c index 1c18db4..c693231 100644 --- a/src/notification.c +++ b/src/notification.c @@ -64,6 +64,7 @@ void notification_print(const struct notification *n) printf("\tformatted: '%s'\n", n->msg); printf("\tfg: %s\n", n->colors.fg); printf("\tbg: %s\n", n->colors.bg); + printf("\thighlight: %s\n", n->colors.highlight); printf("\tframe: %s\n", n->colors.frame); printf("\tfullscreen: %s\n", enum_to_string_fullscreen(n->fullscreen)); printf("\tprogress: %d\n", n->progress); @@ -236,6 +237,7 @@ void notification_unref(struct notification *n) g_free(n->urls); g_free(n->colors.fg); g_free(n->colors.bg); + g_free(n->colors.highlight); g_free(n->colors.frame); g_free(n->stack_tag); g_free(n->desktop_entry); @@ -393,6 +395,8 @@ void notification_init(struct notification *n) n->colors.fg = g_strdup(defcolors.fg); if (!n->colors.bg) n->colors.bg = g_strdup(defcolors.bg); + if (!n->colors.highlight) + n->colors.highlight = g_strdup(defcolors.highlight); if (!n->colors.frame) n->colors.frame = g_strdup(defcolors.frame); diff --git a/src/notification.h b/src/notification.h index e387c4a..5795de6 100644 --- a/src/notification.h +++ b/src/notification.h @@ -33,6 +33,7 @@ struct notification_colors { char *frame; char *bg; char *fg; + char *highlight; }; struct notification { diff --git a/src/rules.c b/src/rules.c index b7f185c..3593473 100644 --- a/src/rules.c +++ b/src/rules.c @@ -38,6 +38,10 @@ void rule_apply(struct rule *r, struct notification *n) g_free(n->colors.bg); n->colors.bg = g_strdup(r->bg); } + if (r->highlight) { + g_free(n->colors.highlight); + n->colors.highlight = g_strdup(r->highlight); + } if (r->fc) { g_free(n->colors.frame); n->colors.frame = g_strdup(r->fc); diff --git a/src/rules.h b/src/rules.h index 6b2d7b2..5589446 100644 --- a/src/rules.h +++ b/src/rules.h @@ -31,6 +31,7 @@ struct rule { char *new_icon; char *fg; char *bg; + char *highlight; char *fc; const char *format; const char *script; diff --git a/src/settings.c b/src/settings.c index 4477403..e07f17a 100644 --- a/src/settings.c +++ b/src/settings.c @@ -355,6 +355,49 @@ void load_settings(char *cmdline_config_path) "Window corner radius" ); + settings.progress_bar_height = option_get_int( + "global", + "progress_bar_height", "-progress_bar_height", defaults.progress_bar_height, + "Height of the progress bar" + ); + + settings.progress_bar_min_width = option_get_int( + "global", + "progress_bar_min_width", "-progress_bar_min_width", defaults.progress_bar_min_width, + "Minimum width of the progress bar" + ); + + settings.progress_bar_max_width = option_get_int( + "global", + "progress_bar_max_width", "-progress_bar_max_width", defaults.progress_bar_max_width, + "Maximum width of the progress bar" + ); + + settings.progress_bar_frame_width = option_get_int( + "global", + "progress_bar_frame_width", "-progress_bar_frame_width", defaults.progress_bar_frame_width, + "Frame width of the progress bar" + ); + + settings.no_progress_bar = option_get_bool( + "global", + "no_progress_bar", "-no_progress_bar", false, + "Hide the progress bar" + ); + + // check sanity of the progress bar options + { + if (settings.progress_bar_height < (2 * settings.progress_bar_frame_width)){ + LOG_E("setting progress_bar_frame_width is bigger than half of progress_bar_height"); + } + if (settings.progress_bar_max_width < (2 * settings.progress_bar_frame_width)){ + LOG_E("setting progress_bar_frame_width is bigger than half of progress_bar_max_width"); + } + if (settings.progress_bar_max_width < settings.progress_bar_min_width){ + LOG_E("setting progress_bar_max_width is smaller than progress_bar_min_width"); + } + } + { char *c = option_get_string( "global", @@ -584,6 +627,12 @@ void load_settings(char *cmdline_config_path) "Foreground color for notifications with low urgency" ); + settings.colors_low.highlight = option_get_string( + "urgency_low", + "highlight", "-lh", defaults.colors_low.highlight, + "Highlight color for notifications with low urgency" + ); + settings.colors_low.frame = option_get_string( "urgency_low", "frame_color", "-lfr", settings.frame_color ? settings.frame_color : defaults.colors_low.frame, @@ -614,6 +663,12 @@ void load_settings(char *cmdline_config_path) "Foreground color for notifications with normal urgency" ); + settings.colors_norm.highlight = option_get_string( + "urgency_normal", + "highlight", "-nh", defaults.colors_norm.highlight, + "Highlight color for notifications with normal urgency" + ); + settings.colors_norm.frame = option_get_string( "urgency_normal", "frame_color", "-nfr", settings.frame_color ? settings.frame_color : defaults.colors_norm.frame, @@ -644,6 +699,12 @@ void load_settings(char *cmdline_config_path) "Foreground color for notifications with ciritical urgency" ); + settings.colors_crit.highlight = option_get_string( + "urgency_critical", + "highlight", "-ch", defaults.colors_crit.highlight, + "Highlight color for notifications with ciritical urgency" + ); + settings.colors_crit.frame = option_get_string( "urgency_critical", "frame_color", "-cfr", settings.frame_color ? settings.frame_color : defaults.colors_crit.frame, @@ -756,6 +817,7 @@ void load_settings(char *cmdline_config_path) r->msg_urgency = ini_get_urgency(cur_section, "msg_urgency", r->msg_urgency); r->fg = ini_get_string(cur_section, "foreground", r->fg); r->bg = ini_get_string(cur_section, "background", r->bg); + r->bg = ini_get_string(cur_section, "highlight", r->highlight); r->fc = ini_get_string(cur_section, "frame_color", r->fc); r->format = ini_get_string(cur_section, "format", r->format); r->new_icon = ini_get_string(cur_section, "new_icon", r->new_icon); diff --git a/src/settings.h b/src/settings.h index 9f1e042..ba0aaea 100644 --- a/src/settings.h +++ b/src/settings.h @@ -92,6 +92,11 @@ struct settings { enum mouse_action *mouse_left_click; enum mouse_action *mouse_middle_click; enum mouse_action *mouse_right_click; + int progress_bar_height; + int progress_bar_min_width; + int progress_bar_max_width; + int progress_bar_frame_width; + bool no_progress_bar; }; extern struct settings settings;