commit
						e111f5393e
					
				
							
								
								
									
										16
									
								
								src/dbus.c
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								src/dbus.c
									
									
									
									
									
								
							| @ -8,6 +8,7 @@ | ||||
| 
 | ||||
| #include "dunst.h" | ||||
| #include "notification.h" | ||||
| #include "queues.h" | ||||
| #include "settings.h" | ||||
| #include "utils.h" | ||||
| 
 | ||||
| @ -280,14 +281,20 @@ static void on_notify(GDBusConnection *connection, | ||||
|         n->color_strings[ColFG] = fgcolor; | ||||
|         n->color_strings[ColBG] = bgcolor; | ||||
| 
 | ||||
|         int id = notification_init(n, replaces_id); | ||||
|         wake_up(); | ||||
|         notification_init(n); | ||||
|         int id = queues_notification_insert(n, replaces_id); | ||||
| 
 | ||||
|         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, | ||||
| @ -297,7 +304,8 @@ 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); | ||||
| } | ||||
|  | ||||
							
								
								
									
										187
									
								
								src/dunst.c
									
									
									
									
									
								
							
							
						
						
									
										187
									
								
								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" | ||||
| @ -35,175 +36,23 @@ typedef struct _x11_source { | ||||
| } x11_source_t; | ||||
| 
 | ||||
| /* index of colors fit to urgency level */ | ||||
| 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 */ | ||||
| 
 | ||||
| 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); | ||||
|                 } | ||||
|         } | ||||
| } | ||||
| 
 | ||||
| void update_lists() | ||||
| { | ||||
|         int limit; | ||||
| 
 | ||||
|         check_timeouts(); | ||||
| 
 | ||||
|         if (pause_display) { | ||||
|                 while (displayed->length > 0) { | ||||
|                         g_queue_insert_sorted(queue, g_queue_pop_head(displayed), | ||||
|                                               notification_cmp_data, NULL); | ||||
|                 } | ||||
|                 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) { | ||||
|                         /* 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 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); | ||||
| } | ||||
| 
 | ||||
| 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(); | ||||
|         queues_check_timeouts(x_is_idle()); | ||||
|         queues_update(); | ||||
| 
 | ||||
|         static int timeout_cnt = 0; | ||||
|         static gint64 next_timeout = 0; | ||||
| 
 | ||||
| @ -211,11 +60,11 @@ gboolean run(void *data) | ||||
|                 timeout_cnt--; | ||||
|         } | ||||
| 
 | ||||
|         if (displayed->length > 0 && !xctx.visible && !pause_display) { | ||||
|         if (queues_length_displayed() > 0 && !xctx.visible) { | ||||
|                 x_win_show(); | ||||
|         } | ||||
| 
 | ||||
|         if (xctx.visible && (pause_display || displayed->length == 0)) { | ||||
|         if (xctx.visible && queues_length_displayed() == 0) { | ||||
|                 x_win_hide(); | ||||
|         } | ||||
| 
 | ||||
| @ -225,7 +74,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) { | ||||
| @ -243,7 +92,7 @@ gboolean run(void *data) | ||||
| 
 | ||||
| gboolean pause_signal(gpointer data) | ||||
| { | ||||
|         pause_display = true; | ||||
|         queues_pause_on(); | ||||
|         wake_up(); | ||||
| 
 | ||||
|         return G_SOURCE_CONTINUE; | ||||
| @ -251,7 +100,7 @@ gboolean pause_signal(gpointer data) | ||||
| 
 | ||||
| gboolean unpause_signal(gpointer data) | ||||
| { | ||||
|         pause_display = false; | ||||
|         queues_pause_off(); | ||||
|         wake_up(); | ||||
| 
 | ||||
|         return G_SOURCE_CONTINUE; | ||||
| @ -264,19 +113,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,9 +125,7 @@ static void teardown(void) | ||||
| int dunst_main(int argc, char *argv[]) | ||||
| { | ||||
| 
 | ||||
|         history = g_queue_new(); | ||||
|         displayed = g_queue_new(); | ||||
|         queue = g_queue_new(); | ||||
|         queues_init(); | ||||
| 
 | ||||
|         cmdline_load(argc, argv); | ||||
| 
 | ||||
| @ -319,7 +158,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); | ||||
|  | ||||
| @ -16,11 +16,7 @@ | ||||
| #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]; | ||||
| 
 | ||||
| /* return id of notification */ | ||||
| @ -30,10 +26,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); | ||||
|  | ||||
| @ -16,6 +16,7 @@ | ||||
| #include "dunst.h" | ||||
| #include "settings.h" | ||||
| #include "notification.h" | ||||
| #include "queues.h" | ||||
| #include "utils.h" | ||||
| 
 | ||||
| static bool is_initialized = false; | ||||
| @ -136,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) { | ||||
| @ -188,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; | ||||
| 
 | ||||
|  | ||||
| @ -19,10 +19,10 @@ | ||||
| #include "menu.h" | ||||
| #include "rules.h" | ||||
| #include "settings.h" | ||||
| #include "queues.h" | ||||
| #include "utils.h" | ||||
| #include "x11/x.h" | ||||
| 
 | ||||
| int next_notification_id = 1; | ||||
| 
 | ||||
| /*
 | ||||
|  * print a human readable representation | ||||
| @ -279,30 +279,19 @@ 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); | ||||
| 
 | ||||
|         if (strcmp("DUNST_COMMAND_PAUSE", n->summary) == 0) { | ||||
|                 pause_display = true; | ||||
|                 return 0; | ||||
|         } | ||||
| 
 | ||||
|         if (strcmp("DUNST_COMMAND_RESUME", n->summary) == 0) { | ||||
|                 pause_display = false; | ||||
|                 return 0; | ||||
|         } | ||||
| 
 | ||||
|         n->script = NULL; | ||||
|         n->text_to_render = NULL; | ||||
| 
 | ||||
| @ -422,64 +411,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; | ||||
| 
 | ||||
|         /* 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; | ||||
| 
 | ||||
| @ -505,17 +438,6 @@ int notification_init(notification *n, int id) | ||||
| 
 | ||||
|         n->first_render = true; | ||||
| 
 | ||||
|         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); | ||||
| 
 | ||||
|         char *tmp_urls = extract_urls(tmp); | ||||
| @ -538,102 +460,6 @@ int notification_init(notification *n, int id) | ||||
|         } | ||||
| 
 | ||||
|         g_free(tmp); | ||||
| 
 | ||||
|         if (settings.print_notifications) | ||||
|                 notification_print(n); | ||||
| 
 | ||||
|         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) | ||||
|  | ||||
| @ -62,15 +62,12 @@ 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_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); | ||||
|  | ||||
							
								
								
									
										381
									
								
								src/queues.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										381
									
								
								src/queues.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,381 @@ | ||||
| /* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ | ||||
| 
 | ||||
| #include "queues.h" | ||||
| 
 | ||||
| #include <assert.h> | ||||
| #include <glib.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| #include "dbus.h" | ||||
| #include "notification.h" | ||||
| #include "settings.h" | ||||
| 
 | ||||
| /* notification lists */ | ||||
| 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 */ | ||||
| 
 | ||||
| unsigned int displayed_limit = 0; | ||||
| int next_notification_id = 1; | ||||
| bool pause_displayed = false; | ||||
| 
 | ||||
| static int queues_stack_duplicate(notification *n); | ||||
| 
 | ||||
| void queues_init(void) | ||||
| { | ||||
|         history   = g_queue_new(); | ||||
|         displayed = g_queue_new(); | ||||
|         waiting   = g_queue_new(); | ||||
| } | ||||
| 
 | ||||
| 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 waiting->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) | ||||
| { | ||||
|         /* 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) { | ||||
|                         int stacked = queues_stack_duplicate(n); | ||||
|                         if (stacked > 0) { | ||||
|                                 // notification got stacked
 | ||||
|                                 return stacked; | ||||
|                         } | ||||
|                 } | ||||
| 
 | ||||
|                 n->id = ++next_notification_id; | ||||
| 
 | ||||
|                 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(waiting, 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(waiting); 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 queues_notification_replace_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); | ||||
|                         queues_history_push(old); | ||||
|                         return true; | ||||
|                 } | ||||
|         } | ||||
| 
 | ||||
|         for (GList *iter = g_queue_peek_head_link(waiting); | ||||
|                     iter; | ||||
|                     iter = iter->next) { | ||||
|                 notification *old = iter->data; | ||||
|                 if (old->id == new->id) { | ||||
|                         iter->data = new; | ||||
|                         new->dup_count = old->dup_count; | ||||
|                         queues_history_push(old); | ||||
|                         return true; | ||||
|                 } | ||||
|         } | ||||
|         return false; | ||||
| } | ||||
| 
 | ||||
| int queues_notification_close_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); | ||||
|                         queues_history_push(n); | ||||
|                         target = n; | ||||
|                         break; | ||||
|                 } | ||||
|         } | ||||
| 
 | ||||
|         for (GList *iter = g_queue_peek_head_link(waiting); iter; | ||||
|              iter = iter->next) { | ||||
|                 notification *n = iter->data; | ||||
|                 if (n->id == id) { | ||||
|                         g_queue_remove(waiting, n); | ||||
|                         queues_history_push(n); | ||||
|                         target = n; | ||||
|                         break; | ||||
|                 } | ||||
|         } | ||||
| 
 | ||||
|         if (reason > 0 && reason < 4 && target != NULL) { | ||||
|                 notification_closed(target, reason); | ||||
|         } | ||||
| 
 | ||||
|         return reason; | ||||
| } | ||||
| 
 | ||||
| int queues_notification_close(notification *n, int reason) | ||||
| { | ||||
|         assert(n != NULL); | ||||
|         return queues_notification_close_id(n->id, reason); | ||||
| } | ||||
| 
 | ||||
| void queues_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(waiting, 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); | ||||
|                 notification_free(to_free); | ||||
|         } | ||||
| 
 | ||||
|         if (!n->history_ignore) | ||||
|                 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 (waiting->length > 0) { | ||||
|                 queues_notification_close(g_queue_peek_head_link(waiting)->data, 2); | ||||
|         } | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|                         queues_notification_close(n, 1); | ||||
|                 } | ||||
|         } | ||||
| } | ||||
| 
 | ||||
| void queues_update() | ||||
| { | ||||
|         if (pause_displayed) { | ||||
|                 while (displayed->length > 0) { | ||||
|                         g_queue_insert_sorted( | ||||
|                             waiting, g_queue_pop_head(displayed), notification_cmp_data, NULL); | ||||
|                 } | ||||
|                 return; | ||||
|         } | ||||
| 
 | ||||
|         /* move notifications from queue to displayed */ | ||||
|         while (waiting->length > 0) { | ||||
| 
 | ||||
|                 if (displayed_limit > 0 && displayed->length >= displayed_limit) { | ||||
|                         /* the list is full */ | ||||
|                         break; | ||||
|                 } | ||||
| 
 | ||||
|                 notification *n = g_queue_pop_head(waiting); | ||||
| 
 | ||||
|                 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; | ||||
| 
 | ||||
|         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; | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
|         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(waiting, teardown_notification); | ||||
| } | ||||
| /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ | ||||
							
								
								
									
										132
									
								
								src/queues.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								src/queues.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,132 @@ | ||||
| /* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ | ||||
| 
 | ||||
| #ifndef DUNST_QUEUE_H | ||||
| #define DUNST_QUEUE_H | ||||
| 
 | ||||
| #include "notification.h" | ||||
| 
 | ||||
| /*
 | ||||
|  * 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); | ||||
| 
 | ||||
| /*
 | ||||
|  * 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 | ||||
|  * | ||||
|  * 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 | ||||
|  * If returned id == 0, the message was dismissed | ||||
|  */ | ||||
| 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 | ||||
|  * right in the same position as the old notification. | ||||
|  * | ||||
|  * Returns true, if a matching notification has been found | ||||
|  * and is replaced. Else false. | ||||
|  */ | ||||
| bool queues_notification_replace_id(notification *new); | ||||
| 
 | ||||
| /*
 | ||||
|  * Close the notification that has n->id == id | ||||
|  * | ||||
|  * 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 | ||||
|  *  1 -> the notification expired | ||||
|  *  2 -> the notification was dismissed by the user_data | ||||
|  *  3 -> The notification was closed by a call to CloseNotification | ||||
|  */ | ||||
| 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); | ||||
| 
 | ||||
| /*
 | ||||
|  * 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 | ||||
|  */ | ||||
| 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 | ||||
|  * | ||||
|  * This may be: | ||||
|  * | ||||
|  * - notification hits timeout | ||||
|  * - notification's age second changes | ||||
|  * - notification's age threshold is hit | ||||
|  */ | ||||
| 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 | ||||
|  */ | ||||
| void teardown_queues(void); | ||||
| 
 | ||||
| #endif | ||||
| /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ | ||||
							
								
								
									
										40
									
								
								src/x11/x.c
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								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" | ||||
| @ -532,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; | ||||
| @ -842,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: | ||||
| @ -852,29 +854,32 @@ 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) | ||||
|                                                 notification_close(n, 2); | ||||
|                                 const GList *displayed = queues_get_displayed(); | ||||
|                                 if (displayed && displayed->data) { | ||||
|                                         queues_notification_close(displayed->data, 2); | ||||
|                                         wake_up(); | ||||
|                                 } | ||||
|                         } | ||||
|                         if (settings.history_ks.str | ||||
|                             && 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 | ||||
|                             && XLookupKeysym(&ev.xkey, | ||||
|                                              0) == settings.context_ks.sym | ||||
|                             && settings.context_ks.mask == state) { | ||||
|                                 context_menu(); | ||||
|                                 wake_up(); | ||||
|                         } | ||||
|                         break; | ||||
|                 case FocusIn: | ||||
| @ -910,7 +915,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; | ||||
|         } | ||||
| @ -919,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) | ||||
| @ -932,7 +937,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); | ||||
|                 } | ||||
| @ -1008,6 +1013,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(); | ||||
| @ -1109,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; | ||||
|         } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Nikos Tsipinakis
						Nikos Tsipinakis