From a7003e3616ecfbe652ac750798cddf7658dcc166 Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Fri, 6 Oct 2017 14:31:55 +0200 Subject: [PATCH 01/14] Refactor: Move queue specific methods to queues.c --- src/dbus.c | 1 + src/dunst.c | 55 ++---------------- src/dunst.h | 6 -- src/menu.c | 1 + src/notification.c | 93 +----------------------------- src/notification.h | 3 - src/queues.c | 137 +++++++++++++++++++++++++++++++++++++++++++++ src/queues.h | 49 ++++++++++++++++ src/x11/x.c | 1 + 9 files changed, 197 insertions(+), 149 deletions(-) create mode 100644 src/queues.c create mode 100644 src/queues.h diff --git a/src/dbus.c b/src/dbus.c index eb387ce..19cf35a 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -8,6 +8,7 @@ #include "dunst.h" #include "notification.h" +#include "queues.h" #include "settings.h" #include "utils.h" diff --git a/src/dunst.c b/src/dunst.c index f4e6349..b1d9696 100644 --- a/src/dunst.c +++ b/src/dunst.c @@ -16,6 +16,7 @@ #include "menu.h" #include "notification.h" #include "option_parser.h" +#include "queues.h" #include "settings.h" #include "x11/x.h" #include "x11/screen.h" @@ -39,14 +40,11 @@ bool pause_display = false; GMainLoop *mainloop = NULL; -/* notification lists */ -GQueue *queue = NULL; /* all new notifications get into here */ -GQueue *displayed = NULL; /* currently displayed notifications */ -GQueue *history = NULL; /* history of displayed notifications */ GSList *rules = NULL; /* misc funtions */ +/*TODO: move to queues.c */ void check_timeouts(void) { /* nothing to do */ @@ -82,6 +80,7 @@ void check_timeouts(void) } } +/*TODO: move to queues.c */ void update_lists() { int limit; @@ -128,47 +127,12 @@ void update_lists() } } -void move_all_to_history() -{ - while (displayed->length > 0) { - notification_close(g_queue_peek_head_link(displayed)->data, 2); - } - - while (queue->length > 0) { - notification_close(g_queue_peek_head_link(queue)->data, 2); - } -} - -void history_pop(void) -{ - if (g_queue_is_empty(history)) - return; - - notification *n = g_queue_pop_tail(history); - n->redisplayed = true; - n->start = 0; - n->timeout = settings.sticky_history ? 0 : n->timeout; - g_queue_push_head(queue, n); - - wake_up(); -} - -void history_push(notification *n) -{ - if (settings.history_length > 0 && history->length >= settings.history_length) { - notification *to_free = g_queue_pop_head(history); - notification_free(to_free); - } - - if (!n->history_ignore) - g_queue_push_tail(history, n); -} - void wake_up(void) { run(NULL); } +/* TODO: move parts to queue.c */ static gint64 get_sleep_time(void) { gint64 time = g_get_monotonic_time(); @@ -264,19 +228,11 @@ gboolean quit_signal(gpointer data) 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); + teardown_queues(); x_free(); } @@ -284,6 +240,7 @@ static void teardown(void) int dunst_main(int argc, char *argv[]) { + /*TODO: move to queues.c */ history = g_queue_new(); displayed = g_queue_new(); queue = g_queue_new(); diff --git a/src/dunst.h b/src/dunst.h index 6982bef..f91d7ba 100644 --- a/src/dunst.h +++ b/src/dunst.h @@ -16,9 +16,6 @@ #define ColFG 1 #define ColBG 0 -extern GQueue *queue; -extern GQueue *displayed; -extern GQueue *history; extern GSList *rules; extern bool pause_display; extern const char *color_strings[3][3]; @@ -30,10 +27,7 @@ void wake_up(void); int dunst_main(int argc, char *argv[]); void check_timeouts(void); -void history_pop(void); -void history_push(notification *n); void usage(int exit_status); -void move_all_to_history(void); void print_version(void); char *extract_urls(const char *str); void context_menu(void); diff --git a/src/menu.c b/src/menu.c index 6bd2940..8ecaffc 100644 --- a/src/menu.c +++ b/src/menu.c @@ -16,6 +16,7 @@ #include "dunst.h" #include "settings.h" #include "notification.h" +#include "queues.h" #include "utils.h" static bool is_initialized = false; diff --git a/src/notification.c b/src/notification.c index ef37eb0..e3c0411 100644 --- a/src/notification.c +++ b/src/notification.c @@ -19,6 +19,7 @@ #include "menu.h" #include "rules.h" #include "settings.h" +#include "queues.h" #include "utils.h" #include "x11/x.h" @@ -430,6 +431,7 @@ int notification_init(notification *n, int id) n->dup_count = 0; + /* TODO: move this to queue.c */ /* check if n is a duplicate */ if (settings.stack_duplicates) { for (GList *iter = g_queue_peek_head_link(queue); iter; @@ -545,97 +547,6 @@ 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 - */ -int notification_close_by_id(int id, int reason) -{ - notification *target = NULL; - - for (GList *iter = g_queue_peek_head_link(displayed); iter; - iter = iter->next) { - notification *n = iter->data; - if (n->id == id) { - g_queue_remove(displayed, n); - history_push(n); - target = n; - break; - } - } - - for (GList *iter = g_queue_peek_head_link(queue); iter; - iter = iter->next) { - notification *n = iter->data; - if (n->id == id) { - g_queue_remove(queue, n); - history_push(n); - target = n; - break; - } - } - - if (reason > 0 && reason < 4 && target != NULL) { - notification_closed(target, reason); - } - - wake_up(); - return reason; -} - -/* - * Close the given notification. SEE notification_close_by_id. - */ -int notification_close(notification *n, int reason) -{ - assert(n != NULL); - return notification_close_by_id(n->id, reason); -} - -/* - * Replace the notification which matches the id field of - * the new notification. The given notification is inserted - * right in the same position as the old notification. - * - * Returns true, if a matching notification has been found - * and is replaced. Else false. - */ -bool notification_replace_by_id(notification *new) -{ - - for (GList *iter = g_queue_peek_head_link(displayed); - iter; - iter = iter->next) { - notification *old = iter->data; - if (old->id == new->id) { - iter->data = new; - new->start = time(NULL); - new->dup_count = old->dup_count; - notification_run_script(new); - history_push(old); - return true; - } - } - - for (GList *iter = g_queue_peek_head_link(queue); - iter; - iter = iter->next) { - notification *old = iter->data; - if (old->id == new->id) { - iter->data = new; - new->dup_count = old->dup_count; - history_push(old); - return true; - } - } - return false; -} - void notification_update_text_to_render(notification *n) { g_free(n->text_to_render); diff --git a/src/notification.h b/src/notification.h index edd051b..d56ef90 100644 --- a/src/notification.h +++ b/src/notification.h @@ -64,13 +64,10 @@ typedef struct _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); -bool notification_replace_by_id(notification *n); 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); void notification_replace_single_field(char **haystack, char **needle, const char *replacement, enum markup_mode markup_mode); void notification_update_text_to_render(notification *n); diff --git a/src/queues.c b/src/queues.c new file mode 100644 index 0000000..a236598 --- /dev/null +++ b/src/queues.c @@ -0,0 +1,137 @@ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ + +#include "queues.h" + +#include +#include + +#include "dbus.h" +#include "dunst.h" +#include "notification.h" +#include "settings.h" + +/* notification lists */ +GQueue *queue = NULL; /* all new notifications get into here */ +GQueue *displayed = NULL; /* currently displayed notifications */ +GQueue *history = NULL; /* history of displayed notifications */ + +bool notification_replace_by_id(notification *new) +{ + + for (GList *iter = g_queue_peek_head_link(displayed); + iter; + iter = iter->next) { + notification *old = iter->data; + if (old->id == new->id) { + iter->data = new; + new->start = time(NULL); + new->dup_count = old->dup_count; + notification_run_script(new); + history_push(old); + return true; + } + } + + for (GList *iter = g_queue_peek_head_link(queue); + iter; + iter = iter->next) { + notification *old = iter->data; + if (old->id == new->id) { + iter->data = new; + new->dup_count = old->dup_count; + history_push(old); + return true; + } + } + return false; +} + +int notification_close_by_id(int id, int reason) +{ + notification *target = NULL; + + for (GList *iter = g_queue_peek_head_link(displayed); iter; + iter = iter->next) { + notification *n = iter->data; + if (n->id == id) { + g_queue_remove(displayed, n); + history_push(n); + target = n; + break; + } + } + + for (GList *iter = g_queue_peek_head_link(queue); iter; + iter = iter->next) { + notification *n = iter->data; + if (n->id == id) { + g_queue_remove(queue, n); + history_push(n); + target = n; + break; + } + } + + if (reason > 0 && reason < 4 && target != NULL) { + notification_closed(target, reason); + } + + wake_up(); + return reason; +} + +int notification_close(notification *n, int reason) +{ + assert(n != NULL); + return notification_close_by_id(n->id, reason); +} + +void move_all_to_history() +{ + while (displayed->length > 0) { + notification_close(g_queue_peek_head_link(displayed)->data, 2); + } + + while (queue->length > 0) { + notification_close(g_queue_peek_head_link(queue)->data, 2); + } +} + +void history_pop(void) +{ + if (g_queue_is_empty(history)) + return; + + notification *n = g_queue_pop_tail(history); + n->redisplayed = true; + n->start = 0; + n->timeout = settings.sticky_history ? 0 : n->timeout; + g_queue_push_head(queue, n); + + wake_up(); +} + +void history_push(notification *n) +{ + if (settings.history_length > 0 && history->length >= settings.history_length) { + notification *to_free = g_queue_pop_head(history); + notification_free(to_free); + } + + if (!n->history_ignore) + g_queue_push_tail(history, n); +} + +static void teardown_notification(gpointer data) +{ + notification *n = data; + notification_free(n); +} + +void teardown_queues(void) +{ + g_queue_free_full(history, teardown_notification); + g_queue_free_full(displayed, teardown_notification); + g_queue_free_full(queue, teardown_notification); +} +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/queues.h b/src/queues.h new file mode 100644 index 0000000..70e031f --- /dev/null +++ b/src/queues.h @@ -0,0 +1,49 @@ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ + +#ifndef DUNST_QUEUE_H +#define DUNST_QUEUE_H + +#include "notification.h" + +extern GQueue *queue; +extern GQueue *displayed; +extern GQueue *history; + +/* + * Replace the notification which matches the id field of + * the new notification. The given notification is inserted + * right in the same position as the old notification. + * + * Returns true, if a matching notification has been found + * and is replaced. Else false. + */ +bool notification_replace_by_id(notification *new); + +/* + * Close the notification that has id. + * + * After closing, call wake_up to remove the notification from UI + * + * 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); + +/* Close the given notification. SEE notification_close_by_id. */ +int notification_close(notification *n, int reason); + +void history_pop(void); +void history_push(notification *n); +void move_all_to_history(void); + +/* + * Remove all notifications from all lists + * and free the notifications + */ +void teardown_queues(void); + +#endif +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/x11/x.c b/src/x11/x.c index ce84229..18899f6 100644 --- a/src/x11/x.c +++ b/src/x11/x.c @@ -29,6 +29,7 @@ #include "src/markup.h" #include "src/notification.h" #include "src/settings.h" +#include "src/queues.h" #include "src/utils.h" #include "screen.h" From 7f335b79d25ee3891df6d0207404d522a050481d Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Fri, 6 Oct 2017 14:50:31 +0200 Subject: [PATCH 02/14] Uncouple dunst.h from queues.c again --- src/dbus.c | 1 + src/queues.c | 4 ---- src/x11/x.c | 8 +++++++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/dbus.c b/src/dbus.c index 19cf35a..fe03902 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -282,6 +282,7 @@ static void on_close_notification(GDBusConnection *connection, guint32 id; g_variant_get(parameters, "(u)", &id); notification_close_by_id(id, 3); + wake_up(); g_dbus_method_invocation_return_value(invocation, NULL); g_dbus_connection_flush(connection, NULL, NULL, NULL); } diff --git a/src/queues.c b/src/queues.c index a236598..163f7d2 100644 --- a/src/queues.c +++ b/src/queues.c @@ -6,7 +6,6 @@ #include #include "dbus.h" -#include "dunst.h" #include "notification.h" #include "settings.h" @@ -76,7 +75,6 @@ int notification_close_by_id(int id, int reason) notification_closed(target, reason); } - wake_up(); return reason; } @@ -107,8 +105,6 @@ void history_pop(void) n->start = 0; n->timeout = settings.sticky_history ? 0 : n->timeout; g_queue_push_head(queue, n); - - wake_up(); } void history_push(notification *n) diff --git a/src/x11/x.c b/src/x11/x.c index 18899f6..587dd2b 100644 --- a/src/x11/x.c +++ b/src/x11/x.c @@ -843,6 +843,7 @@ gboolean x_mainloop_fd_dispatch(GSource *source, GSourceFunc callback, case ButtonRelease: if (ev.xbutton.window == xctx.win) { x_handle_click(ev); + wake_up(); } break; case KeyPress: @@ -855,8 +856,10 @@ gboolean x_mainloop_fd_dispatch(GSource *source, GSourceFunc callback, && settings.close_ks.mask == state) { if (displayed) { notification *n = g_queue_peek_head(displayed); - if (n) + if (n) { notification_close(n, 2); + wake_up(); + } } } if (settings.history_ks.str @@ -864,18 +867,21 @@ gboolean x_mainloop_fd_dispatch(GSource *source, GSourceFunc callback, 0) == settings.history_ks.sym && settings.history_ks.mask == state) { history_pop(); + wake_up(); } if (settings.close_all_ks.str && XLookupKeysym(&ev.xkey, 0) == settings.close_all_ks.sym && settings.close_all_ks.mask == state) { move_all_to_history(); + wake_up(); } if (settings.context_ks.str && XLookupKeysym(&ev.xkey, 0) == settings.context_ks.sym && settings.context_ks.mask == state) { context_menu(); + wake_up(); } break; case FocusIn: From 7110734b6e1defdd880d171ee92fd089d6c5a08f Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Fri, 6 Oct 2017 14:53:04 +0200 Subject: [PATCH 03/14] Move queue initialization to queues.c --- src/dunst.c | 5 +---- src/queues.c | 7 +++++++ src/queues.h | 5 +++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/dunst.c b/src/dunst.c index b1d9696..ef6df80 100644 --- a/src/dunst.c +++ b/src/dunst.c @@ -240,10 +240,7 @@ static void teardown(void) int dunst_main(int argc, char *argv[]) { - /*TODO: move to queues.c */ - history = g_queue_new(); - displayed = g_queue_new(); - queue = g_queue_new(); + queues_init(); cmdline_load(argc, argv); diff --git a/src/queues.c b/src/queues.c index 163f7d2..e1f1a26 100644 --- a/src/queues.c +++ b/src/queues.c @@ -14,6 +14,13 @@ GQueue *queue = NULL; /* all new notifications get into here */ GQueue *displayed = NULL; /* currently displayed notifications */ GQueue *history = NULL; /* history of displayed notifications */ +void queues_init(void) +{ + history = g_queue_new(); + displayed = g_queue_new(); + queue = g_queue_new(); +} + bool notification_replace_by_id(notification *new) { diff --git a/src/queues.h b/src/queues.h index 70e031f..6440e5d 100644 --- a/src/queues.h +++ b/src/queues.h @@ -9,6 +9,11 @@ extern GQueue *queue; extern GQueue *displayed; extern GQueue *history; +/* + * Initialise neccessary queues + */ +void queues_init(void); + /* * Replace the notification which matches the id field of * the new notification. The given notification is inserted From af9f6b8b7d89208189ce374f11ba92668378af87 Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Fri, 6 Oct 2017 16:31:15 +0200 Subject: [PATCH 04/14] Move maximum notification display count to x11 Decouple the x11 stuff from dunst.c, to be able to push update_lists to queues.c in the next commit --- src/dunst.c | 14 +------------- src/queues.c | 7 +++++++ src/queues.h | 7 +++++++ src/x11/x.c | 11 +++++++++++ 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/dunst.c b/src/dunst.c index ef6df80..16867dc 100644 --- a/src/dunst.c +++ b/src/dunst.c @@ -83,8 +83,6 @@ void check_timeouts(void) /*TODO: move to queues.c */ void update_lists() { - int limit; - check_timeouts(); if (pause_display) { @@ -95,20 +93,10 @@ void update_lists() return; } - if (xctx.geometry.h == 0) { - limit = 0; - } else if (xctx.geometry.h == 1) { - limit = 1; - } else if (settings.indicate_hidden) { - limit = xctx.geometry.h - 1; - } else { - limit = xctx.geometry.h; - } - /* move notifications from queue to displayed */ while (queue->length > 0) { - if (limit > 0 && displayed->length >= limit) { + if (displayed_limit > 0 && displayed->length >= displayed_limit) { /* the list is full */ break; } diff --git a/src/queues.c b/src/queues.c index e1f1a26..41bc922 100644 --- a/src/queues.c +++ b/src/queues.c @@ -14,6 +14,8 @@ GQueue *queue = NULL; /* all new notifications get into here */ GQueue *displayed = NULL; /* currently displayed notifications */ GQueue *history = NULL; /* history of displayed notifications */ +unsigned int displayed_limit = 0; + void queues_init(void) { history = g_queue_new(); @@ -21,6 +23,11 @@ void queues_init(void) queue = g_queue_new(); } +void queues_displayed_limit(unsigned int limit) +{ + displayed_limit = limit; +} + bool notification_replace_by_id(notification *new) { diff --git a/src/queues.h b/src/queues.h index 6440e5d..7b53c58 100644 --- a/src/queues.h +++ b/src/queues.h @@ -8,12 +8,19 @@ extern GQueue *queue; extern GQueue *displayed; extern GQueue *history; +extern unsigned int displayed_limit; /* * Initialise neccessary queues */ void queues_init(void); +/* + * Set maximum notification count to display + * and store in displayed queue + */ +void queues_displayed_limit(unsigned int limit); + /* * Replace the notification which matches the id field of * the new notification. The given notification is inserted diff --git a/src/x11/x.c b/src/x11/x.c index 587dd2b..156bfca 100644 --- a/src/x11/x.c +++ b/src/x11/x.c @@ -1015,6 +1015,17 @@ void x_setup(void) &xctx.geometry.x, &xctx.geometry.y, &xctx.geometry.w, &xctx.geometry.h); + /* calculate maximum notification count and push information to queue */ + if (xctx.geometry.h == 0) { + queues_displayed_limit(0); + } else if (xctx.geometry.h == 1) { + queues_displayed_limit(1); + } else if (settings.indicate_hidden) { + queues_displayed_limit(xctx.geometry.h - 1); + } else { + queues_displayed_limit(xctx.geometry.h); + } + xctx.screensaver_info = XScreenSaverAllocInfo(); init_screens(); From f869175d0dc70cc212390d9f9872694867e98326 Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Sun, 8 Oct 2017 18:30:51 +0200 Subject: [PATCH 05/14] Move id assignment to separate function in queues.c Move all id-changing functions out of notification_init and handle this in queues.c Also use stack_duplicates in combination with replacement of notifications correctly. Fixes #404 (issue not found) --- src/dbus.c | 3 +- src/dunst.c | 4 ++- src/notification.c | 77 ++++--------------------------------------- src/notification.h | 2 +- src/queues.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++ src/queues.h | 11 +++++++ 6 files changed, 104 insertions(+), 74 deletions(-) diff --git a/src/dbus.c b/src/dbus.c index fe03902..79af31c 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -264,7 +264,8 @@ static void on_notify(GDBusConnection *connection, n->color_strings[ColFG] = fgcolor; n->color_strings[ColBG] = bgcolor; - int id = notification_init(n, replaces_id); + notification_init(n); + int id = queues_notification_insert(n, replaces_id); wake_up(); GVariant *reply = g_variant_new("(u)", id); diff --git a/src/dunst.c b/src/dunst.c index 16867dc..6ed9eff 100644 --- a/src/dunst.c +++ b/src/dunst.c @@ -261,7 +261,9 @@ int dunst_main(int argc, char *argv[]) n->timeout = 10 * G_USEC_PER_SEC; n->markup = MARKUP_NO; n->urgency = LOW; - notification_init(n, 0); + notification_init(n); + queues_notification_insert(n, 0); + // we do not call wakeup now, wake_up does not work here yet } mainloop = g_main_loop_new(NULL, FALSE); diff --git a/src/notification.c b/src/notification.c index e3c0411..0703377 100644 --- a/src/notification.c +++ b/src/notification.c @@ -23,7 +23,6 @@ #include "utils.h" #include "x11/x.h" -int next_notification_id = 1; /* * print a human readable representation @@ -280,28 +279,28 @@ void notification_init_defaults(notification *n) } /* - * Initialize the given notification and add it to - * the queue. Replace notification with id if id > 0. + * Initialize the given notification * * 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) +void notification_init(notification *n) { assert(n != NULL); //Prevent undefined behaviour by initialising required fields notification_init_defaults(n); + // TODO: this does not belong into notification_init if (strcmp("DUNST_COMMAND_PAUSE", n->summary) == 0) { pause_display = true; - return 0; + return; } if (strcmp("DUNST_COMMAND_RESUME", n->summary) == 0) { pause_display = false; - return 0; + return; } n->script = NULL; @@ -423,65 +422,8 @@ int notification_init(notification *n, int id) n->msg = buffer; } - if (id == 0) { - n->id = ++next_notification_id; - } else { - n->id = id; - } - n->dup_count = 0; - /* TODO: move this to queue.c */ - /* check if n is a duplicate */ - if (settings.stack_duplicates) { - for (GList *iter = g_queue_peek_head_link(queue); iter; - iter = iter->next) { - notification *orig = iter->data; - 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 - */ - if (orig->progress == n->progress) { - orig->dup_count++; - } else { - orig->progress = n->progress; - } - /* notifications that differ only in progress hints should be expected equal, - * but we want the latest message, with the latest hint value - */ - g_free(orig->msg); - orig->msg = g_strdup(n->msg); - notification_free(n); - wake_up(); - return orig->id; - } - } - - for (GList *iter = g_queue_peek_head_link(displayed); iter; - iter = iter->next) { - notification *orig = iter->data; - 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 - */ - g_free(orig->msg); - orig->msg = g_strdup(n->msg); - /* 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 - */ - if (orig->progress == n->progress) { - orig->dup_count++; - } else { - orig->progress = n->progress; - } - orig->start = g_get_monotonic_time(); - notification_free(n); - wake_up(); - return orig->id; - } - } - } - /* urgency > CRIT -> array out of range */ n->urgency = n->urgency > CRIT ? CRIT : n->urgency; @@ -507,15 +449,13 @@ int notification_init(notification *n, int id) n->first_render = true; + /* TODO: this should not be part of notification_init */ if (strlen(n->msg) == 0) { notification_close(n, 2); if (settings.always_run_script) { notification_run_script(n); } printf("skipping notification: %s %s\n", n->body, n->summary); - } else { - if (id == 0 || !notification_replace_by_id(n)) - g_queue_insert_sorted(queue, n, notification_cmp_data, NULL); } char *tmp = g_strconcat(n->summary, " ", n->body, NULL); @@ -540,11 +480,6 @@ int notification_init(notification *n, int id) } g_free(tmp); - - if (settings.print_notifications) - notification_print(n); - - return n->id; } void notification_update_text_to_render(notification *n) diff --git a/src/notification.h b/src/notification.h index d56ef90..e5250c1 100644 --- a/src/notification.h +++ b/src/notification.h @@ -62,7 +62,7 @@ typedef struct _notification { } notification; notification *notification_create(void); -int notification_init(notification *n, int id); +void notification_init(notification *n); void notification_free(notification *n); int notification_cmp(const void *a, const void *b); int notification_cmp_data(const void *a, const void *b, void *data); diff --git a/src/queues.c b/src/queues.c index 41bc922..30b727d 100644 --- a/src/queues.c +++ b/src/queues.c @@ -15,6 +15,9 @@ GQueue *displayed = NULL; /* currently displayed notifications */ GQueue *history = NULL; /* history of displayed notifications */ unsigned int displayed_limit = 0; +int next_notification_id = 1; + +static int queues_stack_duplicate(notification *n); void queues_init(void) { @@ -28,6 +31,84 @@ void queues_displayed_limit(unsigned int limit) displayed_limit = limit; } +int queues_notification_insert(notification *n, int replaces_id) +{ + if (replaces_id == 0) { + + n->id = ++next_notification_id; + + if (settings.stack_duplicates) { + int stacked = queues_stack_duplicate(n); + if (stacked > 0) { + // notification got stacked + return stacked; + } + } + + g_queue_insert_sorted(queue, n, notification_cmp_data, NULL); + + } else { + n->id = replaces_id; + if (!notification_replace_by_id(n)) + g_queue_insert_sorted(queue, n, notification_cmp_data, NULL); + } + + if (settings.print_notifications) + notification_print(n); + + return n->id; +} + +/* + * Replaces duplicate notification and stacks it + * + * Returns the notification id of the stacked notification + * Returns -1 if not notification could be stacked + */ +static int queues_stack_duplicate(notification *n) +{ + for (GList *iter = g_queue_peek_head_link(displayed); iter; + iter = iter->next) { + notification *orig = iter->data; + if (notification_is_duplicate(orig, n)) { + /* If the progress differs, probably notify-send was used to update the notification + * So only count it as a duplicate, if the progress was not the same. + * */ + if (orig->progress == n->progress) { + orig->dup_count++; + } else { + orig->progress = n->progress; + } + orig->start = g_get_monotonic_time(); + g_free(orig->msg); + orig->msg = g_strdup(n->msg); + notification_free(n); + return orig->id; + } + } + + for (GList *iter = g_queue_peek_head_link(queue); iter; + iter = iter->next) { + notification *orig = iter->data; + if (notification_is_duplicate(orig, n)) { + /* If the progress differs, probably notify-send was used to update the notification + * So only count it as a duplicate, if the progress was not the same. + * */ + if (orig->progress == n->progress) { + orig->dup_count++; + } else { + orig->progress = n->progress; + } + g_free(orig->msg); + orig->msg = g_strdup(n->msg); + notification_free(n); + return orig->id; + } + } + + return -1; +} + bool notification_replace_by_id(notification *new) { diff --git a/src/queues.h b/src/queues.h index 7b53c58..f6517e8 100644 --- a/src/queues.h +++ b/src/queues.h @@ -21,6 +21,17 @@ void queues_init(void); */ void queues_displayed_limit(unsigned int limit); +/* + * Insert a fully initialized notification into queues + * Respects stack_duplicates, and notification replacement + * + * If replaces_id != 0, n replaces notification with id replaces_id + * If replaces_id == 0, n gets occupies a new position + * + * Returns the assigned notification id + */ +int queues_notification_insert(notification *n, int replaces_id); + /* * Replace the notification which matches the id field of * the new notification. The given notification is inserted From 3fab4c470b012acc3e6c5d79d9fd5a5dcf7c2b96 Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Thu, 12 Oct 2017 18:29:04 +0200 Subject: [PATCH 06/14] Increment id counter only for displayed notifications Previously for every notification (also stacked ones), a new notification id was used, even if the notification got discarded. --- src/queues.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/queues.c b/src/queues.c index 30b727d..2070bbb 100644 --- a/src/queues.c +++ b/src/queues.c @@ -35,8 +35,6 @@ int queues_notification_insert(notification *n, int replaces_id) { if (replaces_id == 0) { - n->id = ++next_notification_id; - if (settings.stack_duplicates) { int stacked = queues_stack_duplicate(n); if (stacked > 0) { @@ -45,6 +43,8 @@ int queues_notification_insert(notification *n, int replaces_id) } } + n->id = ++next_notification_id; + g_queue_insert_sorted(queue, n, notification_cmp_data, NULL); } else { From 59ac6d0f8898e01e5dc897c7f8c8a6022825b846 Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Sun, 8 Oct 2017 20:01:24 +0200 Subject: [PATCH 07/14] Move get_sleep_time to queues.c --- src/dunst.c | 35 +---------------------------------- src/queues.c | 31 +++++++++++++++++++++++++++++++ src/queues.h | 12 ++++++++++++ 3 files changed, 44 insertions(+), 34 deletions(-) diff --git a/src/dunst.c b/src/dunst.c index 6ed9eff..d32601a 100644 --- a/src/dunst.c +++ b/src/dunst.c @@ -120,39 +120,6 @@ void wake_up(void) run(NULL); } -/* TODO: move parts to queue.c */ -static gint64 get_sleep_time(void) -{ - gint64 time = g_get_monotonic_time(); - gint64 sleep = G_MAXINT64; - - for (GList *iter = g_queue_peek_head_link(displayed); iter; - iter = iter->next) { - notification *n = iter->data; - gint64 ttl = n->timeout - (time - n->start); - - if (n->timeout > 0) { - if (ttl > 0) - sleep = MIN(sleep, ttl); - else - // while we're processing, the notification already timed out - return 0; - } - - if (settings.show_age_threshold >= 0) { - gint64 age = time - n->timestamp; - - if (age > settings.show_age_threshold) - // sleep exactly until the next shift of the second happens - sleep = MIN(sleep, ((G_USEC_PER_SEC) - (age % (G_USEC_PER_SEC)))); - else if (ttl > settings.show_age_threshold) - sleep = MIN(sleep, settings.show_age_threshold); - } - } - - return sleep != G_MAXINT64 ? sleep : -1; -} - gboolean run(void *data) { update_lists(); @@ -177,7 +144,7 @@ gboolean run(void *data) if (xctx.visible) { gint64 now = g_get_monotonic_time(); - gint64 sleep = get_sleep_time(); + gint64 sleep = queues_get_next_datachange(now); gint64 timeout_at = now + sleep; if (sleep >= 0) { diff --git a/src/queues.c b/src/queues.c index 2070bbb..0782835 100644 --- a/src/queues.c +++ b/src/queues.c @@ -213,6 +213,37 @@ void history_push(notification *n) g_queue_push_tail(history, n); } +gint64 queues_get_next_datachange(gint64 time) +{ + gint64 sleep = G_MAXINT64; + + for (GList *iter = g_queue_peek_head_link(displayed); iter; + iter = iter->next) { + notification *n = iter->data; + gint64 ttl = n->timeout - (time - n->start); + + if (n->timeout > 0) { + if (ttl > 0) + sleep = MIN(sleep, ttl); + else + // while we're processing, the notification already timed out + return 0; + } + + if (settings.show_age_threshold >= 0) { + gint64 age = time - n->timestamp; + + if (age > settings.show_age_threshold) + // sleep exactly until the next shift of the second happens + sleep = MIN(sleep, ((G_USEC_PER_SEC) - (age % (G_USEC_PER_SEC)))); + else if (ttl > settings.show_age_threshold) + sleep = MIN(sleep, settings.show_age_threshold); + } + } + + return sleep != G_MAXINT64 ? sleep : -1; +} + static void teardown_notification(gpointer data) { notification *n = data; diff --git a/src/queues.h b/src/queues.h index f6517e8..942d0a0 100644 --- a/src/queues.h +++ b/src/queues.h @@ -62,6 +62,18 @@ void history_pop(void); void history_push(notification *n); void move_all_to_history(void); +/* + * Return the distance to the next event in the queue, + * which forces an update visible to the user + * + * This may be: + * + * - notification hits timeout + * - notification's age second changes + * - notification's age threshold is hit + */ +gint64 queues_get_next_datachange(gint64 time); + /* * Remove all notifications from all lists * and free the notifications From c70da444a9156a4aafe7f2d68749ed91cbe78b7c Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Thu, 12 Oct 2017 21:49:49 +0200 Subject: [PATCH 08/14] Move pause_display to queues.c Hint for dbus.c lines (134,138): pause_display => (displayed->length == 0) --- src/dunst.c | 11 +++++------ src/dunst.h | 1 - src/notification.c | 4 ++-- src/queues.c | 16 ++++++++++++++++ src/queues.h | 11 +++++++++++ 5 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/dunst.c b/src/dunst.c index d32601a..bc0ad0b 100644 --- a/src/dunst.c +++ b/src/dunst.c @@ -36,7 +36,6 @@ typedef struct _x11_source { } x11_source_t; /* index of colors fit to urgency level */ -bool pause_display = false; GMainLoop *mainloop = NULL; @@ -85,7 +84,7 @@ void update_lists() { check_timeouts(); - if (pause_display) { + if (queues_pause_status()) { while (displayed->length > 0) { g_queue_insert_sorted(queue, g_queue_pop_head(displayed), notification_cmp_data, NULL); @@ -130,11 +129,11 @@ gboolean run(void *data) timeout_cnt--; } - if (displayed->length > 0 && !xctx.visible && !pause_display) { + if (displayed->length > 0 && !xctx.visible) { x_win_show(); } - if (xctx.visible && (pause_display || displayed->length == 0)) { + if (xctx.visible && displayed->length == 0) { x_win_hide(); } @@ -162,7 +161,7 @@ gboolean run(void *data) gboolean pause_signal(gpointer data) { - pause_display = true; + queues_pause_on(); wake_up(); return G_SOURCE_CONTINUE; @@ -170,7 +169,7 @@ gboolean pause_signal(gpointer data) gboolean unpause_signal(gpointer data) { - pause_display = false; + queues_pause_off(); wake_up(); return G_SOURCE_CONTINUE; diff --git a/src/dunst.h b/src/dunst.h index f91d7ba..9fa6a7e 100644 --- a/src/dunst.h +++ b/src/dunst.h @@ -17,7 +17,6 @@ #define ColBG 0 extern GSList *rules; -extern bool pause_display; extern const char *color_strings[3][3]; /* return id of notification */ diff --git a/src/notification.c b/src/notification.c index 0703377..a737696 100644 --- a/src/notification.c +++ b/src/notification.c @@ -294,12 +294,12 @@ void notification_init(notification *n) // TODO: this does not belong into notification_init if (strcmp("DUNST_COMMAND_PAUSE", n->summary) == 0) { - pause_display = true; + queues_pause_on(); return; } if (strcmp("DUNST_COMMAND_RESUME", n->summary) == 0) { - pause_display = false; + queues_pause_off(); return; } diff --git a/src/queues.c b/src/queues.c index 0782835..c2df37c 100644 --- a/src/queues.c +++ b/src/queues.c @@ -16,6 +16,7 @@ GQueue *history = NULL; /* history of displayed notifications */ unsigned int displayed_limit = 0; int next_notification_id = 1; +bool pause_displayed = false; static int queues_stack_duplicate(notification *n); @@ -244,6 +245,21 @@ gint64 queues_get_next_datachange(gint64 time) return sleep != G_MAXINT64 ? sleep : -1; } +void queues_pause_on(void) +{ + pause_displayed = true; +} + +void queues_pause_off(void) +{ + pause_displayed = false; +} + +bool queues_pause_status(void) +{ + return pause_displayed; +} + static void teardown_notification(gpointer data) { notification *n = data; diff --git a/src/queues.h b/src/queues.h index 942d0a0..31976d2 100644 --- a/src/queues.h +++ b/src/queues.h @@ -74,6 +74,17 @@ void move_all_to_history(void); */ gint64 queues_get_next_datachange(gint64 time); +/* + * Pause queue-management of dunst + * pause_on = paused (no notifications displayed) + * pause_off = running + * + * Calling update_lists is neccessary + */ +void queues_pause_on(void); +void queues_pause_off(void); +bool queues_pause_status(void); + /* * Remove all notifications from all lists * and free the notifications From 12fa9d6ce14da637ed7f6728c303dd3541ee1701 Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Wed, 11 Oct 2017 00:02:12 +0200 Subject: [PATCH 09/14] Move update_lists and check_timeouts to queues.c Also refactor the names to match the namespace. --- src/dunst.c | 75 +++------------------------------------------------- src/queues.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++ src/queues.h | 12 +++++++++ 3 files changed, 83 insertions(+), 72 deletions(-) diff --git a/src/dunst.c b/src/dunst.c index bc0ad0b..b5b1ddb 100644 --- a/src/dunst.c +++ b/src/dunst.c @@ -43,77 +43,6 @@ GSList *rules = NULL; /* misc funtions */ -/*TODO: move to queues.c */ -void check_timeouts(void) -{ - /* nothing to do */ - if (displayed->length == 0) - return; - - GList *iter = g_queue_peek_head_link(displayed); - while (iter) { - notification *n = iter->data; - - /* - * Update iter to the next item before we either exit the - * current iteration of the loop or potentially delete the - * notification which would invalidate the pointer. - */ - iter = iter->next; - - /* don't timeout when user is idle */ - if (x_is_idle() && !n->transient) { - n->start = g_get_monotonic_time(); - continue; - } - - /* skip hidden and sticky messages */ - if (n->start == 0 || n->timeout == 0) { - continue; - } - - /* remove old message */ - if (g_get_monotonic_time() - n->start > n->timeout) { - notification_close(n, 1); - } - } -} - -/*TODO: move to queues.c */ -void update_lists() -{ - check_timeouts(); - - if (queues_pause_status()) { - while (displayed->length > 0) { - g_queue_insert_sorted(queue, g_queue_pop_head(displayed), - notification_cmp_data, NULL); - } - return; - } - - /* move notifications from queue to displayed */ - while (queue->length > 0) { - - if (displayed_limit > 0 && displayed->length >= displayed_limit) { - /* the list is full */ - break; - } - - notification *n = g_queue_pop_head(queue); - - if (!n) - return; - n->start = g_get_monotonic_time(); - if (!n->redisplayed && n->script) { - notification_run_script(n); - } - - g_queue_insert_sorted(displayed, n, notification_cmp_data, - NULL); - } -} - void wake_up(void) { run(NULL); @@ -121,7 +50,9 @@ void wake_up(void) gboolean run(void *data) { - update_lists(); + queues_check_timeouts(x_is_idle()); + queues_update(); + static int timeout_cnt = 0; static gint64 next_timeout = 0; diff --git a/src/queues.c b/src/queues.c index c2df37c..737fb6e 100644 --- a/src/queues.c +++ b/src/queues.c @@ -214,6 +214,74 @@ void history_push(notification *n) g_queue_push_tail(history, n); } +void queues_check_timeouts(bool idle) +{ + /* nothing to do */ + if (displayed->length == 0) + return; + + GList *iter = g_queue_peek_head_link(displayed); + while (iter) { + notification *n = iter->data; + + /* + * Update iter to the next item before we either exit the + * current iteration of the loop or potentially delete the + * notification which would invalidate the pointer. + */ + iter = iter->next; + + /* don't timeout when user is idle */ + if (idle && !n->transient) { + n->start = g_get_monotonic_time(); + continue; + } + + /* skip hidden and sticky messages */ + if (n->start == 0 || n->timeout == 0) { + continue; + } + + /* remove old message */ + if (g_get_monotonic_time() - n->start > n->timeout) { + notification_close(n, 1); + } + } +} + +void queues_update() +{ + if (pause_displayed) { + while (displayed->length > 0) { + g_queue_insert_sorted( + queue, g_queue_pop_head(displayed), notification_cmp_data, NULL); + } + return; + } + + /* move notifications from queue to displayed */ + while (queue->length > 0) { + + if (displayed_limit > 0 && displayed->length >= displayed_limit) { + /* the list is full */ + break; + } + + notification *n = g_queue_pop_head(queue); + + if (!n) + return; + + n->start = g_get_monotonic_time(); + + if (!n->redisplayed && n->script) { + notification_run_script(n); + } + + g_queue_insert_sorted(displayed, n, notification_cmp_data, NULL); + } +} + gint64 queues_get_next_datachange(gint64 time) { gint64 sleep = G_MAXINT64; diff --git a/src/queues.h b/src/queues.h index 31976d2..0e8f1ad 100644 --- a/src/queues.h +++ b/src/queues.h @@ -62,6 +62,18 @@ void history_pop(void); void history_push(notification *n); void move_all_to_history(void); +/* + * Check timeout of each notification and close it, if neccessary + */ +void queues_check_timeouts(bool idle); + +/* + * Move inserted notifications from waiting queue to displayed queue + * and show them. In displayed queue, the amount of elements is limited + * to the amount set via queues_displayed_limit + */ +void queues_update(); + /* * Return the distance to the next event in the queue, * which forces an update visible to the user From 38e4bbb7bb05f4779fdb89f1b66ae3a530e5e640 Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Wed, 11 Oct 2017 09:55:32 +0200 Subject: [PATCH 10/14] Refactor notification_* functions to match queues namespace --- src/dbus.c | 2 +- src/notification.c | 2 +- src/queues.c | 16 ++++++++-------- src/queues.h | 8 ++++---- src/x11/x.c | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/dbus.c b/src/dbus.c index 79af31c..24cc300 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -282,7 +282,7 @@ static void on_close_notification(GDBusConnection *connection, { guint32 id; g_variant_get(parameters, "(u)", &id); - notification_close_by_id(id, 3); + queues_notification_close_id(id, 3); wake_up(); g_dbus_method_invocation_return_value(invocation, NULL); g_dbus_connection_flush(connection, NULL, NULL, NULL); diff --git a/src/notification.c b/src/notification.c index a737696..d0269c4 100644 --- a/src/notification.c +++ b/src/notification.c @@ -451,7 +451,7 @@ void notification_init(notification *n) /* TODO: this should not be part of notification_init */ if (strlen(n->msg) == 0) { - notification_close(n, 2); + queues_notification_close(n, 2); if (settings.always_run_script) { notification_run_script(n); } diff --git a/src/queues.c b/src/queues.c index 737fb6e..1a0f606 100644 --- a/src/queues.c +++ b/src/queues.c @@ -50,7 +50,7 @@ int queues_notification_insert(notification *n, int replaces_id) } else { n->id = replaces_id; - if (!notification_replace_by_id(n)) + if (!queues_notification_replace_id(n)) g_queue_insert_sorted(queue, n, notification_cmp_data, NULL); } @@ -110,7 +110,7 @@ static int queues_stack_duplicate(notification *n) return -1; } -bool notification_replace_by_id(notification *new) +bool queues_notification_replace_id(notification *new) { for (GList *iter = g_queue_peek_head_link(displayed); @@ -141,7 +141,7 @@ bool notification_replace_by_id(notification *new) return false; } -int notification_close_by_id(int id, int reason) +int queues_notification_close_id(int id, int reason) { notification *target = NULL; @@ -174,20 +174,20 @@ int notification_close_by_id(int id, int reason) return reason; } -int notification_close(notification *n, int reason) +int queues_notification_close(notification *n, int reason) { assert(n != NULL); - return notification_close_by_id(n->id, reason); + return queues_notification_close_id(n->id, reason); } void move_all_to_history() { while (displayed->length > 0) { - notification_close(g_queue_peek_head_link(displayed)->data, 2); + queues_notification_close(g_queue_peek_head_link(displayed)->data, 2); } while (queue->length > 0) { - notification_close(g_queue_peek_head_link(queue)->data, 2); + queues_notification_close(g_queue_peek_head_link(queue)->data, 2); } } @@ -244,7 +244,7 @@ void queues_check_timeouts(bool idle) /* remove old message */ if (g_get_monotonic_time() - n->start > n->timeout) { - notification_close(n, 1); + queues_notification_close(n, 1); } } } diff --git a/src/queues.h b/src/queues.h index 0e8f1ad..14e9eb6 100644 --- a/src/queues.h +++ b/src/queues.h @@ -40,7 +40,7 @@ int queues_notification_insert(notification *n, int replaces_id); * Returns true, if a matching notification has been found * and is replaced. Else false. */ -bool notification_replace_by_id(notification *new); +bool queues_notification_replace_id(notification *new); /* * Close the notification that has id. @@ -53,10 +53,10 @@ bool notification_replace_by_id(notification *new); * 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); +int queues_notification_close_id(int id, int reason); -/* Close the given notification. SEE notification_close_by_id. */ -int notification_close(notification *n, int reason); +/* Close the given notification. SEE queues_notification_close_id. */ +int queues_notification_close(notification *n, int reason); void history_pop(void); void history_push(notification *n); diff --git a/src/x11/x.c b/src/x11/x.c index 156bfca..686334a 100644 --- a/src/x11/x.c +++ b/src/x11/x.c @@ -857,7 +857,7 @@ gboolean x_mainloop_fd_dispatch(GSource *source, GSourceFunc callback, if (displayed) { notification *n = g_queue_peek_head(displayed); if (n) { - notification_close(n, 2); + queues_notification_close(n, 2); wake_up(); } } @@ -939,7 +939,7 @@ static void x_handle_click(XEvent ev) if (n) { if (ev.xbutton.button == Button1) - notification_close(n, 2); + queues_notification_close(n, 2); else notification_do_action(n); } From e3881766c0b07e6a223ff79259e3e9abd14835fe Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Wed, 11 Oct 2017 12:07:06 +0200 Subject: [PATCH 11/14] Refactor history_* functions to match queues namespace --- src/queues.c | 34 +++++++++++++++++----------------- src/queues.h | 19 ++++++++++++++++--- src/x11/x.c | 6 +++--- 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/queues.c b/src/queues.c index 1a0f606..5bf8040 100644 --- a/src/queues.c +++ b/src/queues.c @@ -122,7 +122,7 @@ bool queues_notification_replace_id(notification *new) new->start = time(NULL); new->dup_count = old->dup_count; notification_run_script(new); - history_push(old); + queues_history_push(old); return true; } } @@ -134,7 +134,7 @@ bool queues_notification_replace_id(notification *new) if (old->id == new->id) { iter->data = new; new->dup_count = old->dup_count; - history_push(old); + queues_history_push(old); return true; } } @@ -150,7 +150,7 @@ int queues_notification_close_id(int id, int reason) notification *n = iter->data; if (n->id == id) { g_queue_remove(displayed, n); - history_push(n); + queues_history_push(n); target = n; break; } @@ -161,7 +161,7 @@ int queues_notification_close_id(int id, int reason) notification *n = iter->data; if (n->id == id) { g_queue_remove(queue, n); - history_push(n); + queues_history_push(n); target = n; break; } @@ -180,18 +180,7 @@ int queues_notification_close(notification *n, int reason) return queues_notification_close_id(n->id, reason); } -void move_all_to_history() -{ - while (displayed->length > 0) { - queues_notification_close(g_queue_peek_head_link(displayed)->data, 2); - } - - while (queue->length > 0) { - queues_notification_close(g_queue_peek_head_link(queue)->data, 2); - } -} - -void history_pop(void) +void queues_history_pop(void) { if (g_queue_is_empty(history)) return; @@ -203,7 +192,7 @@ void history_pop(void) g_queue_push_head(queue, n); } -void history_push(notification *n) +void queues_history_push(notification *n) { if (settings.history_length > 0 && history->length >= settings.history_length) { notification *to_free = g_queue_pop_head(history); @@ -214,6 +203,17 @@ void history_push(notification *n) g_queue_push_tail(history, n); } +void queues_history_push_all(void) +{ + while (displayed->length > 0) { + queues_notification_close(g_queue_peek_head_link(displayed)->data, 2); + } + + while (queue->length > 0) { + queues_notification_close(g_queue_peek_head_link(queue)->data, 2); + } +} + void queues_check_timeouts(bool idle) { /* nothing to do */ diff --git a/src/queues.h b/src/queues.h index 14e9eb6..e0605ec 100644 --- a/src/queues.h +++ b/src/queues.h @@ -58,9 +58,22 @@ int queues_notification_close_id(int id, int reason); /* Close the given notification. SEE queues_notification_close_id. */ int queues_notification_close(notification *n, int reason); -void history_pop(void); -void history_push(notification *n); -void move_all_to_history(void); +/* + * Pushed the latest notification of history to the displayed queue + * and removes it from history + */ +void queues_history_pop(void); + +/* + * Push a single notification to history + * The given notification has to be removed its queue + */ +void queues_history_push(notification *n); + +/* + * Push all waiting and displayed notifications to history + */ +void queues_history_push_all(void); /* * Check timeout of each notification and close it, if neccessary diff --git a/src/x11/x.c b/src/x11/x.c index 686334a..be3b0f3 100644 --- a/src/x11/x.c +++ b/src/x11/x.c @@ -866,14 +866,14 @@ gboolean x_mainloop_fd_dispatch(GSource *source, GSourceFunc callback, && XLookupKeysym(&ev.xkey, 0) == settings.history_ks.sym && settings.history_ks.mask == state) { - history_pop(); + queues_history_pop(); wake_up(); } if (settings.close_all_ks.str && XLookupKeysym(&ev.xkey, 0) == settings.close_all_ks.sym && settings.close_all_ks.mask == state) { - move_all_to_history(); + queues_history_push_all(); wake_up(); } if (settings.context_ks.str @@ -917,7 +917,7 @@ bool x_is_idle(void) static void x_handle_click(XEvent ev) { if (ev.xbutton.button == Button3) { - move_all_to_history(); + queues_history_push_all(); return; } From a536e3f60bac9359eb1338a90e2575490d7844ac Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Wed, 11 Oct 2017 12:25:30 +0200 Subject: [PATCH 12/14] Force management of queues to queues.c --- src/dunst.c | 4 ++-- src/menu.c | 4 ++-- src/queues.c | 24 +++++++++++++++++++++--- src/queues.h | 25 ++++++++++++++++++------- src/x11/x.c | 18 ++++++++---------- 5 files changed, 51 insertions(+), 24 deletions(-) diff --git a/src/dunst.c b/src/dunst.c index b5b1ddb..56f4213 100644 --- a/src/dunst.c +++ b/src/dunst.c @@ -60,11 +60,11 @@ gboolean run(void *data) timeout_cnt--; } - if (displayed->length > 0 && !xctx.visible) { + if (queues_length_displayed() > 0 && !xctx.visible) { x_win_show(); } - if (xctx.visible && displayed->length == 0) { + if (xctx.visible && queues_length_displayed() == 0) { x_win_hide(); } diff --git a/src/menu.c b/src/menu.c index 8ecaffc..6344c55 100644 --- a/src/menu.c +++ b/src/menu.c @@ -137,7 +137,7 @@ void invoke_action(const char *action) int appname_len = strlen(appname_begin) - 1; // remove ] int action_len = strlen(action) - appname_len - 3; // remove space, [, ] - for (GList *iter = g_queue_peek_head_link(displayed); iter; + for (const GList *iter = queues_get_displayed(); iter; iter = iter->next) { notification *n = iter->data; if (g_str_has_prefix(appname_begin, n->appname) && strlen(n->appname) == appname_len) { @@ -189,7 +189,7 @@ void context_menu(void) } char *dmenu_input = NULL; - for (GList *iter = g_queue_peek_head_link(displayed); iter; + for (const GList *iter = queues_get_displayed(); iter; iter = iter->next) { notification *n = iter->data; diff --git a/src/queues.c b/src/queues.c index 5bf8040..b8d251f 100644 --- a/src/queues.c +++ b/src/queues.c @@ -10,9 +10,9 @@ #include "settings.h" /* notification lists */ -GQueue *queue = NULL; /* all new notifications get into here */ -GQueue *displayed = NULL; /* currently displayed notifications */ -GQueue *history = NULL; /* history of displayed notifications */ +static GQueue *queue = NULL; /* all new notifications get into here */ +static GQueue *displayed = NULL; /* currently displayed notifications */ +static GQueue *history = NULL; /* history of displayed notifications */ unsigned int displayed_limit = 0; int next_notification_id = 1; @@ -32,6 +32,24 @@ void queues_displayed_limit(unsigned int limit) displayed_limit = limit; } +/* misc getter functions */ +const GList *queues_get_displayed() +{ + return g_queue_peek_head_link(displayed); +} +unsigned int queues_length_waiting() +{ + return queue->length; +} +unsigned int queues_length_displayed() +{ + return displayed->length; +} +unsigned int queues_length_history() +{ + return history->length; +} + int queues_notification_insert(notification *n, int replaces_id) { if (replaces_id == 0) { diff --git a/src/queues.h b/src/queues.h index e0605ec..698eccf 100644 --- a/src/queues.h +++ b/src/queues.h @@ -5,11 +5,6 @@ #include "notification.h" -extern GQueue *queue; -extern GQueue *displayed; -extern GQueue *history; -extern unsigned int displayed_limit; - /* * Initialise neccessary queues */ @@ -21,6 +16,19 @@ void queues_init(void); */ void queues_displayed_limit(unsigned int limit); +/* + * Return read only list of notifications + */ +const GList *queues_get_displayed(); + +/* + * Returns the current amount of notifications, + * which are shown, waiting or already in history + */ +unsigned int queues_length_waiting(); +unsigned int queues_length_displayed(); +unsigned int queues_length_history(); + /* * Insert a fully initialized notification into queues * Respects stack_duplicates, and notification replacement @@ -43,9 +51,12 @@ int queues_notification_insert(notification *n, int replaces_id); bool queues_notification_replace_id(notification *new); /* - * Close the notification that has id. + * Close the notification that has n->id == id * - * After closing, call wake_up to remove the notification from UI + * Sends a signal and pushes it automatically to history. + * + * After closing, call wake_up to synchronize the queues with the UI + * (which closes the notification on screen) * * reasons: * -1 -> notification is a replacement, no NotificationClosed signal emitted diff --git a/src/x11/x.c b/src/x11/x.c index be3b0f3..3647222 100644 --- a/src/x11/x.c +++ b/src/x11/x.c @@ -533,11 +533,11 @@ static GSList *r_create_layouts(cairo_t *c) { GSList *layouts = NULL; - int qlen = g_list_length(g_queue_peek_head_link(queue)); + int qlen = queues_length_waiting(); bool xmore_is_needed = qlen > 0 && settings.indicate_hidden; notification *last = NULL; - for (GList *iter = g_queue_peek_head_link(displayed); + for (const GList *iter = queues_get_displayed(); iter; iter = iter->next) { notification *n = iter->data; @@ -854,12 +854,10 @@ gboolean x_mainloop_fd_dispatch(GSource *source, GSourceFunc callback, && XLookupKeysym(&ev.xkey, 0) == settings.close_ks.sym && settings.close_ks.mask == state) { - if (displayed) { - notification *n = g_queue_peek_head(displayed); - if (n) { - queues_notification_close(n, 2); - wake_up(); - } + const GList *displayed = queues_get_displayed(); + if (displayed && displayed->data) { + queues_notification_close(displayed->data, 2); + wake_up(); } } if (settings.history_ks.str @@ -926,7 +924,7 @@ static void x_handle_click(XEvent ev) int y = settings.separator_height; notification *n = NULL; int first = true; - for (GList *iter = g_queue_peek_head_link(displayed); iter; + for (const GList *iter = queues_get_displayed(); iter; iter = iter->next) { n = iter->data; if (ev.xbutton.y > y && ev.xbutton.y < y + n->displayed_height) @@ -1127,7 +1125,7 @@ static void x_win_setup(void) void x_win_show(void) { /* window is already mapped or there's nothing to show */ - if (xctx.visible || g_queue_is_empty(displayed)) { + if (xctx.visible || queues_length_displayed() == 0) { return; } From 616b8a1758442621a00ce0b16f90e7d42906183a Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Wed, 11 Oct 2017 12:30:53 +0200 Subject: [PATCH 13/14] Rename queue to waiting This gives all three queues unique names makes it easier to trace back, which queue should hold which notifications. --- src/queues.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/queues.c b/src/queues.c index b8d251f..9b0a5b7 100644 --- a/src/queues.c +++ b/src/queues.c @@ -10,7 +10,7 @@ #include "settings.h" /* notification lists */ -static GQueue *queue = NULL; /* all new notifications get into here */ +static GQueue *waiting = NULL; /* all new notifications get into here */ static GQueue *displayed = NULL; /* currently displayed notifications */ static GQueue *history = NULL; /* history of displayed notifications */ @@ -24,7 +24,7 @@ void queues_init(void) { history = g_queue_new(); displayed = g_queue_new(); - queue = g_queue_new(); + waiting = g_queue_new(); } void queues_displayed_limit(unsigned int limit) @@ -39,7 +39,7 @@ const GList *queues_get_displayed() } unsigned int queues_length_waiting() { - return queue->length; + return waiting->length; } unsigned int queues_length_displayed() { @@ -64,12 +64,12 @@ int queues_notification_insert(notification *n, int replaces_id) n->id = ++next_notification_id; - g_queue_insert_sorted(queue, n, notification_cmp_data, NULL); + g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL); } else { n->id = replaces_id; if (!queues_notification_replace_id(n)) - g_queue_insert_sorted(queue, n, notification_cmp_data, NULL); + g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL); } if (settings.print_notifications) @@ -106,7 +106,7 @@ static int queues_stack_duplicate(notification *n) } } - for (GList *iter = g_queue_peek_head_link(queue); iter; + for (GList *iter = g_queue_peek_head_link(waiting); iter; iter = iter->next) { notification *orig = iter->data; if (notification_is_duplicate(orig, n)) { @@ -145,7 +145,7 @@ bool queues_notification_replace_id(notification *new) } } - for (GList *iter = g_queue_peek_head_link(queue); + for (GList *iter = g_queue_peek_head_link(waiting); iter; iter = iter->next) { notification *old = iter->data; @@ -174,11 +174,11 @@ int queues_notification_close_id(int id, int reason) } } - for (GList *iter = g_queue_peek_head_link(queue); iter; + for (GList *iter = g_queue_peek_head_link(waiting); iter; iter = iter->next) { notification *n = iter->data; if (n->id == id) { - g_queue_remove(queue, n); + g_queue_remove(waiting, n); queues_history_push(n); target = n; break; @@ -207,7 +207,7 @@ void queues_history_pop(void) n->redisplayed = true; n->start = 0; n->timeout = settings.sticky_history ? 0 : n->timeout; - g_queue_push_head(queue, n); + g_queue_push_head(waiting, n); } void queues_history_push(notification *n) @@ -227,8 +227,8 @@ void queues_history_push_all(void) queues_notification_close(g_queue_peek_head_link(displayed)->data, 2); } - while (queue->length > 0) { - queues_notification_close(g_queue_peek_head_link(queue)->data, 2); + while (waiting->length > 0) { + queues_notification_close(g_queue_peek_head_link(waiting)->data, 2); } } @@ -272,20 +272,20 @@ void queues_update() if (pause_displayed) { while (displayed->length > 0) { g_queue_insert_sorted( - queue, g_queue_pop_head(displayed), notification_cmp_data, NULL); + waiting, g_queue_pop_head(displayed), notification_cmp_data, NULL); } return; } /* move notifications from queue to displayed */ - while (queue->length > 0) { + while (waiting->length > 0) { if (displayed_limit > 0 && displayed->length >= displayed_limit) { /* the list is full */ break; } - notification *n = g_queue_pop_head(queue); + notification *n = g_queue_pop_head(waiting); if (!n) return; @@ -356,6 +356,6 @@ void teardown_queues(void) { g_queue_free_full(history, teardown_notification); g_queue_free_full(displayed, teardown_notification); - g_queue_free_full(queue, teardown_notification); + g_queue_free_full(waiting, teardown_notification); } /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ From b57483416e0aea0c8a49a883f77dbcf1db6c2d36 Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Wed, 11 Oct 2017 12:40:58 +0200 Subject: [PATCH 14/14] Remove command handling from notification_init --- src/dbus.c | 9 +++++++-- src/notification.c | 20 -------------------- src/queues.c | 20 ++++++++++++++++++++ src/queues.h | 1 + 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/dbus.c b/src/dbus.c index 24cc300..50cea59 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -266,13 +266,18 @@ static void on_notify(GDBusConnection *connection, notification_init(n); int id = queues_notification_insert(n, replaces_id); - wake_up(); GVariant *reply = g_variant_new("(u)", id); g_dbus_method_invocation_return_value(invocation, reply); g_dbus_connection_flush(connection, NULL, NULL, NULL); - run(NULL); + // The message got discarded + if (id == 0) { + notification_closed(n, 2); + notification_free(n); + } + + wake_up(); } static void on_close_notification(GDBusConnection *connection, diff --git a/src/notification.c b/src/notification.c index d0269c4..145e0c4 100644 --- a/src/notification.c +++ b/src/notification.c @@ -292,17 +292,6 @@ void notification_init(notification *n) //Prevent undefined behaviour by initialising required fields notification_init_defaults(n); - // TODO: this does not belong into notification_init - if (strcmp("DUNST_COMMAND_PAUSE", n->summary) == 0) { - queues_pause_on(); - return; - } - - if (strcmp("DUNST_COMMAND_RESUME", n->summary) == 0) { - queues_pause_off(); - return; - } - n->script = NULL; n->text_to_render = NULL; @@ -449,15 +438,6 @@ void notification_init(notification *n) n->first_render = true; - /* TODO: this should not be part of notification_init */ - if (strlen(n->msg) == 0) { - queues_notification_close(n, 2); - if (settings.always_run_script) { - notification_run_script(n); - } - printf("skipping notification: %s %s\n", n->body, n->summary); - } - char *tmp = g_strconcat(n->summary, " ", n->body, NULL); char *tmp_urls = extract_urls(tmp); diff --git a/src/queues.c b/src/queues.c index 9b0a5b7..c6316a8 100644 --- a/src/queues.c +++ b/src/queues.c @@ -4,6 +4,8 @@ #include #include +#include +#include #include "dbus.h" #include "notification.h" @@ -52,6 +54,24 @@ unsigned int queues_length_history() int queues_notification_insert(notification *n, int replaces_id) { + /* do not display the message, if the message is empty */ + if (strlen(n->msg) == 0) { + if (settings.always_run_script) { + notification_run_script(n); + } + printf("skipping notification: %s %s\n", n->body, n->summary); + return 0; + } + /* Do not insert the message if it's a command */ + if (strcmp("DUNST_COMMAND_PAUSE", n->summary) == 0) { + pause_displayed = true; + return 0; + } + if (strcmp("DUNST_COMMAND_RESUME", n->summary) == 0) { + pause_displayed = false; + return 0; + } + if (replaces_id == 0) { if (settings.stack_duplicates) { diff --git a/src/queues.h b/src/queues.h index 698eccf..8cec5fc 100644 --- a/src/queues.h +++ b/src/queues.h @@ -37,6 +37,7 @@ unsigned int queues_length_history(); * If replaces_id == 0, n gets occupies a new position * * Returns the assigned notification id + * If returned id == 0, the message was dismissed */ int queues_notification_insert(notification *n, int replaces_id);