From ae2ce4fb7030ec388d3262f665d42c1c2a9d40fe Mon Sep 17 00:00:00 2001 From: tatou-tatou Date: Fri, 30 May 2014 00:41:32 +0200 Subject: [PATCH 01/72] Fix padding when there's an icon --- x.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/x.c b/x.c index 0b40aa4..714817e 100644 --- a/x.c +++ b/x.c @@ -219,6 +219,7 @@ 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; + dim.h += 2*settings.frame_width; int text_width = 0, total_width = 0; for (GSList *iter = layouts; iter; iter = iter->next) { @@ -430,7 +431,9 @@ 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); + if (cl->icon) { + h = MAX(cairo_image_surface_get_height(cl->icon), h); + } int bg_x = 0; int bg_y = dim.y; @@ -439,22 +442,22 @@ static dimension_t x_render_layout(cairo_t *c, colored_layout *cl, dimension_t d /* adding frame */ bg_x += settings.frame_width; - if (first) { - bg_y += settings.frame_width; - bg_height -= settings.frame_width; - } + bg_y += settings.frame_width; + bg_height -= settings.frame_width; bg_width -= 2 * settings.frame_width; - if (last) - bg_height -= settings.frame_width; + bg_height += settings.frame_width; cairo_set_source_rgb(c, cl->bg.r, cl->bg.g, cl->bg.b); cairo_rectangle(c, bg_x, bg_y, bg_width, bg_height); cairo_fill(c); dim.y += settings.padding; - if (cl->icon && settings.icon_position == icons_left) - cairo_move_to(c, cairo_image_surface_get_width(cl->icon) + 2 * settings.h_padding, dim.y); - else cairo_move_to(c, settings.h_padding, dim.y); + if (cl->icon && settings.icon_position == icons_left) { + cairo_move_to(c, cairo_image_surface_get_width(cl->icon) + 2 * settings.h_padding, bg_y + settings.padding ); + } + else { + cairo_move_to(c, settings.h_padding, bg_y + settings.padding); + } cairo_set_source_rgb(c, cl->fg.r, cl->fg.g, cl->fg.b); pango_cairo_update_layout(c, cl->l); pango_cairo_show_layout(c, cl->l); @@ -463,7 +466,7 @@ static dimension_t x_render_layout(cairo_t *c, colored_layout *cl, dimension_t d if (settings.separator_height > 0 && !last) { cairo_set_source_rgb(c, sep_color.r, sep_color.g, sep_color.b); - cairo_rectangle(c, settings.frame_width, dim.y, + cairo_rectangle(c, settings.frame_width, dim.y + settings.frame_width, dim.w - 2 * settings.frame_width , settings.separator_height); From c8575e1f91ef8482b4f6b3ee4df148a2df0b73f4 Mon Sep 17 00:00:00 2001 From: tatou-tatou Date: Fri, 30 May 2014 00:44:50 +0200 Subject: [PATCH 02/72] Center text vertically when there's an icon --- x.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x.c b/x.c index 714817e..391d885 100644 --- a/x.c +++ b/x.c @@ -430,8 +430,10 @@ static void r_free_layouts(GSList *layouts) static dimension_t x_render_layout(cairo_t *c, colored_layout *cl, dimension_t dim, bool first, bool last) { int h; + int h_text; pango_layout_get_pixel_size(cl->l, NULL, &h); if (cl->icon) { + h_text = h; h = MAX(cairo_image_surface_get_height(cl->icon), h); } @@ -453,7 +455,7 @@ static dimension_t x_render_layout(cairo_t *c, colored_layout *cl, dimension_t d dim.y += settings.padding; if (cl->icon && settings.icon_position == icons_left) { - cairo_move_to(c, cairo_image_surface_get_width(cl->icon) + 2 * settings.h_padding, bg_y + settings.padding ); + cairo_move_to(c, cairo_image_surface_get_width(cl->icon) + 2 * settings.h_padding, bg_y + settings.padding + h/2 - h_text/2); } else { cairo_move_to(c, settings.h_padding, bg_y + settings.padding); From bc31a638f630107c689b651182dfdd53d4a717b6 Mon Sep 17 00:00:00 2001 From: tatou-tatou Date: Sat, 31 May 2014 16:34:06 +0200 Subject: [PATCH 03/72] Horizontal padding is now inside the border too --- x.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x.c b/x.c index 391d885..aa5dad4 100644 --- a/x.c +++ b/x.c @@ -455,10 +455,10 @@ static dimension_t x_render_layout(cairo_t *c, colored_layout *cl, dimension_t d dim.y += settings.padding; if (cl->icon && settings.icon_position == icons_left) { - cairo_move_to(c, cairo_image_surface_get_width(cl->icon) + 2 * settings.h_padding, bg_y + settings.padding + h/2 - h_text/2); + cairo_move_to(c, settings.frame_width + cairo_image_surface_get_width(cl->icon) + 2 * settings.h_padding, bg_y + settings.padding + h/2 - h_text/2); } else { - cairo_move_to(c, settings.h_padding, bg_y + settings.padding); + cairo_move_to(c, settings.frame_width + settings.h_padding, bg_y + settings.padding); } cairo_set_source_rgb(c, cl->fg.r, cl->fg.g, cl->fg.b); pango_cairo_update_layout(c, cl->l); @@ -483,8 +483,8 @@ static dimension_t x_render_layout(cairo_t *c, colored_layout *cl, dimension_t d image_x, image_y = bg_y + settings.padding; - if (settings.icon_position == icons_left) image_x = settings.h_padding; - else image_x = bg_width - settings.h_padding - image_width; + if (settings.icon_position == icons_left) image_x = settings.frame_width + settings.h_padding; + else image_x = bg_width - settings.h_padding - image_width + settings.frame_width; cairo_set_source_surface (c, cl->icon, image_x, image_y); cairo_rectangle (c, image_x, image_y, image_width, image_height); From cee294d911b758acfa214209c38f07185b4016ad Mon Sep 17 00:00:00 2001 From: tatou-tatou Date: Sat, 31 May 2014 16:42:18 +0200 Subject: [PATCH 04/72] Text is vertically centered if the icon is on the right --- x.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/x.c b/x.c index aa5dad4..e033d52 100644 --- a/x.c +++ b/x.c @@ -457,6 +457,9 @@ static dimension_t x_render_layout(cairo_t *c, colored_layout *cl, dimension_t d if (cl->icon && settings.icon_position == icons_left) { cairo_move_to(c, settings.frame_width + cairo_image_surface_get_width(cl->icon) + 2 * settings.h_padding, bg_y + settings.padding + h/2 - h_text/2); } + else if (cl->icon && settings.icon_position == icons_right) { + cairo_move_to(c, settings.frame_width + settings.h_padding, bg_y + settings.padding + h/2 - h_text/2); + } else { cairo_move_to(c, settings.frame_width + settings.h_padding, bg_y + settings.padding); } From b6f56be97ba01d93843b206bbdab63b030e6e450 Mon Sep 17 00:00:00 2001 From: Andrew Krasichkov Date: Sun, 15 Nov 2015 21:16:37 +0200 Subject: [PATCH 05/72] Added support for more image formats for icons ( see knopwob/dunst#150 ) --- config.mk | 2 +- x.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/config.mk b/config.mk index 5171442..0a31b39 100644 --- a/config.mk +++ b/config.mk @@ -27,7 +27,7 @@ CFLAGS += -g --std=gnu99 -pedantic -Wall -Wno-overlength-strings -Os ${STATIC} pkg_config_packs := dbus-1 x11 freetype2 xext xft xscrnsaver \ "glib-2.0 >= 2.36" gio-2.0 \ - pango cairo pangocairo + pango cairo pangocairo gdk-2.0 # check if we need libxdg-basedir ifeq (,$(findstring STATIC_CONFIG,$(CFLAGS))) diff --git a/x.c b/x.c index c645925..5951f8e 100644 --- a/x.c +++ b/x.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "x.h" #include "utils.h" @@ -191,6 +192,17 @@ static bool have_dynamic_width(void) return (xctx.geometry.mask & WidthValue && xctx.geometry.w == 0); } +static bool is_readable_file(const char *filename) +{ + return (access(filename, R_OK) != -1); +} + +const char *get_filename_ext(const char *filename) { + const char *dot = strrchr(filename, '.'); + if(!dot || dot == filename) return ""; + return dot + 1; +} + static dimension_t calculate_dimensions(GSList *layouts) { dimension_t dim; @@ -274,6 +286,47 @@ static dimension_t calculate_dimensions(GSList *layouts) return dim; } +static cairo_surface_t *get_icon_surface_from_file(const char *icon_path) +{ + cairo_surface_t *icon_surface = NULL; + if (is_readable_file(icon_path)) { + char *img_type; + img_type = get_filename_ext(icon_path); + if (strcmp(img_type, "png") == 0) { + icon_surface = cairo_image_surface_create_from_png(icon_path); + } else { + GdkPixbuf *pixbuf; + GError *error = NULL; + cairo_t *cr; + cairo_format_t format; + double width, height; + pixbuf = gdk_pixbuf_new_from_file(icon_path, &error); + if (pixbuf != NULL) { + if (gdk_pixbuf_get_has_alpha(pixbuf)) { + format = CAIRO_FORMAT_ARGB32; + } else { + format = CAIRO_FORMAT_RGB24; + } + width = gdk_pixbuf_get_width(pixbuf); + height = gdk_pixbuf_get_height(pixbuf); + icon_surface = cairo_image_surface_create(format, width, height); + cr = cairo_create(icon_surface); + gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); + cairo_paint(cr); + free(cr); + g_object_unref(pixbuf); + } else { + g_free(error); + } + } + if (cairo_surface_status(icon_surface) != CAIRO_STATUS_SUCCESS) { + cairo_surface_destroy(icon_surface); + icon_surface = NULL; + } + } + return icon_surface; +} + static cairo_surface_t *get_icon_surface(char *icon_path) { cairo_surface_t *icon_surface = NULL; @@ -287,11 +340,7 @@ static cairo_surface_t *get_icon_surface(char *icon_path) } /* absolute path? */ if (icon_path[0] == '/' || icon_path[0] == '~') { - icon_surface = cairo_image_surface_create_from_png(icon_path); - if (cairo_surface_status(icon_surface) != CAIRO_STATUS_SUCCESS) { - cairo_surface_destroy(icon_surface); - icon_surface = NULL; - } + icon_surface = get_icon_surface_from_file(icon_path); } /* search in icon_folders */ if (icon_surface == NULL) { @@ -305,13 +354,10 @@ static cairo_surface_t *get_icon_surface(char *icon_path) maybe_icon_path = g_strconcat(current_folder, "/", icon_path, ".png", NULL); free(current_folder); - icon_surface = cairo_image_surface_create_from_png(maybe_icon_path); + icon_surface = get_icon_surface_from_file(maybe_icon_path); free(maybe_icon_path); - if (cairo_surface_status(icon_surface) == CAIRO_STATUS_SUCCESS) { - return icon_surface; - } else { - cairo_surface_destroy(icon_surface); - icon_surface = NULL; + if (icon_surface != NULL) { + return icon_surface; } start = end + 1; From a6d9626c54aafdae5620edb02512105ad17735cf Mon Sep 17 00:00:00 2001 From: Andrew Krasichkov Date: Wed, 9 Mar 2016 18:37:04 +0200 Subject: [PATCH 06/72] Try to support raw image data (see knopwob/dunst#151 ) --- dbus.c | 54 ++++++++++++++++++++++++++++++++++++++++++ notification.c | 15 ++++++++---- notification.h | 11 +++++++++ x.c | 64 ++++++++++++++++++++++++++++++++++++-------------- 4 files changed, 123 insertions(+), 21 deletions(-) diff --git a/dbus.c b/dbus.c index 27072e4..4d52933 100644 --- a/dbus.c +++ b/dbus.c @@ -74,6 +74,7 @@ static void onGetServerInformation(GDBusConnection * connection, const gchar * sender, const GVariant * parameters, GDBusMethodInvocation * invocation); +static RawImage * get_raw_image_from_data_hint(GVariant *icon_data); void handle_method_call(GDBusConnection * connection, const gchar * sender, @@ -140,6 +141,7 @@ static void onNotify(GDBusConnection * connection, gchar *fgcolor = NULL; gchar *bgcolor = NULL; gchar *category = NULL; + RawImage *raw_icon = NULL; actions->actions = NULL; actions->count = 0; @@ -232,6 +234,23 @@ static void onNotify(GDBusConnection * connection, dict_value, NULL); } + dict_value = + g_variant_lookup_value(content, + "image-data", + G_VARIANT_TYPE("(iiibiiay)")); + if (!dict_value) { + dict_value = + g_variant_lookup_value(content, + "icon_data", + G_VARIANT_TYPE("(iiibiiay)")); + } + + if (dict_value) { + raw_icon = + get_raw_image_from_data_hint( + dict_value); + } + dict_value = g_variant_lookup_value(content, "value", @@ -283,6 +302,7 @@ static void onNotify(GDBusConnection * connection, n->summary = summary; n->body = body; n->icon = icon; + n->raw_icon = raw_icon; n->timeout = timeout; n->allow_markup = settings.allow_markup; n->plain_text = settings.plain_text; @@ -412,6 +432,40 @@ static void on_name_lost(GDBusConnection * connection, exit(1); } +static RawImage * get_raw_image_from_data_hint(GVariant *icon_data) +{ + RawImage *image = malloc(sizeof(RawImage)); + GVariant *data_variant; + gsize expected_len; + + g_variant_get (icon_data, + "(iiibii@ay)", + &image->width, + &image->height, + &image->rowstride, + &image->has_alpha, + &image->bits_per_sample, + &image->n_channels, + &data_variant); + + expected_len = (image->height - 1) * image->rowstride + image->width + * ((image->n_channels * image->bits_per_sample + 7) / 8); + + if (expected_len != g_variant_get_size (data_variant)) { + fprintf(stderr, "Expected image data to be of length %" G_GSIZE_FORMAT + " but got a " "length of %" G_GSIZE_FORMAT, + expected_len, + g_variant_get_size (data_variant)); + free(image); + return NULL; + } + + image->data = (guchar *) g_memdup (g_variant_get_data (data_variant), + g_variant_get_size (data_variant)); + + return image; +} + int initdbus(void) { guint owner_id; diff --git a/notification.c b/notification.c index 21ccfee..0ae12af 100644 --- a/notification.c +++ b/notification.c @@ -161,6 +161,12 @@ void notification_free(notification * n) free(n->actions->dmenu_str); } + if (n->raw_icon) { + if (n->raw_icon->data) + free(n->raw_icon->data); + free(n->raw_icon); + } + free(n); } @@ -442,11 +448,12 @@ int notification_init(notification * n, int id) n->timeout == -1 ? settings.timeouts[n->urgency] : n->timeout; n->start = 0; - if (n->icon == NULL) { - n->icon = strdup(settings.icons[n->urgency]); - } - else if (strlen(n->icon) <= 0) { + if (strlen(n->icon) <= 0) { free(n->icon); + n->icon = NULL; + } + + if (n->raw_icon == NULL && n->icon == NULL) { n->icon = strdup(settings.icons[n->urgency]); } diff --git a/notification.h b/notification.h index 71422ea..c6b0b6a 100644 --- a/notification.h +++ b/notification.h @@ -7,6 +7,16 @@ #define NORM 1 #define CRIT 2 +typedef struct _raw_image { + int width; + int height; + int rowstride; + int has_alpha; + int bits_per_sample; + int n_channels; + unsigned char *data; +} RawImage; + typedef struct _actions { char **actions; char *dmenu_str; @@ -18,6 +28,7 @@ typedef struct _notification { char *summary; char *body; char *icon; + RawImage *raw_icon; char *msg; /* formatted message */ char *category; char *text_to_render; diff --git a/x.c b/x.c index 5951f8e..844c130 100644 --- a/x.c +++ b/x.c @@ -286,6 +286,24 @@ static dimension_t calculate_dimensions(GSList *layouts) return dim; } +static cairo_surface_t *gdk_pixbuf_to_cairo_surface(const GdkPixbuf *pixbuf) +{ + cairo_surface_t *icon_surface = NULL; + cairo_t *cr; + cairo_format_t format; + double width, height; + + format = gdk_pixbuf_get_has_alpha(pixbuf) ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24; + width = gdk_pixbuf_get_width(pixbuf); + height = gdk_pixbuf_get_height(pixbuf); + icon_surface = cairo_image_surface_create(format, width, height); + cr = cairo_create(icon_surface); + gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); + cairo_paint(cr); + free(cr); + return icon_surface; +} + static cairo_surface_t *get_icon_surface_from_file(const char *icon_path) { cairo_surface_t *icon_surface = NULL; @@ -297,23 +315,9 @@ static cairo_surface_t *get_icon_surface_from_file(const char *icon_path) } else { GdkPixbuf *pixbuf; GError *error = NULL; - cairo_t *cr; - cairo_format_t format; - double width, height; pixbuf = gdk_pixbuf_new_from_file(icon_path, &error); if (pixbuf != NULL) { - if (gdk_pixbuf_get_has_alpha(pixbuf)) { - format = CAIRO_FORMAT_ARGB32; - } else { - format = CAIRO_FORMAT_RGB24; - } - width = gdk_pixbuf_get_width(pixbuf); - height = gdk_pixbuf_get_height(pixbuf); - icon_surface = cairo_image_surface_create(format, width, height); - cr = cairo_create(icon_surface); - gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); - cairo_paint(cr); - free(cr); + icon_surface = gdk_pixbuf_to_cairo_surface(pixbuf); g_object_unref(pixbuf); } else { g_free(error); @@ -327,7 +331,7 @@ static cairo_surface_t *get_icon_surface_from_file(const char *icon_path) return icon_surface; } -static cairo_surface_t *get_icon_surface(char *icon_path) +static cairo_surface_t *get_icon_surface_from_path(char *icon_path) { cairo_surface_t *icon_surface = NULL; gchar *uri_path = NULL; @@ -374,6 +378,28 @@ static cairo_surface_t *get_icon_surface(char *icon_path) return icon_surface; } +static cairo_surface_t *get_icon_surface_from_raw_image(const RawImage *raw_image) +{ + cairo_surface_t *icon_surface = NULL; + GdkPixbuf *pixbuf; + + pixbuf = gdk_pixbuf_new_from_data(raw_image->data, + GDK_COLORSPACE_RGB, + raw_image->has_alpha, + raw_image->bits_per_sample, + raw_image->width, + raw_image->height, + raw_image->rowstride, + NULL, + NULL); + + if (pixbuf != NULL) { + icon_surface = gdk_pixbuf_to_cairo_surface(pixbuf); + g_object_unref(pixbuf); + } + return icon_surface; +} + static colored_layout *r_init_shared(cairo_t *c, notification *n) { colored_layout *cl = malloc(sizeof(colored_layout)); @@ -386,7 +412,11 @@ static colored_layout *r_init_shared(cairo_t *c, notification *n) pango_layout_set_ellipsize(cl->l, PANGO_ELLIPSIZE_MIDDLE); } - cl->icon = get_icon_surface(n->icon); + if (n->icon) { + cl->icon = get_icon_surface_from_path(n->icon); + } else if (n->raw_icon) { + cl->icon = get_icon_surface_from_raw_image(n->raw_icon); + } cl->fg = x_string_to_color_t(n->color_strings[ColFG]); cl->bg = x_string_to_color_t(n->color_strings[ColBG]); From 94eecd6b3b32be1b7103bb48aa8bde92755ca4bd Mon Sep 17 00:00:00 2001 From: Bernard Nauwelaerts Date: Fri, 2 Sep 2016 11:21:36 +0200 Subject: [PATCH 07/72] fix/read-category-from-rule --- settings.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/settings.c b/settings.c index c05545e..de9e93f 100644 --- a/settings.c +++ b/settings.c @@ -363,6 +363,7 @@ void load_settings(char *cmdline_config_path) r->summary = ini_get_string(cur_section, "summary", r->summary); r->body = ini_get_string(cur_section, "body", r->body); r->icon = ini_get_string(cur_section, "icon", r->icon); + r->category = ini_get_string(cur_section, "category", r->category); r->timeout = ini_get_int(cur_section, "timeout", r->timeout); r->allow_markup = ini_get_bool(cur_section, "allow_markup", r->allow_markup); r->plain_text = ini_get_bool(cur_section, "plain_text", r->plain_text); @@ -372,7 +373,7 @@ void load_settings(char *cmdline_config_path) r->bg = ini_get_string(cur_section, "background", r->bg); r->format = ini_get_string(cur_section, "format", r->format); r->new_icon = ini_get_string(cur_section, "new_icon", r->new_icon); - r->script = ini_get_string(cur_section, "script", NULL); + r->script = ini_get_string(cur_section, "script", NULL); } #ifndef STATIC_CONFIG From bd84bcb70dea54adb7c08a7bfb9a0f96a3f226a6 Mon Sep 17 00:00:00 2001 From: Bernard Nauwelaerts Date: Fri, 2 Sep 2016 14:05:24 +0200 Subject: [PATCH 08/72] fix/sigsegv-due-to-null-notification-category --- notification.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/notification.c b/notification.c index 21ccfee..af37e9e 100644 --- a/notification.c +++ b/notification.c @@ -335,6 +335,10 @@ int notification_init(notification * n, int id) n->format = settings.format; + if (n->category == NULL) { + n->category = ""; + } + rule_apply_all(n); n->urls = notification_extract_markup_urls(&(n->body)); @@ -450,10 +454,6 @@ int notification_init(notification * n, int id) n->icon = strdup(settings.icons[n->urgency]); } - if (n->category == NULL) { - n->category = ""; - } - n->timestamp = time(NULL); n->redisplayed = false; From f1b0e83776689e7df1daad67a871770ac1d7fad2 Mon Sep 17 00:00:00 2001 From: "Johannes M. Griebler" Date: Thu, 13 Oct 2016 17:30:08 +0200 Subject: [PATCH 09/72] Take lightweight tags into account in VERSION --- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.mk b/config.mk index 5171442..32d1d5d 100644 --- a/config.mk +++ b/config.mk @@ -5,7 +5,7 @@ MANPREFIX = ${PREFIX}/share/man # In dist tarballs, the version is stored in the VERSION files. VERSION := '$(shell [ -f VERSION ] && cat VERSION)' ifeq ('',$(VERSION)) -VERSION := $(shell git describe) +VERSION := $(shell git describe --tags) endif # Xinerama, comment if you don't want it From 1c1d173379bcd55a4f04fa11244e940b8769ef4d Mon Sep 17 00:00:00 2001 From: "Johannes M. Griebler" Date: Thu, 13 Oct 2016 19:59:08 +0200 Subject: [PATCH 10/72] Fix segfault while displaying startup notification --- dunst.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dunst.c b/dunst.c index d8bf621..84cfcb0 100644 --- a/dunst.c +++ b/dunst.c @@ -331,6 +331,7 @@ int main(int argc, char *argv[]) n->plain_text = true; n->urgency = LOW; n->icon = NULL; + n->raw_icon = NULL; n->category = NULL; n->msg = NULL; n->dbus_client = NULL; From 9e80de6153070f534beef138dd1233c4e7cdfd1f Mon Sep 17 00:00:00 2001 From: "Johannes M. Griebler" Date: Thu, 13 Oct 2016 20:51:49 +0200 Subject: [PATCH 11/72] Actually fix segfault --- notification.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notification.c b/notification.c index 0ae12af..cc05ce2 100644 --- a/notification.c +++ b/notification.c @@ -448,7 +448,7 @@ int notification_init(notification * n, int id) n->timeout == -1 ? settings.timeouts[n->urgency] : n->timeout; n->start = 0; - if (strlen(n->icon) <= 0) { + if (n->icon != NULL && strlen(n->icon) <= 0) { free(n->icon); n->icon = NULL; } From 342a23548f290d0ec36dc6e6e6be411cd9d6854b Mon Sep 17 00:00:00 2001 From: "Johannes M. Griebler" Date: Fri, 14 Oct 2016 17:48:59 +0200 Subject: [PATCH 12/72] Scale images down if they exceed a certain size --- x.c | 96 ++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 53 insertions(+), 43 deletions(-) diff --git a/x.c b/x.c index 844c130..65fa442 100644 --- a/x.c +++ b/x.c @@ -304,36 +304,21 @@ static cairo_surface_t *gdk_pixbuf_to_cairo_surface(const GdkPixbuf *pixbuf) return icon_surface; } -static cairo_surface_t *get_icon_surface_from_file(const char *icon_path) +static GdkPixbuf *get_pixbuf_from_file(const char *icon_path) { - cairo_surface_t *icon_surface = NULL; + GdkPixbuf *pixbuf; if (is_readable_file(icon_path)) { - char *img_type; - img_type = get_filename_ext(icon_path); - if (strcmp(img_type, "png") == 0) { - icon_surface = cairo_image_surface_create_from_png(icon_path); - } else { - GdkPixbuf *pixbuf; - GError *error = NULL; - pixbuf = gdk_pixbuf_new_from_file(icon_path, &error); - if (pixbuf != NULL) { - icon_surface = gdk_pixbuf_to_cairo_surface(pixbuf); - g_object_unref(pixbuf); - } else { - g_free(error); - } - } - if (cairo_surface_status(icon_surface) != CAIRO_STATUS_SUCCESS) { - cairo_surface_destroy(icon_surface); - icon_surface = NULL; - } + GError *error = NULL; + pixbuf = gdk_pixbuf_new_from_file(icon_path, &error); + if (pixbuf == NULL) + g_free(error); } - return icon_surface; + return pixbuf; } -static cairo_surface_t *get_icon_surface_from_path(char *icon_path) +static GdkPixbuf *get_pixbuf_from_path(char *icon_path) { - cairo_surface_t *icon_surface = NULL; + GdkPixbuf *pixbuf = NULL; gchar *uri_path = NULL; if (strlen(icon_path) > 0 && settings.icon_position != icons_off) { if (g_str_has_prefix(icon_path, "file://")) { @@ -344,10 +329,10 @@ static cairo_surface_t *get_icon_surface_from_path(char *icon_path) } /* absolute path? */ if (icon_path[0] == '/' || icon_path[0] == '~') { - icon_surface = get_icon_surface_from_file(icon_path); + pixbuf = get_pixbuf_from_file(icon_path); } /* search in icon_folders */ - if (icon_surface == NULL) { + if (pixbuf == NULL) { char *start = settings.icon_folders, *end, *current_folder, *maybe_icon_path; do { @@ -358,16 +343,16 @@ static cairo_surface_t *get_icon_surface_from_path(char *icon_path) maybe_icon_path = g_strconcat(current_folder, "/", icon_path, ".png", NULL); free(current_folder); - icon_surface = get_icon_surface_from_file(maybe_icon_path); + pixbuf = get_pixbuf_from_file(maybe_icon_path); free(maybe_icon_path); - if (icon_surface != NULL) { - return icon_surface; + if (pixbuf != NULL) { + return pixbuf; } start = end + 1; } while (*(end) != '\0'); } - if (icon_surface == NULL) { + if (pixbuf == NULL) { fprintf(stderr, "Could not load icon: '%s'\n", icon_path); } @@ -375,12 +360,11 @@ static cairo_surface_t *get_icon_surface_from_path(char *icon_path) g_free(uri_path); } } - return icon_surface; + return pixbuf; } -static cairo_surface_t *get_icon_surface_from_raw_image(const RawImage *raw_image) +static GdkPixbuf *get_pixbuf_from_raw_image(const RawImage *raw_image) { - cairo_surface_t *icon_surface = NULL; GdkPixbuf *pixbuf; pixbuf = gdk_pixbuf_new_from_data(raw_image->data, @@ -393,11 +377,7 @@ static cairo_surface_t *get_icon_surface_from_raw_image(const RawImage *raw_imag NULL, NULL); - if (pixbuf != NULL) { - icon_surface = gdk_pixbuf_to_cairo_surface(pixbuf); - g_object_unref(pixbuf); - } - return icon_surface; + return pixbuf; } static colored_layout *r_init_shared(cairo_t *c, notification *n) @@ -412,10 +392,40 @@ static colored_layout *r_init_shared(cairo_t *c, notification *n) pango_layout_set_ellipsize(cl->l, PANGO_ELLIPSIZE_MIDDLE); } - if (n->icon) { - cl->icon = get_icon_surface_from_path(n->icon); - } else if (n->raw_icon) { - cl->icon = get_icon_surface_from_raw_image(n->raw_icon); + GdkPixbuf *pixbuf; + + if (n->raw_icon) { + pixbuf = get_pixbuf_from_raw_image(n->raw_icon); + } else if (n->icon) { + pixbuf = get_pixbuf_from_path(n->icon); + } + + if (pixbuf != NULL) { + int w = gdk_pixbuf_get_width(pixbuf); + int h = gdk_pixbuf_get_height(pixbuf); + int larger = w > h ? w : h; + int max_size = 24; + if (larger > max_size) { + if (w >= h) { + pixbuf = gdk_pixbuf_scale_simple(pixbuf, + max_size, (int) ((double) max_size / w * h), + GDK_INTERP_BILINEAR); + } else { + pixbuf = gdk_pixbuf_scale_simple(pixbuf, + (int) ((double) max_size / h * w), max_size, + GDK_INTERP_BILINEAR); + } + } + + cl->icon = gdk_pixbuf_to_cairo_surface(pixbuf); + g_object_unref(pixbuf); + } else { + cl->icon = NULL; + } + + if (cairo_surface_status(cl->icon) != CAIRO_STATUS_SUCCESS) { + cairo_surface_destroy(cl->icon); + cl->icon = NULL; } cl->fg = x_string_to_color_t(n->color_strings[ColFG]); @@ -599,7 +609,7 @@ void x_win_draw(void) int width = dim.w; int height = dim.h; - if ((have_dynamic_width() || settings.shrink) && settings.align != left) { + if ((have_dynamic_width() || settings.shrink) && settings.align != left) { r_update_layouts_width(layouts, width); } From ce8fe45cbf81b351b6802c25563b60e418d271cf Mon Sep 17 00:00:00 2001 From: "Johannes M. Griebler" Date: Fri, 14 Oct 2016 18:12:09 +0200 Subject: [PATCH 13/72] Add configuration option for icon scaling The maximum size for icons can now be set with the max_icon_size option. Setting its value to 0 will disable the scaling of icons. --- config.def.h | 2 ++ settings.c | 10 +++++++--- settings.h | 3 ++- x.c | 9 +++++---- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/config.def.h b/config.def.h index 3f00209..d91e495 100644 --- a/config.def.h +++ b/config.def.h @@ -56,6 +56,8 @@ char *dmenu = "/usr/bin/dmenu"; char *browser = "/usr/bin/firefox"; +int max_icon_size = 32; + /* paths to default icons */ char *icon_folders = "/usr/share/icons/gnome/16x16/status/:/usr/share/icons/gnome/16x16/devices/"; diff --git a/settings.c b/settings.c index c05545e..54baea4 100644 --- a/settings.c +++ b/settings.c @@ -179,8 +179,8 @@ void load_settings(char *cmdline_config_path) "Max amount of notifications kept in history"); settings.show_indicators = option_get_bool("global", "show_indicators", "-show_indicators", - show_indicators, - "Show indicators for actions \"(A)\" and URLs \"(U)\""); + show_indicators, + "Show indicators for actions \"(A)\" and URLs \"(U)\""); settings.separator_height = option_get_int("global", "separator_height", "-sep_height/-separator_height", separator_height, @@ -249,6 +249,10 @@ void load_settings(char *cmdline_config_path) } } + settings.max_icon_size = + option_get_int("global", "max_icon_size", "-max_icon_size", max_icon_size, + "Scale larger icons down to this size, set to 0 to disable"); + settings.icon_folders = option_get_string("global", "icon_folders", "-icon_folders", icon_folders, "paths to default icons"); @@ -372,7 +376,7 @@ void load_settings(char *cmdline_config_path) r->bg = ini_get_string(cur_section, "background", r->bg); r->format = ini_get_string(cur_section, "format", r->format); r->new_icon = ini_get_string(cur_section, "new_icon", r->new_icon); - r->script = ini_get_string(cur_section, "script", NULL); + r->script = ini_get_string(cur_section, "script", NULL); } #ifndef STATIC_CONFIG diff --git a/settings.h b/settings.h index c8b9631..f5b8a0a 100644 --- a/settings.h +++ b/settings.h @@ -29,7 +29,7 @@ typedef struct _settings { float bounce_freq; int sticky_history; int history_length; - int show_indicators; + int show_indicators; int verbosity; int word_wrap; int ignore_newline; @@ -49,6 +49,7 @@ typedef struct _settings { char **dmenu_cmd; char *browser; enum icon_position_t icon_position; + int max_icon_size; char *icon_folders; enum follow_mode f_mode; bool always_run_script; diff --git a/x.c b/x.c index 65fa442..c370eb2 100644 --- a/x.c +++ b/x.c @@ -404,15 +404,16 @@ static colored_layout *r_init_shared(cairo_t *c, notification *n) int w = gdk_pixbuf_get_width(pixbuf); int h = gdk_pixbuf_get_height(pixbuf); int larger = w > h ? w : h; - int max_size = 24; - if (larger > max_size) { + if (settings.max_icon_size && larger > settings.max_icon_size) { if (w >= h) { pixbuf = gdk_pixbuf_scale_simple(pixbuf, - max_size, (int) ((double) max_size / w * h), + settings.max_icon_size, + (int) ((double) settings.max_icon_size / w * h), GDK_INTERP_BILINEAR); } else { pixbuf = gdk_pixbuf_scale_simple(pixbuf, - (int) ((double) max_size / h * w), max_size, + (int) ((double) settings.max_icon_size / h * w), + settings.max_icon_size, GDK_INTERP_BILINEAR); } } From 57d3b293a28e81893a2307d085222bdc609405c3 Mon Sep 17 00:00:00 2001 From: "Johannes M. Griebler" Date: Sun, 16 Oct 2016 12:18:45 +0200 Subject: [PATCH 14/72] Free original pixbuf after scaling --- x.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/x.c b/x.c index c370eb2..01aa62e 100644 --- a/x.c +++ b/x.c @@ -405,17 +405,20 @@ static colored_layout *r_init_shared(cairo_t *c, notification *n) int h = gdk_pixbuf_get_height(pixbuf); int larger = w > h ? w : h; if (settings.max_icon_size && larger > settings.max_icon_size) { + GdkPixbuf *scaled; if (w >= h) { - pixbuf = gdk_pixbuf_scale_simple(pixbuf, + scaled = gdk_pixbuf_scale_simple(pixbuf, settings.max_icon_size, (int) ((double) settings.max_icon_size / w * h), GDK_INTERP_BILINEAR); } else { - pixbuf = gdk_pixbuf_scale_simple(pixbuf, + scaled = gdk_pixbuf_scale_simple(pixbuf, (int) ((double) settings.max_icon_size / h * w), settings.max_icon_size, GDK_INTERP_BILINEAR); } + g_object_unref(pixbuf); + pixbuf = scaled; } cl->icon = gdk_pixbuf_to_cairo_surface(pixbuf); From 7ba4c1cc9bfb590100f9bd4ab607186555565f59 Mon Sep 17 00:00:00 2001 From: "Johannes M. Griebler" Date: Sun, 16 Oct 2016 22:29:10 +0200 Subject: [PATCH 15/72] Fix two segfaults trying to display invalid icons --- x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x.c b/x.c index 01aa62e..d6975bf 100644 --- a/x.c +++ b/x.c @@ -306,7 +306,7 @@ static cairo_surface_t *gdk_pixbuf_to_cairo_surface(const GdkPixbuf *pixbuf) static GdkPixbuf *get_pixbuf_from_file(const char *icon_path) { - GdkPixbuf *pixbuf; + GdkPixbuf *pixbuf = NULL; if (is_readable_file(icon_path)) { GError *error = NULL; pixbuf = gdk_pixbuf_new_from_file(icon_path, &error); @@ -427,7 +427,7 @@ static colored_layout *r_init_shared(cairo_t *c, notification *n) cl->icon = NULL; } - if (cairo_surface_status(cl->icon) != CAIRO_STATUS_SUCCESS) { + if (cl->icon && cairo_surface_status(cl->icon) != CAIRO_STATUS_SUCCESS) { cairo_surface_destroy(cl->icon); cl->icon = NULL; } From 539d4dd1024fba48044eaed80eb8c60601599867 Mon Sep 17 00:00:00 2001 From: Justin Jacobs Date: Tue, 10 Mar 2015 11:21:39 -0400 Subject: [PATCH 16/72] Fix crash from uninitialized pointer value --- dbus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dbus.c b/dbus.c index 4d52933..188a31c 100644 --- a/dbus.c +++ b/dbus.c @@ -145,6 +145,7 @@ static void onNotify(GDBusConnection * connection, actions->actions = NULL; actions->count = 0; + actions->dmenu_str = NULL; { GVariantIter *iter = g_variant_iter_new(parameters); From f25c2945699a3e6f7b0be3a9e678c51af8959626 Mon Sep 17 00:00:00 2001 From: kongo2002 Date: Mon, 20 Jul 2015 11:47:07 +0200 Subject: [PATCH 17/72] fix memleaks --- notification.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/notification.c b/notification.c index cc05ce2..1039cb8 100644 --- a/notification.c +++ b/notification.c @@ -156,6 +156,15 @@ void notification_free(notification * n) free(n->msg); free(n->dbus_client); + if (n->category && *n->category != '\0') + g_free(n->category); + + if (n->text_to_render) + g_free(n->text_to_render); + + if (n->urls) + g_free(n->urls); + if (n->actions) { g_strfreev(n->actions->actions); free(n->actions->dmenu_str); From 4f16213f9fa81d01cbb6d7163a100d72b7a4da08 Mon Sep 17 00:00:00 2001 From: kongo2002 Date: Mon, 20 Jul 2015 15:20:54 +0200 Subject: [PATCH 18/72] add some graceful termination handling --- dbus.c | 3 +++ dunst.c | 49 +++++++++++++++++++++++++++++++++++++++++++++---- menu.c | 51 ++++++++++++++++++++++++++++++++++----------------- menu.h | 1 + x.c | 9 +++++++++ x.h | 1 + 6 files changed, 93 insertions(+), 21 deletions(-) diff --git a/dbus.c b/dbus.c index 188a31c..0aeff83 100644 --- a/dbus.c +++ b/dbus.c @@ -489,6 +489,9 @@ int initdbus(void) void dbus_tear_down(int owner_id) { + if (introspection_data) + g_dbus_node_info_unref(introspection_data); + g_bus_unown_name(owner_id); } diff --git a/dunst.c b/dunst.c index 84cfcb0..4c9591e 100644 --- a/dunst.c +++ b/dunst.c @@ -34,6 +34,7 @@ #include "utils.h" #include "rules.h" #include "notification.h" +#include "menu.h" #include "option_parser.h" #include "settings.h" @@ -272,7 +273,7 @@ gboolean run(void *data) return false; } -gboolean pause_signal (gpointer data) +gboolean pause_signal(gpointer data) { pause_display = true; wake_up(); @@ -280,7 +281,7 @@ gboolean pause_signal (gpointer data) return G_SOURCE_CONTINUE; } -gboolean unpause_signal (gpointer data) +gboolean unpause_signal(gpointer data) { pause_display = false; wake_up(); @@ -288,6 +289,30 @@ gboolean unpause_signal (gpointer data) return G_SOURCE_CONTINUE; } +gboolean quit_signal(gpointer data) +{ + g_main_loop_quit(mainloop); + + return G_SOURCE_CONTINUE; +} + +static void teardown_notification(gpointer data) +{ + notification *n = data; + notification_free(n); +} + +static void teardown(void) +{ + regex_teardown(); + + g_queue_free_full(history, teardown_notification); + g_queue_free_full(displayed, teardown_notification); + g_queue_free_full(queue, teardown_notification); + + x_free(); +} + int main(int argc, char *argv[]) { @@ -365,14 +390,30 @@ int main(int argc, char *argv[]) g_source_attach(x11_source, NULL); - g_unix_signal_add(SIGUSR1, pause_signal, NULL); - g_unix_signal_add(SIGUSR2, unpause_signal, NULL); + guint pause_src = g_unix_signal_add(SIGUSR1, pause_signal, NULL); + guint unpause_src = g_unix_signal_add(SIGUSR2, unpause_signal, NULL); + + /* register SIGINT/SIGTERM handler for + * graceful termination */ + guint term_src = g_unix_signal_add(SIGTERM, quit_signal, NULL); + guint int_src = g_unix_signal_add(SIGINT, quit_signal, NULL); run(NULL); g_main_loop_run(mainloop); + g_main_loop_unref(mainloop); + + /* remove signal handler watches */ + g_source_remove(pause_src); + g_source_remove(unpause_src); + g_source_remove(term_src); + g_source_remove(int_src); + + g_source_destroy(x11_source); dbus_tear_down(owner_id); + teardown(); + return 0; } diff --git a/menu.c b/menu.c index 8c2962a..3839df4 100644 --- a/menu.c +++ b/menu.c @@ -15,6 +15,37 @@ #include "settings.h" #include "dbus.h" +static bool is_initialized = false; +static regex_t cregex; + +static int regex_init(void) +{ + if (is_initialized) + return 1; + + char *regex = + "\\b(https?://|ftps?://|news://|mailto:|file://|www\\.)" + "[-[:alnum:]_\\@;/?:&=%$.+!*\x27,~#]*" + "(\\([-[:alnum:]_\\@;/?:&=%$.+!*\x27,~#]*\\)|[-[:alnum:]_\\@;/?:&=%$+*~])+"; + int ret = regcomp(&cregex, regex, REG_EXTENDED | REG_ICASE); + if (ret != 0) { + fputs("failed to compile regex", stderr); + return 0; + } else { + is_initialized = true; + return 1; + } +} + +void regex_teardown(void) +{ + if (is_initialized) + { + regfree(&cregex); + is_initialized = false; + } +} + /* * Exctract all urls from a given string. * @@ -23,25 +54,11 @@ */ char *extract_urls(const char *to_match) { - static bool is_initialized = false; - static regex_t cregex; - - if (!is_initialized) { - char *regex = - "\\b(https?://|ftps?://|news://|mailto:|file://|www\\.)" - "[-[:alnum:]_\\@;/?:&=%$.+!*\x27,~#]*" - "(\\([-[:alnum:]_\\@;/?:&=%$.+!*\x27,~#]*\\)|[-[:alnum:]_\\@;/?:&=%$+*~])+"; - int ret = regcomp(&cregex, regex, REG_EXTENDED | REG_ICASE); - if (ret != 0) { - printf("failed to compile regex\n"); - return NULL; - } else { - is_initialized = true; - } - } - char *urls = NULL; + if (!regex_init()) + return NULL; + const char *p = to_match; regmatch_t m; diff --git a/menu.h b/menu.h index 805b6a1..01dda4a 100644 --- a/menu.h +++ b/menu.h @@ -5,3 +5,4 @@ char *extract_urls(const char *to_match); void open_browser(const char *url); void invoke_action(const char *action); +void regex_teardown(void); diff --git a/x.c b/x.c index d6975bf..309839a 100644 --- a/x.c +++ b/x.c @@ -1011,6 +1011,15 @@ static void x_screen_info(screen_info * scr) } } +void x_free(void) +{ + cairo_surface_destroy(cairo_ctx.surface); + cairo_destroy(cairo_ctx.context); + + if (xctx.dpy) + XCloseDisplay(xctx.dpy); +} + /* * Setup X11 stuff */ diff --git a/x.h b/x.h index aeb48f6..cf0b27b 100644 --- a/x.h +++ b/x.h @@ -77,6 +77,7 @@ KeySym x_shortcut_string_to_mask(const char *str); /* X misc */ bool x_is_idle(void); void x_setup(void); +void x_free(void); gboolean x_mainloop_fd_dispatch(GSource * source, GSourceFunc callback, gpointer user_data); From be72e22c3891a65b400241880b3582bca74dae09 Mon Sep 17 00:00:00 2001 From: Ilya Tumaykin Date: Fri, 29 Jul 2016 01:53:01 +0100 Subject: [PATCH 19/72] Fix: Respect CFLAGS when building dunstify https://github.com/knopwob/dunst/issues/267 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3d31830..a70e532 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ dunst: ${OBJ} @${CC} ${CFLAGS} -o $@ ${OBJ} ${LDFLAGS} dunstify: - @${CC} -o $@ dunstify.c -std=c99 $(shell pkg-config --libs --cflags glib-2.0 libnotify) + @${CC} ${CFLAGS} -o $@ dunstify.c -std=c99 $(shell pkg-config --libs --cflags glib-2.0 libnotify) debug: ${OBJ} @echo CC -o $@ From d2c63f1f00130a8709c1d5676cfd519da9ea9751 Mon Sep 17 00:00:00 2001 From: Ilya Tumaykin Date: Fri, 29 Jul 2016 02:14:35 +0100 Subject: [PATCH 20/72] Fix: Add a couple of missing stdlib.h includes required for exit() https://github.com/knopwob/dunst/issues/267 --- menu.c | 1 + notification.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/menu.c b/menu.c index 3839df4..fb05798 100644 --- a/menu.c +++ b/menu.c @@ -1,6 +1,7 @@ /* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ #define _GNU_SOURCE +#include #include #include #include diff --git a/notification.c b/notification.c index 1039cb8..b170977 100644 --- a/notification.c +++ b/notification.c @@ -1,7 +1,7 @@ /* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ #define _GNU_SOURCE - +#include #include #include #include From 8ca41b13a8f3e9134398aa4e98d7728736a731a0 Mon Sep 17 00:00:00 2001 From: Ilya Tumaykin Date: Fri, 29 Jul 2016 02:22:36 +0100 Subject: [PATCH 21/72] Fix: Multiple implicitly declared functions https://github.com/knopwob/dunst/issues/267 --- dunst.h | 1 + settings.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/dunst.h b/dunst.h index c4c7519..054c99e 100644 --- a/dunst.h +++ b/dunst.h @@ -3,6 +3,7 @@ #pragma once #include +#include #include #include "x.h" diff --git a/settings.c b/settings.c index 54baea4..e8d4cd3 100644 --- a/settings.c +++ b/settings.c @@ -1,6 +1,8 @@ /* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ #include +#include +#include #ifndef STATIC_CONFIG #include From 40905c9ff8ff256b9d0c3c0854e816320ae18afe Mon Sep 17 00:00:00 2001 From: Ilya Tumaykin Date: Fri, 29 Jul 2016 02:10:45 +0100 Subject: [PATCH 22/72] Remove unneeded Xft include in x.h https://github.com/knopwob/dunst/issues/267 --- x.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/x.h b/x.h index cf0b27b..48b076f 100644 --- a/x.h +++ b/x.h @@ -13,8 +13,6 @@ #endif #include -#include - #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) #define FONT_HEIGHT_BORDER 2 #define DEFFONT "Monospace-11" From 30085f7abdb9623c349f21a2efe54265f0e8a80d Mon Sep 17 00:00:00 2001 From: Moritz Luedecke Date: Sat, 25 Jun 2016 13:38:24 +0200 Subject: [PATCH 23/72] Add option to hide duplicates count --- notification.c | 6 +++--- settings.c | 4 ++++ settings.h | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/notification.c b/notification.c index b170977..da3c80a 100644 --- a/notification.c +++ b/notification.c @@ -586,8 +586,8 @@ void notification_update_text_to_render(notification *n) char *msg = g_strstrip(n->msg); /* print dup_count and msg */ - if (n->dup_count > 0 && (n->actions || n->urls) - && settings.show_indicators) { + if ((n->dup_count > 0 && !settings.hide_duplicates_count) + && (n->actions || n->urls) && settings.show_indicators) { buf = g_strdup_printf("(%d%s%s) %s", n->dup_count, n->actions ? "A" : "", @@ -596,7 +596,7 @@ void notification_update_text_to_render(notification *n) buf = g_strdup_printf("(%s%s) %s", n->actions ? "A" : "", n->urls ? "U" : "", msg); - } else if (n->dup_count > 0) { + } else if (n->dup_count > 0 && !settings.hide_duplicates_count) { buf = g_strdup_printf("(%d) %s", n->dup_count, msg); } else { buf = g_strdup(msg); diff --git a/settings.c b/settings.c index e8d4cd3..ae0c14c 100644 --- a/settings.c +++ b/settings.c @@ -171,6 +171,10 @@ void load_settings(char *cmdline_config_path) option_get_int("global", "show_age_threshold", "-show_age_threshold", show_age_threshold, "When should the age of the notification be displayed?"); + settings.hide_duplicates_count = + option_get_bool("global", "hide_duplicates_count", + "-hide_duplicates_count", false, + "Hide count of the merged notifications with the same content"); settings.sticky_history = option_get_bool("global", "sticky_history", "-sticky_history", sticky_history, diff --git a/settings.h b/settings.h index f5b8a0a..fec97a3 100644 --- a/settings.h +++ b/settings.h @@ -6,6 +6,7 @@ typedef struct _settings { bool allow_markup; bool plain_text; bool stack_duplicates; + bool hide_duplicates_count; char *font; char *normbgcolor; char *normfgcolor; From 8ee86dc477962e58bd018e5a7430ac78f882ebff Mon Sep 17 00:00:00 2001 From: Jakob Nixdorf Date: Wed, 12 Mar 2014 12:22:12 +0100 Subject: [PATCH 24/72] add initial support for per-urgency frame-colors --- dunst.h | 5 ++-- dunstrc | 1 + notification.c | 5 ++++ notification.h | 2 +- settings.c | 9 ++++++ settings.h | 3 ++ x.c | 74 +++++++++++++++++++++++++++++++++++--------------- x.h | 3 +- 8 files changed, 75 insertions(+), 27 deletions(-) diff --git a/dunst.h b/dunst.h index 054c99e..a27a9fa 100644 --- a/dunst.h +++ b/dunst.h @@ -13,7 +13,8 @@ #define PERR(msg, errnum) printf("(%d) %s : %s\n", __LINE__, (msg), (strerror(errnum))) #define LENGTH(X) (sizeof X / sizeof X[0]) -#define ColLast 2 +#define ColLast 3 +#define ColFrame 2 #define ColFG 1 #define ColBG 0 @@ -28,7 +29,7 @@ extern GQueue *displayed; extern GQueue *history; extern GSList *rules; extern bool pause_display; -extern const char *color_strings[2][3]; +extern const char *color_strings[3][3]; /* return id of notification */ gboolean run(void *data); diff --git a/dunstrc b/dunstrc index 61fa321..37407c7 100644 --- a/dunstrc +++ b/dunstrc @@ -194,6 +194,7 @@ [urgency_critical] background = "#900000" foreground = "#ffffff" + frame_color = "#ff0000" timeout = 0 diff --git a/notification.c b/notification.c index da3c80a..b0b12a4 100644 --- a/notification.c +++ b/notification.c @@ -37,6 +37,7 @@ void notification_print(notification * n) printf("\tformatted: '%s'\n", n->msg); printf("\tfg: %s\n", n->color_strings[ColFG]); printf("\tbg: %s\n", n->color_strings[ColBG]); + printf("\tframe: %s\n", n->color_strings[ColFrame]); printf("\tid: %d\n", n->id); if (n->urls) { printf("\turls\n"); @@ -453,6 +454,10 @@ int notification_init(notification * n, int id) n->color_strings[ColBG] = xctx.color_strings[ColBG][n->urgency]; } + if (!n->color_strings[ColFrame]) { + n->color_strings[ColFrame] = xctx.color_strings[ColFrame][n->urgency]; + } + n->timeout = n->timeout == -1 ? settings.timeouts[n->urgency] : n->timeout; n->start = 0; diff --git a/notification.h b/notification.h index c6b0b6a..f7c3858 100644 --- a/notification.h +++ b/notification.h @@ -44,7 +44,7 @@ typedef struct _notification { int id; int dup_count; int displayed_height; - const char *color_strings[2]; + const char *color_strings[3]; bool first_render; int progress; /* percentage + 1, 0 to hide */ diff --git a/settings.c b/settings.c index ae0c14c..88229b9 100644 --- a/settings.c +++ b/settings.c @@ -277,6 +277,9 @@ void load_settings(char *cmdline_config_path) settings.lowfgcolor = option_get_string("urgency_low", "foreground", "-lf", lowfgcolor, "Foreground color for notifications with low urgency"); + settings.lowframecolor = + option_get_string("urgency_low", "frame_color", "-lfr", NULL, + "Frame color for notifications with low urgency"); settings.timeouts[LOW] = option_get_int("urgency_low", "timeout", "-lto", timeouts[LOW], "Timeout for notifications with low urgency"); @@ -291,6 +294,9 @@ void load_settings(char *cmdline_config_path) option_get_string("urgency_normal", "foreground", "-nf", normfgcolor, "Foreground color for notifications with normal urgency"); + settings.normframecolor = + option_get_string("urgency_normal", "frame_color", "-nfr", NULL, + "Frame color for notifications with normal urgency"); settings.timeouts[NORM] = option_get_int("urgency_normal", "timeout", "-nto", timeouts[NORM], "Timeout for notifications with normal urgency"); @@ -305,6 +311,9 @@ void load_settings(char *cmdline_config_path) option_get_string("urgency_critical", "foreground", "-cf", critfgcolor, "Foreground color for notifications with ciritical urgency"); + settings.critframecolor = + option_get_string("urgency_critical", "frame_color", "-cfr", NULL, + "Frame color for notifications with critical urgency"); settings.timeouts[CRIT] = option_get_int("urgency_critical", "timeout", "-cto", timeouts[CRIT], "Timeout for notifications with critical urgency"); diff --git a/settings.h b/settings.h index fec97a3..517922b 100644 --- a/settings.h +++ b/settings.h @@ -10,10 +10,13 @@ typedef struct _settings { char *font; char *normbgcolor; char *normfgcolor; + char *normframecolor; char *critbgcolor; char *critfgcolor; + char *critframecolor; char *lowbgcolor; char *lowfgcolor; + char *lowframecolor; char *format; int timeouts[3]; char *icons[3]; diff --git a/x.c b/x.c index 309839a..49e7099 100644 --- a/x.c +++ b/x.c @@ -40,15 +40,15 @@ typedef struct _colored_layout { PangoLayout *l; color_t fg; color_t bg; + color_t frame; char *text; PangoAttrList *attr; cairo_surface_t *icon; + notification *n; } colored_layout; cairo_ctx_t cairo_ctx; -static color_t frame_color; - /* FIXME refactor setup teardown handlers into one setup and one teardown */ static void x_follow_setup_error_handler(void); static int x_follow_tear_down_error_handler(void); @@ -60,8 +60,6 @@ static void x_handle_click(XEvent ev); static void x_screen_info(screen_info * scr); static void x_win_setup(void); - - static color_t x_color_hex_to_double(int hexValue) { color_t color; @@ -112,20 +110,23 @@ static color_t calculate_foreground_color(color_t bg) } -static color_t x_get_separator_color(color_t fg, color_t bg) +static color_t x_get_separator_color(colored_layout *cl, colored_layout *cl_next) { switch (settings.sep_color) { case FRAME: - return x_string_to_color_t(settings.frame_color); + if (cl_next->n->urgency > cl->n->urgency) + return cl_next->frame; + else + return cl->frame; case CUSTOM: return x_string_to_color_t(settings.sep_custom_color_str); case FOREGROUND: - return fg; + return cl->fg; case AUTO: - return calculate_foreground_color(bg); + return calculate_foreground_color(cl->bg); default: printf("Unknown separator color type. Please file a Bugreport.\n"); - return fg; + return cl->fg; } } @@ -138,8 +139,6 @@ static void x_cairo_setup(void) cairo_ctx.context = cairo_create(cairo_ctx.surface); cairo_ctx.desc = pango_font_description_from_string(settings.font); - - frame_color = x_string_to_color_t(settings.frame_color); } static void r_setup_pango_layout(PangoLayout *layout, int width) @@ -229,6 +228,7 @@ static dimension_t calculate_dimensions(GSList *layouts) dim.w = scr.dim.w; } + dim.h += 2 * settings.frame_width; dim.h += (g_slist_length(layouts) - 1) * settings.separator_height; int text_width = 0, total_width = 0; @@ -434,6 +434,9 @@ static colored_layout *r_init_shared(cairo_t *c, notification *n) cl->fg = x_string_to_color_t(n->color_strings[ColFG]); cl->bg = x_string_to_color_t(n->color_strings[ColBG]); + cl->frame = x_string_to_color_t(n->color_strings[ColFrame]); + + cl->n = n; dimension_t dim = calculate_dimensions(NULL); int width = dim.w; @@ -531,7 +534,7 @@ static void r_free_layouts(GSList *layouts) g_slist_free_full(layouts, free_colored_layout); } -static dimension_t x_render_layout(cairo_t *c, colored_layout *cl, dimension_t dim, bool first, bool last) +static dimension_t x_render_layout(cairo_t *c, colored_layout *cl, colored_layout *cl_next, dimension_t dim, bool first, bool last) { int h; pango_layout_get_pixel_size(cl->l, NULL, &h); @@ -544,11 +547,21 @@ static dimension_t x_render_layout(cairo_t *c, colored_layout *cl, dimension_t d double bg_half_height = settings.notification_height/2.0; int pango_offset = (int) floor(h/2.0); + if (first) bg_height += settings.frame_width; + if (last) bg_height += settings.frame_width; + else bg_height += settings.separator_height; + + cairo_set_source_rgb(c, cl->frame.r, cl->frame.g, cl->frame.b); + cairo_rectangle(c, bg_x, bg_y, bg_width, bg_height); + cairo_fill(c); + /* adding frame */ bg_x += settings.frame_width; if (first) { + dim.y += settings.frame_width; bg_y += settings.frame_width; bg_height -= settings.frame_width; + if (!last) bg_height -= settings.separator_height; } bg_width -= 2 * settings.frame_width; if (last) @@ -574,13 +587,18 @@ static dimension_t x_render_layout(cairo_t *c, colored_layout *cl, dimension_t d else dim.y += (int) (floor(bg_half_height) + pango_offset); - color_t sep_color = x_get_separator_color(cl->fg, cl->bg); if (settings.separator_height > 0 && !last) { + color_t sep_color = x_get_separator_color(cl, cl_next); cairo_set_source_rgb(c, sep_color.r, sep_color.g, sep_color.b); - cairo_rectangle(c, settings.frame_width, dim.y, - dim.w - 2 * settings.frame_width - , settings.separator_height); + if (settings.sep_color == FRAME) + // Draw over the borders on both sides to avoid + // the wrong color in the corners. + cairo_rectangle(c, 0, dim.y, dim.w, settings.separator_height); + else + cairo_rectangle(c, settings.frame_width, dim.y, + dim.w - 2 * settings.frame_width, + settings.separator_height); cairo_fill(c); dim.y += settings.separator_height; @@ -624,16 +642,15 @@ void x_win_draw(void) x_win_move(width, height); cairo_xlib_surface_set_size(cairo_ctx.surface, width, height); - cairo_set_source_rgb(c, frame_color.r, frame_color.g, frame_color.b); - cairo_rectangle(c, 0.0, 0.0, width, height); - cairo_fill(c); - cairo_move_to(c, 0, 0); bool first = true; for (GSList *iter = layouts; iter; iter = iter->next) { - colored_layout *cl = iter->data; - dim = x_render_layout(c, cl, dim, first, iter->next == NULL); + if (iter->next) + dim = x_render_layout(c, iter->data, iter->next->data, dim, first, iter->next == NULL); + else + dim = x_render_layout(c, iter->data, NULL, dim, first, iter->next == NULL); + first = false; } @@ -1055,6 +1072,19 @@ void x_setup(void) xctx.color_strings[ColBG][NORM] = settings.normbgcolor; xctx.color_strings[ColBG][CRIT] = settings.critbgcolor; + if (settings.lowframecolor) + xctx.color_strings[ColFrame][LOW] = settings.lowframecolor; + else + xctx.color_strings[ColFrame][LOW] = settings.frame_color; + if (settings.normframecolor) + xctx.color_strings[ColFrame][NORM] = settings.normframecolor; + else + xctx.color_strings[ColFrame][NORM] = settings.frame_color; + if (settings.critframecolor) + xctx.color_strings[ColFrame][CRIT] = settings.critframecolor; + else + xctx.color_strings[ColFrame][CRIT] = settings.frame_color; + /* parse and set xctx.geometry and monitor position */ if (settings.geom[0] == '-') { xctx.geometry.negative_width = true; diff --git a/x.h b/x.h index 48b076f..cc366b9 100644 --- a/x.h +++ b/x.h @@ -46,10 +46,9 @@ typedef struct _xctx { Window win; bool visible; dimension_t geometry; - const char *color_strings[2][3]; + const char *color_strings[3][3]; XScreenSaverInfo *screensaver_info; dimension_t window_dim; - unsigned long framec; unsigned long sep_custom_col; } xctx_t; From bed4877d7ba11e9212867074e3a82e622d2db3dc Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 21 Dec 2014 14:58:10 +0100 Subject: [PATCH 25/72] Fix/simplify notification_strip_markup - Strip markup before interpreting entitites. - Handle *any* tag uniformly ( is also handled by pango) --- notification.c | 58 +++++++++++++++++++------------------------------- 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/notification.c b/notification.c index b0b12a4..5be57fd 100644 --- a/notification.c +++ b/notification.c @@ -191,25 +191,8 @@ char *notification_strip_markup(char *str) return NULL; } - str = string_replace_all(""", "\"", str); - str = string_replace_all("'", "'", str); - str = string_replace_all("&", "&", str); - str = string_replace_all("<", "<", str); - str = string_replace_all(">", ">", str); - - /* remove tags */ - str = string_replace_all("", "", str); - str = string_replace_all("", "", str); - str = string_replace_all("
", " ", str); - str = string_replace_all("
", " ", str); - str = string_replace_all("
", " ", str); - str = string_replace_all("", "", str); - str = string_replace_all("", "", str); - str = string_replace_all("", "", str); - str = string_replace_all("", "", str); - str = string_replace_all("", "", str); - - while ((start = strstr(str, ""); if (end != NULL) { replace_buf = strndup(start, end - start + 1); @@ -220,16 +203,13 @@ char *notification_strip_markup(char *str) } } - while ((start = strstr(str, ""); - if (end != NULL) { - replace_buf = strndup(start, end - start + 2); - str = string_replace(replace_buf, "", str); - free(replace_buf); - } else { - break; - } - } + /* unquote the remainder */ + str = string_replace_all(""", "\"", str); + str = string_replace_all("'", "'", str); + str = string_replace_all("&", "&", str); + str = string_replace_all("<", "<", str); + str = string_replace_all(">", ">", str); + return str; } @@ -270,19 +250,25 @@ char *notification_replace_format(const char *needle, const char *replacement, tmp = notification_quote_markup(tmp); ret = string_replace_all(needle, tmp, haystack); free(tmp); - } else if (!allow_markup) { + } else { tmp = strdup(replacement); - if (!settings.ignore_newline) { + if (settings.ignore_newline) { + tmp = string_replace_all("
", " ", tmp); + tmp = string_replace_all("
", " ", tmp); + tmp = string_replace_all("
", " ", tmp); + } else { tmp = string_replace_all("
", "\n", tmp); tmp = string_replace_all("
", "\n", tmp); tmp = string_replace_all("
", "\n", tmp); } - tmp = notification_strip_markup(tmp); - tmp = notification_quote_markup(tmp); + + if (!allow_markup) { + tmp = notification_strip_markup(tmp); + tmp = notification_quote_markup(tmp); + } + ret = string_replace_all(needle, tmp, haystack); free(tmp); - } else { - ret = string_replace_all(needle, replacement, haystack); } return ret; @@ -320,7 +306,7 @@ char *notification_extract_markup_urls(char **str_ptr) { } free(replace_buf); } else { - break; + break; } } *str_ptr = str; From 4b53e44d92fc04d9ca822333413838c941878cee Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 21 Dec 2014 22:05:16 +0100 Subject: [PATCH 26/72] Avoid allocations by performing stripping in-place Introduce a helper function (string_strip_delimited). --- notification.c | 13 +------------ utils.c | 15 +++++++++++++++ utils.h | 3 +++ 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/notification.c b/notification.c index 5be57fd..f96931f 100644 --- a/notification.c +++ b/notification.c @@ -185,23 +185,12 @@ void notification_free(notification * n) */ char *notification_strip_markup(char *str) { - char *replace_buf, *start, *end; - if (str == NULL) { return NULL; } /* strip all tags */ - while ((start = strstr(str, "<")) != NULL) { - end = strstr(start, ">"); - if (end != NULL) { - replace_buf = strndup(start, end - start + 1); - str = string_replace(replace_buf, "", str); - free(replace_buf); - } else { - break; - } - } + string_strip_delimited(str, '<', '>'); /* unquote the remainder */ str = string_replace_all(""", "\"", str); diff --git a/utils.c b/utils.c index 0ab4b3a..c162024 100644 --- a/utils.c +++ b/utils.c @@ -105,6 +105,21 @@ char **string_to_argv(const char *s) return argv; } +void string_strip_delimited(char *str, char a, char b) +{ + int iread=-1, iwrite=0, copen=0; + while (str[++iread] != 0) { + if (str[iread] == a) { + ++copen; + } else if (str[iread] == b && copen > 0) { + --copen; + } else if (copen == 0) { + str[iwrite++] = str[iread]; + } + } + str[iwrite] = 0; +} + int digit_count(int i) { i = ABS(i); diff --git a/utils.h b/utils.h index 9617301..1009f96 100644 --- a/utils.h +++ b/utils.h @@ -17,6 +17,9 @@ char *string_append(char *a, const char *b, const char *sep); char **string_to_argv(const char *s); +/* strip content between two delimiter characters (inplace) */ +void string_strip_delimited(char *str, char a, char b); + /* exit with an error message */ void die(char *msg, int exit_value); From 98566667c70036bfe4ab1471d29c5ee32413401b Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 21 Dec 2014 22:12:54 +0100 Subject: [PATCH 27/72] Consistent indentation. --- utils.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/utils.c b/utils.c index c162024..99135cb 100644 --- a/utils.c +++ b/utils.c @@ -11,10 +11,10 @@ #include "dunst.h" char *string_replace_char(char needle, char replacement, char *haystack) { - char *current = haystack; - while ((current = strchr (current, needle)) != NULL) - *current++ = replacement; - return haystack; + char *current = haystack; + while ((current = strchr (current, needle)) != NULL) + *current++ = replacement; + return haystack; } char *string_replace_at(char *buf, int pos, int len, const char *repl) From cf910b0683de6258e12ddf75788f9beb1abe195a Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 21 Dec 2014 22:14:19 +0100 Subject: [PATCH 28/72] Avoid allocations in string_replace_at when possible. --- utils.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/utils.c b/utils.c index 99135cb..7d07ffe 100644 --- a/utils.c +++ b/utils.c @@ -25,13 +25,21 @@ char *string_replace_at(char *buf, int pos, int len, const char *repl) buf_len = strlen(buf); repl_len = strlen(repl); size = (buf_len - len) + repl_len + 1; - tmp = malloc(size); + + if (repl_len <= len) { + tmp = buf; + } else { + tmp = malloc(size); + } memcpy(tmp, buf, pos); memcpy(tmp + pos, repl, repl_len); - memcpy(tmp + pos + repl_len, buf + pos + len, buf_len - (pos + len) + 1); + memmove(tmp + pos + repl_len, buf + pos + len, buf_len - (pos + len) + 1); + + if(tmp != buf) { + free(buf); + } - free(buf); return tmp; } From 69537c2c1d0d0889fcdd1756535052004964a656 Mon Sep 17 00:00:00 2001 From: vimbaer Date: Sun, 18 Jan 2015 21:44:21 +0100 Subject: [PATCH 29/72] Don't trim leading whitespace, fixes #208. Use g_strchomp (https://developer.gnome.org/glib/stable/glib-String-Utility-Functions.html#g-strchomp) instead of g_strstrip which both removes leading and trailing whitespace. --- notification.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notification.c b/notification.c index f96931f..ede5593 100644 --- a/notification.c +++ b/notification.c @@ -353,7 +353,7 @@ int notification_init(notification * n, int id) n->msg = string_replace_all("%p", "", n->msg); } - n->msg = g_strstrip(n->msg); + n->msg = g_strchomp(n->msg); if (id == 0) { n->id = ++next_notification_id; @@ -563,7 +563,7 @@ void notification_update_text_to_render(notification *n) char *buf = NULL; - char *msg = g_strstrip(n->msg); + char *msg = g_strchomp(n->msg); /* print dup_count and msg */ if ((n->dup_count > 0 && !settings.hide_duplicates_count) From 9db667be459c371450b85481e91701b859242032 Mon Sep 17 00:00:00 2001 From: Jack Henschel Date: Thu, 7 Jul 2016 12:45:59 +0200 Subject: [PATCH 30/72] Add note about ctrl+grave to default config Fixes #268 --- dunstrc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dunstrc b/dunstrc index 37407c7..61f5540 100644 --- a/dunstrc +++ b/dunstrc @@ -173,7 +173,8 @@ # Redisplay last message(s). # On the US keyboard layout "grave" is normally above TAB and left - # of "1". + # of "1". Make sure this key actually exists on your keyboard layout, + # e.g. check output of 'xmodmap -pke' history = ctrl+grave # Context menu. From 9dd4768a1f78880a7d7a5b3b4bfd4cbf504d2b5f Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Thu, 17 Nov 2016 19:50:00 +0200 Subject: [PATCH 31/72] Switch to _DEFAULT_SOURCE, _BSD_SOURCE is deprecated --- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.mk b/config.mk index fc45ce1..cd46c19 100644 --- a/config.mk +++ b/config.mk @@ -22,7 +22,7 @@ ifeq (${PKG_CONFIG}, ${EMPTY}) endif # flags -CPPFLAGS += -D_BSD_SOURCE -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} ${INIFLAGS} +CPPFLAGS += -D_DEFAULT_SOURCE -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} ${INIFLAGS} CFLAGS += -g --std=gnu99 -pedantic -Wall -Wno-overlength-strings -Os ${STATIC} ${CPPFLAGS} ${EXTRACFLAGS} pkg_config_packs := dbus-1 x11 freetype2 xext xft xscrnsaver \ From 7e58e5c64c41b861942f7e307175f86a604cc4df Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Thu, 17 Nov 2016 20:27:46 +0200 Subject: [PATCH 32/72] Add expandtab to vim modelines & expand abbreviations Add expandtab to vim modelines so that spaces are expanded to tabs, make life easier for people that have vim configured to use tabs by default. Expand modeline abbreviations to improve readability. --- dbus.c | 2 +- dbus.h | 2 +- dunst.c | 2 +- dunst.h | 2 +- dunstify.c | 2 ++ menu.c | 2 +- menu.h | 2 ++ notification.c | 2 +- notification.h | 2 ++ option_parser.c | 2 +- option_parser.h | 2 +- rules.c | 2 +- rules.h | 2 ++ settings.c | 2 +- settings.h | 2 ++ utils.c | 2 +- utils.h | 2 +- x.c | 2 +- x.h | 2 +- 19 files changed, 24 insertions(+), 14 deletions(-) diff --git a/dbus.c b/dbus.c index 0aeff83..f05f56e 100644 --- a/dbus.c +++ b/dbus.c @@ -495,4 +495,4 @@ void dbus_tear_down(int owner_id) g_bus_unown_name(owner_id); } -/* vim: set ts=8 sw=8 tw=0: */ +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/dbus.h b/dbus.h index 56f1dc7..a98baed 100644 --- a/dbus.h +++ b/dbus.h @@ -15,4 +15,4 @@ void actionInvoked(notification * n, const char *identifier); #endif -/* vim: set ts=8 sw=8 tw=0: */ +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/dunst.c b/dunst.c index 4c9591e..a0debc0 100644 --- a/dunst.c +++ b/dunst.c @@ -434,4 +434,4 @@ void print_version(void) exit(EXIT_SUCCESS); } -/* vim: set ts=8 sw=8 tw=0: */ +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/dunst.h b/dunst.h index a27a9fa..805cb50 100644 --- a/dunst.h +++ b/dunst.h @@ -45,4 +45,4 @@ char *extract_urls(const char *str); void context_menu(void); void wake_up(void); void pause_signal_handler(int sig); -/* vim: set ts=8 sw=8 tw=0: */ +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/dunstify.c b/dunstify.c index 5a6fafe..f2f109f 100644 --- a/dunstify.c +++ b/dunstify.c @@ -312,3 +312,5 @@ int main(int argc, char *argv[]) die(0); } + +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/menu.c b/menu.c index fb05798..d3e4fb4 100644 --- a/menu.c +++ b/menu.c @@ -257,4 +257,4 @@ void context_menu(void) free(dmenu_input); } -/* vim: set ts=8 sw=8 tw=0: */ +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/menu.h b/menu.h index 01dda4a..86491f1 100644 --- a/menu.h +++ b/menu.h @@ -6,3 +6,5 @@ char *extract_urls(const char *to_match); void open_browser(const char *url); void invoke_action(const char *action); void regex_teardown(void); + +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/notification.c b/notification.c index ede5593..41f5389 100644 --- a/notification.c +++ b/notification.c @@ -623,4 +623,4 @@ int notification_get_ttl(notification *n) { int notification_get_age(notification *n) { return time(NULL) - n->timestamp; } -/* vim: set ts=8 sw=8 tw=0: */ +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/notification.h b/notification.h index f7c3858..b15a6ac 100644 --- a/notification.h +++ b/notification.h @@ -67,3 +67,5 @@ char *notification_quote_markup(char *str); void notification_update_text_to_render(notification *n); int notification_get_ttl(notification *n); int notification_get_age(notification *n); + +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/option_parser.c b/option_parser.c index 6de5a76..ea822a3 100644 --- a/option_parser.c +++ b/option_parser.c @@ -473,4 +473,4 @@ char *cmdline_create_usage(void) return g_strdup(usage_str); } -/* vim: set ts=8 sw=8 tw=0: */ +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/option_parser.h b/option_parser.h index 873897f..1b1d9df 100644 --- a/option_parser.h +++ b/option_parser.h @@ -33,4 +33,4 @@ int option_get_bool(char *ini_section, char *ini_key, char *cmdline_key, */ char *next_section(char *section); -/* vim: set ts=8 sw=8 tw=0: */ +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/rules.c b/rules.c index 8687f07..dc8e465 100644 --- a/rules.c +++ b/rules.c @@ -78,4 +78,4 @@ bool rule_matches_notification(rule_t * r, notification * n) && (!r->category || !fnmatch(r->category, n->category, 0)) && (r->msg_urgency == -1 || r->msg_urgency == n->urgency)); } -/* vim: set ts=8 sw=8 tw=0: */ +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/rules.h b/rules.h index f7fc734..218ce37 100644 --- a/rules.h +++ b/rules.h @@ -34,3 +34,5 @@ void rule_init(rule_t * r); void rule_apply(rule_t * r, notification * n); void rule_apply_all(notification * n); bool rule_matches_notification(rule_t * r, notification * n); + +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/settings.c b/settings.c index 88229b9..857cb8f 100644 --- a/settings.c +++ b/settings.c @@ -402,4 +402,4 @@ void load_settings(char *cmdline_config_path) } #endif } -/* vim: set ts=8 sw=8 tw=0: */ +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/settings.h b/settings.h index 517922b..290291f 100644 --- a/settings.h +++ b/settings.h @@ -66,3 +66,5 @@ typedef struct _settings { extern settings_t settings; void load_settings(char *cmdline_config_path); + +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/utils.c b/utils.c index 7d07ffe..4e6821c 100644 --- a/utils.c +++ b/utils.c @@ -147,4 +147,4 @@ void die(char *text, int exit_value) exit(exit_value); } -/* vim: set ts=8 sw=8 tw=0: */ +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/utils.h b/utils.h index 1009f96..5e09550 100644 --- a/utils.h +++ b/utils.h @@ -26,4 +26,4 @@ void die(char *msg, int exit_value); int digit_count(int i); #endif -/* vim: set ts=8 sw=8 tw=0: */ +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/x.c b/x.c index 49e7099..caa1b7b 100644 --- a/x.c +++ b/x.c @@ -1420,4 +1420,4 @@ void x_shortcut_init(keyboard_shortcut * ks) free(str_begin); } -/* vim: set ts=8 sw=8 tw=0: */ +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/x.h b/x.h index cc366b9..767190b 100644 --- a/x.h +++ b/x.h @@ -82,4 +82,4 @@ gboolean x_mainloop_fd_check(GSource * source); gboolean x_mainloop_fd_prepare(GSource * source, gint * timeout); #endif -/* vim: set ts=8 sw=8 tw=0: */ +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ From 8cadd8f905ede075b2542b7bcd8cba3862b13a39 Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Thu, 17 Nov 2016 22:11:08 +0200 Subject: [PATCH 33/72] Don't indent top-level comments --- menu.c | 44 ++++++++--------- notification.c | 90 +++++++++++++++++----------------- x.c | 130 ++++++++++++++++++++++++------------------------- 3 files changed, 132 insertions(+), 132 deletions(-) diff --git a/menu.c b/menu.c index d3e4fb4..44ff6c1 100644 --- a/menu.c +++ b/menu.c @@ -47,12 +47,12 @@ void regex_teardown(void) } } - /* - * Exctract all urls from a given string. - * - * Return: a string of urls separated by \n - * - */ +/* + * Exctract all urls from a given string. + * + * Return: a string of urls separated by \n + * + */ char *extract_urls(const char *to_match) { char *urls = NULL; @@ -87,10 +87,10 @@ char *extract_urls(const char *to_match) return urls; } - /* - * Open url in browser. - * - */ +/* + * Open url in browser. + * + */ void open_browser(const char *url) { int browser_pid1 = fork(); @@ -111,10 +111,10 @@ void open_browser(const char *url) } } - /* - * Notify the corresponding client - * that an action has been invoked - */ +/* + * Notify the corresponding client + * that an action has been invoked + */ void invoke_action(const char *action) { notification *invoked = NULL; @@ -153,10 +153,10 @@ void invoke_action(const char *action) } } - /* - * Dispatch whatever has been returned - * by the menu. - */ +/* + * Dispatch whatever has been returned + * by the menu. + */ void dispatch_menu_result(const char *input) { char *in = strdup(input); @@ -182,10 +182,10 @@ void dispatch_menu_result(const char *input) free(in); } - /* - * Open the context menu that let's the user - * select urls/actions/etc - */ +/* + * Open the context menu that let's the user + * select urls/actions/etc + */ void context_menu(void) { char *dmenu_input = NULL; diff --git a/notification.c b/notification.c index 41f5389..a2fa002 100644 --- a/notification.c +++ b/notification.c @@ -21,10 +21,10 @@ int next_notification_id = 1; - /* - * print a human readable representation - * of the given notification to stdout. - */ +/* + * print a human readable representation + * of the given notification to stdout. + */ void notification_print(notification * n) { printf("{\n"); @@ -60,10 +60,10 @@ void notification_print(notification * n) printf("}\n"); } - /* - * Run the script associated with the - * given notification. - */ +/* + * Run the script associated with the + * given notification. + */ void notification_run_script(notification * n) { if (!n->script || strlen(n->script) < 1) @@ -115,10 +115,10 @@ void notification_run_script(notification * n) } } - /* - * Helper function to compare to given - * notifications. - */ +/* + * Helper function to compare to given + * notifications. + */ int notification_cmp(const void *va, const void *vb) { notification *a = (notification *) va; @@ -134,18 +134,18 @@ int notification_cmp(const void *va, const void *vb) } } - /* - * Wrapper for notification_cmp to match glib's - * compare functions signature. - */ +/* + * Wrapper for notification_cmp to match glib's + * compare functions signature. + */ int notification_cmp_data(const void *va, const void *vb, void *data) { return notification_cmp(va, vb); } - /* - * Free the memory used by the given notification. - */ +/* + * Free the memory used by the given notification. + */ void notification_free(notification * n) { if (n == NULL) @@ -180,9 +180,9 @@ void notification_free(notification * n) free(n); } - /* - * Strip any markup from text - */ +/* + * Strip any markup from text + */ char *notification_strip_markup(char *str) { if (str == NULL) { @@ -202,9 +202,9 @@ char *notification_strip_markup(char *str) return str; } - /* - * Quote a text string for rendering with pango - */ +/* + * Quote a text string for rendering with pango + */ char *notification_quote_markup(char *str) { if (str == NULL) { @@ -220,10 +220,10 @@ char *notification_quote_markup(char *str) return str; } - /* - * Replace all occurrences of "needle" with a quoted "replacement", - * according to the allow_markup/plain_text settings. - */ +/* + * Replace all occurrences of "needle" with a quoted "replacement", + * according to the allow_markup/plain_text settings. + */ char *notification_replace_format(const char *needle, const char *replacement, char *haystack, bool allow_markup, bool plain_text) { @@ -302,10 +302,10 @@ char *notification_extract_markup_urls(char **str_ptr) { return urls; } - /* - * Initialize the given notification and add it to - * the queue. Replace notification with id if id > 0. - */ +/* + * Initialize the given notification and add it to + * the queue. Replace notification with id if id > 0. + */ int notification_init(notification * n, int id) { if (n == NULL) @@ -501,15 +501,15 @@ int notification_init(notification * n, int id) return n->id; } - /* - * Close the notification that has id. - * - * reasons: - * -1 -> notification is a replacement, no NotificationClosed signal emitted - * 1 -> the notification expired - * 2 -> the notification was dismissed by the user_data - * 3 -> The notification was closed by a call to CloseNotification - */ +/* + * Close the notification that has id. + * + * reasons: + * -1 -> notification is a replacement, no NotificationClosed signal emitted + * 1 -> the notification expired + * 2 -> the notification was dismissed by the user_data + * 3 -> The notification was closed by a call to CloseNotification + */ int notification_close_by_id(int id, int reason) { notification *target = NULL; @@ -544,9 +544,9 @@ int notification_close_by_id(int id, int reason) return reason; } - /* - * Close the given notification. SEE notification_close_by_id. - */ +/* + * Close the given notification. SEE notification_close_by_id. + */ int notification_close(notification * n, int reason) { if (n == NULL) diff --git a/x.c b/x.c index caa1b7b..613519a 100644 --- a/x.c +++ b/x.c @@ -713,9 +713,9 @@ static void setopacity(Window win, unsigned long opacity) - /* - * Returns the modifier which is NumLock. - */ +/* + * Returns the modifier which is NumLock. + */ static KeySym x_numlock_mod() { static KeyCode nl = 0; @@ -766,10 +766,10 @@ end: return sym; } - /* - * Helper function to use glib's mainloop mechanic - * with Xlib - */ +/* + * Helper function to use glib's mainloop mechanic + * with Xlib + */ gboolean x_mainloop_fd_prepare(GSource * source, gint * timeout) { if (timeout) @@ -779,18 +779,18 @@ gboolean x_mainloop_fd_prepare(GSource * source, gint * timeout) return false; } - /* - * Helper function to use glib's mainloop mechanic - * with Xlib - */ +/* + * Helper function to use glib's mainloop mechanic + * with Xlib + */ gboolean x_mainloop_fd_check(GSource * source) { return XPending(xctx.dpy) > 0; } - /* - * Main Dispatcher for XEvents - */ +/* + * Main Dispatcher for XEvents + */ gboolean x_mainloop_fd_dispatch(GSource * source, GSourceFunc callback, gpointer user_data) { @@ -854,9 +854,9 @@ gboolean x_mainloop_fd_dispatch(GSource * source, GSourceFunc callback, return true; } - /* - * Check whether the user is currently idle. - */ +/* + * Check whether the user is currently idle. + */ bool x_is_idle(void) { XScreenSaverQueryInfo(xctx.dpy, DefaultRootWindow(xctx.dpy), @@ -868,9 +868,9 @@ bool x_is_idle(void) } /* TODO move to x_mainloop_* */ - /* - * Handle incoming mouse click events - */ +/* + * Handle incoming mouse click events + */ static void x_handle_click(XEvent ev) { if (ev.xbutton.button == Button3) { @@ -898,10 +898,10 @@ static void x_handle_click(XEvent ev) } } - /* - * Return the window that currently has - * the keyboard focus. - */ +/* + * Return the window that currently has + * the keyboard focus. + */ static Window get_focused_window(void) { Window focused = 0; @@ -925,10 +925,10 @@ static Window get_focused_window(void) } #ifdef XINERAMA - /* - * Select the screen on which the Window - * should be displayed. - */ +/* + * Select the screen on which the Window + * should be displayed. + */ static int select_screen(XineramaScreenInfo * info, int info_len) { int ret = 0; @@ -991,10 +991,10 @@ sc_cleanup: } #endif - /* - * Update the information about the monitor - * geometry. - */ +/* + * Update the information about the monitor + * geometry. + */ static void x_screen_info(screen_info * scr) { #ifdef XINERAMA @@ -1037,9 +1037,9 @@ void x_free(void) XCloseDisplay(xctx.dpy); } - /* - * Setup X11 stuff - */ +/* + * Setup X11 stuff + */ void x_setup(void) { @@ -1147,9 +1147,9 @@ static void x_set_wm(Window win) PropModeReplace, (unsigned char *) data, 1L); } - /* - * Setup the window - */ +/* + * Setup the window + */ static void x_win_setup(void) { @@ -1193,9 +1193,9 @@ static void x_win_setup(void) } } - /* - * Show the window and grab shortcuts. - */ +/* + * Show the window and grab shortcuts. + */ void x_win_show(void) { /* window is already mapped or there's nothing to show */ @@ -1218,9 +1218,9 @@ void x_win_show(void) xctx.visible = true; } - /* - * Hide the window and ungrab unused keyboard_shortcuts - */ +/* + * Hide the window and ungrab unused keyboard_shortcuts + */ void x_win_hide() { x_shortcut_ungrab(&settings.close_ks); @@ -1233,9 +1233,9 @@ void x_win_hide() xctx.visible = false; } - /* - * Parse a string into a modifier mask. - */ +/* + * Parse a string into a modifier mask. + */ KeySym x_shortcut_string_to_mask(const char *str) { if (!strcmp(str, "ctrl")) { @@ -1257,9 +1257,9 @@ KeySym x_shortcut_string_to_mask(const char *str) } - /* - * Error handler for grabbing mouse and keyboard errors. - */ +/* + * Error handler for grabbing mouse and keyboard errors. + */ static int GrabXErrorHandler(Display * display, XErrorEvent * e) { dunst_grab_errored = true; @@ -1286,9 +1286,9 @@ static int FollowXErrorHandler(Display * display, XErrorEvent * e) return 0; } - /* - * Setup the Error handler. - */ +/* + * Setup the Error handler. + */ static void x_shortcut_setup_error_handler(void) { dunst_grab_errored = false; @@ -1305,9 +1305,9 @@ static void x_follow_setup_error_handler(void) XSetErrorHandler(FollowXErrorHandler); } - /* - * Tear down the Error handler. - */ +/* + * Tear down the Error handler. + */ static int x_shortcut_tear_down_error_handler(void) { XFlush(xctx.dpy); @@ -1324,9 +1324,9 @@ static int x_follow_tear_down_error_handler(void) return dunst_follow_errored; } - /* - * Grab the given keyboard shortcut. - */ +/* + * Grab the given keyboard shortcut. + */ int x_shortcut_grab(keyboard_shortcut * ks) { if (!ks->is_valid) @@ -1351,9 +1351,9 @@ int x_shortcut_grab(keyboard_shortcut * ks) return 0; } - /* - * Ungrab the given keyboard shortcut. - */ +/* + * Ungrab the given keyboard shortcut. + */ void x_shortcut_ungrab(keyboard_shortcut * ks) { Window root; @@ -1364,9 +1364,9 @@ void x_shortcut_ungrab(keyboard_shortcut * ks) } } - /* - * Initialize the keyboard shortcut. - */ +/* + * Initialize the keyboard shortcut. + */ void x_shortcut_init(keyboard_shortcut * ks) { if (ks == NULL || ks->str == NULL) From 4b36abff9a4f570e9c6345c50e0df3889555eeb9 Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Fri, 18 Nov 2016 21:30:48 +0200 Subject: [PATCH 34/72] Fix uninitialised pointer warning --- x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x.c b/x.c index 613519a..480fb8e 100644 --- a/x.c +++ b/x.c @@ -392,7 +392,7 @@ static colored_layout *r_init_shared(cairo_t *c, notification *n) pango_layout_set_ellipsize(cl->l, PANGO_ELLIPSIZE_MIDDLE); } - GdkPixbuf *pixbuf; + GdkPixbuf *pixbuf = NULL; if (n->raw_icon) { pixbuf = get_pixbuf_from_raw_image(n->raw_icon); From 2df2e7d06cd0902947c619440e6ec83306e2fb8f Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Sat, 19 Nov 2016 11:54:03 +0200 Subject: [PATCH 35/72] Move dunst source files to src/ --- Makefile | 15 +++++---------- dbus.c => src/dbus.c | 0 dbus.h => src/dbus.h | 0 dunst.c => src/dunst.c | 0 dunst.h => src/dunst.h | 0 menu.c => src/menu.c | 0 menu.h => src/menu.h | 0 notification.c => src/notification.c | 0 notification.h => src/notification.h | 0 option_parser.c => src/option_parser.c | 0 option_parser.h => src/option_parser.h | 0 rules.c => src/rules.c | 0 rules.h => src/rules.h | 0 settings.c => src/settings.c | 0 settings.h => src/settings.h | 0 utils.c => src/utils.c | 0 utils.h => src/utils.h | 0 x.c => src/x.c | 0 x.h => src/x.h | 0 19 files changed, 5 insertions(+), 10 deletions(-) rename dbus.c => src/dbus.c (100%) rename dbus.h => src/dbus.h (100%) rename dunst.c => src/dunst.c (100%) rename dunst.h => src/dunst.h (100%) rename menu.c => src/menu.c (100%) rename menu.h => src/menu.h (100%) rename notification.c => src/notification.c (100%) rename notification.h => src/notification.h (100%) rename option_parser.c => src/option_parser.c (100%) rename option_parser.h => src/option_parser.h (100%) rename rules.c => src/rules.c (100%) rename rules.h => src/rules.h (100%) rename settings.c => src/settings.c (100%) rename settings.h => src/settings.h (100%) rename utils.c => src/utils.c (100%) rename utils.h => src/utils.h (100%) rename x.c => src/x.c (100%) rename x.h => src/x.h (100%) diff --git a/Makefile b/Makefile index a70e532..9787ae4 100644 --- a/Makefile +++ b/Makefile @@ -3,15 +3,10 @@ include config.mk -SRC = x.c \ - dunst.c \ - dbus.c \ - utils.c \ - option_parser.c \ - settings.c \ - rules.c \ - menu.c \ - notification.c +CFLAGS += -I. +LDFLAGS += -L. + +SRC = $(shell ls src/*.c) OBJ = ${SRC:.c=.o} V ?= 0 @@ -29,7 +24,7 @@ options: .c.o: @echo CC -c $< - ${CC} -c $< ${CFLAGS} + ${CC} -o $@ -c $< ${CFLAGS} ${OBJ}: config.h config.mk diff --git a/dbus.c b/src/dbus.c similarity index 100% rename from dbus.c rename to src/dbus.c diff --git a/dbus.h b/src/dbus.h similarity index 100% rename from dbus.h rename to src/dbus.h diff --git a/dunst.c b/src/dunst.c similarity index 100% rename from dunst.c rename to src/dunst.c diff --git a/dunst.h b/src/dunst.h similarity index 100% rename from dunst.h rename to src/dunst.h diff --git a/menu.c b/src/menu.c similarity index 100% rename from menu.c rename to src/menu.c diff --git a/menu.h b/src/menu.h similarity index 100% rename from menu.h rename to src/menu.h diff --git a/notification.c b/src/notification.c similarity index 100% rename from notification.c rename to src/notification.c diff --git a/notification.h b/src/notification.h similarity index 100% rename from notification.h rename to src/notification.h diff --git a/option_parser.c b/src/option_parser.c similarity index 100% rename from option_parser.c rename to src/option_parser.c diff --git a/option_parser.h b/src/option_parser.h similarity index 100% rename from option_parser.h rename to src/option_parser.h diff --git a/rules.c b/src/rules.c similarity index 100% rename from rules.c rename to src/rules.c diff --git a/rules.h b/src/rules.h similarity index 100% rename from rules.h rename to src/rules.h diff --git a/settings.c b/src/settings.c similarity index 100% rename from settings.c rename to src/settings.c diff --git a/settings.h b/src/settings.h similarity index 100% rename from settings.h rename to src/settings.h diff --git a/utils.c b/src/utils.c similarity index 100% rename from utils.c rename to src/utils.c diff --git a/utils.h b/src/utils.h similarity index 100% rename from utils.h rename to src/utils.h diff --git a/x.c b/src/x.c similarity index 100% rename from x.c rename to src/x.c diff --git a/x.h b/src/x.h similarity index 100% rename from x.h rename to src/x.h From 32fb32f96f31c414375cdecbe002d7c3b1f5b149 Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Sat, 19 Nov 2016 12:08:27 +0200 Subject: [PATCH 36/72] Split clean and install targets to *-doc *-dunst This allows better control over when to clean and install, and is more easily expandable in the long run. --- Makefile | 50 +++++++++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/Makefile b/Makefile index 9787ae4..c81b28d 100644 --- a/Makefile +++ b/Makefile @@ -44,15 +44,18 @@ debug: ${OBJ} @echo CC -o $@ @${CC} ${CFLAGS} -O0 -o dunst ${OBJ} ${LDFLAGS} -clean: - @echo cleaning - rm -f ${OBJ} - rm -f dunst - rm -f dunst.1 +clean-dunst: + rm -f dunst ${OBJ} rm -f org.knopwob.dunst.service - rm -f core + +clean-dunstify: rm -f dunstify +clean-doc: + rm -f dunst.1 + +clean: clean-dunst clean-dunstify clean-doc + doc: dunst.1 dunst.1: README.pod pod2man --name=dunst -c "Dunst Reference" --section=1 --release=${VERSION} $< > $@ @@ -60,25 +63,30 @@ dunst.1: README.pod service: @sed "s|##PREFIX##|$(PREFIX)|" org.knopwob.dunst.service.in > org.knopwob.dunst.service -install: all - @echo installing executables to ${DESTDIR}${PREFIX}/bin +install-dunst: dunst doc mkdir -p ${DESTDIR}${PREFIX}/bin - cp -f dunst ${DESTDIR}${PREFIX}/bin - chmod 755 ${DESTDIR}${PREFIX}/bin/dunst - @echo installing manual pages to ${DESTDIR}${MANPREFIX}/man1 + install -m755 dunst ${DESTDIR}${PREFIX}/bin mkdir -p ${DESTDIR}${MANPREFIX}/man1 - cp -f dunst.1 ${DESTDIR}${MANPREFIX}/man1/ - chmod 644 ${DESTDIR}${MANPREFIX}/man1/dunst.1 - mkdir -p "${DESTDIR}${PREFIX}/share/dunst" - cp -f dunstrc ${DESTDIR}${PREFIX}/share/dunst - mkdir -p "${DESTDIR}${PREFIX}/share/dbus-1/services/" - cp -vf org.knopwob.dunst.service "${DESTDIR}${PREFIX}/share/dbus-1/services/org.knopwob.dunst.service" + install -m644 dunst.1 ${DESTDIR}${MANPREFIX}/man1 + +install-doc: + mkdir -p ${DESTDIR}${PREFIX}/share/dunst + install -m644 dunstrc ${DESTDIR}${PREFIX}/share/dunst + +install-service: service + mkdir -p ${DESTDIR}${PREFIX}/share/dbus-1/services/ + install -m644 org.knopwob.dunst.service ${DESTDIR}${PREFIX}/share/dbus-1/services + +install: install-dunst install-doc install-service uninstall: - @echo removing executables from ${DESTDIR}${PREFIX}/bin + @echo Removing executables from ${DESTDIR}${PREFIX}/bin rm -f ${DESTDIR}${PREFIX}/bin/dunst - @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1 - rm -f ${DESTDIR}${MANPREFIX}/man1/dunst - rm -f ${DESTDIR}${PREFIX}/share/dbus-1/service/org.knopwob.dunst.service + @echo Removing manual page from ${DESTDIR}${MANPREFIX}/man1 + rm -f ${DESTDIR}${MANPREFIX}/man1/dunst.1 + @echo Removing service file from ${DESTDIR}${PREFIX}/share/dbus-1/services + rm -f ${DESTDIR}${PREFIX}/share/dbus-1/services/org.knopwob.dunst.service + @echo Removing documentation directory ${DESTDIR}${PREFIX}/share/dunst + rm -rf ${DESTDIR}${PREFIX}/share/dunst .PHONY: all options clean dist install uninstall From e0a8b233c2edef848e5fe084931fc780cc1cb87e Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Sat, 19 Nov 2016 12:15:39 +0200 Subject: [PATCH 37/72] Move the main function to main.c Move the main function to main.c in the git root to allow for alternative main functions to be linked in its place. Specifically this will be used to link the test runner main to run tests. --- Makefile | 6 +++--- main.c | 7 +++++++ src/dunst.c | 2 +- src/dunst.h | 2 ++ 4 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 main.c diff --git a/Makefile b/Makefile index c81b28d..0e4f604 100644 --- a/Makefile +++ b/Makefile @@ -33,9 +33,9 @@ config.h: config.def.h @echo creating $@ from $< @cp $< $@ -dunst: ${OBJ} +dunst: ${OBJ} main.o @echo "${CC} ${CFLAGS} -o $@ ${OBJ} ${LDFLAGS}" - @${CC} ${CFLAGS} -o $@ ${OBJ} ${LDFLAGS} + @${CC} ${CFLAGS} -o $@ ${OBJ} main.o ${LDFLAGS} dunstify: @${CC} ${CFLAGS} -o $@ dunstify.c -std=c99 $(shell pkg-config --libs --cflags glib-2.0 libnotify) @@ -45,7 +45,7 @@ debug: ${OBJ} @${CC} ${CFLAGS} -O0 -o dunst ${OBJ} ${LDFLAGS} clean-dunst: - rm -f dunst ${OBJ} + rm -f dunst ${OBJ} main.o rm -f org.knopwob.dunst.service clean-dunstify: diff --git a/main.c b/main.c new file mode 100644 index 0000000..e31b420 --- /dev/null +++ b/main.c @@ -0,0 +1,7 @@ +#include "src/dunst.h" + +int main(int argc, char *argv[]) +{ + return dunst_main(argc, argv); +} +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/dunst.c b/src/dunst.c index a0debc0..11d347b 100644 --- a/src/dunst.c +++ b/src/dunst.c @@ -313,7 +313,7 @@ static void teardown(void) x_free(); } -int main(int argc, char *argv[]) +int dunst_main(int argc, char *argv[]) { history = g_queue_new(); diff --git a/src/dunst.h b/src/dunst.h index 805cb50..b2bc025 100644 --- a/src/dunst.h +++ b/src/dunst.h @@ -35,6 +35,8 @@ extern const char *color_strings[3][3]; gboolean run(void *data); void wake_up(void); +int dunst_main(int argc, char *argv[]); + void check_timeouts(void); void history_pop(void); void history_push(notification *n); From 7ba0fe03aeefe9c82ab9a5d60d7a09c987ddba46 Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Sat, 19 Nov 2016 12:17:23 +0200 Subject: [PATCH 38/72] Add 'greatest' testing framework Never used this framework before but it seems promising. --- test/greatest.h | 1035 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1035 insertions(+) create mode 100644 test/greatest.h diff --git a/test/greatest.h b/test/greatest.h new file mode 100644 index 0000000..bc48e15 --- /dev/null +++ b/test/greatest.h @@ -0,0 +1,1035 @@ +/* + * Copyright (c) 2011-2016 Scott Vokes + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef GREATEST_H +#define GREATEST_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* 1.2.1 */ +#define GREATEST_VERSION_MAJOR 1 +#define GREATEST_VERSION_MINOR 2 +#define GREATEST_VERSION_PATCH 1 + +/* A unit testing system for C, contained in 1 file. + * It doesn't use dynamic allocation or depend on anything + * beyond ANSI C89. + * + * An up-to-date version can be found at: + * https://github.com/silentbicycle/greatest/ + */ + + +/********************************************************************* + * Minimal test runner template + *********************************************************************/ +#if 0 + +#include "greatest.h" + +TEST foo_should_foo(void) { + PASS(); +} + +static void setup_cb(void *data) { + printf("setup callback for each test case\n"); +} + +static void teardown_cb(void *data) { + printf("teardown callback for each test case\n"); +} + +SUITE(suite) { + /* Optional setup/teardown callbacks which will be run before/after + * every test case. If using a test suite, they will be cleared when + * the suite finishes. */ + SET_SETUP(setup_cb, voidp_to_callback_data); + SET_TEARDOWN(teardown_cb, voidp_to_callback_data); + + RUN_TEST(foo_should_foo); +} + +/* Add definitions that need to be in the test runner's main file. */ +GREATEST_MAIN_DEFS(); + +/* Set up, run suite(s) of tests, report pass/fail/skip stats. */ +int run_tests(void) { + GREATEST_INIT(); /* init. greatest internals */ + /* List of suites to run (if any). */ + RUN_SUITE(suite); + + /* Tests can also be run directly, without using test suites. */ + RUN_TEST(foo_should_foo); + + GREATEST_PRINT_REPORT(); /* display results */ + return greatest_all_passed(); +} + +/* main(), for a standalone command-line test runner. + * This replaces run_tests above, and adds command line option + * handling and exiting with a pass/fail status. */ +int main(int argc, char **argv) { + GREATEST_MAIN_BEGIN(); /* init & parse command-line args */ + RUN_SUITE(suite); + GREATEST_MAIN_END(); /* display results */ +} + +#endif +/*********************************************************************/ + + +#include +#include +#include +#include + +/*********** + * Options * + ***********/ + +/* Default column width for non-verbose output. */ +#ifndef GREATEST_DEFAULT_WIDTH +#define GREATEST_DEFAULT_WIDTH 72 +#endif + +/* FILE *, for test logging. */ +#ifndef GREATEST_STDOUT +#define GREATEST_STDOUT stdout +#endif + +/* Remove GREATEST_ prefix from most commonly used symbols? */ +#ifndef GREATEST_USE_ABBREVS +#define GREATEST_USE_ABBREVS 1 +#endif + +/* Set to 0 to disable all use of setjmp/longjmp. */ +#ifndef GREATEST_USE_LONGJMP +#define GREATEST_USE_LONGJMP 1 +#endif + +#if GREATEST_USE_LONGJMP +#include +#endif + +/* Set to 0 to disable all use of time.h / clock(). */ +#ifndef GREATEST_USE_TIME +#define GREATEST_USE_TIME 1 +#endif + +#if GREATEST_USE_TIME +#include +#endif + +/* Floating point type, for ASSERT_IN_RANGE. */ +#ifndef GREATEST_FLOAT +#define GREATEST_FLOAT double +#define GREATEST_FLOAT_FMT "%g" +#endif + +/********* + * Types * + *********/ + +/* Info for the current running suite. */ +typedef struct greatest_suite_info { + unsigned int tests_run; + unsigned int passed; + unsigned int failed; + unsigned int skipped; + +#if GREATEST_USE_TIME + /* timers, pre/post running suite and individual tests */ + clock_t pre_suite; + clock_t post_suite; + clock_t pre_test; + clock_t post_test; +#endif +} greatest_suite_info; + +/* Type for a suite function. */ +typedef void (greatest_suite_cb)(void); + +/* Types for setup/teardown callbacks. If non-NULL, these will be run + * and passed the pointer to their additional data. */ +typedef void (greatest_setup_cb)(void *udata); +typedef void (greatest_teardown_cb)(void *udata); + +/* Type for an equality comparison between two pointers of the same type. + * Should return non-0 if equal, otherwise 0. + * UDATA is a closure value, passed through from ASSERT_EQUAL_T[m]. */ +typedef int greatest_equal_cb(const void *exp, const void *got, void *udata); + +/* Type for a callback that prints a value pointed to by T. + * Return value has the same meaning as printf's. + * UDATA is a closure value, passed through from ASSERT_EQUAL_T[m]. */ +typedef int greatest_printf_cb(const void *t, void *udata); + +/* Callbacks for an arbitrary type; needed for type-specific + * comparisons via GREATEST_ASSERT_EQUAL_T[m].*/ +typedef struct greatest_type_info { + greatest_equal_cb *equal; + greatest_printf_cb *print; +} greatest_type_info; + +typedef struct greatest_memory_cmp_env { + const unsigned char *exp; + const unsigned char *got; + size_t size; +} greatest_memory_cmp_env; + +/* Callbacks for string and raw memory types. */ +extern greatest_type_info greatest_type_info_string; +extern greatest_type_info greatest_type_info_memory; + +typedef enum { + GREATEST_FLAG_FIRST_FAIL = 0x01, + GREATEST_FLAG_LIST_ONLY = 0x02 +} greatest_flag_t; + +/* Struct containing all test runner state. */ +typedef struct greatest_run_info { + unsigned char flags; + unsigned char verbosity; + unsigned int tests_run; /* total test count */ + + /* overall pass/fail/skip counts */ + unsigned int passed; + unsigned int failed; + unsigned int skipped; + unsigned int assertions; + + /* currently running test suite */ + greatest_suite_info suite; + + /* info to print about the most recent failure */ + const char *fail_file; + unsigned int fail_line; + const char *msg; + + /* current setup/teardown hooks and userdata */ + greatest_setup_cb *setup; + void *setup_udata; + greatest_teardown_cb *teardown; + void *teardown_udata; + + /* formatting info for ".....s...F"-style output */ + unsigned int col; + unsigned int width; + + /* only run a specific suite or test */ + const char *suite_filter; + const char *test_filter; + +#if GREATEST_USE_TIME + /* overall timers */ + clock_t begin; + clock_t end; +#endif + +#if GREATEST_USE_LONGJMP + jmp_buf jump_dest; +#endif +} greatest_run_info; + +struct greatest_report_t { + /* overall pass/fail/skip counts */ + unsigned int passed; + unsigned int failed; + unsigned int skipped; + unsigned int assertions; +}; + +/* Global var for the current testing context. + * Initialized by GREATEST_MAIN_DEFS(). */ +extern greatest_run_info greatest_info; + +/* Type for ASSERT_ENUM_EQ's ENUM_STR argument. */ +typedef const char *greatest_enum_str_fun(int value); + +/********************** + * Exported functions * + **********************/ + +/* These are used internally by greatest. */ +void greatest_do_pass(const char *name); +void greatest_do_fail(const char *name); +void greatest_do_skip(const char *name); +int greatest_pre_test(const char *name); +void greatest_post_test(const char *name, int res); +void greatest_usage(const char *name); +int greatest_do_assert_equal_t(const void *exp, const void *got, + greatest_type_info *type_info, void *udata); + +/* These are part of the public greatest API. */ +void GREATEST_SET_SETUP_CB(greatest_setup_cb *cb, void *udata); +void GREATEST_SET_TEARDOWN_CB(greatest_teardown_cb *cb, void *udata); +int greatest_all_passed(void); +void greatest_set_test_filter(const char *name); +void greatest_set_suite_filter(const char *name); +void greatest_get_report(struct greatest_report_t *report); +unsigned int greatest_get_verbosity(void); +void greatest_set_verbosity(unsigned int verbosity); +void greatest_set_flag(greatest_flag_t flag); + + +/******************** +* Language Support * +********************/ + +/* If __VA_ARGS__ (C99) is supported, allow parametric testing +* without needing to manually manage the argument struct. */ +#if __STDC_VERSION__ >= 19901L || _MSC_VER >= 1800 +#define GREATEST_VA_ARGS +#endif + + +/********** + * Macros * + **********/ + +/* Define a suite. */ +#define GREATEST_SUITE(NAME) void NAME(void); void NAME(void) + +/* Declare a suite, provided by another compilation unit. */ +#define GREATEST_SUITE_EXTERN(NAME) void NAME(void) + +/* Start defining a test function. + * The arguments are not included, to allow parametric testing. */ +#define GREATEST_TEST static enum greatest_test_res + +/* PASS/FAIL/SKIP result from a test. Used internally. */ +typedef enum greatest_test_res { + GREATEST_TEST_RES_PASS = 0, + GREATEST_TEST_RES_FAIL = -1, + GREATEST_TEST_RES_SKIP = 1 +} greatest_test_res; + +/* Run a suite. */ +#define GREATEST_RUN_SUITE(S_NAME) greatest_run_suite(S_NAME, #S_NAME) + +/* Run a test in the current suite. */ +#define GREATEST_RUN_TEST(TEST) \ + do { \ + if (greatest_pre_test(#TEST) == 1) { \ + enum greatest_test_res res = GREATEST_SAVE_CONTEXT(); \ + if (res == GREATEST_TEST_RES_PASS) { \ + res = TEST(); \ + } \ + greatest_post_test(#TEST, res); \ + } else if (GREATEST_LIST_ONLY()) { \ + fprintf(GREATEST_STDOUT, " %s\n", #TEST); \ + } \ + } while (0) + +/* Ignore a test, don't warn about it being unused. */ +#define GREATEST_IGNORE_TEST(TEST) (void)TEST + +/* Run a test in the current suite with one void * argument, + * which can be a pointer to a struct with multiple arguments. */ +#define GREATEST_RUN_TEST1(TEST, ENV) \ + do { \ + if (greatest_pre_test(#TEST) == 1) { \ + int res = TEST(ENV); \ + greatest_post_test(#TEST, res); \ + } else if (GREATEST_LIST_ONLY()) { \ + fprintf(GREATEST_STDOUT, " %s\n", #TEST); \ + } \ + } while (0) + +#ifdef GREATEST_VA_ARGS +#define GREATEST_RUN_TESTp(TEST, ...) \ + do { \ + if (greatest_pre_test(#TEST) == 1) { \ + int res = TEST(__VA_ARGS__); \ + greatest_post_test(#TEST, res); \ + } else if (GREATEST_LIST_ONLY()) { \ + fprintf(GREATEST_STDOUT, " %s\n", #TEST); \ + } \ + } while (0) +#endif + + +/* Check if the test runner is in verbose mode. */ +#define GREATEST_IS_VERBOSE() ((greatest_info.verbosity) > 0) +#define GREATEST_LIST_ONLY() \ + (greatest_info.flags & GREATEST_FLAG_LIST_ONLY) +#define GREATEST_FIRST_FAIL() \ + (greatest_info.flags & GREATEST_FLAG_FIRST_FAIL) +#define GREATEST_FAILURE_ABORT() \ + (greatest_info.suite.failed > 0 && GREATEST_FIRST_FAIL()) + +/* Message-less forms of tests defined below. */ +#define GREATEST_PASS() GREATEST_PASSm(NULL) +#define GREATEST_FAIL() GREATEST_FAILm(NULL) +#define GREATEST_SKIP() GREATEST_SKIPm(NULL) +#define GREATEST_ASSERT(COND) \ + GREATEST_ASSERTm(#COND, COND) +#define GREATEST_ASSERT_OR_LONGJMP(COND) \ + GREATEST_ASSERT_OR_LONGJMPm(#COND, COND) +#define GREATEST_ASSERT_FALSE(COND) \ + GREATEST_ASSERT_FALSEm(#COND, COND) +#define GREATEST_ASSERT_EQ(EXP, GOT) \ + GREATEST_ASSERT_EQm(#EXP " != " #GOT, EXP, GOT) +#define GREATEST_ASSERT_EQ_FMT(EXP, GOT, FMT) \ + GREATEST_ASSERT_EQ_FMTm(#EXP " != " #GOT, EXP, GOT, FMT) +#define GREATEST_ASSERT_IN_RANGE(EXP, GOT, TOL) \ + GREATEST_ASSERT_IN_RANGEm(#EXP " != " #GOT " +/- " #TOL, EXP, GOT, TOL) +#define GREATEST_ASSERT_EQUAL_T(EXP, GOT, TYPE_INFO, UDATA) \ + GREATEST_ASSERT_EQUAL_Tm(#EXP " != " #GOT, EXP, GOT, TYPE_INFO, UDATA) +#define GREATEST_ASSERT_STR_EQ(EXP, GOT) \ + GREATEST_ASSERT_STR_EQm(#EXP " != " #GOT, EXP, GOT) +#define GREATEST_ASSERT_STRN_EQ(EXP, GOT, SIZE) \ + GREATEST_ASSERT_STRN_EQm(#EXP " != " #GOT, EXP, GOT, SIZE) +#define GREATEST_ASSERT_MEM_EQ(EXP, GOT, SIZE) \ + GREATEST_ASSERT_MEM_EQm(#EXP " != " #GOT, EXP, GOT, SIZE) +#define GREATEST_ASSERT_ENUM_EQ(EXP, GOT, ENUM_STR) \ + GREATEST_ASSERT_ENUM_EQm(#EXP " != " #GOT, EXP, GOT, ENUM_STR) + +/* The following forms take an additional message argument first, + * to be displayed by the test runner. */ + +/* Fail if a condition is not true, with message. */ +#define GREATEST_ASSERTm(MSG, COND) \ + do { \ + greatest_info.assertions++; \ + if (!(COND)) { GREATEST_FAILm(MSG); } \ + } while (0) + +/* Fail if a condition is not true, longjmping out of test. */ +#define GREATEST_ASSERT_OR_LONGJMPm(MSG, COND) \ + do { \ + greatest_info.assertions++; \ + if (!(COND)) { GREATEST_FAIL_WITH_LONGJMPm(MSG); } \ + } while (0) + +/* Fail if a condition is not false, with message. */ +#define GREATEST_ASSERT_FALSEm(MSG, COND) \ + do { \ + greatest_info.assertions++; \ + if ((COND)) { GREATEST_FAILm(MSG); } \ + } while (0) + +/* Fail if EXP != GOT (equality comparison by ==). */ +#define GREATEST_ASSERT_EQm(MSG, EXP, GOT) \ + do { \ + greatest_info.assertions++; \ + if ((EXP) != (GOT)) { GREATEST_FAILm(MSG); } \ + } while (0) + +/* Fail if EXP != GOT (equality comparison by ==). + * Warning: EXP and GOT will be evaluated more than once on failure. */ +#define GREATEST_ASSERT_EQ_FMTm(MSG, EXP, GOT, FMT) \ + do { \ + const char *greatest_FMT = ( FMT ); \ + greatest_info.assertions++; \ + if ((EXP) != (GOT)) { \ + fprintf(GREATEST_STDOUT, "\nExpected: "); \ + fprintf(GREATEST_STDOUT, greatest_FMT, EXP); \ + fprintf(GREATEST_STDOUT, "\n Got: "); \ + fprintf(GREATEST_STDOUT, greatest_FMT, GOT); \ + fprintf(GREATEST_STDOUT, "\n"); \ + GREATEST_FAILm(MSG); \ + } \ + } while (0) + +/* Fail if EXP is not equal to GOT, printing enum IDs. */ +#define GREATEST_ASSERT_ENUM_EQm(MSG, EXP, GOT, ENUM_STR) \ + do { \ + int greatest_EXP = (int)(EXP); \ + int greatest_GOT = (int)(GOT); \ + greatest_enum_str_fun *greatest_ENUM_STR = ENUM_STR; \ + if (greatest_EXP != greatest_GOT) { \ + fprintf(GREATEST_STDOUT, "\nExpected: %s", \ + greatest_ENUM_STR(greatest_EXP)); \ + fprintf(GREATEST_STDOUT, "\n Got: %s\n", \ + greatest_ENUM_STR(greatest_GOT)); \ + GREATEST_FAILm(MSG); \ + } \ + } while (0) \ + +/* Fail if GOT not in range of EXP +|- TOL. */ +#define GREATEST_ASSERT_IN_RANGEm(MSG, EXP, GOT, TOL) \ + do { \ + GREATEST_FLOAT greatest_EXP = (EXP); \ + GREATEST_FLOAT greatest_GOT = (GOT); \ + GREATEST_FLOAT greatest_TOL = (TOL); \ + greatest_info.assertions++; \ + if ((greatest_EXP > greatest_GOT && \ + greatest_EXP - greatest_GOT > greatest_TOL) || \ + (greatest_EXP < greatest_GOT && \ + greatest_GOT - greatest_EXP > greatest_TOL)) { \ + fprintf(GREATEST_STDOUT, \ + "\nExpected: " GREATEST_FLOAT_FMT \ + " +/- " GREATEST_FLOAT_FMT \ + "\n Got: " GREATEST_FLOAT_FMT \ + "\n", \ + greatest_EXP, greatest_TOL, greatest_GOT); \ + GREATEST_FAILm(MSG); \ + } \ + } while (0) + +/* Fail if EXP is not equal to GOT, according to strcmp. */ +#define GREATEST_ASSERT_STR_EQm(MSG, EXP, GOT) \ + do { \ + GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT, \ + &greatest_type_info_string, NULL); \ + } while (0) \ + +/* Fail if EXP is not equal to GOT, according to strcmp. */ +#define GREATEST_ASSERT_STRN_EQm(MSG, EXP, GOT, SIZE) \ + do { \ + size_t size = SIZE; \ + GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT, \ + &greatest_type_info_string, &size); \ + } while (0) \ + +/* Fail if EXP is not equal to GOT, according to memcmp. */ +#define GREATEST_ASSERT_MEM_EQm(MSG, EXP, GOT, SIZE) \ + do { \ + greatest_memory_cmp_env env; \ + env.exp = (const unsigned char *)EXP; \ + env.got = (const unsigned char *)GOT; \ + env.size = SIZE; \ + GREATEST_ASSERT_EQUAL_Tm(MSG, env.exp, env.got, \ + &greatest_type_info_memory, &env); \ + } while (0) \ + +/* Fail if EXP is not equal to GOT, according to a comparison + * callback in TYPE_INFO. If they are not equal, optionally use a + * print callback in TYPE_INFO to print them. */ +#define GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT, TYPE_INFO, UDATA) \ + do { \ + greatest_type_info *type_info = (TYPE_INFO); \ + greatest_info.assertions++; \ + if (!greatest_do_assert_equal_t(EXP, GOT, \ + type_info, UDATA)) { \ + if (type_info == NULL || type_info->equal == NULL) { \ + GREATEST_FAILm("type_info->equal callback missing!"); \ + } else { \ + GREATEST_FAILm(MSG); \ + } \ + } \ + } while (0) \ + +/* Pass. */ +#define GREATEST_PASSm(MSG) \ + do { \ + greatest_info.msg = MSG; \ + return GREATEST_TEST_RES_PASS; \ + } while (0) + +/* Fail. */ +#define GREATEST_FAILm(MSG) \ + do { \ + greatest_info.fail_file = __FILE__; \ + greatest_info.fail_line = __LINE__; \ + greatest_info.msg = MSG; \ + return GREATEST_TEST_RES_FAIL; \ + } while (0) + +/* Optional GREATEST_FAILm variant that longjmps. */ +#if GREATEST_USE_LONGJMP +#define GREATEST_FAIL_WITH_LONGJMP() GREATEST_FAIL_WITH_LONGJMPm(NULL) +#define GREATEST_FAIL_WITH_LONGJMPm(MSG) \ + do { \ + greatest_info.fail_file = __FILE__; \ + greatest_info.fail_line = __LINE__; \ + greatest_info.msg = MSG; \ + longjmp(greatest_info.jump_dest, GREATEST_TEST_RES_FAIL); \ + } while (0) +#endif + +/* Skip the current test. */ +#define GREATEST_SKIPm(MSG) \ + do { \ + greatest_info.msg = MSG; \ + return GREATEST_TEST_RES_SKIP; \ + } while (0) + +/* Check the result of a subfunction using ASSERT, etc. */ +#define GREATEST_CHECK_CALL(RES) \ + do { \ + enum greatest_test_res greatest_RES = RES; \ + if (greatest_RES != GREATEST_TEST_RES_PASS) { \ + return greatest_RES; \ + } \ + } while (0) \ + +#if GREATEST_USE_TIME +#define GREATEST_SET_TIME(NAME) \ + NAME = clock(); \ + if (NAME == (clock_t) -1) { \ + fprintf(GREATEST_STDOUT, \ + "clock error: %s\n", #NAME); \ + exit(EXIT_FAILURE); \ + } + +#define GREATEST_CLOCK_DIFF(C1, C2) \ + fprintf(GREATEST_STDOUT, " (%lu ticks, %.3f sec)", \ + (long unsigned int) (C2) - (long unsigned int)(C1), \ + (double)((C2) - (C1)) / (1.0 * (double)CLOCKS_PER_SEC)) +#else +#define GREATEST_SET_TIME(UNUSED) +#define GREATEST_CLOCK_DIFF(UNUSED1, UNUSED2) +#endif + +#if GREATEST_USE_LONGJMP +#define GREATEST_SAVE_CONTEXT() \ + /* setjmp returns 0 (GREATEST_TEST_RES_PASS) on first call */ \ + /* so the test runs, then RES_FAIL from FAIL_WITH_LONGJMP. */ \ + ((enum greatest_test_res)(setjmp(greatest_info.jump_dest))) +#else +#define GREATEST_SAVE_CONTEXT() \ + /*a no-op, since setjmp/longjmp aren't being used */ \ + GREATEST_TEST_RES_PASS +#endif + +/* Include several function definitions in the main test file. */ +#define GREATEST_MAIN_DEFS() \ + \ +/* Is FILTER a subset of NAME? */ \ +static int greatest_name_match(const char *name, \ + const char *filter) { \ + size_t offset = 0; \ + size_t filter_len = strlen(filter); \ + while (name[offset] != '\0') { \ + if (name[offset] == filter[0]) { \ + if (0 == strncmp(&name[offset], filter, filter_len)) { \ + return 1; \ + } \ + } \ + offset++; \ + } \ + \ + return 0; \ +} \ + \ +int greatest_pre_test(const char *name) { \ + if (!GREATEST_LIST_ONLY() \ + && (!GREATEST_FIRST_FAIL() || greatest_info.suite.failed == 0) \ + && (greatest_info.test_filter == NULL || \ + greatest_name_match(name, greatest_info.test_filter))) { \ + GREATEST_SET_TIME(greatest_info.suite.pre_test); \ + if (greatest_info.setup) { \ + greatest_info.setup(greatest_info.setup_udata); \ + } \ + return 1; /* test should be run */ \ + } else { \ + return 0; /* skipped */ \ + } \ +} \ + \ +void greatest_post_test(const char *name, int res) { \ + GREATEST_SET_TIME(greatest_info.suite.post_test); \ + if (greatest_info.teardown) { \ + void *udata = greatest_info.teardown_udata; \ + greatest_info.teardown(udata); \ + } \ + \ + if (res <= GREATEST_TEST_RES_FAIL) { \ + greatest_do_fail(name); \ + } else if (res >= GREATEST_TEST_RES_SKIP) { \ + greatest_do_skip(name); \ + } else if (res == GREATEST_TEST_RES_PASS) { \ + greatest_do_pass(name); \ + } \ + greatest_info.suite.tests_run++; \ + greatest_info.col++; \ + if (GREATEST_IS_VERBOSE()) { \ + GREATEST_CLOCK_DIFF(greatest_info.suite.pre_test, \ + greatest_info.suite.post_test); \ + fprintf(GREATEST_STDOUT, "\n"); \ + } else if (greatest_info.col % greatest_info.width == 0) { \ + fprintf(GREATEST_STDOUT, "\n"); \ + greatest_info.col = 0; \ + } \ + if (GREATEST_STDOUT == stdout) fflush(stdout); \ +} \ + \ +static void report_suite(void) { \ + if (greatest_info.suite.tests_run > 0) { \ + fprintf(GREATEST_STDOUT, \ + "\n%u test%s - %u passed, %u failed, %u skipped", \ + greatest_info.suite.tests_run, \ + greatest_info.suite.tests_run == 1 ? "" : "s", \ + greatest_info.suite.passed, \ + greatest_info.suite.failed, \ + greatest_info.suite.skipped); \ + GREATEST_CLOCK_DIFF(greatest_info.suite.pre_suite, \ + greatest_info.suite.post_suite); \ + fprintf(GREATEST_STDOUT, "\n"); \ + } \ +} \ + \ +static void update_counts_and_reset_suite(void) { \ + greatest_info.setup = NULL; \ + greatest_info.setup_udata = NULL; \ + greatest_info.teardown = NULL; \ + greatest_info.teardown_udata = NULL; \ + greatest_info.passed += greatest_info.suite.passed; \ + greatest_info.failed += greatest_info.suite.failed; \ + greatest_info.skipped += greatest_info.suite.skipped; \ + greatest_info.tests_run += greatest_info.suite.tests_run; \ + memset(&greatest_info.suite, 0, sizeof(greatest_info.suite)); \ + greatest_info.col = 0; \ +} \ + \ +static void greatest_run_suite(greatest_suite_cb *suite_cb, \ + const char *suite_name) { \ + if (greatest_info.suite_filter && \ + !greatest_name_match(suite_name, greatest_info.suite_filter)) { \ + return; \ + } \ + update_counts_and_reset_suite(); \ + if (GREATEST_FIRST_FAIL() && greatest_info.failed > 0) { return; } \ + fprintf(GREATEST_STDOUT, "\n* Suite %s:\n", suite_name); \ + GREATEST_SET_TIME(greatest_info.suite.pre_suite); \ + suite_cb(); \ + GREATEST_SET_TIME(greatest_info.suite.post_suite); \ + report_suite(); \ +} \ + \ +void greatest_do_pass(const char *name) { \ + if (GREATEST_IS_VERBOSE()) { \ + fprintf(GREATEST_STDOUT, "PASS %s: %s", \ + name, greatest_info.msg ? greatest_info.msg : ""); \ + } else { \ + fprintf(GREATEST_STDOUT, "."); \ + } \ + greatest_info.suite.passed++; \ +} \ + \ +void greatest_do_fail(const char *name) { \ + if (GREATEST_IS_VERBOSE()) { \ + fprintf(GREATEST_STDOUT, \ + "FAIL %s: %s (%s:%u)", \ + name, greatest_info.msg ? greatest_info.msg : "", \ + greatest_info.fail_file, greatest_info.fail_line); \ + } else { \ + fprintf(GREATEST_STDOUT, "F"); \ + greatest_info.col++; \ + /* add linebreak if in line of '.'s */ \ + if (greatest_info.col != 0) { \ + fprintf(GREATEST_STDOUT, "\n"); \ + greatest_info.col = 0; \ + } \ + fprintf(GREATEST_STDOUT, "FAIL %s: %s (%s:%u)\n", \ + name, \ + greatest_info.msg ? greatest_info.msg : "", \ + greatest_info.fail_file, greatest_info.fail_line); \ + } \ + greatest_info.suite.failed++; \ +} \ + \ +void greatest_do_skip(const char *name) { \ + if (GREATEST_IS_VERBOSE()) { \ + fprintf(GREATEST_STDOUT, "SKIP %s: %s", \ + name, \ + greatest_info.msg ? \ + greatest_info.msg : "" ); \ + } else { \ + fprintf(GREATEST_STDOUT, "s"); \ + } \ + greatest_info.suite.skipped++; \ +} \ + \ +int greatest_do_assert_equal_t(const void *exp, const void *got, \ + greatest_type_info *type_info, void *udata) { \ + int eq = 0; \ + if (type_info == NULL || type_info->equal == NULL) { \ + return 0; \ + } \ + eq = type_info->equal(exp, got, udata); \ + if (!eq) { \ + if (type_info->print != NULL) { \ + fprintf(GREATEST_STDOUT, "\nExpected: "); \ + (void)type_info->print(exp, udata); \ + fprintf(GREATEST_STDOUT, "\n Got: "); \ + (void)type_info->print(got, udata); \ + fprintf(GREATEST_STDOUT, "\n"); \ + } else { \ + fprintf(GREATEST_STDOUT, \ + "GREATEST_ASSERT_EQUAL_T failure at %s:%u\n", \ + greatest_info.fail_file, \ + greatest_info.fail_line); \ + } \ + } \ + return eq; \ +} \ + \ +void greatest_usage(const char *name) { \ + fprintf(GREATEST_STDOUT, \ + "Usage: %s [-hlfv] [-s SUITE] [-t TEST]\n" \ + " -h, --help print this Help\n" \ + " -l List suites and their tests, then exit\n" \ + " -f Stop runner after first failure\n" \ + " -v Verbose output\n" \ + " -s SUITE only run suites containing string SUITE\n" \ + " -t TEST only run tests containing string TEST\n", \ + name); \ +} \ + \ +static void greatest_parse_args(int argc, char **argv) { \ + int i = 0; \ + for (i = 1; i < argc; i++) { \ + if (0 == strncmp("-t", argv[i], 2)) { \ + if (argc <= i + 1) { \ + greatest_usage(argv[0]); \ + exit(EXIT_FAILURE); \ + } \ + greatest_info.test_filter = argv[i+1]; \ + i++; \ + } else if (0 == strncmp("-s", argv[i], 2)) { \ + if (argc <= i + 1) { \ + greatest_usage(argv[0]); \ + exit(EXIT_FAILURE); \ + } \ + greatest_info.suite_filter = argv[i+1]; \ + i++; \ + } else if (0 == strncmp("-f", argv[i], 2)) { \ + greatest_info.flags |= GREATEST_FLAG_FIRST_FAIL; \ + } else if (0 == strncmp("-v", argv[i], 2)) { \ + greatest_info.verbosity++; \ + } else if (0 == strncmp("-l", argv[i], 2)) { \ + greatest_info.flags |= GREATEST_FLAG_LIST_ONLY; \ + } else if (0 == strncmp("-h", argv[i], 2) || \ + 0 == strncmp("--help", argv[i], 6)) { \ + greatest_usage(argv[0]); \ + exit(EXIT_SUCCESS); \ + } else if (0 == strncmp("--", argv[i], 2)) { \ + break; \ + } else { \ + fprintf(GREATEST_STDOUT, \ + "Unknown argument '%s'\n", argv[i]); \ + greatest_usage(argv[0]); \ + exit(EXIT_FAILURE); \ + } \ + } \ +} \ + \ +int greatest_all_passed(void) { return (greatest_info.failed == 0); } \ + \ +void greatest_set_test_filter(const char *name) { \ + greatest_info.test_filter = name; \ +} \ + \ +void greatest_set_suite_filter(const char *name) { \ + greatest_info.suite_filter = name; \ +} \ + \ +void greatest_get_report(struct greatest_report_t *report) { \ + if (report) { \ + report->passed = greatest_info.passed; \ + report->failed = greatest_info.failed; \ + report->skipped = greatest_info.skipped; \ + report->assertions = greatest_info.assertions; \ + } \ +} \ + \ +unsigned int greatest_get_verbosity(void) { \ + return greatest_info.verbosity; \ +} \ + \ +void greatest_set_verbosity(unsigned int verbosity) { \ + greatest_info.verbosity = (unsigned char)verbosity; \ +} \ + \ +void greatest_set_flag(greatest_flag_t flag) { \ + greatest_info.flags |= flag; \ +} \ + \ +void GREATEST_SET_SETUP_CB(greatest_setup_cb *cb, void *udata) { \ + greatest_info.setup = cb; \ + greatest_info.setup_udata = udata; \ +} \ + \ +void GREATEST_SET_TEARDOWN_CB(greatest_teardown_cb *cb, \ + void *udata) { \ + greatest_info.teardown = cb; \ + greatest_info.teardown_udata = udata; \ +} \ + \ +static int greatest_string_equal_cb(const void *exp, const void *got, \ + void *udata) { \ + size_t *size = (size_t *)udata; \ + return (size != NULL \ + ? (0 == strncmp((const char *)exp, (const char *)got, *size)) \ + : (0 == strcmp((const char *)exp, (const char *)got))); \ +} \ + \ +static int greatest_string_printf_cb(const void *t, void *udata) { \ + (void)udata; /* note: does not check \0 termination. */ \ + return fprintf(GREATEST_STDOUT, "%s", (const char *)t); \ +} \ + \ +greatest_type_info greatest_type_info_string = { \ + greatest_string_equal_cb, \ + greatest_string_printf_cb, \ +}; \ + \ +static int greatest_memory_equal_cb(const void *exp, const void *got, \ + void *udata) { \ + greatest_memory_cmp_env *env = (greatest_memory_cmp_env *)udata; \ + return (0 == memcmp(exp, got, env->size)); \ +} \ + \ +static int greatest_memory_printf_cb(const void *t, void *udata) { \ + greatest_memory_cmp_env *env = (greatest_memory_cmp_env *)udata; \ + unsigned char *buf = (unsigned char *)t, diff_mark = ' '; \ + FILE *out = GREATEST_STDOUT; \ + size_t i, line_i, line_len = 0; \ + int len = 0; /* format hexdump with differences highlighted */ \ + for (i = 0; i < env->size; i+= line_len) { \ + diff_mark = ' '; \ + line_len = env->size - i; \ + if (line_len > 16) { line_len = 16; } \ + for (line_i = i; line_i < i + line_len; line_i++) { \ + if (env->exp[line_i] != env->got[line_i]) diff_mark = 'X'; \ + } \ + len += fprintf(out, "\n%04x %c ", (unsigned int)i, diff_mark); \ + for (line_i = i; line_i < i + line_len; line_i++) { \ + int m = env->exp[line_i] == env->got[line_i]; /* match? */ \ + len += fprintf(out, "%02x%c", buf[line_i], m ? ' ' : '<'); \ + } \ + for (line_i = 0; line_i < 16 - line_len; line_i++) { \ + len += fprintf(out, " "); \ + } \ + fprintf(out, " "); \ + for (line_i = i; line_i < i + line_len; line_i++) { \ + unsigned char c = buf[line_i]; \ + len += fprintf(out, "%c", isprint(c) ? c : '.'); \ + } \ + } \ + len += fprintf(out, "\n"); \ + return len; \ +} \ + \ +greatest_type_info greatest_type_info_memory = { \ + greatest_memory_equal_cb, \ + greatest_memory_printf_cb, \ +}; \ + \ +greatest_run_info greatest_info + +/* Init internals. */ +#define GREATEST_INIT() \ + do { \ + /* Suppress unused function warning if features aren't used */ \ + (void)greatest_run_suite; \ + (void)greatest_parse_args; \ + \ + memset(&greatest_info, 0, sizeof(greatest_info)); \ + greatest_info.width = GREATEST_DEFAULT_WIDTH; \ + GREATEST_SET_TIME(greatest_info.begin); \ + } while (0) \ + +/* Handle command-line arguments, etc. */ +#define GREATEST_MAIN_BEGIN() \ + do { \ + GREATEST_INIT(); \ + greatest_parse_args(argc, argv); \ + } while (0) + +/* Report passes, failures, skipped tests, the number of + * assertions, and the overall run time. */ +#define GREATEST_PRINT_REPORT() \ + do { \ + if (!GREATEST_LIST_ONLY()) { \ + update_counts_and_reset_suite(); \ + GREATEST_SET_TIME(greatest_info.end); \ + fprintf(GREATEST_STDOUT, \ + "\nTotal: %u test%s", \ + greatest_info.tests_run, \ + greatest_info.tests_run == 1 ? "" : "s"); \ + GREATEST_CLOCK_DIFF(greatest_info.begin, \ + greatest_info.end); \ + fprintf(GREATEST_STDOUT, ", %u assertion%s\n", \ + greatest_info.assertions, \ + greatest_info.assertions == 1 ? "" : "s"); \ + fprintf(GREATEST_STDOUT, \ + "Pass: %u, fail: %u, skip: %u.\n", \ + greatest_info.passed, \ + greatest_info.failed, greatest_info.skipped); \ + } \ + } while (0) + +/* Report results, exit with exit status based on results. */ +#define GREATEST_MAIN_END() \ + do { \ + GREATEST_PRINT_REPORT(); \ + return (greatest_all_passed() ? EXIT_SUCCESS : EXIT_FAILURE); \ + } while (0) + +/* Make abbreviations without the GREATEST_ prefix for the + * most commonly used symbols. */ +#if GREATEST_USE_ABBREVS +#define TEST GREATEST_TEST +#define SUITE GREATEST_SUITE +#define SUITE_EXTERN GREATEST_SUITE_EXTERN +#define RUN_TEST GREATEST_RUN_TEST +#define RUN_TEST1 GREATEST_RUN_TEST1 +#define RUN_SUITE GREATEST_RUN_SUITE +#define IGNORE_TEST GREATEST_IGNORE_TEST +#define ASSERT GREATEST_ASSERT +#define ASSERTm GREATEST_ASSERTm +#define ASSERT_FALSE GREATEST_ASSERT_FALSE +#define ASSERT_EQ GREATEST_ASSERT_EQ +#define ASSERT_EQ_FMT GREATEST_ASSERT_EQ_FMT +#define ASSERT_IN_RANGE GREATEST_ASSERT_IN_RANGE +#define ASSERT_EQUAL_T GREATEST_ASSERT_EQUAL_T +#define ASSERT_STR_EQ GREATEST_ASSERT_STR_EQ +#define ASSERT_STRN_EQ GREATEST_ASSERT_STRN_EQ +#define ASSERT_MEM_EQ GREATEST_ASSERT_MEM_EQ +#define ASSERT_ENUM_EQ GREATEST_ASSERT_ENUM_EQ +#define ASSERT_FALSEm GREATEST_ASSERT_FALSEm +#define ASSERT_EQm GREATEST_ASSERT_EQm +#define ASSERT_EQ_FMTm GREATEST_ASSERT_EQ_FMTm +#define ASSERT_IN_RANGEm GREATEST_ASSERT_IN_RANGEm +#define ASSERT_EQUAL_Tm GREATEST_ASSERT_EQUAL_Tm +#define ASSERT_STR_EQm GREATEST_ASSERT_STR_EQm +#define ASSERT_STRN_EQm GREATEST_ASSERT_STRN_EQm +#define ASSERT_MEM_EQm GREATEST_ASSERT_MEM_EQm +#define ASSERT_ENUM_EQm GREATEST_ASSERT_ENUM_EQm +#define PASS GREATEST_PASS +#define FAIL GREATEST_FAIL +#define SKIP GREATEST_SKIP +#define PASSm GREATEST_PASSm +#define FAILm GREATEST_FAILm +#define SKIPm GREATEST_SKIPm +#define SET_SETUP GREATEST_SET_SETUP_CB +#define SET_TEARDOWN GREATEST_SET_TEARDOWN_CB +#define CHECK_CALL GREATEST_CHECK_CALL + +#ifdef GREATEST_VA_ARGS +#define RUN_TESTp GREATEST_RUN_TESTp +#endif + +#if GREATEST_USE_LONGJMP +#define ASSERT_OR_LONGJMP GREATEST_ASSERT_OR_LONGJMP +#define ASSERT_OR_LONGJMPm GREATEST_ASSERT_OR_LONGJMPm +#define FAIL_WITH_LONGJMP GREATEST_FAIL_WITH_LONGJMP +#define FAIL_WITH_LONGJMPm GREATEST_FAIL_WITH_LONGJMPm +#endif + +#endif /* USE_ABBREVS */ + +#ifdef __cplusplus +} +#endif + +#endif From d441e950d8db03052aa1c79a49ec4d55dfd4215b Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Sat, 19 Nov 2016 12:26:00 +0200 Subject: [PATCH 39/72] Implement test target and add the first test make test will now compile the tests to test/test. The first test, testing string_replace_char from utils.c, was added. --- Makefile | 13 ++++++++++++- test/test.c | 12 ++++++++++++ test/utils.c | 19 +++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 test/test.c create mode 100644 test/utils.c diff --git a/Makefile b/Makefile index 0e4f604..18c8e18 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ clean-dunstify: clean-doc: rm -f dunst.1 -clean: clean-dunst clean-dunstify clean-doc +clean: clean-dunst clean-dunstify clean-doc test-clean doc: dunst.1 dunst.1: README.pod @@ -89,4 +89,15 @@ uninstall: @echo Removing documentation directory ${DESTDIR}${PREFIX}/share/dunst rm -rf ${DESTDIR}${PREFIX}/share/dunst +test: test/test + +TEST_SRC = $(shell ls test/*.c) +TEST_OBJ = $(TEST_SRC:.c=.o) + +test/test: ${OBJ} ${TEST_OBJ} + ${CC} ${CFLAGS} -o $@ ${TEST_OBJ} ${OBJ} ${LDFLAGS} + +test-clean: + rm -f test/test test/*.o + .PHONY: all options clean dist install uninstall diff --git a/test/test.c b/test/test.c new file mode 100644 index 0000000..5cfd346 --- /dev/null +++ b/test/test.c @@ -0,0 +1,12 @@ +#include "greatest.h" + +SUITE_EXTERN(utils); + +GREATEST_MAIN_DEFS(); + +int main(int argc, char *argv[]) { + GREATEST_MAIN_BEGIN(); + RUN_SUITE(utils); + GREATEST_MAIN_END(); +} +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/test/utils.c b/test/utils.c new file mode 100644 index 0000000..dcfcb05 --- /dev/null +++ b/test/utils.c @@ -0,0 +1,19 @@ +#include "greatest.h" +#include "src/utils.h" + +TEST test_string_replace_char(void) +{ + char *text = calloc(128, sizeof(char)); + strcpy(text, "a aa aaa"); + ASSERT_STR_EQ(string_replace_char('a', 'b', text), "b bb bbb"); + strcpy(text, ""); + ASSERT_STR_EQ(string_replace_char('a', 'b', text), ""); + free(text); + PASS(); +} + +SUITE(utils) +{ + RUN_TEST(test_string_replace_char); +} +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ From dfdc082687f35954408279407ce54c28a2136caf Mon Sep 17 00:00:00 2001 From: Eizen Date: Sat, 19 Nov 2016 20:11:21 -0300 Subject: [PATCH 40/72] Change README Move README to docs/dunst.pod to be used as man page. Write a README with building instructions and dependencies. Remove INSTALL as it's no longer necessary. --- INSTALL | 23 ------------------ Makefile | 2 +- README.md | 46 ++++++++++++++++++++++++++++++++++++ README.pod => docs/dunst.pod | 0 4 files changed, 47 insertions(+), 24 deletions(-) delete mode 100644 INSTALL create mode 100644 README.md rename README.pod => docs/dunst.pod (100%) diff --git a/INSTALL b/INSTALL deleted file mode 100644 index de50361..0000000 --- a/INSTALL +++ /dev/null @@ -1,23 +0,0 @@ -The following dependencies are needed: - - dbus - libxinerama - libxft - libxss - libxdg-basedir - glib - pango/cairo - -On Debian and Debian-based distros you'll probably also need the *-dev packages. - -With all dependencies present you can build dunst with: - - $ make - -If you're getting compilation errors after an update try compiling -with the default config.h. -If you didn't edit your config.h you can just delete it. - -and install with: - - $ sudo make PREFIX=/usr install diff --git a/Makefile b/Makefile index 18c8e18..e297b2f 100644 --- a/Makefile +++ b/Makefile @@ -57,7 +57,7 @@ clean-doc: clean: clean-dunst clean-dunstify clean-doc test-clean doc: dunst.1 -dunst.1: README.pod +dunst.1: docs/dunst.pod pod2man --name=dunst -c "Dunst Reference" --section=1 --release=${VERSION} $< > $@ service: diff --git a/README.md b/README.md new file mode 100644 index 0000000..b3cd19b --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ +## Dunst + + +## Description + +Dunst is a highly configurable and lightweight notification daemon. + + +## Compiling + +Dunst has a number of build dependencies that must be present before attempting configuration. The names are different depending on distribution: + +- dbus +- libxinerama +- libxft +- libxss +- libxdg-basedir +- glib +- pango +- cairo + +On Debian and Debian-based distros you'll probably also need the *-dev packages. + +To build it: +```bash +cd dunst +make +sudo make PREFIX=/usr install +``` + + +## Bug reports + +Please use the [issue tracker][issue-tracker] provided by GitHub to send us bug reports or feature requests. + + +## Author + +written by Sascha Kruse + + +## Copyright + +copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) + +If you feel that copyrights are violated, please send me an email. diff --git a/README.pod b/docs/dunst.pod similarity index 100% rename from README.pod rename to docs/dunst.pod From b8364f41043125f94732ed08dde0a2546c0002e2 Mon Sep 17 00:00:00 2001 From: Eizen Date: Sat, 19 Nov 2016 20:16:35 -0300 Subject: [PATCH 41/72] Fix missing link README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b3cd19b..fbeeb32 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Please use the [issue tracker][issue-tracker] provided by GitHub to send us bug written by Sascha Kruse - +[issue-tracker]: https://github.com/knopwob/dunst/issues ## Copyright copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) From d605c9179071bc5b6d1ceb5e99b48255e7e93547 Mon Sep 17 00:00:00 2001 From: Eizen Date: Sun, 20 Nov 2016 00:03:25 -0300 Subject: [PATCH 42/72] Fix merge commit --- src/x.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/x.c b/src/x.c index 97e33ac..1a5972f 100644 --- a/src/x.c +++ b/src/x.c @@ -568,7 +568,8 @@ static dimension_t x_render_layout(cairo_t *c, colored_layout *cl, colored_layou if (!last) bg_height -= settings.separator_height; } bg_width -= 2 * settings.frame_width; - bg_height += settings.frame_width; + if (last) + bg_height -= settings.frame_width; cairo_set_source_rgb(c, cl->bg.r, cl->bg.g, cl->bg.b); cairo_rectangle(c, bg_x, bg_y, bg_width, bg_height); @@ -581,13 +582,13 @@ static dimension_t x_render_layout(cairo_t *c, colored_layout *cl, colored_layou dim.y += (int) (ceil(bg_half_height) - pango_offset); if (cl->icon && settings.icon_position == icons_left) { cairo_move_to(c, settings.frame_width + cairo_image_surface_get_width(cl->icon) + 2 * settings.h_padding, bg_y + settings.padding + h/2 - h_text/2); - } + } else if (cl->icon && settings.icon_position == icons_right) { - cairo_move_to(c, settings.frame_width + settings.h_padding, bg_y + settings.padding + h/2 - h_text/2); - } + cairo_move_to(c, settings.frame_width + settings.h_padding, bg_y + settings.padding + h/2 - h_text/2); + } else { - cairo_move_to(c, settings.frame_width + settings.h_padding, bg_y + settings.padding); - } + cairo_move_to(c, settings.frame_width + settings.h_padding, bg_y + settings.padding); + } cairo_set_source_rgb(c, cl->fg.r, cl->fg.g, cl->fg.b); pango_cairo_update_layout(c, cl->l); pango_cairo_show_layout(c, cl->l); @@ -605,9 +606,7 @@ static dimension_t x_render_layout(cairo_t *c, colored_layout *cl, colored_layou // the wrong color in the corners. cairo_rectangle(c, 0, dim.y, dim.w, settings.separator_height); else - cairo_rectangle(c, settings.frame_width, dim.y + settings.frame_width, - dim.w - 2 * settings.frame_width - , settings.separator_height); + cairo_rectangle(c, settings.frame_width, dim.y + settings.frame_width, dim.w - 2 * settings.frame_width, settings.separator_height); cairo_fill(c); dim.y += settings.separator_height; From 2784950f452994cf6e7484664aa229783df65a98 Mon Sep 17 00:00:00 2001 From: Eizen Date: Tue, 22 Nov 2016 01:47:42 -0300 Subject: [PATCH 43/72] Fix uninitialized value warning and code indentation --- src/x.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/x.c b/src/x.c index 1a5972f..11e1765 100644 --- a/src/x.c +++ b/src/x.c @@ -537,12 +537,12 @@ static void r_free_layouts(GSList *layouts) static dimension_t x_render_layout(cairo_t *c, colored_layout *cl, colored_layout *cl_next, dimension_t dim, bool first, bool last) { int h; - int h_text; + int h_text = 0; pango_layout_get_pixel_size(cl->l, NULL, &h); if (cl->icon) { - h_text = h; - h = MAX(cairo_image_surface_get_height(cl->icon), h); - } + h_text = h; + h = MAX(cairo_image_surface_get_height(cl->icon), h); + } int bg_x = 0; int bg_y = dim.y; @@ -580,15 +580,15 @@ static dimension_t x_render_layout(cairo_t *c, colored_layout *cl, colored_layou dim.y += settings.padding; else dim.y += (int) (ceil(bg_half_height) - pango_offset); + if (cl->icon && settings.icon_position == icons_left) { cairo_move_to(c, settings.frame_width + cairo_image_surface_get_width(cl->icon) + 2 * settings.h_padding, bg_y + settings.padding + h/2 - h_text/2); - } - else if (cl->icon && settings.icon_position == icons_right) { + } else if (cl->icon && settings.icon_position == icons_right) { cairo_move_to(c, settings.frame_width + settings.h_padding, bg_y + settings.padding + h/2 - h_text/2); - } - else { + } else { cairo_move_to(c, settings.frame_width + settings.h_padding, bg_y + settings.padding); } + cairo_set_source_rgb(c, cl->fg.r, cl->fg.g, cl->fg.b); pango_cairo_update_layout(c, cl->l); pango_cairo_show_layout(c, cl->l); From 756dee58c77fd7711d951e260efdb70b6aaa9828 Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Tue, 22 Nov 2016 17:55:28 +0200 Subject: [PATCH 44/72] Remove unused function --- src/utils.c | 13 ------------- src/utils.h | 2 -- 2 files changed, 15 deletions(-) diff --git a/src/utils.c b/src/utils.c index 4e6821c..1e51da3 100644 --- a/src/utils.c +++ b/src/utils.c @@ -128,19 +128,6 @@ void string_strip_delimited(char *str, char a, char b) str[iwrite] = 0; } -int digit_count(int i) -{ - i = ABS(i); - int len = 1; - - while (i > 0) { - len++; - i /= 10; - } - - return len; -} - void die(char *text, int exit_value) { fputs(text, stderr); diff --git a/src/utils.h b/src/utils.h index 5e09550..cf193cc 100644 --- a/src/utils.h +++ b/src/utils.h @@ -22,8 +22,6 @@ void string_strip_delimited(char *str, char a, char b); /* exit with an error message */ void die(char *msg, int exit_value); - -int digit_count(int i); #endif /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ From 256440b25a878d8ab1f2aeabf2306696220c621b Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Tue, 22 Nov 2016 18:47:38 +0200 Subject: [PATCH 45/72] Implement tests for most of the util functions Also improved the implementation of the test_string_replace_char test. --- test/utils.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 120 insertions(+), 3 deletions(-) diff --git a/test/utils.c b/test/utils.c index dcfcb05..adc9cb7 100644 --- a/test/utils.c +++ b/test/utils.c @@ -3,11 +3,123 @@ TEST test_string_replace_char(void) { - char *text = calloc(128, sizeof(char)); + char *text = malloc(128 * sizeof(char)); strcpy(text, "a aa aaa"); - ASSERT_STR_EQ(string_replace_char('a', 'b', text), "b bb bbb"); + ASSERT_STR_EQ("b bb bbb", string_replace_char('a', 'b', text)); + + strcpy(text, "Nothing to replace"); + ASSERT_STR_EQ("Nothing to replace", string_replace_char('s', 'a', text)); + strcpy(text, ""); - ASSERT_STR_EQ(string_replace_char('a', 'b', text), ""); + ASSERT_STR_EQ("", string_replace_char('a', 'b', text)); + free(text); + + PASS(); +} + +/* + * We trust that string_replace_all and string_replace properly reallocate + * memory if the result is longer than the given string, no real way to test for + * that far as I know. + */ + +TEST test_string_replace_all(void) +{ + + char *text = malloc(128 * sizeof(char)); + strcpy(text, "aaaaa"); + ASSERT_STR_EQ("bbbbb", (text = string_replace_all("a", "b", text))); + + strcpy(text, ""); + ASSERT_STR_EQ("", (text = string_replace_all("a", "b", text))); + + strcpy(text, "Nothing to replace"); + ASSERT_STR_EQ((text = string_replace_all("z", "a", text)), "Nothing to replace"); + + strcpy(text, "Reverse this"); + ASSERT_STR_EQ("Reverse sith", (text = string_replace_all("this", "sith", text))); + + strcpy(text, "abcdabc"); + ASSERT_STR_EQ("xyzabcdxyzabc", (text = string_replace_all("a", "xyza", text))); + + free(text); + PASS(); +} + +TEST test_string_replace(void) +{ + char *text = malloc(128 * sizeof(char)); + strcpy(text, "aaaaa"); + ASSERT_STR_EQ("baaaa", (text = string_replace("a", "b", text)) ); + + strcpy(text, ""); + ASSERT_STR_EQ((text = string_replace("a", "b", text)), ""); + + strcpy(text, "Nothing to replace"); + ASSERT_STR_EQ((text = string_replace("z", "a", text)), "Nothing to replace"); + + strcpy(text, "Reverse this"); + ASSERT_STR_EQ("Reverse sith", (text = string_replace("this", "sith", text))); + + strcpy(text, "abcdabc"); + ASSERT_STR_EQ("xyzabcdabc", (text = string_replace("a", "xyza", text))); + + free(text); + PASS(); +} + +TEST test_string_append(void) +{ + SKIP(); //TODO: Implement this + PASS(); +} + +TEST test_string_to_argv(void) +{ + char **argv = string_to_argv("argv"); + ASSERT_STR_EQ("argv", argv[0]); + ASSERT_EQ( NULL, argv[1]); + free(argv); + argv = NULL; + + argv = string_to_argv("echo test"); + ASSERT_STR_EQ("echo", argv[0]); + ASSERT_STR_EQ("test", argv[1]); + ASSERT_EQ( NULL, argv[2]); + free(argv); + argv = NULL; + + argv = string_to_argv(""); + ASSERT_EQ( NULL, argv[0]); + free(argv); + + PASS(); +} + +TEST test_string_strip_delimited(void) +{ + char *text = malloc(128 * sizeof(char)); + + strcpy(text, "A string_strip_delimited test"); + string_strip_delimited(text, '<', '>'); + ASSERT_STR_EQ("A string_strip_delimited test", text); + + strcpy(text, "Remove html tags"); + string_strip_delimited(text, '<', '>'); + ASSERT_STR_EQ("Remove html tags", text); + + strcpy(text, "Calls|with|identical|delimiters|are|handled|properly"); + string_strip_delimited(text, '|', '|'); + ASSERT_STR_EQ("Calls", text); + + strcpy(text, ""); + string_strip_delimited(text, '<', '>'); + ASSERT_STR_EQ("", text); + + strcpy(text, "Nothing is done if there are no delimiters in the string"); + string_strip_delimited(text, '<', '>'); + ASSERT_STR_EQ("Nothing is done if there are no delimiters in the string", text); + free(text); PASS(); } @@ -15,5 +127,10 @@ TEST test_string_replace_char(void) SUITE(utils) { RUN_TEST(test_string_replace_char); + RUN_TEST(test_string_replace_all); + RUN_TEST(test_string_replace); + RUN_TEST(test_string_append); + RUN_TEST(test_string_to_argv); + RUN_TEST(test_string_strip_delimited); } /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ From 2d562968c041f16f57bde39fd502cfd837dc4ff0 Mon Sep 17 00:00:00 2001 From: Eizen Date: Tue, 22 Nov 2016 15:22:28 -0300 Subject: [PATCH 46/72] Fix raw data when icon position is off and uninitialized pointer --- src/x.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/x.c b/src/x.c index 11e1765..b1eb8a2 100644 --- a/src/x.c +++ b/src/x.c @@ -320,7 +320,7 @@ static GdkPixbuf *get_pixbuf_from_path(char *icon_path) { GdkPixbuf *pixbuf = NULL; gchar *uri_path = NULL; - if (strlen(icon_path) > 0 && settings.icon_position != icons_off) { + if (strlen(icon_path) > 0) { if (g_str_has_prefix(icon_path, "file://")) { uri_path = g_filename_from_uri(icon_path, NULL, NULL); if (uri_path != NULL) { @@ -365,7 +365,7 @@ static GdkPixbuf *get_pixbuf_from_path(char *icon_path) static GdkPixbuf *get_pixbuf_from_raw_image(const RawImage *raw_image) { - GdkPixbuf *pixbuf; + GdkPixbuf *pixbuf = NULL; pixbuf = gdk_pixbuf_new_from_data(raw_image->data, GDK_COLORSPACE_RGB, @@ -394,9 +394,9 @@ static colored_layout *r_init_shared(cairo_t *c, notification *n) GdkPixbuf *pixbuf = NULL; - if (n->raw_icon) { + if (n->raw_icon && settings.icon_position != icons_off) { pixbuf = get_pixbuf_from_raw_image(n->raw_icon); - } else if (n->icon) { + } else if (n->icon && settings.icon_position != icons_off) { pixbuf = get_pixbuf_from_path(n->icon); } From bae745b1fd70251884338505cc5a4e635f0479d2 Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Sat, 3 Dec 2016 19:16:32 +0200 Subject: [PATCH 47/72] Don't use ini_get_int to get doubles option_get_double used ini_get_int to retrieve values from the config file, changed it to use ini_get_double so that decimal accuracy isn't lost. --- src/option_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/option_parser.c b/src/option_parser.c index ea822a3..3617a89 100644 --- a/src/option_parser.c +++ b/src/option_parser.c @@ -421,7 +421,7 @@ double option_get_double(char *ini_section, char *ini_key, char *cmdline_key, double val = cmdline_get_double(cmdline_key, def, description); if (!str) - return ini_get_int(ini_section, ini_key, def); + return ini_get_double(ini_section, ini_key, def); else return val; } From 9333d68656743e7aab1e302f3330e1d3dedbaaf4 Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Sat, 3 Dec 2016 19:19:10 +0200 Subject: [PATCH 48/72] Use the suite_ prefix for test suites --- test/test.c | 4 ++-- test/utils.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test.c b/test/test.c index 5cfd346..0e22f25 100644 --- a/test/test.c +++ b/test/test.c @@ -1,12 +1,12 @@ #include "greatest.h" -SUITE_EXTERN(utils); +SUITE_EXTERN(suite_utils); GREATEST_MAIN_DEFS(); int main(int argc, char *argv[]) { GREATEST_MAIN_BEGIN(); - RUN_SUITE(utils); + RUN_SUITE(suite_utils); GREATEST_MAIN_END(); } /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/test/utils.c b/test/utils.c index adc9cb7..1b42146 100644 --- a/test/utils.c +++ b/test/utils.c @@ -124,7 +124,7 @@ TEST test_string_strip_delimited(void) PASS(); } -SUITE(utils) +SUITE(suite_utils) { RUN_TEST(test_string_replace_char); RUN_TEST(test_string_replace_all); From b9619a1460f321b46ebd410cc1e99bd44f1eb26a Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Sat, 3 Dec 2016 19:33:40 +0200 Subject: [PATCH 49/72] Add option parser test suite --- test/data/test-ini | 38 ++++++++ test/option_parser.c | 226 +++++++++++++++++++++++++++++++++++++++++++ test/test.c | 2 + 3 files changed, 266 insertions(+) create mode 100644 test/data/test-ini create mode 100644 test/option_parser.c diff --git a/test/data/test-ini b/test/data/test-ini new file mode 100644 index 0000000..4afb1d2 --- /dev/null +++ b/test/data/test-ini @@ -0,0 +1,38 @@ +#General comment +[bool] + booltrue = true #This is a test inline comment + booltrue_capital = TRUE + + #This is a comment + boolfalse = false + boolfalse_capital = FALSE + + boolyes = yes + boolyes_capital = YES + + boolno = no + boolno_capital = NO + + boolbin0 = 0 + boolbin1 = 1 + + boolinvalid = invalidbool + +[string] + simple = A simple string + quoted = "A quoted string" + quoted_with_quotes = "A string "with quotes"" + +[int] + simple = 5 + negative = -10 + decimal = 2.71828 + leading_zeroes = 007 + multi_char = 1024 + +[double] + simple = 1 + decimal = 1.5 + negative = -1.2 + zeroes = 0.005 + long = 3.141592653589793 diff --git a/test/option_parser.c b/test/option_parser.c new file mode 100644 index 0000000..3a44b7a --- /dev/null +++ b/test/option_parser.c @@ -0,0 +1,226 @@ +#include "greatest.h" + +#include +#include + +#include "src/option_parser.h" + +TEST test_next_section(void) +{ + char *section = NULL; + ASSERT_STR_EQ("bool", (section = next_section(section))); + ASSERT_STR_EQ("string", (section = next_section(section))); + ASSERT_STR_EQ("int", (section = next_section(section))); + ASSERT_STR_EQ("double", (section = next_section(section))); + PASS(); +} + +TEST test_ini_get_bool(void) +{ + char *bool_section = "bool"; + ASSERT(ini_get_bool(bool_section, "booltrue", false)); + ASSERT(ini_get_bool(bool_section, "booltrue_capital", false)); + + ASSERT_FALSE(ini_get_bool(bool_section, "boolfalse", true)); + ASSERT_FALSE(ini_get_bool(bool_section, "boolfalse_capital", true)); + + ASSERT(ini_get_bool(bool_section, "boolyes", false)); + ASSERT(ini_get_bool(bool_section, "boolyes_capital", false)); + + ASSERT_FALSE(ini_get_bool(bool_section, "boolno", true)); + ASSERT_FALSE(ini_get_bool(bool_section, "boolno_capital", true)); + + ASSERT(ini_get_bool(bool_section, "boolbin1", false)); + ASSERT_FALSE(ini_get_bool(bool_section, "boolbin0", true)); + + ASSERT_FALSE(ini_get_bool(bool_section, "boolinvalid", false)); + + ASSERT(ini_get_bool(bool_section, "nonexistent", true)); + ASSERT_FALSE(ini_get_bool(bool_section, "nonexistent", false)); + PASS(); +} + +TEST test_ini_get_string(void) +{ + char *string_section = "string"; + ASSERT_STR_EQ("A simple string", ini_get_string(string_section, "simple", "")); + + ASSERT_STR_EQ("A quoted string", ini_get_string(string_section, "quoted", "")); + ASSERT_STR_EQ("A string \"with quotes\"", ini_get_string(string_section, "quoted_with_quotes", "")); + + ASSERT_STR_EQ("default value", ini_get_string(string_section, "nonexistent", "default value")); + + PASS(); +} + +TEST test_ini_get_int(void) +{ + char *int_section = "int"; + + ASSERT_EQ(5, ini_get_int(int_section, "simple", 0)); + ASSERT_EQ(-10, ini_get_int(int_section, "negative", 0)); + ASSERT_EQ(2, ini_get_int(int_section, "decimal", 0)); + ASSERT_EQ(7, ini_get_int(int_section, "leading_zeroes", 0)); + ASSERT_EQ(1024, ini_get_int(int_section, "multi_char", 0)); + + ASSERT_EQ(10, ini_get_int(int_section, "nonexistent", 10)); + PASS(); +} + +TEST test_ini_get_double(void) +{ + char *double_section = "double"; + ASSERT_EQ(1, ini_get_double(double_section, "simple", 0)); + ASSERT_EQ(1.5, ini_get_double(double_section, "decimal", 0)); + ASSERT_EQ(-1.2, ini_get_double(double_section, "negative", 0)); + ASSERT_EQ(0.005, ini_get_double(double_section, "zeroes", 0)); + ASSERT_EQ(3.141592653589793, ini_get_double(double_section, "long", 0)); + + ASSERT_EQ(10.5, ini_get_double(double_section, "nonexistent", 10.5)); + PASS(); +} + +TEST test_cmdline_get_string(void) +{ + ASSERT_STR_EQ("A simple string from the cmdline", cmdline_get_string("-string", "", "")); + ASSERT_STR_EQ("Single_word_string", cmdline_get_string("-str/-s", "", "")); + ASSERT_STR_EQ("Default", cmdline_get_string("-nonexistent", "Default", "")); + PASS(); +} + +TEST test_cmdline_get_int(void) +{ + ASSERT_EQ(3, cmdline_get_int("-int", 0, "")); + ASSERT_EQ(2, cmdline_get_int("-int2/-i", 0, "")); + ASSERT_EQ(-7, cmdline_get_int("-negative", 0, "")); + ASSERT_EQ(4, cmdline_get_int("-zeroes", 0, "")); + ASSERT_EQ(2, cmdline_get_int("-intdecim", 0, "")); + ASSERT_EQ(10, cmdline_get_int("-nonexistent", 10, "")); + PASS(); +} + +TEST test_cmdline_get_double(void) +{ + ASSERT_EQ(2, cmdline_get_double("-simple_double", 0, "")); + ASSERT_EQ(5.2, cmdline_get_double("-double", 0, "")); + ASSERT_EQ(3.14, cmdline_get_double("-nonexistent", 3.14, "")); + PASS(); +} + +TEST test_cmdline_get_bool(void) +{ + ASSERT(cmdline_get_bool("-bool", false, "")); + ASSERT(cmdline_get_bool("-shortbool/-b", false, "")); + ASSERT(cmdline_get_bool("-boolnd/-n", true, "")); + ASSERT_FALSE(cmdline_get_bool("-boolnd/-n", false, "")); + PASS(); +} + +TEST test_cmdline_create_usage(void) +{ + cmdline_get_string("-msgstring/-ms", "", "A string to test usage creation"); + cmdline_get_int("-msgint/-mi", 0, "An int to test usage creation"); + cmdline_get_double("-msgdouble/-md", 0, "A double to test usage creation"); + cmdline_get_bool("-msgbool/-mb", false, "A bool to test usage creation"); + char *usage = cmdline_create_usage(); + ASSERT_FALSE(strstr(usage, "-msgstring/-ms") == NULL); + ASSERT_FALSE(strstr(usage, "A string to test usage creation") == NULL); + ASSERT_FALSE(strstr(usage, "-msgint/-mi") == NULL); + ASSERT_FALSE(strstr(usage, "An int to test usage creation") == NULL); + ASSERT_FALSE(strstr(usage, "-msgdouble/-md") == NULL); + ASSERT_FALSE(strstr(usage, "A double to test usage creation") == NULL); + ASSERT_FALSE(strstr(usage, "-msgbool/-mb") == NULL); + ASSERT_FALSE(strstr(usage, "A bool to test usage creation") == NULL); + free(usage); + PASS(); +} + +TEST test_option_get_string(void) +{ + char *string_section = "string"; + + ASSERT_STR_EQ("A simple string", option_get_string(string_section, "simple", "-nonexistent", "", "")); + ASSERT_STR_EQ("Single_word_string", option_get_string(string_section, "simple", "-str/-s", "", "")); + ASSERT_STR_EQ("A simple string from the cmdline", option_get_string(string_section, "simple", "-string", "", "")); + ASSERT_STR_EQ("A simple string from the cmdline", option_get_string(string_section, "simple", "-string/-s", "", "")); + ASSERT_STR_EQ("Single_word_string", option_get_string(string_section, "simple", "-s", "", "")); + ASSERT_STR_EQ("Default", option_get_string(string_section, "nonexistent", "-nonexistent", "Default", "")); + PASS(); +} + +TEST test_option_get_int(void) +{ + char *int_section = "int"; + ASSERT_EQ(3, option_get_int(int_section, "negative", "-int", 0, "")); + ASSERT_EQ(2, option_get_int(int_section, "simple", "-int2/-i", 0, "")); + ASSERT_EQ(-7, option_get_int(int_section, "decimal", "-negative", 0, "")); + ASSERT_EQ(4, option_get_int(int_section, "simple", "-zeroes", 0, "")); + ASSERT_EQ(2, option_get_int(int_section, "simple", "-intdecim", 0, "")); + + ASSERT_EQ(5, option_get_int(int_section, "simple", "-nonexistent", 0, "")); + ASSERT_EQ(-10, option_get_int(int_section, "negative", "-nonexistent", 0, "")); + ASSERT_EQ(2, option_get_int(int_section, "decimal", "-nonexistent", 0, "")); + ASSERT_EQ(7, option_get_int(int_section, "leading_zeroes", "-nonexistent", 0, "")); + ASSERT_EQ(1024, option_get_int(int_section, "multi_char", "-nonexistent", 0, "")); + + ASSERT_EQ(3, option_get_int(int_section, "nonexistent", "-nonexistent", 3, "")); + PASS(); +} + +TEST test_option_get_double(void) +{ + char *double_section = "double"; + ASSERT_EQ(2, option_get_double(double_section, "simple", "-simple_double", 0, "")); + ASSERT_EQ(5.2, option_get_double(double_section, "simple", "-double", 0, "")); + ASSERT_EQ(0.005, option_get_double(double_section, "zeroes", "-nonexistent", 0, "")); + ASSERT_EQ(10.5, option_get_double(double_section, "nonexistent", "-nonexistent", 10.5, "")); + PASS(); +} + +TEST test_option_get_bool(void) +{ + char *bool_section = "bool"; + ASSERT(option_get_bool(bool_section, "boolfalse", "-bool/-b", false, "")); + ASSERT(option_get_bool(bool_section, "boolbin1", "-nonexistent", false, "")); + ASSERT_FALSE(option_get_bool(bool_section, "boolbin0", "-nonexistent", false, "")); + ASSERT_FALSE(option_get_bool(bool_section, "nonexistent", "-nonexistent", false, "")); + PASS(); +} + +SUITE(suite_option_parser) +{ + FILE *config_file = fopen("data/test-ini", "r"); + if (config_file == NULL) { + fputs("\nTest config file 'data/test-ini' couldn't be opened, failing.\n", stderr); + exit(1); + } + load_ini_file(config_file); + RUN_TEST(test_next_section); + RUN_TEST(test_ini_get_bool); + RUN_TEST(test_ini_get_string); + RUN_TEST(test_ini_get_int); + RUN_TEST(test_ini_get_double); + char cmdline[] = "dunst -bool -b " + "-string \"A simple string from the cmdline\" -s Single_word_string " + "-int 3 -i 2 -negative -7 -zeroes 04 -intdecim 2.5 " + "-simple_double 2 -double 5.2" + ; + int argc; + char **argv; + g_shell_parse_argv(&cmdline[0], &argc, &argv, NULL); + cmdline_load(argc, argv); + RUN_TEST(test_cmdline_get_string); + RUN_TEST(test_cmdline_get_int); + RUN_TEST(test_cmdline_get_double); + RUN_TEST(test_cmdline_get_bool); + RUN_TEST(test_cmdline_create_usage); + + RUN_TEST(test_option_get_string); + RUN_TEST(test_option_get_int); + RUN_TEST(test_option_get_double); + RUN_TEST(test_option_get_bool); + free_ini(); + g_strfreev(argv); + fclose(config_file); +} +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/test/test.c b/test/test.c index 0e22f25..6de63cd 100644 --- a/test/test.c +++ b/test/test.c @@ -1,12 +1,14 @@ #include "greatest.h" SUITE_EXTERN(suite_utils); +SUITE_EXTERN(suite_option_parser); GREATEST_MAIN_DEFS(); int main(int argc, char *argv[]) { GREATEST_MAIN_BEGIN(); RUN_SUITE(suite_utils); + RUN_SUITE(suite_option_parser); GREATEST_MAIN_END(); } /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ From 7f8648742f6c246254cfbad4fe6f37fa3c7689bd Mon Sep 17 00:00:00 2001 From: Eizen Date: Sat, 3 Dec 2016 17:42:17 -0300 Subject: [PATCH 50/72] Fix memory leak Incorrect call to disposal function, cairo_destroy should be used per cairo documentation. --- src/x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x.c b/src/x.c index b1eb8a2..f37e96a 100644 --- a/src/x.c +++ b/src/x.c @@ -300,7 +300,7 @@ static cairo_surface_t *gdk_pixbuf_to_cairo_surface(const GdkPixbuf *pixbuf) cr = cairo_create(icon_surface); gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); cairo_paint(cr); - free(cr); + cairo_destroy(cr); return icon_surface; } From 987ec09decc3e20a1baeb976c8e7980030aa1363 Mon Sep 17 00:00:00 2001 From: Eizen Date: Sat, 3 Dec 2016 17:44:16 -0300 Subject: [PATCH 51/72] Update manpage --- docs/dunst.pod | 243 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 173 insertions(+), 70 deletions(-) diff --git a/docs/dunst.pod b/docs/dunst.pod index 3389f43..a8c379d 100644 --- a/docs/dunst.pod +++ b/docs/dunst.pod @@ -4,9 +4,9 @@ dunst - A customizable and lightweight notification-daemon =head1 SYNOPSIS -dunst [-geometry geom] [-shrink shrink] [-fn font] [-nf/nb/lf/lb/cf/cb color] -[-to/nto/lto/cto secs] [-format fmt] [-key key] [-mod mod] [-mon n] -[-t/title title] [-c/class class] [-v] +dunst [-conf file] [-fn font] [-geometry geom] [-lf/lb/lfr/nf/nb/nfr/cf/cb/cfr color] +[-lto/nto/cto secs] [-lh/nh/sep_height height] [-format fmt] [-follow mode] [-mon n] +[-history_length n] [-t/title title] [-c/class class] [-v] =head1 DESCRIPTION @@ -20,100 +20,202 @@ Dunst is a highly configurable and lightweight notification daemon. display help message. +=item B<-conf/-config file> + +use alternative config file. + =item B<-fn font> -Defines the font or font set used. Optionally set the size as a decimal number after the font name and space. -Multiple font options can be separated with commas. - -=item B<-lb/nb/cb color> - -defines the background color of low/normal/critical messages. - -=item B<-lf/nf/cf color> - -defines the foreground color of low/normal/critical messages. - -=item B<-to secs> - -defines the default timeout. Can be (partially) overridden by -the following options. - -=item B<-lto/nto/cto secs> - -timeouts for low/normal/critical messages. - -=item B<-key key> - -remove notification by pressing key. - -=item B<-all_key key> - -remove all notifications by pressing key. - -=item B<-history_key key> - -redisplay last notification by pressing key. - -=item B<-format fmt> - -defines the format of the message. See FORMAT. - -=item B<-mon n> - -show the notification on monitor n. - -=item B<-follow mode> - -display notifications on focused monitor. Possible options are "mouse" to follow the mouse cursor, "keyboard" to follow the window with the keyboard focus and "none" to disable focus following. "mouse" and "keyboard" overwrite the -mon option. - -=item B<-s> - -sort messages by urgency. - -=item B<-ns> - -don't sort messages by urgency. +Defines the font or font set used. Optionally set the size as a decimal number after the font name and space. +Multiple font options can be separated with commas. =item B<-geometry [{width}]x{height}][+/-{x}+/-{y}]> The geometry of the message window. The height is measured in lines everything else in pixels. If the width is omitted but the height is given ("-geometry x2"), the message window -expands over the whole screen (dmenu-like). -If width is 0, the window expands to the longest +expands over the whole screen (dmenu-like). +If width is 0, the window expands to the longest message displayed. A positive x is measured from the left, a negative from the right side of the screen. Y is measured from the top and down respectively. -see also EXAMPLES show the notification on monitor n. + +=item B<-lf/nf/cf color> + +Defines the foreground color of low/normal/critical messages. + +=item B<-lb/nb/cb color> + +Defines the background color of low/normal/critical messages. + +=item B<-lfr/nfr/cfr color> + +Defines the frame color of low/normal/critical messages. + +=item B<-lto/nto/cto secs> + +Defines timeouts for low/normal/critical messages. + +=item B<-lh/-line_height height> + +Defines the height of a single line in pixel. If the height is smaller than the font height, it will get raised to the font height. + +=item B<-nh/-notification_height height> + +Defines the height of the notification window. + +=item B<-sep_height/-separator_height height> + +Defines the height of the separator line. + +=item B<-format fmt> + +Defines the format of the message. See FORMAT. + +=item B<-follow mode> + +Display notifications on focused monitor. Possible options are "mouse" to follow the mouse cursor, "keyboard" to follow the window +with the keyboard focus and "none" to disable focus following. "mouse" and "keyboard" overwrite the -mon option. + +=item B<-mon n> + +Show the notification on monitor n. + +=item B<-history_length n> + +Max amount of notifications kept in history. =item B<-t/-title title> -Define the title of notification windows spawned by dunst. +Defines the title of notification windows spawned by dunst. =item B<-t/-class class> -Define the class of notification windows spawned by dunst. +Defines the class of notification windows spawned by dunst. + +=item B<-key key> + +Remove notification by pressing key. + +=item B<-all_key key> + +Remove all notifications by pressing key. + +=item B<-history_key key> + +Redisplay last notification by pressing key. + +=item B<-context_key key> + +Shortcut for context menu. + +=item B<-alignment position> + +Defines the align position of notifications to left/center/right. + +=item B<-icon_position position> + +Defines the align position of icons to left/right or off to disable icons. + +=item B<-max_icon_size size> + +Defines the max size for icons to scale. If icon_position is set to off, icons won't be displayed. + +=item B<-icon_folders path> + +Defines the path to the folder with the default icons. + +=item B<-li/ni/ci icon> + +Defines the icon for low/normal/critical messages. + +=item B<-padding pad> + +Defines padding between text and separator. + +=item B<-horizontal_padding pad> + +Defines horizontal padding. + +=item B<-transparency range> + +Defines transparency range between 0-100 + +=item B<-sep_color/-separator_color color> + +Defines color of the separator line. + +=item B<-frame_color color> + +Defines color of the frame around window. + +=item B<-frame_width width> + +Defines width of frame around window. + +=item B<-idle_threshold secs> + +Don't timeout notifications if user is longer idle than threshold. + +=item B<-show_age_threshold secs> + +Show age of message if message is older than show_age_threshold seconds. Set to -1 to disable. + +=item B<-bounce_freq freq> + +The frequency with wich text that is longer than the notification window allows bounces back and forth. + +=item B<-markup> + +Allow markups in notifications/formats. + +=item B<-plain> + +Treat incoming notifications as plain text. + +=item B<-indicate_hidden> + +Show how many notificaitons are hidden. + +=item B<-word_wrap> + +Truncating long lines or do word wrap. + +=item B<-ignore_newline> + +Ignore newline characters in notifications. + +=item B<-stack_duplicates> + +Merge multiple notifications with the same content. + +=item B<-hide_duplicates_count> + +Hide count of the merged notifications with the same content. + +=item B<-sticky_history> + +Don't timeout notifications popped up from history. + +=item B<-show_indicators> + +Show indicators for actions and URLs. + +=item B<-sort> + +Sort messages by urgency. =item B<-shrink> Shrink window if it's smaller than the width. Will be ignored if width is 0. -=item B<-lh/-line_height> height - -The height of a single line in pixel. If the height is smaller than the font height, it will get raised to the font height. - =item B<-print> Print notifications to stdout. This might be useful for logging, setting up rules or using the output in other scripts. =item B<-v/--version> -print version information. - - -=item B<-config file> - -use alternative config file. +Print version information. =item B<-always_run_script> @@ -123,7 +225,8 @@ Always run rule-defined scripts, even if the notification is suppressed with for =head1 FORMAT -fmt is a string containing placeholders. The placeholders will be replaced with the corresponding text, or if the text is not present, nothing. Possible placeholders are: +fmt is a string containing placeholders. +The placeholders will be replaced with the corresponding text, or if the text is not present, nothing. Possible placeholders are: =over 4 From 2fe24975064be41c70063b3a58afcf8ec5789453 Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Sun, 11 Dec 2016 13:23:25 +0200 Subject: [PATCH 52/72] Add the test binary to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ee2a189..5173bcb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ config.h dunst.1 org.knopwob.dunst.service dunstify +test/test From 41d3b61f3c5f2a132957d89b2a1f264aeb87dda4 Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Sun, 11 Dec 2016 13:26:20 +0200 Subject: [PATCH 53/72] Fix compiler warnings when compiling dunstify --- dunstify.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dunstify.c b/dunstify.c index f2f109f..6636a7c 100644 --- a/dunstify.c +++ b/dunstify.c @@ -49,7 +49,7 @@ void print_capabilities(void) GList *caps = notify_get_server_caps(); for (GList *iter = caps; iter; iter = iter->next) { if (strlen(iter->data) > 0) { - g_print("%s\n", iter->data); + g_print("%s\n", (char *)iter->data); } } } @@ -171,7 +171,7 @@ int get_id(NotifyNotification *n) return kn->id; } -int put_id(NotifyNotification *n, guint32 id) +void put_id(NotifyNotification *n, guint32 id) { knickers *kn = n->priv; From ad6557239ad1492824f4cf90e1d5a4c3647fe7fc Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Sun, 11 Dec 2016 13:41:43 +0200 Subject: [PATCH 54/72] Fix incorrect indentation --- src/x.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/x.c b/src/x.c index f37e96a..a5e5c70 100644 --- a/src/x.c +++ b/src/x.c @@ -67,7 +67,7 @@ static color_t x_color_hex_to_double(int hexValue) color.g = ((hexValue >> 8) & 0xFF) / 255.0; color.b = ((hexValue) & 0xFF) / 255.0; - return color; + return color; } static color_t x_string_to_color_t(const char *str) @@ -520,10 +520,10 @@ static GSList *r_create_layouts(cairo_t *c) r_create_layout_from_notification(c, n)); } - if (xmore_is_needed && xctx.geometry.h != 1) { - /* append xmore message as new message */ - layouts = g_slist_append(layouts, - r_create_layout_for_xmore(c, last, qlen)); + if (xmore_is_needed && xctx.geometry.h != 1) { + /* append xmore message as new message */ + layouts = g_slist_append(layouts, + r_create_layout_for_xmore(c, last, qlen)); } return layouts; @@ -706,7 +706,6 @@ static void x_win_move(int width, int height) xctx.window_dim.w = width; } - static void setopacity(Window win, unsigned long opacity) { Atom _NET_WM_WINDOW_OPACITY = @@ -715,12 +714,6 @@ static void setopacity(Window win, unsigned long opacity) PropModeReplace, (unsigned char *)&opacity, 1L); } - - - - - - /* * Returns the modifier which is NumLock. */ @@ -1113,7 +1106,6 @@ void x_setup(void) } - static void x_set_wm(Window win) { From e3cbe3883a4d1be6f58b0ac3bea5e0093c856027 Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Sun, 11 Dec 2016 13:48:12 +0200 Subject: [PATCH 55/72] The manpage should be built to the docs directory In the spirit of keeping everything organised, the compiled docs should be in the same directory as the files used to compile them. --- Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index e297b2f..fe55411 100644 --- a/Makefile +++ b/Makefile @@ -52,12 +52,12 @@ clean-dunstify: rm -f dunstify clean-doc: - rm -f dunst.1 + rm -f docs/dunst.1 clean: clean-dunst clean-dunstify clean-doc test-clean -doc: dunst.1 -dunst.1: docs/dunst.pod +doc: docs/dunst.1 +docs/dunst.1: docs/dunst.pod pod2man --name=dunst -c "Dunst Reference" --section=1 --release=${VERSION} $< > $@ service: @@ -67,7 +67,7 @@ install-dunst: dunst doc mkdir -p ${DESTDIR}${PREFIX}/bin install -m755 dunst ${DESTDIR}${PREFIX}/bin mkdir -p ${DESTDIR}${MANPREFIX}/man1 - install -m644 dunst.1 ${DESTDIR}${MANPREFIX}/man1 + install -m644 docs/dunst.1 ${DESTDIR}${MANPREFIX}/man1 install-doc: mkdir -p ${DESTDIR}${PREFIX}/share/dunst From f54d698cba328f1d9b31425f34c989f9aaa62e7f Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Sun, 11 Dec 2016 14:14:18 +0200 Subject: [PATCH 56/72] Bring default config up to date Some of the settings weren't included in the default config before. --- dunstrc | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/dunstrc b/dunstrc index 61f5540..cd3eb29 100644 --- a/dunstrc +++ b/dunstrc @@ -69,6 +69,12 @@ # screen width minus the width defined in within the geometry option. geometry = "300x5-30+20" + # Define the title of the windows spawned by dunst + title = Dunst + + # Define the class of the windows spawned by dunst + class = Dunst + # Shrink window if it's smaller than the width. Will be ignored if # width is 0. shrink = no @@ -99,6 +105,12 @@ # will be ignored. follow = mouse + # Merge multiple notifications with the same content + stack_duplicates = true + + # Hide count of the merged notifications with the same content + hide_duplicates_count = false + # Should a notification popped up from history be sticky or timeout # as if it would normally do. sticky_history = yes @@ -151,9 +163,15 @@ # Align icons left/right/off icon_position = off + # Scale larger icons down to this size, set to 0 to disable + max_icon_size = 32 + # Paths to default icons. icon_folders = /usr/share/icons/gnome/16x16/status/:/usr/share/icons/gnome/16x16/devices/ + # Always run rule-defined scripts, even if the notification is suppressed + always_run_stript = true + [frame] width = 3 color = "#aaaaaa" @@ -186,18 +204,23 @@ background = "#222222" foreground = "#888888" timeout = 10 + # Icon for notifications with low urgency, uncomment to enable + #icon = /path/to/icon [urgency_normal] background = "#285577" foreground = "#ffffff" timeout = 10 + # Icon for notifications with normal urgency, uncomment to enable + #icon = /path/to/icon [urgency_critical] background = "#900000" foreground = "#ffffff" frame_color = "#ff0000" timeout = 0 - + # Icon for notifications with critical urgency, uncomment to enable + #icon = /path/to/icon # Every section that isn't one of the above is interpreted as a rules to # override settings for certain messages. From a2e0a6efe7adda08e8e1ceb3b7ce5ab712d1574b Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Thu, 15 Dec 2016 18:38:34 +0200 Subject: [PATCH 57/72] Remove whitespace from empty line --- src/notification.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/notification.c b/src/notification.c index 692a88c..61c1b51 100644 --- a/src/notification.c +++ b/src/notification.c @@ -329,7 +329,7 @@ int notification_init(notification * n, int id) if (n->category == NULL) { n->category = ""; } - + rule_apply_all(n); n->urls = notification_extract_markup_urls(&(n->body)); From 187d3f9ab9fb63c212c8960b92f53a03964bfd90 Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Thu, 15 Dec 2016 19:13:08 +0200 Subject: [PATCH 58/72] Invalid boolean values should fall back to the default Previously, an invalid value was always false --- src/option_parser.c | 2 +- test/option_parser.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/option_parser.c b/src/option_parser.c index 3617a89..7b682cd 100644 --- a/src/option_parser.c +++ b/src/option_parser.c @@ -175,7 +175,7 @@ int ini_get_bool(char *section, char *key, int def) case '0': return false; default: - return false; + return def; } } } diff --git a/test/option_parser.c b/test/option_parser.c index 3a44b7a..b45788f 100644 --- a/test/option_parser.c +++ b/test/option_parser.c @@ -33,6 +33,7 @@ TEST test_ini_get_bool(void) ASSERT(ini_get_bool(bool_section, "boolbin1", false)); ASSERT_FALSE(ini_get_bool(bool_section, "boolbin0", true)); + ASSERT(ini_get_bool(bool_section, "boolinvalid", true)); ASSERT_FALSE(ini_get_bool(bool_section, "boolinvalid", false)); ASSERT(ini_get_bool(bool_section, "nonexistent", true)); From 2c93c7a2777f786f2778a0904567a93cc561671b Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 18 Sep 2013 21:08:57 -0400 Subject: [PATCH 59/72] Use the appropriate string search functions instead of strstr everywhere. This mostly means using strchr, but I also found: option_parser.c:load_ini_file: - replace multiple calls to strstr with strpbrk notification.c:notification_init: - replace string_replace in a while loop with a single call to string_replace_char redo string replace all --- dunstify.c | 6 +++--- src/option_parser.c | 14 ++++++-------- src/x.c | 2 +- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/dunstify.c b/dunstify.c index 6636a7c..6ae1788 100644 --- a/dunstify.c +++ b/dunstify.c @@ -199,7 +199,7 @@ void closed(NotifyNotification *n, gpointer foo) void add_action(NotifyNotification *n, char *str) { char *action = str; - char *label = strstr(str, ","); + char *label = strchr(str, ','); if (!label || *(label+1) == '\0') { g_printerr("Malformed action. Excpected \"action,label\", got \"%s\"", str); @@ -215,14 +215,14 @@ void add_action(NotifyNotification *n, char *str) void add_hint(NotifyNotification *n, char *str) { char *type = str; - char *name = strstr(str, ":"); + char *name = strchr(str, ':'); if (!name || *(name+1) == '\0') { g_printerr("Malformed hint. Expected \"type:name:value\", got \"%s\"", str); return; } *name = '\0'; name++; - char *value = strstr(name, ":"); + char *value = strchr(name, ':'); if (!value || *(value+1) == '\0') { g_printerr("Malformed hint. Expected \"type:name:value\", got \"%s\"", str); return; diff --git a/src/option_parser.c b/src/option_parser.c index 7b682cd..48d92e0 100644 --- a/src/option_parser.c +++ b/src/option_parser.c @@ -214,7 +214,7 @@ int load_ini_file(FILE * fp) continue; if (*start == '[') { - char *end = strstr(start + 1, "]"); + char *end = strchr(start + 1, ']'); if (!end) { printf ("Warning: invalid config file at line %d\n", @@ -232,7 +232,7 @@ int load_ini_file(FILE * fp) continue; } - char *equal = strstr(start + 1, "="); + char *equal = strchr(start + 1, '='); if (!equal) { printf("Warning: invalid config file at line %d\n", line_num); @@ -244,9 +244,9 @@ int load_ini_file(FILE * fp) char *key = g_strstrip(start); char *value = g_strstrip(equal + 1); - char *quote = strstr(value, "\""); + char *quote = strchr(value, '"'); if (quote) { - char *closing_quote = strstr(quote + 1, "\""); + char *closing_quote = strchr(quote + 1, '"'); if (!closing_quote) { printf ("Warning: invalid config file at line %d\n", @@ -257,9 +257,7 @@ int load_ini_file(FILE * fp) closing_quote = '\0'; } else { - char *comment = strstr(value, "#"); - if (!comment) - comment = strstr(value, ";"); + char *comment = strpbrk(value, "#;"); if (comment) comment = '\0'; } @@ -291,7 +289,7 @@ int cmdline_find_option(char *key) return -1; } char *key1 = g_strdup(key); - char *key2 = strstr(key1, "/"); + char *key2 = strchr(key1, '/'); if (key2) { *key2 = '\0'; diff --git a/src/x.c b/src/x.c index a5e5c70..4316853 100644 --- a/src/x.c +++ b/src/x.c @@ -1383,7 +1383,7 @@ void x_shortcut_init(keyboard_shortcut * ks) if (str == NULL) die("Unable to allocate memory", EXIT_FAILURE); - while (strstr(str, "+")) { + while (strchr(str, '+')) { char *mod = str; while (*str != '+') str++; From 16256d316e8bbbe13a96fd4bea12229b297f1d94 Mon Sep 17 00:00:00 2001 From: Eizen Date: Sat, 17 Dec 2016 17:25:46 -0300 Subject: [PATCH 60/72] Merge release notes into a single file --- RELEASE_NOTES.1.0.0 => RELEASE_NOTES | 24 ++++++++++++++++++++++++ RELEASE_NOTES.0.4.0 | 17 ----------------- 2 files changed, 24 insertions(+), 17 deletions(-) rename RELEASE_NOTES.1.0.0 => RELEASE_NOTES (70%) delete mode 100644 RELEASE_NOTES.0.4.0 diff --git a/RELEASE_NOTES.1.0.0 b/RELEASE_NOTES similarity index 70% rename from RELEASE_NOTES.1.0.0 rename to RELEASE_NOTES index 8ddc231..47be52d 100644 --- a/RELEASE_NOTES.1.0.0 +++ b/RELEASE_NOTES @@ -1,3 +1,7 @@ +=================================================================================== +Release Notes For v1.0.0 +=================================================================================== + PACKAGE MAINTAINERS: There are new dependencies introduced with this version: *glib @@ -53,3 +57,23 @@ PACKAGE MAINTAINERS: Please don't open bug reports when dunstify doesn't work with your version of libnotify + +=================================================================================== +Release Notes For v0.4.0 +=================================================================================== + +Since dunst has lost its ability to show notifications independend of +dbus/libnotify a long time ago I think it is time that the describtion reflects +that. Even though this breaks the acronym. So if you're a packager please update +the package description to read something like: + +short: +"Dunst - a dmenu-ish notification-daemon" + +long: +"Dunst is a highly configurable and lightweight notification-daemon" + +Release Tarballs are now available at: +http://www.knopwob.org/public/dunst-release/ + +For more information have a look at the CHANGELOG and the new options in dunstrc. diff --git a/RELEASE_NOTES.0.4.0 b/RELEASE_NOTES.0.4.0 deleted file mode 100644 index 3a7a43c..0000000 --- a/RELEASE_NOTES.0.4.0 +++ /dev/null @@ -1,17 +0,0 @@ -Release Notes For v0.4.0 - -Since dunst has lost its ability to show notifications independend of -dbus/libnotify a long time ago I think it is time that the describtion reflects -that. Even though this breaks the acronym. So if you're a packager please update -the package description to read something like: - -short: -"Dunst - a dmenu-ish notification-daemon" - -long: -"Dunst is a highly configurable and lightweight notification-daemon" - -Release Tarballs are now available at: -http://www.knopwob.org/public/dunst-release/ - -For more information have a look at the CHANGELOG and the new options in dunstrc. From 810637b2b6e716c94d9a0c8c783bb10bd85396fa Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Sun, 18 Dec 2016 17:14:02 +0200 Subject: [PATCH 61/72] Fix typos --- docs/dunst.pod | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/dunst.pod b/docs/dunst.pod index a8c379d..ae54efb 100644 --- a/docs/dunst.pod +++ b/docs/dunst.pod @@ -163,7 +163,7 @@ Show age of message if message is older than show_age_threshold seconds. Set to =item B<-bounce_freq freq> -The frequency with wich text that is longer than the notification window allows bounces back and forth. +The frequency with which text that is longer than the notification window allows bounces back and forth. =item B<-markup> @@ -175,7 +175,7 @@ Treat incoming notifications as plain text. =item B<-indicate_hidden> -Show how many notificaitons are hidden. +Show how many notifications are hidden. =item B<-word_wrap> From f32659adb7511d2c3779cfc3ac4c0a71294fc7a6 Mon Sep 17 00:00:00 2001 From: Eizen Date: Wed, 21 Dec 2016 01:57:16 -0300 Subject: [PATCH 62/72] Add systemd service unit to contrib Apply sed to reflect prefix but don't install it and clean service file in makefile. Add service file to gitignore --- .gitignore | 1 + Makefile | 2 ++ contrib/dunst.systemd.service.in | 11 +++++++++++ 3 files changed, 14 insertions(+) create mode 100644 contrib/dunst.systemd.service.in diff --git a/.gitignore b/.gitignore index 5173bcb..ac202f0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,6 @@ vgcore.* config.h dunst.1 org.knopwob.dunst.service +dunst.systemd.service dunstify test/test diff --git a/Makefile b/Makefile index fe55411..4f5ae1e 100644 --- a/Makefile +++ b/Makefile @@ -47,6 +47,7 @@ debug: ${OBJ} clean-dunst: rm -f dunst ${OBJ} main.o rm -f org.knopwob.dunst.service + rm -f dunst.systemd.service clean-dunstify: rm -f dunstify @@ -62,6 +63,7 @@ docs/dunst.1: docs/dunst.pod service: @sed "s|##PREFIX##|$(PREFIX)|" org.knopwob.dunst.service.in > org.knopwob.dunst.service + @sed "s|##PREFIX##|$(PREFIX)|" contrib/dunst.systemd.service.in > dunst.systemd.service install-dunst: dunst doc mkdir -p ${DESTDIR}${PREFIX}/bin diff --git a/contrib/dunst.systemd.service.in b/contrib/dunst.systemd.service.in new file mode 100644 index 0000000..9ece8da --- /dev/null +++ b/contrib/dunst.systemd.service.in @@ -0,0 +1,11 @@ +[Unit] +Description=Dunst notification daemon + +[Service] +Type=simple +ExecStart=##PREFIX##/bin/dunst +Environment=DISPLAY=:0 + +[Install] +WantedBy=multi-user.target + From 6c9de72c7d3b74abb6d34767d854776c63203ba8 Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Thu, 22 Dec 2016 19:09:16 +0200 Subject: [PATCH 63/72] Don't consider notifications duplicate if icon or urgency differ Expand the duplication checking functionality to also check for urgency and icons. If icons are turned off in the settings the icon check is skipped. Icons matching is done based on the given path, if the path differs or an icon name is used for one notification but an absolute path for another, the icons are considered different even if they refer to the same file. --- src/notification.c | 17 +++++++++++------ src/notification.h | 1 + 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/notification.c b/src/notification.c index 61c1b51..6a67381 100644 --- a/src/notification.c +++ b/src/notification.c @@ -143,6 +143,15 @@ int notification_cmp_data(const void *va, const void *vb, void *data) return notification_cmp(va, vb); } +int notification_is_duplicate(const notification *a, const notification *b) +{ + return strcmp(a->appname, b->appname) == 0 + && strcmp(a->summary, b->summary) == 0 + && strcmp(a->body, b->body) == 0 + && (settings.icon_position != icons_off ? strcmp(a->icon, b->icon) == 0 : 1) + && a->urgency == b->urgency; +} + /* * Free the memory used by the given notification. */ @@ -373,9 +382,7 @@ int notification_init(notification * n, int id) for (GList * iter = g_queue_peek_head_link(queue); iter; iter = iter->next) { notification *orig = iter->data; - if (strcmp(orig->appname, n->appname) == 0 - && strcmp(orig->summary, n->summary) == 0 - && strcmp(orig->body, n->body) == 0) { + if (notification_is_duplicate(orig, n)) { /* If the progress differs this was probably intended to replace the notification * but notify-send was used. So don't increment dup_count in this case */ @@ -398,9 +405,7 @@ int notification_init(notification * n, int id) for (GList * iter = g_queue_peek_head_link(displayed); iter; iter = iter->next) { notification *orig = iter->data; - if (strcmp(orig->appname, n->appname) == 0 - && strcmp(orig->summary, n->summary) == 0 - && strcmp(orig->body, n->body) == 0) { + if (notification_is_duplicate(orig, n)) { /* notifications that differ only in progress hints should be expected equal, * but we want the latest message, with the latest hint value */ diff --git a/src/notification.h b/src/notification.h index b15a6ac..5a06d24 100644 --- a/src/notification.h +++ b/src/notification.h @@ -59,6 +59,7 @@ void notification_free(notification * n); int notification_close_by_id(int id, int reason); int notification_cmp(const void *a, const void *b); int notification_cmp_data(const void *a, const void *b, void *data); +int notification_is_duplicate(const notification *a, const notification *b); void notification_run_script(notification * n); int notification_close(notification * n, int reason); void notification_print(notification * n); From de9c52f98f2c9bc9bbb962b6e4c8d60b28954565 Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Thu, 22 Dec 2016 19:38:49 +0200 Subject: [PATCH 64/72] Implement notification_create function notification_create currently simply allocates memory and zeroes it to properly initialise a notification. Since we currently have at least 2 places in the code that create notifications(startup notification in dunst.c and notifications from dbus in dbus.c) the creation should be handled from a central location in case we ever need to change the creation procedure later on. --- src/dbus.c | 2 +- src/dunst.c | 2 +- src/notification.c | 14 ++++++++++++++ src/notification.h | 1 + 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/dbus.c b/src/dbus.c index f05f56e..cf0b33a 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -295,7 +295,7 @@ static void onNotify(GDBusConnection * connection, } } - notification *n = malloc(sizeof(notification)); + notification *n = notification_create(); if(n == NULL) { die("Unable to allocate memory", EXIT_FAILURE); } diff --git a/src/dunst.c b/src/dunst.c index 11d347b..7109064 100644 --- a/src/dunst.c +++ b/src/dunst.c @@ -343,7 +343,7 @@ int dunst_main(int argc, char *argv[]) x_setup(); if (settings.startup_notification) { - notification *n = malloc(sizeof(notification)); + notification *n = notification_create(); if(n == NULL) { die("Unable to allocate memory", EXIT_FAILURE); } diff --git a/src/notification.c b/src/notification.c index 6a67381..7771682 100644 --- a/src/notification.c +++ b/src/notification.c @@ -311,6 +311,20 @@ char *notification_extract_markup_urls(char **str_ptr) { return urls; } +/* + * This is a helper function that allocates, initialises a notification and + * returns a pointer to it. All notifications should be created using this + * function. After setting all the necessary fields(i.e. appname, summary, + * body, icon etc) notification_init should be called to do the actual + * initialisation. + */ +notification *notification_create(void) +{ + notification *n = malloc(sizeof(notification)); + memset(n, 0, sizeof(notification)); + return n; +} + /* * Initialize the given notification and add it to * the queue. Replace notification with id if id > 0. diff --git a/src/notification.h b/src/notification.h index 5a06d24..e6d42dc 100644 --- a/src/notification.h +++ b/src/notification.h @@ -54,6 +54,7 @@ typedef struct _notification { Actions *actions; } notification; +notification *notification_create(void); int notification_init(notification * n, int id); void notification_free(notification * n); int notification_close_by_id(int id, int reason); From 0a0c02021d58735e8b8d80f8e145cf6ac13f0dee Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Thu, 22 Dec 2016 20:00:45 +0200 Subject: [PATCH 65/72] Update functions in dbus.c to use camel_case for consistency --- src/dbus.c | 32 ++++++++++++++++---------------- src/dbus.h | 4 ++-- src/menu.c | 2 +- src/notification.c | 2 +- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/dbus.c b/src/dbus.c index cf0b33a..baa37c9 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -59,18 +59,18 @@ static const char *introspection_xml = " " ""; -static void onGetCapabilities(GDBusConnection * connection, +static void on_get_capabilities(GDBusConnection * connection, const gchar * sender, const GVariant * parameters, GDBusMethodInvocation * invocation); -static void onNotify(GDBusConnection * connection, +static void on_notify(GDBusConnection * connection, const gchar * sender, GVariant * parameters, GDBusMethodInvocation * invocation); -static void onCloseNotification(GDBusConnection * connection, +static void on_close_notification(GDBusConnection * connection, const gchar * sender, GVariant * parameters, GDBusMethodInvocation * invocation); -static void onGetServerInformation(GDBusConnection * connection, +static void on_get_server_information(GDBusConnection * connection, const gchar * sender, const GVariant * parameters, GDBusMethodInvocation * invocation); @@ -85,13 +85,13 @@ void handle_method_call(GDBusConnection * connection, GDBusMethodInvocation * invocation, gpointer user_data) { if (g_strcmp0(method_name, "GetCapabilities") == 0) { - onGetCapabilities(connection, sender, parameters, invocation); + on_get_capabilities(connection, sender, parameters, invocation); } else if (g_strcmp0(method_name, "Notify") == 0) { - onNotify(connection, sender, parameters, invocation); + on_notify(connection, sender, parameters, invocation); } else if (g_strcmp0(method_name, "CloseNotification") == 0) { - onCloseNotification(connection, sender, parameters, invocation); + on_close_notification(connection, sender, parameters, invocation); } else if (g_strcmp0(method_name, "GetServerInformation") == 0) { - onGetServerInformation(connection, sender, parameters, + on_get_server_information(connection, sender, parameters, invocation); } else { printf("WARNING: sender: %s; unknown method_name: %s\n", sender, @@ -99,7 +99,7 @@ void handle_method_call(GDBusConnection * connection, } } -static void onGetCapabilities(GDBusConnection * connection, +static void on_get_capabilities(GDBusConnection * connection, const gchar * sender, const GVariant * parameters, GDBusMethodInvocation * invocation) @@ -119,7 +119,7 @@ static void onGetCapabilities(GDBusConnection * connection, g_variant_unref(value); } -static void onNotify(GDBusConnection * connection, +static void on_notify(GDBusConnection * connection, const gchar * sender, GVariant * parameters, GDBusMethodInvocation * invocation) { @@ -335,7 +335,7 @@ static void onNotify(GDBusConnection * connection, run(NULL); } -static void onCloseNotification(GDBusConnection * connection, +static void on_close_notification(GDBusConnection * connection, const gchar * sender, GVariant * parameters, GDBusMethodInvocation * invocation) @@ -347,7 +347,7 @@ static void onCloseNotification(GDBusConnection * connection, g_dbus_connection_flush(connection, NULL, NULL, NULL); } -static void onGetServerInformation(GDBusConnection * connection, +static void on_get_server_information(GDBusConnection * connection, const gchar * sender, const GVariant * parameters, GDBusMethodInvocation * invocation) @@ -360,10 +360,10 @@ static void onGetServerInformation(GDBusConnection * connection, g_dbus_connection_flush(connection, NULL, NULL, NULL); } -void notificationClosed(notification * n, int reason) +void notification_closed(notification * n, int reason) { if (!dbus_conn) { - printf("DEBUG: notificationClosed but not (yet) connected\n"); + printf("DEBUG: notification_closed but not (yet) connected\n"); return; } @@ -377,12 +377,12 @@ void notificationClosed(notification * n, int reason) "NotificationClosed", body, &err); if (err) { - printf("notificationClosed ERROR\n"); + printf("notification_closed ERROR\n"); } } -void actionInvoked(notification * n, const char *identifier) +void action_invoked(notification * n, const char *identifier) { GVariant *body = g_variant_new("(us)", n->id, identifier); GError *err = NULL; diff --git a/src/dbus.h b/src/dbus.h index a98baed..0d536e6 100644 --- a/src/dbus.h +++ b/src/dbus.h @@ -10,8 +10,8 @@ int initdbus(void); void dbus_tear_down(int id); /* void dbus_poll(int timeout); */ -void notificationClosed(notification * n, int reason); -void actionInvoked(notification * n, const char *identifier); +void notification_closed(notification * n, int reason); +void action_invoked(notification * n, const char *identifier); #endif diff --git a/src/menu.c b/src/menu.c index 44ff6c1..06de61e 100644 --- a/src/menu.c +++ b/src/menu.c @@ -149,7 +149,7 @@ void invoke_action(const char *action) } if (invoked && action_identifier) { - actionInvoked(invoked, action_identifier); + action_invoked(invoked, action_identifier); } } diff --git a/src/notification.c b/src/notification.c index 7771682..b3c956f 100644 --- a/src/notification.c +++ b/src/notification.c @@ -556,7 +556,7 @@ int notification_close_by_id(int id, int reason) } if (reason > 0 && reason < 4 && target != NULL) { - notificationClosed(target, reason); + notification_closed(target, reason); } wake_up(); From 0cb1524cc6b02322ba6120babece3bb18eb0e709 Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Sun, 1 Jan 2017 17:05:25 +0200 Subject: [PATCH 66/72] Don't check return status of notification_create notification_create is guaranteed to return a pointer to a notification, if the memory allocation fails it throws an error and exits the program. --- src/dbus.c | 3 --- src/dunst.c | 3 --- src/notification.c | 1 + 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/dbus.c b/src/dbus.c index baa37c9..2d0f53c 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -296,9 +296,6 @@ static void on_notify(GDBusConnection * connection, } notification *n = notification_create(); - if(n == NULL) { - die("Unable to allocate memory", EXIT_FAILURE); - } n->appname = appname; n->summary = summary; n->body = body; diff --git a/src/dunst.c b/src/dunst.c index 7109064..241524c 100644 --- a/src/dunst.c +++ b/src/dunst.c @@ -344,9 +344,6 @@ int dunst_main(int argc, char *argv[]) if (settings.startup_notification) { notification *n = notification_create(); - if(n == NULL) { - die("Unable to allocate memory", EXIT_FAILURE); - } n->appname = strdup("dunst"); n->summary = strdup("startup"); n->body = strdup("dunst is up and running"); diff --git a/src/notification.c b/src/notification.c index b3c956f..a1e68ec 100644 --- a/src/notification.c +++ b/src/notification.c @@ -321,6 +321,7 @@ char *notification_extract_markup_urls(char **str_ptr) { notification *notification_create(void) { notification *n = malloc(sizeof(notification)); + if(n == NULL) die("Unable to allocate memory", EXIT_FAILURE); memset(n, 0, sizeof(notification)); return n; } From 86fbde2de128b00964ec8a5646a51c2b62a2d6e1 Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Sun, 1 Jan 2017 17:08:10 +0200 Subject: [PATCH 67/72] Implement distclean target distclean target should restore the directory tree to the state it originally before make was invoked. In our case it means calling the clean target to remove the compiled blobs and removing the auto-generated config.h. --- Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Makefile b/Makefile index 4f5ae1e..8fec342 100644 --- a/Makefile +++ b/Makefile @@ -57,6 +57,11 @@ clean-doc: clean: clean-dunst clean-dunstify clean-doc test-clean +distclean: clean clean-config + +clean-config: + rm config.h + doc: docs/dunst.1 docs/dunst.1: docs/dunst.pod pod2man --name=dunst -c "Dunst Reference" --section=1 --release=${VERSION} $< > $@ From c6d783f5e2d1416b77707f43ba0aca083582a14d Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Sun, 1 Jan 2017 17:13:35 +0200 Subject: [PATCH 68/72] Replace null checks with assert calls In my opinion, it's better to crash early when something is wrong than to pretend it never happened. This change will allow us to catch more in the long run. --- src/notification.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/notification.c b/src/notification.c index a1e68ec..f14f080 100644 --- a/src/notification.c +++ b/src/notification.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "dbus.h" #include "x.h" @@ -157,8 +158,7 @@ int notification_is_duplicate(const notification *a, const notification *b) */ void notification_free(notification * n) { - if (n == NULL) - return; + assert(n != NULL); free(n->appname); free(n->summary); free(n->body); @@ -332,8 +332,7 @@ notification *notification_create(void) */ int notification_init(notification * n, int id) { - if (n == NULL) - return -1; + assert(n != NULL); if (strcmp("DUNST_COMMAND_PAUSE", n->summary) == 0) { pause_display = true; @@ -569,8 +568,7 @@ int notification_close_by_id(int id, int reason) */ int notification_close(notification * n, int reason) { - if (n == NULL) - return -1; + assert(n != NULL); return notification_close_by_id(n->id, reason); } From 9ec8dbe5dba14d8bc661303c27b19c84e4a5123f Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Sun, 1 Jan 2017 18:06:27 +0200 Subject: [PATCH 69/72] Initialize null fields with sane defaults in notification_init --- src/notification.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/notification.c b/src/notification.c index f14f080..e1e74d3 100644 --- a/src/notification.c +++ b/src/notification.c @@ -165,9 +165,7 @@ void notification_free(notification * n) free(n->icon); free(n->msg); free(n->dbus_client); - - if (n->category && *n->category != '\0') - g_free(n->category); + g_free(n->category); if (n->text_to_render) g_free(n->text_to_render); @@ -312,11 +310,8 @@ char *notification_extract_markup_urls(char **str_ptr) { } /* - * This is a helper function that allocates, initialises a notification and - * returns a pointer to it. All notifications should be created using this - * function. After setting all the necessary fields(i.e. appname, summary, - * body, icon etc) notification_init should be called to do the actual - * initialisation. + * Create notification struct and initialise everything to NULL, + * this function is guaranteed to return a valid pointer. */ notification *notification_create(void) { @@ -326,14 +321,30 @@ notification *notification_create(void) return n; } +void notification_init_defaults(notification *n) +{ + assert(n != NULL); + if(n->appname == NULL) n->appname = g_strdup("unknown"); + if(n->summary == NULL) n->summary = g_strdup(""); + if(n->body == NULL) n->body = g_strdup(""); + if(n->category == NULL) n->category = g_strdup(""); +} + /* * Initialize the given notification and add it to * the queue. Replace notification with id if id > 0. + * + * n should be a pointer to a notification allocated with + * notification_create, it is undefined behaviour to pass a notification + * allocated some other way. */ int notification_init(notification * n, int id) { assert(n != NULL); + //Prevent undefined behaviour by initialising required fields + notification_init_defaults(n); + if (strcmp("DUNST_COMMAND_PAUSE", n->summary) == 0) { pause_display = true; return 0; @@ -349,10 +360,6 @@ int notification_init(notification * n, int id) n->format = settings.format; - if (n->category == NULL) { - n->category = ""; - } - rule_apply_all(n); n->urls = notification_extract_markup_urls(&(n->body)); From 655abd7cc883adfe35476e987a9a2abc66c78539 Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Sun, 1 Jan 2017 19:37:32 +0200 Subject: [PATCH 70/72] Remove unnecessary notification field initializations Since notification_create was implemented memory is zeroed when a notification is allocated, as such we don't need to manually set things to null. --- src/dunst.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/dunst.c b/src/dunst.c index 241524c..9364a00 100644 --- a/src/dunst.c +++ b/src/dunst.c @@ -352,15 +352,6 @@ int dunst_main(int argc, char *argv[]) n->allow_markup = false; n->plain_text = true; n->urgency = LOW; - n->icon = NULL; - n->raw_icon = NULL; - n->category = NULL; - n->msg = NULL; - n->dbus_client = NULL; - n->color_strings[0] = NULL; - n->color_strings[1] = NULL; - n->actions = NULL; - n->urls = NULL; notification_init(n, 0); } From ae87efc0a279eec4a5893064ecb42e0c847aa7d0 Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Wed, 4 Jan 2017 10:38:34 +0200 Subject: [PATCH 71/72] Fix a few minor issues in the makefile & remove debug target * Fix a bug that would cause distclean to fail if config.h didn't exist * Make sure the options target is run when running make dunst * Remove debug target as the optimization override it was doing was only applied in the linking phase. Optimizations are applied during compilation, not linking, and I don't see any easy way to fix that so let's drop the target entirely. --- Makefile | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 8fec342..05fbe19 100644 --- a/Makefile +++ b/Makefile @@ -33,17 +33,13 @@ config.h: config.def.h @echo creating $@ from $< @cp $< $@ -dunst: ${OBJ} main.o +dunst: options ${OBJ} main.o @echo "${CC} ${CFLAGS} -o $@ ${OBJ} ${LDFLAGS}" @${CC} ${CFLAGS} -o $@ ${OBJ} main.o ${LDFLAGS} dunstify: @${CC} ${CFLAGS} -o $@ dunstify.c -std=c99 $(shell pkg-config --libs --cflags glib-2.0 libnotify) -debug: ${OBJ} - @echo CC -o $@ - @${CC} ${CFLAGS} -O0 -o dunst ${OBJ} ${LDFLAGS} - clean-dunst: rm -f dunst ${OBJ} main.o rm -f org.knopwob.dunst.service @@ -60,7 +56,7 @@ clean: clean-dunst clean-dunstify clean-doc test-clean distclean: clean clean-config clean-config: - rm config.h + rm -f config.h doc: docs/dunst.1 docs/dunst.1: docs/dunst.pod From 2614b4d06e7d3b127d07e74e715042cba8b5cba7 Mon Sep 17 00:00:00 2001 From: Nikos Tsipinakis Date: Wed, 4 Jan 2017 11:13:21 +0200 Subject: [PATCH 72/72] Move functional tests to a different subdirectory --- test/{ => functional-tests}/dunstrc.default | 0 .../dunstrc.ignore_newline | 0 .../dunstrc.ignore_newline_no_wrap | 0 test/{ => functional-tests}/dunstrc.markup | 0 test/{ => functional-tests}/dunstrc.nomarkup | 0 test/{ => functional-tests}/dunstrc.nowrap | 0 .../{ => functional-tests}/dunstrc.run_script | 0 test/{ => functional-tests}/dunstrc.show_age | 0 test/{ => functional-tests}/script_test.sh | 0 test/functional-tests/test.sh | 195 ++++++++++++++++++ test/test.sh | 195 ------------------ 11 files changed, 195 insertions(+), 195 deletions(-) rename test/{ => functional-tests}/dunstrc.default (100%) rename test/{ => functional-tests}/dunstrc.ignore_newline (100%) rename test/{ => functional-tests}/dunstrc.ignore_newline_no_wrap (100%) rename test/{ => functional-tests}/dunstrc.markup (100%) rename test/{ => functional-tests}/dunstrc.nomarkup (100%) rename test/{ => functional-tests}/dunstrc.nowrap (100%) rename test/{ => functional-tests}/dunstrc.run_script (100%) rename test/{ => functional-tests}/dunstrc.show_age (100%) rename test/{ => functional-tests}/script_test.sh (100%) create mode 100755 test/functional-tests/test.sh delete mode 100755 test/test.sh diff --git a/test/dunstrc.default b/test/functional-tests/dunstrc.default similarity index 100% rename from test/dunstrc.default rename to test/functional-tests/dunstrc.default diff --git a/test/dunstrc.ignore_newline b/test/functional-tests/dunstrc.ignore_newline similarity index 100% rename from test/dunstrc.ignore_newline rename to test/functional-tests/dunstrc.ignore_newline diff --git a/test/dunstrc.ignore_newline_no_wrap b/test/functional-tests/dunstrc.ignore_newline_no_wrap similarity index 100% rename from test/dunstrc.ignore_newline_no_wrap rename to test/functional-tests/dunstrc.ignore_newline_no_wrap diff --git a/test/dunstrc.markup b/test/functional-tests/dunstrc.markup similarity index 100% rename from test/dunstrc.markup rename to test/functional-tests/dunstrc.markup diff --git a/test/dunstrc.nomarkup b/test/functional-tests/dunstrc.nomarkup similarity index 100% rename from test/dunstrc.nomarkup rename to test/functional-tests/dunstrc.nomarkup diff --git a/test/dunstrc.nowrap b/test/functional-tests/dunstrc.nowrap similarity index 100% rename from test/dunstrc.nowrap rename to test/functional-tests/dunstrc.nowrap diff --git a/test/dunstrc.run_script b/test/functional-tests/dunstrc.run_script similarity index 100% rename from test/dunstrc.run_script rename to test/functional-tests/dunstrc.run_script diff --git a/test/dunstrc.show_age b/test/functional-tests/dunstrc.show_age similarity index 100% rename from test/dunstrc.show_age rename to test/functional-tests/dunstrc.show_age diff --git a/test/script_test.sh b/test/functional-tests/script_test.sh similarity index 100% rename from test/script_test.sh rename to test/functional-tests/script_test.sh diff --git a/test/functional-tests/test.sh b/test/functional-tests/test.sh new file mode 100755 index 0000000..ae3ca17 --- /dev/null +++ b/test/functional-tests/test.sh @@ -0,0 +1,195 @@ +#!/bin/bash + +function keypress { + echo "press enter to continue..." + read key +} + +function basic_notifications { + ../../dunstify -a "dunst tester" "normal" "italic body" + ../../dunstify -a "dunst tester" -u c "critical" "bold body" + ../../dunstify -a "dunst tester" "long body" "This is a notification with a very long body" + ../../dunstify -a "dunst tester" "duplucate" + ../../dunstify -a "dunst tester" "duplucate" + ../../dunstify -a "dunst tester" "duplucate" + ../../dunstify -a "dunst tester" "url" "www.google.de" + +} + +function show_age { + echo "###################################" + echo "show age" + echo "###################################" + killall dunst + ../../dunst -config dunstrc.show_age & + ../../dunstify -a "dunst tester" -u c "Show Age" "These should print their age after 2 seconds" + basic_notifications + keypress +} + +function run_script { + echo "###################################" + echo "run script" + echo "###################################" + killall dunst + PATH=".:$PATH" ../../dunst -config dunstrc.run_script & + ../../dunstify -a "dunst tester" -u c \ + "Run Script" "After Keypress, 2 other notification should pop up. THis needs notify-send installed" + keypress + ../../dunstify -a "dunst tester" -u c "trigger" "this should trigger a notification" + keypress +} + +function ignore_newline { + echo "###################################" + echo "ignore newline" + echo "###################################" + killall dunst + ../../dunst -config dunstrc.ignore_newline_no_wrap & + ../../dunstify -a "dunst tester" -u c "Ignore Newline No Wrap" "There should be no newline anywhere" + ../../dunstify -a "dunst tester" -u c "Th\nis\n\n\n is\n fu\nll of \n" "\nnew\nlines" + basic_notifications + keypress + + killall dunst + ../../dunst -config dunstrc.ignore_newline & + ../../dunstify -a "dunst tester" -u c "Ignore Newline" \ + "The only newlines you should encounter here are wordwraps. That's why I'm so long." + ../../dunstify -a "dunst tester" -u c "Th\nis\n\n\n is\n fu\nll of \n" "\nnew\nlines" + basic_notifications + keypress +} + +function replace { + echo "###################################" + echo "replace" + echo "###################################" + killall dunst + ../../dunst -config dunstrc.default & + id=$(../../dunstify -a "dunst tester" -p "Replace" "this should get replaces after keypress") + keypress + ../../dunstify -a "dunst tester" -r $id "Success?" "I hope this is not a new notification" + keypress + +} + +function markup { + echo "###################################" + echo "markup" + echo "###################################" + killall dunst + ../../dunst -config dunstrc.markup "200x0+10+10" & + ../../dunstify -a "dunst tester" "Markup Tests" -u "c" + ../../dunstify -a "dunst tester" "bold italic" + ../../dunstify -a "dunst tester" "broken markup" + keypress + + killall dunst + ../../dunst -config dunstrc.nomarkup "200x0+10+10" & + ../../dunstify -a "dunst tester" -u c "NO Markup Tests" + ../../dunstify -a "dunst tester" "bolditalic" + ../../dunstify -a "dunst tester" "broken markup" + keypress + +} + +function corners { + echo "###################################" + echo "corners" + echo "###################################" + killall dunst + ../../dunst -config dunstrc.default -geom "200x0+10+10" & + ../../dunstify -a "dunst tester" -u c "upper left" + basic_notifications + keypress + + killall dunst + ../../dunst -config dunstrc.default -geom "200x0-10+10" & + ../../dunstify -a "dunst tester" -u c "upper right" + basic_notifications + keypress + + killall dunst + ../../dunst -config dunstrc.default -geom "200x0-10-10" & + ../../dunstify -a "dunst tester" -u c "lower right" + basic_notifications + keypress + + killall dunst + ../../dunst -config dunstrc.default -geom "200x0+10-10" & + ../../dunstify -a "dunst tester" -u c "lower left" + basic_notifications + keypress + +} + +function geometry { + echo "###################################" + echo "geometry" + echo "###################################" + killall dunst + ../../dunst -config dunstrc.default -geom "0x0" & + ../../dunstify -a "dunst tester" -u c "0x0" + basic_notifications + keypress + + + killall dunst + ../../dunst -config dunstrc.default -geom "200x0" & + ../../dunstify -a "dunst tester" -u c "200x0" + basic_notifications + keypress + + killall dunst + ../../dunst -config dunstrc.default -geom "200x2" & + ../../dunstify -a "dunst tester" -u c "200x2" + basic_notifications + keypress + + killall dunst + ../../dunst -config dunstrc.default -geom "200x1" & + ../../dunstify -a "dunst tester" -u c "200x1" + basic_notifications + keypress + + killall dunst + ../../dunst -config dunstrc.default -geom "0x1" & + ../../dunstify -a "dunst tester" -u c "0x1" + basic_notifications + keypress + + killall dunst + ../../dunst -config dunstrc.default -geom "-300x1" & + ../../dunstify -a "dunst tester" -u c "-300x1" + basic_notifications + keypress + + killall dunst + ../../dunst -config dunstrc.default -geom "-300x1-20-20" & + ../../dunstify -a "dunst tester" -u c "-300x1-20-20" + basic_notifications + keypress + + killall dunst + ../../dunst -config dunstrc.default -geom "x1" & + ../../dunstify -a "dunst tester" -u c "x1-20-20" "across the screen" + basic_notifications + keypress +} + +if [ -n "$1" ]; then + while [ -n "$1" ]; do + $1 + shift + done +else + geometry + corners + show_age + run_script + ignore_newline + replace + markup +fi + +killall dunst diff --git a/test/test.sh b/test/test.sh deleted file mode 100755 index 7883e1e..0000000 --- a/test/test.sh +++ /dev/null @@ -1,195 +0,0 @@ -#!/bin/bash - -function keypress { - echo "press enter to continue..." - read key -} - -function basic_notifications { - ../dunstify -a "dunst tester" "normal" "italic body" - ../dunstify -a "dunst tester" -u c "critical" "bold body" - ../dunstify -a "dunst tester" "long body" "This is a notification with a very long body" - ../dunstify -a "dunst tester" "duplucate" - ../dunstify -a "dunst tester" "duplucate" - ../dunstify -a "dunst tester" "duplucate" - ../dunstify -a "dunst tester" "url" "www.google.de" - -} - -function show_age { - echo "###################################" - echo "show age" - echo "###################################" - killall dunst - ../dunst -config dunstrc.show_age & - ../dunstify -a "dunst tester" -u c "Show Age" "These should print their age after 2 seconds" - basic_notifications - keypress -} - -function run_script { - echo "###################################" - echo "run script" - echo "###################################" - killall dunst - PATH=".:$PATH" ../dunst -config dunstrc.run_script & - ../dunstify -a "dunst tester" -u c \ - "Run Script" "After Keypress, 2 other notification should pop up. THis needs notify-send installed" - keypress - ../dunstify -a "dunst tester" -u c "trigger" "this should trigger a notification" - keypress -} - -function ignore_newline { - echo "###################################" - echo "ignore newline" - echo "###################################" - killall dunst - ../dunst -config dunstrc.ignore_newline_no_wrap & - ../dunstify -a "dunst tester" -u c "Ignore Newline No Wrap" "There should be no newline anywhere" - ../dunstify -a "dunst tester" -u c "Th\nis\n\n\n is\n fu\nll of \n" "\nnew\nlines" - basic_notifications - keypress - - killall dunst - ../dunst -config dunstrc.ignore_newline & - ../dunstify -a "dunst tester" -u c "Ignore Newline" \ - "The only newlines you should encounter here are wordwraps. That's why I'm so long." - ../dunstify -a "dunst tester" -u c "Th\nis\n\n\n is\n fu\nll of \n" "\nnew\nlines" - basic_notifications - keypress -} - -function replace { - echo "###################################" - echo "replace" - echo "###################################" - killall dunst - ../dunst -config dunstrc.default & - id=$(../dunstify -a "dunst tester" -p "Replace" "this should get replaces after keypress") - keypress - ../dunstify -a "dunst tester" -r $id "Success?" "I hope this is not a new notification" - keypress - -} - -function markup { - echo "###################################" - echo "markup" - echo "###################################" - killall dunst - ../dunst -config dunstrc.markup "200x0+10+10" & - ../dunstify -a "dunst tester" "Markup Tests" -u "c" - ../dunstify -a "dunst tester" "bold italic" - ../dunstify -a "dunst tester" "broken markup" - keypress - - killall dunst - ../dunst -config dunstrc.nomarkup "200x0+10+10" & - ../dunstify -a "dunst tester" -u c "NO Markup Tests" - ../dunstify -a "dunst tester" "bolditalic" - ../dunstify -a "dunst tester" "broken markup" - keypress - -} - -function corners { - echo "###################################" - echo "corners" - echo "###################################" - killall dunst - ../dunst -config dunstrc.default -geom "200x0+10+10" & - ../dunstify -a "dunst tester" -u c "upper left" - basic_notifications - keypress - - killall dunst - ../dunst -config dunstrc.default -geom "200x0-10+10" & - ../dunstify -a "dunst tester" -u c "upper right" - basic_notifications - keypress - - killall dunst - ../dunst -config dunstrc.default -geom "200x0-10-10" & - ../dunstify -a "dunst tester" -u c "lower right" - basic_notifications - keypress - - killall dunst - ../dunst -config dunstrc.default -geom "200x0+10-10" & - ../dunstify -a "dunst tester" -u c "lower left" - basic_notifications - keypress - -} - -function geometry { - echo "###################################" - echo "geometry" - echo "###################################" - killall dunst - ../dunst -config dunstrc.default -geom "0x0" & - ../dunstify -a "dunst tester" -u c "0x0" - basic_notifications - keypress - - - killall dunst - ../dunst -config dunstrc.default -geom "200x0" & - ../dunstify -a "dunst tester" -u c "200x0" - basic_notifications - keypress - - killall dunst - ../dunst -config dunstrc.default -geom "200x2" & - ../dunstify -a "dunst tester" -u c "200x2" - basic_notifications - keypress - - killall dunst - ../dunst -config dunstrc.default -geom "200x1" & - ../dunstify -a "dunst tester" -u c "200x1" - basic_notifications - keypress - - killall dunst - ../dunst -config dunstrc.default -geom "0x1" & - ../dunstify -a "dunst tester" -u c "0x1" - basic_notifications - keypress - - killall dunst - ../dunst -config dunstrc.default -geom "-300x1" & - ../dunstify -a "dunst tester" -u c "-300x1" - basic_notifications - keypress - - killall dunst - ../dunst -config dunstrc.default -geom "-300x1-20-20" & - ../dunstify -a "dunst tester" -u c "-300x1-20-20" - basic_notifications - keypress - - killall dunst - ../dunst -config dunstrc.default -geom "x1" & - ../dunstify -a "dunst tester" -u c "x1-20-20" "across the screen" - basic_notifications - keypress -} - -if [ -n "$1" ]; then - while [ -n "$1" ]; do - $1 - shift - done -else - geometry - corners - show_age - run_script - ignore_newline - replace - markup -fi - -killall dunst