commit
7ba6ca910f
48
src/dunst.c
48
src/dunst.c
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "dunst.h"
|
#include "dunst.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <glib-unix.h>
|
#include <glib-unix.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
@ -24,6 +25,34 @@
|
|||||||
|
|
||||||
GMainLoop *mainloop = NULL;
|
GMainLoop *mainloop = NULL;
|
||||||
|
|
||||||
|
static struct dunst_status status;
|
||||||
|
|
||||||
|
/* see dunst.h */
|
||||||
|
void dunst_status(const enum dunst_status_field field,
|
||||||
|
bool value)
|
||||||
|
{
|
||||||
|
switch (field) {
|
||||||
|
case S_FULLSCREEN:
|
||||||
|
status.fullscreen = value;
|
||||||
|
break;
|
||||||
|
case S_IDLE:
|
||||||
|
status.idle = value;
|
||||||
|
break;
|
||||||
|
case S_RUNNING:
|
||||||
|
status.running = value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_E("Invalid %s enum value in %s:%d", "dunst_status", __FILE__, __LINE__);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* see dunst.h */
|
||||||
|
struct dunst_status dunst_status_get(void)
|
||||||
|
{
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
/* misc functions */
|
/* misc functions */
|
||||||
static gboolean run(void *data);
|
static gboolean run(void *data);
|
||||||
|
|
||||||
@ -34,14 +63,14 @@ void wake_up(void)
|
|||||||
|
|
||||||
static gboolean run(void *data)
|
static gboolean run(void *data)
|
||||||
{
|
{
|
||||||
|
static gint64 next_timeout = 0;
|
||||||
|
|
||||||
LOG_D("RUN");
|
LOG_D("RUN");
|
||||||
|
|
||||||
bool fullscreen = have_fullscreen_window();
|
dunst_status(S_FULLSCREEN, have_fullscreen_window());
|
||||||
|
dunst_status(S_IDLE, x_is_idle());
|
||||||
|
|
||||||
queues_check_timeouts(x_is_idle(), fullscreen);
|
queues_update(status);
|
||||||
queues_update(fullscreen);
|
|
||||||
|
|
||||||
static gint64 next_timeout = 0;
|
|
||||||
|
|
||||||
bool active = queues_length_displayed() > 0;
|
bool active = queues_length_displayed() > 0;
|
||||||
|
|
||||||
@ -76,7 +105,7 @@ static gboolean run(void *data)
|
|||||||
|
|
||||||
gboolean pause_signal(gpointer data)
|
gboolean pause_signal(gpointer data)
|
||||||
{
|
{
|
||||||
queues_pause_on();
|
dunst_status(S_RUNNING, false);
|
||||||
wake_up();
|
wake_up();
|
||||||
|
|
||||||
return G_SOURCE_CONTINUE;
|
return G_SOURCE_CONTINUE;
|
||||||
@ -84,7 +113,7 @@ gboolean pause_signal(gpointer data)
|
|||||||
|
|
||||||
gboolean unpause_signal(gpointer data)
|
gboolean unpause_signal(gpointer data)
|
||||||
{
|
{
|
||||||
queues_pause_off();
|
dunst_status(S_RUNNING, true);
|
||||||
wake_up();
|
wake_up();
|
||||||
|
|
||||||
return G_SOURCE_CONTINUE;
|
return G_SOURCE_CONTINUE;
|
||||||
@ -101,7 +130,7 @@ static void teardown(void)
|
|||||||
{
|
{
|
||||||
regex_teardown();
|
regex_teardown();
|
||||||
|
|
||||||
teardown_queues();
|
queues_teardown();
|
||||||
|
|
||||||
draw_deinit();
|
draw_deinit();
|
||||||
}
|
}
|
||||||
@ -109,6 +138,9 @@ static void teardown(void)
|
|||||||
int dunst_main(int argc, char *argv[])
|
int dunst_main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
|
||||||
|
dunst_status(S_RUNNING, true);
|
||||||
|
dunst_status(S_IDLE, false);
|
||||||
|
|
||||||
queues_init();
|
queues_init();
|
||||||
|
|
||||||
cmdline_load(argc, argv);
|
cmdline_load(argc, argv);
|
||||||
|
24
src/dunst.h
24
src/dunst.h
@ -6,6 +6,7 @@
|
|||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "notification.h"
|
#include "notification.h"
|
||||||
|
|
||||||
@ -14,6 +15,29 @@
|
|||||||
#define ColFG 1
|
#define ColFG 1
|
||||||
#define ColBG 0
|
#define ColBG 0
|
||||||
|
|
||||||
|
//!< A structure to describe dunst's global window status
|
||||||
|
struct dunst_status {
|
||||||
|
bool fullscreen; //!< a fullscreen window is currently focused
|
||||||
|
bool running; //!< set true if dunst is currently running
|
||||||
|
bool idle; //!< set true if the user is idle
|
||||||
|
};
|
||||||
|
|
||||||
|
enum dunst_status_field {
|
||||||
|
S_FULLSCREEN,
|
||||||
|
S_IDLE,
|
||||||
|
S_RUNNING,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modify the current status of dunst
|
||||||
|
* @param field The field to change in the global status structure
|
||||||
|
* @param value Anything boolean or DO_TOGGLE to toggle the current value
|
||||||
|
*/
|
||||||
|
void dunst_status(const enum dunst_status_field field,
|
||||||
|
bool value);
|
||||||
|
|
||||||
|
struct dunst_status dunst_status_get(void);
|
||||||
|
|
||||||
extern const char *colors[3][3];
|
extern const char *colors[3][3];
|
||||||
|
|
||||||
void wake_up(void);
|
void wake_up(void);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/* copyright 2012 - 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */
|
/* copyright 2012 - 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */
|
||||||
|
|
||||||
/** @file log.c
|
/**
|
||||||
|
* @file src/log.c
|
||||||
* @brief logging wrapper to use GLib's logging capabilities
|
* @brief logging wrapper to use GLib's logging capabilities
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -376,7 +376,7 @@ static void notification_format_message(struct notification *n)
|
|||||||
|
|
||||||
/* replace all formatter */
|
/* replace all formatter */
|
||||||
for(char *substr = strchr(n->msg, '%');
|
for(char *substr = strchr(n->msg, '%');
|
||||||
substr;
|
substr && *substr;
|
||||||
substr = strchr(substr, '%')) {
|
substr = strchr(substr, '%')) {
|
||||||
|
|
||||||
char pg[16];
|
char pg[16];
|
||||||
@ -450,6 +450,7 @@ static void notification_format_message(struct notification *n)
|
|||||||
case '\0':
|
case '\0':
|
||||||
LOG_W("format_string has trailing %% character. "
|
LOG_W("format_string has trailing %% character. "
|
||||||
"To escape it use %%%%.");
|
"To escape it use %%%%.");
|
||||||
|
substr++;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_W("format_string %%%c is unknown.", substr[1]);
|
LOG_W("format_string %%%c is unknown.", substr[1]);
|
||||||
|
170
src/queues.c
170
src/queues.c
@ -1,7 +1,7 @@
|
|||||||
/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */
|
/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file queues.c
|
* @file src/queues.c
|
||||||
* @brief All important functions to handle the notification queues for
|
* @brief All important functions to handle the notification queues for
|
||||||
* history, entrance and currently displayed ones.
|
* history, entrance and currently displayed ones.
|
||||||
*
|
*
|
||||||
@ -20,6 +20,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "dunst.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "notification.h"
|
#include "notification.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
@ -31,7 +32,6 @@ static GQueue *displayed = NULL; /**< currently displayed notifications */
|
|||||||
static GQueue *history = NULL; /**< history of displayed notifications */
|
static GQueue *history = NULL; /**< history of displayed notifications */
|
||||||
|
|
||||||
int next_notification_id = 1;
|
int next_notification_id = 1;
|
||||||
bool pause_displayed = false;
|
|
||||||
|
|
||||||
static bool queues_stack_duplicate(struct notification *n);
|
static bool queues_stack_duplicate(struct notification *n);
|
||||||
static bool queues_stack_by_tag(struct notification *n);
|
static bool queues_stack_by_tag(struct notification *n);
|
||||||
@ -108,24 +108,54 @@ static void queues_swap_notifications(GQueue *queueA,
|
|||||||
* Check if a notification is eligible to get shown.
|
* Check if a notification is eligible to get shown.
|
||||||
*
|
*
|
||||||
* @param n The notification to check
|
* @param n The notification to check
|
||||||
* @param fullscreen True if a fullscreen window is currently active
|
* @param status The current status of dunst
|
||||||
* @param visible True if the notification is currently displayed
|
* @param shown True if the notification is currently displayed
|
||||||
*/
|
*/
|
||||||
static bool queues_notification_is_ready(const struct notification *n, bool fullscreen, bool visible)
|
static bool queues_notification_is_ready(const struct notification *n, struct dunst_status status, bool shown)
|
||||||
{
|
{
|
||||||
if (fullscreen && visible)
|
if (!status.running)
|
||||||
|
return false;
|
||||||
|
if (status.fullscreen && shown)
|
||||||
return n && n->fullscreen != FS_PUSHBACK;
|
return n && n->fullscreen != FS_PUSHBACK;
|
||||||
else if (fullscreen && !visible)
|
else if (status.fullscreen && !shown)
|
||||||
return n && n->fullscreen == FS_SHOW;
|
return n && n->fullscreen == FS_SHOW;
|
||||||
else
|
else
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a notification has timed out
|
||||||
|
*
|
||||||
|
* @param n the notification to check
|
||||||
|
* @param status the current status of dunst
|
||||||
|
* @returns true, if the notification is timed out, otherwise false
|
||||||
|
*/
|
||||||
|
static bool queues_notification_is_finished(struct notification *n, struct dunst_status status)
|
||||||
|
{
|
||||||
|
assert(n);
|
||||||
|
|
||||||
|
if (n->timeout == 0) // sticky
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool is_idle = status.fullscreen ? false : status.idle;
|
||||||
|
|
||||||
|
/* don't timeout when user is idle */
|
||||||
|
if (is_idle && !n->transient) {
|
||||||
|
n->start = time_monotonic_now();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove old message */
|
||||||
|
if (time_monotonic_now() - n->start > n->timeout) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* see queues.h */
|
/* see queues.h */
|
||||||
int queues_notification_insert(struct notification *n)
|
int queues_notification_insert(struct notification *n)
|
||||||
{
|
{
|
||||||
bool inserted = false;
|
|
||||||
|
|
||||||
/* do not display the message, if the message is empty */
|
/* do not display the message, if the message is empty */
|
||||||
if (STR_EMPTY(n->msg)) {
|
if (STR_EMPTY(n->msg)) {
|
||||||
if (settings.always_run_script) {
|
if (settings.always_run_script) {
|
||||||
@ -136,27 +166,35 @@ int queues_notification_insert(struct notification *n)
|
|||||||
}
|
}
|
||||||
/* Do not insert the message if it's a command */
|
/* Do not insert the message if it's a command */
|
||||||
if (STR_EQ("DUNST_COMMAND_PAUSE", n->summary)) {
|
if (STR_EQ("DUNST_COMMAND_PAUSE", n->summary)) {
|
||||||
pause_displayed = true;
|
dunst_status(S_RUNNING, false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (STR_EQ("DUNST_COMMAND_RESUME", n->summary)) {
|
if (STR_EQ("DUNST_COMMAND_RESUME", n->summary)) {
|
||||||
pause_displayed = false;
|
dunst_status(S_RUNNING, true);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (STR_EQ("DUNST_COMMAND_TOGGLE", n->summary)) {
|
if (STR_EQ("DUNST_COMMAND_TOGGLE", n->summary)) {
|
||||||
pause_displayed = !pause_displayed;
|
dunst_status(S_RUNNING, !dunst_status_get().running);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inserted && n->id != 0 && queues_notification_replace_id(n))
|
bool inserted = false;
|
||||||
|
if (n->id != 0) {
|
||||||
|
if (!queues_notification_replace_id(n)) {
|
||||||
|
// Requested id was not valid, but play nice and assign it anyway
|
||||||
|
g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL);
|
||||||
|
}
|
||||||
inserted = true;
|
inserted = true;
|
||||||
else
|
} else {
|
||||||
n->id = ++next_notification_id;
|
n->id = ++next_notification_id;
|
||||||
|
}
|
||||||
|
|
||||||
if (!inserted && STR_FULL(n->stack_tag) && queues_stack_by_tag(n))
|
if (!inserted && STR_FULL(n->stack_tag) && queues_stack_by_tag(n))
|
||||||
inserted = true;
|
inserted = true;
|
||||||
|
|
||||||
if (!inserted && settings.stack_duplicates && queues_stack_duplicate(n))
|
if (!inserted && settings.stack_duplicates && queues_stack_duplicate(n))
|
||||||
inserted = true;
|
inserted = true;
|
||||||
|
|
||||||
if (!inserted)
|
if (!inserted)
|
||||||
g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL);
|
g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL);
|
||||||
|
|
||||||
@ -304,7 +342,6 @@ void queues_history_pop(void)
|
|||||||
|
|
||||||
struct notification *n = g_queue_pop_tail(history);
|
struct notification *n = g_queue_pop_tail(history);
|
||||||
n->redisplayed = true;
|
n->redisplayed = true;
|
||||||
n->start = 0;
|
|
||||||
n->timeout = settings.sticky_history ? 0 : n->timeout;
|
n->timeout = settings.sticky_history ? 0 : n->timeout;
|
||||||
g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL);
|
g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL);
|
||||||
}
|
}
|
||||||
@ -337,69 +374,33 @@ void queues_history_push_all(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* see queues.h */
|
/* see queues.h */
|
||||||
void queues_check_timeouts(bool idle, bool fullscreen)
|
void queues_update(struct dunst_status status)
|
||||||
{
|
{
|
||||||
/* nothing to do */
|
GList *iter, *nextiter;
|
||||||
if (displayed->length == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
bool is_idle = fullscreen ? false : idle;
|
/* Move back all notifications, which aren't eligible to get shown anymore
|
||||||
|
* Will move the notifications back to waiting, if dunst isn't running or fullscreen
|
||||||
GList *iter = g_queue_peek_head_link(displayed);
|
* and notifications is not eligible to get shown anymore */
|
||||||
|
iter = g_queue_peek_head_link(displayed);
|
||||||
while (iter) {
|
while (iter) {
|
||||||
struct notification *n = iter->data;
|
struct notification *n = iter->data;
|
||||||
|
nextiter = iter->next;
|
||||||
|
|
||||||
/*
|
if (queues_notification_is_finished(n, status)){
|
||||||
* 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 (is_idle && !n->transient) {
|
|
||||||
n->start = time_monotonic_now();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* skip hidden and sticky messages */
|
|
||||||
if (n->start == 0 || n->timeout == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove old message */
|
|
||||||
if (time_monotonic_now() - n->start > n->timeout) {
|
|
||||||
queues_notification_close(n, REASON_TIME);
|
queues_notification_close(n, REASON_TIME);
|
||||||
}
|
iter = nextiter;
|
||||||
}
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
/* see queues.h */
|
|
||||||
void queues_update(bool fullscreen)
|
|
||||||
{
|
|
||||||
if (pause_displayed) {
|
|
||||||
while (displayed->length > 0) {
|
|
||||||
g_queue_insert_sorted(
|
|
||||||
waiting, g_queue_pop_head(displayed), notification_cmp_data, NULL);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* move notifications back to queue, which are set to pushback */
|
if (!queues_notification_is_ready(n, status, true)) {
|
||||||
if (fullscreen) {
|
|
||||||
GList *iter = g_queue_peek_head_link(displayed);
|
|
||||||
while (iter) {
|
|
||||||
struct notification *n = iter->data;
|
|
||||||
GList *nextiter = iter->next;
|
|
||||||
|
|
||||||
if (n->fullscreen == FS_PUSHBACK){
|
|
||||||
g_queue_delete_link(displayed, iter);
|
g_queue_delete_link(displayed, iter);
|
||||||
g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL);
|
g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL);
|
||||||
|
iter = nextiter;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
iter = nextiter;
|
iter = nextiter;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int cur_displayed_limit;
|
int cur_displayed_limit;
|
||||||
if (settings.geometry.h == 0)
|
if (settings.geometry.h == 0)
|
||||||
@ -412,15 +413,15 @@ void queues_update(bool fullscreen)
|
|||||||
cur_displayed_limit = settings.geometry.h;
|
cur_displayed_limit = settings.geometry.h;
|
||||||
|
|
||||||
/* move notifications from queue to displayed */
|
/* move notifications from queue to displayed */
|
||||||
GList *iter = g_queue_peek_head_link(waiting);
|
iter = g_queue_peek_head_link(waiting);
|
||||||
while (displayed->length < cur_displayed_limit && iter) {
|
while (displayed->length < cur_displayed_limit && iter) {
|
||||||
struct notification *n = iter->data;
|
struct notification *n = iter->data;
|
||||||
GList *nextiter = iter->next;
|
nextiter = iter->next;
|
||||||
|
|
||||||
if (!n)
|
if (!n)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!queues_notification_is_ready(n, fullscreen, false)) {
|
if (!queues_notification_is_ready(n, status, false)) {
|
||||||
iter = nextiter;
|
iter = nextiter;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -443,13 +444,13 @@ void queues_update(bool fullscreen)
|
|||||||
/* If displayed is actually full, let the more important notifications
|
/* If displayed is actually full, let the more important notifications
|
||||||
* from waiting seep into displayed.
|
* from waiting seep into displayed.
|
||||||
*/
|
*/
|
||||||
if (settings.sort) {
|
if (settings.sort && displayed->length == cur_displayed_limit) {
|
||||||
GList *i_waiting, *i_displayed;
|
GList *i_waiting, *i_displayed;
|
||||||
|
|
||||||
while ( (i_waiting = g_queue_peek_head_link(waiting))
|
while ( (i_waiting = g_queue_peek_head_link(waiting))
|
||||||
&& (i_displayed = g_queue_peek_tail_link(displayed))) {
|
&& (i_displayed = g_queue_peek_tail_link(displayed))) {
|
||||||
|
|
||||||
while (i_waiting && ! queues_notification_is_ready(i_waiting->data, fullscreen, true)) {
|
while (i_waiting && ! queues_notification_is_ready(i_waiting->data, status, false)) {
|
||||||
i_waiting = i_waiting->prev;
|
i_waiting = i_waiting->prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -488,37 +489,19 @@ gint64 queues_get_next_datachange(gint64 time)
|
|||||||
if (settings.show_age_threshold >= 0) {
|
if (settings.show_age_threshold >= 0) {
|
||||||
gint64 age = time - n->timestamp;
|
gint64 age = time - n->timestamp;
|
||||||
|
|
||||||
if (age > settings.show_age_threshold)
|
|
||||||
// sleep exactly until the next shift of the second happens
|
// sleep exactly until the next shift of the second happens
|
||||||
|
if (age > settings.show_age_threshold - S2US(1))
|
||||||
sleep = MIN(sleep, (S2US(1) - (age % S2US(1))));
|
sleep = MIN(sleep, (S2US(1) - (age % S2US(1))));
|
||||||
else if (n->timeout == 0 || ttl > settings.show_age_threshold)
|
else
|
||||||
sleep = MIN(sleep, settings.show_age_threshold);
|
sleep = MIN(sleep, settings.show_age_threshold - age);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sleep != G_MAXINT64 ? sleep : -1;
|
return sleep != G_MAXINT64 ? sleep : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* see queues.h */
|
|
||||||
void queues_pause_on(void)
|
|
||||||
{
|
|
||||||
pause_displayed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* see queues.h */
|
|
||||||
void queues_pause_off(void)
|
|
||||||
{
|
|
||||||
pause_displayed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* see queues.h */
|
|
||||||
bool queues_pause_status(void)
|
|
||||||
{
|
|
||||||
return pause_displayed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function for teardown_queues() to free a single notification
|
* Helper function for queues_teardown() to free a single notification
|
||||||
*
|
*
|
||||||
* @param data The notification to free
|
* @param data The notification to free
|
||||||
*/
|
*/
|
||||||
@ -529,10 +512,13 @@ static void teardown_notification(gpointer data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* see queues.h */
|
/* see queues.h */
|
||||||
void teardown_queues(void)
|
void queues_teardown(void)
|
||||||
{
|
{
|
||||||
g_queue_free_full(history, teardown_notification);
|
g_queue_free_full(history, teardown_notification);
|
||||||
|
history = NULL;
|
||||||
g_queue_free_full(displayed, teardown_notification);
|
g_queue_free_full(displayed, teardown_notification);
|
||||||
|
displayed = NULL;
|
||||||
g_queue_free_full(waiting, teardown_notification);
|
g_queue_free_full(waiting, teardown_notification);
|
||||||
|
waiting = NULL;
|
||||||
}
|
}
|
||||||
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
||||||
|
42
src/queues.h
42
src/queues.h
@ -1,13 +1,14 @@
|
|||||||
/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */
|
/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file queues.c
|
* @file src/queues.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef DUNST_QUEUE_H
|
#ifndef DUNST_QUEUE_H
|
||||||
#define DUNST_QUEUE_H
|
#define DUNST_QUEUE_H
|
||||||
|
|
||||||
#include "dbus.h"
|
#include "dbus.h"
|
||||||
|
#include "dunst.h"
|
||||||
#include "notification.h"
|
#include "notification.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -117,16 +118,6 @@ void queues_history_push(struct notification *n);
|
|||||||
*/
|
*/
|
||||||
void queues_history_push_all(void);
|
void queues_history_push_all(void);
|
||||||
|
|
||||||
/**
|
|
||||||
* Check timeout of each notification and close it, if necessary
|
|
||||||
*
|
|
||||||
* @param idle the program's idle status. Important to calculate the
|
|
||||||
* timeout for transient notifications
|
|
||||||
* @param fullscreen the desktop's fullscreen status. Important to
|
|
||||||
* calculate the timeout for transient notifications
|
|
||||||
*/
|
|
||||||
void queues_check_timeouts(bool idle, bool fullscreen);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move inserted notifications from waiting queue to displayed queue
|
* Move inserted notifications from waiting queue to displayed queue
|
||||||
* and show them. In displayed queue, the amount of elements is limited
|
* and show them. In displayed queue, the amount of elements is limited
|
||||||
@ -135,10 +126,9 @@ void queues_check_timeouts(bool idle, bool fullscreen);
|
|||||||
* @post Call wake_up() to synchronize the queues with the UI
|
* @post Call wake_up() to synchronize the queues with the UI
|
||||||
* (which closes old and shows new notifications on screen)
|
* (which closes old and shows new notifications on screen)
|
||||||
*
|
*
|
||||||
* @param fullscreen the desktop's fullscreen status. Important to
|
* @param status the current status of dunst
|
||||||
* move notifications to the right queue
|
|
||||||
*/
|
*/
|
||||||
void queues_update(bool fullscreen);
|
void queues_update(struct dunst_status status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the distance to the next event, when an element in the
|
* Calculate the distance to the next event, when an element in the
|
||||||
@ -154,34 +144,12 @@ void queues_update(bool fullscreen);
|
|||||||
*/
|
*/
|
||||||
gint64 queues_get_next_datachange(gint64 time);
|
gint64 queues_get_next_datachange(gint64 time);
|
||||||
|
|
||||||
/**
|
|
||||||
* Pause queue-management of dunst
|
|
||||||
*
|
|
||||||
* @post Calling update_lists() is necessary
|
|
||||||
*/
|
|
||||||
void queues_pause_on(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unpause (run) queue-management of dunst
|
|
||||||
*
|
|
||||||
* @post Calling update_lists() is necessary
|
|
||||||
*/
|
|
||||||
void queues_pause_off(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current status
|
|
||||||
*
|
|
||||||
* @return true if paused
|
|
||||||
* @return false if running
|
|
||||||
*/
|
|
||||||
bool queues_pause_status(void);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all notifications from all list and free the notifications
|
* Remove all notifications from all list and free the notifications
|
||||||
*
|
*
|
||||||
* @pre At least one time queues_init() called
|
* @pre At least one time queues_init() called
|
||||||
*/
|
*/
|
||||||
void teardown_queues(void);
|
void queues_teardown(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
||||||
|
23
test/dunst.c
Normal file
23
test/dunst.c
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include "../src/dunst.c"
|
||||||
|
#include "greatest.h"
|
||||||
|
|
||||||
|
TEST test_dunst_status(void)
|
||||||
|
{
|
||||||
|
status = (struct dunst_status) {false, false, false};
|
||||||
|
|
||||||
|
dunst_status(S_FULLSCREEN, true);
|
||||||
|
ASSERT(status.fullscreen);
|
||||||
|
dunst_status(S_IDLE, true);
|
||||||
|
ASSERT(status.idle);
|
||||||
|
dunst_status(S_RUNNING, true);
|
||||||
|
ASSERT(status.running);
|
||||||
|
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
SUITE(suite_dunst)
|
||||||
|
{
|
||||||
|
RUN_TEST(test_dunst_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
710
test/queues.c
Normal file
710
test/queues.c
Normal file
@ -0,0 +1,710 @@
|
|||||||
|
#include "../src/queues.c"
|
||||||
|
|
||||||
|
#define GREATEST_FLOAT gint64
|
||||||
|
#define GREATEST_FLOAT_FMT "%ld"
|
||||||
|
|
||||||
|
#include "greatest.h"
|
||||||
|
#include "queues.h"
|
||||||
|
|
||||||
|
TEST test_queue_length(void)
|
||||||
|
{
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
struct notification *n;
|
||||||
|
|
||||||
|
n = test_notification("n1", 0);
|
||||||
|
queues_notification_insert(n);
|
||||||
|
queues_notification_close(n, REASON_UNDEF);
|
||||||
|
|
||||||
|
n = test_notification("n2", 0);
|
||||||
|
queues_notification_insert(n);
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
|
||||||
|
n = test_notification("n3", 0);
|
||||||
|
queues_notification_insert(n);
|
||||||
|
|
||||||
|
QUEUE_LEN_ALL(1,1,1);
|
||||||
|
|
||||||
|
ASSERT_EQm("Queue waiting has to contain an element",
|
||||||
|
1, queues_length_waiting());
|
||||||
|
ASSERT_EQm("Queue displayed has to contain an element",
|
||||||
|
1, queues_length_displayed());
|
||||||
|
ASSERT_EQm("Queue history has to contain an element",
|
||||||
|
1, queues_length_history());
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_queue_insert_id_valid_newid(void)
|
||||||
|
{
|
||||||
|
struct notification *n;
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
n = test_notification("n", -1);
|
||||||
|
n->id = 0;
|
||||||
|
|
||||||
|
queues_notification_insert(n);
|
||||||
|
|
||||||
|
QUEUE_LEN_ALL(1, 0, 0);
|
||||||
|
ASSERT(n->id > 0);
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_queue_insert_id_invalid(void)
|
||||||
|
{
|
||||||
|
struct notification *n;
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
n = test_notification("n", -1);
|
||||||
|
n->id = 1000;
|
||||||
|
|
||||||
|
queues_notification_insert(n);
|
||||||
|
QUEUE_LEN_ALL(1, 0, 0);
|
||||||
|
ASSERTm("The given ID shouldn't be 0 anymore.",
|
||||||
|
n->id > 0);
|
||||||
|
ASSERT_EQm("This is a relict from times before stack_tag: "
|
||||||
|
"Even if next_notification_id is lower than the requested id, "
|
||||||
|
"it should use the requested id.",
|
||||||
|
1000, n->id);
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_queue_insert_id_replacement(void)
|
||||||
|
{
|
||||||
|
struct notification *a, *b, *c;
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
a = test_notification("a", -1);
|
||||||
|
notification_ref(a);
|
||||||
|
|
||||||
|
queues_notification_insert(a);
|
||||||
|
QUEUE_LEN_ALL(1, 0, 0);
|
||||||
|
|
||||||
|
b = test_notification("b", -1);
|
||||||
|
notification_ref(b);
|
||||||
|
b->id = a->id;
|
||||||
|
|
||||||
|
queues_notification_insert(b);
|
||||||
|
QUEUE_LEN_ALL(1, 0, 0);
|
||||||
|
|
||||||
|
ASSERT_EQ(a->id, b->id);
|
||||||
|
NOT_LAST(a);
|
||||||
|
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
c = test_notification("c", -1);
|
||||||
|
c->id = b->id;
|
||||||
|
|
||||||
|
queues_notification_insert(c);
|
||||||
|
|
||||||
|
QUEUE_LEN_ALL(0, 1, 0);
|
||||||
|
ASSERT_EQ(b->id, c->id);
|
||||||
|
NOT_LAST(b);
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_queue_notification_close(void)
|
||||||
|
{
|
||||||
|
struct notification *n;
|
||||||
|
|
||||||
|
// Test closing from waiting queue
|
||||||
|
n = test_notification("n", -1);
|
||||||
|
|
||||||
|
queues_init();
|
||||||
|
queues_notification_insert(n);
|
||||||
|
QUEUE_LEN_ALL(1, 0, 0);
|
||||||
|
queues_notification_close(n, REASON_UNDEF);
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
QUEUE_LEN_ALL(0, 0, 1);
|
||||||
|
queues_teardown();
|
||||||
|
|
||||||
|
// Test closing from displayed queue
|
||||||
|
n = test_notification("n", -1);
|
||||||
|
|
||||||
|
queues_init();
|
||||||
|
queues_notification_insert(n);
|
||||||
|
QUEUE_LEN_ALL(1, 0, 0);
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
QUEUE_LEN_ALL(0, 1, 0);
|
||||||
|
queues_notification_close(n, REASON_UNDEF);
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
QUEUE_LEN_ALL(0, 0, 1);
|
||||||
|
queues_teardown();
|
||||||
|
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_queue_notification_close_histignore(void)
|
||||||
|
{
|
||||||
|
struct notification *n;
|
||||||
|
|
||||||
|
// Test closing from waiting queue
|
||||||
|
n = test_notification("n", -1);
|
||||||
|
n->history_ignore = true;
|
||||||
|
|
||||||
|
queues_init();
|
||||||
|
queues_notification_insert(n);
|
||||||
|
QUEUE_LEN_ALL(1, 0, 0);
|
||||||
|
queues_notification_close(n, REASON_UNDEF);
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
QUEUE_LEN_ALL(0, 0, 0);
|
||||||
|
queues_teardown();
|
||||||
|
|
||||||
|
// Test closing from displayed queue
|
||||||
|
n = test_notification("n", -1);
|
||||||
|
n->history_ignore = true;
|
||||||
|
|
||||||
|
queues_init();
|
||||||
|
queues_notification_insert(n);
|
||||||
|
QUEUE_LEN_ALL(1, 0, 0);
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
QUEUE_LEN_ALL(0, 1, 0);
|
||||||
|
queues_notification_close(n, REASON_UNDEF);
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
QUEUE_LEN_ALL(0, 0, 0);
|
||||||
|
queues_teardown();
|
||||||
|
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_queue_history_overfull(void)
|
||||||
|
{
|
||||||
|
settings.history_length = 10;
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
struct notification *n;
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
char name[] = { 'n', '0'+i, '\0' }; // n<i>
|
||||||
|
n = test_notification(name, -1);
|
||||||
|
queues_notification_insert(n);
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
queues_notification_close(n, REASON_UNDEF);
|
||||||
|
}
|
||||||
|
|
||||||
|
QUEUE_LEN_ALL(0, 0, 10);
|
||||||
|
|
||||||
|
n = test_notification("n", -1);
|
||||||
|
queues_notification_insert(n);
|
||||||
|
queues_notification_close(n, REASON_UNDEF);
|
||||||
|
|
||||||
|
QUEUE_CONTAINS(HIST, n);
|
||||||
|
QUEUE_LEN_ALL(0, 0, 10);
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_queue_history_pushall(void)
|
||||||
|
{
|
||||||
|
settings.history_length = 5;
|
||||||
|
settings.indicate_hidden = false;
|
||||||
|
settings.geometry.h = 0;
|
||||||
|
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
struct notification *n;
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
char name[] = { 'n', '0'+i, '\0' }; // n<i>
|
||||||
|
n = test_notification(name, -1);
|
||||||
|
queues_notification_insert(n);
|
||||||
|
}
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
char name[] = { '2', 'n', '0'+i, '\0' }; // 2n<i>
|
||||||
|
n = test_notification(name, -1);
|
||||||
|
queues_notification_insert(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
QUEUE_LEN_ALL(10, 10, 0);
|
||||||
|
|
||||||
|
queues_history_push_all();
|
||||||
|
|
||||||
|
QUEUE_CONTAINS(HIST, n);
|
||||||
|
QUEUE_LEN_ALL(0, 0, 5);
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_queue_init(void)
|
||||||
|
{
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
QUEUE_LEN_ALL(0, 0, 0);
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_queue_teardown(void)
|
||||||
|
{
|
||||||
|
queues_init();
|
||||||
|
QUEUE_LEN_ALL(0, 0, 0);
|
||||||
|
|
||||||
|
struct notification *n = test_notification("n", -1);
|
||||||
|
queues_notification_insert(n);
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
|
||||||
|
ASSERT(waiting == NULL);
|
||||||
|
ASSERT(displayed == NULL);
|
||||||
|
ASSERT(history == NULL);
|
||||||
|
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_datachange_beginning_empty(void)
|
||||||
|
{
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
ASSERTm("There are no notifications at all, the timeout has to be less than 0.",
|
||||||
|
queues_get_next_datachange(time_monotonic_now()) < 0);
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_datachange_endless(void)
|
||||||
|
{
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
settings.show_age_threshold = -1;
|
||||||
|
|
||||||
|
struct notification *n = test_notification("n", 0);
|
||||||
|
|
||||||
|
queues_notification_insert(n);
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
|
||||||
|
ASSERTm("Age threshold is deactivated and the notification is infinite, there is no wakeup necessary.",
|
||||||
|
queues_get_next_datachange(time_monotonic_now()) < 0);
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_datachange_endless_agethreshold(void)
|
||||||
|
{
|
||||||
|
settings.show_age_threshold = S2US(5);
|
||||||
|
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
struct notification *n = test_notification("n", 0);
|
||||||
|
|
||||||
|
queues_notification_insert(n);
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
|
||||||
|
ASSERT_IN_RANGEm("Age threshold is activated and the next wakeup should be less than a second away",
|
||||||
|
S2US(1)/2, queues_get_next_datachange(time_monotonic_now() + S2US(4)), S2US(1)/2);
|
||||||
|
|
||||||
|
ASSERT_IN_RANGEm("Age threshold is activated and the next wakeup should be less than the age threshold",
|
||||||
|
settings.show_age_threshold/2, queues_get_next_datachange(time_monotonic_now()), settings.show_age_threshold/2);
|
||||||
|
|
||||||
|
settings.show_age_threshold = S2US(0);
|
||||||
|
ASSERT_IN_RANGEm("Age threshold is activated and the next wakeup should be less than a second away",
|
||||||
|
S2US(1)/2, queues_get_next_datachange(time_monotonic_now()), S2US(1)/2);
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_datachange_queues(void)
|
||||||
|
{
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
struct notification *n = test_notification("n", 10);
|
||||||
|
|
||||||
|
queues_notification_insert(n);
|
||||||
|
ASSERTm("The inserted notification is inside the waiting queue, so it should get ignored.",
|
||||||
|
queues_get_next_datachange(time_monotonic_now()) < S2US(0));
|
||||||
|
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
ASSERT_IN_RANGEm("The notification has to get closed in less than its timeout",
|
||||||
|
S2US(10)/2, queues_get_next_datachange(time_monotonic_now()), S2US(10)/2);
|
||||||
|
|
||||||
|
queues_notification_close(n, REASON_UNDEF);
|
||||||
|
ASSERTm("The inserted notification is inside the history queue, so it should get ignored",
|
||||||
|
queues_get_next_datachange(time_monotonic_now()) < S2US(0));
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_datachange_ttl(void)
|
||||||
|
{
|
||||||
|
struct notification *n;
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
n = test_notification("n1", 15);
|
||||||
|
|
||||||
|
queues_notification_insert(n);
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
ASSERT_IN_RANGEm("The notification has to get closed in less than its timeout.",
|
||||||
|
n->timeout/2, queues_get_next_datachange(time_monotonic_now()), n->timeout/2);
|
||||||
|
|
||||||
|
n = test_notification("n2", 10);
|
||||||
|
|
||||||
|
queues_notification_insert(n);
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
ASSERT_IN_RANGEm("The timeout of the second notification has to get used as sleep time now.",
|
||||||
|
n->timeout/2, queues_get_next_datachange(time_monotonic_now()), n->timeout/2);
|
||||||
|
|
||||||
|
ASSERT_EQm("The notification already timed out. You have to answer with 0.",
|
||||||
|
S2US(0), queues_get_next_datachange(time_monotonic_now() + S2US(10)));
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_queue_stacking(void)
|
||||||
|
{
|
||||||
|
settings.stack_duplicates = true;
|
||||||
|
struct notification *n1, *n2, *n3;
|
||||||
|
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
n1 = test_notification("n1", -1);
|
||||||
|
n2 = test_notification("n1", -1);
|
||||||
|
n3 = test_notification("n1", -1);
|
||||||
|
|
||||||
|
queues_notification_insert(n1);
|
||||||
|
QUEUE_LEN_ALL(1, 0, 0);
|
||||||
|
|
||||||
|
notification_ref(n1);
|
||||||
|
queues_notification_insert(n2);
|
||||||
|
NOT_LAST(n1);
|
||||||
|
|
||||||
|
notification_ref(n2);
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
queues_notification_insert(n3);
|
||||||
|
QUEUE_LEN_ALL(0, 1, 0);
|
||||||
|
NOT_LAST(n2);
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_queue_stacktag(void)
|
||||||
|
{
|
||||||
|
const char *stacktag = "THIS IS A SUPER WIERD STACK TAG";
|
||||||
|
struct notification *n1, *n2, *n3;
|
||||||
|
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
n1 = test_notification("n1", 1);
|
||||||
|
n2 = test_notification("n2", 1);
|
||||||
|
n3 = test_notification("n3", 1);
|
||||||
|
n1->stack_tag = g_strdup(stacktag);
|
||||||
|
n2->stack_tag = g_strdup(stacktag);
|
||||||
|
n3->stack_tag = g_strdup(stacktag);
|
||||||
|
|
||||||
|
queues_notification_insert(n1);
|
||||||
|
QUEUE_LEN_ALL(1, 0, 0);
|
||||||
|
|
||||||
|
notification_ref(n1);
|
||||||
|
queues_notification_insert(n2);
|
||||||
|
NOT_LAST(n1);
|
||||||
|
|
||||||
|
notification_ref(n2);
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
queues_notification_insert(n3);
|
||||||
|
QUEUE_LEN_ALL(0, 1, 0);
|
||||||
|
NOT_LAST(n2);
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_queue_timeout(void)
|
||||||
|
{
|
||||||
|
settings.geometry.h = 5;
|
||||||
|
struct notification *n1, *n2, *n3;
|
||||||
|
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
n1 = test_notification("n1", 0);
|
||||||
|
n2 = test_notification("n2", 10);
|
||||||
|
n3 = test_notification("n3", 10);
|
||||||
|
n3->transient = true;
|
||||||
|
|
||||||
|
queues_notification_insert(n1);
|
||||||
|
queues_notification_insert(n2);
|
||||||
|
queues_notification_insert(n3);
|
||||||
|
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
|
||||||
|
// hacky way to shift time
|
||||||
|
n1->start -= S2US(11);
|
||||||
|
n2->start -= S2US(11);
|
||||||
|
n3->start -= S2US(11);
|
||||||
|
queues_update(STATUS_IDLE);
|
||||||
|
|
||||||
|
QUEUE_LEN_ALL(0,2,1);
|
||||||
|
QUEUE_CONTAINS(HIST, n3);
|
||||||
|
|
||||||
|
// hacky way to shift time
|
||||||
|
n1->start -= S2US(11);
|
||||||
|
n2->start -= S2US(11);
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
|
||||||
|
QUEUE_LEN_ALL(0,1,2);
|
||||||
|
QUEUE_CONTAINS(DISP, n1);
|
||||||
|
QUEUE_CONTAINS(HIST, n2);
|
||||||
|
QUEUE_CONTAINS(HIST, n3);
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_queues_update_fullscreen(void)
|
||||||
|
{
|
||||||
|
settings.geometry.h = 5;
|
||||||
|
struct notification *n_show, *n_dela, *n_push;
|
||||||
|
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
n_show = test_notification("show", 10);
|
||||||
|
n_dela = test_notification("dela", 10);
|
||||||
|
n_push = test_notification("push", 10);
|
||||||
|
n_show->fullscreen = FS_SHOW;
|
||||||
|
n_dela->fullscreen = FS_DELAY;
|
||||||
|
n_push->fullscreen = FS_PUSHBACK;
|
||||||
|
|
||||||
|
queues_notification_insert(n_show);
|
||||||
|
queues_notification_insert(n_dela);
|
||||||
|
queues_notification_insert(n_push);
|
||||||
|
|
||||||
|
queues_update(STATUS_FS);
|
||||||
|
QUEUE_CONTAINS(DISP, n_show);
|
||||||
|
QUEUE_CONTAINS(WAIT, n_dela);
|
||||||
|
QUEUE_CONTAINS(WAIT, n_push);
|
||||||
|
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
QUEUE_CONTAINS(DISP, n_show);
|
||||||
|
QUEUE_CONTAINS(DISP, n_dela);
|
||||||
|
QUEUE_CONTAINS(DISP, n_push);
|
||||||
|
|
||||||
|
queues_update(STATUS_FS);
|
||||||
|
QUEUE_CONTAINS(DISP, n_show);
|
||||||
|
QUEUE_CONTAINS(DISP, n_dela);
|
||||||
|
QUEUE_CONTAINS(WAIT, n_push);
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_queues_update_paused(void)
|
||||||
|
{
|
||||||
|
settings.geometry.h = 5;
|
||||||
|
struct notification *n1, *n2, *n3;
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
n1 = test_notification("n1", 0);
|
||||||
|
n2 = test_notification("n2", 0);
|
||||||
|
n3 = test_notification("n3", 0);
|
||||||
|
|
||||||
|
queues_notification_insert(n1);
|
||||||
|
queues_notification_insert(n2);
|
||||||
|
queues_notification_insert(n3);
|
||||||
|
|
||||||
|
QUEUE_LEN_ALL(3,0,0);
|
||||||
|
|
||||||
|
queues_update(STATUS_PAUSE);
|
||||||
|
QUEUE_LEN_ALL(3,0,0);
|
||||||
|
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
QUEUE_LEN_ALL(0,3,0);
|
||||||
|
|
||||||
|
queues_update(STATUS_PAUSE);
|
||||||
|
QUEUE_LEN_ALL(3,0,0);
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_queues_update_seeping(void)
|
||||||
|
{
|
||||||
|
settings.geometry.h = 5;
|
||||||
|
settings.sort = true;
|
||||||
|
settings.indicate_hidden = false;
|
||||||
|
struct notification *nl1, *nl2, *nl3, *nl4, *nl5;
|
||||||
|
struct notification *nc1, *nc2, *nc3, *nc4, *nc5;
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
nl1 = test_notification("nl1", 0);
|
||||||
|
nl2 = test_notification("nl2", 0);
|
||||||
|
nl3 = test_notification("nl3", 0);
|
||||||
|
nl4 = test_notification("nl4", 0);
|
||||||
|
nl5 = test_notification("nl5", 0);
|
||||||
|
|
||||||
|
nc1 = test_notification("nc1", 0);
|
||||||
|
nc2 = test_notification("nc2", 0);
|
||||||
|
nc3 = test_notification("nc3", 0);
|
||||||
|
nc4 = test_notification("nc4", 0);
|
||||||
|
nc5 = test_notification("nc5", 0);
|
||||||
|
nc1->urgency = URG_CRIT;
|
||||||
|
nc2->urgency = URG_CRIT;
|
||||||
|
nc3->urgency = URG_CRIT;
|
||||||
|
nc4->urgency = URG_CRIT;
|
||||||
|
nc5->urgency = URG_CRIT;
|
||||||
|
|
||||||
|
queues_notification_insert(nl1);
|
||||||
|
queues_notification_insert(nl2);
|
||||||
|
queues_notification_insert(nl3);
|
||||||
|
queues_notification_insert(nl4);
|
||||||
|
queues_notification_insert(nl5);
|
||||||
|
|
||||||
|
QUEUE_LEN_ALL(5,0,0);
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
QUEUE_LEN_ALL(0,5,0);
|
||||||
|
|
||||||
|
queues_notification_insert(nc1);
|
||||||
|
queues_notification_insert(nc2);
|
||||||
|
queues_notification_insert(nc3);
|
||||||
|
queues_notification_insert(nc4);
|
||||||
|
queues_notification_insert(nc5);
|
||||||
|
|
||||||
|
QUEUE_LEN_ALL(5,5,0);
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
QUEUE_LEN_ALL(5,5,0);
|
||||||
|
|
||||||
|
QUEUE_CONTAINS(DISP, nc1);
|
||||||
|
QUEUE_CONTAINS(DISP, nc2);
|
||||||
|
QUEUE_CONTAINS(DISP, nc3);
|
||||||
|
QUEUE_CONTAINS(DISP, nc4);
|
||||||
|
QUEUE_CONTAINS(DISP, nc5);
|
||||||
|
|
||||||
|
QUEUE_CONTAINS(WAIT, nl1);
|
||||||
|
QUEUE_CONTAINS(WAIT, nl2);
|
||||||
|
QUEUE_CONTAINS(WAIT, nl3);
|
||||||
|
QUEUE_CONTAINS(WAIT, nl4);
|
||||||
|
QUEUE_CONTAINS(WAIT, nl5);
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_queues_update_xmore(void)
|
||||||
|
{
|
||||||
|
settings.indicate_hidden = true;
|
||||||
|
settings.geometry.h = 4;
|
||||||
|
struct notification *n1, *n2, *n3, *n4, *n5;
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
n1 = test_notification("n1", 0);
|
||||||
|
n2 = test_notification("n2", 0);
|
||||||
|
n3 = test_notification("n3", 0);
|
||||||
|
n4 = test_notification("n4", 0);
|
||||||
|
n5 = test_notification("n5", 0);
|
||||||
|
|
||||||
|
queues_notification_insert(n1);
|
||||||
|
queues_notification_insert(n2);
|
||||||
|
queues_notification_insert(n3);
|
||||||
|
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
QUEUE_LEN_ALL(0,3,0);
|
||||||
|
|
||||||
|
queues_notification_insert(n4);
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
QUEUE_LEN_ALL(0,4,0);
|
||||||
|
|
||||||
|
queues_notification_insert(n5);
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
QUEUE_LEN_ALL(2,3,0);
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_queues_update_seep_showlowurg(void)
|
||||||
|
{
|
||||||
|
// Test 3 notifications during fullscreen and only the one
|
||||||
|
// with the lowest priority is eligible to get shown
|
||||||
|
settings.geometry.h = 4;
|
||||||
|
struct notification *n1, *n2, *n3;
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
n1 = test_notification("n1", 0);
|
||||||
|
n2 = test_notification("n2", 0);
|
||||||
|
n3 = test_notification("n3", 0);
|
||||||
|
|
||||||
|
n1->fullscreen = FS_DELAY;
|
||||||
|
n2->fullscreen = FS_DELAY;
|
||||||
|
n3->fullscreen = FS_SHOW;
|
||||||
|
|
||||||
|
n3->urgency = URG_LOW;
|
||||||
|
|
||||||
|
queues_notification_insert(n1);
|
||||||
|
queues_notification_insert(n2);
|
||||||
|
queues_update(STATUS_FS);
|
||||||
|
QUEUE_LEN_ALL(2,0,0);
|
||||||
|
|
||||||
|
queues_notification_insert(n3);
|
||||||
|
|
||||||
|
queues_update(STATUS_FS);
|
||||||
|
|
||||||
|
QUEUE_LEN_ALL(2,1,0);
|
||||||
|
QUEUE_CONTAINS(WAIT, n1);
|
||||||
|
QUEUE_CONTAINS(WAIT, n2);
|
||||||
|
QUEUE_CONTAINS(DISP, n3);
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST test_queues_timeout_before_paused(void)
|
||||||
|
{
|
||||||
|
struct notification *n;
|
||||||
|
queues_init();
|
||||||
|
|
||||||
|
n = test_notification("n", 10);
|
||||||
|
|
||||||
|
queues_notification_insert(n);
|
||||||
|
queues_update(STATUS_NORMAL);
|
||||||
|
|
||||||
|
n->start -= S2US(11);
|
||||||
|
queues_update(STATUS_PAUSE);
|
||||||
|
|
||||||
|
QUEUE_LEN_ALL(0,0,1);
|
||||||
|
|
||||||
|
queues_teardown();
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
SUITE(suite_queues)
|
||||||
|
{
|
||||||
|
RUN_TEST(test_datachange_beginning_empty);
|
||||||
|
RUN_TEST(test_datachange_endless);
|
||||||
|
RUN_TEST(test_datachange_endless_agethreshold);
|
||||||
|
RUN_TEST(test_datachange_queues);
|
||||||
|
RUN_TEST(test_datachange_ttl);
|
||||||
|
RUN_TEST(test_queue_history_overfull);
|
||||||
|
RUN_TEST(test_queue_history_pushall);
|
||||||
|
RUN_TEST(test_queue_init);
|
||||||
|
RUN_TEST(test_queue_insert_id_invalid);
|
||||||
|
RUN_TEST(test_queue_insert_id_replacement);
|
||||||
|
RUN_TEST(test_queue_insert_id_valid_newid);
|
||||||
|
RUN_TEST(test_queue_length);
|
||||||
|
RUN_TEST(test_queue_notification_close);
|
||||||
|
RUN_TEST(test_queue_notification_close_histignore);
|
||||||
|
RUN_TEST(test_queue_stacking);
|
||||||
|
RUN_TEST(test_queue_stacktag);
|
||||||
|
RUN_TEST(test_queue_teardown);
|
||||||
|
RUN_TEST(test_queue_timeout);
|
||||||
|
RUN_TEST(test_queues_update_fullscreen);
|
||||||
|
RUN_TEST(test_queues_update_paused);
|
||||||
|
RUN_TEST(test_queues_update_seep_showlowurg);
|
||||||
|
RUN_TEST(test_queues_update_seeping);
|
||||||
|
RUN_TEST(test_queues_update_xmore);
|
||||||
|
RUN_TEST(test_queues_timeout_before_paused);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
54
test/queues.h
Normal file
54
test/queues.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#include "greatest.h"
|
||||||
|
|
||||||
|
#ifndef DUNST_TEST_QUEUES_H
|
||||||
|
#define DUNST_TEST_QUEUES_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "../src/notification.h"
|
||||||
|
#include "../src/queues.h"
|
||||||
|
|
||||||
|
#define STATUS_NORMAL ((struct dunst_status) {.fullscreen=false, .running=true, .idle=false})
|
||||||
|
#define STATUS_IDLE ((struct dunst_status) {.fullscreen=false, .running=true, .idle=true})
|
||||||
|
#define STATUS_FSIDLE ((struct dunst_status) {.fullscreen=true, .running=true, .idle=true})
|
||||||
|
#define STATUS_FS ((struct dunst_status) {.fullscreen=true, .running=true, .idle=false})
|
||||||
|
#define STATUS_PAUSE ((struct dunst_status) {.fullscreen=false, .running=false, .idle=false})
|
||||||
|
|
||||||
|
#define QUEUE_WAIT waiting
|
||||||
|
#define QUEUE_DISP displayed
|
||||||
|
#define QUEUE_HIST history
|
||||||
|
#define QUEUE(q) QUEUE_##q
|
||||||
|
|
||||||
|
#define QUEUE_LEN_ALL(wait, disp, hist) do { \
|
||||||
|
if (wait >= 0) ASSERTm("Waiting is not " #wait, wait == g_queue_get_length(QUEUE(WAIT))); \
|
||||||
|
if (disp >= 0) ASSERTm("Displayed is not " #disp, disp == g_queue_get_length(QUEUE(DISP))); \
|
||||||
|
if (disp >= 0) ASSERTm("History is not " #hist, hist == g_queue_get_length(QUEUE(HIST))); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define QUEUE_CONTAINS(q, n) QUEUE_CONTAINSm("QUEUE_CONTAINS(" #q "," #n ")", q, n)
|
||||||
|
#define QUEUE_CONTAINSm(msg, q, n) ASSERTm(msg, g_queue_find(QUEUE(q), n))
|
||||||
|
|
||||||
|
#define NOT_LAST(n) do {ASSERT_EQm("Notification " #n " should have been deleted.", 1, notification_refcount_get(n)); g_clear_pointer(&n, notification_unref); } while(0)
|
||||||
|
|
||||||
|
static inline struct notification *test_notification(const char *name, gint64 timeout)
|
||||||
|
{
|
||||||
|
struct notification *n = notification_create();
|
||||||
|
|
||||||
|
if (timeout != -1)
|
||||||
|
n->timeout = S2US(timeout);
|
||||||
|
|
||||||
|
n->dbus_client = g_strconcat(":", name, NULL);
|
||||||
|
n->appname = g_strconcat("app of ", name, NULL);
|
||||||
|
n->summary = g_strconcat(name, NULL);
|
||||||
|
n->body = g_strconcat("See, ", name, ", I've got a body for you!", NULL);
|
||||||
|
|
||||||
|
n->format = "%s\n%b";
|
||||||
|
|
||||||
|
notification_init(n);
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
@ -15,6 +15,8 @@ SUITE_EXTERN(suite_notification);
|
|||||||
SUITE_EXTERN(suite_markup);
|
SUITE_EXTERN(suite_markup);
|
||||||
SUITE_EXTERN(suite_misc);
|
SUITE_EXTERN(suite_misc);
|
||||||
SUITE_EXTERN(suite_icon);
|
SUITE_EXTERN(suite_icon);
|
||||||
|
SUITE_EXTERN(suite_queues);
|
||||||
|
SUITE_EXTERN(suite_dunst);
|
||||||
|
|
||||||
GREATEST_MAIN_DEFS();
|
GREATEST_MAIN_DEFS();
|
||||||
|
|
||||||
@ -36,6 +38,8 @@ int main(int argc, char *argv[]) {
|
|||||||
RUN_SUITE(suite_markup);
|
RUN_SUITE(suite_markup);
|
||||||
RUN_SUITE(suite_misc);
|
RUN_SUITE(suite_misc);
|
||||||
RUN_SUITE(suite_icon);
|
RUN_SUITE(suite_icon);
|
||||||
|
RUN_SUITE(suite_queues);
|
||||||
|
RUN_SUITE(suite_dunst);
|
||||||
GREATEST_MAIN_END();
|
GREATEST_MAIN_END();
|
||||||
|
|
||||||
base = NULL;
|
base = NULL;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user