From c2801181f8ca05c026f1d045a377b7e5410e31c5 Mon Sep 17 00:00:00 2001 From: Gjum Date: Tue, 25 Feb 2014 23:07:02 +0100 Subject: [PATCH] Add icon support - icons are displayed at the top left corner - disabed by default, fully backwards-compatible - no additional dependencies, only cairo used - TODO: only supports png (but all default images are png) - TODO: message formatting is sometimes buggy --- dunstrc | 6 ++++++ notification.c | 5 +++++ settings.c | 9 +++++++++ settings.h | 2 ++ x.c | 40 ++++++++++++++++++++++++++++++++++++---- 5 files changed, 58 insertions(+), 4 deletions(-) diff --git a/dunstrc b/dunstrc index c0a629d..f50618e 100644 --- a/dunstrc +++ b/dunstrc @@ -138,6 +138,12 @@ # Browser for opening urls in context menu. browser = /usr/bin/firefox -new-tab + # Show icons in notifications. + show_icons = no + + # Path to default icons. + icon_path = /usr/share/icons/gnome/32x32/status/%s.png + [frame] width = 3 color = "#aaaaaa" diff --git a/notification.c b/notification.c index 42242d6..286f407 100644 --- a/notification.c +++ b/notification.c @@ -281,6 +281,11 @@ int notification_init(notification * n, int id) n->urls = notification_extract_markup_urls(&(n->body)); + /* Add icon path if relative */ + if (strlen(n->icon) > 0 && n->icon[0] != '/' && n->icon[0] != '~') { + n->icon = string_replace("%s", n->icon, settings.icon_path); + } + n->msg = string_replace("%a", n->appname, g_strdup(n->format)); n->msg = string_replace("%s", n->summary, n->msg); if (n->icon) { diff --git a/settings.c b/settings.c index 7b87d7a..a52a948 100644 --- a/settings.c +++ b/settings.c @@ -192,6 +192,15 @@ void load_settings(char *cmdline_config_path) option_get_string("global", "browser", "-browser", browser, "path to browser"); + settings.show_icons = + option_get_bool("global", "show_icons", + "-show_icons", false, + "show icons in notifications"); + + settings.icon_path = + option_get_string("global", "icon_path", "-icon_path", icon_path, + "path to default icons"); + settings.frame_width = option_get_int("frame", "width", "-frame_width", frame_width, "Width of frame around window"); diff --git a/settings.h b/settings.h index 9481cce..dc368a8 100644 --- a/settings.h +++ b/settings.h @@ -42,6 +42,8 @@ typedef struct _settings { char *dmenu; char **dmenu_cmd; char *browser; + bool show_icons; + char *icon_path; enum follow_mode f_mode; keyboard_shortcut close_ks; keyboard_shortcut close_all_ks; diff --git a/x.c b/x.c index a4e877f..b3edf93 100644 --- a/x.c +++ b/x.c @@ -40,6 +40,7 @@ typedef struct _colored_layout { color_t bg; char *text; PangoAttrList *attr; + cairo_surface_t *icon; } colored_layout; cairo_ctx_t cairo_ctx; @@ -166,6 +167,7 @@ static void free_colored_layout(void *data) g_object_unref(cl->l); pango_attr_list_unref(cl->attr); g_free(cl->text); + if (cl->icon) cairo_surface_destroy(cl->icon); g_free(cl); } @@ -203,11 +205,20 @@ static dimension_t calculate_dimensions(GSList *layouts) dim.h += (g_slist_length(layouts) - 1) * settings.separator_height; dim.h += g_slist_length(layouts) * settings.padding * 2; + /* text_width: width of the widest content so far + * total_width: width of the widest notification so far, with padding + * dim.w: width of the window, with frame + * Also call r_setup_pango_layout() when changing text_width. + */ int text_width = 0, total_width = 0; for (GSList *iter = layouts; iter; iter = iter->next) { colored_layout *cl = iter->data; int w=0,h=0; pango_layout_get_pixel_size(cl->l, &w, &h); + if (cl->icon) { + h = MAX(cairo_image_surface_get_height(cl->icon), h); + w += cairo_image_surface_get_width(cl->icon) + settings.h_padding; + } dim.h += h; text_width = MAX(w, text_width); @@ -227,13 +238,18 @@ static dimension_t calculate_dimensions(GSList *layouts) } /* re-setup the layout */ - int width = dim.w; - width -= 2 * settings.h_padding; - width -= 2 * settings.frame_width; - r_setup_pango_layout(cl->l, width); + w = dim.w; + w -= 2 * settings.h_padding; + w -= 2 * settings.frame_width; + if (cl->icon) w -= cairo_image_surface_get_width(cl->icon) + settings.h_padding; + r_setup_pango_layout(cl->l, w); /* re-read information */ pango_layout_get_pixel_size(cl->l, &w, &h); + if (cl->icon) { + h = MAX(cairo_image_surface_get_height(cl->icon), h); + w += cairo_image_surface_get_width(cl->icon) + settings.h_padding; + } dim.h += h; text_width = MAX(w, text_width); } @@ -256,6 +272,9 @@ static colored_layout *r_init_shared(cairo_t *c, notification *n) pango_layout_set_ellipsize(cl->l, PANGO_ELLIPSIZE_MIDDLE); } + cl->icon = NULL; + if (strlen(n->icon) > 0 && settings.show_icons) + cl->icon = cairo_image_surface_create_from_png(n->icon); cl->fg = x_string_to_color_t(n->color_strings[ColFG]); cl->bg = x_string_to_color_t(n->color_strings[ColBG]); @@ -268,6 +287,7 @@ static colored_layout *r_init_shared(cairo_t *c, notification *n) } else { width -= 2 * settings.h_padding; width -= 2 * settings.frame_width; + if (cl->icon) width -= cairo_image_surface_get_width(cl->icon) + settings.h_padding; r_setup_pango_layout(cl->l, width); } @@ -309,6 +329,7 @@ static colored_layout *r_create_layout_from_notification(cairo_t *c, notificatio 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 += 2 * settings.padding; n->first_render = false; @@ -358,6 +379,7 @@ static dimension_t x_render_layout(cairo_t *c, colored_layout *cl, dimension_t d { int h; pango_layout_get_pixel_size(cl->l, NULL, &h); + if (cl->icon) h = MAX(cairo_image_surface_get_height(cl->icon), h); int bg_x = 0; int bg_y = dim.y; @@ -397,6 +419,16 @@ static dimension_t x_render_layout(cairo_t *c, colored_layout *cl, dimension_t d } cairo_move_to(c, settings.h_padding, dim.y); + if (cl->icon) { + unsigned int image_width = cairo_image_surface_get_width(cl->icon), + image_height = cairo_image_surface_get_height(cl->icon), + image_x = bg_width - settings.h_padding - image_width, + image_y = bg_y + settings.padding; + cairo_set_source_surface (c, cl->icon, image_x, image_y); + cairo_rectangle (c, image_x, image_y, image_width, image_height); + cairo_fill (c); + } + return dim; }