diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..6a4f79d7b --- /dev/null +++ b/.clang-format @@ -0,0 +1,12 @@ +--- +BasedOnStyle: LLVM +IndentWidth: 4 +AllowShortFunctionsOnASingleLine: Empty +BreakBeforeBraces: Mozilla +AllowShortCaseLabelsOnASingleLine: true +AlignConsecutiveShortCaseStatements: + Enabled: true +BreakBeforeBinaryOperators: NonAssignment +AlignOperands: AlignAfterOperator +BinPackArguments: false +BinPackParameters: false diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..927a525d5 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,55 @@ +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 8 +tab_width = 8 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[docs/*.pod] +indent_size = 4 + +[*.awk] +indent_size = 4 + +[{test/greatest.h,test/functional-tests/test.sh,contrib/notification-history.sh,contrib/dunst_xr_theme_changer.sh}] +indent_size = 4 + +[dunstrc*] +indent_size = 4 + +# Just for historical purposes to avoid +# manually reformatting whole files +[src/wayland/pool-buffer.*] +indent_style = tab + +# looks to be external code +[src/wayland/libgwater-wayland.*] +indent_size = 4 + +[completions/*] +indent_size = 4 + +[.valgrind.suppressions] +indent_size = 3 + +[*.yml] +indent_size = 2 + +[completions/*.zshcomp] +indent_size = 2 + +[{Makefile,dunstctl,test/data/test-ini}] +indent_style = tab + +[test/functional-tests/dunstrc.vertical_align] +indent_style = + +# Contains external or generated files +[src/wayland/protocols/**] +indent_style = +trim_trailing_whitespace = false diff --git a/.editorconfig-checker.json b/.editorconfig-checker.json new file mode 100644 index 000000000..777c303a9 --- /dev/null +++ b/.editorconfig-checker.json @@ -0,0 +1,6 @@ +{ + "SpacesAfterTabs": true, + "Disable": { + "IndentSize": true + } +} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9598926e6..658c6fd95 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -112,3 +112,14 @@ jobs: runs-on: ubuntu-latest container: image: ghcr.io/dunst-project/docker-images:misc-doxygen + + editorconfig: + steps: + - uses: actions/checkout@v4 + + - uses: editorconfig-checker/action-editorconfig-checker@main + + - name: Check code matching .editorconfig rules with editorconfig-checker + run: editorconfig-checker + + runs-on: ubuntu-latest diff --git a/HACKING.md b/HACKING.md index 621d85564..e38bf5c47 100644 --- a/HACKING.md +++ b/HACKING.md @@ -77,11 +77,11 @@ documentation for this can be found at https://github.com/dunst-project/docker-i # Comments - Comment system is held similar to JavaDoc - - Use `@param` to describe all input parameters - - Use `@return` to describe the output value - - Use `@retval` to describe special return values (like `NULL`) - - Documentation comments should start with a double star (`/**`) - - Append `()` to function names and prepend variables with `#` to properly reference them in the docs + - Use `@param` to describe all input parameters + - Use `@return` to describe the output value + - Use `@retval` to describe special return values (like `NULL`) + - Documentation comments should start with a double star (`/**`) + - Append `()` to function names and prepend variables with `#` to properly reference them in the docs - Add comments to all functions and methods - Markdown inside the comments is allowed and also desired - Add the comments to the prototype. Doxygen will merge the protoype and implementation documentation anyways. @@ -104,21 +104,21 @@ documentation for this can be found at https://github.com/dunst-project/docker-i For logging, there are printf-like macros `LOG_(E|C|W|M|I|D)`. - `LOG_E` (ERROR): - - All messages, which lead to immediate abort and are caused by a programming error. The program needs patching and the error is not user recoverable. - - e.g.: Switching over an enum, `LOG_E` would go into the default case. + - All messages, which lead to immediate abort and are caused by a programming error. The program needs patching and the error is not user recoverable. + - e.g.: Switching over an enum, `LOG_E` would go into the default case. - `LOG_C` (CRITICAL): - - The program cannot continue to work. It is used in the wrong manner or some outer conditions are not met. - - e.g.: `-config` parameter value is unreadable file + - The program cannot continue to work. It is used in the wrong manner or some outer conditions are not met. + - e.g.: `-config` parameter value is unreadable file - `DIE` (CRITICAL): - - A shorthand for `LOG_C` and terminating the program after. This does not dump the core (unlike `LOG_E`). + - A shorthand for `LOG_C` and terminating the program after. This does not dump the core (unlike `LOG_E`). - `LOG_W` (WARNING): - - Something is not in shape, but it's recoverable. - - e.g.: A value is not parsable in the config file, which will default. + - Something is not in shape, but it's recoverable. + - e.g.: A value is not parsable in the config file, which will default. - `LOG_M` (MESSAGE): - - Important info, which informs about the state. - - e.g.: An empty notification does get removed immediately. + - Important info, which informs about the state. + - e.g.: An empty notification does get removed immediately. - `LOG_I` (INFO): - - Mostly unneccessary info, but important to debug (as the user) some use cases. - - e.g.: print the notification contents after arriving + - Mostly unneccessary info, but important to debug (as the user) some use cases. + - e.g.: print the notification contents after arriving - `LOG_D` (DEBUG): - - Only important during development or tracing some bugs (as the developer). + - Only important during development or tracing some bugs (as the developer). diff --git a/Makefile b/Makefile index ba62927a2..6dfef8f6e 100644 --- a/Makefile +++ b/Makefile @@ -76,9 +76,9 @@ ${OBJ} ${TEST_OBJ}: Makefile config.mk DATE_FMT = +%Y-%m-%d ifdef SOURCE_DATE_EPOCH - BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "$(DATE_FMT)" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "$(DATE_FMT)" 2>/dev/null || date -u "$(DATE_FMT)") + BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "$(DATE_FMT)" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "$(DATE_FMT)" 2>/dev/null || date -u "$(DATE_FMT)") else - BUILD_DATE ?= $(shell date "$(DATE_FMT)") + BUILD_DATE ?= $(shell date "$(DATE_FMT)") endif src/dunst.o: src/dunst.c ${CC} -o $@ -c $< ${CPPFLAGS} ${CFLAGS} \ @@ -224,10 +224,10 @@ clean-wayland-protocols: rm -f src/wayland/protocols/*.h .PHONY: install install-dunst install-dunstctl install-dunstrc \ - install-service install-service-dbus install-service-systemd \ - uninstall uninstall-dunstctl uninstall-dunstrc \ - uninstall-service uninstall-service-dbus uninstall-service-systemd \ - uninstall-keepconf uninstall-purge + install-service install-service-dbus install-service-systemd \ + uninstall uninstall-dunstctl uninstall-dunstrc \ + uninstall-service uninstall-service-dbus uninstall-service-systemd \ + uninstall-keepconf uninstall-purge install: install-dunst install-dunstctl install-dunstrc install-service install-dunst: dunst doc diff --git a/completions/_dunstctl.zshcomp b/completions/_dunstctl.zshcomp index b05487b2c..ef35ed171 100644 --- a/completions/_dunstctl.zshcomp +++ b/completions/_dunstctl.zshcomp @@ -71,10 +71,10 @@ case $state in ;; history-pop) - local -a history_ids; - history_ids=( - `dunstctl history | jq -M '.data[0][].id.data'` - ) + local -a history_ids; + history_ids=( + `dunstctl history | jq -M '.data[0][].id.data'` + ) _describe history_ids history_ids && ret=0 ;; diff --git a/completions/dunst.bashcomp b/completions/dunst.bashcomp index 02658ff06..ea455c5a2 100644 --- a/completions/dunst.bashcomp +++ b/completions/dunst.bashcomp @@ -2,10 +2,10 @@ _dunst() { local opts cur prev split=false _get_comp_words_by_ref cur prev COMPREPLY=() - opts='-v -version --version -verbosity -conf -config -print --print -startup_notification --startup_notification -h -help --help' + opts='-v -version --version -verbosity -conf -config -print --print -startup_notification --startup_notification -h -help --help' case "$prev" in - -verbosity) COMPREPLY=( $( compgen -W 'crit warn mesg info debug' -- "$cur") ) + -verbosity) COMPREPLY=( $( compgen -W 'crit warn mesg info debug' -- "$cur") ) return ;; -conf|--config) _filedir return ;; diff --git a/contrib/notification-history.sh b/contrib/notification-history.sh index 00c5e57a6..2c6b79139 100755 --- a/contrib/notification-history.sh +++ b/contrib/notification-history.sh @@ -10,7 +10,7 @@ tests() { history_json="$(dunstctl history)" history_items="$(printf '%s' "$history_json" | jq -r '.data[0][] | .appname.data , (.timestamp.data | tostring) , .summary.data | gsub("[\\n]"; "\\n")')" # the gsub is to really ensure no escaped new lines in the data lead us to print new lines. New lines in data have to be escaped. (Because) Actual newlines are the field separator essential to the logic of the while loop below, and rofi further down. -#history_items ends up looking like arrays with an order with this meaning: +#history_items ends up looking like arrays with an order with this meaning: #appname (newline) timestamp (newline) summary (newline) # #NetworkManager diff --git a/docs/dunst.1.pod.in b/docs/dunst.1.pod.in index b21a74f07..2b54a2c59 100644 --- a/docs/dunst.1.pod.in +++ b/docs/dunst.1.pod.in @@ -111,11 +111,11 @@ See dunst(5) for the list of accepted hints. Some examples: - notify-send -h string:fgcolor:#ff4444 + notify-send -h string:fgcolor:#ff4444 - notify-send -h string:bgcolor:#4444ff -h string:fgcolor:#ff4444 -h string:frcolor:#44ff44 + notify-send -h string:bgcolor:#4444ff -h string:fgcolor:#ff4444 -h string:frcolor:#44ff44 - notify-send -h int:value:42 "Working ..." + notify-send -h int:value:42 "Working ..." =head1 MISCELLANEOUS diff --git a/docs/dunst.5.pod b/docs/dunst.5.pod index ecac33d2a..ad4e1d205 100644 --- a/docs/dunst.5.pod +++ b/docs/dunst.5.pod @@ -1122,7 +1122,7 @@ You may also specify a transparency component by using the format #RGBA or #RRGG B: '#' is interpreted as a comment, to use it the entire value needs to be quoted. For example: - separator_color="#123456" + separator_color="#123456" =head1 NOTIFY-SEND HINTS @@ -1183,11 +1183,11 @@ The transient value. Some examples: - notify-send -h string:fgcolor:#ff4444 + notify-send -h string:fgcolor:#ff4444 - notify-send -h string:bgcolor:#4444ff -h string:fgcolor:#ff4444 -h string:frcolor:#44ff44 + notify-send -h string:bgcolor:#4444ff -h string:fgcolor:#ff4444 -h string:frcolor:#44ff44 - notify-send -h int:value:42 "Working ..." + notify-send -h int:value:42 "Working ..." =head1 ACTIONS diff --git a/dunstify.c b/dunstify.c index b7cab9e49..b2f435d9f 100644 --- a/dunstify.c +++ b/dunstify.c @@ -1,10 +1,10 @@ +#include #include #include #include #include #include #include -#include static gchar *appname = "dunstify"; static gchar *summary = NULL; @@ -25,25 +25,107 @@ static guint32 close_id = 0; static gboolean block = false; static gchar **rest = NULL; -static GOptionEntry entries[] = -{ - { "appname", 'a', 0, G_OPTION_ARG_STRING, &appname, "Name of your application", "NAME" }, - { "urgency", 'u', 0, G_OPTION_ARG_STRING, &urgency_str, "The urgency of this notification", "URG" }, - { "hints", 'h', 0, G_OPTION_ARG_STRING_ARRAY, &hint_strs, "User specified hints", "HINT" }, - { "action", 'A', 0, G_OPTION_ARG_STRING_ARRAY, &action_strs, "Actions the user can invoke", "ACTION" }, - { "timeout", 't', 0, G_OPTION_ARG_INT, &timeout, "The time in milliseconds until the notification expires", "TIMEOUT" }, - { "icon", 'i', 0, G_OPTION_ARG_STRING, &icon, "An icon that should be displayed with the notification", "ICON" }, - { "raw_icon", 'I', 0, G_OPTION_ARG_STRING, &raw_icon_path, "Path to the icon to be sent as raw image data", "RAW_ICON"}, - { "category", 'c', 0, G_OPTION_ARG_STRING, &category, "The category of this notification", "TYPE" }, - { "capabilities", 0, 0, G_OPTION_ARG_NONE, &capabilities, "Print the server capabilities and exit", NULL }, - { "serverinfo", 's', 0, G_OPTION_ARG_NONE, &serverinfo, "Print server information and exit", NULL }, - { "printid", 'p', 0, G_OPTION_ARG_NONE, &printid, "Print id, which can be used to update/replace this notification", NULL }, - { "replace", 'r', 0, G_OPTION_ARG_INT, &replace_id, "Set id of this notification.", "ID" }, - { "close", 'C', 0, G_OPTION_ARG_INT, &close_id, "Close the notification with the specified ID", "ID" }, - { "block", 'b', 0, G_OPTION_ARG_NONE, &block, "Block until notification is closed and print close reason", NULL }, - { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &rest, NULL, NULL }, - { NULL } -}; +static GOptionEntry entries[] = { + {"appname", + 'a', + 0, + G_OPTION_ARG_STRING, + &appname, + "Name of your application", + "NAME"}, + {"urgency", + 'u', + 0, + G_OPTION_ARG_STRING, + &urgency_str, + "The urgency of this notification", + "URG"}, + {"hints", + 'h', + 0, + G_OPTION_ARG_STRING_ARRAY, + &hint_strs, + "User specified hints", + "HINT"}, + {"action", + 'A', + 0, + G_OPTION_ARG_STRING_ARRAY, + &action_strs, + "Actions the user can invoke", + "ACTION"}, + {"timeout", + 't', + 0, + G_OPTION_ARG_INT, + &timeout, + "The time in milliseconds until the notification expires", + "TIMEOUT"}, + {"icon", + 'i', + 0, + G_OPTION_ARG_STRING, + &icon, + "An icon that should be displayed with the notification", + "ICON"}, + {"raw_icon", + 'I', + 0, + G_OPTION_ARG_STRING, + &raw_icon_path, + "Path to the icon to be sent as raw image data", + "RAW_ICON"}, + {"category", + 'c', + 0, + G_OPTION_ARG_STRING, + &category, + "The category of this notification", + "TYPE"}, + {"capabilities", + 0, + 0, + G_OPTION_ARG_NONE, + &capabilities, + "Print the server capabilities and exit", + NULL}, + {"serverinfo", + 's', + 0, + G_OPTION_ARG_NONE, + &serverinfo, + "Print server information and exit", + NULL}, + {"printid", + 'p', + 0, + G_OPTION_ARG_NONE, + &printid, + "Print id, which can be used to update/replace this notification", + NULL}, + {"replace", + 'r', + 0, + G_OPTION_ARG_INT, + &replace_id, + "Set id of this notification.", + "ID"}, + {"close", + 'C', + 0, + G_OPTION_ARG_INT, + &close_id, + "Close the notification with the specified ID", + "ID"}, + {"block", + 'b', + 0, + G_OPTION_ARG_NONE, + &block, + "Block until notification is closed and print close reason", + NULL}, + {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &rest, NULL, NULL}, + {NULL}}; void die(int exit_value) { @@ -74,10 +156,11 @@ void print_serverinfo(void) exit(1); } - g_print("name:%s\nvendor:%s\nversion:%s\nspec_version:%s\n", name, - vendor, - version, - spec_version); + g_print("name:%s\nvendor:%s\nversion:%s\nspec_version:%s\n", + name, + vendor, + version, + spec_version); } /* @@ -98,7 +181,8 @@ char *get_argv(char *argv[], int index) } /* Count the number of arguments in argv excluding the terminator "--" */ -int count_args(char *argv[], int argc) { +int count_args(char *argv[], int argc) +{ for (int i = 0; i < argc; i++) { if (strcmp(argv[i], "--") == 0) return argc - 1; @@ -114,7 +198,7 @@ void parse_commandline(int argc, char *argv[]) context = g_option_context_new("SUMMARY [BODY]"); g_option_context_add_main_entries(context, entries, NULL); - if (!g_option_context_parse(context, &argc, &argv, &error)){ + if (!g_option_context_parse(context, &argc, &argv, &error)) { g_printerr("Invalid commandline: %s\n", error->message); exit(1); } @@ -143,8 +227,8 @@ void parse_commandline(int argc, char *argv[]) body = g_strcompress(rest[1]); if (rest[2] != NULL) { - g_printerr("Too many arguments!\n"); - die(1); + g_printerr("Too many arguments!\n"); + die(1); } } } @@ -156,25 +240,19 @@ void parse_commandline(int argc, char *argv[]) if (urgency_str) { switch (urgency_str[0]) { - case 'l': - case 'L': - case '0': - urgency = NOTIFY_URGENCY_LOW; - break; - case 'n': - case 'N': - case '1': - urgency = NOTIFY_URGENCY_NORMAL; - break; - case 'c': - case 'C': - case '2': - urgency = NOTIFY_URGENCY_CRITICAL; - break; - default: - g_printerr("Unknown urgency: %s\n", urgency_str); - g_printerr("Assuming normal urgency\n"); - break; + case 'l': + case 'L': + case '0': urgency = NOTIFY_URGENCY_LOW; break; + case 'n': + case 'N': + case '1': urgency = NOTIFY_URGENCY_NORMAL; break; + case 'c': + case 'C': + case '2': urgency = NOTIFY_URGENCY_CRITICAL; break; + default: + g_printerr("Unknown urgency: %s\n", urgency_str); + g_printerr("Assuming normal urgency\n"); + break; } } } @@ -209,8 +287,9 @@ void add_action(NotifyNotification *n, char *str) char *action = str; char *label = strchr(str, ','); - if (!label || *(label+1) == '\0') { - g_printerr("Malformed action. Expected \"action,label\", got \"%s\"", str); + if (!label || *(label + 1) == '\0') { + g_printerr("Malformed action. Expected \"action,label\", got \"%s\"", + str); return; } @@ -224,15 +303,17 @@ void add_hint(NotifyNotification *n, char *str) { char *type = str; char *name = strchr(str, ':'); - if (!name || *(name+1) == '\0') { - g_printerr("Malformed hint. Expected \"type:name:value\", got \"%s\"", str); + if (!name || *(name + 1) == '\0') { + g_printerr("Malformed hint. Expected \"type:name:value\", got \"%s\"", + str); return; } *name = '\0'; name++; char *value = strchr(name, ':'); - if (!value || *(value+1) == '\0') { - g_printerr("Malformed hint. Expected \"type:name:value\", got \"%s\"", str); + if (!value || *(value + 1) == '\0') { + g_printerr("Malformed hint. Expected \"type:name:value\", got \"%s\"", + str); return; } *value = '\0'; @@ -249,9 +330,11 @@ void add_hint(NotifyNotification *n, char *str) if (h_byte < 0 || h_byte > 0xFF) g_printerr("Not a byte: \"%s\"", value); else - notify_notification_set_hint_byte(n, name, (guchar) h_byte); + notify_notification_set_hint_byte(n, name, (guchar)h_byte); } else - g_printerr("Malformed hint. Expected a type of int, double, string or byte, got %s\n", type); + g_printerr("Malformed hint. Expected a type of int, double, string or " + "byte, got %s\n", + type); } int main(int argc, char *argv[]) @@ -259,9 +342,9 @@ int main(int argc, char *argv[]) setlocale(LC_ALL, ""); g_set_prgname(argv[0]); - #if !GLIB_CHECK_VERSION(2,35,0) - g_type_init(); - #endif +#if !GLIB_CHECK_VERSION(2, 35, 0) + g_type_init(); +#endif parse_commandline(argc, argv); @@ -283,14 +366,14 @@ int main(int argc, char *argv[]) GError *err = NULL; if (raw_icon_path) { - GdkPixbuf *raw_icon = gdk_pixbuf_new_from_file(raw_icon_path, &err); + GdkPixbuf *raw_icon = gdk_pixbuf_new_from_file(raw_icon_path, &err); - if(err) { - g_printerr("Unable to get raw icon: %s\n", err->message); - die(1); - } + if (err) { + g_printerr("Unable to get raw icon: %s\n", err->message); + die(1); + } - notify_notification_set_image_from_pixbuf(n, raw_icon); + notify_notification_set_image_from_pixbuf(n, raw_icon); } if (close_id > 0) { @@ -324,7 +407,6 @@ int main(int argc, char *argv[]) add_hint(n, hint_strs[i]); } - notify_notification_show(n, &err); if (err) { g_printerr("Unable to send notification: %s\n", err->message); @@ -339,7 +421,7 @@ int main(int argc, char *argv[]) if (block || action_strs) g_main_loop_run(l); - g_object_unref(G_OBJECT (n)); + g_object_unref(G_OBJECT(n)); die(0); } diff --git a/main.c b/main.c index 0f4f6849c..deeecfa6f 100644 --- a/main.c +++ b/main.c @@ -2,6 +2,6 @@ int main(int argc, char *argv[]) { - return dunst_main(argc, argv); + return dunst_main(argc, argv); } /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/dbus.c b/src/dbus.c index 8b8f95815..fd7f9abab 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -1,4 +1,5 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ #include "dbus.h" #include @@ -11,12 +12,12 @@ #include "log.h" #include "menu.h" #include "notification.h" +#include "option_parser.h" #include "queues.h" +#include "rules.h" #include "settings.h" #include "settings_data.h" #include "utils.h" -#include "rules.h" -#include "option_parser.h" #define FDN_PATH "/org/freedesktop/Notifications" #define FDN_IFAC "org.freedesktop.Notifications" @@ -34,8 +35,8 @@ static GDBusNodeInfo *introspection_data = NULL; static const char *introspection_xml = "" - "" - " " + "" + " " " " " " @@ -48,7 +49,8 @@ static const char *introspection_xml = " " " " " " - " " + " " " " " " " " @@ -74,7 +76,7 @@ static const char *introspection_xml = " " " " " " - " " + " " " " " " @@ -84,7 +86,8 @@ static const char *introspection_xml = " " " " " " - " " + " " " " " " " " @@ -98,7 +101,8 @@ static const char *introspection_xml = " " " " " " - " " + " " " " " " " " @@ -106,11 +110,13 @@ static const char *introspection_xml = " " " " - " " + " " " " " " - " " + " " " " " " @@ -132,33 +138,32 @@ static const char *introspection_xml = " " ""; -static const char *stack_tag_hints[] = { - "synchronous", - "private-synchronous", - "x-canonical-private-synchronous", - "x-dunst-stack-tag" -}; +static const char *stack_tag_hints[] = {"synchronous", + "private-synchronous", + "x-canonical-private-synchronous", + "x-dunst-stack-tag"}; -struct dbus_method { - const char *method_name; - void (*method) (GDBusConnection *connection, +struct dbus_method +{ + const char *method_name; + void (*method)(GDBusConnection *connection, const gchar *sender, GVariant *parameters, GDBusMethodInvocation *invocation); }; -#define DBUS_METHOD(name) static void dbus_cb_##name( \ - GDBusConnection *connection, \ - const gchar *sender, \ - GVariant *parameters, \ - GDBusMethodInvocation *invocation) +#define DBUS_METHOD(name) \ + static void dbus_cb_##name(GDBusConnection *connection, \ + const gchar *sender, \ + GVariant *parameters, \ + GDBusMethodInvocation *invocation) int cmp_methods(const void *vkey, const void *velem) { - const char *key = (const char*)vkey; - const struct dbus_method *m = (const struct dbus_method*)velem; + const char *key = (const char *)vkey; + const struct dbus_method *m = (const struct dbus_method *)velem; - return strcmp(key, m->method_name); + return strcmp(key, m->method_name); } DBUS_METHOD(Notify); @@ -166,34 +171,32 @@ DBUS_METHOD(CloseNotification); DBUS_METHOD(GetCapabilities); DBUS_METHOD(GetServerInformation); static struct dbus_method methods_fdn[] = { - {"CloseNotification", dbus_cb_CloseNotification}, - {"GetCapabilities", dbus_cb_GetCapabilities}, - {"GetServerInformation", dbus_cb_GetServerInformation}, - {"Notify", dbus_cb_Notify}, + {"CloseNotification", dbus_cb_CloseNotification}, + {"GetCapabilities", dbus_cb_GetCapabilities}, + {"GetServerInformation", dbus_cb_GetServerInformation}, + {"Notify", dbus_cb_Notify}, }; void dbus_cb_fdn_methods(GDBusConnection *connection, - const gchar *sender, - const gchar *object_path, - const gchar *interface_name, - const gchar *method_name, - GVariant *parameters, - GDBusMethodInvocation *invocation, - gpointer user_data) + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) { - struct dbus_method *m = bsearch(method_name, - methods_fdn, - G_N_ELEMENTS(methods_fdn), - sizeof(struct dbus_method), - cmp_methods); - - if (m) { - m->method(connection, sender, parameters, invocation); - } else { - LOG_M("Unknown method name: '%s' (sender: '%s').", - method_name, - sender); - } + struct dbus_method *m = bsearch(method_name, + methods_fdn, + G_N_ELEMENTS(methods_fdn), + sizeof(struct dbus_method), + cmp_methods); + + if (m) { + m->method(connection, sender, parameters, invocation); + } else { + LOG_M("Unknown method name: '%s' (sender: '%s').", method_name, sender); + } } DBUS_METHOD(dunst_ContextMenuCall); @@ -212,19 +215,20 @@ DBUS_METHOD(dunst_Ping); // NOTE: Keep the names sorted alphabetically static struct dbus_method methods_dunst[] = { - {"ConfigReload", dbus_cb_dunst_ConfigReload}, - {"ContextMenuCall", dbus_cb_dunst_ContextMenuCall}, - {"NotificationAction", dbus_cb_dunst_NotificationAction}, - {"NotificationClearHistory", dbus_cb_dunst_NotificationClearHistory}, - {"NotificationCloseAll", dbus_cb_dunst_NotificationCloseAll}, - {"NotificationCloseLast", dbus_cb_dunst_NotificationCloseLast}, - {"NotificationListHistory", dbus_cb_dunst_NotificationListHistory}, - {"NotificationPopHistory", dbus_cb_dunst_NotificationPopHistory}, - {"NotificationRemoveFromHistory", dbus_cb_dunst_NotificationRemoveFromHistory}, - {"NotificationShow", dbus_cb_dunst_NotificationShow}, - {"Ping", dbus_cb_dunst_Ping}, - {"RuleEnable", dbus_cb_dunst_RuleEnable}, - {"RuleList", dbus_cb_dunst_RuleList}, + {"ConfigReload", dbus_cb_dunst_ConfigReload}, + {"ContextMenuCall", dbus_cb_dunst_ContextMenuCall}, + {"NotificationAction", dbus_cb_dunst_NotificationAction}, + {"NotificationClearHistory", dbus_cb_dunst_NotificationClearHistory}, + {"NotificationCloseAll", dbus_cb_dunst_NotificationCloseAll}, + {"NotificationCloseLast", dbus_cb_dunst_NotificationCloseLast}, + {"NotificationListHistory", dbus_cb_dunst_NotificationListHistory}, + {"NotificationPopHistory", dbus_cb_dunst_NotificationPopHistory}, + {"NotificationRemoveFromHistory", + dbus_cb_dunst_NotificationRemoveFromHistory}, + {"NotificationShow", dbus_cb_dunst_NotificationShow}, + {"Ping", dbus_cb_dunst_Ping}, + {"RuleEnable", dbus_cb_dunst_RuleEnable}, + {"RuleList", dbus_cb_dunst_RuleList}, }; void dbus_cb_dunst_methods(GDBusConnection *connection, @@ -236,18 +240,17 @@ void dbus_cb_dunst_methods(GDBusConnection *connection, GDBusMethodInvocation *invocation, gpointer user_data) { - struct dbus_method *m = bsearch(method_name, - methods_dunst, - G_N_ELEMENTS(methods_dunst), - sizeof(struct dbus_method), - cmp_methods); - - if (m) { - m->method(connection, sender, parameters, invocation); - } else { - LOG_M("Unknown method name: '%s' (sender: '%s').", - method_name, sender); - } + struct dbus_method *m = bsearch(method_name, + methods_dunst, + G_N_ELEMENTS(methods_dunst), + sizeof(struct dbus_method), + cmp_methods); + + if (m) { + m->method(connection, sender, parameters, invocation); + } else { + LOG_M("Unknown method name: '%s' (sender: '%s').", method_name, sender); + } } static void dbus_cb_dunst_ContextMenuCall(GDBusConnection *connection, @@ -255,11 +258,11 @@ static void dbus_cb_dunst_ContextMenuCall(GDBusConnection *connection, GVariant *parameters, GDBusMethodInvocation *invocation) { - LOG_D("CMD: Calling context menu"); - context_menu(); + LOG_D("CMD: Calling context menu"); + context_menu(); - g_dbus_method_invocation_return_value(invocation, NULL); - g_dbus_connection_flush(connection, NULL, NULL, NULL); + g_dbus_method_invocation_return_value(invocation, NULL); + g_dbus_connection_flush(connection, NULL, NULL, NULL); } static void dbus_cb_dunst_NotificationAction(GDBusConnection *connection, @@ -267,74 +270,81 @@ static void dbus_cb_dunst_NotificationAction(GDBusConnection *connection, GVariant *parameters, GDBusMethodInvocation *invocation) { - guint32 notification_nr = 0; - g_variant_get(parameters, "(u)", ¬ification_nr); - - LOG_D("CMD: Calling action for notification %d", notification_nr); - - if (queues_length_waiting() < notification_nr) { - g_dbus_method_invocation_return_error(invocation, - G_DBUS_ERROR, - G_DBUS_ERROR_INVALID_ARGS, - "Couldn't activate action for notification in position %d, %d notifications currently open", - notification_nr, queues_length_waiting()); - return; - } - - struct notification *n = g_list_nth_data(queues_get_displayed(), notification_nr); - - if (n) { - LOG_D("CMD: Calling action for notification %s", n->summary); - notification_do_action(n); - } - - g_dbus_method_invocation_return_value(invocation, NULL); - g_dbus_connection_flush(connection, NULL, NULL, NULL); + guint32 notification_nr = 0; + g_variant_get(parameters, "(u)", ¬ification_nr); + + LOG_D("CMD: Calling action for notification %d", notification_nr); + + if (queues_length_waiting() < notification_nr) { + g_dbus_method_invocation_return_error( + invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + "Couldn't activate action for notification in position %d, %d " + "notifications currently open", + notification_nr, + queues_length_waiting()); + return; + } + + struct notification *n = + g_list_nth_data(queues_get_displayed(), notification_nr); + + if (n) { + LOG_D("CMD: Calling action for notification %s", n->summary); + notification_do_action(n); + } + + g_dbus_method_invocation_return_value(invocation, NULL); + g_dbus_connection_flush(connection, NULL, NULL, NULL); } -static void dbus_cb_dunst_NotificationClearHistory(GDBusConnection *connection, - const gchar *sender, - GVariant *parameters, - GDBusMethodInvocation *invocation) +static void +dbus_cb_dunst_NotificationClearHistory(GDBusConnection *connection, + const gchar *sender, + GVariant *parameters, + GDBusMethodInvocation *invocation) { - LOG_D("CMD: Clearing the history"); - guint n = queues_history_clear(); - wake_up(); + LOG_D("CMD: Clearing the history"); + guint n = queues_history_clear(); + wake_up(); - signal_history_cleared(n); + signal_history_cleared(n); - g_dbus_method_invocation_return_value(invocation, NULL); - g_dbus_connection_flush(connection, NULL, NULL, NULL); + g_dbus_method_invocation_return_value(invocation, NULL); + g_dbus_connection_flush(connection, NULL, NULL, NULL); } -static void dbus_cb_dunst_NotificationCloseAll(GDBusConnection *connection, - const gchar *sender, - GVariant *parameters, - GDBusMethodInvocation *invocation) +static void +dbus_cb_dunst_NotificationCloseAll(GDBusConnection *connection, + const gchar *sender, + GVariant *parameters, + GDBusMethodInvocation *invocation) { - LOG_D("CMD: Pushing all to history"); - queues_history_push_all(); - wake_up(); + LOG_D("CMD: Pushing all to history"); + queues_history_push_all(); + wake_up(); - g_dbus_method_invocation_return_value(invocation, NULL); - g_dbus_connection_flush(connection, NULL, NULL, NULL); + g_dbus_method_invocation_return_value(invocation, NULL); + g_dbus_connection_flush(connection, NULL, NULL, NULL); } -static void dbus_cb_dunst_NotificationCloseLast(GDBusConnection *connection, - const gchar *sender, - GVariant *parameters, - GDBusMethodInvocation *invocation) +static void +dbus_cb_dunst_NotificationCloseLast(GDBusConnection *connection, + const gchar *sender, + GVariant *parameters, + GDBusMethodInvocation *invocation) { - LOG_D("CMD: Closing last notification"); - const GList *list = queues_get_displayed(); - if (list && list->data) { - struct notification *n = list->data; - queues_notification_close_id(n->id, REASON_USER); - wake_up(); - } + LOG_D("CMD: Closing last notification"); + const GList *list = queues_get_displayed(); + if (list && list->data) { + struct notification *n = list->data; + queues_notification_close_id(n->id, REASON_USER); + wake_up(); + } - g_dbus_method_invocation_return_value(invocation, NULL); - g_dbus_connection_flush(connection, NULL, NULL, NULL); + g_dbus_method_invocation_return_value(invocation, NULL); + g_dbus_connection_flush(connection, NULL, NULL, NULL); } static void dbus_cb_dunst_NotificationShow(GDBusConnection *connection, @@ -342,144 +352,169 @@ static void dbus_cb_dunst_NotificationShow(GDBusConnection *connection, GVariant *parameters, GDBusMethodInvocation *invocation) { - LOG_D("CMD: Showing last notification from history"); - queues_history_pop(); - wake_up(); + LOG_D("CMD: Showing last notification from history"); + queues_history_pop(); + wake_up(); - g_dbus_method_invocation_return_value(invocation, NULL); - g_dbus_connection_flush(connection, NULL, NULL, NULL); + g_dbus_method_invocation_return_value(invocation, NULL); + g_dbus_connection_flush(connection, NULL, NULL, NULL); } -static void dbus_cb_dunst_NotificationListHistory(GDBusConnection *connection, - const gchar *sender, - GVariant *parameters, - GDBusMethodInvocation *invocation) +static void +dbus_cb_dunst_NotificationListHistory(GDBusConnection *connection, + const gchar *sender, + GVariant *parameters, + GDBusMethodInvocation *invocation) { - LOG_D("CMD: Listing all notifications from history"); - - GVariantBuilder builder; - g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}")); - - GList *notification_list = queues_get_history(); - - // reverse chronological list - for(int i = queues_length_history(); i > 0; i--) { - struct notification *n; - n = g_list_nth_data(notification_list, i-1); - - GVariantBuilder n_builder; - g_variant_builder_init(&n_builder, G_VARIANT_TYPE("a{sv}")); - - char *body, *msg, *summary, *appname, *category; - char *default_action_name, *icon_path; - char *urls, *stack_tag; - const char *urgency; - - body = (n->body == NULL) ? "" : n->body; - msg = (n->msg == NULL) ? "" : n->msg; - summary = (n->summary == NULL) ? "" : n->summary; - appname = (n->appname == NULL) ? "" : n->appname; - category = (n->category == NULL) ? "" : n->category; - default_action_name= (n->default_action_name == NULL) ? - "" : n->default_action_name; - icon_path = (n->icon_path == NULL) ? "" : n->icon_path; - urgency = notification_urgency_to_string(n->urgency); - urls = (n->urls == NULL) ? "" : n->urls; - stack_tag = (n->stack_tag == NULL) ? "" : n->stack_tag; - - g_variant_builder_add(&n_builder, "{sv}", "body", g_variant_new_string(body)); - g_variant_builder_add(&n_builder, "{sv}", "message", g_variant_new_string(msg)); - g_variant_builder_add(&n_builder, "{sv}", "summary", g_variant_new_string(summary)); - g_variant_builder_add(&n_builder, "{sv}", "appname", g_variant_new_string(appname)); - g_variant_builder_add(&n_builder, "{sv}", "category", g_variant_new_string(category)); - g_variant_builder_add(&n_builder, "{sv}", "default_action_name", - g_variant_new_string(default_action_name)); - g_variant_builder_add(&n_builder, "{sv}", "icon_path", g_variant_new_string(icon_path)); - g_variant_builder_add(&n_builder, "{sv}", "id", g_variant_new_int32(n->id)); - g_variant_builder_add(&n_builder, "{sv}", "timestamp", g_variant_new_int64(n->timestamp)); - g_variant_builder_add(&n_builder, "{sv}", "timeout", g_variant_new_int64(n->timeout)); - g_variant_builder_add(&n_builder, "{sv}", "progress", g_variant_new_int32(n->progress)); - g_variant_builder_add(&n_builder, "{sv}", "urgency", g_variant_new_string(urgency)); - g_variant_builder_add(&n_builder, "{sv}", "stack_tag", g_variant_new_string(stack_tag)); - g_variant_builder_add(&n_builder, "{sv}", "urls", g_variant_new_string(urls)); - - g_variant_builder_add(&builder, "a{sv}", &n_builder); - } - - g_dbus_method_invocation_return_value(invocation, g_variant_new("(aa{sv})", &builder)); - g_dbus_connection_flush(connection, NULL, NULL, NULL); + LOG_D("CMD: Listing all notifications from history"); + + GVariantBuilder builder; + g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}")); + + GList *notification_list = queues_get_history(); + + // reverse chronological list + for (int i = queues_length_history(); i > 0; i--) { + struct notification *n; + n = g_list_nth_data(notification_list, i - 1); + + GVariantBuilder n_builder; + g_variant_builder_init(&n_builder, G_VARIANT_TYPE("a{sv}")); + + char *body, *msg, *summary, *appname, *category; + char *default_action_name, *icon_path; + char *urls, *stack_tag; + const char *urgency; + + body = (n->body == NULL) ? "" : n->body; + msg = (n->msg == NULL) ? "" : n->msg; + summary = (n->summary == NULL) ? "" : n->summary; + appname = (n->appname == NULL) ? "" : n->appname; + category = (n->category == NULL) ? "" : n->category; + default_action_name = + (n->default_action_name == NULL) ? "" : n->default_action_name; + icon_path = (n->icon_path == NULL) ? "" : n->icon_path; + urgency = notification_urgency_to_string(n->urgency); + urls = (n->urls == NULL) ? "" : n->urls; + stack_tag = (n->stack_tag == NULL) ? "" : n->stack_tag; + + g_variant_builder_add( + &n_builder, "{sv}", "body", g_variant_new_string(body)); + g_variant_builder_add( + &n_builder, "{sv}", "message", g_variant_new_string(msg)); + g_variant_builder_add( + &n_builder, "{sv}", "summary", g_variant_new_string(summary)); + g_variant_builder_add( + &n_builder, "{sv}", "appname", g_variant_new_string(appname)); + g_variant_builder_add( + &n_builder, "{sv}", "category", g_variant_new_string(category)); + g_variant_builder_add(&n_builder, + "{sv}", + "default_action_name", + g_variant_new_string(default_action_name)); + g_variant_builder_add( + &n_builder, "{sv}", "icon_path", g_variant_new_string(icon_path)); + g_variant_builder_add( + &n_builder, "{sv}", "id", g_variant_new_int32(n->id)); + g_variant_builder_add( + &n_builder, "{sv}", "timestamp", g_variant_new_int64(n->timestamp)); + g_variant_builder_add( + &n_builder, "{sv}", "timeout", g_variant_new_int64(n->timeout)); + g_variant_builder_add( + &n_builder, "{sv}", "progress", g_variant_new_int32(n->progress)); + g_variant_builder_add( + &n_builder, "{sv}", "urgency", g_variant_new_string(urgency)); + g_variant_builder_add( + &n_builder, "{sv}", "stack_tag", g_variant_new_string(stack_tag)); + g_variant_builder_add( + &n_builder, "{sv}", "urls", g_variant_new_string(urls)); + + g_variant_builder_add(&builder, "a{sv}", &n_builder); + } + + g_dbus_method_invocation_return_value(invocation, + g_variant_new("(aa{sv})", &builder)); + g_dbus_connection_flush(connection, NULL, NULL, NULL); } -static void dbus_cb_dunst_NotificationPopHistory(GDBusConnection *connection, - const gchar *sender, - GVariant *parameters, - GDBusMethodInvocation *invocation) +static void +dbus_cb_dunst_NotificationPopHistory(GDBusConnection *connection, + const gchar *sender, + GVariant *parameters, + GDBusMethodInvocation *invocation) { - LOG_D("CMD: Popping notification from history"); + LOG_D("CMD: Popping notification from history"); - guint32 id; - g_variant_get(parameters, "(u)", &id); + guint32 id; + g_variant_get(parameters, "(u)", &id); - queues_history_pop_by_id(id); - wake_up(); + queues_history_pop_by_id(id); + wake_up(); - g_dbus_method_invocation_return_value(invocation, NULL); - g_dbus_connection_flush(connection, NULL, NULL, NULL); + g_dbus_method_invocation_return_value(invocation, NULL); + g_dbus_connection_flush(connection, NULL, NULL, NULL); } -static void dbus_cb_dunst_NotificationRemoveFromHistory(GDBusConnection *connection, - const gchar *sender, - GVariant *parameters, - GDBusMethodInvocation *invocation) +static void +dbus_cb_dunst_NotificationRemoveFromHistory(GDBusConnection *connection, + const gchar *sender, + GVariant *parameters, + GDBusMethodInvocation *invocation) { - LOG_D("CMD: Removing notification from history"); + LOG_D("CMD: Removing notification from history"); - guint32 id; - g_variant_get(parameters, "(u)", &id); + guint32 id; + g_variant_get(parameters, "(u)", &id); - if (queues_history_remove_by_id(id)) { - signal_history_removed(id); - wake_up(); - } + if (queues_history_remove_by_id(id)) { + signal_history_removed(id); + wake_up(); + } - g_dbus_method_invocation_return_value(invocation, NULL); - g_dbus_connection_flush(connection, NULL, NULL, NULL); + g_dbus_method_invocation_return_value(invocation, NULL); + g_dbus_connection_flush(connection, NULL, NULL, NULL); } -static const char *enum_to_string(const struct string_to_enum_def values[], int enum_value) +static const char *enum_to_string(const struct string_to_enum_def values[], + int enum_value) { - for (size_t i = 0; values[i].string != NULL; i++) { - if (values[i].enum_value == enum_value) { - return values[i].string; - } + for (size_t i = 0; values[i].string != NULL; i++) { + if (values[i].enum_value == enum_value) { + return values[i].string; } - return NULL; + } + return NULL; } -static void color_entry(const struct color c, GVariantDict *dict, const char *field_name) { - char buf[10]; - if (color_to_string(c, buf)) { - g_variant_dict_insert(dict, field_name, "s", buf); - } +static void +color_entry(const struct color c, GVariantDict *dict, const char *field_name) +{ + char buf[10]; + if (color_to_string(c, buf)) { + g_variant_dict_insert(dict, field_name, "s", buf); + } } -static void gradient_entry(const struct gradient *grad, GVariantDict *dict, const char *field_name) { - if (GRADIENT_VALID(grad)) { - if (grad->length == 1) { - color_entry(grad->colors[0], dict, field_name); - return; - } - - char **strv = g_malloc((grad->length + 1) * sizeof(char *)); - for (size_t i = 0; i < grad->length; i++) { - char buf[10]; - if (color_to_string(grad->colors[i], buf)) - strv[i] = g_strdup(buf); - } - strv[grad->length] = NULL; - - g_variant_dict_insert(dict, field_name, "^as", strv); +static void gradient_entry(const struct gradient *grad, + GVariantDict *dict, + const char *field_name) +{ + if (GRADIENT_VALID(grad)) { + if (grad->length == 1) { + color_entry(grad->colors[0], dict, field_name); + return; + } + + char **strv = g_malloc((grad->length + 1) * sizeof(char *)); + for (size_t i = 0; i < grad->length; i++) { + char buf[10]; + if (color_to_string(grad->colors[i], buf)) + strv[i] = g_strdup(buf); } + strv[grad->length] = NULL; + + g_variant_dict_insert(dict, field_name, "^as", strv); + } } static void dbus_cb_dunst_RuleList(GDBusConnection *connection, @@ -487,122 +522,149 @@ static void dbus_cb_dunst_RuleList(GDBusConnection *connection, GVariant *parameters, GDBusMethodInvocation *invocation) { - LOG_D("CMD: Listing all configured rules"); - - GVariantBuilder builder; - g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}")); - - for (GSList *iter = rules; iter; iter = iter->next) { - struct rule *r = iter->data; - - if (is_special_section(r->name)) { - continue; - } - - GVariantDict dict; - g_variant_dict_init(&dict, NULL); - g_variant_dict_insert(&dict, "name", "s", r->name); - - // filters - order according to rule_matches_notification - g_variant_dict_insert(&dict, "enabled", "b", BOOL2G(r->enabled)); - // undocumented filter? - if (r->match_dbus_timeout > -1) - g_variant_dict_insert(&dict, "match_dbus_timeout", "i", r->match_dbus_timeout); - if (r->msg_urgency != URG_NONE) - g_variant_dict_insert(&dict, - "msg_urgency", - "s", - enum_to_string(urgency_enum_data, r->msg_urgency)); - if (r->match_transient > -1) - g_variant_dict_insert(&dict, "match_transient", "b", BOOL2G(r->match_transient)); - if (r->appname) - g_variant_dict_insert(&dict, "appname", "s", r->appname); - if (r->desktop_entry) - g_variant_dict_insert(&dict, "desktop_entry", "s", r->desktop_entry); - if (r->summary) - g_variant_dict_insert(&dict, "summary", "s", r->summary); - if (r->body) - g_variant_dict_insert(&dict, "body", "s", r->body); - if (r->category) - g_variant_dict_insert(&dict, "category", "s", r->category); - if (r->stack_tag) - g_variant_dict_insert(&dict, "stack_tag", "s", r->stack_tag); - - // settings to apply - order according to rule_apply - if (r->timeout != -1) - g_variant_dict_insert(&dict, "timeout", "x", r->timeout); - if (r->override_dbus_timeout != -1) - g_variant_dict_insert(&dict, "override_dbus_timeout", "x", r->override_dbus_timeout); - if (r->urgency != URG_NONE) - g_variant_dict_insert(&dict, "urgency", "s", enum_to_string(urgency_enum_data, r->urgency)); - if (r->fullscreen != FS_NULL) - g_variant_dict_insert(&dict, - "fullscreen", - "s", - enum_to_string(fullscreen_enum_data, r->fullscreen)); - if (r->history_ignore != -1) - g_variant_dict_insert(&dict, "history_ignore", "b", BOOL2G(r->history_ignore)); - if (r->set_transient != -1) - g_variant_dict_insert(&dict, "set_transient", "b", BOOL2G(r->set_transient)); - if (r->skip_display != -1) - g_variant_dict_insert(&dict, "skip_display", "b", BOOL2G(r->skip_display)); - if (r->word_wrap != -1) - g_variant_dict_insert(&dict, "word_wrap", "b", BOOL2G(r->word_wrap)); - if (r->ellipsize != -1) - g_variant_dict_insert(&dict, - "ellipsize", - "s", - enum_to_string(ellipsize_enum_data, r->ellipsize)); - if (r->alignment != -1) - g_variant_dict_insert(&dict, - "alignment", - "s", - enum_to_string(horizontal_alignment_enum_data, r->alignment)); - if (r->hide_text != -1) - g_variant_dict_insert(&dict, "hide_text", "b", BOOL2G(r->hide_text)); - if (r->progress_bar_alignment != -1) - g_variant_dict_insert(&dict, - "progress_bar_alignment", - "s", - enum_to_string(horizontal_alignment_enum_data, - r->progress_bar_alignment)); - if (r->min_icon_size != -1) - g_variant_dict_insert(&dict, "min_icon_size", "i", r->min_icon_size); - if (r->max_icon_size != -1) - g_variant_dict_insert(&dict, "max_icon_size", "i", r->max_icon_size); - if (r->action_name) - g_variant_dict_insert(&dict, "action_name", "s", r->action_name); - if (r->set_category) - g_variant_dict_insert(&dict, "set_category", "s", r->set_category); - if (r->markup != MARKUP_NULL) - g_variant_dict_insert(&dict, "markup", "s", enum_to_string(markup_mode_enum_data, r->markup)); - if (r->icon_position != -1) - g_variant_dict_insert(&dict, - "icon_position", - "s", - enum_to_string(icon_position_enum_data, r->icon_position)); - color_entry(r->fg, &dict, "fg"); - color_entry(r->bg, &dict, "bg"); - gradient_entry(r->highlight, &dict, "highlight"); - color_entry(r->fc, &dict, "fc"); - if (r->format) - g_variant_dict_insert(&dict, "format", "s", r->format); - if (r->default_icon) - g_variant_dict_insert(&dict, "default_icon", "s", r->default_icon); - if (r->new_icon) - g_variant_dict_insert(&dict, "new_icon", "s", r->new_icon); - if (r->script) - g_variant_dict_insert(&dict, "script", "s", r->script); - if (r->set_stack_tag) - g_variant_dict_insert(&dict, "set_stack_tag", "s", r->set_stack_tag); - if (r->override_pause_level != -1) - g_variant_dict_insert(&dict, "override_pause_level", "i", r->override_pause_level); - - g_variant_builder_add_value(&builder, g_variant_dict_end(&dict)); + LOG_D("CMD: Listing all configured rules"); + + GVariantBuilder builder; + g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}")); + + for (GSList *iter = rules; iter; iter = iter->next) { + struct rule *r = iter->data; + + if (is_special_section(r->name)) { + continue; } - g_dbus_method_invocation_return_value(invocation, g_variant_new("(aa{sv})", &builder)); - g_dbus_connection_flush(connection, NULL, NULL, NULL); + GVariantDict dict; + g_variant_dict_init(&dict, NULL); + g_variant_dict_insert(&dict, "name", "s", r->name); + + // filters - order according to rule_matches_notification + g_variant_dict_insert(&dict, "enabled", "b", BOOL2G(r->enabled)); + // undocumented filter? + if (r->match_dbus_timeout > -1) + g_variant_dict_insert( + &dict, "match_dbus_timeout", "i", r->match_dbus_timeout); + if (r->msg_urgency != URG_NONE) + g_variant_dict_insert( + &dict, + "msg_urgency", + "s", + enum_to_string(urgency_enum_data, r->msg_urgency)); + if (r->match_transient > -1) + g_variant_dict_insert( + &dict, "match_transient", "b", BOOL2G(r->match_transient)); + if (r->appname) + g_variant_dict_insert(&dict, "appname", "s", r->appname); + if (r->desktop_entry) + g_variant_dict_insert( + &dict, "desktop_entry", "s", r->desktop_entry); + if (r->summary) + g_variant_dict_insert(&dict, "summary", "s", r->summary); + if (r->body) + g_variant_dict_insert(&dict, "body", "s", r->body); + if (r->category) + g_variant_dict_insert(&dict, "category", "s", r->category); + if (r->stack_tag) + g_variant_dict_insert(&dict, "stack_tag", "s", r->stack_tag); + + // settings to apply - order according to rule_apply + if (r->timeout != -1) + g_variant_dict_insert(&dict, "timeout", "x", r->timeout); + if (r->override_dbus_timeout != -1) + g_variant_dict_insert( + &dict, "override_dbus_timeout", "x", r->override_dbus_timeout); + if (r->urgency != URG_NONE) + g_variant_dict_insert( + &dict, + "urgency", + "s", + enum_to_string(urgency_enum_data, r->urgency)); + if (r->fullscreen != FS_NULL) + g_variant_dict_insert( + &dict, + "fullscreen", + "s", + enum_to_string(fullscreen_enum_data, r->fullscreen)); + if (r->history_ignore != -1) + g_variant_dict_insert( + &dict, "history_ignore", "b", BOOL2G(r->history_ignore)); + if (r->set_transient != -1) + g_variant_dict_insert( + &dict, "set_transient", "b", BOOL2G(r->set_transient)); + if (r->skip_display != -1) + g_variant_dict_insert( + &dict, "skip_display", "b", BOOL2G(r->skip_display)); + if (r->word_wrap != -1) + g_variant_dict_insert( + &dict, "word_wrap", "b", BOOL2G(r->word_wrap)); + if (r->ellipsize != -1) + g_variant_dict_insert( + &dict, + "ellipsize", + "s", + enum_to_string(ellipsize_enum_data, r->ellipsize)); + if (r->alignment != -1) + g_variant_dict_insert( + &dict, + "alignment", + "s", + enum_to_string(horizontal_alignment_enum_data, r->alignment)); + if (r->hide_text != -1) + g_variant_dict_insert( + &dict, "hide_text", "b", BOOL2G(r->hide_text)); + if (r->progress_bar_alignment != -1) + g_variant_dict_insert(&dict, + "progress_bar_alignment", + "s", + enum_to_string(horizontal_alignment_enum_data, + r->progress_bar_alignment)); + if (r->min_icon_size != -1) + g_variant_dict_insert( + &dict, "min_icon_size", "i", r->min_icon_size); + if (r->max_icon_size != -1) + g_variant_dict_insert( + &dict, "max_icon_size", "i", r->max_icon_size); + if (r->action_name) + g_variant_dict_insert(&dict, "action_name", "s", r->action_name); + if (r->set_category) + g_variant_dict_insert(&dict, "set_category", "s", r->set_category); + if (r->markup != MARKUP_NULL) + g_variant_dict_insert( + &dict, + "markup", + "s", + enum_to_string(markup_mode_enum_data, r->markup)); + if (r->icon_position != -1) + g_variant_dict_insert( + &dict, + "icon_position", + "s", + enum_to_string(icon_position_enum_data, r->icon_position)); + color_entry(r->fg, &dict, "fg"); + color_entry(r->bg, &dict, "bg"); + gradient_entry(r->highlight, &dict, "highlight"); + color_entry(r->fc, &dict, "fc"); + if (r->format) + g_variant_dict_insert(&dict, "format", "s", r->format); + if (r->default_icon) + g_variant_dict_insert(&dict, "default_icon", "s", r->default_icon); + if (r->new_icon) + g_variant_dict_insert(&dict, "new_icon", "s", r->new_icon); + if (r->script) + g_variant_dict_insert(&dict, "script", "s", r->script); + if (r->set_stack_tag) + g_variant_dict_insert( + &dict, "set_stack_tag", "s", r->set_stack_tag); + if (r->override_pause_level != -1) + g_variant_dict_insert( + &dict, "override_pause_level", "i", r->override_pause_level); + + g_variant_builder_add_value(&builder, g_variant_dict_end(&dict)); + } + + g_dbus_method_invocation_return_value(invocation, + g_variant_new("(aa{sv})", &builder)); + g_dbus_connection_flush(connection, NULL, NULL, NULL); } static void dbus_cb_dunst_RuleEnable(GDBusConnection *connection, @@ -610,44 +672,45 @@ static void dbus_cb_dunst_RuleEnable(GDBusConnection *connection, GVariant *parameters, GDBusMethodInvocation *invocation) { - // dbus param state: 0 → disable, 1 → enable, 2 → toggle. - - int state = 0; - char *name = NULL; - g_variant_get(parameters, "(si)", &name, &state); - - LOG_D("CMD: Changing rule \"%s\" enable state to %d", name, state); - - if (state < 0 || state > 2) { - g_dbus_method_invocation_return_error(invocation, - G_DBUS_ERROR, - G_DBUS_ERROR_INVALID_ARGS, - "Couldn't understand state %d. It must be 0, 1 or 2", - state); - return; - } - - struct rule *target_rule = get_rule(name); - g_free(name); - - if (target_rule == NULL) { - g_dbus_method_invocation_return_error(invocation, - G_DBUS_ERROR, - G_DBUS_ERROR_INVALID_ARGS, - "There is no rule named \"%s\"", - name); - return; - } - - if (state == 0) - target_rule->enabled = false; - else if (state == 1) - target_rule->enabled = true; - else if (state == 2) - target_rule->enabled = !target_rule->enabled; - - g_dbus_method_invocation_return_value(invocation, NULL); - g_dbus_connection_flush(connection, NULL, NULL, NULL); + // dbus param state: 0 → disable, 1 → enable, 2 → toggle. + + int state = 0; + char *name = NULL; + g_variant_get(parameters, "(si)", &name, &state); + + LOG_D("CMD: Changing rule \"%s\" enable state to %d", name, state); + + if (state < 0 || state > 2) { + g_dbus_method_invocation_return_error( + invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + "Couldn't understand state %d. It must be 0, 1 or 2", + state); + return; + } + + struct rule *target_rule = get_rule(name); + g_free(name); + + if (target_rule == NULL) { + g_dbus_method_invocation_return_error(invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + "There is no rule named \"%s\"", + name); + return; + } + + if (state == 0) + target_rule->enabled = false; + else if (state == 1) + target_rule->enabled = true; + else if (state == 2) + target_rule->enabled = !target_rule->enabled; + + g_dbus_method_invocation_return_value(invocation, NULL); + g_dbus_connection_flush(connection, NULL, NULL, NULL); } static void dbus_cb_dunst_ConfigReload(GDBusConnection *connection, @@ -655,492 +718,508 @@ static void dbus_cb_dunst_ConfigReload(GDBusConnection *connection, GVariant *parameters, GDBusMethodInvocation *invocation) { - gchar **configs = NULL; - g_variant_get(parameters, "(^as)", &configs); - reload(configs); + gchar **configs = NULL; + g_variant_get(parameters, "(^as)", &configs); + reload(configs); - signal_config_reloaded(configs); + signal_config_reloaded(configs); - g_dbus_method_invocation_return_value(invocation, NULL); - g_dbus_connection_flush(connection, NULL, NULL, NULL); + g_dbus_method_invocation_return_value(invocation, NULL); + g_dbus_connection_flush(connection, NULL, NULL, NULL); } -/* Just a simple Ping command to give the ability to dunstctl to test for the existence of this interface - * Any other way requires parsing the XML of the Introspection or other foo. Just calling the Ping on an old dunst version will fail. */ +/* Just a simple Ping command to give the ability to dunstctl to test for the + * existence of this interface Any other way requires parsing the XML of the + * Introspection or other foo. Just calling the Ping on an old dunst version + * will fail. */ static void dbus_cb_dunst_Ping(GDBusConnection *connection, const gchar *sender, GVariant *parameters, GDBusMethodInvocation *invocation) { - g_dbus_method_invocation_return_value(invocation, NULL); - g_dbus_connection_flush(connection, NULL, NULL, NULL); + g_dbus_method_invocation_return_value(invocation, NULL); + g_dbus_connection_flush(connection, NULL, NULL, NULL); } - -static void dbus_cb_GetCapabilities( - GDBusConnection *connection, - const gchar *sender, - GVariant *parameters, - GDBusMethodInvocation *invocation) +static void dbus_cb_GetCapabilities(GDBusConnection *connection, + const gchar *sender, + GVariant *parameters, + GDBusMethodInvocation *invocation) { - GVariantBuilder *builder; - GVariant *value; - - builder = g_variant_builder_new(G_VARIANT_TYPE("as")); - g_variant_builder_add(builder, "s", "actions"); - g_variant_builder_add(builder, "s", "body"); - g_variant_builder_add(builder, "s", "body-hyperlinks"); - g_variant_builder_add(builder, "s", "icon-static"); - - for (size_t i = 0; i < sizeof(stack_tag_hints)/sizeof(*stack_tag_hints); ++i) - g_variant_builder_add(builder, "s", stack_tag_hints[i]); - - // Since markup isn't a global variable anymore, look it up in the - // global rule - struct rule *global_rule = get_rule("global"); - if (global_rule && global_rule->markup != MARKUP_NO) - g_variant_builder_add(builder, "s", "body-markup"); - - value = g_variant_new("(as)", builder); - g_clear_pointer(&builder, g_variant_builder_unref); - g_dbus_method_invocation_return_value(invocation, value); - - g_dbus_connection_flush(connection, NULL, NULL, NULL); + GVariantBuilder *builder; + GVariant *value; + + builder = g_variant_builder_new(G_VARIANT_TYPE("as")); + g_variant_builder_add(builder, "s", "actions"); + g_variant_builder_add(builder, "s", "body"); + g_variant_builder_add(builder, "s", "body-hyperlinks"); + g_variant_builder_add(builder, "s", "icon-static"); + + for (size_t i = 0; i < sizeof(stack_tag_hints) / sizeof(*stack_tag_hints); + ++i) + g_variant_builder_add(builder, "s", stack_tag_hints[i]); + + // Since markup isn't a global variable anymore, look it up in the + // global rule + struct rule *global_rule = get_rule("global"); + if (global_rule && global_rule->markup != MARKUP_NO) + g_variant_builder_add(builder, "s", "body-markup"); + + value = g_variant_new("(as)", builder); + g_clear_pointer(&builder, g_variant_builder_unref); + g_dbus_method_invocation_return_value(invocation, value); + + g_dbus_connection_flush(connection, NULL, NULL, NULL); } -static struct notification *dbus_message_to_notification(const gchar *sender, GVariant *parameters) +static struct notification *dbus_message_to_notification(const gchar *sender, + GVariant *parameters) { - /* Assert that the parameters' type is actually correct. Albeit usually DBus - * already rejects ill typed parameters, it may not be always the case. */ - GVariantType *required_type = g_variant_type_new("(susssasa{sv}i)"); - if (!g_variant_is_of_type(parameters, required_type)) { - g_variant_type_free(required_type); - return NULL; - } - - struct notification *n = notification_create(); - n->dbus_client = g_strdup(sender); - n->dbus_valid = true; - - GVariant *hints; - gchar **actions; - int timeout; - - GVariantIter i; - g_variant_iter_init(&i, parameters); - - g_variant_iter_next(&i, "s", &n->appname); - g_variant_iter_next(&i, "u", &n->id); - g_variant_iter_next(&i, "s", &n->iconname); - g_variant_iter_next(&i, "s", &n->summary); - g_variant_iter_next(&i, "s", &n->body); - g_variant_iter_next(&i, "^a&s", &actions); - g_variant_iter_next(&i, "@a{?*}", &hints); - g_variant_iter_next(&i, "i", &timeout); - - gsize num = 0; - while (actions[num]) { - if (actions[num+1]) { - g_hash_table_insert(n->actions, - g_strdup(actions[num]), - g_strdup(actions[num+1])); - num+=2; - } else { - LOG_W("Odd length in actions array. Ignoring element: %s", actions[num]); - break; - } - } - - GVariant *dict_value; - GVariant *icon_value = NULL; - - // First process the items that can be filtered on - if ((dict_value = g_variant_lookup_value(hints, "urgency", G_VARIANT_TYPE_BYTE))) { - n->urgency = g_variant_get_byte(dict_value); - g_variant_unref(dict_value); - } - - if ((dict_value = g_variant_lookup_value(hints, "category", G_VARIANT_TYPE_STRING))) { - n->category = g_variant_dup_string(dict_value, NULL); - g_variant_unref(dict_value); - } - - if ((dict_value = g_variant_lookup_value(hints, "desktop-entry", G_VARIANT_TYPE_STRING))) { - n->desktop_entry = g_variant_dup_string(dict_value, NULL); - g_variant_unref(dict_value); - } - - if ((dict_value = g_variant_lookup_value(hints, "value", G_VARIANT_TYPE_INT32))) { - n->progress = g_variant_get_int32(dict_value); - g_variant_unref(dict_value); - } else if ((dict_value = g_variant_lookup_value(hints, "value", G_VARIANT_TYPE_UINT32))) { - n->progress = g_variant_get_uint32(dict_value); - g_variant_unref(dict_value); - } - if (n->progress < 0) - n->progress = -1; - - /* Check for hints that define the stack_tag - * - * Only accept to first one we find. - */ - for (size_t i = 0; i < sizeof(stack_tag_hints)/sizeof(*stack_tag_hints); ++i) { - if ((dict_value = g_variant_lookup_value(hints, stack_tag_hints[i], G_VARIANT_TYPE_STRING))) { - n->stack_tag = g_variant_dup_string(dict_value, NULL); - g_variant_unref(dict_value); - break; - } - } - - /* Check for transient hints - * - * According to the spec, the transient hint should be boolean. - * But notify-send does not support hints of type 'boolean'. - * So let's check for int and boolean until notify-send is fixed. - */ - if ((dict_value = g_variant_lookup_value(hints, "transient", G_VARIANT_TYPE_BOOLEAN))) { - n->transient = g_variant_get_boolean(dict_value); - g_variant_unref(dict_value); - } else if ((dict_value = g_variant_lookup_value(hints, "transient", G_VARIANT_TYPE_UINT32))) { - n->transient = g_variant_get_uint32(dict_value) > 0; - g_variant_unref(dict_value); - } else if ((dict_value = g_variant_lookup_value(hints, "transient", G_VARIANT_TYPE_INT32))) { - n->transient = g_variant_get_int32(dict_value) > 0; - g_variant_unref(dict_value); - } - - dict_value = g_variant_lookup_value(hints, "image-path", G_VARIANT_TYPE_STRING); - if (!dict_value) - dict_value = g_variant_lookup_value(hints, "image_path", G_VARIANT_TYPE_STRING); - - if (dict_value) { - g_free(n->iconname); - n->iconname = g_variant_dup_string(dict_value, NULL); - g_variant_unref(dict_value); + /* Assert that the parameters' type is actually correct. Albeit usually DBus + * already rejects ill typed parameters, it may not be always the case. */ + GVariantType *required_type = g_variant_type_new("(susssasa{sv}i)"); + if (!g_variant_is_of_type(parameters, required_type)) { + g_variant_type_free(required_type); + return NULL; + } + + struct notification *n = notification_create(); + n->dbus_client = g_strdup(sender); + n->dbus_valid = true; + + GVariant *hints; + gchar **actions; + int timeout; + + GVariantIter i; + g_variant_iter_init(&i, parameters); + + g_variant_iter_next(&i, "s", &n->appname); + g_variant_iter_next(&i, "u", &n->id); + g_variant_iter_next(&i, "s", &n->iconname); + g_variant_iter_next(&i, "s", &n->summary); + g_variant_iter_next(&i, "s", &n->body); + g_variant_iter_next(&i, "^a&s", &actions); + g_variant_iter_next(&i, "@a{?*}", &hints); + g_variant_iter_next(&i, "i", &timeout); + + gsize num = 0; + while (actions[num]) { + if (actions[num + 1]) { + g_hash_table_insert( + n->actions, g_strdup(actions[num]), g_strdup(actions[num + 1])); + num += 2; + } else { + LOG_W("Odd length in actions array. Ignoring element: %s", + actions[num]); + break; } - - // Set raw icon data only after initializing the notification, so the - // desired icon size is known. This way the buffer can be immediately - // rescaled. If at some point you might want to match by if a - // notificaton has an image, this has to be reworked. - dict_value = g_variant_lookup_value(hints, "image-data", G_VARIANT_TYPE("(iiibiiay)")); - if (!dict_value) - dict_value = g_variant_lookup_value(hints, "image_data", G_VARIANT_TYPE("(iiibiiay)")); - if (!dict_value) - dict_value = g_variant_lookup_value(hints, "icon_data", G_VARIANT_TYPE("(iiibiiay)")); - if (dict_value) { - // Signal that the notification is still waiting for a raw - // icon. It cannot be set now, because min_icon_size and - // max_icon_size aren't known yet. It cannot be set later, - // because it has to be overwritten by the new_icon rule. - n->receiving_raw_icon = true; - icon_value = dict_value; - dict_value = NULL; + } + + GVariant *dict_value; + GVariant *icon_value = NULL; + + // First process the items that can be filtered on + if ((dict_value = + g_variant_lookup_value(hints, "urgency", G_VARIANT_TYPE_BYTE))) { + n->urgency = g_variant_get_byte(dict_value); + g_variant_unref(dict_value); + } + + if ((dict_value = g_variant_lookup_value( + hints, "category", G_VARIANT_TYPE_STRING))) { + n->category = g_variant_dup_string(dict_value, NULL); + g_variant_unref(dict_value); + } + + if ((dict_value = g_variant_lookup_value( + hints, "desktop-entry", G_VARIANT_TYPE_STRING))) { + n->desktop_entry = g_variant_dup_string(dict_value, NULL); + g_variant_unref(dict_value); + } + + if ((dict_value = + g_variant_lookup_value(hints, "value", G_VARIANT_TYPE_INT32))) { + n->progress = g_variant_get_int32(dict_value); + g_variant_unref(dict_value); + } else if ((dict_value = g_variant_lookup_value( + hints, "value", G_VARIANT_TYPE_UINT32))) { + n->progress = g_variant_get_uint32(dict_value); + g_variant_unref(dict_value); + } + if (n->progress < 0) + n->progress = -1; + + /* Check for hints that define the stack_tag + * + * Only accept to first one we find. + */ + for (size_t i = 0; i < sizeof(stack_tag_hints) / sizeof(*stack_tag_hints); + ++i) { + if ((dict_value = g_variant_lookup_value( + hints, stack_tag_hints[i], G_VARIANT_TYPE_STRING))) { + n->stack_tag = g_variant_dup_string(dict_value, NULL); + g_variant_unref(dict_value); + break; } - - // Set the dbus timeout - if (timeout >= 0) - n->dbus_timeout = ((gint64)timeout) * 1000; - - // All attributes that have to be set before initializations are set, - // so we can initialize the notification. This applies all rules that - // are defined and applies the formatting to the message. - notification_init(n); - - if (icon_value) { - if (n->receiving_raw_icon) - notification_icon_replace_data(n, icon_value); - g_variant_unref(icon_value); + } + + /* Check for transient hints + * + * According to the spec, the transient hint should be boolean. + * But notify-send does not support hints of type 'boolean'. + * So let's check for int and boolean until notify-send is fixed. + */ + if ((dict_value = g_variant_lookup_value( + hints, "transient", G_VARIANT_TYPE_BOOLEAN))) { + n->transient = g_variant_get_boolean(dict_value); + g_variant_unref(dict_value); + } else if ((dict_value = g_variant_lookup_value( + hints, "transient", G_VARIANT_TYPE_UINT32))) { + n->transient = g_variant_get_uint32(dict_value) > 0; + g_variant_unref(dict_value); + } else if ((dict_value = g_variant_lookup_value( + hints, "transient", G_VARIANT_TYPE_INT32))) { + n->transient = g_variant_get_int32(dict_value) > 0; + g_variant_unref(dict_value); + } + + dict_value = + g_variant_lookup_value(hints, "image-path", G_VARIANT_TYPE_STRING); + if (!dict_value) + dict_value = + g_variant_lookup_value(hints, "image_path", G_VARIANT_TYPE_STRING); + + if (dict_value) { + g_free(n->iconname); + n->iconname = g_variant_dup_string(dict_value, NULL); + g_variant_unref(dict_value); + } + + // Set raw icon data only after initializing the notification, so the + // desired icon size is known. This way the buffer can be immediately + // rescaled. If at some point you might want to match by if a + // notificaton has an image, this has to be reworked. + dict_value = g_variant_lookup_value( + hints, "image-data", G_VARIANT_TYPE("(iiibiiay)")); + if (!dict_value) + dict_value = g_variant_lookup_value( + hints, "image_data", G_VARIANT_TYPE("(iiibiiay)")); + if (!dict_value) + dict_value = g_variant_lookup_value( + hints, "icon_data", G_VARIANT_TYPE("(iiibiiay)")); + if (dict_value) { + // Signal that the notification is still waiting for a raw + // icon. It cannot be set now, because min_icon_size and + // max_icon_size aren't known yet. It cannot be set later, + // because it has to be overwritten by the new_icon rule. + n->receiving_raw_icon = true; + icon_value = dict_value; + dict_value = NULL; + } + + // Set the dbus timeout + if (timeout >= 0) + n->dbus_timeout = ((gint64)timeout) * 1000; + + // All attributes that have to be set before initializations are set, + // so we can initialize the notification. This applies all rules that + // are defined and applies the formatting to the message. + notification_init(n); + + if (icon_value) { + if (n->receiving_raw_icon) + notification_icon_replace_data(n, icon_value); + g_variant_unref(icon_value); + } + + // Modify these values after the notification is initialized and all rules + // are applied. + if ((dict_value = + g_variant_lookup_value(hints, "fgcolor", G_VARIANT_TYPE_STRING))) { + struct color c; + if (string_parse_color(g_variant_get_string(dict_value, NULL), &c)) { + notification_keep_original(n); + if (!COLOR_VALID(n->original->fg)) + n->original->fg = n->colors.fg; + n->colors.fg = c; } - - // Modify these values after the notification is initialized and all rules are applied. - if ((dict_value = g_variant_lookup_value(hints, "fgcolor", G_VARIANT_TYPE_STRING))) { - struct color c; - if (string_parse_color(g_variant_get_string(dict_value, NULL), &c)) { - notification_keep_original(n); - if (!COLOR_VALID(n->original->fg)) n->original->fg = n->colors.fg; - n->colors.fg = c; - } - g_variant_unref(dict_value); + g_variant_unref(dict_value); + } + + if ((dict_value = + g_variant_lookup_value(hints, "bgcolor", G_VARIANT_TYPE_STRING))) { + struct color c; + if (string_parse_color(g_variant_get_string(dict_value, NULL), &c)) { + notification_keep_original(n); + if (!COLOR_VALID(n->original->bg)) + n->original->bg = n->colors.bg; + n->colors.bg = c; } - - if ((dict_value = g_variant_lookup_value(hints, "bgcolor", G_VARIANT_TYPE_STRING))) { - struct color c; - if (string_parse_color(g_variant_get_string(dict_value, NULL), &c)) { - notification_keep_original(n); - if (!COLOR_VALID(n->original->bg)) n->original->bg = n->colors.bg; - n->colors.bg = c; - } - g_variant_unref(dict_value); + g_variant_unref(dict_value); + } + + if ((dict_value = + g_variant_lookup_value(hints, "frcolor", G_VARIANT_TYPE_STRING))) { + struct color c; + if (string_parse_color(g_variant_get_string(dict_value, NULL), &c)) { + notification_keep_original(n); + if (!COLOR_VALID(n->original->fc)) + n->original->fc = n->colors.frame; + n->colors.frame = c; } - - if ((dict_value = g_variant_lookup_value(hints, "frcolor", G_VARIANT_TYPE_STRING))) { - struct color c; - if (string_parse_color(g_variant_get_string(dict_value, NULL), &c)) { - notification_keep_original(n); - if (!COLOR_VALID(n->original->fc)) n->original->fc = n->colors.frame; - n->colors.frame = c; - } - g_variant_unref(dict_value); + g_variant_unref(dict_value); + } + + if ((dict_value = g_variant_lookup_value( + hints, "hlcolor", G_VARIANT_TYPE_STRING_ARRAY))) { + char **cols = (char **)g_variant_get_strv(dict_value, NULL); + size_t length = g_strv_length(cols); + struct gradient *grad = gradient_alloc(length); + + for (size_t i = 0; i < length; i++) { + if (!string_parse_color(cols[i], &grad->colors[i])) { + g_free(grad); + goto end; + } } - if ((dict_value = g_variant_lookup_value(hints, "hlcolor", G_VARIANT_TYPE_STRING_ARRAY))) { - char **cols = (char **)g_variant_get_strv(dict_value, NULL); - size_t length = g_strv_length(cols); - struct gradient *grad = gradient_alloc(length); - - for (size_t i = 0; i < length; i++) { - if (!string_parse_color(cols[i], &grad->colors[i])) { - g_free(grad); - goto end; - } - } - - - gradient_pattern(grad); - - notification_keep_original(n); - if (!GRADIENT_VALID(n->original->highlight)) n->original->highlight = gradient_acquire(n->colors.highlight); - gradient_release(n->colors.highlight); - n->colors.highlight = gradient_acquire(grad); - -end: - g_variant_unref(dict_value); - } else if ((dict_value = g_variant_lookup_value(hints, "hlcolor", G_VARIANT_TYPE_STRING))) { - struct color c; - if (string_parse_color(g_variant_get_string(dict_value, NULL), &c)) { - struct gradient *grad = gradient_alloc(1); - grad->colors[0] = c; - gradient_pattern(grad); - - notification_keep_original(n); - if (!GRADIENT_VALID(n->original->highlight)) n->original->highlight = gradient_acquire(n->colors.highlight); - gradient_release(n->colors.highlight); - n->colors.highlight = gradient_acquire(grad); - } - g_variant_unref(dict_value); + gradient_pattern(grad); + + notification_keep_original(n); + if (!GRADIENT_VALID(n->original->highlight)) + n->original->highlight = gradient_acquire(n->colors.highlight); + gradient_release(n->colors.highlight); + n->colors.highlight = gradient_acquire(grad); + + end: + g_variant_unref(dict_value); + } else if ((dict_value = g_variant_lookup_value( + hints, "hlcolor", G_VARIANT_TYPE_STRING))) { + struct color c; + if (string_parse_color(g_variant_get_string(dict_value, NULL), &c)) { + struct gradient *grad = gradient_alloc(1); + grad->colors[0] = c; + gradient_pattern(grad); + + notification_keep_original(n); + if (!GRADIENT_VALID(n->original->highlight)) + n->original->highlight = gradient_acquire(n->colors.highlight); + gradient_release(n->colors.highlight); + n->colors.highlight = gradient_acquire(grad); } + g_variant_unref(dict_value); + } - g_variant_unref(hints); - g_variant_type_free(required_type); - g_free(actions); // the strv is only a shallow copy + g_variant_unref(hints); + g_variant_type_free(required_type); + g_free(actions); // the strv is only a shallow copy - return n; + return n; } void signal_length_propertieschanged(void) { - static unsigned int last_displayed = 0; - static unsigned int last_history = 0; - static unsigned int last_waiting = 0; - - if (!dbus_conn) - return; - - GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE_VARDICT); - GVariantBuilder *invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE_STRING_ARRAY); + static unsigned int last_displayed = 0; + static unsigned int last_history = 0; + static unsigned int last_waiting = 0; + + if (!dbus_conn) + return; + + GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE_VARDICT); + GVariantBuilder *invalidated_builder = + g_variant_builder_new(G_VARIANT_TYPE_STRING_ARRAY); + + unsigned int displayed = queues_length_displayed(); + unsigned int history = queues_length_history(); + unsigned int waiting = queues_length_waiting(); + bool properties_changed = false; + + if (last_displayed != displayed) { + g_variant_builder_add(builder, + "{sv}", + "displayedLength", + g_variant_new_uint32(displayed)); + last_displayed = displayed; + properties_changed = true; + } + + if (last_history != history) { + g_variant_builder_add( + builder, "{sv}", "historyLength", g_variant_new_uint32(history)); + last_history = history; + properties_changed = true; + } + if (last_waiting != waiting) { + g_variant_builder_add( + builder, "{sv}", "waitingLength", g_variant_new_uint32(waiting)); + last_waiting = waiting; + properties_changed = true; + } + + if (properties_changed) { + GVariant *body = g_variant_new( + "(sa{sv}as)", DUNST_IFAC, builder, invalidated_builder); - unsigned int displayed = queues_length_displayed(); - unsigned int history = queues_length_history(); - unsigned int waiting = queues_length_waiting(); - bool properties_changed = false; - - if (last_displayed != displayed) { - g_variant_builder_add(builder, - "{sv}", - "displayedLength", g_variant_new_uint32(displayed)); - last_displayed = displayed; - properties_changed = true; - } + GError *err = NULL; - if (last_history != history) { - g_variant_builder_add(builder, - "{sv}", - "historyLength", g_variant_new_uint32(history)); - last_history = history; - properties_changed = true; - } - if (last_waiting != waiting) { - g_variant_builder_add(builder, - "{sv}", - "waitingLength", g_variant_new_uint32(waiting)); - last_waiting = waiting; - properties_changed = true; - } + g_dbus_connection_emit_signal(dbus_conn, + NULL, + FDN_PATH, + PROPERTIES_IFAC, + "PropertiesChanged", + body, + &err); - if (properties_changed) { - GVariant *body = g_variant_new("(sa{sv}as)", - DUNST_IFAC, - builder, - invalidated_builder); - - GError *err = NULL; - - g_dbus_connection_emit_signal(dbus_conn, - NULL, - FDN_PATH, - PROPERTIES_IFAC, - "PropertiesChanged", - body, - &err); - - if (err) { - LOG_W("Unable to emit signal: %s", err->message); - g_error_free(err); - } + if (err) { + LOG_W("Unable to emit signal: %s", err->message); + g_error_free(err); } + } - g_clear_pointer(&builder, g_variant_builder_unref); - g_clear_pointer(&invalidated_builder, g_variant_builder_unref); + g_clear_pointer(&builder, g_variant_builder_unref); + g_clear_pointer(&invalidated_builder, g_variant_builder_unref); } -static void dbus_cb_Notify( - GDBusConnection *connection, - const gchar *sender, - GVariant *parameters, - GDBusMethodInvocation *invocation) +static void dbus_cb_Notify(GDBusConnection *connection, + const gchar *sender, + GVariant *parameters, + GDBusMethodInvocation *invocation) { - struct notification *n = dbus_message_to_notification(sender, parameters); - if (!n) { - LOG_W("A notification failed to decode."); - g_dbus_method_invocation_return_dbus_error( - invocation, - FDN_IFAC".Error", - "Cannot decode notification!"); - return; - } - - int id = queues_notification_insert(n); - - GVariant *reply = g_variant_new("(u)", id); - g_dbus_method_invocation_return_value(invocation, reply); - g_dbus_connection_flush(connection, NULL, NULL, NULL); - - // The message got discarded - if (id == 0) { - signal_notification_closed(n, REASON_USER); - notification_unref(n); - } - - wake_up(); + struct notification *n = dbus_message_to_notification(sender, parameters); + if (!n) { + LOG_W("A notification failed to decode."); + g_dbus_method_invocation_return_dbus_error( + invocation, FDN_IFAC ".Error", "Cannot decode notification!"); + return; + } + + int id = queues_notification_insert(n); + + GVariant *reply = g_variant_new("(u)", id); + g_dbus_method_invocation_return_value(invocation, reply); + g_dbus_connection_flush(connection, NULL, NULL, NULL); + + // The message got discarded + if (id == 0) { + signal_notification_closed(n, REASON_USER); + notification_unref(n); + } + + wake_up(); } -static void dbus_cb_CloseNotification( - GDBusConnection *connection, - const gchar *sender, - GVariant *parameters, - GDBusMethodInvocation *invocation) +static void dbus_cb_CloseNotification(GDBusConnection *connection, + const gchar *sender, + GVariant *parameters, + GDBusMethodInvocation *invocation) { - guint32 id; - g_variant_get(parameters, "(u)", &id); - if (settings.ignore_dbusclose) { - LOG_D("Ignoring CloseNotification message"); - // Stay commpliant by lying to the sender, telling him we closed the notification - if (id > 0) { - struct notification *n = queues_get_by_id(id); - if (n) - signal_notification_closed(n, REASON_SIG); - } - } else { - queues_notification_close_id(id, REASON_SIG); + guint32 id; + g_variant_get(parameters, "(u)", &id); + if (settings.ignore_dbusclose) { + LOG_D("Ignoring CloseNotification message"); + // Stay commpliant by lying to the sender, telling him we closed the + // notification + if (id > 0) { + struct notification *n = queues_get_by_id(id); + if (n) + signal_notification_closed(n, REASON_SIG); } - wake_up(); - g_dbus_method_invocation_return_value(invocation, NULL); - g_dbus_connection_flush(connection, NULL, NULL, NULL); + } else { + queues_notification_close_id(id, REASON_SIG); + } + wake_up(); + g_dbus_method_invocation_return_value(invocation, NULL); + g_dbus_connection_flush(connection, NULL, NULL, NULL); } -static void dbus_cb_GetServerInformation( - GDBusConnection *connection, - const gchar *sender, - GVariant *parameters, - GDBusMethodInvocation *invocation) +static void dbus_cb_GetServerInformation(GDBusConnection *connection, + const gchar *sender, + GVariant *parameters, + GDBusMethodInvocation *invocation) { - GVariant *answer = g_variant_new("(ssss)", "dunst", "knopwob", VERSION, "1.2"); + GVariant *answer = + g_variant_new("(ssss)", "dunst", "knopwob", VERSION, "1.2"); - g_dbus_method_invocation_return_value(invocation, answer); - g_dbus_connection_flush(connection, NULL, NULL, NULL); + g_dbus_method_invocation_return_value(invocation, answer); + g_dbus_connection_flush(connection, NULL, NULL, NULL); } void signal_notification_closed(struct notification *n, enum reason reason) { - if (!n->dbus_valid) { - return; - } - - if (reason < REASON_MIN || REASON_MAX < reason) { - LOG_W("Closing notification with reason '%d' not supported. " - "Closing it with reason '%d'.", reason, REASON_UNDEF); - reason = REASON_UNDEF; + if (!n->dbus_valid) { + return; + } + + if (reason < REASON_MIN || REASON_MAX < reason) { + LOG_W("Closing notification with reason '%d' not supported. " + "Closing it with reason '%d'.", + reason, + REASON_UNDEF); + reason = REASON_UNDEF; + } + + if (!dbus_conn) { + LOG_E("Unable to close notification: No DBus connection."); + } + + GVariant *body = g_variant_new("(uu)", n->id, reason); + GError *err = NULL; + + g_dbus_connection_emit_signal(dbus_conn, + n->dbus_client, + FDN_PATH, + FDN_IFAC, + "NotificationClosed", + body, + &err); + + notification_invalidate_actions(n); + + n->dbus_valid = false; + + if (err) { + LOG_W("Unable to close notification: %s", err->message); + g_error_free(err); + } else { + char *reason_string; + switch (reason) { + case REASON_TIME: reason_string = "time"; break; + case REASON_USER: reason_string = "user"; break; + case REASON_SIG: reason_string = "signal"; break; + case REASON_UNDEF: reason_string = "undefined"; break; + default: reason_string = "unknown"; } - if (!dbus_conn) { - LOG_E("Unable to close notification: No DBus connection."); - } - - GVariant *body = g_variant_new("(uu)", n->id, reason); - GError *err = NULL; - - g_dbus_connection_emit_signal(dbus_conn, - n->dbus_client, - FDN_PATH, - FDN_IFAC, - "NotificationClosed", - body, - &err); - - notification_invalidate_actions(n); - - n->dbus_valid = false; - - if (err) { - LOG_W("Unable to close notification: %s", err->message); - g_error_free(err); - } else { - char* reason_string; - switch (reason) { - case REASON_TIME: - reason_string="time"; - break; - case REASON_USER: - reason_string="user"; - break; - case REASON_SIG: - reason_string="signal"; - break; - case REASON_UNDEF: - reason_string="undefined"; - break; - default: - reason_string="unknown"; - } - - LOG_D("Queues: Closing notification for reason: %s", reason_string); - } + LOG_D("Queues: Closing notification for reason: %s", reason_string); + } } void signal_action_invoked(const struct notification *n, const char *identifier) { - if (!n->dbus_valid) { - LOG_W("Invoking action '%s' not supported. " - "Notification already closed.", identifier); - return; - } - - GVariant *body = g_variant_new("(us)", n->id, identifier); - GError *err = NULL; - - g_dbus_connection_emit_signal(dbus_conn, - n->dbus_client, - FDN_PATH, - FDN_IFAC, - "ActionInvoked", - body, - &err); - - if (err) { - LOG_W("Unable to invoke action: %s", err->message); - g_error_free(err); - } + if (!n->dbus_valid) { + LOG_W("Invoking action '%s' not supported. " + "Notification already closed.", + identifier); + return; + } + + GVariant *body = g_variant_new("(us)", n->id, identifier); + GError *err = NULL; + + g_dbus_connection_emit_signal(dbus_conn, + n->dbus_client, + FDN_PATH, + FDN_IFAC, + "ActionInvoked", + body, + &err); + + if (err) { + LOG_W("Unable to invoke action: %s", err->message); + g_error_free(err); + } } GVariant *dbus_cb_dunst_Properties_Get(GDBusConnection *connection, @@ -1151,26 +1230,27 @@ GVariant *dbus_cb_dunst_Properties_Get(GDBusConnection *connection, GError **error, gpointer user_data) { - struct dunst_status status = dunst_status_get(); - - if (STR_EQ(property_name, "paused")) { - return g_variant_new_boolean(status.pause_level != 0); - } else if (STR_EQ(property_name, "pauseLevel")) { - return g_variant_new_uint32(status.pause_level); - } else if (STR_EQ(property_name, "displayedLength")) { - unsigned int displayed = queues_length_displayed(); - return g_variant_new_uint32(displayed); - } else if (STR_EQ(property_name, "historyLength")) { - unsigned int history = queues_length_history(); - return g_variant_new_uint32(history); - } else if (STR_EQ(property_name, "waitingLength")) { - unsigned int waiting = queues_length_waiting(); - return g_variant_new_uint32(waiting); - } else { - LOG_W("Unknown property!\n"); - *error = g_error_new(G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property"); - return NULL; - } + struct dunst_status status = dunst_status_get(); + + if (STR_EQ(property_name, "paused")) { + return g_variant_new_boolean(status.pause_level != 0); + } else if (STR_EQ(property_name, "pauseLevel")) { + return g_variant_new_uint32(status.pause_level); + } else if (STR_EQ(property_name, "displayedLength")) { + unsigned int displayed = queues_length_displayed(); + return g_variant_new_uint32(displayed); + } else if (STR_EQ(property_name, "historyLength")) { + unsigned int history = queues_length_history(); + return g_variant_new_uint32(history); + } else if (STR_EQ(property_name, "waitingLength")) { + unsigned int waiting = queues_length_waiting(); + return g_variant_new_uint32(waiting); + } else { + LOG_W("Unknown property!\n"); + *error = g_error_new( + G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property"); + return NULL; + } } gboolean dbus_cb_dunst_Properties_Set(GDBusConnection *connection, @@ -1182,99 +1262,104 @@ gboolean dbus_cb_dunst_Properties_Set(GDBusConnection *connection, GError **error, gpointer user_data) { - int targetPauseLevel = -1; - if (STR_EQ(property_name, "paused")) { - if (g_variant_get_boolean(value)) { - targetPauseLevel = MAX_PAUSE_LEVEL; - } else { - targetPauseLevel = 0; - } - } else if STR_EQ(property_name, "pauseLevel") { - targetPauseLevel = g_variant_get_uint32(value); - if (targetPauseLevel > MAX_PAUSE_LEVEL) { - targetPauseLevel = MAX_PAUSE_LEVEL; - } + int targetPauseLevel = -1; + if (STR_EQ(property_name, "paused")) { + if (g_variant_get_boolean(value)) { + targetPauseLevel = MAX_PAUSE_LEVEL; + } else { + targetPauseLevel = 0; } - - if (targetPauseLevel >= 0) { - dunst_status_int(S_PAUSE_LEVEL, targetPauseLevel); - wake_up(); - - GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE_VARDICT); - GVariantBuilder *invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE_STRING_ARRAY); - g_variant_builder_add(builder, - "{sv}", - "paused", g_variant_new_boolean(targetPauseLevel != 0)); - g_variant_builder_add(builder, - "{sv}", - "pauseLevel", g_variant_new_uint32(targetPauseLevel)); - g_dbus_connection_emit_signal(connection, - NULL, - object_path, - PROPERTIES_IFAC, - "PropertiesChanged", - g_variant_new("(sa{sv}as)", - interface_name, - builder, - invalidated_builder), - NULL); - - g_clear_pointer(&builder, g_variant_builder_unref); - g_clear_pointer(&invalidated_builder, g_variant_builder_unref); - return true; + } else if STR_EQ (property_name, "pauseLevel") { + targetPauseLevel = g_variant_get_uint32(value); + if (targetPauseLevel > MAX_PAUSE_LEVEL) { + targetPauseLevel = MAX_PAUSE_LEVEL; } + } - *error = g_error_new(G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property"); + if (targetPauseLevel >= 0) { + dunst_status_int(S_PAUSE_LEVEL, targetPauseLevel); + wake_up(); - return false; -} + GVariantBuilder *builder = + g_variant_builder_new(G_VARIANT_TYPE_VARDICT); + GVariantBuilder *invalidated_builder = + g_variant_builder_new(G_VARIANT_TYPE_STRING_ARRAY); + g_variant_builder_add(builder, + "{sv}", + "paused", + g_variant_new_boolean(targetPauseLevel != 0)); + g_variant_builder_add(builder, + "{sv}", + "pauseLevel", + g_variant_new_uint32(targetPauseLevel)); + g_dbus_connection_emit_signal( + connection, + NULL, + object_path, + PROPERTIES_IFAC, + "PropertiesChanged", + g_variant_new( + "(sa{sv}as)", interface_name, builder, invalidated_builder), + NULL); + + g_clear_pointer(&builder, g_variant_builder_unref); + g_clear_pointer(&invalidated_builder, g_variant_builder_unref); + return true; + } + + *error = g_error_new( + G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property"); + return false; +} static const GDBusInterfaceVTable interface_vtable_fdn = { - dbus_cb_fdn_methods, + dbus_cb_fdn_methods, }; static const GDBusInterfaceVTable interface_vtable_dunst = { - dbus_cb_dunst_methods, - dbus_cb_dunst_Properties_Get, - dbus_cb_dunst_Properties_Set, + dbus_cb_dunst_methods, + dbus_cb_dunst_Properties_Get, + dbus_cb_dunst_Properties_Set, }; static void dbus_cb_bus_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data) { - GError *err = NULL; - if(!g_dbus_connection_register_object( - connection, - FDN_PATH, - introspection_data->interfaces[0], - &interface_vtable_fdn, - NULL, - NULL, - &err)) { - DIE("Unable to register dbus connection interface '%s': %s", introspection_data->interfaces[0]->name, err->message); - } - - if(!g_dbus_connection_register_object( - connection, - FDN_PATH, - introspection_data->interfaces[1], - &interface_vtable_dunst, - NULL, - NULL, - &err)) { - DIE("Unable to register dbus connection interface '%s': %s", introspection_data->interfaces[1]->name, err->message); - } + GError *err = NULL; + if (!g_dbus_connection_register_object(connection, + FDN_PATH, + introspection_data->interfaces[0], + &interface_vtable_fdn, + NULL, + NULL, + &err)) { + DIE("Unable to register dbus connection interface '%s': %s", + introspection_data->interfaces[0]->name, + err->message); + } + + if (!g_dbus_connection_register_object(connection, + FDN_PATH, + introspection_data->interfaces[1], + &interface_vtable_dunst, + NULL, + NULL, + &err)) { + DIE("Unable to register dbus connection interface '%s': %s", + introspection_data->interfaces[1]->name, + err->message); + } } static void dbus_cb_name_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data) { - // If we're not able to get org.fd.N bus, we've still got a problem - if (STR_EQ(name, FDN_NAME)) - dbus_conn = connection; + // If we're not able to get org.fd.N bus, we've still got a problem + if (STR_EQ(name, FDN_NAME)) + dbus_conn = connection; } /** @@ -1291,225 +1376,223 @@ static void dbus_cb_name_acquired(GDBusConnection *connection, * @retval true: on success * @retval false: Any error happened */ -static bool dbus_get_fdn_daemon_info(GDBusConnection *connection, - guint *pid, - char **name, - char **vendor) +static bool dbus_get_fdn_daemon_info(GDBusConnection *connection, + guint *pid, + char **name, + char **vendor) { - ASSERT_OR_RET(pid, false); - ASSERT_OR_RET(connection, false); - - char *owner = NULL; - GError *error = NULL; - - GDBusProxy *proxy_fdn; - GDBusProxy *proxy_dbus; - - proxy_fdn = g_dbus_proxy_new_sync( - connection, - /* do not trigger a start of the notification daemon */ - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, /* info */ - FDN_NAME, - FDN_PATH, - FDN_IFAC, - NULL, /* cancelable */ - &error); - - if (error) { - g_error_free(error); - return false; - } - - GVariant *daemoninfo = NULL; - if (name || vendor) { - daemoninfo = g_dbus_proxy_call_sync( - proxy_fdn, - FDN_IFAC ".GetServerInformation", - NULL, - G_DBUS_CALL_FLAGS_NONE, - /* It's not worth to wait for the info - * longer than half a second when dying */ - 500, - NULL, /* cancelable */ - &error); - } - - if (error) { - /* Ignore the error, we may still be able to retrieve the PID */ - g_clear_pointer(&error, g_error_free); - } else { - g_variant_get(daemoninfo, "(ssss)", name, vendor, NULL, NULL); - } - - owner = g_dbus_proxy_get_name_owner(proxy_fdn); - - proxy_dbus = g_dbus_proxy_new_sync( - connection, - G_DBUS_PROXY_FLAGS_NONE, - NULL, /* info */ - "org.freedesktop.DBus", - "/org/freedesktop/DBus", - "org.freedesktop.DBus", - NULL, /* cancelable */ - &error); - - if (error) { - g_error_free(error); - return false; - } - - GVariant *pidinfo = g_dbus_proxy_call_sync( - proxy_dbus, - "org.freedesktop.DBus.GetConnectionUnixProcessID", - g_variant_new("(s)", owner), - G_DBUS_CALL_FLAGS_NONE, - /* It's not worth to wait for the PID - * longer than half a second when dying */ - 500, - NULL, - &error); - - if (error) { - g_error_free(error); - return false; - } - - g_object_unref(proxy_fdn); - g_object_unref(proxy_dbus); - g_free(owner); - if (daemoninfo) - g_variant_unref(daemoninfo); - - if (pidinfo) { - g_variant_get(pidinfo, "(u)", pid); - g_variant_unref(pidinfo); - return true; - } else { - return false; - } + ASSERT_OR_RET(pid, false); + ASSERT_OR_RET(connection, false); + + char *owner = NULL; + GError *error = NULL; + + GDBusProxy *proxy_fdn; + GDBusProxy *proxy_dbus; + + proxy_fdn = g_dbus_proxy_new_sync( + connection, + /* do not trigger a start of the notification daemon */ + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, /* info */ + FDN_NAME, + FDN_PATH, + FDN_IFAC, + NULL, /* cancelable */ + &error); + + if (error) { + g_error_free(error); + return false; + } + + GVariant *daemoninfo = NULL; + if (name || vendor) { + daemoninfo = + g_dbus_proxy_call_sync(proxy_fdn, + FDN_IFAC ".GetServerInformation", + NULL, + G_DBUS_CALL_FLAGS_NONE, + /* It's not worth to wait for the info + * longer than half a second when dying */ + 500, + NULL, /* cancelable */ + &error); + } + + if (error) { + /* Ignore the error, we may still be able to retrieve the PID */ + g_clear_pointer(&error, g_error_free); + } else { + g_variant_get(daemoninfo, "(ssss)", name, vendor, NULL, NULL); + } + + owner = g_dbus_proxy_get_name_owner(proxy_fdn); + + proxy_dbus = g_dbus_proxy_new_sync(connection, + G_DBUS_PROXY_FLAGS_NONE, + NULL, /* info */ + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + NULL, /* cancelable */ + &error); + + if (error) { + g_error_free(error); + return false; + } + + GVariant *pidinfo = g_dbus_proxy_call_sync( + proxy_dbus, + "org.freedesktop.DBus.GetConnectionUnixProcessID", + g_variant_new("(s)", owner), + G_DBUS_CALL_FLAGS_NONE, + /* It's not worth to wait for the PID + * longer than half a second when dying */ + 500, + NULL, + &error); + + if (error) { + g_error_free(error); + return false; + } + + g_object_unref(proxy_fdn); + g_object_unref(proxy_dbus); + g_free(owner); + if (daemoninfo) + g_variant_unref(daemoninfo); + + if (pidinfo) { + g_variant_get(pidinfo, "(u)", pid); + g_variant_unref(pidinfo); + return true; + } else { + return false; + } } - static void dbus_cb_name_lost(GDBusConnection *connection, const gchar *name, gpointer user_data) { - if (connection) { - char *name; - unsigned int pid; - if (dbus_get_fdn_daemon_info(connection, &pid, &name, NULL)) { - DIE("Cannot acquire '"FDN_NAME"': " - "Name is acquired by '%s' with PID '%d'.", name, pid); - } else { - DIE("Cannot acquire '"FDN_NAME"'."); - } + if (connection) { + char *name; + unsigned int pid; + if (dbus_get_fdn_daemon_info(connection, &pid, &name, NULL)) { + DIE("Cannot acquire '" FDN_NAME "': " + "Name is acquired by '%s' with PID '%d'.", + name, + pid); } else { - const char *env = getenv("DBUS_SESSION_BUS_ADDRESS"); - if (STR_EMPTY(env)) { - LOG_W("DBUS_SESSION_BUS_ADDRESS is blank. Is the dbus session configured correctly?"); - } - - DIE("Cannot connect to DBus."); + DIE("Cannot acquire '" FDN_NAME "'."); + } + } else { + const char *env = getenv("DBUS_SESSION_BUS_ADDRESS"); + if (STR_EMPTY(env)) { + LOG_W("DBUS_SESSION_BUS_ADDRESS is blank. Is the dbus session " + "configured correctly?"); } - exit(1); + + DIE("Cannot connect to DBus."); + } + exit(1); } int dbus_init(void) { - guint owner_id; + guint owner_id; - introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, - NULL); + introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL); - owner_id = g_bus_own_name(G_BUS_TYPE_SESSION, - FDN_NAME, - G_BUS_NAME_OWNER_FLAGS_NONE, - dbus_cb_bus_acquired, - dbus_cb_name_acquired, - dbus_cb_name_lost, - NULL, - NULL); + owner_id = g_bus_own_name(G_BUS_TYPE_SESSION, + FDN_NAME, + G_BUS_NAME_OWNER_FLAGS_NONE, + dbus_cb_bus_acquired, + dbus_cb_name_acquired, + dbus_cb_name_lost, + NULL, + NULL); - return owner_id; + return owner_id; } void signal_history_removed(guint id) { - if (!dbus_conn) { - LOG_E("Unable to send signal: No DBus connection."); - } + if (!dbus_conn) { + LOG_E("Unable to send signal: No DBus connection."); + } - GVariant *body = g_variant_new("(u)", id); - GError *err = NULL; + GVariant *body = g_variant_new("(u)", id); + GError *err = NULL; - g_dbus_connection_emit_signal(dbus_conn, - NULL, - FDN_PATH, - DUNST_IFAC, - "NotificationHistoryRemoved", - body, - &err); - - if (err) { - LOG_W("Unable to send NotificationHistoryRemoved signal: %s", err->message); - g_error_free(err); - } + g_dbus_connection_emit_signal(dbus_conn, + NULL, + FDN_PATH, + DUNST_IFAC, + "NotificationHistoryRemoved", + body, + &err); + + if (err) { + LOG_W("Unable to send NotificationHistoryRemoved signal: %s", + err->message); + g_error_free(err); + } } void signal_history_cleared(guint n) { - if (!dbus_conn) { - LOG_E("Unable to send signal: No DBus connection."); - } - - GVariant *body = g_variant_new("(u)", n); - GError *err = NULL; + if (!dbus_conn) { + LOG_E("Unable to send signal: No DBus connection."); + } - g_dbus_connection_emit_signal(dbus_conn, - NULL, - FDN_PATH, - DUNST_IFAC, - "NotificationHistoryCleared", - body, - &err); + GVariant *body = g_variant_new("(u)", n); + GError *err = NULL; - if (err) { - LOG_W("Unable to send NotificationHistoryCleared signal: %s", err->message); - g_error_free(err); - } + g_dbus_connection_emit_signal(dbus_conn, + NULL, + FDN_PATH, + DUNST_IFAC, + "NotificationHistoryCleared", + body, + &err); + + if (err) { + LOG_W("Unable to send NotificationHistoryCleared signal: %s", + err->message); + g_error_free(err); + } } void signal_config_reloaded(char **const configs) { - if (!dbus_conn) { - LOG_E("Unable to send signal: No DBus connection."); - } - - guint length = g_strv_length(configs); - GVariant *body = g_variant_new("(^as)", length != 0 ? configs : config_paths); - GError *err = NULL; - - g_dbus_connection_emit_signal(dbus_conn, - NULL, - FDN_PATH, - DUNST_IFAC, - "ConfigReloaded", - body, - &err); - - if (err) { - LOG_W("Unable to send ConfigReloaded signal: %s", err->message); - g_error_free(err); - } + if (!dbus_conn) { + LOG_E("Unable to send signal: No DBus connection."); + } + + guint length = g_strv_length(configs); + GVariant *body = + g_variant_new("(^as)", length != 0 ? configs : config_paths); + GError *err = NULL; + + g_dbus_connection_emit_signal( + dbus_conn, NULL, FDN_PATH, DUNST_IFAC, "ConfigReloaded", body, &err); + + if (err) { + LOG_W("Unable to send ConfigReloaded signal: %s", err->message); + g_error_free(err); + } } void dbus_teardown(int owner_id) { - g_clear_pointer(&introspection_data, g_dbus_node_info_unref); + g_clear_pointer(&introspection_data, g_dbus_node_info_unref); - g_bus_unown_name(owner_id); - dbus_conn = NULL; + g_bus_unown_name(owner_id); + dbus_conn = NULL; } /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/dbus.h b/src/dbus.h index ed306ccb3..7c0b2b091 100644 --- a/src/dbus.h +++ b/src/dbus.h @@ -1,4 +1,5 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ #ifndef DUNST_DBUS_H #define DUNST_DBUS_H @@ -7,19 +8,21 @@ #include "notification.h" /// The reasons according to the notification spec -enum reason { - REASON_MIN = 1, /**< Minimum value, useful for boundary checking */ - REASON_TIME = 1, /**< The notification timed out */ - REASON_USER = 2, /**< The user closed the notification */ - REASON_SIG = 3, /**< The daemon received a `NotificationClose` signal */ - REASON_UNDEF = 4, /**< Undefined reason not matching the previous ones */ - REASON_MAX = 4, /**< Maximum value, useful for boundary checking */ +enum reason +{ + REASON_MIN = 1, /**< Minimum value, useful for boundary checking */ + REASON_TIME = 1, /**< The notification timed out */ + REASON_USER = 2, /**< The user closed the notification */ + REASON_SIG = 3, /**< The daemon received a `NotificationClose` signal */ + REASON_UNDEF = 4, /**< Undefined reason not matching the previous ones */ + REASON_MAX = 4, /**< Maximum value, useful for boundary checking */ }; int dbus_init(void); void dbus_teardown(int id); void signal_notification_closed(struct notification *n, enum reason reason); -void signal_action_invoked(const struct notification *n, const char *identifier); +void signal_action_invoked(const struct notification *n, + const char *identifier); void signal_length_propertieschanged(void); void signal_history_removed(guint id); void signal_history_cleared(guint n); diff --git a/src/draw.c b/src/draw.c index c91c38066..1ad6ee8f0 100644 --- a/src/draw.c +++ b/src/draw.c @@ -1,34 +1,35 @@ #include "draw.h" #include +#include +#include #include #include -#include #include #include #include +#include #include -#include -#include #include "dunst.h" +#include "icon-lookup.h" #include "icon.h" #include "log.h" #include "markup.h" #include "notification.h" -#include "queues.h" #include "output.h" +#include "queues.h" #include "settings.h" #include "utils.h" -#include "icon-lookup.h" -struct colored_layout { - PangoLayout *l; - char *text; - PangoAttrList *attr; - cairo_surface_t *icon; - struct notification *n; - bool is_xmore; +struct colored_layout +{ + PangoLayout *l; + char *text; + PangoAttrList *attr; + cairo_surface_t *icon; + struct notification *n; + bool is_xmore; }; const struct output *output; @@ -41,468 +42,498 @@ PangoFontDescription *pango_fdesc; void load_icon_themes(void) { - bool loaded_theme = false; - - for (int i = 0; settings.icon_theme[i] != NULL; i++) { - char *theme = settings.icon_theme[i]; - int theme_index = load_icon_theme(theme); - if (theme_index >= 0) { - LOG_I("Adding theme %s", theme); - add_default_theme(theme_index); - loaded_theme = true; - } + bool loaded_theme = false; + + for (int i = 0; settings.icon_theme[i] != NULL; i++) { + char *theme = settings.icon_theme[i]; + int theme_index = load_icon_theme(theme); + if (theme_index >= 0) { + LOG_I("Adding theme %s", theme); + add_default_theme(theme_index); + loaded_theme = true; } - if (!loaded_theme) { - int theme_index = load_icon_theme("hicolor"); - add_default_theme(theme_index); - } - + } + if (!loaded_theme) { + int theme_index = load_icon_theme("hicolor"); + add_default_theme(theme_index); + } } char *color_to_string(struct color c, char buf[10]) { - if (!COLOR_VALID(c)) return NULL; - - g_snprintf(buf, 10, "#%02x%02x%02x%02x", - (int)(c.r * 255), - (int)(c.g * 255), - (int)(c.b * 255), - (int)(c.a * 255)); - return buf; + if (!COLOR_VALID(c)) + return NULL; + + g_snprintf(buf, + 10, + "#%02x%02x%02x%02x", + (int)(c.r * 255), + (int)(c.g * 255), + (int)(c.b * 255), + (int)(c.a * 255)); + return buf; } struct gradient *gradient_alloc(size_t length) { - if (length == 0) - return NULL; + if (length == 0) + return NULL; - struct gradient *grad = g_rc_box_alloc(sizeof(struct gradient) + length * sizeof(struct color)); + struct gradient *grad = + g_rc_box_alloc(sizeof(struct gradient) + length * sizeof(struct color)); - grad->length = length; - grad->pattern = NULL; + grad->length = length; + grad->pattern = NULL; - return grad; + return grad; } struct gradient *gradient_acquire(struct gradient *grad) { - return grad != NULL ? g_rc_box_acquire(grad) : NULL; + return grad != NULL ? g_rc_box_acquire(grad) : NULL; } static void gradient_free(struct gradient *grad) { - if (grad->pattern) - cairo_pattern_destroy(grad->pattern); + if (grad->pattern) + cairo_pattern_destroy(grad->pattern); } void gradient_release(struct gradient *grad) { - if (grad != NULL) - g_rc_box_release_full(grad, (GDestroyNotify)gradient_free); + if (grad != NULL) + g_rc_box_release_full(grad, (GDestroyNotify)gradient_free); } void gradient_pattern(struct gradient *grad) { - if (grad->length == 1) { - grad->pattern = cairo_pattern_create_rgba(grad->colors[0].r, - grad->colors[0].g, - grad->colors[0].b, - grad->colors[0].a); - } else { - grad->pattern = cairo_pattern_create_linear(0, 0, 1, 0); - for (size_t i = 0; i < grad->length; i++) { - double offset = i / (double)(grad->length - 1); - cairo_pattern_add_color_stop_rgba(grad->pattern, - offset, - grad->colors[i].r, - grad->colors[i].g, - grad->colors[i].b, - grad->colors[i].a); - } + if (grad->length == 1) { + grad->pattern = cairo_pattern_create_rgba(grad->colors[0].r, + grad->colors[0].g, + grad->colors[0].b, + grad->colors[0].a); + } else { + grad->pattern = cairo_pattern_create_linear(0, 0, 1, 0); + for (size_t i = 0; i < grad->length; i++) { + double offset = i / (double)(grad->length - 1); + cairo_pattern_add_color_stop_rgba(grad->pattern, + offset, + grad->colors[i].r, + grad->colors[i].g, + grad->colors[i].b, + grad->colors[i].a); } + } } char *gradient_to_string(const struct gradient *grad) { - if (!GRADIENT_VALID(grad)) return NULL; - - int max = grad->length * 11 + 1; - char *buf = g_malloc(max); - - for (size_t i = 0, j = 0; i < grad->length; i++) { - j += g_snprintf(buf + j, max - j, "#%02x%02x%02x%02x", - (int)(grad->colors[i].r * 255), - (int)(grad->colors[i].g * 255), - (int)(grad->colors[i].b * 255), - (int)(grad->colors[i].a * 255)); - - if (i != grad->length - 1) { - j += g_snprintf(buf + j, max - j, ", "); - } + if (!GRADIENT_VALID(grad)) + return NULL; + + int max = grad->length * 11 + 1; + char *buf = g_malloc(max); + + for (size_t i = 0, j = 0; i < grad->length; i++) { + j += g_snprintf(buf + j, + max - j, + "#%02x%02x%02x%02x", + (int)(grad->colors[i].r * 255), + (int)(grad->colors[i].g * 255), + (int)(grad->colors[i].b * 255), + (int)(grad->colors[i].a * 255)); + + if (i != grad->length - 1) { + j += g_snprintf(buf + j, max - j, ", "); } + } - return buf; + return buf; } void draw_setup(void) { - const struct output *out = output_create(settings.force_xwayland); - output = out; + const struct output *out = output_create(settings.force_xwayland); + output = out; - win = out->win_create(); + win = out->win_create(); - LOG_D("Trying to load font: '%s'", settings.font); - pango_fdesc = pango_font_description_from_string(settings.font); - LOG_D("Loaded closest matching font: '%s'", pango_font_description_get_family(pango_fdesc)); + LOG_D("Trying to load font: '%s'", settings.font); + pango_fdesc = pango_font_description_from_string(settings.font); + LOG_D("Loaded closest matching font: '%s'", + pango_font_description_get_family(pango_fdesc)); - if (settings.enable_recursive_icon_lookup) - load_icon_themes(); + if (settings.enable_recursive_icon_lookup) + load_icon_themes(); } static inline double color_apply_delta(double base, double delta) { - base += delta; - if (base > 1) - base = 1; - if (base < 0) - base = 0; + base += delta; + if (base > 1) + base = 1; + if (base < 0) + base = 0; - return base; + return base; } static struct color calculate_foreground_color(struct color bg) { - double c_delta = 0.1; - struct color fg = bg; + double c_delta = 0.1; + struct color fg = bg; - /* do we need to darken or brighten the colors? */ - bool darken = (bg.r + bg.g + bg.b) / 3 > 0.5; + /* do we need to darken or brighten the colors? */ + bool darken = (bg.r + bg.g + bg.b) / 3 > 0.5; - int signedness = darken ? -1 : 1; + int signedness = darken ? -1 : 1; - fg.r = color_apply_delta(fg.r, c_delta * signedness); - fg.g = color_apply_delta(fg.g, c_delta * signedness); - fg.b = color_apply_delta(fg.b, c_delta * signedness); + fg.r = color_apply_delta(fg.r, c_delta * signedness); + fg.g = color_apply_delta(fg.g, c_delta * signedness); + fg.b = color_apply_delta(fg.b, c_delta * signedness); - return fg; + return fg; } static struct color layout_get_sepcolor(struct colored_layout *cl, struct colored_layout *cl_next) { - switch (settings.sep_color.type) { - case SEP_FRAME: - return COLOR(cl_next->n->urgency > cl->n->urgency ? cl_next : cl, frame); - case SEP_CUSTOM: - return settings.sep_color.color; - case SEP_FOREGROUND: - return COLOR(cl, fg); - case SEP_AUTO: - return calculate_foreground_color(COLOR(cl, bg)); - default: - LOG_E("Invalid %s enum value in %s:%d", "sep_color", __FILE__, __LINE__); - break; - } + switch (settings.sep_color.type) { + case SEP_FRAME: + return COLOR(cl_next->n->urgency > cl->n->urgency ? cl_next : cl, + frame); + case SEP_CUSTOM: return settings.sep_color.color; + case SEP_FOREGROUND: return COLOR(cl, fg); + case SEP_AUTO: return calculate_foreground_color(COLOR(cl, bg)); + default: + LOG_E( + "Invalid %s enum value in %s:%d", "sep_color", __FILE__, __LINE__); + break; + } } static int get_horizontal_text_icon_padding(struct notification *n) { - bool horizontal_icon = ( - n->icon && (n->icon_position == ICON_LEFT || n->icon_position == ICON_RIGHT) - ); - if (settings.text_icon_padding && horizontal_icon) { - return settings.text_icon_padding; - } else { - return settings.h_padding; - } + bool horizontal_icon = + (n->icon + && (n->icon_position == ICON_LEFT || n->icon_position == ICON_RIGHT)); + if (settings.text_icon_padding && horizontal_icon) { + return settings.text_icon_padding; + } else { + return settings.h_padding; + } } static int get_vertical_text_icon_padding(struct notification *n) { - bool vertical_icon = n->icon && (n->icon_position == ICON_TOP); - if (settings.text_icon_padding && vertical_icon) { - return settings.text_icon_padding; - } else { - return settings.padding; - } + bool vertical_icon = n->icon && (n->icon_position == ICON_TOP); + if (settings.text_icon_padding && vertical_icon) { + return settings.text_icon_padding; + } else { + return settings.padding; + } } static bool have_progress_bar(const struct colored_layout *cl) { - return (cl->n->progress >= 0 && settings.progress_bar == true && - !cl->is_xmore); + return (cl->n->progress >= 0 && settings.progress_bar == true + && !cl->is_xmore); } -static void get_text_size(PangoLayout *l, int *w, int *h, double scale) { - pango_layout_get_pixel_size(l, w, h); - // scale the size down, because it may be rendered at higher DPI +static void get_text_size(PangoLayout *l, int *w, int *h, double scale) +{ + pango_layout_get_pixel_size(l, w, h); + // scale the size down, because it may be rendered at higher DPI - if (w) - *w = ceil(*w / scale); - if (h) - *h = ceil(*h / scale); + if (w) + *w = ceil(*w / scale); + if (h) + *h = ceil(*h / scale); } // Set up pango for a given layout. -// @param width The avaiable text width in pixels, used for caluclating alignment and wrapping +// @param width The avaiable text width in pixels, used for caluclating +// alignment and wrapping // @param height The maximum text height in pixels. -static void layout_setup_pango(PangoLayout *layout, int width, int height, - bool word_wrap, PangoEllipsizeMode ellipsize_mode, - PangoAlignment alignment) +static void layout_setup_pango(PangoLayout *layout, + int width, + int height, + bool word_wrap, + PangoEllipsizeMode ellipsize_mode, + PangoAlignment alignment) { - double scale = output->get_scale(); - pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); - pango_layout_set_width(layout, round(width * scale * PANGO_SCALE)); + double scale = output->get_scale(); + pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); + pango_layout_set_width(layout, round(width * scale * PANGO_SCALE)); - // When no height is set, word wrap is turned off - if (word_wrap) - pango_layout_set_height(layout, round(height * scale * PANGO_SCALE)); + // When no height is set, word wrap is turned off + if (word_wrap) + pango_layout_set_height(layout, round(height * scale * PANGO_SCALE)); - pango_layout_set_font_description(layout, pango_fdesc); - pango_layout_set_spacing(layout, round(settings.line_height * scale * PANGO_SCALE)); + pango_layout_set_font_description(layout, pango_fdesc); + pango_layout_set_spacing(layout, + round(settings.line_height * scale * PANGO_SCALE)); - pango_layout_set_ellipsize(layout, ellipsize_mode); + pango_layout_set_ellipsize(layout, ellipsize_mode); - pango_layout_set_alignment(layout, alignment); + pango_layout_set_alignment(layout, alignment); } // Set up the layout of a single notification // @param width Width of the layout // @param height Height of the layout -static void layout_setup(struct colored_layout *cl, int width, int height, double scale) +static void +layout_setup(struct colored_layout *cl, int width, int height, double scale) { - int horizontal_padding = get_horizontal_text_icon_padding(cl->n); - int icon_width = cl->icon ? get_icon_width(cl->icon, scale) + horizontal_padding : 0; - int text_width = width - 2 * settings.h_padding - (cl->n->icon_position == ICON_TOP ? 0 : icon_width); - int progress_bar_height = have_progress_bar(cl) ? settings.progress_bar_height + settings.padding : 0; - int max_text_height = MAX(0, settings.height.max - progress_bar_height - 2 * settings.padding); - layout_setup_pango(cl->l, text_width, max_text_height, cl->n->word_wrap, cl->n->ellipsize, cl->n->alignment); + int horizontal_padding = get_horizontal_text_icon_padding(cl->n); + int icon_width = + cl->icon ? get_icon_width(cl->icon, scale) + horizontal_padding : 0; + int text_width = width - 2 * settings.h_padding + - (cl->n->icon_position == ICON_TOP ? 0 : icon_width); + int progress_bar_height = + have_progress_bar(cl) ? settings.progress_bar_height + settings.padding + : 0; + int max_text_height = MAX( + 0, settings.height.max - progress_bar_height - 2 * settings.padding); + layout_setup_pango(cl->l, + text_width, + max_text_height, + cl->n->word_wrap, + cl->n->ellipsize, + cl->n->alignment); } static void free_colored_layout(void *data) { - struct colored_layout *cl = data; - g_object_unref(cl->l); - pango_attr_list_unref(cl->attr); - g_free(cl->text); - g_free(cl); + struct colored_layout *cl = data; + g_object_unref(cl->l); + pango_attr_list_unref(cl->attr); + g_free(cl->text); + g_free(cl); } // calculates the minimum dimensions of the notification excluding the frame -static struct dimensions calculate_notification_dimensions(struct colored_layout *cl, double scale) +static struct dimensions +calculate_notification_dimensions(struct colored_layout *cl, double scale) { - struct dimensions dim = { 0 }; - layout_setup(cl, settings.width.max, settings.height.max, scale); - - int horizontal_padding = get_horizontal_text_icon_padding(cl->n); - int icon_width = cl->icon? get_icon_width(cl->icon, scale) + horizontal_padding : 0; - int icon_height = cl->icon? get_icon_height(cl->icon, scale) : 0; - int progress_bar_height = have_progress_bar(cl) ? settings.progress_bar_height + settings.padding : 0; - - int vertical_padding; - if (cl->n->hide_text) { - vertical_padding = 0; - dim.text_width = 0; - dim.text_height = 0; - } else { - get_text_size(cl->l, &dim.text_width, &dim.text_height, scale); - vertical_padding = get_vertical_text_icon_padding(cl->n); - } - - if (cl->n->icon_position == ICON_TOP && cl->n->icon) { - dim.h = icon_height + dim.text_height + vertical_padding; - } else { - dim.h = MAX(icon_height, dim.text_height); - } - - dim.h += progress_bar_height + settings.padding * 2; - dim.w = dim.text_width + icon_width + 2 * settings.h_padding; - - if (have_progress_bar(cl)) - dim.w = MAX(settings.progress_bar_min_width, dim.w); - - dim.h = MAX(settings.height.min, dim.h); - dim.h = MIN(settings.height.max, dim.h); - - dim.w = MAX(settings.width.min, dim.w); - dim.w = MIN(settings.width.max, dim.w); - - cl->n->displayed_height = dim.h; - return dim; + struct dimensions dim = {0}; + layout_setup(cl, settings.width.max, settings.height.max, scale); + + int horizontal_padding = get_horizontal_text_icon_padding(cl->n); + int icon_width = + cl->icon ? get_icon_width(cl->icon, scale) + horizontal_padding : 0; + int icon_height = cl->icon ? get_icon_height(cl->icon, scale) : 0; + int progress_bar_height = + have_progress_bar(cl) ? settings.progress_bar_height + settings.padding + : 0; + + int vertical_padding; + if (cl->n->hide_text) { + vertical_padding = 0; + dim.text_width = 0; + dim.text_height = 0; + } else { + get_text_size(cl->l, &dim.text_width, &dim.text_height, scale); + vertical_padding = get_vertical_text_icon_padding(cl->n); + } + + if (cl->n->icon_position == ICON_TOP && cl->n->icon) { + dim.h = icon_height + dim.text_height + vertical_padding; + } else { + dim.h = MAX(icon_height, dim.text_height); + } + + dim.h += progress_bar_height + settings.padding * 2; + dim.w = dim.text_width + icon_width + 2 * settings.h_padding; + + if (have_progress_bar(cl)) + dim.w = MAX(settings.progress_bar_min_width, dim.w); + + dim.h = MAX(settings.height.min, dim.h); + dim.h = MIN(settings.height.max, dim.h); + + dim.w = MAX(settings.width.min, dim.w); + dim.w = MIN(settings.width.max, dim.w); + + cl->n->displayed_height = dim.h; + return dim; } static struct dimensions calculate_dimensions(GSList *layouts) { - int layout_count = g_slist_length(layouts); - struct dimensions dim = { 0 }; - double scale = output->get_scale(); - - dim.corner_radius = settings.corner_radius; - - for (GSList *iter = layouts; iter; iter = iter->next) { - struct colored_layout *cl = iter->data; - struct dimensions n_dim = calculate_notification_dimensions(cl, scale); - dim.h += n_dim.h; - LOG_D("Notification dimensions %ix%i", n_dim.w, n_dim.h); - dim.w = MAX(dim.w, n_dim.w + settings.frame_width); - } - - dim.w += 2 * settings.frame_width; - dim.corner_radius = MIN(dim.corner_radius, dim.h/2); - - /* clamp max width to screen width */ - const struct screen_info *scr = output->get_active_screen(); - int max_width = scr->w - settings.offset.x; - if (dim.w > max_width) { - dim.w = max_width; - } - - if (settings.gap_size) { - int extra_frame_height = layout_count * (2 * settings.frame_width); - int extra_gap_height = (layout_count * settings.gap_size) - settings.gap_size; - int total_extra_height = extra_frame_height + extra_gap_height; - dim.h += total_extra_height; - } else { - dim.h += 2 * settings.frame_width; - dim.h += (layout_count - 1) * settings.separator_height; - } - - return dim; + int layout_count = g_slist_length(layouts); + struct dimensions dim = {0}; + double scale = output->get_scale(); + + dim.corner_radius = settings.corner_radius; + + for (GSList *iter = layouts; iter; iter = iter->next) { + struct colored_layout *cl = iter->data; + struct dimensions n_dim = calculate_notification_dimensions(cl, scale); + dim.h += n_dim.h; + LOG_D("Notification dimensions %ix%i", n_dim.w, n_dim.h); + dim.w = MAX(dim.w, n_dim.w + settings.frame_width); + } + + dim.w += 2 * settings.frame_width; + dim.corner_radius = MIN(dim.corner_radius, dim.h / 2); + + /* clamp max width to screen width */ + const struct screen_info *scr = output->get_active_screen(); + int max_width = scr->w - settings.offset.x; + if (dim.w > max_width) { + dim.w = max_width; + } + + if (settings.gap_size) { + int extra_frame_height = layout_count * (2 * settings.frame_width); + int extra_gap_height = + (layout_count * settings.gap_size) - settings.gap_size; + int total_extra_height = extra_frame_height + extra_gap_height; + dim.h += total_extra_height; + } else { + dim.h += 2 * settings.frame_width; + dim.h += (layout_count - 1) * settings.separator_height; + } + + return dim; } static PangoLayout *layout_create(cairo_t *c) { - const struct screen_info *screen = output->get_active_screen(); + const struct screen_info *screen = output->get_active_screen(); - PangoContext *context = pango_cairo_create_context(c); - pango_cairo_context_set_resolution(context, screen->dpi); + PangoContext *context = pango_cairo_create_context(c); + pango_cairo_context_set_resolution(context, screen->dpi); - PangoLayout *layout = pango_layout_new(context); + PangoLayout *layout = pango_layout_new(context); - g_object_unref(context); + g_object_unref(context); - return layout; + return layout; } -static struct colored_layout *layout_init_shared(cairo_t *c, struct notification *n) +static struct colored_layout *layout_init_shared(cairo_t *c, + struct notification *n) { - struct colored_layout *cl = g_malloc(sizeof(struct colored_layout)); - cl->l = layout_create(c); - cl->is_xmore = false; - cl->n = n; - - // Invalid colors should never reach this point! - assert(settings.frame_width == 0 || COLOR_VALID(COLOR(cl, frame))); - assert(!have_progress_bar(cl) || COLOR(cl, highlight) != NULL); - assert(COLOR_VALID(COLOR(cl, fg))); - assert(COLOR_VALID(COLOR(cl, bg))); - return cl; + struct colored_layout *cl = g_malloc(sizeof(struct colored_layout)); + cl->l = layout_create(c); + cl->is_xmore = false; + cl->n = n; + + // Invalid colors should never reach this point! + assert(settings.frame_width == 0 || COLOR_VALID(COLOR(cl, frame))); + assert(!have_progress_bar(cl) || COLOR(cl, highlight) != NULL); + assert(COLOR_VALID(COLOR(cl, fg))); + assert(COLOR_VALID(COLOR(cl, bg))); + return cl; } -static struct colored_layout *layout_derive_xmore(cairo_t *c, struct notification *n, int qlen) +static struct colored_layout * +layout_derive_xmore(cairo_t *c, struct notification *n, int qlen) { - struct colored_layout *cl = layout_init_shared(c, n); - cl->text = g_strdup_printf("(%d more)", qlen); - cl->attr = NULL; - cl->is_xmore = true; - cl->icon = NULL; - pango_layout_set_text(cl->l, cl->text, -1); - return cl; + struct colored_layout *cl = layout_init_shared(c, n); + cl->text = g_strdup_printf("(%d more)", qlen); + cl->attr = NULL; + cl->is_xmore = true; + cl->icon = NULL; + pango_layout_set_text(cl->l, cl->text, -1); + return cl; } -static struct colored_layout *layout_from_notification(cairo_t *c, struct notification *n) +static struct colored_layout *layout_from_notification(cairo_t *c, + struct notification *n) { - struct colored_layout *cl = layout_init_shared(c, n); + struct colored_layout *cl = layout_init_shared(c, n); - if (n->icon_position != ICON_OFF && n->icon) { - cl->icon = n->icon; - } else { - cl->icon = NULL; - } + if (n->icon_position != ICON_OFF && n->icon) { + cl->icon = n->icon; + } else { + cl->icon = NULL; + } - /* markup */ - GError *err = NULL; - pango_parse_markup(n->text_to_render, -1, 0, &(cl->attr), &(cl->text), NULL, &err); + /* markup */ + GError *err = NULL; + pango_parse_markup( + n->text_to_render, -1, 0, &(cl->attr), &(cl->text), NULL, &err); - if (!err) { - pango_layout_set_text(cl->l, cl->text, -1); - pango_attr_list_insert(cl->attr, pango_attr_fallback_new(true)); - pango_layout_set_attributes(cl->l, cl->attr); - } else { - /* remove markup and display plain message instead */ - n->text_to_render = markup_strip(n->text_to_render); - cl->text = NULL; - cl->attr = pango_attr_list_new(); - pango_attr_list_insert(cl->attr, pango_attr_fallback_new(true)); - pango_layout_set_text(cl->l, n->text_to_render, -1); - if (n->first_render) { - LOG_W("Unable to parse markup: %s", err->message); - } - g_error_free(err); + if (!err) { + pango_layout_set_text(cl->l, cl->text, -1); + pango_attr_list_insert(cl->attr, pango_attr_fallback_new(true)); + pango_layout_set_attributes(cl->l, cl->attr); + } else { + /* remove markup and display plain message instead */ + n->text_to_render = markup_strip(n->text_to_render); + cl->text = NULL; + cl->attr = pango_attr_list_new(); + pango_attr_list_insert(cl->attr, pango_attr_fallback_new(true)); + pango_layout_set_text(cl->l, n->text_to_render, -1); + if (n->first_render) { + LOG_W("Unable to parse markup: %s", err->message); } + g_error_free(err); + } - n->first_render = false; - return cl; + n->first_render = false; + return cl; } static GSList *create_layouts(cairo_t *c) { - GSList *layouts = NULL; + GSList *layouts = NULL; - int qlen = queues_length_waiting(); - bool xmore_is_needed = qlen > 0 && settings.indicate_hidden; + int qlen = queues_length_waiting(); + bool xmore_is_needed = qlen > 0 && settings.indicate_hidden; - for (const GList *iter = queues_get_displayed(); - iter; iter = iter->next) - { - struct notification *n = iter->data; + for (const GList *iter = queues_get_displayed(); iter; iter = iter->next) { + struct notification *n = iter->data; - notification_update_text_to_render(n); + notification_update_text_to_render(n); - if (!iter->next && xmore_is_needed && settings.notification_limit == 1) { - char *new_ttr = g_strdup_printf("%s (%d more)", n->text_to_render, qlen); - g_free(n->text_to_render); - n->text_to_render = new_ttr; - } - layouts = g_slist_append(layouts, - layout_from_notification(c, n)); + if (!iter->next && xmore_is_needed + && settings.notification_limit == 1) { + char *new_ttr = + g_strdup_printf("%s (%d more)", n->text_to_render, qlen); + g_free(n->text_to_render); + n->text_to_render = new_ttr; } + layouts = g_slist_append(layouts, layout_from_notification(c, n)); + } - if (xmore_is_needed && settings.notification_limit != 1) { - /* append xmore message as new message */ - layouts = g_slist_append(layouts, - layout_derive_xmore(c, queues_get_head_waiting(), qlen)); - } + if (xmore_is_needed && settings.notification_limit != 1) { + /* append xmore message as new message */ + layouts = g_slist_append( + layouts, layout_derive_xmore(c, queues_get_head_waiting(), qlen)); + } - return layouts; + return layouts; } - static int layout_get_height(struct colored_layout *cl, double scale) { - int h_text = 0; - int h_icon = 0; - int h_progress_bar = 0; - - int vertical_padding; - if (cl->n->hide_text) { - vertical_padding = 0; - } else { - get_text_size(cl->l, NULL, &h_text, scale); - vertical_padding = get_vertical_text_icon_padding(cl->n); - } - - if (cl->icon) - h_icon = get_icon_height(cl->icon, scale); - - if (have_progress_bar(cl)) { - h_progress_bar = settings.progress_bar_height + settings.padding; - } - - return (cl->n->icon_position == ICON_TOP && cl->n->icon) - ? h_icon + h_text + h_progress_bar + vertical_padding - : MAX(h_text, h_icon) + h_progress_bar; + int h_text = 0; + int h_icon = 0; + int h_progress_bar = 0; + + int vertical_padding; + if (cl->n->hide_text) { + vertical_padding = 0; + } else { + get_text_size(cl->l, NULL, &h_text, scale); + vertical_padding = get_vertical_text_icon_padding(cl->n); + } + + if (cl->icon) + h_icon = get_icon_height(cl->icon, scale); + + if (have_progress_bar(cl)) { + h_progress_bar = settings.progress_bar_height + settings.padding; + } + + return (cl->n->icon_position == ICON_TOP && cl->n->icon) + ? h_icon + h_text + h_progress_bar + vertical_padding + : MAX(h_text, h_icon) + h_progress_bar; } /* Attempt to make internal radius more organic. @@ -511,192 +542,211 @@ static int layout_get_height(struct colored_layout *cl, double scale) * r, w - corner radius & frame width, * h - box height */ -static int frame_internal_radius (int r, int w, int h) +static int frame_internal_radius(int r, int w, int h) { - if (r == 0 || h + (w - r) * 2 == 0) - return 0; + if (r == 0 || h + (w - r) * 2 == 0) + return 0; - // Integer precision scaler, using 1/4 of int size - const int s = 2 << (8 * sizeof(int) / 4); + // Integer precision scaler, using 1/4 of int size + const int s = 2 << (8 * sizeof(int) / 4); - int r1, r2, ret; - h *= s; - r *= s; - w *= s; - r1 = r - w + w * w / (r * 2); // w < r - r2 = r * h / (h + (w - r) * 2); // w >= r + int r1, r2, ret; + h *= s; + r *= s; + w *= s; + r1 = r - w + w * w / (r * 2); // w < r + r2 = r * h / (h + (w - r) * 2); // w >= r - ret = (r > w) ? r1 : (r / 2 < r2) ? r / 2 : r2; + ret = (r > w) ? r1 : (r / 2 < r2) ? r / 2 : r2; - return ret / s; + return ret / s; } /** * A small wrapper around cairo_rectange for drawing a scaled rectangle. */ -static inline void draw_rect(cairo_t *c, double x, double y, double width, double height, double scale) +static inline void draw_rect( + cairo_t *c, double x, double y, double width, double height, double scale) { - cairo_rectangle(c, round(x * scale), round(y * scale), round(width * scale), round(height * scale)); + cairo_rectangle(c, + round(x * scale), + round(y * scale), + round(width * scale), + round(height * scale)); } /** - * Create a path on the given cairo context to draw the background of a notification. - * The top corners will get rounded by `corner_radius`, if `first` is set. - * Respectably the same for `last` with the bottom corners. + * Create a path on the given cairo context to draw the background of a + * notification. The top corners will get rounded by `corner_radius`, if `first` + * is set. Respectably the same for `last` with the bottom corners. * - * TODO: Pass additional frame width information to fix blurry lines due to fractional scaling - * X and Y can then be calculated as: x = round(x*scale) + half_frame_width + * TODO: Pass additional frame width information to fix blurry lines due to + * fractional scaling X and Y can then be calculated as: x = round(x*scale) + + * half_frame_width */ -void draw_rounded_rect(cairo_t *c, float x, float y, int width, int height, int corner_radius, double scale, enum corner_pos corners) +void draw_rounded_rect(cairo_t *c, + float x, + float y, + int width, + int height, + int corner_radius, + double scale, + enum corner_pos corners) { - // Fast path for simple rects - if (corners == C_NONE || corner_radius <= 0) { - draw_rect(c, x, y, width, height, scale); - return; - } - - width = round(width * scale); - height = round(height * scale); - x *= scale; - y *= scale; - corner_radius = round(corner_radius * scale); - - // Nothing valid to draw - if (width <= 0 || height <= 0 || scale <= 0) - return; - - const double degrees = M_PI / 180.0; - - // This seems to be needed for a problem that occurs mostly when using cairo_stroke - // and not cairo_fill. Since the only case where we have partial angles is the progress - // bar and there we use fill, maybe this can be removed completely? - enum corner_pos skip = C_NONE; - - float top_y_off = 0, bot_y_off = 0, top_x_off, bot_x_off; - top_x_off = bot_x_off = MAX(width - corner_radius, corner_radius); - - double bot_left_angle1 = degrees * 90; - double bot_left_angle2 = degrees * 180; - - double top_left_angle1 = degrees * 180; - double top_left_angle2 = degrees * 270; - - double top_right_angle1 = degrees * 270; - double top_right_angle2 = degrees * 360; - - double bot_right_angle1 = degrees * 0; - double bot_right_angle2 = degrees * 90; - - // The trickiest cases to handle are when the width is less than corner_radius and corner_radius * 2, - // because we have to split the angle for the arc in the rounded corner - if (width <= corner_radius) { - double angle1 = 0, angle2 = 0; - - // If there are two corners on the top/bottom they occupy half of the width - if ((corners & C_TOP) == C_TOP) - angle1 = acos(1.0 - ((double)width / 2.0) / (double)corner_radius); - else - angle1 = acos(1.0 - (double)width / (double)corner_radius); - - if ((corners & C_BOT) == C_BOT) - angle2 = acos(1.0 - ((double)width / 2.0) / (double)corner_radius); - else - angle2 = acos(1.0 - (double)width / (double)corner_radius); - - if ((corners & (C_TOP_RIGHT | C_BOT_LEFT)) == (C_TOP_RIGHT | C_BOT_LEFT) && !(corners & C_TOP_LEFT)) { - top_y_off -= corner_radius * (1.0 - sin(angle1)); - } + // Fast path for simple rects + if (corners == C_NONE || corner_radius <= 0) { + draw_rect(c, x, y, width, height, scale); + return; + } + + width = round(width * scale); + height = round(height * scale); + x *= scale; + y *= scale; + corner_radius = round(corner_radius * scale); + + // Nothing valid to draw + if (width <= 0 || height <= 0 || scale <= 0) + return; + + const double degrees = M_PI / 180.0; + + // This seems to be needed for a problem that occurs mostly when using + // cairo_stroke and not cairo_fill. Since the only case where we have + // partial angles is the progress bar and there we use fill, maybe this can + // be removed completely? + enum corner_pos skip = C_NONE; + + float top_y_off = 0, bot_y_off = 0, top_x_off, bot_x_off; + top_x_off = bot_x_off = MAX(width - corner_radius, corner_radius); + + double bot_left_angle1 = degrees * 90; + double bot_left_angle2 = degrees * 180; + + double top_left_angle1 = degrees * 180; + double top_left_angle2 = degrees * 270; + + double top_right_angle1 = degrees * 270; + double top_right_angle2 = degrees * 360; + + double bot_right_angle1 = degrees * 0; + double bot_right_angle2 = degrees * 90; + + // The trickiest cases to handle are when the width is less than + // corner_radius and corner_radius * 2, because we have to split the angle + // for the arc in the rounded corner + if (width <= corner_radius) { + double angle1 = 0, angle2 = 0; + + // If there are two corners on the top/bottom they occupy half of the + // width + if ((corners & C_TOP) == C_TOP) + angle1 = acos(1.0 - ((double)width / 2.0) / (double)corner_radius); + else + angle1 = acos(1.0 - (double)width / (double)corner_radius); - if ((corners & (C_TOP_LEFT | C_BOT_RIGHT)) == (C_TOP_LEFT | C_BOT_RIGHT) && !(corners & C_BOT_LEFT)) { - bot_y_off = corner_radius * (1.0 - sin(angle2)); - } + if ((corners & C_BOT) == C_BOT) + angle2 = acos(1.0 - ((double)width / 2.0) / (double)corner_radius); + else + angle2 = acos(1.0 - (double)width / (double)corner_radius); - top_left_angle2 = degrees * 180 + angle1; - top_right_angle1 = degrees * 360 - angle1; - bot_left_angle1 = degrees * 180 - angle2; - bot_right_angle2 = angle2; + if ((corners & (C_TOP_RIGHT | C_BOT_LEFT)) == (C_TOP_RIGHT | C_BOT_LEFT) + && !(corners & C_TOP_LEFT)) { + top_y_off -= corner_radius * (1.0 - sin(angle1)); + } - top_x_off = -(corner_radius - width); - bot_x_off = -(corner_radius - width); + if ((corners & (C_TOP_LEFT | C_BOT_RIGHT)) == (C_TOP_LEFT | C_BOT_RIGHT) + && !(corners & C_BOT_LEFT)) { + bot_y_off = corner_radius * (1.0 - sin(angle2)); + } - if (corners != C_TOP && corners != C_BOT) - skip = ~corners; + top_left_angle2 = degrees * 180 + angle1; + top_right_angle1 = degrees * 360 - angle1; + bot_left_angle1 = degrees * 180 - angle2; + bot_right_angle2 = angle2; - } else if (width <= corner_radius * 2 && (corners & C_LEFT && corners & C_RIGHT)) { - double angle1 = 0, angle2 = 0; - if (!(corners & C_TOP_LEFT) && corners & C_TOP_RIGHT) - top_x_off = width - corner_radius; - else - angle1 = acos((double)width / (double)corner_radius - 1.0); + top_x_off = -(corner_radius - width); + bot_x_off = -(corner_radius - width); - if (!(corners & C_BOT_LEFT) && corners & C_BOT_RIGHT) - bot_x_off = width - corner_radius; - else - angle2 = acos((double)width / (double)corner_radius - 1.0); + if (corners != C_TOP && corners != C_BOT) + skip = ~corners; - top_right_angle2 = degrees * 360 - angle1; - bot_right_angle1 = angle2; - } + } else if (width <= corner_radius * 2 + && (corners & C_LEFT && corners & C_RIGHT)) { + double angle1 = 0, angle2 = 0; + if (!(corners & C_TOP_LEFT) && corners & C_TOP_RIGHT) + top_x_off = width - corner_radius; + else + angle1 = acos((double)width / (double)corner_radius - 1.0); - cairo_new_sub_path(c); - - // bottom left - if (!(skip & C_BOT_LEFT)) { - if (corners & C_BOT_LEFT) { - cairo_arc(c, - x + corner_radius, - y + height - corner_radius, - corner_radius, - bot_left_angle1, - bot_left_angle2); - } else { - cairo_line_to(c, x, y + height); - } + if (!(corners & C_BOT_LEFT) && corners & C_BOT_RIGHT) + bot_x_off = width - corner_radius; + else + angle2 = acos((double)width / (double)corner_radius - 1.0); + + top_right_angle2 = degrees * 360 - angle1; + bot_right_angle1 = angle2; + } + + cairo_new_sub_path(c); + + // bottom left + if (!(skip & C_BOT_LEFT)) { + if (corners & C_BOT_LEFT) { + cairo_arc(c, + x + corner_radius, + y + height - corner_radius, + corner_radius, + bot_left_angle1, + bot_left_angle2); + } else { + cairo_line_to(c, x, y + height); } - - // top left - if (!(skip & C_TOP_LEFT)) { - if (corners & C_TOP_LEFT) { - cairo_arc(c, - x + corner_radius, - y + corner_radius, - corner_radius, - top_left_angle1, - top_left_angle2); - } else { - cairo_line_to(c, x, y); - } + } + + // top left + if (!(skip & C_TOP_LEFT)) { + if (corners & C_TOP_LEFT) { + cairo_arc(c, + x + corner_radius, + y + corner_radius, + corner_radius, + top_left_angle1, + top_left_angle2); + } else { + cairo_line_to(c, x, y); } - - // top right - if (!(skip & C_TOP_RIGHT)) { - if (corners & C_TOP_RIGHT) { - cairo_arc(c, - x + top_x_off, - y + corner_radius + top_y_off, - corner_radius, - top_right_angle1, - top_right_angle2); - } else { - cairo_line_to(c, x + width, y); - } + } + + // top right + if (!(skip & C_TOP_RIGHT)) { + if (corners & C_TOP_RIGHT) { + cairo_arc(c, + x + top_x_off, + y + corner_radius + top_y_off, + corner_radius, + top_right_angle1, + top_right_angle2); + } else { + cairo_line_to(c, x + width, y); } - - // bottom right - if (!(skip & C_BOT_RIGHT)) { - if (corners & C_BOT_RIGHT) { - cairo_arc(c, - x + bot_x_off, - y + height - corner_radius + bot_y_off, - corner_radius, - bot_right_angle1, - bot_right_angle2); - } else { - cairo_line_to(c, x + width, y + height); - } + } + + // bottom right + if (!(skip & C_BOT_RIGHT)) { + if (corners & C_BOT_RIGHT) { + cairo_arc(c, + x + bot_x_off, + y + height - corner_radius + bot_y_off, + corner_radius, + bot_right_angle1, + bot_right_angle2); + } else { + cairo_line_to(c, x + width, y + height); } + } - cairo_close_path(c); + cairo_close_path(c); } static cairo_surface_t *render_background(cairo_surface_t *srf, @@ -710,219 +760,268 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, int *ret_width, double scale) { - int x = 0; - int radius_int = corner_radius; - - cairo_t *c = cairo_create(srf); - - /* stroke area doesn't intersect with main area */ - cairo_set_fill_rule(c, CAIRO_FILL_RULE_EVEN_ODD); - - /* for correct combination of adjacent areas */ - cairo_set_operator(c, CAIRO_OPERATOR_ADD); - - if (corners & (C_TOP | _C_FIRST)) - height += settings.frame_width; - if (corners & (C_BOT | _C_LAST)) - height += settings.frame_width; - else - height += settings.separator_height; - - draw_rounded_rect(c, x, y, width, height, corner_radius, scale, corners); - - /* adding frame */ - x += settings.frame_width; - if (corners & (C_TOP | _C_FIRST)) { - y += settings.frame_width; - height -= settings.frame_width; - } - - width -= 2 * settings.frame_width; - - if (corners & (C_BOT | _C_LAST)) - height -= settings.frame_width; - else - height -= settings.separator_height; - - radius_int = frame_internal_radius(corner_radius, settings.frame_width, height); - - draw_rounded_rect(c, x, y, width, height, radius_int, scale, corners); - cairo_set_source_rgba(c, COLOR(cl, frame.r), COLOR(cl, frame.g), COLOR(cl, frame.b), COLOR(cl, frame.a)); - cairo_fill(c); + int x = 0; + int radius_int = corner_radius; + + cairo_t *c = cairo_create(srf); + + /* stroke area doesn't intersect with main area */ + cairo_set_fill_rule(c, CAIRO_FILL_RULE_EVEN_ODD); + + /* for correct combination of adjacent areas */ + cairo_set_operator(c, CAIRO_OPERATOR_ADD); + + if (corners & (C_TOP | _C_FIRST)) + height += settings.frame_width; + if (corners & (C_BOT | _C_LAST)) + height += settings.frame_width; + else + height += settings.separator_height; + + draw_rounded_rect(c, x, y, width, height, corner_radius, scale, corners); + + /* adding frame */ + x += settings.frame_width; + if (corners & (C_TOP | _C_FIRST)) { + y += settings.frame_width; + height -= settings.frame_width; + } + + width -= 2 * settings.frame_width; + + if (corners & (C_BOT | _C_LAST)) + height -= settings.frame_width; + else + height -= settings.separator_height; + + radius_int = + frame_internal_radius(corner_radius, settings.frame_width, height); + + draw_rounded_rect(c, x, y, width, height, radius_int, scale, corners); + cairo_set_source_rgba(c, + COLOR(cl, frame.r), + COLOR(cl, frame.g), + COLOR(cl, frame.b), + COLOR(cl, frame.a)); + cairo_fill(c); + + draw_rounded_rect(c, x, y, width, height, radius_int, scale, corners); + cairo_set_source_rgba( + c, COLOR(cl, bg.r), COLOR(cl, bg.g), COLOR(cl, bg.b), COLOR(cl, bg.a)); + cairo_fill(c); + + cairo_set_operator(c, CAIRO_OPERATOR_SOURCE); + + if (settings.sep_color.type != SEP_FRAME && settings.separator_height > 0 + && (corners & (C_BOT | _C_LAST)) == 0) { + struct color sep_color = layout_get_sepcolor(cl, cl_next); + cairo_set_source_rgba( + c, sep_color.r, sep_color.g, sep_color.b, sep_color.a); + + draw_rect(c, + settings.frame_width, + y + height, + width, + settings.separator_height, + scale); - draw_rounded_rect(c, x, y, width, height, radius_int, scale, corners); - cairo_set_source_rgba(c, COLOR(cl, bg.r), COLOR(cl, bg.g), COLOR(cl, bg.b), COLOR(cl, bg.a)); cairo_fill(c); + } - cairo_set_operator(c, CAIRO_OPERATOR_SOURCE); + cairo_destroy(c); - if ( settings.sep_color.type != SEP_FRAME - && settings.separator_height > 0 - && (corners & (C_BOT | _C_LAST)) == 0) { - struct color sep_color = layout_get_sepcolor(cl, cl_next); - cairo_set_source_rgba(c, sep_color.r, sep_color.g, sep_color.b, sep_color.a); + if (ret_width) + *ret_width = width; - draw_rect(c, settings.frame_width, y + height, width, settings.separator_height, scale); - - cairo_fill(c); - } - - cairo_destroy(c); - - if (ret_width) - *ret_width = width; - - return cairo_surface_create_for_rectangle(srf, - round(x * scale), round(y * scale), - round(width * scale), round(height * scale)); + return cairo_surface_create_for_rectangle(srf, + round(x * scale), + round(y * scale), + round(width * scale), + round(height * scale)); } -static void render_content(cairo_t *c, struct colored_layout *cl, int width, int height, double scale) +static void render_content( + cairo_t *c, struct colored_layout *cl, int width, int height, double scale) { - // Redo layout setup, while knowing the width. This is to make - // alignment work correctly - layout_setup(cl, width, height, scale); - - // NOTE: Includes paddings! - int h_without_progress_bar = height; - if (have_progress_bar(cl)) { - h_without_progress_bar -= settings.progress_bar_height + settings.padding; - } - - int text_h = 0; - if (!cl->n->hide_text) { - get_text_size(cl->l, NULL, &text_h, scale); - } - - // text vertical alignment - int text_x = settings.h_padding, + // Redo layout setup, while knowing the width. This is to make + // alignment work correctly + layout_setup(cl, width, height, scale); + + // NOTE: Includes paddings! + int h_without_progress_bar = height; + if (have_progress_bar(cl)) { + h_without_progress_bar -= + settings.progress_bar_height + settings.padding; + } + + int text_h = 0; + if (!cl->n->hide_text) { + get_text_size(cl->l, NULL, &text_h, scale); + } + + // text vertical alignment + int text_x = settings.h_padding, text_y = settings.padding; + + if (settings.vertical_alignment == VERTICAL_CENTER) { + text_y = h_without_progress_bar / 2 - text_h / 2; + } else if (settings.vertical_alignment == VERTICAL_BOTTOM) { + text_y = h_without_progress_bar - settings.padding - text_h; + if (text_y < 0) text_y = settings.padding; - - if (settings.vertical_alignment == VERTICAL_CENTER) { - text_y = h_without_progress_bar / 2 - text_h / 2; - } else if (settings.vertical_alignment == VERTICAL_BOTTOM) { - text_y = h_without_progress_bar - settings.padding - text_h; - if (text_y < 0) text_y = settings.padding; - } // else VERTICAL_TOP - - // icon positioning - if (cl->icon && cl->n->icon_position != ICON_OFF) { - int image_width = get_icon_width(cl->icon, scale), - image_height = get_icon_height(cl->icon, scale), - image_x = width - settings.h_padding - image_width, - image_y = text_y, - v_padding = get_vertical_text_icon_padding(cl->n); - - // vertical alignment - switch (settings.vertical_alignment) { - case VERTICAL_TOP: - if (cl->n->icon_position == ICON_TOP) { - // Shift text downward - text_y += image_height + v_padding; - } - break; - case VERTICAL_CENTER: - if (cl->n->icon_position == ICON_TOP) { - // Adjust text and image by half - image_y -= (image_height + v_padding) / 2; - text_y += (image_height + v_padding) / 2; - } else { - image_y += text_h / 2 - image_height / 2; - } - break; - case VERTICAL_BOTTOM: - if (cl->n->icon_position == ICON_TOP) { - image_y -= image_height + v_padding; - } else { - image_y -= image_height - text_h; - } - break; - } - - // icon position - if (cl->n->icon_position == ICON_TOP) { - image_x = (width - image_width) / 2; - } else if (cl->n->icon_position == ICON_LEFT) { - image_x = settings.h_padding; - text_x += image_width + get_horizontal_text_icon_padding(cl->n); - } // else ICON_RIGHT - - cairo_set_source_surface(c, cl->icon, round(image_x * scale), round(image_y * scale)); - draw_rounded_rect(c, image_x, image_y, image_width, image_height, settings.icon_corner_radius, scale, settings.icon_corners); - cairo_fill(c); + } // else VERTICAL_TOP + + // icon positioning + if (cl->icon && cl->n->icon_position != ICON_OFF) { + int image_width = get_icon_width(cl->icon, scale), + image_height = get_icon_height(cl->icon, scale), + image_x = width - settings.h_padding - image_width, + image_y = text_y, v_padding = get_vertical_text_icon_padding(cl->n); + + // vertical alignment + switch (settings.vertical_alignment) { + case VERTICAL_TOP: + if (cl->n->icon_position == ICON_TOP) { + // Shift text downward + text_y += image_height + v_padding; + } + break; + case VERTICAL_CENTER: + if (cl->n->icon_position == ICON_TOP) { + // Adjust text and image by half + image_y -= (image_height + v_padding) / 2; + text_y += (image_height + v_padding) / 2; + } else { + image_y += text_h / 2 - image_height / 2; + } + break; + case VERTICAL_BOTTOM: + if (cl->n->icon_position == ICON_TOP) { + image_y -= image_height + v_padding; + } else { + image_y -= image_height - text_h; + } + break; } - // text positioning - if (!cl->n->hide_text) { - cairo_move_to(c, round(text_x * scale), round(text_y * scale)); - cairo_set_source_rgba(c, COLOR(cl, fg.r), COLOR(cl, fg.g), COLOR(cl, fg.b), COLOR(cl, fg.a)); - pango_cairo_update_layout(c, cl->l); - pango_cairo_show_layout(c, cl->l); + // icon position + if (cl->n->icon_position == ICON_TOP) { + image_x = (width - image_width) / 2; + } else if (cl->n->icon_position == ICON_LEFT) { + image_x = settings.h_padding; + text_x += image_width + get_horizontal_text_icon_padding(cl->n); + } // else ICON_RIGHT + + cairo_set_source_surface( + c, cl->icon, round(image_x * scale), round(image_y * scale)); + draw_rounded_rect(c, + image_x, + image_y, + image_width, + image_height, + settings.icon_corner_radius, + scale, + settings.icon_corners); + cairo_fill(c); + } + + // text positioning + if (!cl->n->hide_text) { + cairo_move_to(c, round(text_x * scale), round(text_y * scale)); + cairo_set_source_rgba(c, + COLOR(cl, fg.r), + COLOR(cl, fg.g), + COLOR(cl, fg.b), + COLOR(cl, fg.a)); + pango_cairo_update_layout(c, cl->l); + pango_cairo_show_layout(c, cl->l); + } + + // progress bar positioning + if (have_progress_bar(cl)) { + int progress = MIN(cl->n->progress, 100); + unsigned int frame_x = 0; + unsigned int frame_width = settings.progress_bar_frame_width, + progress_width = MIN(width - 2 * settings.h_padding, + settings.progress_bar_max_width), + progress_height = + settings.progress_bar_height - frame_width, + frame_y = h_without_progress_bar, + progress_width_without_frame = + progress_width - 2 * frame_width, + progress_width_1 = + progress_width_without_frame * progress / 100, + progress_width_2 = progress_width_without_frame - 1, + progress_width_scaled = (progress_width + 1) * scale; + + switch (cl->n->progress_bar_alignment) { + case PANGO_ALIGN_LEFT: frame_x = settings.h_padding; break; + case PANGO_ALIGN_CENTER: + frame_x = width / 2 - progress_width / 2; + break; + case PANGO_ALIGN_RIGHT: + frame_x = width - progress_width - settings.h_padding; + break; } + unsigned int x_bar_1 = frame_x + frame_width, x_bar_2 = x_bar_1 + 0.5; + + double half_frame_width = (double)frame_width / 2.0; + + /* Draw progress bar + * TODO: Modify draw_rounded_rect to fix blurry lines due to fractional + * scaling Note: for now the bar background is drawn a little bit + * smaller than the fill, however this solution is not particularly + * solid (basically subracting a pixel or two) + */ + + // back layer (background) + cairo_set_source_rgba(c, + COLOR(cl, bg.r), + COLOR(cl, bg.g), + COLOR(cl, bg.b), + COLOR(cl, bg.a)); + draw_rounded_rect(c, + x_bar_2, + frame_y, + progress_width_2, + progress_height, + settings.progress_bar_corner_radius, + scale, + settings.progress_bar_corners); + cairo_fill(c); - // progress bar positioning - if (have_progress_bar(cl)) { - int progress = MIN(cl->n->progress, 100); - unsigned int frame_x = 0; - unsigned int frame_width = settings.progress_bar_frame_width, - progress_width = MIN(width - 2 * settings.h_padding, settings.progress_bar_max_width), - progress_height = settings.progress_bar_height - frame_width, - frame_y = h_without_progress_bar, - progress_width_without_frame = progress_width - 2 * frame_width, - progress_width_1 = progress_width_without_frame * progress / 100, - progress_width_2 = progress_width_without_frame - 1, - progress_width_scaled = (progress_width + 1) * scale; - - switch (cl->n->progress_bar_alignment) { - case PANGO_ALIGN_LEFT: - frame_x = settings.h_padding; - break; - case PANGO_ALIGN_CENTER: - frame_x = width/2 - progress_width/2; - break; - case PANGO_ALIGN_RIGHT: - frame_x = width - progress_width - settings.h_padding; - break; - } - unsigned int x_bar_1 = frame_x + frame_width, - x_bar_2 = x_bar_1 + 0.5; - - double half_frame_width = (double)frame_width / 2.0; - - /* Draw progress bar - * TODO: Modify draw_rounded_rect to fix blurry lines due to fractional scaling - * Note: for now the bar background is drawn a little bit smaller than the fill, however - * this solution is not particularly solid (basically subracting a pixel or two) - */ - - // back layer (background) - cairo_set_source_rgba(c, COLOR(cl, bg.r), COLOR(cl, bg.g), COLOR(cl, bg.b), COLOR(cl, bg.a)); - draw_rounded_rect(c, x_bar_2, frame_y, progress_width_2, progress_height, - settings.progress_bar_corner_radius, scale, settings.progress_bar_corners); - cairo_fill(c); - - // top layer (fill) - cairo_matrix_t matrix; - cairo_matrix_init_scale(&matrix, 1.0 / progress_width_scaled, 1.0); - cairo_pattern_set_matrix(COLOR(cl, highlight->pattern), &matrix); - cairo_set_source(c, COLOR(cl, highlight->pattern)); - - draw_rounded_rect(c, x_bar_1, frame_y, progress_width_1, progress_height, - settings.progress_bar_corner_radius, scale, settings.progress_bar_corners); - cairo_fill(c); - - // border - cairo_set_source_rgba(c, COLOR(cl, frame.r), COLOR(cl, frame.g), COLOR(cl, frame.b), COLOR(cl, frame.a)); - cairo_set_line_width(c, frame_width * scale); - draw_rounded_rect(c, - frame_x + half_frame_width + 1, - frame_y, - progress_width - frame_width - 2, - progress_height, - settings.progress_bar_corner_radius, - scale, settings.progress_bar_corners); - cairo_stroke(c); - } + // top layer (fill) + cairo_matrix_t matrix; + cairo_matrix_init_scale(&matrix, 1.0 / progress_width_scaled, 1.0); + cairo_pattern_set_matrix(COLOR(cl, highlight->pattern), &matrix); + cairo_set_source(c, COLOR(cl, highlight->pattern)); + + draw_rounded_rect(c, + x_bar_1, + frame_y, + progress_width_1, + progress_height, + settings.progress_bar_corner_radius, + scale, + settings.progress_bar_corners); + cairo_fill(c); + + // border + cairo_set_source_rgba(c, + COLOR(cl, frame.r), + COLOR(cl, frame.g), + COLOR(cl, frame.b), + COLOR(cl, frame.a)); + cairo_set_line_width(c, frame_width * scale); + draw_rounded_rect(c, + frame_x + half_frame_width + 1, + frame_y, + progress_width - frame_width - 2, + progress_height, + settings.progress_bar_corner_radius, + scale, + settings.progress_bar_corners); + cairo_stroke(c); + } } static struct dimensions layout_render(cairo_surface_t *srf, @@ -931,144 +1030,154 @@ static struct dimensions layout_render(cairo_surface_t *srf, struct dimensions dim, enum corner_pos corners) { - double scale = output->get_scale(); - const int cl_h = layout_get_height(cl, scale); - - int bg_width = 0; - int bg_height = MAX(settings.height.min, 2 * settings.padding + cl_h); - bg_height = MIN(settings.height.max, bg_height); - - cairo_surface_t *content = render_background(srf, cl, cl_next, dim.y, dim.w, bg_height, dim.corner_radius, corners, &bg_width, scale); - cairo_t *c = cairo_create(content); - - render_content(c, cl, bg_width, bg_height, scale); - - /* adding frame */ - if (corners & (C_TOP | _C_FIRST)) - dim.y += settings.frame_width; - - if (corners & (C_BOT | _C_LAST)) - dim.y += settings.frame_width; - - dim.y += bg_height; - - if (settings.gap_size) - dim.y += settings.gap_size; - else - dim.y += settings.separator_height; - - cairo_destroy(c); - cairo_surface_destroy(content); - return dim; + double scale = output->get_scale(); + const int cl_h = layout_get_height(cl, scale); + + int bg_width = 0; + int bg_height = MAX(settings.height.min, 2 * settings.padding + cl_h); + bg_height = MIN(settings.height.max, bg_height); + + cairo_surface_t *content = render_background(srf, + cl, + cl_next, + dim.y, + dim.w, + bg_height, + dim.corner_radius, + corners, + &bg_width, + scale); + cairo_t *c = cairo_create(content); + + render_content(c, cl, bg_width, bg_height, scale); + + /* adding frame */ + if (corners & (C_TOP | _C_FIRST)) + dim.y += settings.frame_width; + + if (corners & (C_BOT | _C_LAST)) + dim.y += settings.frame_width; + + dim.y += bg_height; + + if (settings.gap_size) + dim.y += settings.gap_size; + else + dim.y += settings.separator_height; + + cairo_destroy(c); + cairo_surface_destroy(content); + return dim; } /** * Calculates the position the window should be placed at given its width and * height and stores them in \p ret_x and \p ret_y. */ -void calc_window_pos(const struct screen_info *scr, int width, int height, int *ret_x, int *ret_y) +void calc_window_pos(const struct screen_info *scr, + int width, + int height, + int *ret_x, + int *ret_y) { - if(!ret_x || !ret_y) - return; - - // horizontal - switch (settings.origin) { - case ORIGIN_TOP_LEFT: - case ORIGIN_LEFT_CENTER: - case ORIGIN_BOTTOM_LEFT: - *ret_x = scr->x + round(settings.offset.x * draw_get_scale()); - break; - case ORIGIN_TOP_RIGHT: - case ORIGIN_RIGHT_CENTER: - case ORIGIN_BOTTOM_RIGHT: - *ret_x = scr->x + (scr->w - width) - round(settings.offset.x * draw_get_scale()); - break; - case ORIGIN_TOP_CENTER: - case ORIGIN_CENTER: - case ORIGIN_BOTTOM_CENTER: - default: - *ret_x = scr->x + (scr->w - width) / 2; - break; - } - - // vertical - switch (settings.origin) { - case ORIGIN_TOP_LEFT: - case ORIGIN_TOP_CENTER: - case ORIGIN_TOP_RIGHT: - *ret_y = scr->y + round(settings.offset.y * draw_get_scale()); - break; - case ORIGIN_BOTTOM_LEFT: - case ORIGIN_BOTTOM_CENTER: - case ORIGIN_BOTTOM_RIGHT: - *ret_y = scr->y + (scr->h - height) - round(settings.offset.y * draw_get_scale()); - break; - case ORIGIN_LEFT_CENTER: - case ORIGIN_CENTER: - case ORIGIN_RIGHT_CENTER: - default: - *ret_y = scr->y + (scr->h - height) / 2; - break; - } + if (!ret_x || !ret_y) + return; + + // horizontal + switch (settings.origin) { + case ORIGIN_TOP_LEFT: + case ORIGIN_LEFT_CENTER: + case ORIGIN_BOTTOM_LEFT: + *ret_x = scr->x + round(settings.offset.x * draw_get_scale()); + break; + case ORIGIN_TOP_RIGHT: + case ORIGIN_RIGHT_CENTER: + case ORIGIN_BOTTOM_RIGHT: + *ret_x = scr->x + (scr->w - width) + - round(settings.offset.x * draw_get_scale()); + break; + case ORIGIN_TOP_CENTER: + case ORIGIN_CENTER: + case ORIGIN_BOTTOM_CENTER: + default: *ret_x = scr->x + (scr->w - width) / 2; break; + } + + // vertical + switch (settings.origin) { + case ORIGIN_TOP_LEFT: + case ORIGIN_TOP_CENTER: + case ORIGIN_TOP_RIGHT: + *ret_y = scr->y + round(settings.offset.y * draw_get_scale()); + break; + case ORIGIN_BOTTOM_LEFT: + case ORIGIN_BOTTOM_CENTER: + case ORIGIN_BOTTOM_RIGHT: + *ret_y = scr->y + (scr->h - height) + - round(settings.offset.y * draw_get_scale()); + break; + case ORIGIN_LEFT_CENTER: + case ORIGIN_CENTER: + case ORIGIN_RIGHT_CENTER: + default: *ret_y = scr->y + (scr->h - height) / 2; break; + } } void draw(void) { - assert(queues_length_displayed() > 0); + assert(queues_length_displayed() > 0); - cairo_t *c = output->win_get_context(win); + cairo_t *c = output->win_get_context(win); - if (c == NULL) { - return; - } + if (c == NULL) { + return; + } - GSList *layouts = create_layouts(c); + GSList *layouts = create_layouts(c); - struct dimensions dim = calculate_dimensions(layouts); - LOG_D("Window dimensions %ix%i", dim.w, dim.h); - double scale = output->get_scale(); + struct dimensions dim = calculate_dimensions(layouts); + LOG_D("Window dimensions %ix%i", dim.w, dim.h); + double scale = output->get_scale(); - cairo_surface_t *image_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - round(dim.w * scale), - round(dim.h * scale)); + cairo_surface_t *image_surface = cairo_image_surface_create( + CAIRO_FORMAT_ARGB32, round(dim.w * scale), round(dim.h * scale)); - enum corner_pos corners = (settings.corners & C_TOP) | _C_FIRST; - for (GSList *iter = layouts; iter; iter = iter->next) { + enum corner_pos corners = (settings.corners & C_TOP) | _C_FIRST; + for (GSList *iter = layouts; iter; iter = iter->next) { - struct colored_layout *cl_this = iter->data; - struct colored_layout *cl_next = iter->next ? iter->next->data : NULL; + struct colored_layout *cl_this = iter->data; + struct colored_layout *cl_next = iter->next ? iter->next->data : NULL; - if (settings.gap_size) - corners = settings.corners; - else if (!cl_next) - corners |= (settings.corners & C_BOT) | _C_LAST; + if (settings.gap_size) + corners = settings.corners; + else if (!cl_next) + corners |= (settings.corners & C_BOT) | _C_LAST; - dim = layout_render(image_surface, cl_this, cl_next, dim, corners); - corners &= ~(C_TOP | _C_FIRST); - } + dim = layout_render(image_surface, cl_this, cl_next, dim, corners); + corners &= ~(C_TOP | _C_FIRST); + } - output->display_surface(image_surface, win, &dim); + output->display_surface(image_surface, win, &dim); - cairo_surface_destroy(image_surface); - g_slist_free_full(layouts, free_colored_layout); + cairo_surface_destroy(image_surface); + g_slist_free_full(layouts, free_colored_layout); } void draw_deinit(void) { - pango_font_description_free(pango_fdesc); - output->win_destroy(win); - output->deinit(); - if (settings.enable_recursive_icon_lookup) - free_all_themes(); + pango_font_description_free(pango_fdesc); + output->win_destroy(win); + output->deinit(); + if (settings.enable_recursive_icon_lookup) + free_all_themes(); } double draw_get_scale(void) { - if (output) { - return output->get_scale(); - } else { - LOG_W("Called draw_get_scale before output init"); - return 1; - } + if (output) { + return output->get_scale(); + } else { + LOG_W("Called draw_get_scale before output init"); + return 1; + } } /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/draw.h b/src/draw.h index cac9d4f53..3260b74ad 100644 --- a/src/draw.h +++ b/src/draw.h @@ -1,9 +1,9 @@ #ifndef DUNST_DRAW_H #define DUNST_DRAW_H -#include -#include #include "output.h" +#include +#include extern window win; // Temporary extern const struct output *output; @@ -16,36 +16,42 @@ extern const struct output *output; * C_BOT_LEFT 0100 * C_BOT_RIGHT 1000 */ -enum corner_pos { - C_NONE = 0, - C_TOP_LEFT = 1 << 0, - C_TOP_RIGHT = 1 << 1, - C_BOT_LEFT = 1 << 2, - C_BOT_RIGHT = 1 << 3, - - // Handy combinations of the corners - C_TOP = C_TOP_LEFT | C_TOP_RIGHT, - C_BOT = C_BOT_LEFT | C_BOT_RIGHT, - C_LEFT = C_TOP_LEFT | C_BOT_LEFT, - C_RIGHT = C_TOP_RIGHT | C_BOT_RIGHT, - C_ALL = C_TOP | C_BOT, - - // These two values are internal only and - // should not be used outside of draw.c ! - _C_FIRST = 1 << 4, - _C_LAST = 1 << 5, +enum corner_pos +{ + C_NONE = 0, + C_TOP_LEFT = 1 << 0, + C_TOP_RIGHT = 1 << 1, + C_BOT_LEFT = 1 << 2, + C_BOT_RIGHT = 1 << 3, + + // Handy combinations of the corners + C_TOP = C_TOP_LEFT | C_TOP_RIGHT, + C_BOT = C_BOT_LEFT | C_BOT_RIGHT, + C_LEFT = C_TOP_LEFT | C_BOT_LEFT, + C_RIGHT = C_TOP_RIGHT | C_BOT_RIGHT, + C_ALL = C_TOP | C_BOT, + + // These two values are internal only and + // should not be used outside of draw.c ! + _C_FIRST = 1 << 4, + _C_LAST = 1 << 5, }; -struct color { - double r; - double g; - double b; - double a; +struct color +{ + double r; + double g; + double b; + double a; }; -#define COLOR_UNINIT { -1, -1, -1, -1 } -#define COLOR_VALID(c) ((c).r >= 0 && (c).g >= 0 && (c).b >= 0 && (c).a >= 0 && (c).r <= 1 && (c).g <= 1 && (c).b <= 1 && (c).a <= 1) -#define COLOR_SAME(c1, c2) ((c1).r == (c2).r && (c1).g == (c2).g && (c1).b == (c2).b && (c1).a == (c2).a) +#define COLOR_UNINIT {-1, -1, -1, -1} +#define COLOR_VALID(c) \ + ((c).r >= 0 && (c).g >= 0 && (c).b >= 0 && (c).a >= 0 && (c).r <= 1 \ + && (c).g <= 1 && (c).b <= 1 && (c).a <= 1) +#define COLOR_SAME(c1, c2) \ + ((c1).r == (c2).r && (c1).g == (c2).g && (c1).b == (c2).b \ + && (c1).a == (c2).a) /** * Stringify a color struct to a RRGGBBAA string. @@ -53,10 +59,11 @@ struct color { */ char *color_to_string(struct color c, char buf[10]); -struct gradient { - cairo_pattern_t *pattern; - size_t length; - struct color colors[]; +struct gradient +{ + cairo_pattern_t *pattern; + size_t length; + struct color colors[]; }; #define GRADIENT_VALID(g) ((g) != NULL && (g)->length != 0) @@ -71,19 +78,29 @@ void gradient_pattern(struct gradient *grad); char *gradient_to_string(const struct gradient *grad); - void draw_setup(void); void draw(void); -void draw_rounded_rect(cairo_t *c, float x, float y, int width, int height, int corner_radius, double scale, enum corner_pos corners); +void draw_rounded_rect(cairo_t *c, + float x, + float y, + int width, + int height, + int corner_radius, + double scale, + enum corner_pos corners); // TODO get rid of this function by passing scale to everything that needs it. double draw_get_scale(void); void draw_deinit(void); -void calc_window_pos(const struct screen_info *scr, int width, int height, int *ret_x, int *ret_y); +void calc_window_pos(const struct screen_info *scr, + int width, + int height, + int *ret_x, + int *ret_y); #endif /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/dunst.c b/src/dunst.c index 2d5217ade..7b12e05b6 100644 --- a/src/dunst.c +++ b/src/dunst.c @@ -1,10 +1,11 @@ -/* copyright 2012 - 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2012 - 2013 Sascha Kruse and contributors (see LICENSE for + * licensing information) */ #include "dunst.h" #include -#include #include +#include #include #include #include @@ -14,13 +15,13 @@ #include "draw.h" #include "log.h" #include "menu.h" -#include "rules.h" #include "notification.h" #include "option_parser.h" +#include "output.h" #include "queues.h" +#include "rules.h" #include "settings.h" #include "utils.h" -#include "output.h" GMainLoop *mainloop = NULL; @@ -29,39 +30,37 @@ static bool setup_done = false; char **config_paths = NULL; /* see dunst.h */ -void dunst_status(const enum dunst_status_field field, - bool value) +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; - default: - LOG_E("Invalid %s enum value in %s:%d for bool type", "dunst_status", __FILE__, __LINE__); - break; - } + switch (field) { + case S_FULLSCREEN: status.fullscreen = value; break; + case S_IDLE: status.idle = value; break; + default: + LOG_E("Invalid %s enum value in %s:%d for bool type", + "dunst_status", + __FILE__, + __LINE__); + break; + } } -void dunst_status_int(const enum dunst_status_field field, - int value) +void dunst_status_int(const enum dunst_status_field field, int value) { - switch (field) { - case S_PAUSE_LEVEL: - status.pause_level = value; - break; - default: - LOG_E("Invalid %s enum value in %s:%d for int type", "dunst_status", __FILE__, __LINE__); - break; - } + switch (field) { + case S_PAUSE_LEVEL: status.pause_level = value; break; + default: + LOG_E("Invalid %s enum value in %s:%d for int type", + "dunst_status", + __FILE__, + __LINE__); + break; + } } /* see dunst.h */ struct dunst_status dunst_status_get(void) { - return status; + return status; } /* misc functions */ @@ -74,289 +73,296 @@ static gboolean run(void *data); * - DUNST_WAKEUP: an external event (eg. new notification) triggered a call to * wake_up (unscheduled wakeup) */ -enum dunst_run_reason { - DUNST_TIMER, - DUNST_WAKEUP, +enum dunst_run_reason +{ + DUNST_TIMER, + DUNST_WAKEUP, }; -const char* dunst_run_reason_str(enum dunst_run_reason reason) { - switch(reason) { - case DUNST_TIMER: - return "DUNST_TIMER"; - case DUNST_WAKEUP: - return "DUNST_WAKEUP"; - default: - return "BAD VALUE"; - } +const char *dunst_run_reason_str(enum dunst_run_reason reason) +{ + switch (reason) { + case DUNST_TIMER: return "DUNST_TIMER"; + case DUNST_WAKEUP: return "DUNST_WAKEUP"; + default: return "BAD VALUE"; + } } void wake_up(void) { - // If wake_up is being called before the output has been setup we should - // return. - if (!setup_done) { - LOG_D("Ignoring wake up"); - return; - } - - LOG_D("Waking up"); - run(GINT_TO_POINTER(DUNST_WAKEUP)); + // If wake_up is being called before the output has been setup we should + // return. + if (!setup_done) { + LOG_D("Ignoring wake up"); + return; + } + + LOG_D("Waking up"); + run(GINT_TO_POINTER(DUNST_WAKEUP)); } static gboolean run(void *data) { - /* Timer gestion - * ============= - * - * - At any time (except transiently during the execution of `run`), at - * most one glib timeout source (or "timer" here) exists. If `run` - * was invoked by a timer, it will be deleted upon return, as the - * function always returns G_SOURCE_REMOVE. - * - Furthermore, if next_timeout_id is not null, a timer with this - * glib source id exists and is running. As a consequence, - * - if reason is DUNST_TIMER, it is the timer that triggered the - * current call to run; - * - if reason is DUNST_WAKEUP, this timer was scheduled some time in - * the future (or in the past, but not yet executed my the main loop, - * which is equivalent for our purpose). - * - * Thus, in each call to run, - * - if reason is DUNST_WAKEUP and next_timeout_id != 0, we delete this - * timer -- we now have more recent information on which we can - * decide of a (maybe) better timeout. - * - in any case, we reset next_timeout_id to 0. - * - if there is any event to be run in the future, we set a new timer - * to this time, and update next_timeout_id accordingly. - */ - - static guint next_timeout_id = 0; - enum dunst_run_reason reason = GPOINTER_TO_INT(data); - - LOG_D("RUN, reason %i: %s", reason, dunst_run_reason_str(reason)); - gint64 now = time_monotonic_now(); - - dunst_status(S_FULLSCREEN, output->have_fullscreen_window()); - dunst_status(S_IDLE, output->is_idle()); - - queues_update(status, now); - - if(reason == DUNST_WAKEUP && next_timeout_id != 0) { - // Delete the upcoming timer - g_source_remove(next_timeout_id); - } - next_timeout_id = 0; - - if (!queues_length_displayed()) { - output->win_hide(win); - return G_SOURCE_REMOVE; - } - - // Call draw before showing the window to avoid flickering - draw(); - output->win_show(win); - - gint64 timeout_at = queues_get_next_datachange(now); - if (timeout_at != -1) { - // Previous computations may have taken time, update `now` - // This might mean that `timeout_at` is now before `now`, so - // we have to make sure that `sleep` is still positive. - now = time_monotonic_now(); - gint64 sleep = timeout_at - now; - sleep = MAX(sleep, 1000); // Sleep at least 1ms - - LOG_D("Sleeping for %"G_GINT64_FORMAT" ms", sleep/1000); - - next_timeout_id = g_timeout_add(sleep/1000, run, NULL); - } - - /* If the execution got triggered by g_timeout_add, - * we have to remove the timeout (which is actually a - * recurring interval), as we have set a new one - * by ourselves. - */ + /* Timer gestion + * ============= + * + * - At any time (except transiently during the execution of `run`), at + * most one glib timeout source (or "timer" here) exists. If `run` + * was invoked by a timer, it will be deleted upon return, as the + * function always returns G_SOURCE_REMOVE. + * - Furthermore, if next_timeout_id is not null, a timer with this + * glib source id exists and is running. As a consequence, + * - if reason is DUNST_TIMER, it is the timer that triggered the + * current call to run; + * - if reason is DUNST_WAKEUP, this timer was scheduled some time in + * the future (or in the past, but not yet executed my the main loop, + * which is equivalent for our purpose). + * + * Thus, in each call to run, + * - if reason is DUNST_WAKEUP and next_timeout_id != 0, we delete this + * timer -- we now have more recent information on which we can + * decide of a (maybe) better timeout. + * - in any case, we reset next_timeout_id to 0. + * - if there is any event to be run in the future, we set a new timer + * to this time, and update next_timeout_id accordingly. + */ + + static guint next_timeout_id = 0; + enum dunst_run_reason reason = GPOINTER_TO_INT(data); + + LOG_D("RUN, reason %i: %s", reason, dunst_run_reason_str(reason)); + gint64 now = time_monotonic_now(); + + dunst_status(S_FULLSCREEN, output->have_fullscreen_window()); + dunst_status(S_IDLE, output->is_idle()); + + queues_update(status, now); + + if (reason == DUNST_WAKEUP && next_timeout_id != 0) { + // Delete the upcoming timer + g_source_remove(next_timeout_id); + } + next_timeout_id = 0; + + if (!queues_length_displayed()) { + output->win_hide(win); return G_SOURCE_REMOVE; + } + + // Call draw before showing the window to avoid flickering + draw(); + output->win_show(win); + + gint64 timeout_at = queues_get_next_datachange(now); + if (timeout_at != -1) { + // Previous computations may have taken time, update `now` + // This might mean that `timeout_at` is now before `now`, so + // we have to make sure that `sleep` is still positive. + now = time_monotonic_now(); + gint64 sleep = timeout_at - now; + sleep = MAX(sleep, 1000); // Sleep at least 1ms + + LOG_D("Sleeping for %" G_GINT64_FORMAT " ms", sleep / 1000); + + next_timeout_id = g_timeout_add(sleep / 1000, run, NULL); + } + + /* If the execution got triggered by g_timeout_add, + * we have to remove the timeout (which is actually a + * recurring interval), as we have set a new one + * by ourselves. + */ + return G_SOURCE_REMOVE; } gboolean pause_signal(gpointer data) { - (void)data; + (void)data; - dunst_status_int(S_PAUSE_LEVEL, MAX_PAUSE_LEVEL); - wake_up(); + dunst_status_int(S_PAUSE_LEVEL, MAX_PAUSE_LEVEL); + wake_up(); - return G_SOURCE_CONTINUE; + return G_SOURCE_CONTINUE; } gboolean unpause_signal(gpointer data) { - (void)data; + (void)data; - dunst_status_int(S_PAUSE_LEVEL, 0); - wake_up(); + dunst_status_int(S_PAUSE_LEVEL, 0); + wake_up(); - return G_SOURCE_CONTINUE; + return G_SOURCE_CONTINUE; } gboolean quit_signal(gpointer data) { - (void)data; - g_main_loop_quit(mainloop); + (void)data; + g_main_loop_quit(mainloop); - return G_SOURCE_CONTINUE; + return G_SOURCE_CONTINUE; } static void teardown(void) { - regex_teardown(); + regex_teardown(); - queues_teardown(); + queues_teardown(); - draw_deinit(); + draw_deinit(); - g_strfreev(config_paths); + g_strfreev(config_paths); - g_slist_free_full(rules, (GDestroyNotify)rule_free); + g_slist_free_full(rules, (GDestroyNotify)rule_free); } void reload(char **const configs) { - guint length = g_strv_length(configs); - LOG_M("Reloading settings (with the %s files)", length != 0 ? "new" : "old"); + guint length = g_strv_length(configs); + LOG_M("Reloading settings (with the %s files)", + length != 0 ? "new" : "old"); - pause_signal(NULL); + pause_signal(NULL); - setup_done = false; - draw_deinit(); + setup_done = false; + draw_deinit(); - g_slist_free_full(rules, (GDestroyNotify)rule_free); - rules = NULL; + g_slist_free_full(rules, (GDestroyNotify)rule_free); + rules = NULL; - settings_free(&settings); - load_settings(length != 0 ? configs : config_paths); + settings_free(&settings); + load_settings(length != 0 ? configs : config_paths); - draw_setup(); - setup_done = true; + draw_setup(); + setup_done = true; - queues_reapply_all_rules(); + queues_reapply_all_rules(); - unpause_signal(NULL); + unpause_signal(NULL); } int dunst_main(int argc, char *argv[]) { - dunst_status_int(S_PAUSE_LEVEL, 0); - dunst_status(S_IDLE, false); + dunst_status_int(S_PAUSE_LEVEL, 0); + dunst_status(S_IDLE, false); - queues_init(); + queues_init(); - cmdline_load(argc, argv); + cmdline_load(argc, argv); - dunst_log_init(DUNST_LOG_AUTO); + dunst_log_init(DUNST_LOG_AUTO); - if (cmdline_get_bool("-v/-version/--version", false, "Print version")) { - print_version(); - } + if (cmdline_get_bool("-v/-version/--version", false, "Print version")) { + print_version(); + } - char *verbosity = cmdline_get_string("-verbosity", NULL, "Minimum level for message"); - log_set_level_from_string(verbosity); - g_free(verbosity); + char *verbosity = + cmdline_get_string("-verbosity", NULL, "Minimum level for message"); + log_set_level_from_string(verbosity); + g_free(verbosity); - cmdline_usage_append("-conf/-config", "string", "Path to configuration file"); + cmdline_usage_append( + "-conf/-config", "string", "Path to configuration file"); - int start = 1, count = 1; - while (cmdline_get_string_offset("-conf/-config", NULL, start, &start)) - count++; + int start = 1, count = 1; + while (cmdline_get_string_offset("-conf/-config", NULL, start, &start)) + count++; - // Leaves an extra space for the NULL - config_paths = g_malloc0(sizeof(char *) * count); - start = 1, count = 0; - char *path = NULL; + // Leaves an extra space for the NULL + config_paths = g_malloc0(sizeof(char *) * count); + start = 1, count = 0; + char *path = NULL; - do { - path = cmdline_get_string_offset("-conf/-config", NULL, start, &start); - config_paths[count++] = path; - } while (path != NULL); + do { + path = cmdline_get_string_offset("-conf/-config", NULL, start, &start); + config_paths[count++] = path; + } while (path != NULL); - print_notifications = cmdline_get_bool("-print/--print", false, "Print notifications to stdout"); + print_notifications = cmdline_get_bool( + "-print/--print", false, "Print notifications to stdout"); - bool startup_notification = cmdline_get_bool("-startup_notification/--startup_notification", - false, "Display a notification on startup."); + bool startup_notification = + cmdline_get_bool("-startup_notification/--startup_notification", + false, + "Display a notification on startup."); - /* Help should always be the last to set up as calls to cmdline_get_* (as a side effect) add entries to the usage list. */ - if (cmdline_get_bool("-h/-help/--help", false, "Print help")) { - usage(EXIT_SUCCESS); - } + /* Help should always be the last to set up as calls to cmdline_get_* (as a + * side effect) add entries to the usage list. */ + if (cmdline_get_bool("-h/-help/--help", false, "Print help")) { + usage(EXIT_SUCCESS); + } - load_settings(config_paths); - int dbus_owner_id = dbus_init(); + load_settings(config_paths); + int dbus_owner_id = dbus_init(); - mainloop = g_main_loop_new(NULL, FALSE); + mainloop = g_main_loop_new(NULL, FALSE); - draw_setup(); + draw_setup(); - guint pause_src = g_unix_signal_add(SIGUSR1, pause_signal, NULL); - guint unpause_src = g_unix_signal_add(SIGUSR2, unpause_signal, NULL); + guint pause_src = g_unix_signal_add(SIGUSR1, pause_signal, NULL); + guint unpause_src = g_unix_signal_add(SIGUSR2, unpause_signal, NULL); - /* register SIGINT/SIGTERM handler for - * graceful termination */ - guint term_src = g_unix_signal_add(SIGTERM, quit_signal, NULL); - guint int_src = g_unix_signal_add(SIGINT, quit_signal, NULL); + /* register SIGINT/SIGTERM handler for + * graceful termination */ + guint term_src = g_unix_signal_add(SIGTERM, quit_signal, NULL); + guint int_src = g_unix_signal_add(SIGINT, quit_signal, NULL); - if (startup_notification) { - struct notification *n = notification_create(); - n->id = 0; - n->appname = g_strdup("dunst"); - n->summary = g_strdup("startup"); - n->body = g_strdup("dunst is up and running"); - n->progress = -1; - n->timeout = S2US(10); - n->markup = MARKUP_NO; - n->urgency = URG_LOW; - notification_init(n); - queues_notification_insert(n); - // we do not call wakeup now, wake_up does not work here yet - } + if (startup_notification) { + struct notification *n = notification_create(); + n->id = 0; + n->appname = g_strdup("dunst"); + n->summary = g_strdup("startup"); + n->body = g_strdup("dunst is up and running"); + n->progress = -1; + n->timeout = S2US(10); + n->markup = MARKUP_NO; + n->urgency = URG_LOW; + notification_init(n); + queues_notification_insert(n); + // we do not call wakeup now, wake_up does not work here yet + } - setup_done = true; - run(GINT_TO_POINTER(DUNST_TIMER)); // The first run() is a scheduled one - g_main_loop_run(mainloop); - g_clear_pointer(&mainloop, g_main_loop_unref); + setup_done = true; + run(GINT_TO_POINTER(DUNST_TIMER)); // The first run() is a scheduled one + g_main_loop_run(mainloop); + g_clear_pointer(&mainloop, g_main_loop_unref); - /* remove signal handler watches */ - g_source_remove(pause_src); - g_source_remove(unpause_src); - g_source_remove(term_src); - g_source_remove(int_src); + /* remove signal handler watches */ + g_source_remove(pause_src); + g_source_remove(unpause_src); + g_source_remove(term_src); + g_source_remove(int_src); - dbus_teardown(dbus_owner_id); + dbus_teardown(dbus_owner_id); - teardown(); + teardown(); - settings_free(&settings); + settings_free(&settings); - return 0; + return 0; } void usage(int exit_status) { - puts("usage:\n"); - const char *us = cmdline_create_usage(); - puts(us); - exit(exit_status); + puts("usage:\n"); + const char *us = cmdline_create_usage(); + puts(us); + exit(exit_status); } void print_version(void) { - printf("Dunst - A customizable and lightweight notification-daemon %s\n", VERSION); - printf("Compiled on %s with the following options:\n", STR_TO(_CCDATE)); + printf("Dunst - A customizable and lightweight notification-daemon %s\n", + VERSION); + printf("Compiled on %s with the following options:\n", STR_TO(_CCDATE)); - printf("X11 support: %s\n", X11_SUPPORT ? "enabled" : "disabled"); - printf("Wayland support: %s\n", WAYLAND_SUPPORT ? "enabled" : "disabled"); - printf("SYSCONFDIR set to: %s\n", SYSCONFDIR); + printf("X11 support: %s\n", X11_SUPPORT ? "enabled" : "disabled"); + printf("Wayland support: %s\n", WAYLAND_SUPPORT ? "enabled" : "disabled"); + printf("SYSCONFDIR set to: %s\n", SYSCONFDIR); - printf("Compiler flags: %s\n", STR_TO(_CFLAGS)); - printf("Linker flags: %s\n", STR_TO(_LDFLAGS)); - exit(EXIT_SUCCESS); + printf("Compiler flags: %s\n", STR_TO(_CFLAGS)); + printf("Linker flags: %s\n", STR_TO(_LDFLAGS)); + exit(EXIT_SUCCESS); } /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/dunst.h b/src/dunst.h index 8f5b35ad9..afe00bacb 100644 --- a/src/dunst.h +++ b/src/dunst.h @@ -1,28 +1,32 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ #ifndef DUNST_DUNST_H #define DUNST_DUNST_H #include #include -#include #include +#include #include "notification.h" #define MAX_PAUSE_LEVEL 100 //!< A structure to describe dunst's global window status -struct dunst_status { - bool fullscreen; //!< a fullscreen window is currently focused - int pause_level; //!< current pause level. 0 = all notifications come through, 100 = no notifications come through - bool idle; //!< set true if the user is idle +struct dunst_status +{ + bool fullscreen; //!< a fullscreen window is currently focused + int pause_level; //!< current pause level. 0 = all notifications come + //!< through, 100 = no notifications come through + bool idle; //!< set true if the user is idle }; -enum dunst_status_field { - S_FULLSCREEN, - S_IDLE, - S_PAUSE_LEVEL, +enum dunst_status_field +{ + S_FULLSCREEN, + S_IDLE, + S_PAUSE_LEVEL, }; extern char **config_paths; @@ -32,10 +36,8 @@ extern char **config_paths; * @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); -void dunst_status_int(const enum dunst_status_field field, - int value); +void dunst_status(const enum dunst_status_field field, bool value); +void dunst_status_int(const enum dunst_status_field field, int value); struct dunst_status dunst_status_get(void); diff --git a/src/icon-lookup.c b/src/icon-lookup.c index 7156ca8c6..7a70c9851 100644 --- a/src/icon-lookup.c +++ b/src/icon-lookup.c @@ -1,27 +1,28 @@ #define _GNU_SOURCE #include "icon-lookup.h" +#include #include #include #include -#include #include "ini.h" -#include "utils.h" #include "log.h" +#include "utils.h" struct icon_theme *icon_themes = NULL; int icon_themes_count = 0; int *default_themes_index = NULL; int default_themes_count = 0; -int get_icon_theme(char *name) { - for (int i = 0; i < icon_themes_count; i++) { - if (STR_EQ(icon_themes[i].subdir_theme, name)) { - return i; - } +int get_icon_theme(char *name) +{ + for (int i = 0; i < icon_themes_count; i++) { + if (STR_EQ(icon_themes[i].subdir_theme, name)) { + return i; } - return -1; + } + return -1; } /** @@ -37,282 +38,303 @@ int get_icon_theme(char *name) { * @returns the index to the theme that was loaded * @retval -1 means no index was found */ -int load_icon_theme_from_dir(const char *icon_dir, const char *subdir_theme) { - LOG_D("Loading theme %s/%s", STR_NN(icon_dir), STR_NN(subdir_theme)); - char *theme_index_dir = g_build_filename(icon_dir, subdir_theme, "index.theme", NULL); - FILE *theme_index = fopen(theme_index_dir, "r"); - g_free(theme_index_dir); - if (!theme_index) - return -1; - - struct ini *ini = load_ini_file(theme_index); - fclose(theme_index); - if (ini->section_count == 0) { - finish_ini(ini); - g_free(ini); - return -1; - } - - icon_themes_count++; - icon_themes = g_realloc(icon_themes, icon_themes_count * sizeof(struct icon_theme)); - int index = icon_themes_count - 1; - icon_themes[index].name = g_strdup(section_get_value(ini, &ini->sections[0], "Name")); - icon_themes[index].location = g_strdup(icon_dir); - icon_themes[index].subdir_theme = g_strdup(subdir_theme); - icon_themes[index].inherits_index = NULL; - icon_themes[index].inherits_count = 0; - - // load theme directories - icon_themes[index].dirs_count = ini->section_count - 1; - icon_themes[index].dirs = g_malloc0_n(icon_themes[index].dirs_count, sizeof(struct icon_theme_dir)); - - for (int i = 0; i < icon_themes[index].dirs_count; i++) { - struct section section = ini->sections[i+1]; - icon_themes[index].dirs[i].name = g_strdup(section.name); - - // read size - const char *size_str = section_get_value(ini, §ion, "Size"); - safe_string_to_int(&icon_themes[index].dirs[i].size, size_str); - - // read optional scale, defaulting to 1 - const char *scale_str = section_get_value(ini, §ion, "Scale"); - icon_themes[index].dirs[i].scale = 1; - if (scale_str) { - safe_string_to_int(&icon_themes[index].dirs[i].scale, scale_str); - } - - // read type - const char *type = section_get_value(ini, §ion, "Type"); - if (STR_EQ(type, "Fixed")) { - icon_themes[index].dirs[i].type = THEME_DIR_FIXED; - } else if (STR_EQ(type, "Scalable")) { - icon_themes[index].dirs[i].type = THEME_DIR_SCALABLE; - } else if (STR_EQ(type, "Threshold")) { - icon_themes[index].dirs[i].type = THEME_DIR_THRESHOLD; - } else { - // default to type threshold - icon_themes[index].dirs[i].type = THEME_DIR_THRESHOLD; - } +int load_icon_theme_from_dir(const char *icon_dir, const char *subdir_theme) +{ + LOG_D("Loading theme %s/%s", STR_NN(icon_dir), STR_NN(subdir_theme)); + char *theme_index_dir = + g_build_filename(icon_dir, subdir_theme, "index.theme", NULL); + FILE *theme_index = fopen(theme_index_dir, "r"); + g_free(theme_index_dir); + if (!theme_index) + return -1; - // read type-specific data - if (icon_themes[index].dirs[i].type == THEME_DIR_SCALABLE) { - const char *min_size = section_get_value(ini, §ion, "MinSize"); - if (min_size) - safe_string_to_int(&icon_themes[index].dirs[i].min_size, min_size); - else - icon_themes[index].dirs[i].min_size = icon_themes[index].dirs[i].size; - - const char *max_size = section_get_value(ini, §ion, "MaxSize"); - if (max_size) - safe_string_to_int(&icon_themes[index].dirs[i].max_size, max_size); - else - icon_themes[index].dirs[i].max_size = icon_themes[index].dirs[i].size; - - } else if (icon_themes[index].dirs[i].type == THEME_DIR_THRESHOLD) { - icon_themes[index].dirs[i].threshold = 2; - const char *threshold = section_get_value(ini, §ion, "Threshold"); - if (threshold) { - safe_string_to_int(&icon_themes[index].dirs[i].threshold, threshold); - } - } + struct ini *ini = load_ini_file(theme_index); + fclose(theme_index); + if (ini->section_count == 0) { + finish_ini(ini); + g_free(ini); + return -1; + } + + icon_themes_count++; + icon_themes = + g_realloc(icon_themes, icon_themes_count * sizeof(struct icon_theme)); + int index = icon_themes_count - 1; + icon_themes[index].name = + g_strdup(section_get_value(ini, &ini->sections[0], "Name")); + icon_themes[index].location = g_strdup(icon_dir); + icon_themes[index].subdir_theme = g_strdup(subdir_theme); + icon_themes[index].inherits_index = NULL; + icon_themes[index].inherits_count = 0; + + // load theme directories + icon_themes[index].dirs_count = ini->section_count - 1; + icon_themes[index].dirs = g_malloc0_n(icon_themes[index].dirs_count, + sizeof(struct icon_theme_dir)); + + for (int i = 0; i < icon_themes[index].dirs_count; i++) { + struct section section = ini->sections[i + 1]; + icon_themes[index].dirs[i].name = g_strdup(section.name); + + // read size + const char *size_str = section_get_value(ini, §ion, "Size"); + safe_string_to_int(&icon_themes[index].dirs[i].size, size_str); + + // read optional scale, defaulting to 1 + const char *scale_str = section_get_value(ini, §ion, "Scale"); + icon_themes[index].dirs[i].scale = 1; + if (scale_str) { + safe_string_to_int(&icon_themes[index].dirs[i].scale, scale_str); } - - // load inherited themes - if (!STR_EQ(icon_themes[index].name, "Hicolor")) { - char **inherits = string_to_array(get_value(ini, "Icon Theme", "Inherits"), ","); - icon_themes[index].inherits_count = string_array_length(inherits); - LOG_D("Theme has %i inherited themes", icon_themes[index].inherits_count); - if (icon_themes[index].inherits_count <= 0) { - // set fallback theme to hicolor if there are no inherits - g_strfreev(inherits); - inherits = g_malloc0_n(2, sizeof(char*)); - inherits[0] = g_strdup("hicolor"); - inherits[1] = NULL; - icon_themes[index].inherits_count = 1; - } - - icon_themes[index].inherits_index = g_malloc0_n(icon_themes[index].inherits_count, sizeof(int)); - - for (int i = 0; inherits[i] != NULL; i++) { - LOG_D("inherits: %s", inherits[i]); - icon_themes[index].inherits_index[i] = get_icon_theme(inherits[i]); - if (icon_themes[index].inherits_index[i] == -1) { - LOG_D("Loading inherited theme"); - // FIXME don't use a pointer to the theme, - // since it may be invalidated after realloc. Use an index instead - icon_themes[index].inherits_index[i] = load_icon_theme(inherits[i]); - } - } - g_strfreev(inherits); + // read type + const char *type = section_get_value(ini, §ion, "Type"); + if (STR_EQ(type, "Fixed")) { + icon_themes[index].dirs[i].type = THEME_DIR_FIXED; + } else if (STR_EQ(type, "Scalable")) { + icon_themes[index].dirs[i].type = THEME_DIR_SCALABLE; + } else if (STR_EQ(type, "Threshold")) { + icon_themes[index].dirs[i].type = THEME_DIR_THRESHOLD; + } else { + // default to type threshold + icon_themes[index].dirs[i].type = THEME_DIR_THRESHOLD; } + // read type-specific data + if (icon_themes[index].dirs[i].type == THEME_DIR_SCALABLE) { + const char *min_size = section_get_value(ini, §ion, "MinSize"); + if (min_size) + safe_string_to_int(&icon_themes[index].dirs[i].min_size, + min_size); + else + icon_themes[index].dirs[i].min_size = + icon_themes[index].dirs[i].size; + + const char *max_size = section_get_value(ini, §ion, "MaxSize"); + if (max_size) + safe_string_to_int(&icon_themes[index].dirs[i].max_size, + max_size); + else + icon_themes[index].dirs[i].max_size = + icon_themes[index].dirs[i].size; + + } else if (icon_themes[index].dirs[i].type == THEME_DIR_THRESHOLD) { + icon_themes[index].dirs[i].threshold = 2; + const char *threshold = + section_get_value(ini, §ion, "Threshold"); + if (threshold) { + safe_string_to_int(&icon_themes[index].dirs[i].threshold, + threshold); + } + } + } + + // load inherited themes + if (!STR_EQ(icon_themes[index].name, "Hicolor")) { + char **inherits = + string_to_array(get_value(ini, "Icon Theme", "Inherits"), ","); + icon_themes[index].inherits_count = string_array_length(inherits); + LOG_D("Theme has %i inherited themes", + icon_themes[index].inherits_count); + if (icon_themes[index].inherits_count <= 0) { + // set fallback theme to hicolor if there are no inherits + g_strfreev(inherits); + inherits = g_malloc0_n(2, sizeof(char *)); + inherits[0] = g_strdup("hicolor"); + inherits[1] = NULL; + icon_themes[index].inherits_count = 1; + } + icon_themes[index].inherits_index = + g_malloc0_n(icon_themes[index].inherits_count, sizeof(int)); + + for (int i = 0; inherits[i] != NULL; i++) { + LOG_D("inherits: %s", inherits[i]); + icon_themes[index].inherits_index[i] = get_icon_theme(inherits[i]); + if (icon_themes[index].inherits_index[i] == -1) { + LOG_D("Loading inherited theme"); + // FIXME don't use a pointer to the theme, + // since it may be invalidated after realloc. Use an index + // instead + icon_themes[index].inherits_index[i] = + load_icon_theme(inherits[i]); + } + } + g_strfreev(inherits); + } - finish_ini(ini); - g_free(ini); - return index; + finish_ini(ini); + g_free(ini); + return index; } // a list of directories where icon themes might be located GPtrArray *theme_path = NULL; -void get_theme_path(void) { - theme_path = g_ptr_array_new_full(5, g_free); - const char *home = g_get_home_dir(); - g_ptr_array_add(theme_path, g_build_filename(home, ".icons", NULL)); - - char *data_home_default = g_build_filename(home, ".local", "share", NULL); - add_paths_from_env(theme_path, "XDG_DATA_HOME", "icons", data_home_default); - g_free(data_home_default); - - add_paths_from_env(theme_path, "XDG_DATA_DIRS", "icons", "/usr/local/share/:/usr/share/"); - g_ptr_array_add(theme_path, g_strdup("/usr/share/pixmaps")); - for (size_t i = 0; i < theme_path->len; i++) { - LOG_D("Theme locations: %s", (char*)theme_path->pdata[i]); - } +void get_theme_path(void) +{ + theme_path = g_ptr_array_new_full(5, g_free); + const char *home = g_get_home_dir(); + g_ptr_array_add(theme_path, g_build_filename(home, ".icons", NULL)); + + char *data_home_default = g_build_filename(home, ".local", "share", NULL); + add_paths_from_env(theme_path, "XDG_DATA_HOME", "icons", data_home_default); + g_free(data_home_default); + + add_paths_from_env( + theme_path, "XDG_DATA_DIRS", "icons", "/usr/local/share/:/usr/share/"); + g_ptr_array_add(theme_path, g_strdup("/usr/share/pixmaps")); + for (size_t i = 0; i < theme_path->len; i++) { + LOG_D("Theme locations: %s", (char *)theme_path->pdata[i]); + } } // see icon-lookup.h -int load_icon_theme(char *name) { - if(!theme_path) { - get_theme_path(); - } - - for (size_t i = 0; i < theme_path->len; i++) { - int theme_index = load_icon_theme_from_dir(theme_path->pdata[i], name); - if (theme_index != -1) - return theme_index; - } - - LOG_W("Could not find theme %s", STR_NN(name)); - return -1; +int load_icon_theme(char *name) +{ + if (!theme_path) { + get_theme_path(); + } + + for (size_t i = 0; i < theme_path->len; i++) { + int theme_index = load_icon_theme_from_dir(theme_path->pdata[i], name); + if (theme_index != -1) + return theme_index; + } + + LOG_W("Could not find theme %s", STR_NN(name)); + return -1; } -void finish_icon_theme_dir(struct icon_theme_dir *dir) { - if (!dir) - return; - g_free(dir->name); +void finish_icon_theme_dir(struct icon_theme_dir *dir) +{ + if (!dir) + return; + g_free(dir->name); } -void finish_icon_theme(struct icon_theme *theme) { - if (!theme) - return; - for (int i = 0; i < theme->dirs_count; i++) { - finish_icon_theme_dir(&theme->dirs[i]); - } - g_free(theme->name); - g_free(theme->location); - g_free(theme->subdir_theme); - g_free(theme->inherits_index); - g_free(theme->dirs); +void finish_icon_theme(struct icon_theme *theme) +{ + if (!theme) + return; + for (int i = 0; i < theme->dirs_count; i++) { + finish_icon_theme_dir(&theme->dirs[i]); + } + g_free(theme->name); + g_free(theme->location); + g_free(theme->subdir_theme); + g_free(theme->inherits_index); + g_free(theme->dirs); } -void free_all_themes(void) { - g_free(default_themes_index); - default_themes_index = NULL; - default_themes_count = 0; - LOG_D("Finishing %i themes", icon_themes_count); - for (int i = 0; i < icon_themes_count; i++) { - finish_icon_theme(&icon_themes[i]); - } - g_free(icon_themes); - icon_themes_count = 0; - icon_themes = NULL; - g_ptr_array_unref(theme_path); - theme_path = NULL; +void free_all_themes(void) +{ + g_free(default_themes_index); + default_themes_index = NULL; + default_themes_count = 0; + LOG_D("Finishing %i themes", icon_themes_count); + for (int i = 0; i < icon_themes_count; i++) { + finish_icon_theme(&icon_themes[i]); + } + g_free(icon_themes); + icon_themes_count = 0; + icon_themes = NULL; + g_ptr_array_unref(theme_path); + theme_path = NULL; } // see icon-lookup.h -void add_default_theme(int theme_index) { - if (theme_index < 0) { - LOG_W("Invalid theme index: %i", theme_index); - return; - } - if (theme_index >= icon_themes_count) { - LOG_W("Invalid theme index: %i. Theme does not exists.", - theme_index); - return; - } - default_themes_count++; - default_themes_index = g_realloc(default_themes_index, - default_themes_count * sizeof(int)); - default_themes_index[default_themes_count - 1] = theme_index; +void add_default_theme(int theme_index) +{ + if (theme_index < 0) { + LOG_W("Invalid theme index: %i", theme_index); + return; + } + if (theme_index >= icon_themes_count) { + LOG_W("Invalid theme index: %i. Theme does not exists.", theme_index); + return; + } + default_themes_count++; + default_themes_index = + g_realloc(default_themes_index, default_themes_count * sizeof(int)); + default_themes_index[default_themes_count - 1] = theme_index; } // see icon-lookup.h -char *find_icon_in_theme(const char *name, int theme_index, int size) { - struct icon_theme *theme = &icon_themes[theme_index]; - LOG_D("Finding icon %s in theme %s", STR_NN(name), STR_NN(theme->name)); - for (int i = 0; i < theme->dirs_count; i++) { - bool match_size = false; - struct icon_theme_dir dir = theme->dirs[i]; - switch (dir.type) { - case THEME_DIR_FIXED: - match_size = dir.size == size; - break; - - case THEME_DIR_SCALABLE: - match_size = dir.min_size <= size && dir.max_size >= size; - break; - - case THEME_DIR_THRESHOLD: - match_size = (float)dir.size / dir.threshold <= size - && dir.size * dir.threshold >= size; - break; - } - if (match_size) { - const char *suffixes[] = { ".svg", ".svgz", ".png", ".xpm", NULL }; - for (const char **suf = suffixes; *suf; suf++) { - char *name_with_extension = g_strconcat(name, *suf, NULL); - char *icon = g_build_filename(theme->location, theme->subdir_theme, - dir.name, name_with_extension, - NULL); - if (is_readable_file(icon)) { - g_free(name_with_extension); - return icon; - } - g_free(name_with_extension); - g_free(icon); - } +char *find_icon_in_theme(const char *name, int theme_index, int size) +{ + struct icon_theme *theme = &icon_themes[theme_index]; + LOG_D("Finding icon %s in theme %s", STR_NN(name), STR_NN(theme->name)); + for (int i = 0; i < theme->dirs_count; i++) { + bool match_size = false; + struct icon_theme_dir dir = theme->dirs[i]; + switch (dir.type) { + case THEME_DIR_FIXED: match_size = dir.size == size; break; + + case THEME_DIR_SCALABLE: + match_size = dir.min_size <= size && dir.max_size >= size; + break; + + case THEME_DIR_THRESHOLD: + match_size = (float)dir.size / dir.threshold <= size + && dir.size * dir.threshold >= size; + break; + } + if (match_size) { + const char *suffixes[] = {".svg", ".svgz", ".png", ".xpm", NULL}; + for (const char **suf = suffixes; *suf; suf++) { + char *name_with_extension = g_strconcat(name, *suf, NULL); + char *icon = g_build_filename(theme->location, + theme->subdir_theme, + dir.name, + name_with_extension, + NULL); + if (is_readable_file(icon)) { + g_free(name_with_extension); + return icon; } + g_free(name_with_extension); + g_free(icon); + } } - return NULL; + } + return NULL; } -char *find_icon_in_theme_with_inherit(const char *name, int theme_index, int size) { - char *icon = find_icon_in_theme(name, theme_index, size); +char * +find_icon_in_theme_with_inherit(const char *name, int theme_index, int size) +{ + char *icon = find_icon_in_theme(name, theme_index, size); + if (icon) + return icon; + + for (int i = 0; i < icon_themes[theme_index].inherits_count; i++) { + if (icon_themes[theme_index].inherits_index[i] <= 0) + continue; // inherited theme could not be found + icon = find_icon_in_theme( + name, icon_themes[theme_index].inherits_index[i], size); if (icon) - return icon; - - for (int i = 0; i < icon_themes[theme_index].inherits_count; i++) { - if (icon_themes[theme_index].inherits_index[i] <= 0) - continue; // inherited theme could not be found - icon = find_icon_in_theme(name, - icon_themes[theme_index].inherits_index[i], - size); - if (icon) - return icon; - } - return NULL; + return icon; + } + return NULL; } /* see icon-lookup.h */ -char *find_icon_path(const char *name, int size) { - if (STR_EMPTY(name)) - return NULL; - - if (!default_themes_index) { - LOG_W("No icon theme has been set"); - return NULL; - } - - for (int i = 0; i < default_themes_count; i++) { - char *icon = find_icon_in_theme_with_inherit(name, - default_themes_index[i], size); - if (icon) - return icon; +char *find_icon_path(const char *name, int size) +{ + if (STR_EMPTY(name)) + return NULL; - } + if (!default_themes_index) { + LOG_W("No icon theme has been set"); return NULL; + } + + for (int i = 0; i < default_themes_count; i++) { + char *icon = find_icon_in_theme_with_inherit( + name, default_themes_index[i], size); + if (icon) + return icon; + } + return NULL; } diff --git a/src/icon-lookup.h b/src/icon-lookup.h index c8888bb78..99a2fa68f 100644 --- a/src/icon-lookup.h +++ b/src/icon-lookup.h @@ -1,29 +1,35 @@ #ifndef DUNST_ICON_LOOKUP_H #define DUNST_ICON_LOOKUP_H -struct icon_theme { - char *name; - char *location; // full path to the theme - char *subdir_theme; // name of the directory in which the theme is located +struct icon_theme +{ + char *name; + char *location; // full path to the theme + char *subdir_theme; // name of the directory in which the theme is located - int inherits_count; - int *inherits_index; + int inherits_count; + int *inherits_index; - int dirs_count; - struct icon_theme_dir *dirs; + int dirs_count; + struct icon_theme_dir *dirs; }; -enum theme_dir_type { THEME_DIR_FIXED, THEME_DIR_SCALABLE, THEME_DIR_THRESHOLD }; - -struct icon_theme_dir { - char *name; - int size; - int scale; - int min_size, max_size; - int threshold; - enum theme_dir_type type; +enum theme_dir_type +{ + THEME_DIR_FIXED, + THEME_DIR_SCALABLE, + THEME_DIR_THRESHOLD }; +struct icon_theme_dir +{ + char *name; + int size; + int scale; + int min_size, max_size; + int threshold; + enum theme_dir_type type; +}; /** * Load a theme with given name from a standard icon directory. Don't call this @@ -36,7 +42,6 @@ struct icon_theme_dir { */ int load_icon_theme(char *name); - /** * Add theme to the list of default themes. The theme that's added first will * be used first for lookup. After that the inherited themes will be used and diff --git a/src/icon.c b/src/icon.c index 2ce2ec5ec..eed2a6f9f 100644 --- a/src/icon.c +++ b/src/icon.c @@ -3,118 +3,124 @@ #include #include #include +#include #include #include -#include +#include "icon-lookup.h" #include "log.h" #include "notification.h" #include "settings.h" #include "utils.h" -#include "icon-lookup.h" /** * Reassemble the data parts of a GdkPixbuf into a cairo_surface_t's data field. * - * Requires to call on the surface flush before and mark_dirty after the execution. + * Requires to call on the surface flush before and mark_dirty after the + * execution. */ -static void pixbuf_data_to_cairo_data( - const unsigned char *pixels_p, - unsigned char *pixels_c, - size_t rowstride_p, - size_t rowstride_c, - int width, - int height, - int n_channels) +static void pixbuf_data_to_cairo_data(const unsigned char *pixels_p, + unsigned char *pixels_c, + size_t rowstride_p, + size_t rowstride_c, + int width, + int height, + int n_channels) { #if G_BYTE_ORDER == G_LITTLE_ENDIAN - static const size_t CAIRO_B = 0; - static const size_t CAIRO_G = 1; - static const size_t CAIRO_R = 2; - static const size_t CAIRO_A = 3; + static const size_t CAIRO_B = 0; + static const size_t CAIRO_G = 1; + static const size_t CAIRO_R = 2; + static const size_t CAIRO_A = 3; #elif G_BYTE_ORDER == G_BIG_ENDIAN - static const size_t CAIRO_A = 0; - static const size_t CAIRO_R = 1; - static const size_t CAIRO_G = 2; - static const size_t CAIRO_B = 3; + static const size_t CAIRO_A = 0; + static const size_t CAIRO_R = 1; + static const size_t CAIRO_G = 2; + static const size_t CAIRO_B = 3; #elif G_BYTE_ORDER == G_PDP_ENDIAN - static const size_t CAIRO_R = 0; - static const size_t CAIRO_A = 1; - static const size_t CAIRO_B = 2; - static const size_t CAIRO_G = 3; + static const size_t CAIRO_R = 0; + static const size_t CAIRO_A = 1; + static const size_t CAIRO_B = 2; + static const size_t CAIRO_G = 3; #else // GLib doesn't support any other endiannesses #error Unsupported Endianness #endif - assert(pixels_p); - assert(pixels_c); - assert(width > 0); - assert(height > 0); - - if (n_channels == 3) { - for (int h = 0; h < height; h++) { - unsigned char *iter_c = pixels_c + h * rowstride_c; - const unsigned char *iter_p = pixels_p + h * rowstride_p; - for (int w = 0; w < width; w++) { - iter_c[CAIRO_R] = iter_p[0]; - iter_c[CAIRO_G] = iter_p[1]; - iter_c[CAIRO_B] = iter_p[2]; - iter_c[CAIRO_A] = 0xff; - iter_c += 4; - iter_p += n_channels; - } - } - } else { - for (int h = 0; h < height; h++) { - unsigned char *iter_c = pixels_c + h * rowstride_c; - const unsigned char *iter_p = pixels_p + h * rowstride_p; - for (int w = 0; w < width; w++) { - double alpha_factor = iter_p[3] / (double)0xff; - iter_c[CAIRO_R] = (unsigned char)(iter_p[0] * alpha_factor + .5); - iter_c[CAIRO_G] = (unsigned char)(iter_p[1] * alpha_factor + .5); - iter_c[CAIRO_B] = (unsigned char)(iter_p[2] * alpha_factor + .5); - iter_c[CAIRO_A] = iter_p[3]; - iter_c += 4; - iter_p += n_channels; - } - } - + assert(pixels_p); + assert(pixels_c); + assert(width > 0); + assert(height > 0); + + if (n_channels == 3) { + for (int h = 0; h < height; h++) { + unsigned char *iter_c = pixels_c + h * rowstride_c; + const unsigned char *iter_p = pixels_p + h * rowstride_p; + for (int w = 0; w < width; w++) { + iter_c[CAIRO_R] = iter_p[0]; + iter_c[CAIRO_G] = iter_p[1]; + iter_c[CAIRO_B] = iter_p[2]; + iter_c[CAIRO_A] = 0xff; + iter_c += 4; + iter_p += n_channels; + } + } + } else { + for (int h = 0; h < height; h++) { + unsigned char *iter_c = pixels_c + h * rowstride_c; + const unsigned char *iter_p = pixels_p + h * rowstride_p; + for (int w = 0; w < width; w++) { + double alpha_factor = iter_p[3] / (double)0xff; + iter_c[CAIRO_R] = + (unsigned char)(iter_p[0] * alpha_factor + .5); + iter_c[CAIRO_G] = + (unsigned char)(iter_p[1] * alpha_factor + .5); + iter_c[CAIRO_B] = + (unsigned char)(iter_p[2] * alpha_factor + .5); + iter_c[CAIRO_A] = iter_p[3]; + iter_c += 4; + iter_p += n_channels; + } } + } } -int get_icon_width(cairo_surface_t *icon, double scale) { - return round(cairo_image_surface_get_width(icon) / scale); +int get_icon_width(cairo_surface_t *icon, double scale) +{ + return round(cairo_image_surface_get_width(icon) / scale); } -int get_icon_height(cairo_surface_t *icon, double scale) { - return round(cairo_image_surface_get_height(icon) / scale); +int get_icon_height(cairo_surface_t *icon, double scale) +{ + return round(cairo_image_surface_get_height(icon) / scale); } cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf) { - if (!pixbuf) { - return NULL; - } - - int width = gdk_pixbuf_get_width(pixbuf); - int height = gdk_pixbuf_get_height(pixbuf); - - cairo_format_t fmt = gdk_pixbuf_get_has_alpha(pixbuf) ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24; - cairo_surface_t *icon_surface = cairo_image_surface_create(fmt, width, height); - - /* Copy pixel data from pixbuf to surface */ - cairo_surface_flush(icon_surface); - pixbuf_data_to_cairo_data(gdk_pixbuf_read_pixels(pixbuf), - cairo_image_surface_get_data(icon_surface), - gdk_pixbuf_get_rowstride(pixbuf), - cairo_format_stride_for_width(fmt, width), - gdk_pixbuf_get_width(pixbuf), - gdk_pixbuf_get_height(pixbuf), - gdk_pixbuf_get_n_channels(pixbuf)); - cairo_surface_mark_dirty(icon_surface); - - return icon_surface; + if (!pixbuf) { + return NULL; + } + + int width = gdk_pixbuf_get_width(pixbuf); + int height = gdk_pixbuf_get_height(pixbuf); + + cairo_format_t fmt = gdk_pixbuf_get_has_alpha(pixbuf) ? CAIRO_FORMAT_ARGB32 + : CAIRO_FORMAT_RGB24; + cairo_surface_t *icon_surface = + cairo_image_surface_create(fmt, width, height); + + /* Copy pixel data from pixbuf to surface */ + cairo_surface_flush(icon_surface); + pixbuf_data_to_cairo_data(gdk_pixbuf_read_pixels(pixbuf), + cairo_image_surface_get_data(icon_surface), + gdk_pixbuf_get_rowstride(pixbuf), + cairo_format_stride_for_width(fmt, width), + gdk_pixbuf_get_width(pixbuf), + gdk_pixbuf_get_height(pixbuf), + gdk_pixbuf_get_n_channels(pixbuf)); + cairo_surface_mark_dirty(icon_surface); + + return icon_surface; } /** @@ -124,28 +130,30 @@ cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf) * @param h a pointer to the image height, to be modified in-place * @param min_size the minimum icon size setting for this notification * @param max_size the maximum icon size setting for this notification - * @return TRUE if the dimensions were updated, FALSE if they were left unchanged + * @return TRUE if the dimensions were updated, FALSE if they were left + * unchanged */ -static bool icon_size_clamp(int *w, int *h, int min_size, int max_size) { - int _w = *w, _h = *h; - int landscape = _w > _h; - int orig_larger = landscape ? _w : _h; - double larger = orig_larger; - double smaller = landscape ? _h : _w; - if (min_size && smaller < min_size) { - larger = larger / smaller * min_size; - smaller = min_size; - } - if (max_size && larger > max_size) { - smaller = smaller / larger * max_size; - larger = max_size; - } - if ((int) larger != orig_larger) { - *w = (int) (landscape ? larger : smaller); - *h = (int) (landscape ? smaller : larger); - return TRUE; - } - return FALSE; +static bool icon_size_clamp(int *w, int *h, int min_size, int max_size) +{ + int _w = *w, _h = *h; + int landscape = _w > _h; + int orig_larger = landscape ? _w : _h; + double larger = orig_larger; + double smaller = landscape ? _h : _w; + if (min_size && smaller < min_size) { + larger = larger / smaller * min_size; + smaller = min_size; + } + if (max_size && larger > max_size) { + smaller = smaller / larger * max_size; + larger = max_size; + } + if ((int)larger != orig_larger) { + *w = (int)(landscape ? larger : smaller); + *h = (int)(landscape ? smaller : larger); + return TRUE; + } + return FALSE; } /** @@ -161,232 +169,239 @@ static bool icon_size_clamp(int *w, int *h, int min_size, int max_size) { * necessary, it returns the same pixbuf. Transfers full * ownership of the reference. */ -static GdkPixbuf *icon_pixbuf_scale_to_size(GdkPixbuf *pixbuf, double dpi_scale, int min_size, int max_size) +static GdkPixbuf *icon_pixbuf_scale_to_size(GdkPixbuf *pixbuf, + double dpi_scale, + int min_size, + int max_size) { - ASSERT_OR_RET(pixbuf, NULL); - - int w = gdk_pixbuf_get_width(pixbuf); - int h = gdk_pixbuf_get_height(pixbuf); - - // TODO immediately rescale icon upon scale changes - if(icon_size_clamp(&w, &h, min_size, max_size)) { - w = round(w * dpi_scale); - h = round(h * dpi_scale); - } - GdkPixbuf *scaled = gdk_pixbuf_scale_simple( - pixbuf, - w, - h, - GDK_INTERP_BILINEAR); - g_object_unref(pixbuf); - pixbuf = scaled; - return pixbuf; + ASSERT_OR_RET(pixbuf, NULL); + + int w = gdk_pixbuf_get_width(pixbuf); + int h = gdk_pixbuf_get_height(pixbuf); + + // TODO immediately rescale icon upon scale changes + if (icon_size_clamp(&w, &h, min_size, max_size)) { + w = round(w * dpi_scale); + h = round(h * dpi_scale); + } + GdkPixbuf *scaled = + gdk_pixbuf_scale_simple(pixbuf, w, h, GDK_INTERP_BILINEAR); + g_object_unref(pixbuf); + pixbuf = scaled; + return pixbuf; } -GdkPixbuf *get_pixbuf_from_file(const char *filename, int min_size, int max_size, double scale) +GdkPixbuf *get_pixbuf_from_file(const char *filename, + int min_size, + int max_size, + double scale) { - GError *error = NULL; - gint w, h; - - if (!gdk_pixbuf_get_file_info (filename, &w, &h)) { - LOG_W("Failed to load image info for %s", STR_NN(filename)); - return NULL; - } - GdkPixbuf *pixbuf = NULL; - // TODO immediately rescale icon upon scale changes - icon_size_clamp(&w, &h, min_size, max_size); - pixbuf = gdk_pixbuf_new_from_file_at_scale(filename, - round(w * scale), - round(h * scale), - TRUE, - &error); - - if (error) { - LOG_W("%s", error->message); - g_error_free(error); - } - - return pixbuf; + GError *error = NULL; + gint w, h; + + if (!gdk_pixbuf_get_file_info(filename, &w, &h)) { + LOG_W("Failed to load image info for %s", STR_NN(filename)); + return NULL; + } + GdkPixbuf *pixbuf = NULL; + // TODO immediately rescale icon upon scale changes + icon_size_clamp(&w, &h, min_size, max_size); + pixbuf = gdk_pixbuf_new_from_file_at_scale( + filename, round(w * scale), round(h * scale), TRUE, &error); + + if (error) { + LOG_W("%s", error->message); + g_error_free(error); + } + + return pixbuf; } char *get_path_from_icon_name(const char *iconname, int size) { - if (STR_EMPTY(iconname)) - return NULL; - - if (g_str_has_prefix(iconname, "file://")) { - char *uri_path = g_filename_from_uri(iconname, NULL, NULL); - if (STR_EMPTY(uri_path)) { - LOG_W("Invalid file uri '%s'", iconname); - return NULL; - } - return uri_path; - } else if (iconname[0] == '/' || iconname[0] == '~') { - // NOTE: Paths starting with ~ should have already been handled at this point - return g_strdup(iconname); - } else if (settings.enable_recursive_icon_lookup) { - char *path = find_icon_path(iconname, size); - if (STR_EMPTY(path)) - LOG_W("Icon '%s' not found in themes", iconname); - else - LOG_I("Found icon '%s' at %s", iconname, STR_NN(path)); - return path; + if (STR_EMPTY(iconname)) + return NULL; + + if (g_str_has_prefix(iconname, "file://")) { + char *uri_path = g_filename_from_uri(iconname, NULL, NULL); + if (STR_EMPTY(uri_path)) { + LOG_W("Invalid file uri '%s'", iconname); + return NULL; } - - // Search icon_path - const char *suffixes[] = { ".svg", ".svgz", ".png", ".xpm", NULL }; - char *start = settings.icon_path, *end, *current_folder, *maybe_icon_path, *path = NULL; - - do { - end = strchr(start, ':'); - if (!end) end = strchr(settings.icon_path, '\0'); /* end = end of string */ - - current_folder = string_to_path(g_strndup(start, end - start)); - - for (const char **suf = suffixes; *suf; suf++) { - gchar *name_with_extension = g_strconcat(iconname, *suf, NULL); - maybe_icon_path = g_build_filename(current_folder, name_with_extension, NULL); - if (is_readable_file(maybe_icon_path)) { - path = g_strdup(maybe_icon_path); - } - g_free(name_with_extension); - g_free(maybe_icon_path); - - if (path) break; - } - g_free(current_folder); - - if (path) break; - start = end + 1; - } while (STR_FULL(end)); - + return uri_path; + } else if (iconname[0] == '/' || iconname[0] == '~') { + // NOTE: Paths starting with ~ should have already been handled at this + // point + return g_strdup(iconname); + } else if (settings.enable_recursive_icon_lookup) { + char *path = find_icon_path(iconname, size); if (STR_EMPTY(path)) - LOG_W("Icon '%s' not found in icon_path", iconname); + LOG_W("Icon '%s' not found in themes", iconname); else - LOG_I("Found icon '%s' at %s", iconname, path); - + LOG_I("Found icon '%s' at %s", iconname, STR_NN(path)); return path; + } + + // Search icon_path + const char *suffixes[] = {".svg", ".svgz", ".png", ".xpm", NULL}; + char *start = settings.icon_path, *end, *current_folder, *maybe_icon_path, + *path = NULL; + + do { + end = strchr(start, ':'); + if (!end) + end = strchr(settings.icon_path, '\0'); /* end = end of string */ + + current_folder = string_to_path(g_strndup(start, end - start)); + + for (const char **suf = suffixes; *suf; suf++) { + gchar *name_with_extension = g_strconcat(iconname, *suf, NULL); + maybe_icon_path = + g_build_filename(current_folder, name_with_extension, NULL); + if (is_readable_file(maybe_icon_path)) { + path = g_strdup(maybe_icon_path); + } + g_free(name_with_extension); + g_free(maybe_icon_path); + + if (path) + break; + } + g_free(current_folder); + + if (path) + break; + start = end + 1; + } while (STR_FULL(end)); + + if (STR_EMPTY(path)) + LOG_W("Icon '%s' not found in icon_path", iconname); + else + LOG_I("Found icon '%s' at %s", iconname, path); + + return path; } static void icon_destroy(guchar *pixels, gpointer data) { - (void)data; - g_free(pixels); + (void)data; + g_free(pixels); } -GdkPixbuf *icon_get_for_data(GVariant *data, char **id, double dpi_scale, int min_size, int max_size) +GdkPixbuf *icon_get_for_data( + GVariant *data, char **id, double dpi_scale, int min_size, int max_size) { - ASSERT_OR_RET(data, NULL); - ASSERT_OR_RET(id, NULL); - - if (!STR_EQ("(iiibiiay)", g_variant_get_type_string(data))) { - LOG_W("Invalid data for pixbuf given."); - return NULL; - } - - /* The raw image is a big array of char data. - * - * The image is serialised rowwise pixel by pixel. The rows are aligned - * by a spacer full of garbage. The overall data length of data + garbage - * is called the rowstride. - * - * Mind the missing spacer at the last row. - * - * len: |<--------------rowstride---------------->| - * len: |<-width*pixelstride->| - * row 1: | data for row 1 | spacer of garbage | - * row 2: | data for row 2 | spacer of garbage | - * | . | spacer of garbage | - * | . | spacer of garbage | - * | . | spacer of garbage | - * row n-1: | data for row n-1 | spacer of garbage | - * row n: | data for row n | - */ - - GdkPixbuf *pixbuf = NULL; - GVariant *data_variant = NULL; - unsigned char *data_pb; - - gsize len_expected; - gsize len_actual; - gsize pixelstride; - - int width; - int height; - int rowstride; - int has_alpha; - int bits_per_sample; - int n_channels; - - g_variant_get(data, - "(iiibii@ay)", - &width, - &height, - &rowstride, - &has_alpha, - &bits_per_sample, - &n_channels, - &data_variant); - - // note: (A+7)/8 rounds up A to the next byte boundary - pixelstride = (n_channels * bits_per_sample + 7)/8; - len_expected = (height - 1) * rowstride + width * pixelstride; - len_actual = g_variant_get_size(data_variant); - - if (len_actual != len_expected) { - LOG_W("Expected image data to be of length %" G_GSIZE_FORMAT - " but got a length of %" G_GSIZE_FORMAT, - len_expected, - len_actual); - g_variant_unref(data_variant); - return NULL; - } + ASSERT_OR_RET(data, NULL); + ASSERT_OR_RET(id, NULL); + + if (!STR_EQ("(iiibiiay)", g_variant_get_type_string(data))) { + LOG_W("Invalid data for pixbuf given."); + return NULL; + } + + /* The raw image is a big array of char data. + * + * The image is serialised rowwise pixel by pixel. The rows are aligned + * by a spacer full of garbage. The overall data length of data + garbage + * is called the rowstride. + * + * Mind the missing spacer at the last row. + * + * len: |<--------------rowstride---------------->| + * len: |<-width*pixelstride->| + * row 1: | data for row 1 | spacer of garbage | + * row 2: | data for row 2 | spacer of garbage | + * | . | spacer of garbage | + * | . | spacer of garbage | + * | . | spacer of garbage | + * row n-1: | data for row n-1 | spacer of garbage | + * row n: | data for row n | + */ + + GdkPixbuf *pixbuf = NULL; + GVariant *data_variant = NULL; + unsigned char *data_pb; + + gsize len_expected; + gsize len_actual; + gsize pixelstride; + + int width; + int height; + int rowstride; + int has_alpha; + int bits_per_sample; + int n_channels; + + g_variant_get(data, + "(iiibii@ay)", + &width, + &height, + &rowstride, + &has_alpha, + &bits_per_sample, + &n_channels, + &data_variant); + + // note: (A+7)/8 rounds up A to the next byte boundary + pixelstride = (n_channels * bits_per_sample + 7) / 8; + len_expected = (height - 1) * rowstride + width * pixelstride; + len_actual = g_variant_get_size(data_variant); + + if (len_actual != len_expected) { + LOG_W("Expected image data to be of length %" G_GSIZE_FORMAT + " but got a length of %" G_GSIZE_FORMAT, + len_expected, + len_actual); + g_variant_unref(data_variant); + return NULL; + } - // g_memdup is deprecated in glib 2.67.4 and higher. - // g_memdup2 is a safer alternative -#if GLIB_CHECK_VERSION(2,67,3) - data_pb = (guchar *) g_memdup2(g_variant_get_data(data_variant), len_actual); + // g_memdup is deprecated in glib 2.67.4 and higher. + // g_memdup2 is a safer alternative +#if GLIB_CHECK_VERSION(2, 67, 3) + data_pb = (guchar *)g_memdup2(g_variant_get_data(data_variant), len_actual); #else - data_pb = (guchar *) g_memdup(g_variant_get_data(data_variant), len_actual); + data_pb = (guchar *)g_memdup(g_variant_get_data(data_variant), len_actual); #endif - pixbuf = gdk_pixbuf_new_from_data(data_pb, - GDK_COLORSPACE_RGB, - has_alpha, - bits_per_sample, - width, - height, - rowstride, - icon_destroy, - data_pb); - if (!pixbuf) { - /* Dear user, I'm sorry, I'd like to give you a more specific - * error message. But sadly, I can't */ - LOG_W("Cannot serialise raw icon data into pixbuf."); - return NULL; - } - - /* To calculate a checksum of the current image, we have to remove - * all excess spacers, so that our checksummed memory only contains - * real data. */ - size_t data_chk_len = pixelstride * width * height; - unsigned char *data_chk = g_malloc(data_chk_len); - size_t rowstride_short = pixelstride * width; - - for (int i = 0; i < height; i++) { - memcpy(data_chk + (i*rowstride_short), - data_pb + (i*rowstride), - rowstride_short); - } - - *id = g_compute_checksum_for_data(G_CHECKSUM_MD5, data_chk, data_chk_len); - - g_free(data_chk); - g_variant_unref(data_variant); - - pixbuf = icon_pixbuf_scale_to_size(pixbuf, dpi_scale, min_size, max_size); - - return pixbuf; + pixbuf = gdk_pixbuf_new_from_data(data_pb, + GDK_COLORSPACE_RGB, + has_alpha, + bits_per_sample, + width, + height, + rowstride, + icon_destroy, + data_pb); + if (!pixbuf) { + /* Dear user, I'm sorry, I'd like to give you a more specific + * error message. But sadly, I can't */ + LOG_W("Cannot serialise raw icon data into pixbuf."); + return NULL; + } + + /* To calculate a checksum of the current image, we have to remove + * all excess spacers, so that our checksummed memory only contains + * real data. */ + size_t data_chk_len = pixelstride * width * height; + unsigned char *data_chk = g_malloc(data_chk_len); + size_t rowstride_short = pixelstride * width; + + for (int i = 0; i < height; i++) { + memcpy(data_chk + (i * rowstride_short), + data_pb + (i * rowstride), + rowstride_short); + } + + *id = g_compute_checksum_for_data(G_CHECKSUM_MD5, data_chk, data_chk_len); + + g_free(data_chk); + g_variant_unref(data_variant); + + pixbuf = icon_pixbuf_scale_to_size(pixbuf, dpi_scale, min_size, max_size); + + return pixbuf; } /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/icon.h b/src/icon.h index 13d04b07c..e86c861e3 100644 --- a/src/icon.h +++ b/src/icon.h @@ -11,15 +11,19 @@ cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf); /** Retrieve an icon by its full filepath, scaled according to settings. * * @param filename A string representing a readable file path - * @param min_size An iteger representing the desired minimum unscaled icon size. - * @param max_size An iteger representing the desired maximum unscaled icon size. + * @param min_size An iteger representing the desired minimum unscaled icon + * size. + * @param max_size An iteger representing the desired maximum unscaled icon + * size. * @param scale An integer representing the output dpi scaling. * * @return an instance of `GdkPixbuf` * @retval NULL: file does not exist, not readable, etc.. */ -GdkPixbuf *get_pixbuf_from_file(const char *filename, int min_size, int max_size, double scale); - +GdkPixbuf *get_pixbuf_from_file(const char *filename, + int min_size, + int max_size, + double scale); /** * Get the unscaled icon width. @@ -57,12 +61,15 @@ char *get_path_from_icon_name(const char *iconname, int size); * @param id (necessary) A unique identifier of the returned pixbuf. * Only filled, if the return value is non-NULL. * @param dpi_scale An integer representing the output dpi scaling. - * @param min_size An integer representing the desired minimum unscaled icon size. - * @param max_size An integer representing the desired maximum unscaled icon size. + * @param min_size An integer representing the desired minimum unscaled icon + * size. + * @param max_size An integer representing the desired maximum unscaled icon + * size. * @return an instance of `GdkPixbuf` derived from the GVariant * @retval NULL: GVariant parameter nulled, invalid or in wrong format */ -GdkPixbuf *icon_get_for_data(GVariant *data, char **id, double dpi_scale, int min_size, int max_size); +GdkPixbuf *icon_get_for_data( + GVariant *data, char **id, double dpi_scale, int min_size, int max_size); #endif /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/ini.c b/src/ini.c index e36d2657c..f2b638b19 100644 --- a/src/ini.c +++ b/src/ini.c @@ -1,169 +1,175 @@ #include "ini.h" -#include "utils.h" #include "log.h" #include "settings.h" +#include "utils.h" struct section *get_section(struct ini *ini, const char *name) { - for (int i = 0; i < ini->section_count; i++) { - if (STR_EQ(ini->sections[i].name, name)) - return &ini->sections[i]; - } + for (int i = 0; i < ini->section_count; i++) { + if (STR_EQ(ini->sections[i].name, name)) + return &ini->sections[i]; + } - return NULL; + return NULL; } struct section *get_or_create_section(struct ini *ini, const char *name) { - struct section *s = get_section(ini, name); - if (!s) { - ini->section_count++; - ini->sections = g_realloc(ini->sections, sizeof(struct section) * ini->section_count); - - s = &ini->sections[ini->section_count - 1]; - s->name = g_strdup(name); - s->entries = NULL; - s->entry_count = 0; - } - return s; + struct section *s = get_section(ini, name); + if (!s) { + ini->section_count++; + ini->sections = g_realloc(ini->sections, + sizeof(struct section) * ini->section_count); + + s = &ini->sections[ini->section_count - 1]; + s->name = g_strdup(name); + s->entries = NULL; + s->entry_count = 0; + } + return s; } -void add_entry(struct ini *ini, const char *section_name, const char *key, const char *value) +void add_entry(struct ini *ini, + const char *section_name, + const char *key, + const char *value) { - struct section *s = get_or_create_section(ini, section_name); + struct section *s = get_or_create_section(ini, section_name); - s->entry_count++; - int len = s->entry_count; - s->entries = g_realloc(s->entries, sizeof(struct entry) * len); - s->entries[s->entry_count - 1].key = g_strdup(key); - s->entries[s->entry_count - 1].value = string_strip_quotes(value); + s->entry_count++; + int len = s->entry_count; + s->entries = g_realloc(s->entries, sizeof(struct entry) * len); + s->entries[s->entry_count - 1].key = g_strdup(key); + s->entries[s->entry_count - 1].value = string_strip_quotes(value); } -const char *section_get_value(struct ini *ini, const struct section *s, const char *key) +const char * +section_get_value(struct ini *ini, const struct section *s, const char *key) { - ASSERT_OR_RET(s, NULL); + ASSERT_OR_RET(s, NULL); - for (int i = 0; i < s->entry_count; i++) { - if (STR_EQ(s->entries[i].key, key)) { - return s->entries[i].value; - } + for (int i = 0; i < s->entry_count; i++) { + if (STR_EQ(s->entries[i].key, key)) { + return s->entries[i].value; } - return NULL; + } + return NULL; } const char *get_value(struct ini *ini, const char *section, const char *key) { - struct section *s = get_section(ini, section); - return section_get_value(ini, s, key); + struct section *s = get_section(ini, section); + return section_get_value(ini, s, key); } bool ini_is_set(struct ini *ini, const char *ini_section, const char *ini_key) { - return get_value(ini, ini_section, ini_key) != NULL; + return get_value(ini, ini_section, ini_key) != NULL; } -const char *next_section(const struct ini *ini,const char *section) +const char *next_section(const struct ini *ini, const char *section) { - ASSERT_OR_RET(ini->section_count > 0, NULL); - ASSERT_OR_RET(section, ini->sections[0].name); - - for (int i = 0; i < ini->section_count; i++) { - if (STR_EQ(section, ini->sections[i].name)) { - if (i + 1 >= ini->section_count) - return NULL; - else - return ini->sections[i + 1].name; - } + ASSERT_OR_RET(ini->section_count > 0, NULL); + ASSERT_OR_RET(section, ini->sections[0].name); + + for (int i = 0; i < ini->section_count; i++) { + if (STR_EQ(section, ini->sections[i].name)) { + if (i + 1 >= ini->section_count) + return NULL; + else + return ini->sections[i + 1].name; } - return NULL; + } + return NULL; } struct ini *load_ini_file(FILE *fp) { - if (!fp) - return NULL; + if (!fp) + return NULL; + + struct ini *ini = g_malloc0(sizeof(struct ini)); + char *line = NULL; + size_t line_len = 0; + + int line_num = 0; + char *current_section = NULL; + while (getline(&line, &line_len, fp) != -1) { + line_num++; + + char *start = g_strstrip(line); - struct ini *ini = g_malloc0(sizeof(struct ini)); - char *line = NULL; - size_t line_len = 0; - - int line_num = 0; - char *current_section = NULL; - while (getline(&line, &line_len, fp) != -1) { - line_num++; - - char *start = g_strstrip(line); - - if (*start == ';' || *start == '#' || STR_EMPTY(start)) - continue; - - if (*start == '[') { - char *end = strchr(start + 1, ']'); - if (!end) { - LOG_W("Invalid config file at line %d: Missing ']'.", line_num); - continue; - } - - *end = '\0'; - - g_free(current_section); - current_section = g_strdup(start + 1); - continue; - } - - char *equal = strchr(start + 1, '='); - if (!equal) { - LOG_W("Invalid config file at line %d: Missing '='.", line_num); - continue; - } - - *equal = '\0'; - char *key = g_strstrip(start); - char *value = g_strstrip(equal + 1); - - char *quote = strchr(value, '"'); - char *value_end = NULL; - if (quote) { - value_end = strchr(quote + 1, '"'); - if (!value_end) { - LOG_W("Invalid config file at line %d: Missing '\"'.", line_num); - continue; - } - } else { - value_end = value; - } - - char *comment = strpbrk(value_end, "#;"); - if (comment) - *comment = '\0'; - - value = g_strstrip(value); - - if (!current_section) { - LOG_W("Invalid config file at line %d: Key value pair without a section.", line_num); - continue; - } - - add_entry(ini, current_section, key, value); + if (*start == ';' || *start == '#' || STR_EMPTY(start)) + continue; + + if (*start == '[') { + char *end = strchr(start + 1, ']'); + if (!end) { + LOG_W("Invalid config file at line %d: Missing ']'.", line_num); + continue; + } + + *end = '\0'; + + g_free(current_section); + current_section = g_strdup(start + 1); + continue; } - free(line); - g_free(current_section); - return ini; -} + char *equal = strchr(start + 1, '='); + if (!equal) { + LOG_W("Invalid config file at line %d: Missing '='.", line_num); + continue; + } + + *equal = '\0'; + char *key = g_strstrip(start); + char *value = g_strstrip(equal + 1); + + char *quote = strchr(value, '"'); + char *value_end = NULL; + if (quote) { + value_end = strchr(quote + 1, '"'); + if (!value_end) { + LOG_W("Invalid config file at line %d: Missing '\"'.", + line_num); + continue; + } + } else { + value_end = value; + } + + char *comment = strpbrk(value_end, "#;"); + if (comment) + *comment = '\0'; + + value = g_strstrip(value); + + if (!current_section) { + LOG_W("Invalid config file at line %d: Key value pair without a " + "section.", + line_num); + continue; + } + + add_entry(ini, current_section, key, value); + } + free(line); + g_free(current_section); + return ini; +} void finish_ini(struct ini *ini) { - for (int i = 0; i < ini->section_count; i++) { - for (int j = 0; j < ini->sections[i].entry_count; j++) { - g_free(ini->sections[i].entries[j].key); - g_free(ini->sections[i].entries[j].value); - } - g_free(ini->sections[i].entries); - g_free(ini->sections[i].name); + for (int i = 0; i < ini->section_count; i++) { + for (int j = 0; j < ini->sections[i].entry_count; j++) { + g_free(ini->sections[i].entries[j].key); + g_free(ini->sections[i].entries[j].value); } - g_clear_pointer(&ini->sections, g_free); - ini->section_count = 0; + g_free(ini->sections[i].entries); + g_free(ini->sections[i].name); + } + g_clear_pointer(&ini->sections, g_free); + ini->section_count = 0; } - diff --git a/src/ini.h b/src/ini.h index e3f9ec971..aaeeaffa7 100644 --- a/src/ini.h +++ b/src/ini.h @@ -1,32 +1,37 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ #ifndef DUNST_INI_H #define DUNST_INI_H #include #include -struct entry { - char *key; - char *value; +struct entry +{ + char *key; + char *value; }; -struct section { - char *name; - int entry_count; - struct entry *entries; +struct section +{ + char *name; + int entry_count; + struct entry *entries; }; -struct ini { - int section_count; - struct section *sections; +struct ini +{ + int section_count; + struct section *sections; }; /* returns the next known section. * if section == NULL returns first section. * returns NULL if no more sections are available */ -const char *next_section(const struct ini *ini,const char *section); -const char *section_get_value(struct ini *ini, const struct section *s, const char *key); +const char *next_section(const struct ini *ini, const char *section); +const char * +section_get_value(struct ini *ini, const struct section *s, const char *key); const char *get_value(struct ini *ini, const char *section, const char *key); struct ini *load_ini_file(FILE *fp); void finish_ini(struct ini *ini); diff --git a/src/input.c b/src/input.c index 979778f04..445617fd0 100644 --- a/src/input.c +++ b/src/input.c @@ -1,119 +1,119 @@ #include "input.h" #include "log.h" #include "menu.h" -#include "settings.h" #include "queues.h" +#include "settings.h" #include #if defined(__linux__) || defined(__FreeBSD__) #include #else -#define BTN_LEFT (0x110) -#define BTN_RIGHT (0x111) -#define BTN_MIDDLE (0x112) -#define BTN_TOUCH (0x14a) +#define BTN_LEFT (0x110) +#define BTN_RIGHT (0x111) +#define BTN_MIDDLE (0x112) +#define BTN_TOUCH (0x14a) #endif -int get_notification_clickable_height(struct notification *n, bool first, bool last) +int get_notification_clickable_height(struct notification *n, + bool first, + bool last) { - int notification_size = n->displayed_height; - if (settings.gap_size) { - notification_size += settings.frame_width * 2; - } else { - double half_separator = settings.separator_height / 2.0; - notification_size += settings.separator_height; - if(first) - notification_size += (settings.frame_width - half_separator); - if(last) - notification_size += (settings.frame_width - half_separator); - } - return notification_size; + int notification_size = n->displayed_height; + if (settings.gap_size) { + notification_size += settings.frame_width * 2; + } else { + double half_separator = settings.separator_height / 2.0; + notification_size += settings.separator_height; + if (first) + notification_size += (settings.frame_width - half_separator); + if (last) + notification_size += (settings.frame_width - half_separator); + } + return notification_size; } -struct notification *get_notification_at(const int y) { - int curr_y = 0; - bool first = true; - bool last; - for (const GList *iter = queues_get_displayed(); iter; - iter = iter->next) { - struct notification *current = iter->data; - struct notification *next = iter->next ? iter->next->data : NULL; +struct notification *get_notification_at(const int y) +{ + int curr_y = 0; + bool first = true; + bool last; + for (const GList *iter = queues_get_displayed(); iter; iter = iter->next) { + struct notification *current = iter->data; + struct notification *next = iter->next ? iter->next->data : NULL; - last = !next; - int notification_size = get_notification_clickable_height(current, first, last); + last = !next; + int notification_size = + get_notification_clickable_height(current, first, last); - if (y >= curr_y && y < curr_y + notification_size) { - return current; - } + if (y >= curr_y && y < curr_y + notification_size) { + return current; + } - curr_y += notification_size; - if (settings.gap_size) - curr_y += settings.gap_size; + curr_y += notification_size; + if (settings.gap_size) + curr_y += settings.gap_size; - first = false; - } - // no matching notification was found - return NULL; + first = false; + } + // no matching notification was found + return NULL; } -void input_handle_click(unsigned int button, bool button_down, int mouse_x, int mouse_y){ - LOG_I("Pointer handle button %i: %i", button, button_down); +void input_handle_click(unsigned int button, + bool button_down, + int mouse_x, + int mouse_y) +{ + LOG_I("Pointer handle button %i: %i", button, button_down); - if (button_down) { - // make sure it only reacts on button release - return; - } + if (button_down) { + // make sure it only reacts on button release + return; + } - enum mouse_action *acts; + enum mouse_action *acts; - switch (button) { - case BTN_LEFT: - acts = settings.mouse_left_click; - break; - case BTN_MIDDLE: - acts = settings.mouse_middle_click; - break; - case BTN_RIGHT: - acts = settings.mouse_right_click; - break; - case BTN_TOUCH: - // TODO Add separate action for touch - acts = settings.mouse_left_click; - break; - default: - LOG_W("Unsupported mouse button: '%d'", button); - return; - } + switch (button) { + case BTN_LEFT: acts = settings.mouse_left_click; break; + case BTN_MIDDLE: acts = settings.mouse_middle_click; break; + case BTN_RIGHT: acts = settings.mouse_right_click; break; + case BTN_TOUCH: + // TODO Add separate action for touch + acts = settings.mouse_left_click; + break; + default: LOG_W("Unsupported mouse button: '%d'", button); return; + } - // if other list types are added, make sure they have the same end value - for (int i = 0; acts[i] != MOUSE_ACTION_END; i++) { - enum mouse_action act = acts[i]; - if (act == MOUSE_CLOSE_ALL) { - queues_history_push_all(); - continue; - } + // if other list types are added, make sure they have the same end value + for (int i = 0; acts[i] != MOUSE_ACTION_END; i++) { + enum mouse_action act = acts[i]; + if (act == MOUSE_CLOSE_ALL) { + queues_history_push_all(); + continue; + } - if (act == MOUSE_CONTEXT_ALL) { - context_menu(); - continue; - } + if (act == MOUSE_CONTEXT_ALL) { + context_menu(); + continue; + } - if (act == MOUSE_DO_ACTION || act == MOUSE_CLOSE_CURRENT || act == MOUSE_CONTEXT || act == MOUSE_OPEN_URL) { - struct notification *n = get_notification_at(mouse_y); + if (act == MOUSE_DO_ACTION || act == MOUSE_CLOSE_CURRENT + || act == MOUSE_CONTEXT || act == MOUSE_OPEN_URL) { + struct notification *n = get_notification_at(mouse_y); - if (n) { - if (act == MOUSE_CLOSE_CURRENT) { - n->marked_for_closure = REASON_USER; - } else if (act == MOUSE_DO_ACTION) { - notification_do_action(n); - } else if (act == MOUSE_OPEN_URL) { - notification_open_url(n); - } else { - notification_open_context_menu(n); - } - } + if (n) { + if (act == MOUSE_CLOSE_CURRENT) { + n->marked_for_closure = REASON_USER; + } else if (act == MOUSE_DO_ACTION) { + notification_do_action(n); + } else if (act == MOUSE_OPEN_URL) { + notification_open_url(n); + } else { + notification_open_context_menu(n); } + } } + } - wake_up(); + wake_up(); } /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/input.h b/src/input.h index 0f2f1e479..6c0a7eb4c 100644 --- a/src/input.h +++ b/src/input.h @@ -5,14 +5,17 @@ /** * Handle incoming mouse click events - * + * * @param button code, A linux input event code * @param button_down State of the button * @param mouse_x X-position of the mouse, relative to the window * @param mouse_y Y-position of the mouse, relative to the window * */ -void input_handle_click(unsigned int button, bool button_down, int mouse_x, int mouse_y); - +void input_handle_click(unsigned int button, + bool button_down, + int mouse_x, + int mouse_y); + #endif /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/log.c b/src/log.c index 60f39e1ea..4d2679318 100644 --- a/src/log.c +++ b/src/log.c @@ -1,4 +1,5 @@ -/* 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 src/log.c @@ -19,47 +20,47 @@ static enum log_mask log_mask = DUNST_LOG_AUTO; /* see log.h */ static const char *log_level_to_string(GLogLevelFlags level) { - switch (level) { - case G_LOG_LEVEL_ERROR: return "ERROR"; - case G_LOG_LEVEL_CRITICAL: return "CRITICAL"; - case G_LOG_LEVEL_WARNING: return "WARNING"; - case G_LOG_LEVEL_MESSAGE: return "MESSAGE"; - case G_LOG_LEVEL_INFO: return "INFO"; - case G_LOG_LEVEL_DEBUG: return "DEBUG"; - default: return "UNKNOWN"; - } + switch (level) { + case G_LOG_LEVEL_ERROR: return "ERROR"; + case G_LOG_LEVEL_CRITICAL: return "CRITICAL"; + case G_LOG_LEVEL_WARNING: return "WARNING"; + case G_LOG_LEVEL_MESSAGE: return "MESSAGE"; + case G_LOG_LEVEL_INFO: return "INFO"; + case G_LOG_LEVEL_DEBUG: return "DEBUG"; + default: return "UNKNOWN"; + } } /* see log.h */ void log_set_level_from_string(const char *level) { - ASSERT_OR_RET(level,); - - if (STR_CASEQ(level, "critical")) - log_level = G_LOG_LEVEL_CRITICAL; - else if (STR_CASEQ(level, "crit")) - log_level = G_LOG_LEVEL_CRITICAL; - else if (STR_CASEQ(level, "warning")) - log_level = G_LOG_LEVEL_WARNING; - else if (STR_CASEQ(level, "warn")) - log_level = G_LOG_LEVEL_WARNING; - else if (STR_CASEQ(level, "message")) - log_level = G_LOG_LEVEL_MESSAGE; - else if (STR_CASEQ(level, "mesg")) - log_level = G_LOG_LEVEL_MESSAGE; - else if (STR_CASEQ(level, "info")) - log_level = G_LOG_LEVEL_INFO; - else if (STR_CASEQ(level, "debug")) - log_level = G_LOG_LEVEL_DEBUG; - else if (STR_CASEQ(level, "deb")) - log_level = G_LOG_LEVEL_DEBUG; - else - LOG_W("Unknown log level: '%s'", level); + ASSERT_OR_RET(level, ); + + if (STR_CASEQ(level, "critical")) + log_level = G_LOG_LEVEL_CRITICAL; + else if (STR_CASEQ(level, "crit")) + log_level = G_LOG_LEVEL_CRITICAL; + else if (STR_CASEQ(level, "warning")) + log_level = G_LOG_LEVEL_WARNING; + else if (STR_CASEQ(level, "warn")) + log_level = G_LOG_LEVEL_WARNING; + else if (STR_CASEQ(level, "message")) + log_level = G_LOG_LEVEL_MESSAGE; + else if (STR_CASEQ(level, "mesg")) + log_level = G_LOG_LEVEL_MESSAGE; + else if (STR_CASEQ(level, "info")) + log_level = G_LOG_LEVEL_INFO; + else if (STR_CASEQ(level, "debug")) + log_level = G_LOG_LEVEL_DEBUG; + else if (STR_CASEQ(level, "deb")) + log_level = G_LOG_LEVEL_DEBUG; + else + LOG_W("Unknown log level: '%s'", level); } void log_set_level(GLogLevelFlags level) { - log_level = level; + log_level = level; } /** @@ -70,35 +71,33 @@ void log_set_level(GLogLevelFlags level) * @param message Used only by GLib * @param ignore */ -static void dunst_log_handler( - const gchar *log_domain, - GLogLevelFlags message_level, - const gchar *message, - gpointer ignore) +static void dunst_log_handler(const gchar *log_domain, + GLogLevelFlags message_level, + const gchar *message, + gpointer ignore) { - (void)log_domain; + (void)log_domain; - GLogLevelFlags message_level_masked = message_level & G_LOG_LEVEL_MASK; + GLogLevelFlags message_level_masked = message_level & G_LOG_LEVEL_MASK; - if (log_mask == DUNST_LOG_NONE || - (log_mask == DUNST_LOG_AUTO && log_level < message_level_masked)) - return; + if (log_mask == DUNST_LOG_NONE + || (log_mask == DUNST_LOG_AUTO && log_level < message_level_masked)) + return; - const char *log_level_str = - log_level_to_string(message_level_masked); + const char *log_level_str = log_level_to_string(message_level_masked); - /* Use stderr for warnings and higher */ - if (message_level_masked <= G_LOG_LEVEL_WARNING) - g_printerr("%s: %s\n", log_level_str, message); - else - g_print("%s: %s\n", log_level_str, message); + /* Use stderr for warnings and higher */ + if (message_level_masked <= G_LOG_LEVEL_WARNING) + g_printerr("%s: %s\n", log_level_str, message); + else + g_print("%s: %s\n", log_level_str, message); } /* see log.h */ void dunst_log_init(enum log_mask mask) { - log_mask = mask; - g_log_set_default_handler(dunst_log_handler, NULL); + log_mask = mask; + g_log_set_default_handler(dunst_log_handler, NULL); } /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/log.h b/src/log.h index 53df1f9a9..b9fc49671 100644 --- a/src/log.h +++ b/src/log.h @@ -1,4 +1,5 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ #include #include @@ -22,7 +23,8 @@ * compiling with '-std=gnu99', this should be fine. */ #if __GNUC__ >= 8 || __clang_major__ >= 6 -#define MSG(format, ...) "[%16s:%04d] " format, __func__, __LINE__, ## __VA_ARGS__ +#define MSG(format, ...) \ + "[%16s:%04d] " format, __func__, __LINE__, ##__VA_ARGS__ #endif #ifdef MSG @@ -40,16 +42,21 @@ #define LOG_M g_message #define LOG_I g_info -#define DIE(...) do { LOG_C(__VA_ARGS__); exit(EXIT_FAILURE); } while (0) +#define DIE(...) \ + do { \ + LOG_C(__VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } while (0) // unified fopen() result messages #define MSG_FOPEN_SUCCESS(path, fp) "Opened '%s' (fd: '%d')", path, fileno(fp) #define MSG_FOPEN_FAILURE(path) "Cannot open '%s': %s", path, strerror(errno) -enum log_mask { - DUNST_LOG_NONE, - DUNST_LOG_ALL, - DUNST_LOG_AUTO, +enum log_mask +{ + DUNST_LOG_NONE, + DUNST_LOG_ALL, + DUNST_LOG_AUTO, }; /** @@ -70,7 +77,7 @@ void log_set_level(GLogLevelFlags level); * If `level` is `NULL`, nothing will be done. * If `level` is an invalid value, nothing will be done. */ -void log_set_level_from_string(const char* level); +void log_set_level_from_string(const char *level); /** * Initialise log handling. Can be called any time. diff --git a/src/markup.c b/src/markup.c index 89de3d896..2d885eaa2 100644 --- a/src/markup.c +++ b/src/markup.c @@ -1,4 +1,5 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ #include "markup.h" @@ -18,15 +19,15 @@ */ static char *markup_quote(char *str) { - ASSERT_OR_RET(str, NULL); + ASSERT_OR_RET(str, NULL); - str = string_replace_all("&", "&", str); - str = string_replace_all("\"", """, str); - str = string_replace_all("'", "'", str); - str = string_replace_all("<", "<", str); - str = string_replace_all(">", ">", str); + str = string_replace_all("&", "&", str); + str = string_replace_all("\"", """, str); + str = string_replace_all("'", "'", str); + str = string_replace_all("<", "<", str); + str = string_replace_all(">", ">", str); - return str; + return str; } /** @@ -35,15 +36,15 @@ static char *markup_quote(char *str) */ static char *markup_unquote(char *str) { - ASSERT_OR_RET(str, NULL); + ASSERT_OR_RET(str, NULL); - str = string_replace_all(""", "\"", str); - str = string_replace_all("'", "'", str); - str = string_replace_all("<", "<", str); - str = string_replace_all(">", ">", str); - str = string_replace_all("&", "&", str); + str = string_replace_all(""", "\"", str); + str = string_replace_all("'", "'", str); + str = string_replace_all("<", "<", str); + str = string_replace_all(">", ">", str); + str = string_replace_all("&", "&", str); - return str; + return str; } /** @@ -52,184 +53,188 @@ static char *markup_unquote(char *str) */ static char *markup_br2nl(char *str) { - ASSERT_OR_RET(str, NULL); + ASSERT_OR_RET(str, NULL); - str = string_replace_all("
", "\n", str); - str = string_replace_all("
", "\n", str); - str = string_replace_all("
", "\n", str); - return str; + str = string_replace_all("
", "\n", str); + str = string_replace_all("
", "\n", str); + str = string_replace_all("
", "\n", str); + return str; } /* see markup.h */ void markup_strip_a(char **str, char **urls) { - assert(*str); - char *tag1 = NULL; - - if (urls) - *urls = NULL; - - while ((tag1 = strstr(*str, ""); - char *tag2 = strstr(tag1, ""); - - // the tag is broken, ignore it - if (!tag1_end) { - LOG_W("Given link is broken: '%s'", - tag1); - string_replace_at(*str, tag1-*str, strlen(tag1), ""); - break; - } - if (tag2 && tag2 < tag1_end) { - int repl_len = (tag2 - tag1) + strlen(""); - LOG_W("Given link is broken: '%.*s.'", - repl_len, tag1); - string_replace_at(*str, tag1-*str, repl_len, ""); - break; - } - - // search contents of href attribute - char *plain_url = NULL; - if (href && href < tag1_end) { - - // shift href to the actual begin of the value - href = href+6; - - const char *quote = strstr(href, "\""); - - if (quote && quote < tag1_end) { - plain_url = g_strndup(href, quote-href); - } - } - - // text between a tags - int text_len; - if (tag2) - text_len = tag2 - (tag1_end+1); - else - text_len = strlen(tag1_end+1); - - char *text = g_strndup(tag1_end+1, text_len); - - int repl_len = text_len + (tag1_end-tag1) + 1; - repl_len += tag2 ? strlen("") : 0; - - *str = string_replace_at(*str, tag1-*str, repl_len, text); - - // if there had been a href attribute, - // add it to the URLs - if (plain_url && urls) { - text = string_replace_all("]", "", text); - text = string_replace_all("[", "", text); - - char *url = g_strdup_printf("[%s] %s", text, plain_url); - - *urls = string_append(*urls, url, "\n"); - g_free(url); - } - - g_free(plain_url); - g_free(text); + assert(*str); + char *tag1 = NULL; + + if (urls) + *urls = NULL; + + while ((tag1 = strstr(*str, ""); + char *tag2 = strstr(tag1, ""); + + // the tag is broken, ignore it + if (!tag1_end) { + LOG_W("Given link is broken: '%s'", tag1); + string_replace_at(*str, tag1 - *str, strlen(tag1), ""); + break; + } + if (tag2 && tag2 < tag1_end) { + int repl_len = (tag2 - tag1) + strlen(""); + LOG_W("Given link is broken: '%.*s.'", repl_len, tag1); + string_replace_at(*str, tag1 - *str, repl_len, ""); + break; } -} -/* see markup.h */ -void markup_strip_img(char **str, char **urls) -{ - const char *start; + // search contents of href attribute + char *plain_url = NULL; + if (href && href < tag1_end) { + + // shift href to the actual begin of the value + href = href + 6; - if (urls) - *urls = NULL; + const char *quote = strstr(href, "\""); + + if (quote && quote < tag1_end) { + plain_url = g_strndup(href, quote - href); + } + } - while ((start = strstr(*str, ""); + // text between a tags + int text_len; + if (tag2) + text_len = tag2 - (tag1_end + 1); + else + text_len = strlen(tag1_end + 1); - // the tag is broken, ignore it - if (!end) { - LOG_W("Given image is broken: '%s'", start); - string_replace_at(*str, start-*str, strlen(start), ""); - break; - } + char *text = g_strndup(tag1_end + 1, text_len); - // use attribute=" as stated in the notification spec - const char *alt_s = strstr(start, "alt=\""); - const char *src_s = strstr(start, "src=\""); + int repl_len = text_len + (tag1_end - tag1) + 1; + repl_len += tag2 ? strlen("") : 0; - char *text_alt = NULL; - char *text_src = NULL; + *str = string_replace_at(*str, tag1 - *str, repl_len, text); - const char *src_e = NULL, *alt_e = NULL; - if (alt_s) - alt_e = strstr(alt_s + strlen("alt=\""), "\""); - if (src_s) - src_e = strstr(src_s + strlen("src=\""), "\""); + // if there had been a href attribute, + // add it to the URLs + if (plain_url && urls) { + text = string_replace_all("]", "", text); + text = string_replace_all("[", "", text); - // Move pointer to the actual start - alt_s = alt_s ? alt_s + strlen("alt=\"") : NULL; - src_s = src_s ? src_s + strlen("src=\"") : NULL; + char *url = g_strdup_printf("[%s] %s", text, plain_url); - /* check if alt and src attribute are given - * If both given, check the alignment of all pointers */ - if ( alt_s && alt_e - && src_s && src_e - && ( (alt_s < src_s && alt_e < src_s-strlen("src=\"") && src_e < end) - ||(src_s < alt_s && src_e < alt_s-strlen("alt=\"") && alt_e < end)) ) { + *urls = string_append(*urls, url, "\n"); + g_free(url); + } + + g_free(plain_url); + g_free(text); + } +} + +/* see markup.h */ +void markup_strip_img(char **str, char **urls) +{ + const char *start; - text_alt = g_strndup(alt_s, alt_e-alt_s); - text_src = g_strndup(src_s, src_e-src_s); + if (urls) + *urls = NULL; - /* check if single valid alt attribute is available */ - } else if (alt_s && alt_e && alt_e < end && (!src_s || src_s < alt_s || alt_e < src_s - strlen("src=\""))) { - text_alt = g_strndup(alt_s, alt_e-alt_s); + while ((start = strstr(*str, ""); - /* check if single valid src attribute is available */ - } else if (src_s && src_e && src_e < end && (!alt_s || alt_s < src_s || src_e < alt_s - strlen("alt=\""))) { - text_src = g_strndup(src_s, src_e-src_s); + // the tag is broken, ignore it + if (!end) { + LOG_W("Given image is broken: '%s'", start); + string_replace_at(*str, start - *str, strlen(start), ""); + break; + } - } else { - LOG_W("Given image argument is broken: '%.*s'", - (int)(end-start), start); - } + // use attribute=" as stated in the notification spec + const char *alt_s = strstr(start, "alt=\""); + const char *src_s = strstr(start, "src=\""); + + char *text_alt = NULL; + char *text_src = NULL; + + const char *src_e = NULL, *alt_e = NULL; + if (alt_s) + alt_e = strstr(alt_s + strlen("alt=\""), "\""); + if (src_s) + src_e = strstr(src_s + strlen("src=\""), "\""); + + // Move pointer to the actual start + alt_s = alt_s ? alt_s + strlen("alt=\"") : NULL; + src_s = src_s ? src_s + strlen("src=\"") : NULL; + + /* check if alt and src attribute are given + * If both given, check the alignment of all pointers */ + if (alt_s && alt_e && src_s && src_e + && ((alt_s < src_s && alt_e < src_s - strlen("src=\"") + && src_e < end) + || (src_s < alt_s && src_e < alt_s - strlen("alt=\"") + && alt_e < end))) { + + text_alt = g_strndup(alt_s, alt_e - alt_s); + text_src = g_strndup(src_s, src_e - src_s); + + /* check if single valid alt attribute is available */ + } else if (alt_s && alt_e && alt_e < end + && (!src_s || src_s < alt_s + || alt_e < src_s - strlen("src=\""))) { + text_alt = g_strndup(alt_s, alt_e - alt_s); + + /* check if single valid src attribute is available */ + } else if (src_s && src_e && src_e < end + && (!alt_s || alt_s < src_s + || src_e < alt_s - strlen("alt=\""))) { + text_src = g_strndup(src_s, src_e - src_s); - // replacement text for alt - int repl_len = end - start + 1; + } else { + LOG_W("Given image argument is broken: '%.*s'", + (int)(end - start), + start); + } - if (!text_alt) - text_alt = g_strdup("[image]"); + // replacement text for alt + int repl_len = end - start + 1; - *str = string_replace_at(*str, start-*str, repl_len, text_alt); + if (!text_alt) + text_alt = g_strdup("[image]"); - // if there had been a href attribute, - // add it to the URLs - if (text_src && urls) { - text_alt = string_replace_all("]", "", text_alt); - text_alt = string_replace_all("[", "", text_alt); + *str = string_replace_at(*str, start - *str, repl_len, text_alt); - char *url = g_strdup_printf("[%s] %s", text_alt, text_src); + // if there had been a href attribute, + // add it to the URLs + if (text_src && urls) { + text_alt = string_replace_all("]", "", text_alt); + text_alt = string_replace_all("[", "", text_alt); - *urls = string_append(*urls, url, "\n"); - g_free(url); - } + char *url = g_strdup_printf("[%s] %s", text_alt, text_src); - g_free(text_src); - g_free(text_alt); + *urls = string_append(*urls, url, "\n"); + g_free(url); } + + g_free(text_src); + g_free(text_alt); + } } /* see markup.h */ char *markup_strip(char *str) { - ASSERT_OR_RET(str, NULL); + ASSERT_OR_RET(str, NULL); - /* strip all tags */ - string_strip_delimited(str, '<', '>'); + /* strip all tags */ + string_strip_delimited(str, '<', '>'); - /* unquote the remainder */ - str = markup_unquote(str); + /* unquote the remainder */ + str = markup_unquote(str); - return str; + return str; } /** @@ -241,44 +246,46 @@ char *markup_strip(char *str) */ static bool markup_is_entity(const char *str) { - assert(str); - assert(*str == '&'); + assert(str); + assert(*str == '&'); - char *end = strchr(str, ';'); - ASSERT_OR_RET(end, false); + char *end = strchr(str, ';'); + ASSERT_OR_RET(end, false); - // Parse (hexa)decimal entities with the format Ӓ or ઼ - if (str[1] == '#') { - const char *cur = str + 2; + // Parse (hexa)decimal entities with the format Ӓ or ઼ + if (str[1] == '#') { + const char *cur = str + 2; - if (*cur == 'x') { - cur++; + if (*cur == 'x') { + cur++; - // Reject &#x; - if (*cur == ';') - return false; + // Reject &#x; + if (*cur == ';') + return false; - while (isxdigit(*cur) && cur < end) - cur++; - } else { + while (isxdigit(*cur) && cur < end) + cur++; + } else { - // Reject &#; - if (*cur == ';') - return false; + // Reject &#; + if (*cur == ';') + return false; - while (isdigit(*cur) && cur < end) - cur++; - } + while (isdigit(*cur) && cur < end) + cur++; + } - return (cur == end); - } else { - const char *supported_tags[] = {"&", "<", ">", """, "'"}; - for (size_t i = 0; i < sizeof(supported_tags)/sizeof(*supported_tags); i++) { - if (g_str_has_prefix(str, supported_tags[i])) - return true; - } - return false; + return (cur == end); + } else { + const char *supported_tags[] = { + "&", "<", ">", """, "'"}; + for (size_t i = 0; i < sizeof(supported_tags) / sizeof(*supported_tags); + i++) { + if (g_str_has_prefix(str, supported_tags[i])) + return true; } + return false; + } } /** @@ -289,53 +296,51 @@ static bool markup_is_entity(const char *str) */ static char *markup_escape_unsupported(char *str) { - ASSERT_OR_RET(str, NULL); - - char *match = str; - while ((match = strchr(match, '&'))) { - if (!markup_is_entity(match)) { - int pos = match - str; - str = string_replace_at(str, pos, 1, "&"); - match = str + pos + strlen("&"); - } else { - match++; - } + ASSERT_OR_RET(str, NULL); + + char *match = str; + while ((match = strchr(match, '&'))) { + if (!markup_is_entity(match)) { + int pos = match - str; + str = string_replace_at(str, pos, 1, "&"); + match = str + pos + strlen("&"); + } else { + match++; } + } - return str; + return str; } /* see markup.h */ char *markup_transform(char *str, enum markup_mode markup_mode) { - ASSERT_OR_RET(str, NULL); - - switch (markup_mode) { - case MARKUP_NULL: - /* `assert(false)`, but with a meaningful error message */ - assert(markup_mode != MARKUP_NULL); - break; - case MARKUP_NO: - str = markup_quote(str); - break; - case MARKUP_STRIP: - str = markup_br2nl(str); - str = markup_strip(str); - str = markup_quote(str); - break; - case MARKUP_FULL: - str = markup_escape_unsupported(str); - str = markup_br2nl(str); - markup_strip_a(&str, NULL); - markup_strip_img(&str, NULL); - break; - } - - if (settings.ignore_newline) { - str = string_replace_all("\n", " ", str); - } - - return str; + ASSERT_OR_RET(str, NULL); + + switch (markup_mode) { + case MARKUP_NULL: + /* `assert(false)`, but with a meaningful error message */ + assert(markup_mode != MARKUP_NULL); + break; + case MARKUP_NO: str = markup_quote(str); break; + case MARKUP_STRIP: + str = markup_br2nl(str); + str = markup_strip(str); + str = markup_quote(str); + break; + case MARKUP_FULL: + str = markup_escape_unsupported(str); + str = markup_br2nl(str); + markup_strip_a(&str, NULL); + markup_strip_img(&str, NULL); + break; + } + + if (settings.ignore_newline) { + str = string_replace_all("\n", " ", str); + } + + return str; } /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/markup.h b/src/markup.h index e3d26afef..71a467abe 100644 --- a/src/markup.h +++ b/src/markup.h @@ -1,12 +1,14 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ #ifndef DUNST_MARKUP_H #define DUNST_MARKUP_H -enum markup_mode { - MARKUP_NULL, - MARKUP_NO, - MARKUP_STRIP, - MARKUP_FULL +enum markup_mode +{ + MARKUP_NULL, + MARKUP_NO, + MARKUP_STRIP, + MARKUP_FULL }; /** @@ -36,8 +38,8 @@ void markup_strip_a(char **str, char **urls); * Remove img-tags of a string. If alt attribute given, use this as replacement. * * @param str The string to replace img tags - * @param urls (nullable) If any src-attributes found, an `\n` concatenated string of - * the URLs in format `[] ` + * @param urls (nullable) If any src-attributes found, an `\n` concatenated + * string of the URLs in format `[] ` */ void markup_strip_img(char **str, char **urls); diff --git a/src/menu.c b/src/menu.c index 4bc97eaf3..b579b1372 100644 --- a/src/menu.c +++ b/src/menu.c @@ -1,4 +1,5 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ #include "menu.h" @@ -25,8 +26,9 @@ static regex_t url_regex; static gpointer context_menu_thread(gpointer data); -struct { - GList *locked_notifications; +struct +{ + GList *locked_notifications; } menu_ctx; /** @@ -36,62 +38,62 @@ struct { */ static bool regex_init(void) { - if (is_initialized) - return true; - - char *regex = - "\\<(https?://|ftps?://|news://|mailto:|file://|www\\.)" - "[-[:alnum:]_\\@;/?:&=%$.+!*\x27,~#]*" - "(\\([-[:alnum:]_\\@;/?:&=%$.+!*\x27,~#]*\\)|[-[:alnum:]_\\@;/?:&=%$+*~])+"; - int code = regcomp(&url_regex, regex, REG_EXTENDED | REG_ICASE); - if (code != 0) { - char error_buf[120]; - regerror(code, &url_regex, error_buf, sizeof(error_buf)); - LOG_W("Failed to compile URL-matching regex: %s", error_buf); - return false; - } else { - is_initialized = true; - return true; - } + if (is_initialized) + return true; + + char *regex = "\\<(https?://|ftps?://|news://|mailto:|file://|www\\.)" + "[-[:alnum:]_\\@;/?:&=%$.+!*\x27,~#]*" + "(\\([-[:alnum:]_\\@;/" + "?:&=%$.+!*\x27,~#]*\\)|[-[:alnum:]_\\@;/?:&=%$+*~])+"; + int code = regcomp(&url_regex, regex, REG_EXTENDED | REG_ICASE); + if (code != 0) { + char error_buf[120]; + regerror(code, &url_regex, error_buf, sizeof(error_buf)); + LOG_W("Failed to compile URL-matching regex: %s", error_buf); + return false; + } else { + is_initialized = true; + return true; + } } void regex_teardown(void) { - if (is_initialized) { - regfree(&url_regex); - is_initialized = false; - } + if (is_initialized) { + regfree(&url_regex); + is_initialized = false; + } } /* see menu.h */ char *extract_urls(const char *to_match) { - if (!to_match) - return NULL; + if (!to_match) + return NULL; - if (!regex_init()) - return NULL; + if (!regex_init()) + return NULL; - char *urls = NULL; - const char *p = to_match; - regmatch_t m; + char *urls = NULL; + const char *p = to_match; + regmatch_t m; - while (1) { - int nomatch = regexec(&url_regex, p, 1, &m, 0); + while (1) { + int nomatch = regexec(&url_regex, p, 1, &m, 0); - if (nomatch || m.rm_so == -1) - break; + if (nomatch || m.rm_so == -1) + break; - int start = m.rm_so + (p - to_match); - int finish = m.rm_eo + (p - to_match); + int start = m.rm_so + (p - to_match); + int finish = m.rm_eo + (p - to_match); - char *match = g_strndup(to_match + start, finish - start); - urls = string_append(urls, match, "\n"); + char *match = g_strndup(to_match + start, finish - start); + urls = string_append(urls, match, "\n"); - g_free(match); - p += m.rm_eo; - } - return urls; + g_free(match); + p += m.rm_eo; + } + return urls; } /* @@ -100,66 +102,65 @@ char *extract_urls(const char *to_match) */ void open_browser(const char *in) { - if (!settings.browser_cmd) { - LOG_C("Unable to open browser: No browser command set."); - return; - } - - char *url, *end; - // If any, remove leading [ linktext ] from URL - if (*in == '[' && (end = strstr(in, "] "))) - url = g_strdup(end + 2); - else - url = g_strdup(in); - - int argc = 2+g_strv_length(settings.browser_cmd); - char **argv = g_malloc_n(argc, sizeof(char*)); - - memcpy(argv, settings.browser_cmd, argc * sizeof(char*)); - argv[argc-2] = url; - argv[argc-1] = NULL; - - GError *err = NULL; - g_spawn_async(NULL, - argv, - NULL, - G_SPAWN_DEFAULT - | G_SPAWN_SEARCH_PATH - | G_SPAWN_STDOUT_TO_DEV_NULL - | G_SPAWN_STDERR_TO_DEV_NULL, - NULL, - NULL, - NULL, - &err); - - if (err) { - LOG_C("Cannot spawn browser: %s", err->message); - g_error_free(err); - } - - g_free(argv); - g_free(url); + if (!settings.browser_cmd) { + LOG_C("Unable to open browser: No browser command set."); + return; + } + + char *url, *end; + // If any, remove leading [ linktext ] from URL + if (*in == '[' && (end = strstr(in, "] "))) + url = g_strdup(end + 2); + else + url = g_strdup(in); + + int argc = 2 + g_strv_length(settings.browser_cmd); + char **argv = g_malloc_n(argc, sizeof(char *)); + + memcpy(argv, settings.browser_cmd, argc * sizeof(char *)); + argv[argc - 2] = url; + argv[argc - 1] = NULL; + + GError *err = NULL; + g_spawn_async(NULL, + argv, + NULL, + G_SPAWN_DEFAULT | G_SPAWN_SEARCH_PATH + | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, + NULL, + NULL, + NULL, + &err); + + if (err) { + LOG_C("Cannot spawn browser: %s", err->message); + g_error_free(err); + } + + g_free(argv); + g_free(url); } char *notification_dmenu_string(struct notification *n) { - char *dmenu_str = NULL; + char *dmenu_str = NULL; - gpointer p_key; - gpointer p_value; - GHashTableIter iter; - g_hash_table_iter_init(&iter, n->actions); - while (g_hash_table_iter_next(&iter, &p_key, &p_value)) { + gpointer p_key; + gpointer p_value; + GHashTableIter iter; + g_hash_table_iter_init(&iter, n->actions); + while (g_hash_table_iter_next(&iter, &p_key, &p_value)) { - char *key = (char*) p_key; - char *value = (char*) p_value; + char *key = (char *)p_key; + char *value = (char *)p_value; - char *act_str = g_strdup_printf("#%s (%s) [%d,%s]", value, n->summary, n->id, key); - dmenu_str = string_append(dmenu_str, act_str, "\n"); + char *act_str = + g_strdup_printf("#%s (%s) [%d,%s]", value, n->summary, n->id, key); + dmenu_str = string_append(dmenu_str, act_str, "\n"); - g_free(act_str); - } - return dmenu_str; + g_free(act_str); + } + return dmenu_str; } /* @@ -168,50 +169,48 @@ char *notification_dmenu_string(struct notification *n) */ void invoke_action(const char *action) { - struct notification *invoked = NULL; - gint id; - - char *data_start, *data_comma, *data_end; - - /* format: # ()[,] */ - data_start = strrchr(action, '['); - if (!data_start) { - LOG_W("Invalid action: '%s'", action); - return; + struct notification *invoked = NULL; + gint id; + + char *data_start, *data_comma, *data_end; + + /* format: # ()[,] */ + data_start = strrchr(action, '['); + if (!data_start) { + LOG_W("Invalid action: '%s'", action); + return; + } + + id = strtol(++data_start, &data_comma, 10); + if (*data_comma != ',') { + LOG_W("Invalid action: '%s'", action); + return; + } + + data_end = strchr(data_comma + 1, ']'); + if (!data_end) { + LOG_W("Invalid action: '%s'", action); + return; + } + + char *action_key = g_strndup(data_comma + 1, data_end - data_comma - 1); + + for (const GList *iter = queues_get_displayed(); iter; iter = iter->next) { + struct notification *n = iter->data; + if (n->id != id) + continue; + + if (g_hash_table_contains(n->actions, action_key)) { + invoked = n; + break; } + } - id = strtol(++data_start, &data_comma, 10); - if (*data_comma != ',') { - LOG_W("Invalid action: '%s'", action); - return; - } + if (invoked && action_key) { + signal_action_invoked(invoked, action_key); + } - data_end = strchr(data_comma+1, ']'); - if (!data_end) { - LOG_W("Invalid action: '%s'", action); - return; - } - - char *action_key = g_strndup(data_comma+1, data_end-data_comma-1); - - for (const GList *iter = queues_get_displayed(); - iter; - iter = iter->next) { - struct notification *n = iter->data; - if (n->id != id) - continue; - - if (g_hash_table_contains(n->actions, action_key)) { - invoked = n; - break; - } - } - - if (invoked && action_key) { - signal_action_invoked(invoked, action_key); - } - - g_free(action_key); + g_free(action_key); } /** @@ -222,17 +221,17 @@ void invoke_action(const char *action) */ void dispatch_menu_result(const char *input) { - ASSERT_OR_RET(input,); + ASSERT_OR_RET(input, ); - char *in = g_strdup(input); - g_strstrip(in); + char *in = g_strdup(input); + g_strstrip(in); - if (in[0] == '#') - invoke_action(in + 1); - else if (in[0] != '\0') - open_browser(in); + if (in[0] == '#') + invoke_action(in + 1); + else if (in[0] != '\0') + open_browser(in); - g_free(in); + g_free(in); } /** Call dmenu with the specified input. Blocks until dmenu is finished. @@ -242,53 +241,52 @@ void dispatch_menu_result(const char *input) */ char *invoke_dmenu(const char *dmenu_input) { - if (!settings.dmenu_cmd) { - LOG_C("Unable to open dmenu: No dmenu command set."); - return NULL; + if (!settings.dmenu_cmd) { + LOG_C("Unable to open dmenu: No dmenu command set."); + return NULL; + } + + ASSERT_OR_RET(STR_FULL(dmenu_input), NULL); + + gint dunst_to_dmenu; + gint dmenu_to_dunst; + GError *err = NULL; + char buf[1024]; + char *ret = NULL; + + g_spawn_async_with_pipes(NULL, + settings.dmenu_cmd, + NULL, + G_SPAWN_DEFAULT | G_SPAWN_SEARCH_PATH, + NULL, + NULL, + NULL, + &dunst_to_dmenu, + &dmenu_to_dunst, + NULL, + &err); + + if (err) { + LOG_C("Cannot spawn dmenu: %s", err->message); + g_error_free(err); + } else { + size_t wlen = strlen(dmenu_input); + ssize_t n = write(dunst_to_dmenu, dmenu_input, wlen); + if (n < 0 || (size_t)n != wlen) { + LOG_W("Cannot feed dmenu with input: %s", strerror(errno)); } + close(dunst_to_dmenu); - ASSERT_OR_RET(STR_FULL(dmenu_input), NULL); - - gint dunst_to_dmenu; - gint dmenu_to_dunst; - GError *err = NULL; - char buf[1024]; - char *ret = NULL; - - g_spawn_async_with_pipes(NULL, - settings.dmenu_cmd, - NULL, - G_SPAWN_DEFAULT - | G_SPAWN_SEARCH_PATH, - NULL, - NULL, - NULL, - &dunst_to_dmenu, - &dmenu_to_dunst, - NULL, - &err); - - if (err) { - LOG_C("Cannot spawn dmenu: %s", err->message); - g_error_free(err); - } else { - size_t wlen = strlen(dmenu_input); - ssize_t n = write(dunst_to_dmenu, dmenu_input, wlen); - if (n < 0 || (size_t)n != wlen) { - LOG_W("Cannot feed dmenu with input: %s", strerror(errno)); - } - close(dunst_to_dmenu); - - ssize_t rlen = read(dmenu_to_dunst, buf, sizeof(buf)); - close(dmenu_to_dunst); - - if (rlen > 0) - ret = g_strndup(buf, rlen); - else - LOG_W("Didn't receive input from dmenu."); - } + ssize_t rlen = read(dmenu_to_dunst, buf, sizeof(buf)); + close(dmenu_to_dunst); + + if (rlen > 0) + ret = g_strndup(buf, rlen); + else + LOG_W("Didn't receive input from dmenu."); + } - return ret; + return ret; } /** @@ -296,100 +294,96 @@ char *invoke_dmenu(const char *dmenu_input) **/ static GList *get_actionable_notifications(void) { - GList *locked_notifications = NULL; + GList *locked_notifications = NULL; - for (const GList *iter = queues_get_displayed(); iter; - iter = iter->next) { - struct notification *n = iter->data; + for (const GList *iter = queues_get_displayed(); iter; iter = iter->next) { + struct notification *n = iter->data; - if (n->urls || g_hash_table_size(n->actions)) { - notification_lock(n); - locked_notifications = g_list_prepend(locked_notifications, n); - } + if (n->urls || g_hash_table_size(n->actions)) { + notification_lock(n); + locked_notifications = g_list_prepend(locked_notifications, n); } + } - return g_list_reverse(locked_notifications); + return g_list_reverse(locked_notifications); } /* see menu.h */ void context_menu(void) { - GList *notifications = get_actionable_notifications(); - context_menu_for(notifications); + GList *notifications = get_actionable_notifications(); + context_menu_for(notifications); } /* see menu.h */ void context_menu_for(GList *notifications) { - if (menu_ctx.locked_notifications) { - LOG_W("Context menu already running, refusing to rerun"); - return; - } + if (menu_ctx.locked_notifications) { + LOG_W("Context menu already running, refusing to rerun"); + return; + } - menu_ctx.locked_notifications = notifications; + menu_ctx.locked_notifications = notifications; - GError *err = NULL; - g_thread_unref(g_thread_try_new("dmenu", - context_menu_thread, - NULL, - &err)); + GError *err = NULL; + g_thread_unref(g_thread_try_new("dmenu", context_menu_thread, NULL, &err)); - if (err) { - LOG_C("Cannot start thread to call dmenu: %s", err->message); - g_error_free(err); - } + if (err) { + LOG_C("Cannot start thread to call dmenu: %s", err->message); + g_error_free(err); + } } static gboolean context_menu_result_dispatch(gpointer user_data) { - char *dmenu_output = (char*)user_data; - - dispatch_menu_result(dmenu_output); - - for (GList *iter = menu_ctx.locked_notifications; iter; iter = iter->next) { - struct notification *n = iter->data; - notification_unlock(n); - if (n->marked_for_closure) { - // Don't close notification if context was aborted - if (dmenu_output != NULL) - queues_notification_close(n, n->marked_for_closure); - n->marked_for_closure = 0; - } + char *dmenu_output = (char *)user_data; + + dispatch_menu_result(dmenu_output); + + for (GList *iter = menu_ctx.locked_notifications; iter; iter = iter->next) { + struct notification *n = iter->data; + notification_unlock(n); + if (n->marked_for_closure) { + // Don't close notification if context was aborted + if (dmenu_output != NULL) + queues_notification_close(n, n->marked_for_closure); + n->marked_for_closure = 0; } + } - menu_ctx.locked_notifications = NULL; + menu_ctx.locked_notifications = NULL; - g_list_free(menu_ctx.locked_notifications); - g_free(dmenu_output); + g_list_free(menu_ctx.locked_notifications); + g_free(dmenu_output); - wake_up(); + wake_up(); - return G_SOURCE_REMOVE; + return G_SOURCE_REMOVE; } static gpointer context_menu_thread(gpointer data) { - (void)data; + (void)data; - char *dmenu_input = NULL; - char *dmenu_output; + char *dmenu_input = NULL; + char *dmenu_output; - for (GList *iter = menu_ctx.locked_notifications; iter; iter = iter->next) { - struct notification *n = iter->data; + for (GList *iter = menu_ctx.locked_notifications; iter; iter = iter->next) { + struct notification *n = iter->data; - char *dmenu_str = notification_dmenu_string(n); - dmenu_input = string_append(dmenu_input, dmenu_str, "\n"); - g_free(dmenu_str); + char *dmenu_str = notification_dmenu_string(n); + dmenu_input = string_append(dmenu_input, dmenu_str, "\n"); + g_free(dmenu_str); - if (n->urls) - dmenu_input = string_append(dmenu_input, n->urls, "\n"); - } + if (n->urls) + dmenu_input = string_append(dmenu_input, n->urls, "\n"); + } - dmenu_output = invoke_dmenu(dmenu_input); - g_timeout_add(50, context_menu_result_dispatch, dmenu_output); + dmenu_output = invoke_dmenu(dmenu_input); + g_timeout_add(50, context_menu_result_dispatch, dmenu_output); - g_free(dmenu_input); + g_free(dmenu_input); - return NULL; + return NULL; } /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/menu.h b/src/menu.h index 5263c585f..ef9d8e549 100644 --- a/src/menu.h +++ b/src/menu.h @@ -1,4 +1,5 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ #ifndef DUNST_MENU_H #define DUNST_MENU_H @@ -18,13 +19,16 @@ void invoke_action(const char *action); void regex_teardown(void); /** - * Open the context menu that lets the user select urls/actions/etc for all displayed notifications. + * Open the context menu that lets the user select urls/actions/etc for all + * displayed notifications. */ void context_menu(void); /** - * Open the context menu that lets the user select urls/actions/etc for the specified notifications. - * @param notifications (nullable) List of notifications for which the context menu should be opened + * Open the context menu that lets the user select urls/actions/etc for the + * specified notifications. + * @param notifications (nullable) List of notifications for which the context + * menu should be opened */ void context_menu_for(GList *notifications); diff --git a/src/notification.c b/src/notification.c index 6a0d4fe40..3bb578f41 100644 --- a/src/notification.c +++ b/src/notification.c @@ -1,4 +1,5 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ #include "notification.h" @@ -14,7 +15,9 @@ #include #include "dbus.h" +#include "draw.h" #include "dunst.h" +#include "icon-lookup.h" #include "icon.h" #include "log.h" #include "markup.h" @@ -22,10 +25,8 @@ #include "queues.h" #include "rules.h" #include "settings.h" -#include "utils.h" -#include "draw.h" -#include "icon-lookup.h" #include "settings_data.h" +#include "utils.h" static void notification_extract_urls(struct notification *n); static void notification_format_message(struct notification *n); @@ -33,151 +34,159 @@ static void notification_format_message(struct notification *n); /* see notification.h */ const char *enum_to_string_fullscreen(enum behavior_fullscreen in) { - switch (in) { - case FS_SHOW: return "show"; - case FS_DELAY: return "delay"; - case FS_PUSHBACK: return "pushback"; - case FS_NULL: return "(null)"; - default: - LOG_E("Invalid %s enum value in %s:%d", "fullscreen", __FILE__, __LINE__); - break; - } + switch (in) { + case FS_SHOW: return "show"; + case FS_DELAY: return "delay"; + case FS_PUSHBACK: return "pushback"; + case FS_NULL: return "(null)"; + default: + LOG_E( + "Invalid %s enum value in %s:%d", "fullscreen", __FILE__, __LINE__); + break; + } } -struct _notification_private { - gint refcount; +struct _notification_private +{ + gint refcount; }; /* see notification.h */ void notification_print(const struct notification *n) { - //TODO: use logging info for this - printf("{\n"); - printf("\tappname: '%s'\n", STR_NN(n->appname)); - printf("\tsummary: '%s'\n", STR_NN(n->summary)); - printf("\tbody: '%s'\n", STR_NN(n->body)); - printf("\ticon: '%s'\n", STR_NN(n->iconname)); - printf("\traw_icon set: %s\n", (n->icon_id && !STR_EQ(n->iconname, n->icon_id)) ? "true" : "false"); - printf("\ticon_id: '%s'\n", STR_NN(n->icon_id)); - printf("\tdesktop_entry: '%s'\n", n->desktop_entry ? n->desktop_entry : ""); - printf("\tcategory: %s\n", STR_NN(n->category)); - printf("\ttimeout: %"G_GINT64_FORMAT"\n", n->timeout/1000); - printf("\tstart: %"G_GINT64_FORMAT"\n", n->start); - printf("\ttimestamp: %"G_GINT64_FORMAT"\n", n->timestamp); - printf("\turgency: %s\n", notification_urgency_to_string(n->urgency)); - printf("\ttransient: %d\n", n->transient); - printf("\tformatted: '%s'\n", STR_NN(n->msg)); - char buf[10]; - printf("\tfg: %s\n", STR_NN(color_to_string(n->colors.fg, buf))); - printf("\tbg: %s\n", STR_NN(color_to_string(n->colors.bg, buf))); - printf("\tframe: %s\n", STR_NN(color_to_string(n->colors.frame, buf))); - - char *grad = gradient_to_string(n->colors.highlight); - printf("\thighlight: %s\n", STR_NN(grad)); - g_free(grad); - - printf("\tfullscreen: %s\n", enum_to_string_fullscreen(n->fullscreen)); - printf("\tformat: %s\n", STR_NN(n->format)); - printf("\tprogress: %d\n", n->progress); - printf("\tstack_tag: %s\n", (n->stack_tag ? n->stack_tag : "")); - printf("\tid: %d\n", n->id); - if (n->urls) { - char *urls = string_replace_all("\n", "\t\t\n", g_strdup(n->urls)); - printf("\turls:\n"); - printf("\t{\n"); - printf("\t\t%s\n", STR_NN(urls)); - printf("\t}\n"); - g_free(urls); + // TODO: use logging info for this + printf("{\n"); + printf("\tappname: '%s'\n", STR_NN(n->appname)); + printf("\tsummary: '%s'\n", STR_NN(n->summary)); + printf("\tbody: '%s'\n", STR_NN(n->body)); + printf("\ticon: '%s'\n", STR_NN(n->iconname)); + printf("\traw_icon set: %s\n", + (n->icon_id && !STR_EQ(n->iconname, n->icon_id)) ? "true" : "false"); + printf("\ticon_id: '%s'\n", STR_NN(n->icon_id)); + printf("\tdesktop_entry: '%s'\n", n->desktop_entry ? n->desktop_entry : ""); + printf("\tcategory: %s\n", STR_NN(n->category)); + printf("\ttimeout: %" G_GINT64_FORMAT "\n", n->timeout / 1000); + printf("\tstart: %" G_GINT64_FORMAT "\n", n->start); + printf("\ttimestamp: %" G_GINT64_FORMAT "\n", n->timestamp); + printf("\turgency: %s\n", notification_urgency_to_string(n->urgency)); + printf("\ttransient: %d\n", n->transient); + printf("\tformatted: '%s'\n", STR_NN(n->msg)); + char buf[10]; + printf("\tfg: %s\n", STR_NN(color_to_string(n->colors.fg, buf))); + printf("\tbg: %s\n", STR_NN(color_to_string(n->colors.bg, buf))); + printf("\tframe: %s\n", STR_NN(color_to_string(n->colors.frame, buf))); + + char *grad = gradient_to_string(n->colors.highlight); + printf("\thighlight: %s\n", STR_NN(grad)); + g_free(grad); + + printf("\tfullscreen: %s\n", enum_to_string_fullscreen(n->fullscreen)); + printf("\tformat: %s\n", STR_NN(n->format)); + printf("\tprogress: %d\n", n->progress); + printf("\tstack_tag: %s\n", (n->stack_tag ? n->stack_tag : "")); + printf("\tid: %d\n", n->id); + if (n->urls) { + char *urls = string_replace_all("\n", "\t\t\n", g_strdup(n->urls)); + printf("\turls:\n"); + printf("\t{\n"); + printf("\t\t%s\n", STR_NN(urls)); + printf("\t}\n"); + g_free(urls); + } + if (g_hash_table_size(n->actions) == 0) { + printf("\tactions: {}\n"); + } else { + gpointer p_key, p_value; + GHashTableIter iter; + g_hash_table_iter_init(&iter, n->actions); + printf("\tactions: {\n"); + while (g_hash_table_iter_next(&iter, &p_key, &p_value)) + printf( + "\t\t\"%s\": \"%s\"\n", (char *)p_key, STR_NN((char *)p_value)); + printf("\t}\n"); + } + printf("\tscript_count: %d\n", n->script_count); + if (n->script_count > 0) { + printf("\tscripts: "); + for (int i = 0; i < n->script_count; i++) { + printf("'%s' ", STR_NN(n->scripts[i])); } - if (g_hash_table_size(n->actions) == 0) { - printf("\tactions: {}\n"); - } else { - gpointer p_key, p_value; - GHashTableIter iter; - g_hash_table_iter_init(&iter, n->actions); - printf("\tactions: {\n"); - while (g_hash_table_iter_next(&iter, &p_key, &p_value)) - printf("\t\t\"%s\": \"%s\"\n", (char*)p_key, STR_NN((char*)p_value)); - printf("\t}\n"); - } - printf("\tscript_count: %d\n", n->script_count); - if (n->script_count > 0) { - printf("\tscripts: "); - for (int i = 0; i < n->script_count; i++) { - printf("'%s' ", STR_NN(n->scripts[i])); - } - printf("\n"); - } - printf("}\n"); - fflush(stdout); + printf("\n"); + } + printf("}\n"); + fflush(stdout); } /* see notification.h */ void notification_run_script(struct notification *n) { - if (n->script_run && !settings.always_run_script) - return; - - n->script_run = true; - - const char *appname = n->appname ? n->appname : ""; - const char *summary = n->summary ? n->summary : ""; - const char *body = n->body ? n->body : ""; - const char *icon = n->iconname ? n->iconname : ""; - - const char *urgency = notification_urgency_to_string(n->urgency); - - for(int i = 0; i < n->script_count; i++) { - - const char *script = n->scripts[i]; - - if (STR_EMPTY(script)) - continue; - - int pid1 = fork(); - - if (pid1) { - int status; - waitpid(pid1, &status, 0); - } else { - // second fork to prevent zombie processes - int pid2 = fork(); - if (pid2) { - exit(0); - } else { - // Set environment variables - gchar *n_id_str = g_strdup_printf("%i", n->id); - gchar *n_progress_str = g_strdup_printf("%i", n->progress); - gchar *n_timeout_str = g_strdup_printf("%"G_GINT64_FORMAT, n->timeout/1000); - gchar *n_timestamp_str = g_strdup_printf("%"G_GINT64_FORMAT, n->timestamp / 1000); - safe_setenv("DUNST_APP_NAME", appname); - safe_setenv("DUNST_SUMMARY", summary); - safe_setenv("DUNST_BODY", body); - safe_setenv("DUNST_ICON_PATH", n->icon_path); - safe_setenv("DUNST_URGENCY", urgency); - safe_setenv("DUNST_ID", n_id_str); - safe_setenv("DUNST_PROGRESS", n_progress_str); - safe_setenv("DUNST_CATEGORY", n->category); - safe_setenv("DUNST_STACK_TAG", n->stack_tag); - safe_setenv("DUNST_URLS", n->urls); - safe_setenv("DUNST_TIMEOUT", n_timeout_str); - safe_setenv("DUNST_TIMESTAMP", n_timestamp_str); - safe_setenv("DUNST_DESKTOP_ENTRY", n->desktop_entry); - - execlp(script, - script, - appname, - summary, - body, - icon, - urgency, - (char *)NULL); - - LOG_W("Unable to run script %s: %s", n->scripts[i], strerror(errno)); - exit(EXIT_FAILURE); - } - } + if (n->script_run && !settings.always_run_script) + return; + + n->script_run = true; + + const char *appname = n->appname ? n->appname : ""; + const char *summary = n->summary ? n->summary : ""; + const char *body = n->body ? n->body : ""; + const char *icon = n->iconname ? n->iconname : ""; + + const char *urgency = notification_urgency_to_string(n->urgency); + + for (int i = 0; i < n->script_count; i++) { + + const char *script = n->scripts[i]; + + if (STR_EMPTY(script)) + continue; + + int pid1 = fork(); + + if (pid1) { + int status; + waitpid(pid1, &status, 0); + } else { + // second fork to prevent zombie processes + int pid2 = fork(); + if (pid2) { + exit(0); + } else { + // Set environment variables + gchar *n_id_str = g_strdup_printf("%i", n->id); + gchar *n_progress_str = g_strdup_printf("%i", n->progress); + gchar *n_timeout_str = + g_strdup_printf("%" G_GINT64_FORMAT, n->timeout / 1000); + gchar *n_timestamp_str = + g_strdup_printf("%" G_GINT64_FORMAT, n->timestamp / 1000); + safe_setenv("DUNST_APP_NAME", appname); + safe_setenv("DUNST_SUMMARY", summary); + safe_setenv("DUNST_BODY", body); + safe_setenv("DUNST_ICON_PATH", n->icon_path); + safe_setenv("DUNST_URGENCY", urgency); + safe_setenv("DUNST_ID", n_id_str); + safe_setenv("DUNST_PROGRESS", n_progress_str); + safe_setenv("DUNST_CATEGORY", n->category); + safe_setenv("DUNST_STACK_TAG", n->stack_tag); + safe_setenv("DUNST_URLS", n->urls); + safe_setenv("DUNST_TIMEOUT", n_timeout_str); + safe_setenv("DUNST_TIMESTAMP", n_timestamp_str); + safe_setenv("DUNST_DESKTOP_ENTRY", n->desktop_entry); + + execlp(script, + script, + appname, + summary, + body, + icon, + urgency, + (char *)NULL); + + LOG_W("Unable to run script %s: %s", + n->scripts[i], + strerror(errno)); + exit(EXIT_FAILURE); + } } + } } /* @@ -185,221 +194,224 @@ void notification_run_script(struct notification *n) */ const char *notification_urgency_to_string(const enum urgency urgency) { - switch (urgency) { - case URG_NONE: - return "NONE"; - case URG_LOW: - return "LOW"; - case URG_NORM: - return "NORMAL"; - case URG_CRIT: - return "CRITICAL"; - default: - return "UNDEF"; - } + switch (urgency) { + case URG_NONE: return "NONE"; + case URG_LOW: return "LOW"; + case URG_NORM: return "NORMAL"; + case URG_CRIT: return "CRITICAL"; + default: return "UNDEF"; + } } /* see notification.h */ int notification_cmp(const struct notification *a, const struct notification *b) { - const struct notification *a_order; - const struct notification *b_order; - if(settings.sort == SORT_TYPE_UPDATE && settings.origin & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM){ - a_order = b; - b_order = a; - } else { - a_order = a; - b_order = b; + const struct notification *a_order; + const struct notification *b_order; + if (settings.sort == SORT_TYPE_UPDATE + && settings.origin & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) { + a_order = b; + b_order = a; + } else { + a_order = a; + b_order = b; + } + + if (settings.sort == SORT_TYPE_URGENCY_ASCENDING) { + if (a_order->urgency != b_order->urgency) { + return a_order->urgency - b_order->urgency; } - - if(settings.sort == SORT_TYPE_URGENCY_ASCENDING){ - if(a_order->urgency != b_order->urgency){ - return a_order->urgency - b_order->urgency; - } - } else if (settings.sort == SORT_TYPE_URGENCY_DESCENDING) { - if(a_order->urgency != b_order->urgency){ - return b_order->urgency - a_order->urgency; - } - } else if(settings.sort == SORT_TYPE_UPDATE){ - return b_order->timestamp - a_order->timestamp; + } else if (settings.sort == SORT_TYPE_URGENCY_DESCENDING) { + if (a_order->urgency != b_order->urgency) { + return b_order->urgency - a_order->urgency; } + } else if (settings.sort == SORT_TYPE_UPDATE) { + return b_order->timestamp - a_order->timestamp; + } - return a_order->id - b_order->id; + return a_order->id - b_order->id; } /* see notification.h */ int notification_cmp_data(const void *va, const void *vb, void *data) { - (void)data; + (void)data; - struct notification *a = (struct notification *) va; - struct notification *b = (struct notification *) vb; + struct notification *a = (struct notification *)va; + struct notification *b = (struct notification *)vb; - return notification_cmp(a, b); + return notification_cmp(a, b); } -bool notification_is_duplicate(const struct notification *a, const struct notification *b) +bool notification_is_duplicate(const struct notification *a, + const struct notification *b) { - return STR_EQ(a->appname, b->appname) - && STR_EQ(a->summary, b->summary) - && STR_EQ(a->body, b->body) - && (a->icon_position != ICON_OFF ? STR_EQ(a->icon_id, b->icon_id) : 1) - && a->urgency == b->urgency; + return STR_EQ(a->appname, b->appname) && STR_EQ(a->summary, b->summary) + && STR_EQ(a->body, b->body) + && (a->icon_position != ICON_OFF ? STR_EQ(a->icon_id, b->icon_id) : 1) + && a->urgency == b->urgency; } -bool notification_is_locked(struct notification *n) { - assert(n); +bool notification_is_locked(struct notification *n) +{ + assert(n); - return g_atomic_int_get(&n->locked) != 0; + return g_atomic_int_get(&n->locked) != 0; } -struct notification* notification_lock(struct notification *n) { - assert(n); +struct notification *notification_lock(struct notification *n) +{ + assert(n); - g_atomic_int_set(&n->locked, 1); - notification_ref(n); + g_atomic_int_set(&n->locked, 1); + notification_ref(n); - return n; + return n; } -struct notification* notification_unlock(struct notification *n) { - assert(n); +struct notification *notification_unlock(struct notification *n) +{ + assert(n); - g_atomic_int_set(&n->locked, 0); - notification_unref(n); + g_atomic_int_set(&n->locked, 0); + notification_unref(n); - return n; + return n; } static void notification_private_free(NotificationPrivate *p) { - g_free(p); + g_free(p); } /* see notification.h */ gint notification_refcount_get(struct notification *n) { - assert(n->priv->refcount > 0); - return g_atomic_int_get(&n->priv->refcount); + assert(n->priv->refcount > 0); + return g_atomic_int_get(&n->priv->refcount); } /* see notification.h */ void notification_ref(struct notification *n) { - assert(n->priv->refcount > 0); - g_atomic_int_inc(&n->priv->refcount); + assert(n->priv->refcount > 0); + g_atomic_int_inc(&n->priv->refcount); } /* see notification.h */ void notification_unref(struct notification *n) { - ASSERT_OR_RET(n,); + ASSERT_OR_RET(n, ); - assert(n->priv->refcount > 0); - if (!g_atomic_int_dec_and_test(&n->priv->refcount)) - return; + assert(n->priv->refcount > 0); + if (!g_atomic_int_dec_and_test(&n->priv->refcount)) + return; - if (n->original) - rule_free(n->original); + if (n->original) + rule_free(n->original); - g_free(n->dbus_client); - g_free(n->appname); - g_free(n->summary); - g_free(n->body); - g_free(n->category); - g_free(n->desktop_entry); + g_free(n->dbus_client); + g_free(n->appname); + g_free(n->summary); + g_free(n->body); + g_free(n->category); + g_free(n->desktop_entry); - g_free(n->icon_id); - g_free(n->iconname); - g_free(n->icon_path); - g_free(n->default_icon_name); + g_free(n->icon_id); + g_free(n->iconname); + g_free(n->icon_path); + g_free(n->default_icon_name); - g_hash_table_unref(n->actions); - g_free(n->default_action_name); + g_hash_table_unref(n->actions); + g_free(n->default_action_name); - if (n->icon) - cairo_surface_destroy(n->icon); + if (n->icon) + cairo_surface_destroy(n->icon); - notification_private_free(n->priv); + notification_private_free(n->priv); - gradient_release(n->colors.highlight); + gradient_release(n->colors.highlight); - g_free(n->format); - g_strfreev(n->scripts); - g_free(n->stack_tag); + g_free(n->format); + g_strfreev(n->scripts); + g_free(n->stack_tag); - g_free(n->msg); - g_free(n->text_to_render); - g_free(n->urls); + g_free(n->msg); + g_free(n->text_to_render); + g_free(n->urls); - g_free(n); + g_free(n); } -void notification_transfer_icon(struct notification *from, struct notification *to) +void notification_transfer_icon(struct notification *from, + struct notification *to) { - if (from->iconname && to->iconname - && strcmp(from->iconname, to->iconname) == 0){ - // Icons are the same. Transfer icon surface - to->icon = from->icon; - - // prevent the surface being freed by the old notification - from->icon = NULL; - } + if (from->iconname && to->iconname + && strcmp(from->iconname, to->iconname) == 0) { + // Icons are the same. Transfer icon surface + to->icon = from->icon; + + // prevent the surface being freed by the old notification + from->icon = NULL; + } } -void notification_icon_replace_path(struct notification *n, const char *new_icon) +void notification_icon_replace_path(struct notification *n, + const char *new_icon) { - ASSERT_OR_RET(n && n->icon_position != ICON_OFF,); - ASSERT_OR_RET(new_icon,); + ASSERT_OR_RET(n && n->icon_position != ICON_OFF, ); + ASSERT_OR_RET(new_icon, ); - if (n->iconname && n->icon && STR_EQ(n->iconname, new_icon)) - return; + if (n->iconname && n->icon && STR_EQ(n->iconname, new_icon)) + return; - // make sure it works, even if n->iconname is passed as new_icon - if (n->iconname != new_icon) { - g_free(n->iconname); - n->iconname = g_strdup(new_icon); - } - - cairo_surface_destroy(n->icon); - n->icon = NULL; - g_clear_pointer(&n->icon_id, g_free); - - g_free(n->icon_path); - n->icon_path = get_path_from_icon_name(new_icon, n->min_icon_size); - if (n->icon_path) { - GdkPixbuf *pixbuf = get_pixbuf_from_file(n->icon_path, - n->min_icon_size, n->max_icon_size, - draw_get_scale()); - if (pixbuf) { - n->icon = gdk_pixbuf_to_cairo_surface(pixbuf); - g_object_unref(pixbuf); - } else { - LOG_W("Failed to load icon from path: '%s'", n->icon_path); - } + // make sure it works, even if n->iconname is passed as new_icon + if (n->iconname != new_icon) { + g_free(n->iconname); + n->iconname = g_strdup(new_icon); + } + + cairo_surface_destroy(n->icon); + n->icon = NULL; + g_clear_pointer(&n->icon_id, g_free); + + g_free(n->icon_path); + n->icon_path = get_path_from_icon_name(new_icon, n->min_icon_size); + if (n->icon_path) { + GdkPixbuf *pixbuf = get_pixbuf_from_file( + n->icon_path, n->min_icon_size, n->max_icon_size, draw_get_scale()); + if (pixbuf) { + n->icon = gdk_pixbuf_to_cairo_surface(pixbuf); + g_object_unref(pixbuf); + } else { + LOG_W("Failed to load icon from path: '%s'", n->icon_path); } + } } void notification_icon_replace_data(struct notification *n, GVariant *new_icon) { - ASSERT_OR_RET(n && n->icon_position != ICON_OFF,); - ASSERT_OR_RET(new_icon,); - - cairo_surface_destroy(n->icon); - n->icon = NULL; - g_clear_pointer(&n->icon_id, g_free); - - GdkPixbuf *icon = icon_get_for_data(new_icon, &n->icon_id, - draw_get_scale(), n->min_icon_size, n->max_icon_size); - n->icon = gdk_pixbuf_to_cairo_surface(icon); - if (icon) - g_object_unref(icon); + ASSERT_OR_RET(n && n->icon_position != ICON_OFF, ); + ASSERT_OR_RET(new_icon, ); + + cairo_surface_destroy(n->icon); + n->icon = NULL; + g_clear_pointer(&n->icon_id, g_free); + + GdkPixbuf *icon = icon_get_for_data(new_icon, + &n->icon_id, + draw_get_scale(), + n->min_icon_size, + n->max_icon_size); + n->icon = gdk_pixbuf_to_cairo_surface(icon); + if (icon) + g_object_unref(icon); } void notification_replace_format(struct notification *n, const char *format) { - g_free(n->format); - n->format = g_strdup(format); + g_free(n->format); + n->format = g_strdup(format); } /* see notification.h */ @@ -409,398 +421,387 @@ void notification_replace_single_field(char **haystack, enum markup_mode markup_mode) { - assert(*needle[0] == '%'); - // needle has to point into haystack (but not on the last char) - assert(*needle >= *haystack); - assert(*needle - *haystack < strlen(*haystack) - 1); + assert(*needle[0] == '%'); + // needle has to point into haystack (but not on the last char) + assert(*needle >= *haystack); + assert(*needle - *haystack < strlen(*haystack) - 1); - int pos = *needle - *haystack; + int pos = *needle - *haystack; - char *input = markup_transform(g_strdup(replacement), markup_mode); - *haystack = string_replace_at(*haystack, pos, 2, input); + char *input = markup_transform(g_strdup(replacement), markup_mode); + *haystack = string_replace_at(*haystack, pos, 2, input); - // point the needle to the next char - // which was originally in haystack - *needle = *haystack + pos + strlen(input); + // point the needle to the next char + // which was originally in haystack + *needle = *haystack + pos + strlen(input); - g_free(input); + g_free(input); } static NotificationPrivate *notification_private_create(void) { - NotificationPrivate *priv = g_malloc0(sizeof(NotificationPrivate)); - g_atomic_int_set(&priv->refcount, 1); + NotificationPrivate *priv = g_malloc0(sizeof(NotificationPrivate)); + g_atomic_int_set(&priv->refcount, 1); - return priv; + return priv; } /* see notification.h */ struct notification *notification_create(void) { - struct notification *n = g_malloc0(sizeof(struct notification)); + struct notification *n = g_malloc0(sizeof(struct notification)); - n->priv = notification_private_create(); + n->priv = notification_private_create(); - /* Unparameterized default values */ - n->first_render = true; - n->markup = MARKUP_FULL; - n->format = g_strdup(settings.format); + /* Unparameterized default values */ + n->first_render = true; + n->markup = MARKUP_FULL; + n->format = g_strdup(settings.format); - n->timestamp = time_monotonic_now(); + n->timestamp = time_monotonic_now(); - n->urgency = URG_NORM; - n->timeout = -1; - n->dbus_timeout = -1; + n->urgency = URG_NORM; + n->timeout = -1; + n->dbus_timeout = -1; - n->transient = false; - n->progress = -1; - n->word_wrap = true; - n->ellipsize = PANGO_ELLIPSIZE_MIDDLE; - n->alignment = PANGO_ALIGN_LEFT; - n->progress_bar_alignment = PANGO_ALIGN_CENTER; - n->hide_text = false; - n->icon_position = ICON_LEFT; - n->min_icon_size = 32; - n->max_icon_size = 32; - n->receiving_raw_icon = false; - - struct color invalid = COLOR_UNINIT; - n->colors.fg = invalid; - n->colors.bg = invalid; - n->colors.frame = invalid; - n->colors.highlight = NULL; - - n->script_run = false; - n->dbus_valid = false; - - n->fullscreen = FS_SHOW; - - n->original = NULL; - - n->actions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - n->default_action_name = g_strdup("default"); - - n->script_count = 0; - return n; -} + n->transient = false; + n->progress = -1; + n->word_wrap = true; + n->ellipsize = PANGO_ELLIPSIZE_MIDDLE; + n->alignment = PANGO_ALIGN_LEFT; + n->progress_bar_alignment = PANGO_ALIGN_CENTER; + n->hide_text = false; + n->icon_position = ICON_LEFT; + n->min_icon_size = 32; + n->max_icon_size = 32; + n->receiving_raw_icon = false; -/* see notification.h */ -void notification_init(struct notification *n) -{ - /* default to empty string to avoid further NULL faults */ - n->appname = n->appname ? n->appname : g_strdup("unknown"); - n->summary = n->summary ? n->summary : g_strdup(""); - n->body = n->body ? n->body : g_strdup(""); - n->category = n->category ? n->category : g_strdup(""); - - /* sanitize urgency */ - if (n->urgency < URG_MIN) - n->urgency = URG_LOW; - if (n->urgency > URG_MAX) - n->urgency = URG_CRIT; - - /* Timeout processing */ - if (n->timeout < 0) - n->timeout = settings.timeouts[n->urgency]; - - /* Color hints */ - struct notification_colors defcolors; - switch (n->urgency) { - case URG_LOW: - defcolors = settings.colors_low; - break; - case URG_NORM: - defcolors = settings.colors_norm; - break; - case URG_CRIT: - defcolors = settings.colors_crit; - break; - default: - g_error("Unhandled urgency type: %d", n->urgency); - } - if (!COLOR_VALID(n->colors.fg)) n->colors.fg = defcolors.fg; - if (!COLOR_VALID(n->colors.bg)) n->colors.bg = defcolors.bg; - if (!COLOR_VALID(n->colors.frame)) n->colors.frame = defcolors.frame; + struct color invalid = COLOR_UNINIT; + n->colors.fg = invalid; + n->colors.bg = invalid; + n->colors.frame = invalid; + n->colors.highlight = NULL; - if (!GRADIENT_VALID(n->colors.highlight)) { - gradient_release(n->colors.highlight); - n->colors.highlight = gradient_acquire(defcolors.highlight); - } - - /* Sanitize misc hints */ - if (n->progress < 0) - n->progress = -1; + n->script_run = false; + n->dbus_valid = false; - n->override_pause_level = 0; + n->fullscreen = FS_SHOW; - /* Process rules */ - rule_apply_all(n); + n->original = NULL; - if (g_str_has_prefix(n->summary, "DUNST_COMMAND_")) { - const char *msg = "DUNST_COMMAND_* has been removed, please switch to dunstctl. See #830 for more details. https://github.com/dunst-project/dunst/pull/830"; - LOG_W("%s", msg); - n->body = string_append(n->body, msg, "\n"); - } + n->actions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + n->default_action_name = g_strdup("default"); - /* Icon handling */ - if (STR_EMPTY(n->iconname)) - g_clear_pointer(&n->iconname, g_free); - if (!n->icon && !n->iconname && n->default_icon_name) { - n->iconname = g_strdup(n->default_icon_name); - } - if (!n->icon && !n->iconname) - n->iconname = g_strdup(settings.icons[n->urgency]); + n->script_count = 0; + return n; +} - /* UPDATE derived fields */ - notification_extract_urls(n); - notification_format_message(n); +/* see notification.h */ +void notification_init(struct notification *n) +{ + /* default to empty string to avoid further NULL faults */ + n->appname = n->appname ? n->appname : g_strdup("unknown"); + n->summary = n->summary ? n->summary : g_strdup(""); + n->body = n->body ? n->body : g_strdup(""); + n->category = n->category ? n->category : g_strdup(""); + + /* sanitize urgency */ + if (n->urgency < URG_MIN) + n->urgency = URG_LOW; + if (n->urgency > URG_MAX) + n->urgency = URG_CRIT; + + /* Timeout processing */ + if (n->timeout < 0) + n->timeout = settings.timeouts[n->urgency]; + + /* Color hints */ + struct notification_colors defcolors; + switch (n->urgency) { + case URG_LOW: defcolors = settings.colors_low; break; + case URG_NORM: defcolors = settings.colors_norm; break; + case URG_CRIT: defcolors = settings.colors_crit; break; + default: g_error("Unhandled urgency type: %d", n->urgency); + } + if (!COLOR_VALID(n->colors.fg)) + n->colors.fg = defcolors.fg; + if (!COLOR_VALID(n->colors.bg)) + n->colors.bg = defcolors.bg; + if (!COLOR_VALID(n->colors.frame)) + n->colors.frame = defcolors.frame; + + if (!GRADIENT_VALID(n->colors.highlight)) { + gradient_release(n->colors.highlight); + n->colors.highlight = gradient_acquire(defcolors.highlight); + } - /* Update timeout: dbus_timeout has priority over timeout */ - if (n->dbus_timeout >= 0) - n->timeout = n->dbus_timeout; + /* Sanitize misc hints */ + if (n->progress < 0) + n->progress = -1; + n->override_pause_level = 0; + + /* Process rules */ + rule_apply_all(n); + + if (g_str_has_prefix(n->summary, "DUNST_COMMAND_")) { + const char *msg = "DUNST_COMMAND_* has been removed, please switch to " + "dunstctl. See #830 for more details. " + "https://github.com/dunst-project/dunst/pull/830"; + LOG_W("%s", msg); + n->body = string_append(n->body, msg, "\n"); + } + + /* Icon handling */ + if (STR_EMPTY(n->iconname)) + g_clear_pointer(&n->iconname, g_free); + if (!n->icon && !n->iconname && n->default_icon_name) { + n->iconname = g_strdup(n->default_icon_name); + } + if (!n->icon && !n->iconname) + n->iconname = g_strdup(settings.icons[n->urgency]); + + /* UPDATE derived fields */ + notification_extract_urls(n); + notification_format_message(n); + + /* Update timeout: dbus_timeout has priority over timeout */ + if (n->dbus_timeout >= 0) + n->timeout = n->dbus_timeout; } static void notification_format_message(struct notification *n) { - g_clear_pointer(&n->msg, g_free); - - n->msg = string_replace_all("\\n", "\n", g_strdup(n->format)); - - /* replace all formatter */ - for(char *substr = strchr(n->msg, '%'); - substr && *substr; - substr = strchr(substr, '%')) { - - char pg[16]; - char *icon_tmp; - - switch(substr[1]) { - case 'a': - notification_replace_single_field( - &n->msg, - &substr, - n->appname, - MARKUP_NO); - break; - case 's': - notification_replace_single_field( - &n->msg, - &substr, - n->summary, - MARKUP_NO); - break; - case 'b': - notification_replace_single_field( - &n->msg, - &substr, - n->body, - n->markup); - break; - case 'I': - icon_tmp = g_strdup(n->iconname); - notification_replace_single_field( - &n->msg, - &substr, - icon_tmp ? basename(icon_tmp) : "", - MARKUP_NO); - g_free(icon_tmp); - break; - case 'i': - notification_replace_single_field( - &n->msg, - &substr, - n->iconname ? n->iconname : "", - MARKUP_NO); - break; - case 'p': - if (n->progress != -1) - sprintf(pg, "[%3d%%]", n->progress); - - notification_replace_single_field( - &n->msg, - &substr, - n->progress != -1 ? pg : "", - MARKUP_NO); - break; - case 'n': - if (n->progress != -1) - sprintf(pg, "%d", n->progress); - - notification_replace_single_field( - &n->msg, - &substr, - n->progress != -1 ? pg : "", - MARKUP_NO); - break; - case '%': - notification_replace_single_field( - &n->msg, - &substr, - "%", - MARKUP_NO); - break; - case '\0': - LOG_W("format_string has trailing %% character. " - "To escape it use %%%%."); - substr++; - break; - default: - LOG_W("format_string %%%c is unknown.", substr[1]); - // shift substr pointer forward, - // as we can't interpret the format string - substr++; - break; - } + g_clear_pointer(&n->msg, g_free); + + n->msg = string_replace_all("\\n", "\n", g_strdup(n->format)); + + /* replace all formatter */ + for (char *substr = strchr(n->msg, '%'); substr && *substr; + substr = strchr(substr, '%')) { + + char pg[16]; + char *icon_tmp; + + switch (substr[1]) { + case 'a': + notification_replace_single_field( + &n->msg, &substr, n->appname, MARKUP_NO); + break; + case 's': + notification_replace_single_field( + &n->msg, &substr, n->summary, MARKUP_NO); + break; + case 'b': + notification_replace_single_field( + &n->msg, &substr, n->body, n->markup); + break; + case 'I': + icon_tmp = g_strdup(n->iconname); + notification_replace_single_field(&n->msg, + &substr, + icon_tmp ? basename(icon_tmp) + : "", + MARKUP_NO); + g_free(icon_tmp); + break; + case 'i': + notification_replace_single_field( + &n->msg, &substr, n->iconname ? n->iconname : "", MARKUP_NO); + break; + case 'p': + if (n->progress != -1) + sprintf(pg, "[%3d%%]", n->progress); + + notification_replace_single_field( + &n->msg, &substr, n->progress != -1 ? pg : "", MARKUP_NO); + break; + case 'n': + if (n->progress != -1) + sprintf(pg, "%d", n->progress); + + notification_replace_single_field( + &n->msg, &substr, n->progress != -1 ? pg : "", MARKUP_NO); + break; + case '%': + notification_replace_single_field(&n->msg, &substr, "%", MARKUP_NO); + break; + case '\0': + LOG_W("format_string has trailing %% character. " + "To escape it use %%%%."); + substr++; + break; + default: + LOG_W("format_string %%%c is unknown.", substr[1]); + // shift substr pointer forward, + // as we can't interpret the format string + substr++; + break; } + } - n->msg = g_strchomp(n->msg); + n->msg = g_strchomp(n->msg); - /* truncate overlong messages */ - if (strnlen(n->msg, DUNST_NOTIF_MAX_CHARS + 1) > DUNST_NOTIF_MAX_CHARS) { - char * buffer = g_strndup(n->msg, DUNST_NOTIF_MAX_CHARS); - g_free(n->msg); - n->msg = buffer; - } + /* truncate overlong messages */ + if (strnlen(n->msg, DUNST_NOTIF_MAX_CHARS + 1) > DUNST_NOTIF_MAX_CHARS) { + char *buffer = g_strndup(n->msg, DUNST_NOTIF_MAX_CHARS); + g_free(n->msg); + n->msg = buffer; + } } static void notification_extract_urls(struct notification *n) { - g_clear_pointer(&n->urls, g_free); - - char *urls_in = string_append(g_strdup(n->summary), n->body, " "); - - char *urls_a = NULL; - char *urls_img = NULL; - markup_strip_a(&urls_in, &urls_a); - markup_strip_img(&urls_in, &urls_img); - // remove links and images first to not confuse - // plain urls extraction - char *urls_text = extract_urls(urls_in); - - n->urls = string_append(n->urls, urls_a, "\n"); - n->urls = string_append(n->urls, urls_img, "\n"); - n->urls = string_append(n->urls, urls_text, "\n"); - - g_free(urls_in); - g_free(urls_a); - g_free(urls_img); - g_free(urls_text); + g_clear_pointer(&n->urls, g_free); + + char *urls_in = string_append(g_strdup(n->summary), n->body, " "); + + char *urls_a = NULL; + char *urls_img = NULL; + markup_strip_a(&urls_in, &urls_a); + markup_strip_img(&urls_in, &urls_img); + // remove links and images first to not confuse + // plain urls extraction + char *urls_text = extract_urls(urls_in); + + n->urls = string_append(n->urls, urls_a, "\n"); + n->urls = string_append(n->urls, urls_img, "\n"); + n->urls = string_append(n->urls, urls_text, "\n"); + + g_free(urls_in); + g_free(urls_a); + g_free(urls_img); + g_free(urls_text); } - void notification_update_text_to_render(struct notification *n) { - g_clear_pointer(&n->text_to_render, g_free); - - char *buf = NULL; - - char *msg = g_strchomp(n->msg); - - /* print dup_count and msg */ - if ((n->dup_count > 0 && !settings.hide_duplicate_count) - && (g_hash_table_size(n->actions) || n->urls) && settings.show_indicators) { - buf = g_strdup_printf("(%d%s%s) %s", - n->dup_count, - g_hash_table_size(n->actions) ? "A" : "", - n->urls ? "U" : "", msg); - } else if ((g_hash_table_size(n->actions) || n->urls) && settings.show_indicators) { - buf = g_strdup_printf("(%s%s) %s", - g_hash_table_size(n->actions) ? "A" : "", - n->urls ? "U" : "", msg); - } else if (n->dup_count > 0 && !settings.hide_duplicate_count) { - buf = g_strdup_printf("(%d) %s", n->dup_count, msg); + g_clear_pointer(&n->text_to_render, g_free); + + char *buf = NULL; + + char *msg = g_strchomp(n->msg); + + /* print dup_count and msg */ + if ((n->dup_count > 0 && !settings.hide_duplicate_count) + && (g_hash_table_size(n->actions) || n->urls) + && settings.show_indicators) { + buf = g_strdup_printf("(%d%s%s) %s", + n->dup_count, + g_hash_table_size(n->actions) ? "A" : "", + n->urls ? "U" : "", + msg); + } else if ((g_hash_table_size(n->actions) || n->urls) + && settings.show_indicators) { + buf = g_strdup_printf("(%s%s) %s", + g_hash_table_size(n->actions) ? "A" : "", + n->urls ? "U" : "", + msg); + } else if (n->dup_count > 0 && !settings.hide_duplicate_count) { + buf = g_strdup_printf("(%d) %s", n->dup_count, msg); + } else { + buf = g_strdup(msg); + } + + /* print age */ + gint64 hours, minutes, seconds; + // Timestamp is floored to the second for display purposes -- see queues.c + gint64 t_delta = + time_monotonic_now() - (n->timestamp - n->timestamp % S2US(1)); + + if (settings.show_age_threshold >= 0 + && t_delta >= settings.show_age_threshold) { + hours = US2S(t_delta) / 3600; + minutes = US2S(t_delta) / 60 % 60; + seconds = US2S(t_delta) % 60; + + char *new_buf; + if (hours > 0) { + new_buf = + g_strdup_printf("%s (%" G_GINT64_FORMAT "h %" G_GINT64_FORMAT + "m %" G_GINT64_FORMAT "s old)", + buf, + hours, + minutes, + seconds); + } else if (minutes > 0) { + new_buf = g_strdup_printf("%s (%" G_GINT64_FORMAT + "m %" G_GINT64_FORMAT "s old)", + buf, + minutes, + seconds); } else { - buf = g_strdup(msg); + new_buf = + g_strdup_printf("%s (%" G_GINT64_FORMAT "s old)", buf, seconds); } - /* print age */ - gint64 hours, minutes, seconds; - // Timestamp is floored to the second for display purposes -- see queues.c - gint64 t_delta = time_monotonic_now() - (n->timestamp - n->timestamp % S2US(1)); - - if (settings.show_age_threshold >= 0 - && t_delta >= settings.show_age_threshold) { - hours = US2S(t_delta) / 3600; - minutes = US2S(t_delta) / 60 % 60; - seconds = US2S(t_delta) % 60; - - char *new_buf; - if (hours > 0) { - new_buf = g_strdup_printf("%s (%"G_GINT64_FORMAT"h %"G_GINT64_FORMAT"m %"G_GINT64_FORMAT"s old)", - buf, hours, minutes, seconds); - } else if (minutes > 0) { - new_buf = g_strdup_printf("%s (%"G_GINT64_FORMAT"m %"G_GINT64_FORMAT"s old)", - buf, minutes, seconds); - } else { - new_buf = g_strdup_printf("%s (%"G_GINT64_FORMAT"s old)", - buf, seconds); - } - - g_free(buf); - buf = new_buf; - } + g_free(buf); + buf = new_buf; + } - n->text_to_render = buf; + n->text_to_render = buf; } /* see notification.h */ void notification_do_action(struct notification *n) { - assert(n->default_action_name); - - if (g_hash_table_size(n->actions)) { - if (g_hash_table_contains(n->actions, n->default_action_name)) { - signal_action_invoked(n, n->default_action_name); - return; - } - if (strcmp(n->default_action_name, "default") == 0 && g_hash_table_size(n->actions) == 1) { - GList *keys = g_hash_table_get_keys(n->actions); - signal_action_invoked(n, keys->data); - g_list_free(keys); - return; - } - notification_open_context_menu(n); - - } else if (n->urls) { - // Try urls otherwise - notification_open_url(n); + assert(n->default_action_name); + + if (g_hash_table_size(n->actions)) { + if (g_hash_table_contains(n->actions, n->default_action_name)) { + signal_action_invoked(n, n->default_action_name); + return; } + if (strcmp(n->default_action_name, "default") == 0 + && g_hash_table_size(n->actions) == 1) { + GList *keys = g_hash_table_get_keys(n->actions); + signal_action_invoked(n, keys->data); + g_list_free(keys); + return; + } + notification_open_context_menu(n); + + } else if (n->urls) { + // Try urls otherwise + notification_open_url(n); + } } /* see notification.h */ void notification_open_url(struct notification *n) { - if (!n->urls) { - LOG_W("There are no URL's in this notification"); - return; - } - if (strstr(n->urls, "\n")) - notification_open_context_menu(n); - else - open_browser(n->urls); + if (!n->urls) { + LOG_W("There are no URL's in this notification"); + return; + } + if (strstr(n->urls, "\n")) + notification_open_context_menu(n); + else + open_browser(n->urls); } /* see notification.h */ void notification_open_context_menu(struct notification *n) { - GList *notifications = NULL; - notifications = g_list_append(notifications, n); - notification_lock(n); + GList *notifications = NULL; + notifications = g_list_append(notifications, n); + notification_lock(n); - context_menu_for(notifications); + context_menu_for(notifications); } -void notification_invalidate_actions(struct notification *n) { - g_hash_table_remove_all(n->actions); +void notification_invalidate_actions(struct notification *n) +{ + g_hash_table_remove_all(n->actions); } void notification_keep_original(struct notification *n) { - if (n->original) return; - n->original = g_malloc0(sizeof(struct rule)); - *n->original = empty_rule; - n->original->name = g_strdup("original"); + if (n->original) + return; + n->original = g_malloc0(sizeof(struct rule)); + *n->original = empty_rule; + n->original->name = g_strdup("original"); } /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/notification.h b/src/notification.h index 7d2f0d68a..56fcf2956 100644 --- a/src/notification.h +++ b/src/notification.h @@ -1,120 +1,138 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ #ifndef DUNST_NOTIFICATION_H #define DUNST_NOTIFICATION_H +#include #include -#include #include -#include +#include -#include "markup.h" #include "draw.h" +#include "markup.h" #define DUNST_NOTIF_MAX_CHARS 50000 -enum icon_position { - ICON_LEFT, - ICON_RIGHT, - ICON_TOP, - ICON_OFF +enum icon_position +{ + ICON_LEFT, + ICON_RIGHT, + ICON_TOP, + ICON_OFF }; -enum behavior_fullscreen { - FS_NULL, //!< Invalid value - FS_DELAY, //!< Delay the notification until leaving fullscreen mode - FS_PUSHBACK, //!< When entering fullscreen mode, push the notification back to waiting - FS_SHOW, //!< Show the message when in fullscreen mode +enum behavior_fullscreen +{ + FS_NULL, //!< Invalid value + FS_DELAY, //!< Delay the notification until leaving fullscreen mode + FS_PUSHBACK, //!< When entering fullscreen mode, push the notification back + //!< to waiting + FS_SHOW, //!< Show the message when in fullscreen mode }; /// Representing the urgencies according to the notification spec -enum urgency { - URG_NONE = -1, /**< Urgency not set (invalid) */ - URG_MIN = 0, /**< Minimum value, useful for boundary checking */ - URG_LOW = 0, /**< Low urgency */ - URG_NORM = 1, /**< Normal urgency */ - URG_CRIT = 2, /**< Critical urgency */ - URG_MAX = 2, /**< Maximum value, useful for boundary checking */ +enum urgency +{ + URG_NONE = -1, /**< Urgency not set (invalid) */ + URG_MIN = 0, /**< Minimum value, useful for boundary checking */ + URG_LOW = 0, /**< Low urgency */ + URG_NORM = 1, /**< Normal urgency */ + URG_CRIT = 2, /**< Critical urgency */ + URG_MAX = 2, /**< Maximum value, useful for boundary checking */ }; typedef struct _notification_private NotificationPrivate; -struct notification_colors { - struct color frame; - struct color bg; - struct color fg; - struct gradient *highlight; +struct notification_colors +{ + struct color frame; + struct color bg; + struct color fg; + struct gradient *highlight; }; -struct notification { - NotificationPrivate *priv; - gint id; - char *dbus_client; - bool dbus_valid; - - // We keep the original notification properties here when it is modified - struct rule *original; - - char *appname; - char *summary; - char *body; - char *category; - char *desktop_entry; /**< The desktop entry hint sent via every GApplication */ - enum urgency urgency; - int override_pause_level; - - cairo_surface_t *icon; /**< The raw cached icon data used to draw */ - char *icon_id; /**< Plain icon information, which acts as the icon's id. - May be a hash for a raw icon or a name/path for a regular app icon. */ - char *iconname; /**< plain icon information (may be a path or just a name) as recieved from dbus. - Use this to compare the icon name with rules. May also be modified by rules.*/ - char *icon_path; /**< Full path to the notification's icon. */ - char *default_icon_name; /**< The icon that is used when no other icon is available. */ - int min_icon_size; /**< Minimum icon size. Also used for looking up icon names. */ - int max_icon_size; /**< Maximum icon size. */ - enum icon_position icon_position; /**< Icon position (enum left,right,top,off). */ - bool receiving_raw_icon; /**< Still waiting for raw icon to be received */ - - gint64 start; /**< begin of current display (in milliseconds) */ - gint64 timestamp; /**< arrival time (in milliseconds) */ - gint64 timeout; /**< time to display (in milliseconds) */ - gint64 dbus_timeout; /**< time to display (in milliseconds) (set by dbus) */ - int locked; /**< If non-zero the notification is locked **/ - PangoAlignment progress_bar_alignment; /**< Horizontal alignment of the progress bar **/ - - GHashTable *actions; - char *default_action_name; /**< The name of the action to be invoked on do_action */ - - enum markup_mode markup; - char *format; - char **scripts; - int script_count; - struct notification_colors colors; - - char *stack_tag; /**< stack notifications by tag */ - - /* Hints */ - bool transient; /**< timeout albeit user is idle */ - int progress; /**< percentage (-1: undefined) */ - int history_ignore; /**< push to history or free directly */ - int skip_display; /**< insert notification into history, skipping initial waiting and display */ - - /* internal */ - bool redisplayed; /**< has been displayed before? */ - bool first_render; /**< markup has been rendered before? */ - int dup_count; /**< amount of duplicate notifications stacked onto this */ - int displayed_height; - enum behavior_fullscreen fullscreen; //!< The instruction what to do with it, when desktop enters fullscreen - bool script_run; /**< Has the script been executed already? */ - guint8 marked_for_closure; - bool word_wrap; - PangoEllipsizeMode ellipsize; - PangoAlignment alignment; - bool hide_text; - - /* derived fields */ - char *msg; /**< formatted message */ - char *text_to_render; /**< formatted message (with age and action indicators) */ - char *urls; /**< urllist delimited by '\\n' */ +struct notification +{ + NotificationPrivate *priv; + gint id; + char *dbus_client; + bool dbus_valid; + + // We keep the original notification properties here when it is modified + struct rule *original; + + char *appname; + char *summary; + char *body; + char *category; + char *desktop_entry; /**< The desktop entry hint sent via every GApplication + */ + enum urgency urgency; + int override_pause_level; + + cairo_surface_t *icon; /**< The raw cached icon data used to draw */ + char *icon_id; /**< Plain icon information, which acts as the icon's id. + May be a hash for a raw icon or a name/path for a + regular app icon. */ + char *iconname; /**< plain icon information (may be a path or just a name) + as recieved from dbus. Use this to compare the icon name + with rules. May also be modified by rules.*/ + char *icon_path; /**< Full path to the notification's icon. */ + char *default_icon_name; /**< The icon that is used when no other icon is + available. */ + int min_icon_size; /**< Minimum icon size. Also used for looking up icon + names. */ + int max_icon_size; /**< Maximum icon size. */ + enum icon_position + icon_position; /**< Icon position (enum left,right,top,off). */ + bool receiving_raw_icon; /**< Still waiting for raw icon to be received */ + + gint64 start; /**< begin of current display (in milliseconds) */ + gint64 timestamp; /**< arrival time (in milliseconds) */ + gint64 timeout; /**< time to display (in milliseconds) */ + gint64 dbus_timeout; /**< time to display (in milliseconds) (set by dbus) */ + int locked; /**< If non-zero the notification is locked **/ + PangoAlignment progress_bar_alignment; /**< Horizontal alignment of the + progress bar **/ + + GHashTable *actions; + char *default_action_name; /**< The name of the action to be invoked on + do_action */ + + enum markup_mode markup; + char *format; + char **scripts; + int script_count; + struct notification_colors colors; + + char *stack_tag; /**< stack notifications by tag */ + + /* Hints */ + bool transient; /**< timeout albeit user is idle */ + int progress; /**< percentage (-1: undefined) */ + int history_ignore; /**< push to history or free directly */ + int skip_display; /**< insert notification into history, skipping initial + waiting and display */ + + /* internal */ + bool redisplayed; /**< has been displayed before? */ + bool first_render; /**< markup has been rendered before? */ + int dup_count; /**< amount of duplicate notifications stacked onto this */ + int displayed_height; + enum behavior_fullscreen fullscreen; //!< The instruction what to do with + //!< it, when desktop enters fullscreen + bool script_run; /**< Has the script been executed already? */ + guint8 marked_for_closure; + bool word_wrap; + PangoEllipsizeMode ellipsize; + PangoAlignment alignment; + bool hide_text; + + /* derived fields */ + char *msg; /**< formatted message */ + char *text_to_render; /**< formatted message (with age and action + indicators) */ + char *urls; /**< urllist delimited by '\\n' */ }; /** @@ -157,7 +175,8 @@ void notification_unref(struct notification *n); /** * Helper function to compare two given notifications. */ -int notification_cmp(const struct notification *a, const struct notification *b); +int notification_cmp(const struct notification *a, + const struct notification *b); /** * Wrapper for notification_cmp to match glib's @@ -165,7 +184,8 @@ int notification_cmp(const struct notification *a, const struct notification *b) */ int notification_cmp_data(const void *va, const void *vb, void *data); -bool notification_is_duplicate(const struct notification *a, const struct notification *b); +bool notification_is_duplicate(const struct notification *a, + const struct notification *b); bool notification_is_locked(struct notification *n); @@ -181,24 +201,29 @@ struct notification *notification_unlock(struct notification *n); * @param from The notification of which the icon surface is removed. * @param to The notification that receives the icon surface. */ -void notification_transfer_icon(struct notification *from, struct notification *to); +void notification_transfer_icon(struct notification *from, + struct notification *to); /**Replace the current notification's icon with the icon specified by path. * - * Removes the reference for the previous icon automatically and will also free the - * iconname field. So passing n->iconname as new_icon is invalid. + * Removes the reference for the previous icon automatically and will also free + * the iconname field. So passing n->iconname as new_icon is invalid. * * @param n the notification to replace the icon - * @param new_icon The path of the new icon. May be an absolute path or an icon name. + * @param new_icon The path of the new icon. May be an absolute path or an icon + * name. */ -void notification_icon_replace_path(struct notification *n, const char *new_icon); +void notification_icon_replace_path(struct notification *n, + const char *new_icon); -/**Replace the current notification's icon with the raw icon given in the GVariant. +/**Replace the current notification's icon with the raw icon given in the + * GVariant. * * Removes the reference for the previous icon automatically. * * @param n the notification to replace the icon - * @param new_icon The icon's data. Has to be in the format of the notification spec. + * @param new_icon The icon's data. Has to be in the format of the notification + * spec. */ void notification_icon_replace_data(struct notification *n, GVariant *new_icon); @@ -233,9 +258,10 @@ void notification_replace_single_field(char **haystack, void notification_update_text_to_render(struct notification *n); /** - * If the notification has an action named n->default_action_name or there is only one - * action and n->default_action_name is set to "default", invoke it. If there is no - * such action, open the context menu if threre are other actions. Otherwise, do nothing. + * If the notification has an action named n->default_action_name or there is + * only one action and n->default_action_name is set to "default", invoke it. If + * there is no such action, open the context menu if threre are other actions. + * Otherwise, do nothing. */ void notification_do_action(struct notification *n); @@ -248,7 +274,8 @@ void notification_open_url(struct notification *n); /** * Open the context menu for the notification. * - * Convenience function that creates the GList and passes it to context_menu_for(). + * Convenience function that creates the GList and passes it to + * context_menu_for(). */ void notification_open_context_menu(struct notification *n); diff --git a/src/option_parser.c b/src/option_parser.c index 519eec05f..abf4c181b 100644 --- a/src/option_parser.c +++ b/src/option_parser.c @@ -1,37 +1,46 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ #include "option_parser.h" +#include #include #include #include #include #include -#include #include "dunst.h" #include "log.h" -#include "utils.h" -#include "settings.h" #include "rules.h" +#include "settings.h" #include "settings_data.h" +#include "utils.h" static int cmdline_argc; static char **cmdline_argv; static char *usage_str = NULL; -#define STRING_PARSE_RET(string, value) if (STR_EQ(s, string)) { *ret = value; return true; } +#define STRING_PARSE_RET(string, value) \ + if (STR_EQ(s, string)) { \ + *ret = value; \ + return true; \ + } -int string_parse_enum(const void *data, const char *s, void * ret) { - struct string_to_enum_def *string_to_enum = (struct string_to_enum_def*)data; - for (int i = 0; string_to_enum[i].string != NULL; i++) { - if (strcmp(s, string_to_enum[i].string) == 0) { - *(int*) ret = string_to_enum[i].enum_value; - LOG_D("Setting enum to %i (%s)", *(int*) ret, string_to_enum[i].string); - return true; - } +int string_parse_enum(const void *data, const char *s, void *ret) +{ + struct string_to_enum_def *string_to_enum = + (struct string_to_enum_def *)data; + for (int i = 0; string_to_enum[i].string != NULL; i++) { + if (strcmp(s, string_to_enum[i].string) == 0) { + *(int *)ret = string_to_enum[i].enum_value; + LOG_D("Setting enum to %i (%s)", + *(int *)ret, + string_to_enum[i].string); + return true; } - return false; + } + return false; } // Only changes the return when succesful @@ -39,25 +48,25 @@ int string_parse_enum(const void *data, const char *s, void * ret) { // @returns True for success, false otherwise. int string_parse_enum_list(const void *data, char **s, void *ret_void) { - int **ret = (int **) ret_void; - int *tmp; - ASSERT_OR_RET(s, false); - ASSERT_OR_RET(ret, false); - - int len = string_array_length(s); - - tmp = g_malloc_n((len + 1), sizeof(int)); - for (int i = 0; i < len; i++) { - if (!string_parse_enum(data, s[i], tmp + i)) { - LOG_W("Unknown mouse action value: '%s'", s[i]); - g_free(tmp); - return false; - } + int **ret = (int **)ret_void; + int *tmp; + ASSERT_OR_RET(s, false); + ASSERT_OR_RET(ret, false); + + int len = string_array_length(s); + + tmp = g_malloc_n((len + 1), sizeof(int)); + for (int i = 0; i < len; i++) { + if (!string_parse_enum(data, s[i], tmp + i)) { + LOG_W("Unknown mouse action value: '%s'", s[i]); + g_free(tmp); + return false; } - tmp[len] = MOUSE_ACTION_END; // sentinel end value - g_free(*ret); - *ret = tmp; - return true; + } + tmp[len] = MOUSE_ACTION_END; // sentinel end value + g_free(*ret); + *ret = tmp; + return true; } // Parse a string list of enum values and return a single integer with the @@ -69,121 +78,121 @@ int string_parse_enum_list(const void *data, char **s, void *ret_void) // @returns True for success, false otherwise. int string_parse_enum_list_to_single(const void *data, char **s, int *ret) { - int tmp = 0, tmp_ret = 0; - ASSERT_OR_RET(s, false); - ASSERT_OR_RET(ret, false); - - int len = string_array_length(s); - for (int i = 0; i < len; i++) { - if (!string_parse_enum(data, s[i], &tmp)) { - LOG_W("Unknown value: '%s'", s[i]); - return false; - } - tmp_ret |= tmp; + int tmp = 0, tmp_ret = 0; + ASSERT_OR_RET(s, false); + ASSERT_OR_RET(ret, false); + + int len = string_array_length(s); + for (int i = 0; i < len; i++) { + if (!string_parse_enum(data, s[i], &tmp)) { + LOG_W("Unknown value: '%s'", s[i]); + return false; } - *ret = tmp_ret; - return true; + tmp_ret |= tmp; + } + *ret = tmp_ret; + return true; } int string_parse_corners(const void *data, const char *s, void *ret) { - char **s_arr = string_to_array(s, ","); - int success = string_parse_enum_list_to_single(data, s_arr, ret); - g_strfreev(s_arr); - return success; + char **s_arr = string_to_array(s, ","); + int success = string_parse_enum_list_to_single(data, s_arr, ret); + g_strfreev(s_arr); + return success; } // When allow empty is true, empty strings are interpreted as -1 -bool string_parse_int_list(char **s, int **ret, bool allow_empty) { - int len = string_array_length(s); - ASSERT_OR_RET(s, false); - - int *tmp = g_malloc_n((len + 1), sizeof(int)); - for (int i = 0; i < len; i++) { - if (allow_empty && STR_EMPTY(s[i])) { - tmp[i] = -1; - continue; - } - bool success = safe_string_to_int(&tmp[i], s[i]); - if (!success) { - LOG_W("Invalid int value: '%s'", s[i]); - g_free(tmp); - return false; - } - +bool string_parse_int_list(char **s, int **ret, bool allow_empty) +{ + int len = string_array_length(s); + ASSERT_OR_RET(s, false); + + int *tmp = g_malloc_n((len + 1), sizeof(int)); + for (int i = 0; i < len; i++) { + if (allow_empty && STR_EMPTY(s[i])) { + tmp[i] = -1; + continue; } + bool success = safe_string_to_int(&tmp[i], s[i]); + if (!success) { + LOG_W("Invalid int value: '%s'", s[i]); + g_free(tmp); + return false; + } + } - tmp[len] = LIST_END; - g_free(*ret); - *ret = tmp; - return true; + tmp[len] = LIST_END; + g_free(*ret); + *ret = tmp; + return true; } // Only changes the return when succesful -int string_parse_list(const void *data, const char *s, void *ret) { - const enum list_type type = GPOINTER_TO_INT(data); - char **arr = NULL; - int success = false; - switch (type) { - case MOUSE_LIST: - arr = string_to_array(s, ","); - success = string_parse_enum_list(&mouse_action_enum_data, arr, ret); - break; - case OFFSET_LIST: - arr = string_to_array(s, "x"); - int len = string_array_length(arr); - if (len != 2) { - success = false; - break; - } - int *int_arr = NULL; - success = string_parse_int_list(arr, &int_arr, false); - if (!success) - break; - - struct position* offset = (struct position*) ret; - offset->x = int_arr[0]; - offset->y = int_arr[1]; - g_free(int_arr); - break; - case STRING_LIST: ; - g_strfreev(*(char ***) ret); - *(char ***) ret = string_to_array(s, ","); - success = true; - break; - - default: - LOG_W("Don't know this list type: %i", type); - break; +int string_parse_list(const void *data, const char *s, void *ret) +{ + const enum list_type type = GPOINTER_TO_INT(data); + char **arr = NULL; + int success = false; + switch (type) { + case MOUSE_LIST: + arr = string_to_array(s, ","); + success = string_parse_enum_list(&mouse_action_enum_data, arr, ret); + break; + case OFFSET_LIST: + arr = string_to_array(s, "x"); + int len = string_array_length(arr); + if (len != 2) { + success = false; + break; } - g_strfreev(arr); - return success; + int *int_arr = NULL; + success = string_parse_int_list(arr, &int_arr, false); + if (!success) + break; + + struct position *offset = (struct position *)ret; + offset->x = int_arr[0]; + offset->y = int_arr[1]; + g_free(int_arr); + break; + case STRING_LIST:; + g_strfreev(*(char ***)ret); + *(char ***)ret = string_to_array(s, ","); + success = true; + break; + + default: LOG_W("Don't know this list type: %i", type); break; + } + g_strfreev(arr); + return success; } int string_parse_sepcolor(const void *data, const char *s, void *ret) { - LOG_D("parsing sep_color"); - struct separator_color_data *sep_color = (struct separator_color_data*) ret; - struct color invalid = COLOR_UNINIT; - - enum separator_color type; - bool is_enum = string_parse_enum(data, s, &type); - if (is_enum) { - sep_color->type = type; - sep_color->color = invalid; - return true; - } else { - if (STR_EMPTY(s)) { - LOG_W("Sep color is empty, make sure to quote the value if it's a color."); - return false; - } + LOG_D("parsing sep_color"); + struct separator_color_data *sep_color = (struct separator_color_data *)ret; + struct color invalid = COLOR_UNINIT; + + enum separator_color type; + bool is_enum = string_parse_enum(data, s, &type); + if (is_enum) { + sep_color->type = type; + sep_color->color = invalid; + return true; + } else { + if (STR_EMPTY(s)) { + LOG_W("Sep color is empty, make sure to quote the value if it's a " + "color."); + return false; + } - if (string_parse_color(s, &sep_color->color)) { - sep_color->type = SEP_CUSTOM; - return true; - } + if (string_parse_color(s, &sep_color->color)) { + sep_color->type = SEP_CUSTOM; + return true; } - return false; + } + return false; } #define UINT_MAX_N(bits) ((1 << bits) - 1) @@ -191,534 +200,561 @@ int string_parse_sepcolor(const void *data, const char *s, void *ret) // Parse a #RRGGBB[AA] string int string_parse_color(const char *s, struct color *ret) { - if (STR_EMPTY(s) || *s != '#') { - LOG_W("A color string should start with '#' and contain at least 3 hex characters"); - return false; - } + if (STR_EMPTY(s) || *s != '#') { + LOG_W("A color string should start with '#' and contain at least 3 hex " + "characters"); + return false; + } - char *end = NULL; - unsigned long val = strtoul(s + 1, &end, 16); + char *end = NULL; + unsigned long val = strtoul(s + 1, &end, 16); - if (end[0] != '\0' && end[1] != '\0') { - LOG_W("Invalid color string: '%s'", s); - return false; - } + if (end[0] != '\0' && end[1] != '\0') { + LOG_W("Invalid color string: '%s'", s); + return false; + } - int bpc = 0; - switch (end - (s + 1)) { - case 3: - bpc = 4; - val = (val << 4) | 0xF; - break; - case 6: - bpc = 8; - val = (val << 8) | 0xFF; - break; - case 4: - bpc = 4; - break; - case 8: - bpc = 8; - break; - default: - LOG_W("Invalid color string: '%s'", s); - return false; - } + int bpc = 0; + switch (end - (s + 1)) { + case 3: + bpc = 4; + val = (val << 4) | 0xF; + break; + case 6: + bpc = 8; + val = (val << 8) | 0xFF; + break; + case 4: bpc = 4; break; + case 8: bpc = 8; break; + default: LOG_W("Invalid color string: '%s'", s); return false; + } - const unsigned single_max = UINT_MAX_N(bpc); + const unsigned single_max = UINT_MAX_N(bpc); - ret->r = ((val >> 3 * bpc) & single_max) / (double)single_max; - ret->g = ((val >> 2 * bpc) & single_max) / (double)single_max; - ret->b = ((val >> 1 * bpc) & single_max) / (double)single_max; - ret->a = ((val) & single_max) / (double)single_max; + ret->r = ((val >> 3 * bpc) & single_max) / (double)single_max; + ret->g = ((val >> 2 * bpc) & single_max) / (double)single_max; + ret->b = ((val >> 1 * bpc) & single_max) / (double)single_max; + ret->a = ((val)&single_max) / (double)single_max; - return true; + return true; } int string_parse_gradient(const char *s, struct gradient **ret) { - struct color colors[16]; - size_t length = 0; - - gchar **strs = g_strsplit(s, ",", -1); - for (int i = 0; strs[i] != NULL; i++) { - if (i > 16) { - LOG_W("Do you really need so many colors? ;)"); - break; - } - - if (!string_parse_color(g_strstrip(strs[i]), &colors[length++])) { - g_strfreev(strs); - return false; - } + struct color colors[16]; + size_t length = 0; + + gchar **strs = g_strsplit(s, ",", -1); + for (int i = 0; strs[i] != NULL; i++) { + if (i > 16) { + LOG_W("Do you really need so many colors? ;)"); + break; } - g_strfreev(strs); - if (length == 0) { - LOG_W("Provide at least one color"); - return false; + if (!string_parse_color(g_strstrip(strs[i]), &colors[length++])) { + g_strfreev(strs); + return false; } + } - *ret = gradient_alloc(length); - memcpy((*ret)->colors, colors, length * sizeof(struct color)); - gradient_pattern(*ret); + g_strfreev(strs); + if (length == 0) { + LOG_W("Provide at least one color"); + return false; + } - return true; + *ret = gradient_alloc(length); + memcpy((*ret)->colors, colors, length * sizeof(struct color)); + gradient_pattern(*ret); + + return true; } int string_parse_bool(const void *data, const char *s, void *ret) { - // this is needed, since string_parse_enum assumses a - // variable of size int is passed - int tmp_int = -1; - bool success = string_parse_enum(data, s, &tmp_int); + // this is needed, since string_parse_enum assumses a + // variable of size int is passed + int tmp_int = -1; + bool success = string_parse_enum(data, s, &tmp_int); - *(bool*) ret = (bool) tmp_int; - return success; + *(bool *)ret = (bool)tmp_int; + return success; } // Parse a string that may represent an integer value int string_parse_maybe_int(const void *data, const char *s, void *ret) { - int *intval = (int *)data; - if (!safe_string_to_int(intval, s)) { - *intval = INT_MIN; - } + int *intval = (int *)data; + if (!safe_string_to_int(intval, s)) { + *intval = INT_MIN; + } - g_free(*(char**) ret); - *(char**) ret = g_strdup(s); - return true; + g_free(*(char **)ret); + *(char **)ret = g_strdup(s); + return true; } -int get_setting_id(const char *key, const char *section) { - int error_code = 0; - int partial_match_id = -1; - bool match_section = section && is_special_section(section); - if (!match_section) { - LOG_D("not matching section %s", section); - } - for (size_t i = 0; i < G_N_ELEMENTS(allowed_settings); i++) { - if (strcmp(allowed_settings[i].name, key) == 0) { - bool is_rule = allowed_settings[i].rule_offset > 0; - - // a rule matches every section - if (is_rule || strcmp(section, allowed_settings[i].section) == 0) { - return i; - } else { - // name matches, but in wrong section. Continueing to see - // if we find the same setting name with another section - error_code = -2; - partial_match_id = i; - continue; - } - } +int get_setting_id(const char *key, const char *section) +{ + int error_code = 0; + int partial_match_id = -1; + bool match_section = section && is_special_section(section); + if (!match_section) { + LOG_D("not matching section %s", section); + } + for (size_t i = 0; i < G_N_ELEMENTS(allowed_settings); i++) { + if (strcmp(allowed_settings[i].name, key) == 0) { + bool is_rule = allowed_settings[i].rule_offset > 0; + + // a rule matches every section + if (is_rule || strcmp(section, allowed_settings[i].section) == 0) { + return i; + } else { + // name matches, but in wrong section. Continueing to see + // if we find the same setting name with another section + error_code = -2; + partial_match_id = i; + continue; + } } + } - if (error_code == -2) { - LOG_W("Setting %s is in the wrong section (%s, should be %s)", - key, section, - allowed_settings[partial_match_id].section); - // found, but in wrong section - return -2; - } + if (error_code == -2) { + LOG_W("Setting %s is in the wrong section (%s, should be %s)", + key, + section, + allowed_settings[partial_match_id].section); + // found, but in wrong section + return -2; + } - // not found - return -1; + // not found + return -1; } -// NOTE: We do minimal checks in this function so the values should be sanitized somewhere else -int string_parse_length(void *ret_in, const char *s) { - struct length *ret = (struct length*) ret_in; - char *s_stripped = string_strip_brackets(s); - - // single int without brackets - if (!s_stripped) { - int val = 0; - bool success = safe_string_to_int(&val, s); - if (!success) { - LOG_W("Specify either a single value or two comma-separated values between parentheses"); - return false; - } - - ret->min = val; - ret->max = val; - return true; +// NOTE: We do minimal checks in this function so the values should be sanitized +// somewhere else +int string_parse_length(void *ret_in, const char *s) +{ + struct length *ret = (struct length *)ret_in; + char *s_stripped = string_strip_brackets(s); + + // single int without brackets + if (!s_stripped) { + int val = 0; + bool success = safe_string_to_int(&val, s); + if (!success) { + LOG_W("Specify either a single value or two comma-separated values " + "between parentheses"); + return false; } - char **s_arr = string_to_array(s_stripped, ","); - g_free(s_stripped); + ret->min = val; + ret->max = val; + return true; + } - int len = string_array_length(s_arr); - if (len != 2) { - g_strfreev(s_arr); - LOG_W("Specify either a single value or two comma-separated values between parentheses"); - return false; - } + char **s_arr = string_to_array(s_stripped, ","); + g_free(s_stripped); - int *int_arr = NULL; - bool success = string_parse_int_list(s_arr, &int_arr, true); + int len = string_array_length(s_arr); + if (len != 2) { g_strfreev(s_arr); + LOG_W("Specify either a single value or two comma-separated values " + "between parentheses"); + return false; + } - if (!success) - return false; + int *int_arr = NULL; + bool success = string_parse_int_list(s_arr, &int_arr, true); + g_strfreev(s_arr); - ret->min = int_arr[0] == -1 ? INT_MIN : int_arr[0]; - ret->max = int_arr[1] == -1 ? INT_MAX : int_arr[1]; + if (!success) + return false; - g_free(int_arr); - return success; + ret->min = int_arr[0] == -1 ? INT_MIN : int_arr[0]; + ret->max = int_arr[1] == -1 ? INT_MAX : int_arr[1]; + + g_free(int_arr); + return success; } -bool set_from_string(void *target, struct setting setting, const char *value) { - GError *error = NULL; +bool set_from_string(void *target, struct setting setting, const char *value) +{ + GError *error = NULL; - if (!strlen(value) && setting.type != TYPE_STRING) { - LOG_W("Cannot set empty value for setting %s", setting.name); - return false; + if (!strlen(value) && setting.type != TYPE_STRING) { + LOG_W("Cannot set empty value for setting %s", setting.name); + return false; + } + + bool success = false; + // Do not use setting.value, since we might want to set a rule. Use + // target instead + switch (setting.type) { + case TYPE_INT: return safe_string_to_int(target, value); + case TYPE_DOUBLE: return safe_string_to_double(target, value); + case TYPE_STRING: + g_free(*(char **)target); + *(char **)target = g_strdup(value); + return true; + case TYPE_CUSTOM: + if (setting.parser == NULL) { + LOG_W("Setting %s doesn't have parser", setting.name); + return false; } + success = setting.parser(setting.parser_data, value, target); - bool success = false; - // Do not use setting.value, since we might want to set a rule. Use - // target instead - switch (setting.type) { - case TYPE_INT: - return safe_string_to_int(target, value); - case TYPE_DOUBLE: - return safe_string_to_double(target, value); - case TYPE_STRING: - g_free(*(char**) target); - *(char**) target = g_strdup(value); - return true; - case TYPE_CUSTOM: - if (setting.parser == NULL) { - LOG_W("Setting %s doesn't have parser", setting.name); - return false; - } - success = setting.parser(setting.parser_data, value, target); - - if (!success) LOG_W("Invalid %s value: '%s'", setting.name, value); - return success; - case TYPE_PATH: ; - g_free(*(char**) target); - *(char**) target = string_to_path(g_strdup(value)); - - // TODO make scripts take arguments in the config and - // deprecate the arguments that are now passed to the - // scripts - if (!setting.parser_data) - return true; - g_strfreev(*(char***)setting.parser_data); - if (!g_shell_parse_argv(*(char**) target, NULL, (char***)setting.parser_data, &error)) { - LOG_W("Unable to parse %s command: '%s'. " - "It's functionality will be disabled.", - setting.name, error->message); - g_error_free(error); - return false; - } - return true; - case TYPE_TIME: ; - gint64 tmp_time = string_to_time(value); - if (errno != 0) { - return false; - } - *(gint64*) target = tmp_time; - return true; - case TYPE_LIST: ; - LOG_D("list type %i", GPOINTER_TO_INT(setting.parser_data)); - return string_parse_list(setting.parser_data, value, target); - case TYPE_LENGTH: - // Keep compatibility with old offset syntax - if (STR_EQ(setting.name, "offset") && string_parse_list(GINT_TO_POINTER(OFFSET_LIST), value, target)) { - LOG_M("Using legacy offset syntax NxN, you should switch to the new syntax (N, N)"); - return true; - } - - // Keep compatibility with old height semantics - if (STR_EQ(setting.name, "height") && string_is_int(value)) { - LOG_M("Setting 'height' has changed behaviour after dunst 1.12.0, see https://dunst-project.org/release/#v1.12.0."); - LOG_M("Legacy height support may be dropped in the future. If you want to hide this message transition to"); - LOG_M("'height = (0, X)' for dynamic height (old behaviour equivalent) or to 'height = (X, X)' for a fixed height."); - - int height; - if (!safe_string_to_int(&height, value)) - return false; - - ((struct length *)target)->min = 0; - ((struct length *)target)->max = height; - return true; - } - return string_parse_length(target, value); - case TYPE_COLOR: - return string_parse_color(value, target); - case TYPE_GRADIENT: - return string_parse_gradient(value, target); - default: - LOG_W("Setting type of '%s' is not known (type %i)", setting.name, setting.type); - return false; + if (!success) + LOG_W("Invalid %s value: '%s'", setting.name, value); + return success; + case TYPE_PATH:; + g_free(*(char **)target); + *(char **)target = string_to_path(g_strdup(value)); + + // TODO make scripts take arguments in the config and + // deprecate the arguments that are now passed to the + // scripts + if (!setting.parser_data) + return true; + g_strfreev(*(char ***)setting.parser_data); + if (!g_shell_parse_argv(*(char **)target, + NULL, + (char ***)setting.parser_data, + &error)) { + LOG_W("Unable to parse %s command: '%s'. " + "It's functionality will be disabled.", + setting.name, + error->message); + g_error_free(error); + return false; } -} + return true; + case TYPE_TIME:; + gint64 tmp_time = string_to_time(value); + if (errno != 0) { + return false; + } + *(gint64 *)target = tmp_time; + return true; + case TYPE_LIST:; + LOG_D("list type %i", GPOINTER_TO_INT(setting.parser_data)); + return string_parse_list(setting.parser_data, value, target); + case TYPE_LENGTH: + // Keep compatibility with old offset syntax + if (STR_EQ(setting.name, "offset") + && string_parse_list(GINT_TO_POINTER(OFFSET_LIST), value, target)) { + LOG_M("Using legacy offset syntax NxN, you should switch to the " + "new syntax (N, N)"); + return true; + } + + // Keep compatibility with old height semantics + if (STR_EQ(setting.name, "height") && string_is_int(value)) { + LOG_M("Setting 'height' has changed behaviour after dunst 1.12.0, " + "see https://dunst-project.org/release/#v1.12.0."); + LOG_M("Legacy height support may be dropped in the future. If you " + "want to hide this message transition to"); + LOG_M("'height = (0, X)' for dynamic height (old behaviour " + "equivalent) or to 'height = (X, X)' for a fixed height."); + + int height; + if (!safe_string_to_int(&height, value)) + return false; -bool set_setting(struct setting setting, char* value) { - LOG_D("[%s] Trying to set %s to %s", setting.section, setting.name, value); - if (setting.value == NULL) { - // setting.value is NULL, so it must be only a rule - return true; + ((struct length *)target)->min = 0; + ((struct length *)target)->max = height; + return true; } + return string_parse_length(target, value); + case TYPE_COLOR: return string_parse_color(value, target); + case TYPE_GRADIENT: return string_parse_gradient(value, target); + default: + LOG_W("Setting type of '%s' is not known (type %i)", + setting.name, + setting.type); + return false; + } +} + +bool set_setting(struct setting setting, char *value) +{ + LOG_D("[%s] Trying to set %s to %s", setting.section, setting.name, value); + if (setting.value == NULL) { + // setting.value is NULL, so it must be only a rule + return true; + } - return set_from_string(setting.value, setting, value); + return set_from_string(setting.value, setting, value); } -int set_rule_value(struct rule* r, struct setting setting, char* value) { - // Apply rule member offset. Converting to char* because it's - // guaranteed to be 1 byte - void *target = (char*)r + setting.rule_offset; +int set_rule_value(struct rule *r, struct setting setting, char *value) +{ + // Apply rule member offset. Converting to char* because it's + // guaranteed to be 1 byte + void *target = (char *)r + setting.rule_offset; - return set_from_string(target, setting, value); + return set_from_string(target, setting, value); } -bool set_rule(struct setting setting, char* value, char* section) { - struct rule *r = get_rule(section); - if (!r) { - r = rule_new(section); - LOG_D("Creating new rule '%s'", section); - } - return set_rule_value(r, setting, value); +bool set_rule(struct setting setting, char *value, char *section) +{ + struct rule *r = get_rule(section); + if (!r) { + r = rule_new(section); + LOG_D("Creating new rule '%s'", section); + } + return set_rule_value(r, setting, value); } -void set_defaults(void) { - LOG_D("Initializing settings"); - settings = (struct settings) {0}; +void set_defaults(void) +{ + LOG_D("Initializing settings"); + settings = (struct settings){0}; - for (size_t i = 0; i < G_N_ELEMENTS(allowed_settings); i++) { - // FIXME Rule settings can only have a default if they have an - // working entry in the settings struct as well. Make an - // alternative way of setting defaults for rules. + for (size_t i = 0; i < G_N_ELEMENTS(allowed_settings); i++) { + // FIXME Rule settings can only have a default if they have an + // working entry in the settings struct as well. Make an + // alternative way of setting defaults for rules. - if (!allowed_settings[i].value) // don't set default if it's only a rule - continue; + if (!allowed_settings[i].value) // don't set default if it's only a rule + continue; - if(!set_setting(allowed_settings[i], allowed_settings[i].default_value)) { - LOG_E("Could not set default of setting %s", allowed_settings[i].name); - } + if (!set_setting(allowed_settings[i], + allowed_settings[i].default_value)) { + LOG_E("Could not set default of setting %s", + allowed_settings[i].name); } + } } -void save_settings(struct ini *ini) { - for (int i = 0; i < ini->section_count; i++) { - const struct section curr_section = ini->sections[i]; +void save_settings(struct ini *ini) +{ + for (int i = 0; i < ini->section_count; i++) { + const struct section curr_section = ini->sections[i]; + + if (is_deprecated_section(curr_section.name)) { + LOG_W("Section %s is deprecated.\n%s\nIgnoring this section.", + curr_section.name, + get_section_deprecation_message(curr_section.name)); + continue; + } - if (is_deprecated_section(curr_section.name)) { - LOG_W("Section %s is deprecated.\n%s\nIgnoring this section.", - curr_section.name, - get_section_deprecation_message(curr_section.name)); - continue; + LOG_D("Entering section [%s]", curr_section.name); + for (int j = 0; j < curr_section.entry_count; j++) { + const struct entry curr_entry = curr_section.entries[j]; + int setting_id = get_setting_id(curr_entry.key, curr_section.name); + struct setting curr_setting = allowed_settings[setting_id]; + if (setting_id < 0) { + if (setting_id == -1) { + LOG_W("Setting %s in section %s doesn't exist", + curr_entry.key, + curr_section.name); } - - LOG_D("Entering section [%s]", curr_section.name); - for (int j = 0; j < curr_section.entry_count; j++) { - const struct entry curr_entry = curr_section.entries[j]; - int setting_id = get_setting_id(curr_entry.key, curr_section.name); - struct setting curr_setting = allowed_settings[setting_id]; - if (setting_id < 0) { - if (setting_id == -1) { - LOG_W("Setting %s in section %s doesn't exist", curr_entry.key, curr_section.name); - } - continue; - } - - bool is_rule = curr_setting.rule_offset > 0; - if (is_special_section(curr_section.name)) { - if (is_rule) { - // set as a rule, but only if it's not a filter - if (rule_offset_is_modifying(curr_setting.rule_offset)) { - LOG_D("Adding rule '%s = %s' to special section %s", - curr_entry.key, - curr_entry.value, - curr_section.name); - set_rule(curr_setting, curr_entry.value, curr_section.name); - } else { - LOG_W("Cannot use filtering rules in special section. Ignoring %s in section %s.", - curr_entry.key, - curr_section.name); - } - } else { - // set as a regular setting - char *value = g_strstrip(curr_entry.value); - set_setting(curr_setting, value); - } - } else { - // interpret this section as a rule - LOG_D("Adding rule '%s = %s' to section %s", - curr_entry.key, - curr_entry.value, - curr_section.name); - set_rule(curr_setting, curr_entry.value, curr_section.name); - } + continue; + } + + bool is_rule = curr_setting.rule_offset > 0; + if (is_special_section(curr_section.name)) { + if (is_rule) { + // set as a rule, but only if it's not a filter + if (rule_offset_is_modifying(curr_setting.rule_offset)) { + LOG_D("Adding rule '%s = %s' to special section %s", + curr_entry.key, + curr_entry.value, + curr_section.name); + set_rule( + curr_setting, curr_entry.value, curr_section.name); + } else { + LOG_W("Cannot use filtering rules in special section. " + "Ignoring %s in section %s.", + curr_entry.key, + curr_section.name); + } + } else { + // set as a regular setting + char *value = g_strstrip(curr_entry.value); + set_setting(curr_setting, value); } + } else { + // interpret this section as a rule + LOG_D("Adding rule '%s = %s' to section %s", + curr_entry.key, + curr_entry.value, + curr_section.name); + set_rule(curr_setting, curr_entry.value, curr_section.name); + } } + } } void cmdline_load(int argc, char *argv[]) { - cmdline_argc = argc; - cmdline_argv = argv; + cmdline_argc = argc; + cmdline_argv = argv; } static int cmdline_find_option(const char *key, int start) { - ASSERT_OR_RET(key, -1); + ASSERT_OR_RET(key, -1); - gchar **keys = g_strsplit(key, "/", -1); + gchar **keys = g_strsplit(key, "/", -1); - for (int i = 0; keys[i] != NULL; i++) { - for (int j = start; j < cmdline_argc; j++) { - if (STR_EQ(keys[i], cmdline_argv[j])) { - g_strfreev(keys); - return j; - } - } + for (int i = 0; keys[i] != NULL; i++) { + for (int j = start; j < cmdline_argc; j++) { + if (STR_EQ(keys[i], cmdline_argv[j])) { + g_strfreev(keys); + return j; + } } + } - g_strfreev(keys); - return -1; + g_strfreev(keys); + return -1; } static const char *cmdline_get_value(const char *key, int start, int *found) { - int idx = cmdline_find_option(key, start); - if (idx < 0) { - return NULL; - } - - if (found) - *found = idx + 1; - - if (idx + 1 >= cmdline_argc) { - /* the argument is missing */ - LOG_W("%s: Missing argument. Ignoring.", key); - return NULL; - } - return cmdline_argv[idx + 1]; -} - -char *cmdline_get_string_offset(const char *key, const char *def, int start, int *found) + int idx = cmdline_find_option(key, start); + if (idx < 0) { + return NULL; + } + + if (found) + *found = idx + 1; + + if (idx + 1 >= cmdline_argc) { + /* the argument is missing */ + LOG_W("%s: Missing argument. Ignoring.", key); + return NULL; + } + return cmdline_argv[idx + 1]; +} + +char *cmdline_get_string_offset(const char *key, + const char *def, + int start, + int *found) { - const char *str = cmdline_get_value(key, start, found); + const char *str = cmdline_get_value(key, start, found); - if (str) - return g_strdup(str); - if (def) - return g_strdup(def); - else - return NULL; + if (str) + return g_strdup(str); + if (def) + return g_strdup(def); + else + return NULL; } -char *cmdline_get_string(const char *key, const char *def, const char *description) +char * +cmdline_get_string(const char *key, const char *def, const char *description) { - cmdline_usage_append(key, "string", description); - return cmdline_get_string_offset(key, def, 1, NULL); + cmdline_usage_append(key, "string", description); + return cmdline_get_string_offset(key, def, 1, NULL); } -char *cmdline_get_path(const char *key, const char *def, const char *description) +char * +cmdline_get_path(const char *key, const char *def, const char *description) { - cmdline_usage_append(key, "string", description); - const char *str = cmdline_get_value(key, 1, NULL); + cmdline_usage_append(key, "string", description); + const char *str = cmdline_get_value(key, 1, NULL); - if (str) - return string_to_path(g_strdup(str)); - else - return string_to_path(g_strdup(def)); + if (str) + return string_to_path(g_strdup(str)); + else + return string_to_path(g_strdup(def)); } -char **cmdline_get_list(const char *key, const char *def, const char *description) +char ** +cmdline_get_list(const char *key, const char *def, const char *description) { - cmdline_usage_append(key, "list", description); - const char *str = cmdline_get_value(key, 1, NULL); + cmdline_usage_append(key, "list", description); + const char *str = cmdline_get_value(key, 1, NULL); - if (str) - return string_to_array(str, ","); - else - return string_to_array(def, ","); + if (str) + return string_to_array(str, ","); + else + return string_to_array(def, ","); } gint64 cmdline_get_time(const char *key, gint64 def, const char *description) { - cmdline_usage_append(key, "time", description); - const char *timestring = cmdline_get_value(key, 1, NULL); - gint64 val = def; + cmdline_usage_append(key, "time", description); + const char *timestring = cmdline_get_value(key, 1, NULL); + gint64 val = def; - if (timestring) { - val = string_to_time(timestring); - } + if (timestring) { + val = string_to_time(timestring); + } - return val; + return val; } int cmdline_get_int(const char *key, int def, const char *description) { - cmdline_usage_append(key, "int", description); - const char *str = cmdline_get_value(key, 1, NULL); + cmdline_usage_append(key, "int", description); + const char *str = cmdline_get_value(key, 1, NULL); - if (str) - return atoi(str); - else - return def; + if (str) + return atoi(str); + else + return def; } double cmdline_get_double(const char *key, double def, const char *description) { - cmdline_usage_append(key, "double", description); - const char *str = cmdline_get_value(key, 1, NULL); + cmdline_usage_append(key, "double", description); + const char *str = cmdline_get_value(key, 1, NULL); - if (str) - return atof(str); - else - return def; + if (str) + return atof(str); + else + return def; } int cmdline_get_bool(const char *key, int def, const char *description) { - cmdline_usage_append(key, "", description); - int idx = cmdline_find_option(key, 1); + cmdline_usage_append(key, "", description); + int idx = cmdline_find_option(key, 1); - if (idx > 0) - return true; - else - return def; + if (idx > 0) + return true; + else + return def; } bool cmdline_is_set(const char *key) { - return cmdline_get_value(key, 1, NULL) != NULL; + return cmdline_get_value(key, 1, NULL) != NULL; } -void cmdline_usage_append(const char *key, const char *type, const char *description) +void cmdline_usage_append(const char *key, + const char *type, + const char *description) { - char *key_type; - if (STR_FULL(type)) - key_type = g_strdup_printf("%s (%s)", key, type); - else - key_type = g_strdup(key); - - if (!usage_str) { - usage_str = - g_strdup_printf("%-50s - %s\n", key_type, description); - g_free(key_type); - return; - } - - char *tmp; - tmp = g_strdup_printf("%s%-50s - %s\n", usage_str, key_type, description); + char *key_type; + if (STR_FULL(type)) + key_type = g_strdup_printf("%s (%s)", key, type); + else + key_type = g_strdup(key); + + if (!usage_str) { + usage_str = g_strdup_printf("%-50s - %s\n", key_type, description); g_free(key_type); + return; + } - g_free(usage_str); - usage_str = tmp; + char *tmp; + tmp = g_strdup_printf("%s%-50s - %s\n", usage_str, key_type, description); + g_free(key_type); + g_free(usage_str); + usage_str = tmp; } const char *cmdline_create_usage(void) { - return usage_str; + return usage_str; } /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/option_parser.h b/src/option_parser.h index 9261cd22e..7660788a1 100644 --- a/src/option_parser.h +++ b/src/option_parser.h @@ -1,4 +1,5 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ #ifndef DUNST_OPTION_PARSER_H #define DUNST_OPTION_PARSER_H @@ -7,10 +8,10 @@ #include #include "dunst.h" -#include "settings.h" #include "ini.h" +#include "settings.h" -int string_parse_enum(const void* data, const char *s, void * ret); +int string_parse_enum(const void *data, const char *s, void *ret); int string_parse_sepcolor(const void *data, const char *s, void *ret); int string_parse_color(const char *s, struct color *ret); int string_parse_gradient(const char *s, struct gradient **ret); @@ -23,15 +24,23 @@ void save_settings(struct ini *ini); void cmdline_load(int argc, char *argv[]); /* for all cmdline_get_* key can be either "-key" or "-key/-longkey" */ -char *cmdline_get_string_offset(const char *key, const char *def, int start, int *found); -char *cmdline_get_string(const char *key, const char *def, const char *description); -char *cmdline_get_path(const char *key, const char *def, const char *description); -char **cmdline_get_list(const char *key, const char *def, const char *description); +char *cmdline_get_string_offset(const char *key, + const char *def, + int start, + int *found); +char * +cmdline_get_string(const char *key, const char *def, const char *description); +char * +cmdline_get_path(const char *key, const char *def, const char *description); +char ** +cmdline_get_list(const char *key, const char *def, const char *description); int cmdline_get_int(const char *key, int def, const char *description); double cmdline_get_double(const char *key, double def, const char *description); int cmdline_get_bool(const char *key, int def, const char *description); bool cmdline_is_set(const char *key); -void cmdline_usage_append(const char *key, const char *type, const char *description); +void cmdline_usage_append(const char *key, + const char *type, + const char *description); const char *cmdline_create_usage(void); #endif diff --git a/src/output.c b/src/output.c index a3c121e38..734da7bae 100644 --- a/src/output.c +++ b/src/output.c @@ -2,109 +2,114 @@ #include "log.h" #ifdef ENABLE_X11 -#include "x11/x.h" #include "x11/screen.h" +#include "x11/x.h" #endif #ifdef ENABLE_WAYLAND #include "wayland/wl.h" #endif -bool is_running_wayland(void) { - char* wayland_display = getenv("WAYLAND_DISPLAY"); - return !(wayland_display == NULL); +bool is_running_wayland(void) +{ + char *wayland_display = getenv("WAYLAND_DISPLAY"); + return !(wayland_display == NULL); } #ifdef ENABLE_X11 const struct output output_x11 = { - x_setup, - x_free, + x_setup, + x_free, - x_win_create, - x_win_destroy, + x_win_create, + x_win_destroy, - x_win_show, - x_win_hide, + x_win_show, + x_win_hide, - x_display_surface, - x_win_get_context, + x_display_surface, + x_win_get_context, - get_active_screen, + get_active_screen, - x_is_idle, - have_fullscreen_window, + x_is_idle, + have_fullscreen_window, - x_get_scale, + x_get_scale, }; #endif #ifdef ENABLE_WAYLAND const struct output output_wl = { - wl_init, - wl_deinit, + wl_init, + wl_deinit, - wl_win_create, - wl_win_destroy, + wl_win_create, + wl_win_destroy, - wl_win_show, - wl_win_hide, + wl_win_show, + wl_win_hide, - wl_display_surface, - wl_win_get_context, + wl_display_surface, + wl_win_get_context, - wl_get_active_screen, + wl_get_active_screen, - wl_is_idle, - wl_have_fullscreen_window, + wl_is_idle, + wl_have_fullscreen_window, - wl_get_scale, + wl_get_scale, }; #endif #ifdef ENABLE_X11 -const struct output* get_x11_output(void) { - const struct output* output = &output_x11; - if (output->init()) { - return output; - } else { - LOG_E("Couldn't initialize X11 output. Aborting..."); - } +const struct output *get_x11_output(void) +{ + const struct output *output = &output_x11; + if (output->init()) { + return output; + } else { + LOG_E("Couldn't initialize X11 output. Aborting..."); + } } #endif #ifdef ENABLE_WAYLAND -const struct output* get_wl_output(void) { - const struct output* output = &output_wl; - if (output->init()) { - return output; - } else { +const struct output *get_wl_output(void) +{ + const struct output *output = &output_wl; + if (output->init()) { + return output; + } else { #ifdef ENABLE_X11 - LOG_W("Couldn't initialize wayland output. Falling back to X11 output."); - output->deinit(); - return get_x11_output(); + LOG_W( + "Couldn't initialize wayland output. Falling back to X11 output."); + output->deinit(); + return get_x11_output(); #else - DIE("Couldn't initialize wayland output"); + DIE("Couldn't initialize wayland output"); #endif - } + } } #endif -const struct output* output_create(bool force_xwayland) +const struct output *output_create(bool force_xwayland) { #ifdef ENABLE_WAYLAND - if ((!force_xwayland || !X11_SUPPORT) && is_running_wayland()) { - LOG_I("Using Wayland output"); - if (force_xwayland) - LOG_W("Ignoring force_xwayland setting because X11 output was not compiled"); - return get_wl_output(); - } + if ((!force_xwayland || !X11_SUPPORT) && is_running_wayland()) { + LOG_I("Using Wayland output"); + if (force_xwayland) + LOG_W("Ignoring force_xwayland setting because X11 output was not " + "compiled"); + return get_wl_output(); + } #endif #ifdef ENABLE_X11 - LOG_I("Using X11 output"); - return get_x11_output(); + LOG_I("Using X11 output"); + return get_x11_output(); #endif - DIE("No applicable ouput was found (X11, Wayland)"); + DIE("No applicable ouput was found (X11, Wayland)"); } /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/output.h b/src/output.h index f5ab71de4..165727afa 100644 --- a/src/output.h +++ b/src/output.h @@ -1,54 +1,59 @@ #ifndef DUNST_OUTPUT_H #define DUNST_OUTPUT_H -#include -#include #include +#include +#include typedef gpointer window; -struct dimensions { - int x; - int y; - int w; - int h; - int text_width; - int text_height; +struct dimensions +{ + int x; + int y; + int w; + int h; + int text_width; + int text_height; - int corner_radius; + int corner_radius; }; -struct screen_info { - char *name; - int id; - int x; - int y; - unsigned int h; - unsigned int mmh; - unsigned int w; - int dpi; +struct screen_info +{ + char *name; + int id; + int x; + int y; + unsigned int h; + unsigned int mmh; + unsigned int w; + int dpi; }; -struct output { - bool (*init)(void); - void (*deinit)(void); +struct output +{ + bool (*init)(void); + void (*deinit)(void); - window (*win_create)(void); - void (*win_destroy)(window); + window (*win_create)(void); + void (*win_destroy)(window); - void (*win_show)(window); - void (*win_hide)(window); + void (*win_show)(window); + void (*win_hide)(window); - void (*display_surface)(cairo_surface_t *srf, window win, const struct dimensions*); + void (*display_surface)(cairo_surface_t *srf, + window win, + const struct dimensions *); - cairo_t* (*win_get_context)(window); + cairo_t *(*win_get_context)(window); - const struct screen_info* (*get_active_screen)(void); + const struct screen_info *(*get_active_screen)(void); - bool (*is_idle)(void); - bool (*have_fullscreen_window)(void); + bool (*is_idle)(void); + bool (*have_fullscreen_window)(void); - double (*get_scale)(void); + double (*get_scale)(void); }; #ifdef ENABLE_X11 @@ -74,7 +79,7 @@ struct output { * * Either output is skipped if it was not compiled. */ -const struct output* output_create(bool force_xwayland); +const struct output *output_create(bool force_xwayland); bool is_running_wayland(void); diff --git a/src/queues.c b/src/queues.c index d578b47f7..fe4034f0e 100644 --- a/src/queues.c +++ b/src/queues.c @@ -1,4 +1,5 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ /** * @file src/queues.c @@ -23,14 +24,14 @@ #include "dunst.h" #include "log.h" #include "notification.h" +#include "rules.h" #include "settings.h" #include "utils.h" -#include "rules.h" /* notification lists */ -static GQueue *waiting = NULL; /**< all new notifications get into here */ +static GQueue *waiting = NULL; /**< all new notifications get into here */ static GQueue *displayed = NULL; /**< currently displayed notifications */ -static GQueue *history = NULL; /**< history of displayed notifications */ +static GQueue *history = NULL; /**< history of displayed notifications */ int next_notification_id = 1; @@ -40,47 +41,47 @@ static bool queues_stack_by_tag(struct notification *n); /* see queues.h */ void queues_init(void) { - history = g_queue_new(); - displayed = g_queue_new(); - waiting = g_queue_new(); + history = g_queue_new(); + displayed = g_queue_new(); + waiting = g_queue_new(); } /* see queues.h */ GList *queues_get_displayed(void) { - return g_queue_peek_head_link(displayed); + return g_queue_peek_head_link(displayed); } /* see queues.h */ struct notification *queues_get_head_waiting(void) { - if (waiting->length == 0) - return NULL; - return g_queue_peek_head(waiting); + if (waiting->length == 0) + return NULL; + return g_queue_peek_head(waiting); } /* see queues.h */ unsigned int queues_length_waiting(void) { - return waiting->length; + return waiting->length; } /* see queues.h */ unsigned int queues_length_displayed(void) { - return displayed->length; + return displayed->length; } /* see queues.h */ unsigned int queues_length_history(void) { - return history->length; + return history->length; } /* see queues.h */ GList *queues_get_history(void) { - return g_queue_peek_head_link(history); + return g_queue_peek_head_link(history); } /** @@ -95,20 +96,20 @@ GList *queues_get_history(void) * @param elemB The element, which will get removed from queueB */ static void queues_swap_notifications(GQueue *queueA, - GList *elemA, + GList *elemA, GQueue *queueB, - GList *elemB) + GList *elemB) { - struct notification *toB = elemA->data; - struct notification *toA = elemB->data; + struct notification *toB = elemA->data; + struct notification *toA = elemB->data; - g_queue_delete_link(queueA, elemA); - g_queue_delete_link(queueB, elemB); + g_queue_delete_link(queueA, elemA); + g_queue_delete_link(queueB, elemB); - if (toA) - g_queue_insert_sorted(queueA, toA, notification_cmp_data, NULL); - if (toB) - g_queue_insert_sorted(queueB, toB, notification_cmp_data, NULL); + if (toA) + g_queue_insert_sorted(queueA, toA, notification_cmp_data, NULL); + if (toB) + g_queue_insert_sorted(queueB, toB, notification_cmp_data, NULL); } /** @@ -118,18 +119,20 @@ static void queues_swap_notifications(GQueue *queueA, * @param status The current status of dunst * @param shown True if the notification is currently displayed */ -static bool queues_notification_is_ready(const struct notification *n, struct dunst_status status, bool shown) +static bool queues_notification_is_ready(const struct notification *n, + struct dunst_status status, + bool shown) { - if (status.pause_level > n->override_pause_level) { - return false; - } + if (status.pause_level > n->override_pause_level) { + return false; + } - if (status.fullscreen && shown) - return n && n->fullscreen != FS_PUSHBACK; - else if (status.fullscreen && !shown) - return n && n->fullscreen == FS_SHOW; - else - return true; + if (status.fullscreen && shown) + return n && n->fullscreen != FS_PUSHBACK; + else if (status.fullscreen && !shown) + return n && n->fullscreen == FS_SHOW; + else + return true; } /** @@ -141,76 +144,80 @@ static bool queues_notification_is_ready(const struct notification *n, struct du * @retval true: the notification is timed out * @retval false: otherwise */ -static bool queues_notification_is_finished(struct notification *n, struct dunst_status status, gint64 time) +static bool queues_notification_is_finished(struct notification *n, + struct dunst_status status, + gint64 time) { - assert(n); + assert(n); - if (n->skip_display && !n->redisplayed) - return true; + if (n->skip_display && !n->redisplayed) + return true; - if (n->timeout == 0) // sticky - return false; + if (n->timeout == 0) // sticky + return false; - bool is_idle = status.fullscreen ? false : status.idle; + 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; - } + /* don't timeout when user is idle */ + if (is_idle && !n->transient) { + n->start = time_monotonic_now(); + return false; + } - /* remove old message */ - if (time - n->start > n->timeout) { - return true; - } + /* remove old message */ + if (time - n->start > n->timeout) { + return true; + } - return false; + return false; } /* see queues.h */ int queues_notification_insert(struct notification *n) { - /* do not display the message, if the message is empty */ - if (STR_EMPTY(n->msg)) { - if (settings.always_run_script) { - notification_run_script(n); - } - LOG_M("Skipping notification: '%s' '%s'", STR_NN(n->body), STR_NN(n->summary)); - return 0; + /* do not display the message, if the message is empty */ + if (STR_EMPTY(n->msg)) { + if (settings.always_run_script) { + notification_run_script(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; - } else { - n->id = ++next_notification_id; + LOG_M("Skipping notification: '%s' '%s'", + STR_NN(n->body), + STR_NN(n->summary)); + return 0; + } + + 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; + } else { + n->id = ++next_notification_id; + } - if (!inserted && STR_FULL(n->stack_tag) && queues_stack_by_tag(n)) - inserted = true; + if (!inserted && STR_FULL(n->stack_tag) && queues_stack_by_tag(n)) + inserted = true; - if (!inserted && settings.stack_duplicates && queues_stack_duplicate(n)){ - if(settings.sort == SORT_TYPE_UPDATE){ - g_queue_sort(displayed, notification_cmp_data, NULL); - } - inserted = true; + if (!inserted && settings.stack_duplicates && queues_stack_duplicate(n)) { + if (settings.sort == SORT_TYPE_UPDATE) { + g_queue_sort(displayed, notification_cmp_data, NULL); } + inserted = true; + } - if (!inserted) - g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL); + if (!inserted) + g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL); - if (!n->icon) { - notification_icon_replace_path(n, n->iconname); - } + if (!n->icon) { + notification_icon_replace_path(n, n->iconname); + } - if (print_notifications) - notification_print(n); + if (print_notifications) + notification_print(n); - return n->id; + return n->id; } /** @@ -221,37 +228,38 @@ int queues_notification_insert(struct notification *n) */ static bool queues_stack_duplicate(struct notification *new) { - GQueue *allqueues[] = { displayed, waiting }; - for (size_t i = 0; i < sizeof(allqueues)/sizeof(GQueue*); i++) { - for (GList *iter = g_queue_peek_head_link(allqueues[i]); iter; - iter = iter->next) { - struct notification *old = iter->data; - if (notification_is_duplicate(old, new)) { - /* 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 (old->progress == new->progress) { - old->dup_count++; - } else { - old->progress = new->progress; - } - iter->data = new; - - new->dup_count = old->dup_count; - signal_notification_closed(old, 1); - - if (allqueues[i] == displayed) - new->start = time_monotonic_now(); - - notification_transfer_icon(old, new); - - notification_unref(old); - return true; - } + GQueue *allqueues[] = {displayed, waiting}; + for (size_t i = 0; i < sizeof(allqueues) / sizeof(GQueue *); i++) { + for (GList *iter = g_queue_peek_head_link(allqueues[i]); iter; + iter = iter->next) { + struct notification *old = iter->data; + if (notification_is_duplicate(old, new)) { + /* 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 (old->progress == new->progress) { + old->dup_count++; + } else { + old->progress = new->progress; } + iter->data = new; + + new->dup_count = old->dup_count; + signal_notification_closed(old, 1); + + if (allqueues[i] == displayed) + new->start = time_monotonic_now(); + + notification_transfer_icon(old, new); + + notification_unref(old); + return true; + } } + } - return false; + return false; } /** @@ -262,384 +270,394 @@ static bool queues_stack_duplicate(struct notification *new) */ static bool queues_stack_by_tag(struct notification *new) { - GQueue *allqueues[] = { displayed, waiting }; - for (size_t i = 0; i < sizeof(allqueues)/sizeof(GQueue*); i++) { - for (GList *iter = g_queue_peek_head_link(allqueues[i]); iter; - iter = iter->next) { - struct notification *old = iter->data; - if (STR_FULL(old->stack_tag) && STR_EQ(old->stack_tag, new->stack_tag) - && STR_EQ(old->appname, new->appname)) { - iter->data = new; - new->dup_count = old->dup_count; - - signal_notification_closed(old, 1); - - if (allqueues[i] == displayed) { - new->start = time_monotonic_now(); - notification_run_script(new); - } - - notification_transfer_icon(old, new); - - notification_unref(old); - return true; - } + GQueue *allqueues[] = {displayed, waiting}; + for (size_t i = 0; i < sizeof(allqueues) / sizeof(GQueue *); i++) { + for (GList *iter = g_queue_peek_head_link(allqueues[i]); iter; + iter = iter->next) { + struct notification *old = iter->data; + if (STR_FULL(old->stack_tag) + && STR_EQ(old->stack_tag, new->stack_tag) + && STR_EQ(old->appname, new->appname)) { + iter->data = new; + new->dup_count = old->dup_count; + + signal_notification_closed(old, 1); + + if (allqueues[i] == displayed) { + new->start = time_monotonic_now(); + notification_run_script(new); } + + notification_transfer_icon(old, new); + + notification_unref(old); + return true; + } } - return false; + } + return false; } /* see queues.h */ bool queues_notification_replace_id(struct notification *new) { - GQueue *allqueues[] = { displayed, waiting }; - for (size_t i = 0; i < sizeof(allqueues)/sizeof(GQueue*); i++) { - for (GList *iter = g_queue_peek_head_link(allqueues[i]); - iter; - iter = iter->next) { - struct notification *old = iter->data; - if (old->id == new->id) { - iter->data = new; - new->dup_count = old->dup_count; - - if (allqueues[i] == displayed) { - new->start = time_monotonic_now(); - notification_run_script(new); - } - - notification_unref(old); - return true; - } + GQueue *allqueues[] = {displayed, waiting}; + for (size_t i = 0; i < sizeof(allqueues) / sizeof(GQueue *); i++) { + for (GList *iter = g_queue_peek_head_link(allqueues[i]); iter; + iter = iter->next) { + struct notification *old = iter->data; + if (old->id == new->id) { + iter->data = new; + new->dup_count = old->dup_count; + + if (allqueues[i] == displayed) { + new->start = time_monotonic_now(); + notification_run_script(new); } + + notification_unref(old); + return true; + } } - return false; + } + return false; } /* see queues.h */ void queues_notification_close_id(gint id, enum reason reason) { - struct notification *target = NULL; - - GQueue *allqueues[] = { displayed, waiting }; - for (size_t i = 0; i < sizeof(allqueues)/sizeof(GQueue*); i++) { - for (GList *iter = g_queue_peek_head_link(allqueues[i]); iter; - iter = iter->next) { - struct notification *n = iter->data; - if (n->id == id) { - g_queue_remove(allqueues[i], n); - target = n; - break; - } - } - } - - if (target) { - //Don't notify clients if notification was pulled from history - if (!target->redisplayed) - signal_notification_closed(target, reason); - queues_history_push(target); + struct notification *target = NULL; + + GQueue *allqueues[] = {displayed, waiting}; + for (size_t i = 0; i < sizeof(allqueues) / sizeof(GQueue *); i++) { + for (GList *iter = g_queue_peek_head_link(allqueues[i]); iter; + iter = iter->next) { + struct notification *n = iter->data; + if (n->id == id) { + g_queue_remove(allqueues[i], n); + target = n; + break; + } } + } + + if (target) { + // Don't notify clients if notification was pulled from history + if (!target->redisplayed) + signal_notification_closed(target, reason); + queues_history_push(target); + } } /* see queues.h */ void queues_notification_close(struct notification *n, enum reason reason) { - assert(n != NULL); - queues_notification_close_id(n->id, reason); + assert(n != NULL); + queues_notification_close_id(n->id, reason); } -static void queues_destroy_notification(struct notification *n, gpointer user_data) +static void queues_destroy_notification(struct notification *n, + gpointer user_data) { - (void)user_data; - notification_unref(n); + (void)user_data; + notification_unref(n); } /* see queues.h */ guint queues_history_clear(void) { - guint n = g_queue_get_length(history); - g_queue_foreach(history, (GFunc)queues_destroy_notification, NULL); - g_queue_clear(history); - return n; + guint n = g_queue_get_length(history); + g_queue_foreach(history, (GFunc)queues_destroy_notification, NULL); + g_queue_clear(history); + return n; } /* see queues.h */ void queues_history_pop(void) { - if (g_queue_is_empty(history)) - return; + if (g_queue_is_empty(history)) + return; - struct notification *n = g_queue_pop_tail(history); - n->redisplayed = true; - n->timeout = settings.sticky_history ? 0 : n->timeout; - g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL); + struct notification *n = g_queue_pop_tail(history); + n->redisplayed = true; + n->timeout = settings.sticky_history ? 0 : n->timeout; + g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL); } /* see queues.h */ void queues_history_pop_by_id(gint id) { - struct notification *n = NULL; - - if (g_queue_is_empty(history)) - return; - - // search through the history buffer - for (GList *iter = g_queue_peek_head_link(history); iter; - iter = iter->next) { - struct notification *cur = iter->data; - if (cur->id == id) { - n = cur; - break; - } + struct notification *n = NULL; + + if (g_queue_is_empty(history)) + return; + + // search through the history buffer + for (GList *iter = g_queue_peek_head_link(history); iter; + iter = iter->next) { + struct notification *cur = iter->data; + if (cur->id == id) { + n = cur; + break; } + } - // must be a valid notification - if (n == NULL) - return; + // must be a valid notification + if (n == NULL) + return; - g_queue_remove(history, n); - n->redisplayed = true; - n->timeout = settings.sticky_history ? 0 : n->timeout; - g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL); + g_queue_remove(history, n); + n->redisplayed = true; + n->timeout = settings.sticky_history ? 0 : n->timeout; + g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL); } /* see queues.h */ void queues_history_push(struct notification *n) { - if (!n->history_ignore) { - guint maxlen = settings.history_length; - if (settings.history_length > 0 && history->length >= maxlen) { - struct notification *to_free = g_queue_pop_head(history); - notification_unref(to_free); - } - - g_queue_push_tail(history, n); - } else { - notification_unref(n); + if (!n->history_ignore) { + guint maxlen = settings.history_length; + if (settings.history_length > 0 && history->length >= maxlen) { + struct notification *to_free = g_queue_pop_head(history); + notification_unref(to_free); } + + g_queue_push_tail(history, n); + } else { + notification_unref(n); + } } /* see queues.h */ void queues_history_push_all(void) { - while (displayed->length > 0) { - queues_notification_close(g_queue_peek_head_link(displayed)->data, REASON_USER); - } - - while (waiting->length > 0) { - queues_notification_close(g_queue_peek_head_link(waiting)->data, REASON_USER); - } + while (displayed->length > 0) { + queues_notification_close(g_queue_peek_head_link(displayed)->data, + REASON_USER); + } + + while (waiting->length > 0) { + queues_notification_close(g_queue_peek_head_link(waiting)->data, + REASON_USER); + } } /* see queues.h */ -bool queues_history_remove_by_id(gint id) { - struct notification *n = NULL; - - if (g_queue_is_empty(history)) - return false; - - for (GList *iter = g_queue_peek_head_link(history); iter; - iter = iter->next) { - struct notification *cur = iter->data; - if (cur->id == id) { - n = cur; - break; - } +bool queues_history_remove_by_id(gint id) +{ + struct notification *n = NULL; + + if (g_queue_is_empty(history)) + return false; + + for (GList *iter = g_queue_peek_head_link(history); iter; + iter = iter->next) { + struct notification *cur = iter->data; + if (cur->id == id) { + n = cur; + break; } + } - if (n == NULL) - return false; + if (n == NULL) + return false; - g_queue_remove(history, n); - notification_unref(n); - return true; + g_queue_remove(history, n); + notification_unref(n); + return true; } /* see queues.h */ void queues_update(struct dunst_status status, gint64 time) { - GList *iter, *nextiter; - - /* 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 - * and notifications is not eligible to get shown anymore */ - iter = g_queue_peek_head_link(displayed); - while (iter) { - struct notification *n = iter->data; - nextiter = iter->next; - - if (notification_is_locked(n)) { - iter = nextiter; - continue; - } - - if (n->marked_for_closure) { - queues_notification_close(n, n->marked_for_closure); - n->marked_for_closure = 0; - iter = nextiter; - continue; - } - - - if (queues_notification_is_finished(n, status, time)) { - queues_notification_close(n, REASON_TIME); - iter = nextiter; - continue; - } - - if (!queues_notification_is_ready(n, status, true)) { - g_queue_delete_link(displayed, iter); - g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL); - iter = nextiter; - continue; - } - - iter = nextiter; + GList *iter, *nextiter; + + /* 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 and notifications is not eligible to get shown anymore */ + iter = g_queue_peek_head_link(displayed); + while (iter) { + struct notification *n = iter->data; + nextiter = iter->next; + + if (notification_is_locked(n)) { + iter = nextiter; + continue; } - int cur_displayed_limit; - if (settings.notification_limit == 0) - cur_displayed_limit = INT_MAX; - else if ( settings.indicate_hidden - && settings.notification_limit > 1 - && displayed->length + waiting->length > settings.notification_limit) - cur_displayed_limit = settings.notification_limit-1; - else - cur_displayed_limit = settings.notification_limit; - - /* move notifications from queue to displayed */ - iter = g_queue_peek_head_link(waiting); - while (displayed->length < cur_displayed_limit && iter) { - struct notification *n = iter->data; - nextiter = iter->next; - - ASSERT_OR_RET(n,); - - if (!queues_notification_is_ready(n, status, false)) { - iter = nextiter; - continue; - } - - n->start = time; - notification_run_script(n); - - if (n->skip_display && !n->redisplayed) { - queues_notification_close(n, REASON_USER); - } else { - g_queue_delete_link(waiting, iter); - g_queue_insert_sorted(displayed, n, notification_cmp_data, NULL); - } - - iter = nextiter; + if (n->marked_for_closure) { + queues_notification_close(n, n->marked_for_closure); + n->marked_for_closure = 0; + iter = nextiter; + continue; } - /* if necessary, push the overhanging notifications from displayed to waiting again */ - while (displayed->length > cur_displayed_limit) { - struct notification *n = g_queue_pop_tail(displayed); - g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL); //TODO: actually it should be on the head if unsorted + if (queues_notification_is_finished(n, status, time)) { + queues_notification_close(n, REASON_TIME); + iter = nextiter; + continue; } - /* If displayed is actually full, let the more important notifications - * from waiting seep into displayed. - */ - if (settings.sort && displayed->length == cur_displayed_limit) { - GList *i_waiting, *i_displayed; - - while ( (i_waiting = g_queue_peek_head_link(waiting)) - && (i_displayed = g_queue_peek_tail_link(displayed))) { + if (!queues_notification_is_ready(n, status, true)) { + g_queue_delete_link(displayed, iter); + g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL); + iter = nextiter; + continue; + } - while (i_waiting && ! queues_notification_is_ready(i_waiting->data, status, false)) { - i_waiting = i_waiting->prev; - } + iter = nextiter; + } + + int cur_displayed_limit; + if (settings.notification_limit == 0) + cur_displayed_limit = INT_MAX; + else if (settings.indicate_hidden && settings.notification_limit > 1 + && displayed->length + waiting->length + > settings.notification_limit) + cur_displayed_limit = settings.notification_limit - 1; + else + cur_displayed_limit = settings.notification_limit; + + /* move notifications from queue to displayed */ + iter = g_queue_peek_head_link(waiting); + while (displayed->length < cur_displayed_limit && iter) { + struct notification *n = iter->data; + nextiter = iter->next; + + ASSERT_OR_RET(n, ); + + if (!queues_notification_is_ready(n, status, false)) { + iter = nextiter; + continue; + } - if (i_waiting && notification_cmp(i_displayed->data, i_waiting->data) > 0) { - struct notification *todisp = i_waiting->data; + n->start = time; + notification_run_script(n); - todisp->start = time; - notification_run_script(todisp); + if (n->skip_display && !n->redisplayed) { + queues_notification_close(n, REASON_USER); + } else { + g_queue_delete_link(waiting, iter); + g_queue_insert_sorted(displayed, n, notification_cmp_data, NULL); + } - queues_swap_notifications(displayed, i_displayed, waiting, i_waiting); - } else { - break; - } - } + iter = nextiter; + } + + /* if necessary, push the overhanging notifications from displayed to + * waiting again */ + while (displayed->length > cur_displayed_limit) { + struct notification *n = g_queue_pop_tail(displayed); + g_queue_insert_sorted( + waiting, + n, + notification_cmp_data, + NULL); // TODO: actually it should be on the head if unsorted + } + + /* If displayed is actually full, let the more important notifications + * from waiting seep into displayed. + */ + if (settings.sort && displayed->length == cur_displayed_limit) { + GList *i_waiting, *i_displayed; + + while ((i_waiting = g_queue_peek_head_link(waiting)) + && (i_displayed = g_queue_peek_tail_link(displayed))) { + + while (i_waiting + && !queues_notification_is_ready( + i_waiting->data, status, false)) { + i_waiting = i_waiting->prev; + } + + if (i_waiting + && notification_cmp(i_displayed->data, i_waiting->data) > 0) { + struct notification *todisp = i_waiting->data; + + todisp->start = time; + notification_run_script(todisp); + + queues_swap_notifications( + displayed, i_displayed, waiting, i_waiting); + } else { + break; + } } - signal_length_propertieschanged(); + } + signal_length_propertieschanged(); } /* see queues.h */ gint64 queues_get_next_datachange(gint64 time) { - gint64 wakeup_time = G_MAXINT64; - gint64 next_second = time + S2US(1) - (time % S2US(1)); - - for (GList *iter = g_queue_peek_head_link(displayed); iter; - iter = iter->next) { - struct notification *n = iter->data; - gint64 timeout_ts = n->start + n->timeout; - - if (n->timeout > 0 && n->locked == 0) { - if (timeout_ts > time) - wakeup_time = MIN(wakeup_time, timeout_ts); - else - // while we're processing or while locked, the notification already timed out - return time; - } + gint64 wakeup_time = G_MAXINT64; + gint64 next_second = time + S2US(1) - (time % S2US(1)); + + for (GList *iter = g_queue_peek_head_link(displayed); iter; + iter = iter->next) { + struct notification *n = iter->data; + gint64 timeout_ts = n->start + n->timeout; + + if (n->timeout > 0 && n->locked == 0) { + if (timeout_ts > time) + wakeup_time = MIN(wakeup_time, timeout_ts); + else + // while we're processing or while locked, the notification + // already timed out + return time; + } - if (settings.show_age_threshold >= 0) { - gint64 age = time - n->timestamp; - - if (age > settings.show_age_threshold - S2US(1)) { - /* Notification age should be updated -- sleep - * until the next turn of second. - * This ensures that all notifications' ages - * will change at once, and that at most one - * update will occur each second for this - * purpose. */ - wakeup_time = MIN(wakeup_time, next_second); - } - else - wakeup_time = MIN(wakeup_time, n->timestamp + settings.show_age_threshold); - } + if (settings.show_age_threshold >= 0) { + gint64 age = time - n->timestamp; + + if (age > settings.show_age_threshold - S2US(1)) { + /* Notification age should be updated -- sleep + * until the next turn of second. + * This ensures that all notifications' ages + * will change at once, and that at most one + * update will occur each second for this + * purpose. */ + wakeup_time = MIN(wakeup_time, next_second); + } else + wakeup_time = MIN(wakeup_time, + n->timestamp + settings.show_age_threshold); } + } - return wakeup_time != G_MAXINT64 ? wakeup_time : -1; + return wakeup_time != G_MAXINT64 ? wakeup_time : -1; } - - - /* see queues.h */ -struct notification* queues_get_by_id(gint id) +struct notification *queues_get_by_id(gint id) { - assert(id > 0); - - GQueue *recqueues[] = { displayed, waiting, history }; - for (size_t i = 0; i < sizeof(recqueues)/sizeof(GQueue*); i++) { - for (GList *iter = g_queue_peek_head_link(recqueues[i]); iter; - iter = iter->next) { - struct notification *cur = iter->data; - if (cur->id == id) - return cur; - } + assert(id > 0); + + GQueue *recqueues[] = {displayed, waiting, history}; + for (size_t i = 0; i < sizeof(recqueues) / sizeof(GQueue *); i++) { + for (GList *iter = g_queue_peek_head_link(recqueues[i]); iter; + iter = iter->next) { + struct notification *cur = iter->data; + if (cur->id == id) + return cur; } + } - return NULL; + return NULL; } void queues_reapply_all_rules(void) { - GQueue *recqueues[] = { displayed, waiting, history }; - for (size_t i = 0; i < sizeof(recqueues)/sizeof(GQueue*); i++) { - for (GList *iter = g_queue_peek_head_link(recqueues[i]); iter; - iter = iter->next) { - struct notification *cur = iter->data; - if (cur->original) { - rule_apply(cur->original, cur, false); - } - rule_apply_all(cur); - } + GQueue *recqueues[] = {displayed, waiting, history}; + for (size_t i = 0; i < sizeof(recqueues) / sizeof(GQueue *); i++) { + for (GList *iter = g_queue_peek_head_link(recqueues[i]); iter; + iter = iter->next) { + struct notification *cur = iter->data; + if (cur->original) { + rule_apply(cur->original, cur, false); + } + rule_apply_all(cur); } + } } /** @@ -649,20 +667,19 @@ void queues_reapply_all_rules(void) */ static void teardown_notification(gpointer data) { - struct notification *n = data; - notification_unref(n); + struct notification *n = data; + notification_unref(n); } /* see queues.h */ void queues_teardown(void) { - g_queue_free_full(history, teardown_notification); - history = NULL; - g_queue_free_full(displayed, teardown_notification); - displayed = NULL; - g_queue_free_full(waiting, teardown_notification); - waiting = NULL; + g_queue_free_full(history, teardown_notification); + history = NULL; + g_queue_free_full(displayed, teardown_notification); + displayed = NULL; + g_queue_free_full(waiting, teardown_notification); + waiting = NULL; } - /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/queues.h b/src/queues.h index 7490842ad..64e93b6d7 100644 --- a/src/queues.h +++ b/src/queues.h @@ -1,4 +1,5 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ /** * @file src/queues.h @@ -171,14 +172,14 @@ void queues_update(struct dunst_status status, gint64 time); gint64 queues_get_next_datachange(gint64 time); /** - * Get the notification which has the given id in the displayed and waiting queue or - * NULL if not found + * Get the notification which has the given id in the displayed and waiting + * queue or NULL if not found * * @param id the id searched for. * * @return the `id` notification or NULL */ -struct notification* queues_get_by_id(gint id); +struct notification *queues_get_by_id(gint id); /** * Reapply all rules to the queue (used when reloading configs) diff --git a/src/rules.c b/src/rules.c index 111b5bcc2..3aacd961b 100644 --- a/src/rules.c +++ b/src/rules.c @@ -1,27 +1,28 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ #include "rules.h" #include #include -#include #include +#include #include "dunst.h" -#include "utils.h" -#include "settings_data.h" #include "log.h" +#include "settings_data.h" +#include "utils.h" GSList *rules = NULL; // NOTE: Internal, only for rule_apply(...) -#define RULE_APPLY2(nprop, rprop, defval) \ - if (r->rprop != (defval)) { \ - if (save && n->original->rprop == (defval)) \ - n->original->rprop = n->nprop; \ - n->nprop = r->rprop; \ - } +#define RULE_APPLY2(nprop, rprop, defval) \ + if (r->rprop != (defval)) { \ + if (save && n->original->rprop == (defval)) \ + n->original->rprop = n->nprop; \ + n->nprop = r->rprop; \ + } #define RULE_APPLY(prop, defval) RULE_APPLY2(prop, prop, defval) @@ -31,164 +32,207 @@ GSList *rules = NULL; */ void rule_apply(struct rule *r, struct notification *n, bool save) { - if (save) notification_keep_original(n); - - RULE_APPLY2(dbus_timeout, override_dbus_timeout, -1); - RULE_APPLY2(transient, set_transient, -1); - - RULE_APPLY(timeout, -1); - RULE_APPLY(urgency, URG_NONE); - RULE_APPLY(fullscreen, FS_NULL); - RULE_APPLY(history_ignore, -1); - RULE_APPLY(skip_display, -1); - RULE_APPLY(word_wrap, -1); - RULE_APPLY(ellipsize, -1); - RULE_APPLY(alignment, -1); - RULE_APPLY(hide_text, -1); - RULE_APPLY(progress_bar_alignment, -1); - RULE_APPLY(min_icon_size, -1); - RULE_APPLY(max_icon_size, -1); - RULE_APPLY(markup, MARKUP_NULL); - RULE_APPLY(icon_position, -1); - RULE_APPLY(override_pause_level, -1); - - if (COLOR_VALID(r->fg)) { - if (save && !COLOR_VALID(n->original->fg)) n->original->fg = n->colors.fg; - n->colors.fg = r->fg; - } - if (COLOR_VALID(r->bg)) { - if (save && !COLOR_VALID(n->original->bg)) n->original->bg = n->colors.bg; - n->colors.bg = r->bg; - } - if (r->highlight != NULL) { - if (save && n->original->highlight == NULL) { - n->original->highlight = gradient_acquire(n->colors.highlight); - } - gradient_release(n->colors.highlight); - n->colors.highlight = gradient_acquire(r->highlight); - } - if (COLOR_VALID(r->fc)) { - if (save && !COLOR_VALID(n->original->fc)) n->original->fc = n->colors.frame; - n->colors.frame = r->fc; - } - if (r->action_name) { - if (save && n->original->action_name == NULL) - n->original->action_name = n->default_action_name; - else - g_free(n->default_action_name); - - n->default_action_name = g_strdup(r->action_name); - } - if (r->set_category) { - if (save && n->original->set_category == NULL) - n->original->set_category = n->category; - else - g_free(n->category); - - n->category = g_strdup(r->set_category); - } - if (r->default_icon) { - if (save && n->original->default_icon == NULL) - n->original->default_icon = n->default_icon_name; - else - g_free(n->default_icon_name); - - n->default_icon_name = g_strdup(r->default_icon); - } - if (r->set_stack_tag) { - if (save && n->original->set_stack_tag == NULL) - n->original->set_stack_tag = n->stack_tag; - else - g_free(n->stack_tag); - - n->stack_tag = g_strdup(r->set_stack_tag); - } - if (r->new_icon) { - if (save && n->original->new_icon == NULL) - n->original->new_icon = g_strdup(n->iconname); - - // FIXME This is not efficient when the icon is replaced - // multiple times for the same notification. To fix this, a - // separate variable is needed to track if the icon is - // replaced, like in 86cbc1d34bb0f551461dbd466cd9e4860ae01817. - notification_icon_replace_path(n, r->new_icon); - n->receiving_raw_icon = false; - } - if (r->format != NULL) { - if (save && n->original->format == NULL) - n->original->format = n->format; - else - g_free(n->format); - - n->format = g_strdup(r->format); - } - if (r->script) { - if (save && n->original->script == NULL) - n->original->script = n->script_count > 0 - ? g_strdup(n->scripts[0]) - : g_strdup(r->script); - - n->scripts = g_renew(char *, n->scripts, n->script_count + 2); - n->scripts[n->script_count] = g_strdup(r->script); - n->scripts[n->script_count + 1] = NULL; - n->script_count++; + if (save) + notification_keep_original(n); + + RULE_APPLY2(dbus_timeout, override_dbus_timeout, -1); + RULE_APPLY2(transient, set_transient, -1); + + RULE_APPLY(timeout, -1); + RULE_APPLY(urgency, URG_NONE); + RULE_APPLY(fullscreen, FS_NULL); + RULE_APPLY(history_ignore, -1); + RULE_APPLY(skip_display, -1); + RULE_APPLY(word_wrap, -1); + RULE_APPLY(ellipsize, -1); + RULE_APPLY(alignment, -1); + RULE_APPLY(hide_text, -1); + RULE_APPLY(progress_bar_alignment, -1); + RULE_APPLY(min_icon_size, -1); + RULE_APPLY(max_icon_size, -1); + RULE_APPLY(markup, MARKUP_NULL); + RULE_APPLY(icon_position, -1); + RULE_APPLY(override_pause_level, -1); + + if (COLOR_VALID(r->fg)) { + if (save && !COLOR_VALID(n->original->fg)) + n->original->fg = n->colors.fg; + n->colors.fg = r->fg; + } + if (COLOR_VALID(r->bg)) { + if (save && !COLOR_VALID(n->original->bg)) + n->original->bg = n->colors.bg; + n->colors.bg = r->bg; + } + if (r->highlight != NULL) { + if (save && n->original->highlight == NULL) { + n->original->highlight = gradient_acquire(n->colors.highlight); } + gradient_release(n->colors.highlight); + n->colors.highlight = gradient_acquire(r->highlight); + } + if (COLOR_VALID(r->fc)) { + if (save && !COLOR_VALID(n->original->fc)) + n->original->fc = n->colors.frame; + n->colors.frame = r->fc; + } + if (r->action_name) { + if (save && n->original->action_name == NULL) + n->original->action_name = n->default_action_name; + else + g_free(n->default_action_name); + + n->default_action_name = g_strdup(r->action_name); + } + if (r->set_category) { + if (save && n->original->set_category == NULL) + n->original->set_category = n->category; + else + g_free(n->category); + + n->category = g_strdup(r->set_category); + } + if (r->default_icon) { + if (save && n->original->default_icon == NULL) + n->original->default_icon = n->default_icon_name; + else + g_free(n->default_icon_name); + + n->default_icon_name = g_strdup(r->default_icon); + } + if (r->set_stack_tag) { + if (save && n->original->set_stack_tag == NULL) + n->original->set_stack_tag = n->stack_tag; + else + g_free(n->stack_tag); + + n->stack_tag = g_strdup(r->set_stack_tag); + } + if (r->new_icon) { + if (save && n->original->new_icon == NULL) + n->original->new_icon = g_strdup(n->iconname); + + // FIXME This is not efficient when the icon is replaced + // multiple times for the same notification. To fix this, a + // separate variable is needed to track if the icon is + // replaced, like in 86cbc1d34bb0f551461dbd466cd9e4860ae01817. + notification_icon_replace_path(n, r->new_icon); + n->receiving_raw_icon = false; + } + if (r->format != NULL) { + if (save && n->original->format == NULL) + n->original->format = n->format; + else + g_free(n->format); + + n->format = g_strdup(r->format); + } + if (r->script) { + if (save && n->original->script == NULL) + n->original->script = n->script_count > 0 ? g_strdup(n->scripts[0]) + : g_strdup(r->script); + + n->scripts = g_renew(char *, n->scripts, n->script_count + 2); + n->scripts[n->script_count] = g_strdup(r->script); + n->scripts[n->script_count + 1] = NULL; + n->script_count++; + } } void rule_print(const struct rule *r) { - printf("{\n"); - printf("\tname: '%s'\n", STR_NN(r->name)); - printf("\tenabled: %d\n", r->enabled); - - // filters - if (r->appname != NULL) printf("\tappname: '%s'\n", r->appname); - if (r->summary != NULL) printf("\tsummary: '%s'\n", r->summary); - if (r->body != NULL) printf("\tbody: '%s'\n", r->body); - if (r->icon != NULL) printf("\ticon: '%s'\n", r->icon); - if (r->category != NULL) printf("\tcategory: '%s'\n", r->category); - if (r->msg_urgency != URG_NONE) printf("\tmsg_urgency: '%s'\n", notification_urgency_to_string(r->msg_urgency)); - if (r->stack_tag != NULL) printf("\tstack_tag: '%s'\n", r->stack_tag); - if (r->desktop_entry != NULL) printf("\tdesktop_entry: '%s'\n", r->desktop_entry); - if (r->match_dbus_timeout != -1) printf("\tmatch_dbus_timeout: %"G_GINT64_FORMAT"\n", r->match_dbus_timeout); - if (r->match_transient != -1) printf("\tmatch_transient: %d\n", r->match_transient); - - // modifiers - if (r->timeout != -1) printf("\ttimeout: %"G_GINT64_FORMAT"\n", r->timeout); - if (r->override_dbus_timeout != -1) printf("\toverride_dbus_timeout: %"G_GINT64_FORMAT"\n", r->override_dbus_timeout); - if (r->markup != -1) printf("\tmarkup: %d\n", r->markup); - if (r->action_name != NULL) printf("\taction_name: '%s'\n", r->action_name); - if (r->urgency != URG_NONE) printf("\turgency: '%s'\n", notification_urgency_to_string(r->urgency)); - if (r->history_ignore != -1) printf("\thistory_ignore: %d\n", r->history_ignore); - if (r->set_transient != -1) printf("\tset_transient: %d\n", r->set_transient); - if (r->skip_display != -1) printf("\tskip_display: %d\n", r->skip_display); - if (r->word_wrap != -1) printf("\tword_wrap: %d\n", r->word_wrap); - if (r->ellipsize != -1) printf("\tellipsize: %d\n", r->ellipsize); - if (r->alignment != -1) printf("\talignment: %d\n", r->alignment); - if (r->hide_text != -1) printf("\thide_text: %d\n", r->hide_text); - if (r->icon_position != -1) printf("\ticon_position: %d\n", r->icon_position); - if (r->min_icon_size != -1) printf("\tmin_icon_size: %d\n", r->min_icon_size); - if (r->max_icon_size != -1) printf("\tmax_icon_size: %d\n", r->max_icon_size); - if (r->override_pause_level != -1) printf("\toverride_pause_level: %d\n", r->override_pause_level); - if (r->new_icon != NULL) printf("\tnew_icon: '%s'\n", r->new_icon); - if (r->default_icon != NULL) printf("\tdefault_icon: '%s'\n", r->default_icon); - - char buf[10]; - if (COLOR_VALID(r->fg)) printf("\tfg: %s\n", color_to_string(r->fg, buf)); - if (COLOR_VALID(r->bg)) printf("\tbg: %s\n", color_to_string(r->bg, buf)); - if (COLOR_VALID(r->fc)) printf("\tframe: %s\n", color_to_string(r->fc, buf)); - - char *grad = gradient_to_string(r->highlight); - printf("\thighlight: %s\n", STR_NN(grad)); - g_free(grad); - - if (r->set_category != NULL) printf("\tset_category: '%s'\n", r->set_category); - if (r->format != NULL) printf("\tformat: '%s'\n", r->format); - if (r->script != NULL) printf("\tscript: '%s'\n", r->script); - if (r->fullscreen != FS_NULL) printf("\tfullscreen: %s\n", enum_to_string_fullscreen(r->fullscreen)); - if (r->progress_bar_alignment != -1) printf("\tprogress_bar_alignment: %d\n", r->progress_bar_alignment); - if (r->set_stack_tag != NULL) printf("\tset_stack_tag: %s\n", r->set_stack_tag); - printf("}\n"); + printf("{\n"); + printf("\tname: '%s'\n", STR_NN(r->name)); + printf("\tenabled: %d\n", r->enabled); + + // filters + if (r->appname != NULL) + printf("\tappname: '%s'\n", r->appname); + if (r->summary != NULL) + printf("\tsummary: '%s'\n", r->summary); + if (r->body != NULL) + printf("\tbody: '%s'\n", r->body); + if (r->icon != NULL) + printf("\ticon: '%s'\n", r->icon); + if (r->category != NULL) + printf("\tcategory: '%s'\n", r->category); + if (r->msg_urgency != URG_NONE) + printf("\tmsg_urgency: '%s'\n", + notification_urgency_to_string(r->msg_urgency)); + if (r->stack_tag != NULL) + printf("\tstack_tag: '%s'\n", r->stack_tag); + if (r->desktop_entry != NULL) + printf("\tdesktop_entry: '%s'\n", r->desktop_entry); + if (r->match_dbus_timeout != -1) + printf("\tmatch_dbus_timeout: %" G_GINT64_FORMAT "\n", + r->match_dbus_timeout); + if (r->match_transient != -1) + printf("\tmatch_transient: %d\n", r->match_transient); + + // modifiers + if (r->timeout != -1) + printf("\ttimeout: %" G_GINT64_FORMAT "\n", r->timeout); + if (r->override_dbus_timeout != -1) + printf("\toverride_dbus_timeout: %" G_GINT64_FORMAT "\n", + r->override_dbus_timeout); + if (r->markup != -1) + printf("\tmarkup: %d\n", r->markup); + if (r->action_name != NULL) + printf("\taction_name: '%s'\n", r->action_name); + if (r->urgency != URG_NONE) + printf("\turgency: '%s'\n", notification_urgency_to_string(r->urgency)); + if (r->history_ignore != -1) + printf("\thistory_ignore: %d\n", r->history_ignore); + if (r->set_transient != -1) + printf("\tset_transient: %d\n", r->set_transient); + if (r->skip_display != -1) + printf("\tskip_display: %d\n", r->skip_display); + if (r->word_wrap != -1) + printf("\tword_wrap: %d\n", r->word_wrap); + if (r->ellipsize != -1) + printf("\tellipsize: %d\n", r->ellipsize); + if (r->alignment != -1) + printf("\talignment: %d\n", r->alignment); + if (r->hide_text != -1) + printf("\thide_text: %d\n", r->hide_text); + if (r->icon_position != -1) + printf("\ticon_position: %d\n", r->icon_position); + if (r->min_icon_size != -1) + printf("\tmin_icon_size: %d\n", r->min_icon_size); + if (r->max_icon_size != -1) + printf("\tmax_icon_size: %d\n", r->max_icon_size); + if (r->override_pause_level != -1) + printf("\toverride_pause_level: %d\n", r->override_pause_level); + if (r->new_icon != NULL) + printf("\tnew_icon: '%s'\n", r->new_icon); + if (r->default_icon != NULL) + printf("\tdefault_icon: '%s'\n", r->default_icon); + + char buf[10]; + if (COLOR_VALID(r->fg)) + printf("\tfg: %s\n", color_to_string(r->fg, buf)); + if (COLOR_VALID(r->bg)) + printf("\tbg: %s\n", color_to_string(r->bg, buf)); + if (COLOR_VALID(r->fc)) + printf("\tframe: %s\n", color_to_string(r->fc, buf)); + + char *grad = gradient_to_string(r->highlight); + printf("\thighlight: %s\n", STR_NN(grad)); + g_free(grad); + + if (r->set_category != NULL) + printf("\tset_category: '%s'\n", r->set_category); + if (r->format != NULL) + printf("\tformat: '%s'\n", r->format); + if (r->script != NULL) + printf("\tscript: '%s'\n", r->script); + if (r->fullscreen != FS_NULL) + printf("\tfullscreen: %s\n", enum_to_string_fullscreen(r->fullscreen)); + if (r->progress_bar_alignment != -1) + printf("\tprogress_bar_alignment: %d\n", r->progress_bar_alignment); + if (r->set_stack_tag != NULL) + printf("\tset_stack_tag: %s\n", r->set_stack_tag); + printf("}\n"); } /* @@ -196,114 +240,116 @@ void rule_print(const struct rule *r) */ void rule_apply_all(struct notification *n) { - for (GSList *iter = rules; iter; iter = iter->next) { - struct rule *r = iter->data; - if (rule_matches_notification(r, n)) { - rule_apply(r, n, true); - } + for (GSList *iter = rules; iter; iter = iter->next) { + struct rule *r = iter->data; + if (rule_matches_notification(r, n)) { + rule_apply(r, n, true); } + } } -bool rule_apply_special_filters(struct rule *r, const char *name) { - if (is_deprecated_section(name)) // shouldn't happen, but just in case - return false; - - if (strcmp(name, "global") == 0) { - // no filters for global section - return true; - } - if (strcmp(name, "urgency_low") == 0) { - r->msg_urgency = URG_LOW; - return true; - } - if (strcmp(name, "urgency_normal") == 0) { - r->msg_urgency = URG_NORM; - return true; - } - if (strcmp(name, "urgency_critical") == 0) { - r->msg_urgency = URG_CRIT; - return true; - } - +bool rule_apply_special_filters(struct rule *r, const char *name) +{ + if (is_deprecated_section(name)) // shouldn't happen, but just in case return false; + + if (strcmp(name, "global") == 0) { + // no filters for global section + return true; + } + if (strcmp(name, "urgency_low") == 0) { + r->msg_urgency = URG_LOW; + return true; + } + if (strcmp(name, "urgency_normal") == 0) { + r->msg_urgency = URG_NORM; + return true; + } + if (strcmp(name, "urgency_critical") == 0) { + r->msg_urgency = URG_CRIT; + return true; + } + + return false; } struct rule *rule_new(const char *name) { - struct rule *r = g_malloc0(sizeof(struct rule)); - *r = empty_rule; - rules = g_slist_insert(rules, r, -1); - r->name = g_strdup(name); - if (is_special_section(name)) { - bool success = rule_apply_special_filters(r, name); - if (!success) { - LOG_M("Could not apply special filters for section %s", name); - } + struct rule *r = g_malloc0(sizeof(struct rule)); + *r = empty_rule; + rules = g_slist_insert(rules, r, -1); + r->name = g_strdup(name); + if (is_special_section(name)) { + bool success = rule_apply_special_filters(r, name); + if (!success) { + LOG_M("Could not apply special filters for section %s", name); } - return r; + } + return r; } void rule_free(struct rule *r) { - if (r == NULL || r == &empty_rule) - return; - - g_free(r->name); - g_free(r->appname); - g_free(r->summary); - g_free(r->body); - g_free(r->icon); - g_free(r->category); - g_free(r->stack_tag); - g_free(r->desktop_entry); - - g_free(r->action_name); - g_free(r->new_icon); - g_free(r->default_icon); - gradient_release(r->highlight); - - g_free(r->set_category); - g_free(r->format); - g_free(r->script); - g_free(r->set_stack_tag); - - g_free(r); + if (r == NULL || r == &empty_rule) + return; + + g_free(r->name); + g_free(r->appname); + g_free(r->summary); + g_free(r->body); + g_free(r->icon); + g_free(r->category); + g_free(r->stack_tag); + g_free(r->desktop_entry); + + g_free(r->action_name); + g_free(r->new_icon); + g_free(r->default_icon); + gradient_release(r->highlight); + + g_free(r->set_category); + g_free(r->format); + g_free(r->script); + g_free(r->set_stack_tag); + + g_free(r); } - -static inline bool rule_field_matches_string(const char *value, const char *pattern) +static inline bool rule_field_matches_string(const char *value, + const char *pattern) { - if (settings.enable_regex) { - if (!pattern) { - return true; - } - if (!value) { - return false; - } - regex_t regex; - - // TODO compile each regex only once - int err = regcomp(®ex, pattern, REG_NEWLINE | REG_EXTENDED | REG_NOSUB); - if (err) { - size_t err_size = regerror(err, ®ex, NULL, 0); - char *err_buf = g_malloc(err_size); - regerror(err, ®ex, err_buf, err_size); - LOG_W("%s: \"%s\"", err_buf, pattern); - g_free(err_buf); - return false; - } - - while (true) { - if (regexec(®ex, value, 0, NULL, 0)) - break; - regfree(®ex); - return true; - } - regfree(®ex); - return false; - } else { - return !pattern || (value && !fnmatch(pattern, value, 0)); + if (settings.enable_regex) { + if (!pattern) { + return true; + } + if (!value) { + return false; + } + regex_t regex; + + // TODO compile each regex only once + int err = + regcomp(®ex, pattern, REG_NEWLINE | REG_EXTENDED | REG_NOSUB); + if (err) { + size_t err_size = regerror(err, ®ex, NULL, 0); + char *err_buf = g_malloc(err_size); + regerror(err, ®ex, err_buf, err_size); + LOG_W("%s: \"%s\"", err_buf, pattern); + g_free(err_buf); + return false; + } + + while (true) { + if (regexec(®ex, value, 0, NULL, 0)) + break; + regfree(®ex); + return true; } + regfree(®ex); + return false; + } else { + return !pattern || (value && !fnmatch(pattern, value, 0)); + } } /* @@ -311,46 +357,50 @@ static inline bool rule_field_matches_string(const char *value, const char *patt */ bool rule_matches_notification(struct rule *r, struct notification *n) { - return r->enabled - && (r->msg_urgency == URG_NONE || r->msg_urgency == n->urgency) - && (r->match_dbus_timeout < 0 || (r->match_dbus_timeout == n->dbus_timeout)) - && (r->match_transient == -1 || (r->match_transient == n->transient)) - && rule_field_matches_string(n->appname, r->appname) - && rule_field_matches_string(n->desktop_entry, r->desktop_entry) - && rule_field_matches_string(n->summary, r->summary) - && rule_field_matches_string(n->body, r->body) - && rule_field_matches_string(n->iconname, r->icon) - && rule_field_matches_string(n->category, r->category) - && rule_field_matches_string(n->stack_tag, r->stack_tag); + return r->enabled + && (r->msg_urgency == URG_NONE || r->msg_urgency == n->urgency) + && (r->match_dbus_timeout < 0 + || (r->match_dbus_timeout == n->dbus_timeout)) + && (r->match_transient == -1 || (r->match_transient == n->transient)) + && rule_field_matches_string(n->appname, r->appname) + && rule_field_matches_string(n->desktop_entry, r->desktop_entry) + && rule_field_matches_string(n->summary, r->summary) + && rule_field_matches_string(n->body, r->body) + && rule_field_matches_string(n->iconname, r->icon) + && rule_field_matches_string(n->category, r->category) + && rule_field_matches_string(n->stack_tag, r->stack_tag); } /** * Check if a rule exists with that name */ -struct rule *get_rule(const char* name) { - for (GSList *iter = rules; iter; iter = iter->next) { - struct rule *r = iter->data; - if (r->name && STR_EQ(r->name, name)) - return r; - } - return NULL; +struct rule *get_rule(const char *name) +{ + for (GSList *iter = rules; iter; iter = iter->next) { + struct rule *r = iter->data; + if (r->name && STR_EQ(r->name, name)) + return r; + } + return NULL; } /** * see rules.h */ -bool rule_offset_is_modifying(const size_t offset) { - const size_t first_action = offsetof(struct rule, timeout); - const size_t last_action = offsetof(struct rule, set_stack_tag); - return (offset >= first_action) && (offset <= last_action); +bool rule_offset_is_modifying(const size_t offset) +{ + const size_t first_action = offsetof(struct rule, timeout); + const size_t last_action = offsetof(struct rule, set_stack_tag); + return (offset >= first_action) && (offset <= last_action); } /** * see rules.h */ -bool rule_offset_is_filter(const size_t offset) { - const size_t first_filter = offsetof(struct rule, appname); - return (offset >= first_filter) && !rule_offset_is_modifying(offset); +bool rule_offset_is_filter(const size_t offset) +{ + const size_t first_filter = offsetof(struct rule, appname); + return (offset >= first_filter) && !rule_offset_is_modifying(offset); } /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/rules.h b/src/rules.h index 463078ebc..069810328 100644 --- a/src/rules.h +++ b/src/rules.h @@ -1,4 +1,5 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ #ifndef DUNST_RULES_H #define DUNST_RULES_H @@ -8,57 +9,58 @@ #include "notification.h" #include "settings.h" -struct rule { - // Since there's heavy use of offsets from this class, both in rules.c - // and in settings_data.h the layout of the class should not be - // changed, unless it's well considered and tested. See the comments - // below for what should not be changed. +struct rule +{ + // Since there's heavy use of offsets from this class, both in rules.c + // and in settings_data.h the layout of the class should not be + // changed, unless it's well considered and tested. See the comments + // below for what should not be changed. - // This has to be the first member, see struct setting.rule_offset. - char *name; + // This has to be the first member, see struct setting.rule_offset. + char *name; - /* filters */ - char *appname; // this has to be the first filter, see rules.c - char *summary; - char *body; - char *icon; - char *category; - char *stack_tag; - char *desktop_entry; - int msg_urgency; - gint64 match_dbus_timeout; + /* filters */ + char *appname; // this has to be the first filter, see rules.c + char *summary; + char *body; + char *icon; + char *category; + char *stack_tag; + char *desktop_entry; + int msg_urgency; + gint64 match_dbus_timeout; - /* modifying */ - gint64 timeout; // this has to be the first modifying rule - gint64 override_dbus_timeout; - enum urgency urgency; - char *action_name; - enum markup_mode markup; - gint history_ignore; - gint match_transient; - gint set_transient; - gint skip_display; - gint word_wrap; - int ellipsize; - int alignment; - gint hide_text; - int icon_position; - int min_icon_size; - int max_icon_size; - int override_pause_level; - char *new_icon; - char *default_icon; - struct color fg; - struct color bg; - struct gradient *highlight; - struct color fc; - char *set_category; - char *format; - char *script; - enum behavior_fullscreen fullscreen; - bool enabled; - int progress_bar_alignment; - char *set_stack_tag; // this has to be the last modifying rule + /* modifying */ + gint64 timeout; // this has to be the first modifying rule + gint64 override_dbus_timeout; + enum urgency urgency; + char *action_name; + enum markup_mode markup; + gint history_ignore; + gint match_transient; + gint set_transient; + gint skip_display; + gint word_wrap; + int ellipsize; + int alignment; + gint hide_text; + int icon_position; + int min_icon_size; + int max_icon_size; + int override_pause_level; + char *new_icon; + char *default_icon; + struct color fg; + struct color bg; + struct gradient *highlight; + struct color fc; + char *set_category; + char *format; + char *script; + enum behavior_fullscreen fullscreen; + bool enabled; + int progress_bar_alignment; + char *set_stack_tag; // this has to be the last modifying rule }; extern GSList *rules; @@ -87,7 +89,7 @@ bool rule_matches_notification(struct rule *r, struct notification *n); * * @returns the rule that matches. Null if no rule matches */ -struct rule *get_rule(const char* name); +struct rule *get_rule(const char *name); /** * Check if a rule is an action diff --git a/src/settings.c b/src/settings.c index 9383a24dd..ce585ed19 100644 --- a/src/settings.c +++ b/src/settings.c @@ -1,4 +1,5 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ /** @file src/settings.c * @brief Take care of the settings. @@ -14,13 +15,13 @@ #include #include "dunst.h" +#include "ini.h" #include "log.h" #include "notification.h" #include "option_parser.h" -#include "ini.h" +#include "output.h" #include "rules.h" #include "utils.h" -#include "output.h" #ifndef SYSCONFDIR /** @brief Fallback for doxygen, mostly. @@ -43,10 +44,11 @@ bool print_notifications = false; * * @param dent [in] @brief directory entry */ -static int is_drop_in(const struct dirent *dent) { - return 0 == fnmatch("*.conf", dent->d_name, FNM_PATHNAME | FNM_PERIOD) - ? 1 // success - : 0; +static int is_drop_in(const struct dirent *dent) +{ + return 0 == fnmatch("*.conf", dent->d_name, FNM_PATHNAME | FNM_PERIOD) + ? 1 // success + : 0; } /** @brief Get all relevant config base directories @@ -60,48 +62,51 @@ static int is_drop_in(const struct dirent *dent) { * The result @e must @e not be freed! The array is cached in a static variable, * so it is OK to call this again instead of caching its return value. */ -static GPtrArray *get_xdg_conf_basedirs(void) { - GPtrArray *arr = g_ptr_array_new_full(4, g_free); - g_ptr_array_add(arr, g_build_filename(g_get_user_config_dir(), "dunst", NULL)); - - /* - * A default of SYSCONFDIR is set to separate installs to a - * local PREFIX. With this default /usr/local/etc/xdg is set a - * system-wide config location and not /etc/xdg. Users/admins - * can override this by explicitly setting XDG_CONFIG_DIRS to - * their liking at runtime or by setting SYSCONFDIR=/etc/xdg at - * compile time. - */ - add_paths_from_env(arr, "XDG_CONFIG_DIRS", "dunst", SYSCONFDIR); - return arr; +static GPtrArray *get_xdg_conf_basedirs(void) +{ + GPtrArray *arr = g_ptr_array_new_full(4, g_free); + g_ptr_array_add(arr, + g_build_filename(g_get_user_config_dir(), "dunst", NULL)); + + /* + * A default of SYSCONFDIR is set to separate installs to a + * local PREFIX. With this default /usr/local/etc/xdg is set a + * system-wide config location and not /etc/xdg. Users/admins + * can override this by explicitly setting XDG_CONFIG_DIRS to + * their liking at runtime or by setting SYSCONFDIR=/etc/xdg at + * compile time. + */ + add_paths_from_env(arr, "XDG_CONFIG_DIRS", "dunst", SYSCONFDIR); + return arr; } -static void config_files_add_drop_ins(GPtrArray *config_files, const char *path) { - int insert_index = config_files->len; - if (insert_index == 0) { - // there is no base config file - return; - } - char *drop_in_dir = g_strconcat(path, ".d", NULL); - struct dirent **drop_ins = NULL; - int n = scandir(drop_in_dir, &drop_ins, is_drop_in, alphasort); - - if (n == -1) { - // Scandir error. Most likely the directory doesn't exist. - g_free(drop_in_dir); - return; - } - - while (n--) { - char *drop_in = g_strconcat(drop_in_dir, "/", - drop_ins[n]->d_name, NULL); - LOG_D("Found drop-in: %s\n", drop_in); - g_ptr_array_insert(config_files, insert_index, drop_in); - g_free(drop_ins[n]); - } - +static void config_files_add_drop_ins(GPtrArray *config_files, const char *path) +{ + int insert_index = config_files->len; + if (insert_index == 0) { + // there is no base config file + return; + } + char *drop_in_dir = g_strconcat(path, ".d", NULL); + struct dirent **drop_ins = NULL; + int n = scandir(drop_in_dir, &drop_ins, is_drop_in, alphasort); + + if (n == -1) { + // Scandir error. Most likely the directory doesn't exist. g_free(drop_in_dir); - g_free(drop_ins); + return; + } + + while (n--) { + char *drop_in = + g_strconcat(drop_in_dir, "/", drop_ins[n]->d_name, NULL); + LOG_D("Found drop-in: %s\n", drop_in); + g_ptr_array_insert(config_files, insert_index, drop_in); + g_free(drop_ins[n]); + } + + g_free(drop_in_dir); + g_free(drop_ins); } /** @brief Find all config files. @@ -111,214 +116,233 @@ static void config_files_add_drop_ins(GPtrArray *config_files, const char *path) * * The returned GPtrArray and it's elements are owned by the caller. */ -static GPtrArray* get_conf_files(void) { - GPtrArray *config_locations = get_xdg_conf_basedirs(); - GPtrArray *config_files = g_ptr_array_new_full(3, g_free); - char *dunstrc_location = NULL; - for (size_t i = 0; i < config_locations->len; i++) { - dunstrc_location = g_build_filename(config_locations->pdata[i], - "dunstrc", NULL); - LOG_D("Trying config location: %s", dunstrc_location); - if (is_readable_file(dunstrc_location)) { - g_ptr_array_add(config_files, dunstrc_location); - break; - } +static GPtrArray *get_conf_files(void) +{ + GPtrArray *config_locations = get_xdg_conf_basedirs(); + GPtrArray *config_files = g_ptr_array_new_full(3, g_free); + char *dunstrc_location = NULL; + for (size_t i = 0; i < config_locations->len; i++) { + dunstrc_location = + g_build_filename(config_locations->pdata[i], "dunstrc", NULL); + LOG_D("Trying config location: %s", dunstrc_location); + if (is_readable_file(dunstrc_location)) { + g_ptr_array_add(config_files, dunstrc_location); + break; } + } - config_files_add_drop_ins(config_files, dunstrc_location); + config_files_add_drop_ins(config_files, dunstrc_location); - g_ptr_array_unref(config_locations); - return config_files; + g_ptr_array_unref(config_locations); + return config_files; } -FILE *fopen_conf(char * const path) +FILE *fopen_conf(char *const path) { - FILE *f = NULL; - char *real_path = string_to_path(g_strdup(path)); + FILE *f = NULL; + char *real_path = string_to_path(g_strdup(path)); - if (is_readable_file(real_path) && NULL != (f = fopen(real_path, "r"))) - LOG_I(MSG_FOPEN_SUCCESS(path, f)); - else - LOG_W(MSG_FOPEN_FAILURE(path)); + if (is_readable_file(real_path) && NULL != (f = fopen(real_path, "r"))) + LOG_I(MSG_FOPEN_SUCCESS(path, f)); + else + LOG_W(MSG_FOPEN_FAILURE(path)); - g_free(real_path); - return f; + g_free(real_path); + return f; } -void check_and_correct_settings(struct settings *s) { +void check_and_correct_settings(struct settings *s) +{ #ifndef ENABLE_WAYLAND - if (is_running_wayland()) { - /* We are using xwayland now. Setting force_xwayland to make sure - * the idle workaround below is activated */ - settings.force_xwayland = true; - } + if (is_running_wayland()) { + /* We are using xwayland now. Setting force_xwayland to make sure + * the idle workaround below is activated */ + settings.force_xwayland = true; + } #endif - if (settings.force_xwayland && is_running_wayland()) { - if (settings.idle_threshold > 0) - LOG_W("Using xwayland. Disabling idle."); - /* There is no way to detect if the user is idle - * on xwayland, so turn this feature off */ - settings.idle_threshold = 0; - } - - // check sanity of the progress bar options - { - if (s->progress_bar_height < (2 * s->progress_bar_frame_width)) { - DIE("setting progress_bar_frame_width is bigger than half of progress_bar_height"); - } - if (s->progress_bar_max_width < (2 * s->progress_bar_frame_width)) { - DIE("setting progress_bar_frame_width is bigger than half of progress_bar_max_width"); - } - if (s->progress_bar_max_width < s->progress_bar_min_width) { - DIE("setting progress_bar_max_width is smaller than progress_bar_min_width"); - } - if (s->progress_bar_min_width > s->width.max) { - LOG_W("Progress bar min width is greater than the max width of the notification"); - } - int progress_bar_max_corner_radius = (s->progress_bar_height / 2); - if (s->progress_bar_corner_radius > progress_bar_max_corner_radius) { - settings.progress_bar_corner_radius = progress_bar_max_corner_radius; - LOG_W("Progress bar corner radius clamped to half of progress bar height (%i)", - progress_bar_max_corner_radius); - } + if (settings.force_xwayland && is_running_wayland()) { + if (settings.idle_threshold > 0) + LOG_W("Using xwayland. Disabling idle."); + /* There is no way to detect if the user is idle + * on xwayland, so turn this feature off */ + settings.idle_threshold = 0; + } + + // check sanity of the progress bar options + { + if (s->progress_bar_height < (2 * s->progress_bar_frame_width)) { + DIE("setting progress_bar_frame_width is bigger than half of " + "progress_bar_height"); } - - // check lengths - if (s->width.min == INT_MIN) { - s->width.min = 0; + if (s->progress_bar_max_width < (2 * s->progress_bar_frame_width)) { + DIE("setting progress_bar_frame_width is bigger than half of " + "progress_bar_max_width"); } - if (s->width.min < 0 || s->width.max < 0) { - DIE("setting width does not support negative values"); - } - if (s->width.min > s->width.max) { - DIE("setting width min (%i) is always greather than max (%i)", s->width.min, s->width.max); - } - - if (s->height.min == INT_MIN) { - s->height.min = 0; + if (s->progress_bar_max_width < s->progress_bar_min_width) { + DIE("setting progress_bar_max_width is smaller than " + "progress_bar_min_width"); } - if (s->height.min < 0 || s->height.max < 0) { - DIE("setting height does not support negative values"); + if (s->progress_bar_min_width > s->width.max) { + LOG_W("Progress bar min width is greater than the max width of the " + "notification"); } - if (s->height.min > s->height.max) { - DIE("setting height min (%i) is always greather than max (%i)", s->height.min, s->height.max); + int progress_bar_max_corner_radius = (s->progress_bar_height / 2); + if (s->progress_bar_corner_radius > progress_bar_max_corner_radius) { + settings.progress_bar_corner_radius = + progress_bar_max_corner_radius; + LOG_W("Progress bar corner radius clamped to half of progress bar " + "height (%i)", + progress_bar_max_corner_radius); } - - if (s->offset.x == INT_MIN || s->offset.y == INT_MAX) { - DIE("setting offset needs both horizontal and vertical values"); - } - - // TODO Implement this with icon sizes as rules - - // restrict the icon size to a reasonable limit if we have a fixed width. - // Otherwise the layout will be broken by too large icons. - // See https://github.com/dunst-project/dunst/issues/540 - // if (s->width.max > 0) { - // const int icon_size_limit = s->width.max / 2; - // if ( s->max_icon_size == 0 - // || s->max_icon_size > icon_size_limit) { - // if (s->max_icon_size != 0) { - // LOG_W("Max width was set to %d but got a max_icon_size of %d, too large to use. Setting max_icon_size=%d", - // s->width.max, s->max_icon_size, icon_size_limit); - // } else { - // LOG_I("Max width was set but max_icon_size is unlimited. Limiting icons to %d pixels", icon_size_limit); - // } - - // s->max_icon_size = icon_size_limit; - // } - // } - - // int text_icon_padding = settings.text_icon_padding != 0 ? settings.text_icon_padding : settings.h_padding; - // int max_text_width = settings.width.max - settings.max_icon_size - text_icon_padding - 2 * settings.h_padding; - // if (max_text_width < 10) { - // DIE("max_icon_size and horizontal padding are too large for the given width"); - // } - + } + + // check lengths + if (s->width.min == INT_MIN) { + s->width.min = 0; + } + if (s->width.min < 0 || s->width.max < 0) { + DIE("setting width does not support negative values"); + } + if (s->width.min > s->width.max) { + DIE("setting width min (%i) is always greather than max (%i)", + s->width.min, + s->width.max); + } + + if (s->height.min == INT_MIN) { + s->height.min = 0; + } + if (s->height.min < 0 || s->height.max < 0) { + DIE("setting height does not support negative values"); + } + if (s->height.min > s->height.max) { + DIE("setting height min (%i) is always greather than max (%i)", + s->height.min, + s->height.max); + } + + if (s->offset.x == INT_MIN || s->offset.y == INT_MAX) { + DIE("setting offset needs both horizontal and vertical values"); + } + + // TODO Implement this with icon sizes as rules + + // restrict the icon size to a reasonable limit if we have a fixed width. + // Otherwise the layout will be broken by too large icons. + // See https://github.com/dunst-project/dunst/issues/540 + // if (s->width.max > 0) { + // const int icon_size_limit = s->width.max / 2; + // if ( s->max_icon_size == 0 + // || s->max_icon_size > icon_size_limit) { + // if (s->max_icon_size != 0) { + // LOG_W("Max width was set to %d but got a + // max_icon_size of %d, too large to use. Setting + // max_icon_size=%d", + // s->width.max, s->max_icon_size, + // icon_size_limit); + // } else { + // LOG_I("Max width was set but max_icon_size is + // unlimited. Limiting icons to %d pixels", + // icon_size_limit); + // } + + // s->max_icon_size = icon_size_limit; + // } + // } + + // int text_icon_padding = settings.text_icon_padding != 0 ? + // settings.text_icon_padding : settings.h_padding; int max_text_width = + // settings.width.max - settings.max_icon_size - text_icon_padding - 2 * + // settings.h_padding; if (max_text_width < 10) { + // DIE("max_icon_size and horizontal padding are too large for the + // given width"); + // } } -static void process_conf_file(const gpointer conf_fname, gpointer n_success) { - const gchar * const p = conf_fname; +static void process_conf_file(const gpointer conf_fname, gpointer n_success) +{ + const gchar *const p = conf_fname; - LOG_D("Reading config file '%s'", p); - /* Check for "-" here, so the file handling stays in one place */ - FILE *f = STR_EQ(p, "-") ? stdin : fopen_verbose(p); - if (!f) - return; + LOG_D("Reading config file '%s'", p); + /* Check for "-" here, so the file handling stays in one place */ + FILE *f = STR_EQ(p, "-") ? stdin : fopen_verbose(p); + if (!f) + return; - struct ini *ini = load_ini_file(f); - fclose(f); + struct ini *ini = load_ini_file(f); + fclose(f); - LOG_D("Loading settings"); - save_settings(ini); + LOG_D("Loading settings"); + save_settings(ini); - LOG_D("Checking/correcting settings"); - check_and_correct_settings(&settings); + LOG_D("Checking/correcting settings"); + check_and_correct_settings(&settings); - finish_ini(ini); - g_free(ini); + finish_ini(ini); + g_free(ini); - ++(*(int *) n_success); + ++(*(int *)n_success); } void load_settings(char **const paths) { - LOG_D("Setting defaults"); - set_defaults(); + LOG_D("Setting defaults"); + set_defaults(); - guint length = g_strv_length(paths); + guint length = g_strv_length(paths); - GPtrArray *conf_files; + GPtrArray *conf_files; - if (length != 0) { - conf_files = g_ptr_array_new_full(length, g_free); - for (int i = 0; paths[i]; i++) - g_ptr_array_add(conf_files, g_strdup(paths[i])); - } else { - // Use default locations (and search drop-ins) - conf_files = get_conf_files(); - } + if (length != 0) { + conf_files = g_ptr_array_new_full(length, g_free); + for (int i = 0; paths[i]; i++) + g_ptr_array_add(conf_files, g_strdup(paths[i])); + } else { + // Use default locations (and search drop-ins) + conf_files = get_conf_files(); + } - /* Load all conf files and drop-ins, least important first. */ - int n_loaded_confs = 0; - g_ptr_array_foreach(conf_files, process_conf_file, &n_loaded_confs); + /* Load all conf files and drop-ins, least important first. */ + int n_loaded_confs = 0; + g_ptr_array_foreach(conf_files, process_conf_file, &n_loaded_confs); - if (0 == n_loaded_confs) - LOG_M("No configuration file found, using defaults"); + if (0 == n_loaded_confs) + LOG_M("No configuration file found, using defaults"); - g_ptr_array_unref(conf_files); + g_ptr_array_unref(conf_files); } void settings_free(struct settings *s) { - gradient_release(s->colors_low.highlight); - gradient_release(s->colors_norm.highlight); - gradient_release(s->colors_crit.highlight); - - g_free(s->font); - g_free(s->format); - g_free(s->icons[0]); - g_free(s->icons[1]); - g_free(s->icons[2]); - g_free(s->title); - g_free(s->class); - g_free(s->monitor); - g_free(s->dmenu); - g_strfreev(s->dmenu_cmd); - g_free(s->browser); - g_strfreev(s->browser_cmd); - g_strfreev(s->icon_theme); - g_free(s->icon_path); - - g_free(s->mouse_left_click); - g_free(s->mouse_middle_click); - g_free(s->mouse_right_click); - - g_free(s->close_ks.str); - g_free(s->close_all_ks.str); - g_free(s->history_ks.str); - g_free(s->context_ks.str); + gradient_release(s->colors_low.highlight); + gradient_release(s->colors_norm.highlight); + gradient_release(s->colors_crit.highlight); + + g_free(s->font); + g_free(s->format); + g_free(s->icons[0]); + g_free(s->icons[1]); + g_free(s->icons[2]); + g_free(s->title); + g_free(s->class); + g_free(s->monitor); + g_free(s->dmenu); + g_strfreev(s->dmenu_cmd); + g_free(s->browser); + g_strfreev(s->browser_cmd); + g_strfreev(s->icon_theme); + g_free(s->icon_path); + + g_free(s->mouse_left_click); + g_free(s->mouse_middle_click); + g_free(s->mouse_right_click); + + g_free(s->close_ks.str); + g_free(s->close_all_ks.str); + g_free(s->history_ks.str); + g_free(s->context_ks.str); } /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/settings.h b/src/settings.h index 653c8623c..c1b3879c3 100644 --- a/src/settings.h +++ b/src/settings.h @@ -1,4 +1,5 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ #ifndef DUNST_SETTINGS_H #define DUNST_SETTINGS_H @@ -13,170 +14,233 @@ #endif // Note: Wayland doesn't support hotkeys -struct keyboard_shortcut { - char *str; +struct keyboard_shortcut +{ + char *str; #ifdef ENABLE_X11 - KeyCode code; - KeySym sym; - KeySym mask; - bool is_valid; + KeyCode code; + KeySym sym; + KeySym mask; + bool is_valid; #endif }; -#include "notification.h" #include "draw.h" +#include "notification.h" #define LIST_END (-1) -enum alignment { ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT }; -enum sort_type { SORT_TYPE_ID, SORT_TYPE_URGENCY_ASCENDING, SORT_TYPE_URGENCY_DESCENDING, SORT_TYPE_UPDATE }; -enum vertical_alignment { VERTICAL_TOP, VERTICAL_CENTER, VERTICAL_BOTTOM }; -enum separator_color { SEP_FOREGROUND, SEP_AUTO, SEP_FRAME, SEP_CUSTOM }; -enum follow_mode { FOLLOW_NONE, FOLLOW_MOUSE, FOLLOW_KEYBOARD }; -enum mouse_action { MOUSE_NONE, MOUSE_DO_ACTION, MOUSE_CLOSE_CURRENT, - MOUSE_CLOSE_ALL, MOUSE_CONTEXT, MOUSE_CONTEXT_ALL, MOUSE_OPEN_URL, - MOUSE_ACTION_END = LIST_END /* indicates the end of a list of mouse actions */}; +enum alignment +{ + ALIGN_LEFT, + ALIGN_CENTER, + ALIGN_RIGHT +}; +enum sort_type +{ + SORT_TYPE_ID, + SORT_TYPE_URGENCY_ASCENDING, + SORT_TYPE_URGENCY_DESCENDING, + SORT_TYPE_UPDATE +}; +enum vertical_alignment +{ + VERTICAL_TOP, + VERTICAL_CENTER, + VERTICAL_BOTTOM +}; +enum separator_color +{ + SEP_FOREGROUND, + SEP_AUTO, + SEP_FRAME, + SEP_CUSTOM +}; +enum follow_mode +{ + FOLLOW_NONE, + FOLLOW_MOUSE, + FOLLOW_KEYBOARD +}; +enum mouse_action +{ + MOUSE_NONE, + MOUSE_DO_ACTION, + MOUSE_CLOSE_CURRENT, + MOUSE_CLOSE_ALL, + MOUSE_CONTEXT, + MOUSE_CONTEXT_ALL, + MOUSE_OPEN_URL, + MOUSE_ACTION_END = + LIST_END /* indicates the end of a list of mouse actions */ +}; #ifndef ZWLR_LAYER_SHELL_V1_LAYER_ENUM #define ZWLR_LAYER_SHELL_V1_LAYER_ENUM // Needed for compiling without wayland dependency -enum zwlr_layer_shell_v1_layer { - ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND = 0, - ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM = 1, - ZWLR_LAYER_SHELL_V1_LAYER_TOP = 2, - ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY = 3, +enum zwlr_layer_shell_v1_layer +{ + ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND = 0, + ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM = 1, + ZWLR_LAYER_SHELL_V1_LAYER_TOP = 2, + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY = 3, }; #endif /* ZWLR_LAYER_SHELL_V1_LAYER_ENUM */ #ifndef ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM #define ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM -enum zwlr_layer_surface_v1_anchor { - /** - * the top edge of the anchor rectangle - */ - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP = 1, - /** - * the bottom edge of the anchor rectangle - */ - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM = 2, - /** - * the left edge of the anchor rectangle - */ - ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT = 4, - /** - * the right edge of the anchor rectangle - */ - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT = 8, +enum zwlr_layer_surface_v1_anchor +{ + /** + * the top edge of the anchor rectangle + */ + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP = 1, + /** + * the bottom edge of the anchor rectangle + */ + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM = 2, + /** + * the left edge of the anchor rectangle + */ + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT = 4, + /** + * the right edge of the anchor rectangle + */ + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT = 8, }; #endif /* ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM */ -enum origin_values { - ORIGIN_TOP_LEFT = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT, - ORIGIN_TOP_CENTER = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, - ORIGIN_TOP_RIGHT = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, - ORIGIN_BOTTOM_LEFT = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT, - ORIGIN_BOTTOM_CENTER = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, - ORIGIN_BOTTOM_RIGHT = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, - ORIGIN_LEFT_CENTER = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT, - ORIGIN_RIGHT_CENTER = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, - ORIGIN_CENTER = 0, +enum origin_values +{ + ORIGIN_TOP_LEFT = + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT, + ORIGIN_TOP_CENTER = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, + ORIGIN_TOP_RIGHT = + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, + ORIGIN_BOTTOM_LEFT = + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT, + ORIGIN_BOTTOM_CENTER = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, + ORIGIN_BOTTOM_RIGHT = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM + | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, + ORIGIN_LEFT_CENTER = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT, + ORIGIN_RIGHT_CENTER = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, + ORIGIN_CENTER = 0, }; -// TODO make a TYPE_CMD, instead of using TYPE_PATH for settings like dmenu and browser -enum setting_type { TYPE_MIN = 0, TYPE_INT, TYPE_DOUBLE, TYPE_STRING, - TYPE_PATH, TYPE_TIME, TYPE_LIST, TYPE_CUSTOM, TYPE_LENGTH, TYPE_COLOR, - TYPE_GRADIENT, TYPE_DEPRECATED, TYPE_MAX = TYPE_DEPRECATED + 1 }; // to be implemented - -struct separator_color_data { - enum separator_color type; - struct color color; +// TODO make a TYPE_CMD, instead of using TYPE_PATH for settings like dmenu and +// browser +enum setting_type +{ + TYPE_MIN = 0, + TYPE_INT, + TYPE_DOUBLE, + TYPE_STRING, + TYPE_PATH, + TYPE_TIME, + TYPE_LIST, + TYPE_CUSTOM, + TYPE_LENGTH, + TYPE_COLOR, + TYPE_GRADIENT, + TYPE_DEPRECATED, + TYPE_MAX = TYPE_DEPRECATED + 1 +}; // to be implemented + +struct separator_color_data +{ + enum separator_color type; + struct color color; }; -struct length { - int min; - int max; +struct length +{ + int min; + int max; }; -struct position { - int x; - int y; +struct position +{ + int x; + int y; }; -struct settings { - bool print_notifications; - bool per_monitor_dpi; - bool stack_duplicates; - bool hide_duplicate_count; - char *font; - struct notification_colors colors_low; - struct notification_colors colors_norm; - struct notification_colors colors_crit; - char *format; - gint64 timeouts[3]; - char *icons[3]; - unsigned int transparency; - char *title; - char *class; - int shrink; - enum sort_type sort; - int indicate_hidden; - gint64 idle_threshold; - gint64 show_age_threshold; - enum alignment align; - int sticky_history; - int history_length; - int show_indicators; - int ignore_dbusclose; - int ignore_newline; - int line_height; - int separator_height; - int padding; - int h_padding; - int text_icon_padding; - struct separator_color_data sep_color; - int frame_width; - struct color frame_color; - int startup_notification; - char *monitor; - int monitor_num; - double scale; - char *dmenu; - char **dmenu_cmd; - char *browser; - char **browser_cmd; - enum vertical_alignment vertical_alignment; - char **icon_theme; // experimental - bool enable_recursive_icon_lookup; // experimental - bool enable_regex; // experimental - char *icon_path; - enum follow_mode f_mode; - bool always_run_script; - struct keyboard_shortcut close_ks; - struct keyboard_shortcut close_all_ks; - struct keyboard_shortcut history_ks; - struct keyboard_shortcut context_ks; - bool force_xinerama; - bool force_xwayland; - int corner_radius; - enum mouse_action *mouse_left_click; - enum mouse_action *mouse_middle_click; - enum mouse_action *mouse_right_click; - int progress_bar_height; - int progress_bar_min_width; - int progress_bar_max_width; - int progress_bar_frame_width; - int progress_bar_corner_radius; - int icon_corner_radius; - enum corner_pos corners; - enum corner_pos icon_corners; - enum corner_pos progress_bar_corners; - bool progress_bar; - enum zwlr_layer_shell_v1_layer layer; - enum origin_values origin; - struct length width; - struct length height; - struct position offset; // NOTE: we rely on the fact that lenght and position are similar - int notification_limit; - int gap_size; +struct settings +{ + bool print_notifications; + bool per_monitor_dpi; + bool stack_duplicates; + bool hide_duplicate_count; + char *font; + struct notification_colors colors_low; + struct notification_colors colors_norm; + struct notification_colors colors_crit; + char *format; + gint64 timeouts[3]; + char *icons[3]; + unsigned int transparency; + char *title; + char *class; + int shrink; + enum sort_type sort; + int indicate_hidden; + gint64 idle_threshold; + gint64 show_age_threshold; + enum alignment align; + int sticky_history; + int history_length; + int show_indicators; + int ignore_dbusclose; + int ignore_newline; + int line_height; + int separator_height; + int padding; + int h_padding; + int text_icon_padding; + struct separator_color_data sep_color; + int frame_width; + struct color frame_color; + int startup_notification; + char *monitor; + int monitor_num; + double scale; + char *dmenu; + char **dmenu_cmd; + char *browser; + char **browser_cmd; + enum vertical_alignment vertical_alignment; + char **icon_theme; // experimental + bool enable_recursive_icon_lookup; // experimental + bool enable_regex; // experimental + char *icon_path; + enum follow_mode f_mode; + bool always_run_script; + struct keyboard_shortcut close_ks; + struct keyboard_shortcut close_all_ks; + struct keyboard_shortcut history_ks; + struct keyboard_shortcut context_ks; + bool force_xinerama; + bool force_xwayland; + int corner_radius; + enum mouse_action *mouse_left_click; + enum mouse_action *mouse_middle_click; + enum mouse_action *mouse_right_click; + int progress_bar_height; + int progress_bar_min_width; + int progress_bar_max_width; + int progress_bar_frame_width; + int progress_bar_corner_radius; + int icon_corner_radius; + enum corner_pos corners; + enum corner_pos icon_corners; + enum corner_pos progress_bar_corners; + bool progress_bar; + enum zwlr_layer_shell_v1_layer layer; + enum origin_values origin; + struct length width; + struct length height; + struct position offset; // NOTE: we rely on the fact that lenght and + // position are similar + int notification_limit; + int gap_size; }; extern struct settings settings; diff --git a/src/settings_data.h b/src/settings_data.h index eb6f33cfc..2dd8ffce0 100644 --- a/src/settings_data.h +++ b/src/settings_data.h @@ -1,114 +1,115 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ #ifndef DUNST_SETTING_DATA_H #define DUNST_SETTING_DATA_H -#include #include +#include #include "option_parser.h" -#include "settings.h" #include "rules.h" +#include "settings.h" -struct string_to_enum_def { - const char* string; - const int enum_value; +struct string_to_enum_def +{ + const char *string; + const int enum_value; }; -struct setting { - /** - * A string with the setting key as found in the config file. - */ - char *name; +struct setting +{ + /** + * A string with the setting key as found in the config file. + */ + char *name; - /** - * A string with the ini section where the variable is allowed. This - * section should be part of the special_sections array. - * - * Example: - * .section = "global", - */ - char *section; + /** + * A string with the ini section where the variable is allowed. This + * section should be part of the special_sections array. + * + * Example: + * .section = "global", + */ + char *section; - /** - * A string with a short description of the config variable. This is - * currently not used, but it may be used to generate help messages. - */ - char *description; + /** + * A string with a short description of the config variable. This is + * currently not used, but it may be used to generate help messages. + */ + char *description; - // IDEA: Add long description to generate man page from this. This could - // also be useful for an extended help text. + // IDEA: Add long description to generate man page from this. This could + // also be useful for an extended help text. - /** - * Enum of the setting type. Every setting type is parsed differently in - * option_parser.c. - */ - enum setting_type type; + /** + * Enum of the setting type. Every setting type is parsed differently in + * option_parser.c. + */ + enum setting_type type; - /** - * A string with the default value of the setting. This should be the - * same as what it would be in the config file, as this is parsed by the - * same parser. - * default_value is unused when the setting is only a rule (value == NULL). - * - * Example: - * .default_value = "10s", // 10 seconds of time - */ - char *default_value; + /** + * A string with the default value of the setting. This should be the + * same as what it would be in the config file, as this is parsed by the + * same parser. + * default_value is unused when the setting is only a rule (value == NULL). + * + * Example: + * .default_value = "10s", // 10 seconds of time + */ + char *default_value; - /** - * (nullable) - * A pointer to the corresponding setting in the setting struct. Make - * sure to always take the address, even if it's already a pointer in the - * settings struct. - * If value is NULL, the setting is interpreted as a rule. - * - * Example: - * .value = &settings.font, - */ - void *value; + /** + * (nullable) + * A pointer to the corresponding setting in the setting struct. Make + * sure to always take the address, even if it's already a pointer in the + * settings struct. + * If value is NULL, the setting is interpreted as a rule. + * + * Example: + * .value = &settings.font, + */ + void *value; + /** + * (nullable) + * Function pointer for the parser - to be used in case of enums or other + * special settings. If the parse requires extra data, it should be given + * with parser_data. This allows for one generic parser for, for example, + * enums, instead of a parser for every enum. + * + * @param data The required data for parsing the value. See parser_data. + * @param cfg_value The string representing the value of the config + * variable + * @param ret A pointer to the return value. This casted by the parser to + * the right type. + */ + int (*parser)(const void *data, const char *cfg_value, void *ret); - /** - * (nullable) - * Function pointer for the parser - to be used in case of enums or other - * special settings. If the parse requires extra data, it should be given - * with parser_data. This allows for one generic parser for, for example, - * enums, instead of a parser for every enum. - * - * @param data The required data for parsing the value. See parser_data. - * @param cfg_value The string representing the value of the config - * variable - * @param ret A pointer to the return value. This casted by the parser to - * the right type. - */ - int (*parser)(const void* data, const char *cfg_value, void* ret); + /** + * (nullable) + * A pointer to the data required for the parser to parse this setting. + */ + const void *parser_data; // This is passed to the parser function - /** - * (nullable) - * A pointer to the data required for the parser to parse this setting. - */ - const void* parser_data; // This is passed to the parser function + /** + * The offset of this setting in the rule struct, if it exists. Zero is + * being interpreted as if no rule exists for this setting. + * + * Example: + * .rule_offset = offsetof(struct rule, *member*); + */ + size_t rule_offset; - /** - * The offset of this setting in the rule struct, if it exists. Zero is - * being interpreted as if no rule exists for this setting. - * - * Example: - * .rule_offset = offsetof(struct rule, *member*); - */ - size_t rule_offset; - - /** - * True if a setting has a different default in the default dunstrc. - * This is useful to transition a default value without breaking exisitng - * configs. This value is needed for the test suite to skip testing this - * setting against the default dunstrc. - * - * False by default. - */ - bool different_default; + /** + * True if a setting has a different default in the default dunstrc. + * This is useful to transition a default value without breaking exisitng + * configs. This value is needed for the test suite to skip testing this + * setting against the default dunstrc. + * + * False by default. + */ + bool different_default; }; - /* * How to add/change a rule * ------------------------ @@ -130,1484 +131,1509 @@ struct setting { * - Update the documentation * - Test that it works * - * An example of making a setting a rule can be found in commit edc6f5a8c7a51a56b591cfa72618a43adc7b8d11 + * An example of making a setting a rule can be found in commit + * edc6f5a8c7a51a56b591cfa72618a43adc7b8d11 */ -static const struct rule empty_rule = { - .name = "empty", - .appname = NULL, - .action_name = NULL, - .summary = NULL, - .body = NULL, - .icon = NULL, - .category = NULL, - .msg_urgency = URG_NONE, - .match_dbus_timeout = -1, - .timeout = -1, - .override_dbus_timeout = -1, - .urgency = URG_NONE, - .markup = MARKUP_NULL, - .history_ignore = -1, - .match_transient = -1, - .set_transient = -1, - .icon_position = -1, - .skip_display = -1, - .word_wrap = -1, - .ellipsize = -1, - .alignment = -1, - .hide_text = -1, - .new_icon = NULL, - .default_icon = NULL, - .fg = COLOR_UNINIT, - .bg = COLOR_UNINIT, - .highlight = NULL, - .fc = COLOR_UNINIT, - .format = NULL, - .script = NULL, - .enabled = true, - .progress_bar_alignment = -1, - .min_icon_size = -1, - .max_icon_size = -1, - .fullscreen = FS_NULL, - .override_pause_level = -1 -}; - +static const struct rule empty_rule = {.name = "empty", + .appname = NULL, + .action_name = NULL, + .summary = NULL, + .body = NULL, + .icon = NULL, + .category = NULL, + .msg_urgency = URG_NONE, + .match_dbus_timeout = -1, + .timeout = -1, + .override_dbus_timeout = -1, + .urgency = URG_NONE, + .markup = MARKUP_NULL, + .history_ignore = -1, + .match_transient = -1, + .set_transient = -1, + .icon_position = -1, + .skip_display = -1, + .word_wrap = -1, + .ellipsize = -1, + .alignment = -1, + .hide_text = -1, + .new_icon = NULL, + .default_icon = NULL, + .fg = COLOR_UNINIT, + .bg = COLOR_UNINIT, + .highlight = NULL, + .fc = COLOR_UNINIT, + .format = NULL, + .script = NULL, + .enabled = true, + .progress_bar_alignment = -1, + .min_icon_size = -1, + .max_icon_size = -1, + .fullscreen = FS_NULL, + .override_pause_level = -1}; #ifndef ZWLR_LAYER_SHELL_V1_LAYER_ENUM #define ZWLR_LAYER_SHELL_V1_LAYER_ENUM // Needed for compiling without wayland dependency const enum zwlr_layer_shell_v1_layer { - ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND = 0, - ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM = 1, - ZWLR_LAYER_SHELL_V1_LAYER_TOP = 2, - ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY = 3, + ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND = 0, + ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM = 1, + ZWLR_LAYER_SHELL_V1_LAYER_TOP = 2, + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY = 3, }; #endif /* ZWLR_LAYER_SHELL_V1_LAYER_ENUM */ -enum list_type { - INVALID_LIST = 0, - MOUSE_LIST = 1, - OFFSET_LIST = 2, - STRING_LIST = 3, +enum list_type +{ + INVALID_LIST = 0, + MOUSE_LIST = 1, + OFFSET_LIST = 2, + STRING_LIST = 3, }; #define ENUM_END {NULL, 0} static const struct string_to_enum_def verbosity_enum_data[] = { - {"critical", G_LOG_LEVEL_CRITICAL }, - {"crit", G_LOG_LEVEL_CRITICAL }, - {"warning", G_LOG_LEVEL_WARNING }, - {"warn", G_LOG_LEVEL_WARNING }, - {"message", G_LOG_LEVEL_MESSAGE }, - {"mesg", G_LOG_LEVEL_MESSAGE }, - {"info", G_LOG_LEVEL_INFO }, - {"debug", G_LOG_LEVEL_DEBUG }, - {"deb", G_LOG_LEVEL_DEBUG }, - ENUM_END, + {"critical", G_LOG_LEVEL_CRITICAL}, + {"crit", G_LOG_LEVEL_CRITICAL}, + {"warning", G_LOG_LEVEL_WARNING}, + {"warn", G_LOG_LEVEL_WARNING}, + {"message", G_LOG_LEVEL_MESSAGE}, + {"mesg", G_LOG_LEVEL_MESSAGE}, + {"info", G_LOG_LEVEL_INFO}, + {"debug", G_LOG_LEVEL_DEBUG}, + {"deb", G_LOG_LEVEL_DEBUG}, + ENUM_END, }; static const struct string_to_enum_def boolean_enum_data[] = { - {"True", true }, - {"true", true }, - {"On", true }, - {"on", true }, - {"Yes", true }, - {"yes", true }, - {"1", true }, - {"False", false }, - {"false", false }, - {"Off", false }, - {"off", false }, - {"No", false }, - {"no", false }, - {"0", false }, - {"n", false }, - {"y", false }, - {"N", false }, - {"Y", true }, - ENUM_END, + {"True", true}, {"true", true}, {"On", true}, {"on", true}, + {"Yes", true}, {"yes", true}, {"1", true}, {"False", false}, + {"false", false}, {"Off", false}, {"off", false}, {"No", false}, + {"no", false}, {"0", false}, {"n", false}, {"y", false}, + {"N", false}, {"Y", true}, ENUM_END, }; static const struct string_to_enum_def sort_type_enum_data[] = { - {"True", SORT_TYPE_URGENCY_DESCENDING }, - {"true", SORT_TYPE_URGENCY_DESCENDING }, - {"On", SORT_TYPE_URGENCY_DESCENDING }, - {"on", SORT_TYPE_URGENCY_DESCENDING }, - {"Yes", SORT_TYPE_URGENCY_DESCENDING }, - {"yes", SORT_TYPE_URGENCY_DESCENDING }, - {"1", SORT_TYPE_URGENCY_DESCENDING }, - {"False", SORT_TYPE_ID }, - {"false", SORT_TYPE_ID }, - {"Off", SORT_TYPE_ID }, - {"off", SORT_TYPE_ID }, - {"No", SORT_TYPE_ID }, - {"no", SORT_TYPE_ID }, - {"0", SORT_TYPE_ID }, - {"n", SORT_TYPE_ID }, - {"y", SORT_TYPE_ID }, - {"N", SORT_TYPE_ID }, - {"Y", SORT_TYPE_URGENCY_DESCENDING }, - {"id", SORT_TYPE_ID}, - {"urgency_ascending", SORT_TYPE_URGENCY_ASCENDING }, - {"urgency_descending", SORT_TYPE_URGENCY_DESCENDING }, - {"update", SORT_TYPE_UPDATE }, - ENUM_END, + {"True", SORT_TYPE_URGENCY_DESCENDING}, + {"true", SORT_TYPE_URGENCY_DESCENDING}, + {"On", SORT_TYPE_URGENCY_DESCENDING}, + {"on", SORT_TYPE_URGENCY_DESCENDING}, + {"Yes", SORT_TYPE_URGENCY_DESCENDING}, + {"yes", SORT_TYPE_URGENCY_DESCENDING}, + {"1", SORT_TYPE_URGENCY_DESCENDING}, + {"False", SORT_TYPE_ID}, + {"false", SORT_TYPE_ID}, + {"Off", SORT_TYPE_ID}, + {"off", SORT_TYPE_ID}, + {"No", SORT_TYPE_ID}, + {"no", SORT_TYPE_ID}, + {"0", SORT_TYPE_ID}, + {"n", SORT_TYPE_ID}, + {"y", SORT_TYPE_ID}, + {"N", SORT_TYPE_ID}, + {"Y", SORT_TYPE_URGENCY_DESCENDING}, + {"id", SORT_TYPE_ID}, + {"urgency_ascending", SORT_TYPE_URGENCY_ASCENDING}, + {"urgency_descending", SORT_TYPE_URGENCY_DESCENDING}, + {"update", SORT_TYPE_UPDATE}, + ENUM_END, }; static const struct string_to_enum_def horizontal_alignment_enum_data[] = { - {"left", PANGO_ALIGN_LEFT }, - {"center", PANGO_ALIGN_CENTER }, - {"right", PANGO_ALIGN_RIGHT }, - ENUM_END, + {"left", PANGO_ALIGN_LEFT}, + {"center", PANGO_ALIGN_CENTER}, + {"right", PANGO_ALIGN_RIGHT}, + ENUM_END, }; static const struct string_to_enum_def ellipsize_enum_data[] = { - {"start", PANGO_ELLIPSIZE_START }, - {"middle", PANGO_ELLIPSIZE_MIDDLE }, - {"end", PANGO_ELLIPSIZE_END }, - ENUM_END, + {"start", PANGO_ELLIPSIZE_START}, + {"middle", PANGO_ELLIPSIZE_MIDDLE}, + {"end", PANGO_ELLIPSIZE_END}, + ENUM_END, }; static struct string_to_enum_def follow_mode_enum_data[] = { - {"mouse", FOLLOW_MOUSE }, - {"keyboard", FOLLOW_KEYBOARD }, - {"none", FOLLOW_NONE }, - ENUM_END, + {"mouse", FOLLOW_MOUSE}, + {"keyboard", FOLLOW_KEYBOARD}, + {"none", FOLLOW_NONE}, + ENUM_END, }; static const struct string_to_enum_def fullscreen_enum_data[] = { - {"show", FS_SHOW }, - {"delay", FS_DELAY }, - {"pushback", FS_PUSHBACK }, - ENUM_END, + {"show", FS_SHOW}, + {"delay", FS_DELAY}, + {"pushback", FS_PUSHBACK}, + ENUM_END, }; static const struct string_to_enum_def icon_position_enum_data[] = { - {"left", ICON_LEFT }, - {"right", ICON_RIGHT }, - {"top", ICON_TOP }, - {"off", ICON_OFF }, - ENUM_END, + {"left", ICON_LEFT}, + {"right", ICON_RIGHT}, + {"top", ICON_TOP}, + {"off", ICON_OFF}, + ENUM_END, }; static const struct string_to_enum_def vertical_alignment_enum_data[] = { - {"top", VERTICAL_TOP }, - {"center", VERTICAL_CENTER }, - {"bottom", VERTICAL_BOTTOM }, - ENUM_END, + {"top", VERTICAL_TOP}, + {"center", VERTICAL_CENTER}, + {"bottom", VERTICAL_BOTTOM}, + ENUM_END, }; static const struct string_to_enum_def markup_mode_enum_data[] = { - {"strip", MARKUP_STRIP }, - {"no", MARKUP_NO }, - {"full", MARKUP_FULL }, - {"yes", MARKUP_FULL }, - ENUM_END, + {"strip", MARKUP_STRIP}, + {"no", MARKUP_NO}, + {"full", MARKUP_FULL}, + {"yes", MARKUP_FULL}, + ENUM_END, }; static const struct string_to_enum_def mouse_action_enum_data[] = { - {"none", MOUSE_NONE }, - {"do_action", MOUSE_DO_ACTION }, - {"close_current", MOUSE_CLOSE_CURRENT }, - {"close_all", MOUSE_CLOSE_ALL }, - {"context", MOUSE_CONTEXT }, - {"context_all", MOUSE_CONTEXT_ALL }, - {"open_url", MOUSE_OPEN_URL }, - ENUM_END, + {"none", MOUSE_NONE}, + {"do_action", MOUSE_DO_ACTION}, + {"close_current", MOUSE_CLOSE_CURRENT}, + {"close_all", MOUSE_CLOSE_ALL}, + {"context", MOUSE_CONTEXT}, + {"context_all", MOUSE_CONTEXT_ALL}, + {"open_url", MOUSE_OPEN_URL}, + ENUM_END, }; static const struct string_to_enum_def sep_color_enum_data[] = { - {"auto", SEP_AUTO }, - {"foreground", SEP_FOREGROUND }, - {"frame", SEP_FRAME }, - ENUM_END, + {"auto", SEP_AUTO}, + {"foreground", SEP_FOREGROUND}, + {"frame", SEP_FRAME}, + ENUM_END, }; static const struct string_to_enum_def urgency_enum_data[] = { - {"low", URG_LOW }, - {"normal", URG_NORM }, - {"critical", URG_CRIT }, - ENUM_END, + {"low", URG_LOW}, + {"normal", URG_NORM}, + {"critical", URG_CRIT}, + ENUM_END, }; static const struct string_to_enum_def layer_enum_data[] = { - {"bottom", ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM }, - {"top", ZWLR_LAYER_SHELL_V1_LAYER_TOP }, - {"overlay", ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY }, - ENUM_END, + {"bottom", ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM}, + {"top", ZWLR_LAYER_SHELL_V1_LAYER_TOP}, + {"overlay", ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY}, + ENUM_END, }; static const struct string_to_enum_def origin_enum_data[] = { - { "top-left", ORIGIN_TOP_LEFT }, - { "top-center", ORIGIN_TOP_CENTER }, - { "top-right", ORIGIN_TOP_RIGHT }, - { "bottom-left", ORIGIN_BOTTOM_LEFT }, - { "bottom-center", ORIGIN_BOTTOM_CENTER }, - { "bottom-right", ORIGIN_BOTTOM_RIGHT }, - { "left-center", ORIGIN_LEFT_CENTER }, - { "right-center", ORIGIN_RIGHT_CENTER }, - { "center", ORIGIN_CENTER }, - ENUM_END, + {"top-left", ORIGIN_TOP_LEFT}, + {"top-center", ORIGIN_TOP_CENTER}, + {"top-right", ORIGIN_TOP_RIGHT}, + {"bottom-left", ORIGIN_BOTTOM_LEFT}, + {"bottom-center", ORIGIN_BOTTOM_CENTER}, + {"bottom-right", ORIGIN_BOTTOM_RIGHT}, + {"left-center", ORIGIN_LEFT_CENTER}, + {"right-center", ORIGIN_RIGHT_CENTER}, + {"center", ORIGIN_CENTER}, + ENUM_END, }; static const struct string_to_enum_def corners_enum_data[] = { - { "top-left", C_TOP_LEFT }, - { "top-right", C_TOP_RIGHT }, - { "bottom-left", C_BOT_LEFT }, - { "bottom-right", C_BOT_RIGHT }, - { "left", C_LEFT }, - { "right", C_RIGHT }, - { "bottom", C_BOT }, - { "top", C_TOP }, - { "all", C_ALL }, - { "none", C_NONE }, - ENUM_END, + {"top-left", C_TOP_LEFT}, + {"top-right", C_TOP_RIGHT}, + {"bottom-left", C_BOT_LEFT}, + {"bottom-right", C_BOT_RIGHT}, + {"left", C_LEFT}, + {"right", C_RIGHT}, + {"bottom", C_BOT}, + {"top", C_TOP}, + {"all", C_ALL}, + {"none", C_NONE}, + ENUM_END, }; static const struct setting allowed_settings[] = { - // These icon settings have to be above the icon rule - { - .name = "icon", - .section = "urgency_low", - .description = "Icon for notifications with low urgency", - .type = TYPE_STRING, - .default_value = "", - .value = &settings.icons[URG_LOW], - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "icon", - .section = "urgency_normal", - .description = "Icon for notifications with normal urgency", - .type = TYPE_STRING, - .default_value = "", - .value = &settings.icons[URG_NORM], - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "icon", - .section = "urgency_critical", - .description = "Icon for notifications with critical urgency", - .type = TYPE_STRING, - .default_value = "", - .value = &settings.icons[URG_CRIT], - .parser = NULL, - .parser_data = NULL, - }, - // filtering rules below - { - .name = "appname", - .section = "*", - .description = "The name of the application as reported by the client. Be aware that the name can often differ depending on the locale used.", - .type = TYPE_STRING, - .default_value = "*", // default_value is not used for rules - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, appname), - }, - { - .name = "body", - .section = "*", - .description = "The body of the notification", - .type = TYPE_STRING, - .default_value = "*", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, body), - }, - { - .name = "category", - .section = "*", - .description = "The category of the notification as defined by the notification spec. See https://specifications.freedesktop.org/notification-spec/latest/ar01s06.html", - .type = TYPE_STRING, - .default_value = "*", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, category), - }, - { - .name = "desktop_entry", - .section = "*", - .description = "GLib based applications export their desktop-entry name. In comparison to the appname, the desktop-entry won't get localized.", - .type = TYPE_STRING, - .default_value = "*", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, desktop_entry), - }, - { - .name = "icon", - .section = "*", - .description = "The icon of the notification in the form of a file path. Can be empty if no icon is available or a raw icon is used instead.", - .type = TYPE_STRING, - .default_value = "*", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, icon), - }, - { - .name = "match_transient", - .section = "*", - .description = "Match if the notification has been declared as transient by the client or by some other rule.", - .type = TYPE_CUSTOM, - .default_value = "*", - .value = NULL, - .parser = string_parse_enum, - .parser_data = boolean_enum_data, - .rule_offset = offsetof(struct rule, match_transient), - }, - { - .name = "msg_urgency", - .section = "*", - .description = "Matches the urgency of the notification as set by the client or by some other rule.", - .type = TYPE_CUSTOM, - .default_value = "*", - .value = NULL, - .parser = string_parse_enum, - .parser_data = urgency_enum_data, - .rule_offset = offsetof(struct rule, msg_urgency), - }, - { - .name = "match_dbus_timeout", - .section = "*", - .description = "Matches the dbus_timeout of the notification", - .type = TYPE_TIME, - .default_value = "*", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, match_dbus_timeout), - }, - { - .name = "stack_tag", - .section = "*", - .description = "Matches the stack tag of the notification as set by the client or by some other rule.", - .type = TYPE_STRING, - .default_value = "*", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, stack_tag), - }, - { - .name = "summary", - .section = "*", - .description = "summary text of the notification", - .type = TYPE_STRING, - .default_value = "*", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, summary), - }, + // These icon settings have to be above the icon rule + { + .name = "icon", + .section = "urgency_low", + .description = "Icon for notifications with low urgency", + .type = TYPE_STRING, + .default_value = "", + .value = &settings.icons[URG_LOW], + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "icon", + .section = "urgency_normal", + .description = "Icon for notifications with normal urgency", + .type = TYPE_STRING, + .default_value = "", + .value = &settings.icons[URG_NORM], + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "icon", + .section = "urgency_critical", + .description = "Icon for notifications with critical urgency", + .type = TYPE_STRING, + .default_value = "", + .value = &settings.icons[URG_CRIT], + .parser = NULL, + .parser_data = NULL, + }, + // filtering rules below + { + .name = "appname", + .section = "*", + .description = + "The name of the application as reported by the client. Be aware " + "that the name can often differ depending on the locale used.", + .type = TYPE_STRING, + .default_value = "*", // default_value is not used for rules + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, appname), + }, + { + .name = "body", + .section = "*", + .description = "The body of the notification", + .type = TYPE_STRING, + .default_value = "*", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, body), + }, + { + .name = "category", + .section = "*", + .description = "The category of the notification as defined by the " + "notification spec. See " + "https://specifications.freedesktop.org/" + "notification-spec/latest/ar01s06.html", + .type = TYPE_STRING, + .default_value = "*", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, category), + }, + { + .name = "desktop_entry", + .section = "*", + .description = + "GLib based applications export their desktop-entry name. In " + "comparison to the appname, the desktop-entry won't get localized.", + .type = TYPE_STRING, + .default_value = "*", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, desktop_entry), + }, + { + .name = "icon", + .section = "*", + .description = + "The icon of the notification in the form of a file path. Can be " + "empty if no icon is available or a raw icon is used instead.", + .type = TYPE_STRING, + .default_value = "*", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, icon), + }, + { + .name = "match_transient", + .section = "*", + .description = "Match if the notification has been declared as " + "transient by the client or by some other rule.", + .type = TYPE_CUSTOM, + .default_value = "*", + .value = NULL, + .parser = string_parse_enum, + .parser_data = boolean_enum_data, + .rule_offset = offsetof(struct rule, match_transient), + }, + { + .name = "msg_urgency", + .section = "*", + .description = "Matches the urgency of the notification as set by the " + "client or by some other rule.", + .type = TYPE_CUSTOM, + .default_value = "*", + .value = NULL, + .parser = string_parse_enum, + .parser_data = urgency_enum_data, + .rule_offset = offsetof(struct rule, msg_urgency), + }, + { + .name = "match_dbus_timeout", + .section = "*", + .description = "Matches the dbus_timeout of the notification", + .type = TYPE_TIME, + .default_value = "*", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, match_dbus_timeout), + }, + { + .name = "stack_tag", + .section = "*", + .description = "Matches the stack tag of the notification as set by " + "the client or by some other rule.", + .type = TYPE_STRING, + .default_value = "*", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, stack_tag), + }, + { + .name = "summary", + .section = "*", + .description = "summary text of the notification", + .type = TYPE_STRING, + .default_value = "*", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, summary), + }, - // modifying rules below - { - .name = "script", - .section = "*", - .description = "script", - .type = TYPE_PATH, - .default_value = "*", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, script), - }, - { - .name = "background", - .section = "*", - .description = "The background color of the notification.", - .type = TYPE_COLOR, - .default_value = "*", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, bg), - }, - { - .name = "action_name", - .section = "*", - .description = "Sets the name of the action to be invoked on do_action.", - .type = TYPE_STRING, - .default_value = "*", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, action_name), - }, - { - .name = "foreground", - .section = "*", - .description = "The foreground color of the notification.", - .type = TYPE_COLOR, - .default_value = "*", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, fg), - }, - { - .name = "highlight", - .section = "*", - .description = "The highlight color of the notification.", - .type = TYPE_GRADIENT, - .default_value = "*", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, highlight), - }, - { - .name = "default_icon", - .section = "*", - .description = "The default icon that is used when no icon is passed", - .type = TYPE_PATH, - .default_value = "*", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, default_icon), - }, - { - .name = "format", - .section = "global", - .description = "The format template for the notifications", - .type = TYPE_STRING, - .default_value = "%s\n%b", - .value = &settings.format, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, format), - }, - { - .name = "fullscreen", - .section = "*", - .description = "This attribute specifies how notifications are handled if a fullscreen window is focused. One of show, delay, or pushback.", - .type = TYPE_CUSTOM, - .default_value = "show", - .value = NULL, - .parser = string_parse_enum, - .parser_data = fullscreen_enum_data, - .rule_offset = offsetof(struct rule, fullscreen), - }, - { - .name = "new_icon", - .section = "*", - .description = "Updates the icon of the notification, it should be a path to a valid image.", - .type = TYPE_PATH, - .default_value = "*", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, new_icon), - }, - { - .name = "set_stack_tag", - .section = "*", - .description = "Sets the stack tag for the notification, notifications with the same (non-empty) stack tag will replace each-other so only the newest one is visible.", - .type = TYPE_STRING, - .default_value = "*", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, set_stack_tag), - }, - { - .name = "set_transient", - .section = "*", - .description = "Sets whether the notification is considered transient. Transient notifications will bypass the idle_threshold setting.", - .type = TYPE_CUSTOM, - .default_value = "*", - .value = NULL, - .parser = string_parse_enum, - .parser_data = boolean_enum_data, - .rule_offset = offsetof(struct rule, set_transient), - }, - { - .name = "set_category", - .section = "*", - .description = "The category of the notification as defined by the notification spec. See https://specifications.freedesktop.org/notification-spec/latest/ar01s06.html", - .type = TYPE_STRING, - .default_value = "*", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, set_category), - }, - { - .name = "timeout", - .section = "*", - .description = "Don't timeout notifications if user is longer idle than threshold", - .type = TYPE_TIME, - .default_value = "*", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, timeout), - }, - { - .name = "override_dbus_timeout", - .section = "*", - .description = "Replace the dbus timeout with this value.", - .type = TYPE_TIME, - .default_value = "*", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, override_dbus_timeout), - }, - { - .name = "urgency", - .section = "*", - .description = "This sets the notification urgency.", - .type = TYPE_CUSTOM, - .default_value = "*", - .value = NULL, - .parser = string_parse_enum, - .parser_data = urgency_enum_data, - .rule_offset = offsetof(struct rule, urgency), - }, - { - .name = "skip_display", - .section = "*", - .description = "Setting this to true will prevent the notification from being displayed initially but will be saved in history for later viewing.", - .type = TYPE_CUSTOM, - .default_value = "*", - .value = NULL, - .parser = string_parse_enum, - .parser_data = boolean_enum_data, - .rule_offset = offsetof(struct rule, skip_display), - }, - { - .name = "history_ignore", - .section = "*", - .description = "Setting this to true will display the notification initially, but stop it from being recalled via the history.", - .type = TYPE_CUSTOM, - .default_value = "*", - .value = NULL, - .parser = string_parse_enum, - .parser_data = boolean_enum_data, - .rule_offset = offsetof(struct rule, history_ignore), - }, - { - .name = "word_wrap", - .section = "*", - .description = "Wrap long lines of text", - .type = TYPE_CUSTOM, - .default_value = "*", - .value = NULL, - .parser = string_parse_enum, - .parser_data = boolean_enum_data, - .rule_offset = offsetof(struct rule, word_wrap), - }, - { - .name = "ellipsize", - .section = "*", - .description = "Ellipsize truncated lines on the start/middle/end", - .type = TYPE_CUSTOM, - .default_value = "*", - .value = NULL, - .parser = string_parse_enum, - .parser_data = ellipsize_enum_data, - .rule_offset = offsetof(struct rule, ellipsize), - }, - { - .name = "alignment", - .section = "*", - .description = "Text alignment left/center/right", - .type = TYPE_CUSTOM, - .default_value = "*", - .value = NULL, - .parser = string_parse_enum, - .parser_data = horizontal_alignment_enum_data, - .rule_offset = offsetof(struct rule, alignment), - }, - { - .name = "hide_text", - .section = "*", - .description = "Skip rendering summary and body text in notification window (keeps icon and progress bar)", - .type = TYPE_CUSTOM, - .default_value = "*", - .value = NULL, - .parser = string_parse_enum, - .parser_data = boolean_enum_data, - .rule_offset = offsetof(struct rule, hide_text), - }, - { - .name = "markup", - .section = "*", - .description = "Specify how markup should be handled", - .type = TYPE_CUSTOM, - .default_value = "*", - .value = NULL, - .parser = string_parse_enum, - .parser_data = markup_mode_enum_data, - .rule_offset = offsetof(struct rule, markup), - }, - { - .name = "icon_position", - .section = "*", - .description = "Align icons left/right/top/off", - .type = TYPE_CUSTOM, - .default_value = "*", - .value = NULL, - .parser = string_parse_enum, - .parser_data = icon_position_enum_data, - .rule_offset = offsetof(struct rule, icon_position), - }, - { - .name = "enabled", - .section = "*", - .description = "Enable or disable a rule", - .type = TYPE_CUSTOM, - .default_value = "true", - .value = NULL, - .parser = string_parse_bool, - .parser_data = boolean_enum_data, - .rule_offset = offsetof(struct rule, enabled), - }, - { - .name = "corners", - .section = "global", - .description = "Select the corners to round", - .type = TYPE_CUSTOM, - .default_value = "all", - .value = &settings.corners, - .parser = string_parse_corners, - .parser_data = corners_enum_data, - }, - { - .name = "progress_bar_corners", - .section = "global", - .description = "Select the corners to round for the progress bar", - .type = TYPE_CUSTOM, - .default_value = "all", - .value = &settings.progress_bar_corners, - .parser = string_parse_corners, - .parser_data = corners_enum_data, - }, - { - .name = "icon_corners", - .section = "global", - .description = "Select the corners to round for the icon image", - .type = TYPE_CUSTOM, - .default_value = "all", - .value = &settings.icon_corners, - .parser = string_parse_corners, - .parser_data = corners_enum_data, - }, - { - .name = "progress_bar_horizontal_alignment", - .section = "*", - .description = "Set the horizontal alignment of the progress bar", - .type = TYPE_CUSTOM, - .default_value = "center", - .value = NULL, - .parser = string_parse_enum, - .parser_data = horizontal_alignment_enum_data, - .rule_offset = offsetof(struct rule, progress_bar_alignment), - }, - { - .name = "min_icon_size", - .section = "global", - .description = "Scale smaller icons up to this size, set to 0 to disable. If max_icon_size also specified, that has the final say.", - .type = TYPE_INT, - .default_value = "*", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, min_icon_size), - }, - { - .name = "max_icon_size", - .section = "global", - .description = "Scale larger icons down to this size, set to 0 to disable", - .type = TYPE_INT, - .default_value = "*", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, max_icon_size), - }, - { - .name = "override_pause_level", - .section = "*", - .description = "TODO", - .type = TYPE_INT, - .default_value = "-1", - .value = NULL, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, override_pause_level), - }, - // end of modifying rules + // modifying rules below + { + .name = "script", + .section = "*", + .description = "script", + .type = TYPE_PATH, + .default_value = "*", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, script), + }, + { + .name = "background", + .section = "*", + .description = "The background color of the notification.", + .type = TYPE_COLOR, + .default_value = "*", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, bg), + }, + { + .name = "action_name", + .section = "*", + .description = + "Sets the name of the action to be invoked on do_action.", + .type = TYPE_STRING, + .default_value = "*", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, action_name), + }, + { + .name = "foreground", + .section = "*", + .description = "The foreground color of the notification.", + .type = TYPE_COLOR, + .default_value = "*", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, fg), + }, + { + .name = "highlight", + .section = "*", + .description = "The highlight color of the notification.", + .type = TYPE_GRADIENT, + .default_value = "*", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, highlight), + }, + { + .name = "default_icon", + .section = "*", + .description = "The default icon that is used when no icon is passed", + .type = TYPE_PATH, + .default_value = "*", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, default_icon), + }, + { + .name = "format", + .section = "global", + .description = "The format template for the notifications", + .type = TYPE_STRING, + .default_value = "%s\n%b", + .value = &settings.format, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, format), + }, + { + .name = "fullscreen", + .section = "*", + .description = + "This attribute specifies how notifications are handled if a " + "fullscreen window is focused. One of show, delay, or pushback.", + .type = TYPE_CUSTOM, + .default_value = "show", + .value = NULL, + .parser = string_parse_enum, + .parser_data = fullscreen_enum_data, + .rule_offset = offsetof(struct rule, fullscreen), + }, + { + .name = "new_icon", + .section = "*", + .description = "Updates the icon of the notification, it should be a " + "path to a valid image.", + .type = TYPE_PATH, + .default_value = "*", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, new_icon), + }, + { + .name = "set_stack_tag", + .section = "*", + .description = "Sets the stack tag for the notification, notifications " + "with the same (non-empty) stack tag will replace " + "each-other so only the newest one is visible.", + .type = TYPE_STRING, + .default_value = "*", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, set_stack_tag), + }, + { + .name = "set_transient", + .section = "*", + .description = + "Sets whether the notification is considered transient. Transient " + "notifications will bypass the idle_threshold setting.", + .type = TYPE_CUSTOM, + .default_value = "*", + .value = NULL, + .parser = string_parse_enum, + .parser_data = boolean_enum_data, + .rule_offset = offsetof(struct rule, set_transient), + }, + { + .name = "set_category", + .section = "*", + .description = "The category of the notification as defined by the " + "notification spec. See " + "https://specifications.freedesktop.org/" + "notification-spec/latest/ar01s06.html", + .type = TYPE_STRING, + .default_value = "*", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, set_category), + }, + { + .name = "timeout", + .section = "*", + .description = + "Don't timeout notifications if user is longer idle than threshold", + .type = TYPE_TIME, + .default_value = "*", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, timeout), + }, + { + .name = "override_dbus_timeout", + .section = "*", + .description = "Replace the dbus timeout with this value.", + .type = TYPE_TIME, + .default_value = "*", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, override_dbus_timeout), + }, + { + .name = "urgency", + .section = "*", + .description = "This sets the notification urgency.", + .type = TYPE_CUSTOM, + .default_value = "*", + .value = NULL, + .parser = string_parse_enum, + .parser_data = urgency_enum_data, + .rule_offset = offsetof(struct rule, urgency), + }, + { + .name = "skip_display", + .section = "*", + .description = "Setting this to true will prevent the notification " + "from being displayed initially but will be saved in " + "history for later viewing.", + .type = TYPE_CUSTOM, + .default_value = "*", + .value = NULL, + .parser = string_parse_enum, + .parser_data = boolean_enum_data, + .rule_offset = offsetof(struct rule, skip_display), + }, + { + .name = "history_ignore", + .section = "*", + .description = + "Setting this to true will display the notification initially, but " + "stop it from being recalled via the history.", + .type = TYPE_CUSTOM, + .default_value = "*", + .value = NULL, + .parser = string_parse_enum, + .parser_data = boolean_enum_data, + .rule_offset = offsetof(struct rule, history_ignore), + }, + { + .name = "word_wrap", + .section = "*", + .description = "Wrap long lines of text", + .type = TYPE_CUSTOM, + .default_value = "*", + .value = NULL, + .parser = string_parse_enum, + .parser_data = boolean_enum_data, + .rule_offset = offsetof(struct rule, word_wrap), + }, + { + .name = "ellipsize", + .section = "*", + .description = "Ellipsize truncated lines on the start/middle/end", + .type = TYPE_CUSTOM, + .default_value = "*", + .value = NULL, + .parser = string_parse_enum, + .parser_data = ellipsize_enum_data, + .rule_offset = offsetof(struct rule, ellipsize), + }, + { + .name = "alignment", + .section = "*", + .description = "Text alignment left/center/right", + .type = TYPE_CUSTOM, + .default_value = "*", + .value = NULL, + .parser = string_parse_enum, + .parser_data = horizontal_alignment_enum_data, + .rule_offset = offsetof(struct rule, alignment), + }, + { + .name = "hide_text", + .section = "*", + .description = "Skip rendering summary and body text in notification " + "window (keeps icon and progress bar)", + .type = TYPE_CUSTOM, + .default_value = "*", + .value = NULL, + .parser = string_parse_enum, + .parser_data = boolean_enum_data, + .rule_offset = offsetof(struct rule, hide_text), + }, + { + .name = "markup", + .section = "*", + .description = "Specify how markup should be handled", + .type = TYPE_CUSTOM, + .default_value = "*", + .value = NULL, + .parser = string_parse_enum, + .parser_data = markup_mode_enum_data, + .rule_offset = offsetof(struct rule, markup), + }, + { + .name = "icon_position", + .section = "*", + .description = "Align icons left/right/top/off", + .type = TYPE_CUSTOM, + .default_value = "*", + .value = NULL, + .parser = string_parse_enum, + .parser_data = icon_position_enum_data, + .rule_offset = offsetof(struct rule, icon_position), + }, + { + .name = "enabled", + .section = "*", + .description = "Enable or disable a rule", + .type = TYPE_CUSTOM, + .default_value = "true", + .value = NULL, + .parser = string_parse_bool, + .parser_data = boolean_enum_data, + .rule_offset = offsetof(struct rule, enabled), + }, + { + .name = "corners", + .section = "global", + .description = "Select the corners to round", + .type = TYPE_CUSTOM, + .default_value = "all", + .value = &settings.corners, + .parser = string_parse_corners, + .parser_data = corners_enum_data, + }, + { + .name = "progress_bar_corners", + .section = "global", + .description = "Select the corners to round for the progress bar", + .type = TYPE_CUSTOM, + .default_value = "all", + .value = &settings.progress_bar_corners, + .parser = string_parse_corners, + .parser_data = corners_enum_data, + }, + { + .name = "icon_corners", + .section = "global", + .description = "Select the corners to round for the icon image", + .type = TYPE_CUSTOM, + .default_value = "all", + .value = &settings.icon_corners, + .parser = string_parse_corners, + .parser_data = corners_enum_data, + }, + { + .name = "progress_bar_horizontal_alignment", + .section = "*", + .description = "Set the horizontal alignment of the progress bar", + .type = TYPE_CUSTOM, + .default_value = "center", + .value = NULL, + .parser = string_parse_enum, + .parser_data = horizontal_alignment_enum_data, + .rule_offset = offsetof(struct rule, progress_bar_alignment), + }, + { + .name = "min_icon_size", + .section = "global", + .description = + "Scale smaller icons up to this size, set to 0 to disable. If " + "max_icon_size also specified, that has the final say.", + .type = TYPE_INT, + .default_value = "*", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, min_icon_size), + }, + { + .name = "max_icon_size", + .section = "global", + .description = + "Scale larger icons down to this size, set to 0 to disable", + .type = TYPE_INT, + .default_value = "*", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, max_icon_size), + }, + { + .name = "override_pause_level", + .section = "*", + .description = "TODO", + .type = TYPE_INT, + .default_value = "-1", + .value = NULL, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, override_pause_level), + }, + // end of modifying rules - // other settings below - { - .name = "frame_color", - .section = "*", - .description = "Color of the frame around the window", - .type = TYPE_COLOR, - .default_value = "#888888", - .value = &settings.frame_color, - .parser = NULL, - .parser_data = NULL, - .rule_offset = offsetof(struct rule, fc), - }, - { - .name = "per_monitor_dpi", - .section = "experimental", - .description = "Use a different DPI per monitor", - .type = TYPE_CUSTOM, - .default_value = "false", - .value = &settings.per_monitor_dpi, - .parser = string_parse_bool, - .parser_data = boolean_enum_data, - }, - { - .name = "force_xinerama", - .section = "global", - .description = "Force the use of the Xinerama extension", - .type = TYPE_CUSTOM, - .default_value = "false", - .value = &settings.force_xinerama, - .parser = string_parse_bool, - .parser_data = boolean_enum_data, - }, - { - .name = "force_xwayland", - .section = "global", - .description = "Force the use of the xwayland output", - .type = TYPE_CUSTOM, - .default_value = "false", - .value = &settings.force_xwayland, - .parser = string_parse_bool, - .parser_data = boolean_enum_data, - }, - { - .name = "font", - .section = "global", - .description = "The font dunst should use.", - .type = TYPE_STRING, - .default_value = "Monospace 8", - .value = &settings.font, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "sort", - .section = "global", - .description = "Sort type by id/urgency/update", - .type = TYPE_CUSTOM, - .default_value = "true", - .value = &settings.sort, - .parser = string_parse_enum, - .parser_data = sort_type_enum_data, - }, - { - .name = "indicate_hidden", - .section = "global", - .description = "Show how many notifications are hidden", - .type = TYPE_CUSTOM, - .default_value = "true", - .value = &settings.indicate_hidden, - .parser = string_parse_enum, - .parser_data = boolean_enum_data, - }, - { - .name = "ignore_dbusclose", - .section = "global", - .description = "Ignore dbus CloseNotification events", - .type = TYPE_CUSTOM, - .default_value = "false", - .value = &settings.ignore_dbusclose, - .parser = string_parse_enum, - .parser_data = boolean_enum_data, - }, - { - .name = "ignore_newline", - .section = "global", - .description = "Ignore newline characters in notifications", - .type = TYPE_CUSTOM, - .default_value = "false", - .value = &settings.ignore_newline, - .parser = string_parse_enum, - .parser_data = boolean_enum_data, - }, - { - .name = "idle_threshold", - .section = "global", - .description = "Don't timeout notifications if user is longer idle than threshold", - .type = TYPE_TIME, - .default_value = "0", - .value = &settings.idle_threshold, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "monitor", - .section = "global", - .description = "On which monitor should the notifications be displayed", - .type = TYPE_CUSTOM, - .default_value = "0", - .value = &settings.monitor, - .parser = string_parse_maybe_int, - .parser_data = &settings.monitor_num, - }, - { - .name = "title", - .section = "global", - .description = "Define the title of windows spawned by dunst.", - .type = TYPE_STRING, - .default_value = "Dunst", - .value = &settings.title, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "class", - .section = "global", - .description = "Define the class of windows spawned by dunst.", - .type = TYPE_STRING, - .default_value = "Dunst", - .value = &settings.class, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "shrink", - .section = "global", - .description = "Shrink window if it's smaller than the width", - .type = TYPE_CUSTOM, - .default_value = "false", - .value = &settings.shrink, - .parser = string_parse_enum, - .parser_data = boolean_enum_data, - }, - { - .name = "line_height", - .section = "global", - .description = "Add spacing between lines of text", - .type = TYPE_INT, - .default_value = "0", - .value = &settings.line_height, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "show_age_threshold", - .section = "global", - .description = "When should the age of the notification be displayed?", - .type = TYPE_TIME, - .default_value = "60", - .value = &settings.show_age_threshold, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "hide_duplicate_count", - .section = "global", - .description = "Hide the count of stacked notifications with the same content", - .type = TYPE_CUSTOM, - .default_value = "false", - .value = &settings.hide_duplicate_count, - .parser = string_parse_bool, - .parser_data = boolean_enum_data, - }, - { - .name = "sticky_history", - .section = "global", - .description = "Don't timeout notifications popped up from history", - .type = TYPE_CUSTOM, - .default_value = "true", - .value = &settings.sticky_history, - .parser = string_parse_enum, - .parser_data = boolean_enum_data, - }, - { - .name = "history_length", - .section = "global", - .description = "Max amount of notifications kept in history", - .type = TYPE_INT, - .default_value = "20", - .value = &settings.history_length, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "show_indicators", - .section = "global", - .description = "Show indicators for actions \"(A)\" and URLs \"(U)\"", - .type = TYPE_CUSTOM, - .default_value = "true", - .value = &settings.show_indicators, - .parser = string_parse_enum, - .parser_data = boolean_enum_data, - }, - { - .name = "separator_height", - .section = "global", - .description = "height of the separator line", - .type = TYPE_INT, - .default_value = "2", - .value = &settings.separator_height, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "padding", - .section = "global", - .description = "Padding between text and separator", - .type = TYPE_INT, - .default_value = "8", - .value = &settings.padding, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "horizontal_padding", - .section = "global", - .description = "horizontal padding", - .type = TYPE_INT, - .default_value = "8", - .value = &settings.h_padding, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "text_icon_padding", - .section = "global", - .description = "Padding between text and icon", - .type = TYPE_INT, - .default_value = "0", - .value = &settings.text_icon_padding, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "transparency", - .section = "global", - .description = "Transparency. Range 0-100", - .type = TYPE_INT, - .default_value = "0", - .value = &settings.transparency, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "corner_radius", - .section = "global", - .description = "Window corner radius", - .type = TYPE_INT, - .default_value = "0", - .value = &settings.corner_radius, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "progress_bar_height", - .section = "global", - .description = "Height of the progress bar", - .type = TYPE_INT, - .default_value = "10", - .value = &settings.progress_bar_height, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "progress_bar_min_width", - .section = "global", - .description = "Minimum width of the progress bar", - .type = TYPE_INT, - .default_value = "150", - .value = &settings.progress_bar_min_width, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "progress_bar_max_width", - .section = "global", - .description = "Maximum width of the progress bar", - .type = TYPE_INT, - .default_value = "300", - .value = &settings.progress_bar_max_width, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "progress_bar_frame_width", - .section = "global", - .description = "Frame width of the progress bar", - .type = TYPE_INT, - .default_value = "1", - .value = &settings.progress_bar_frame_width, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "progress_bar_corner_radius", - .section = "global", - .description = "Progress bar corner radius", - .type = TYPE_INT, - .default_value = "0", - .value = &settings.progress_bar_corner_radius, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "icon_corner_radius", - .section = "global", - .description = "Icon corner radius", - .type = TYPE_INT, - .default_value = "0", - .value = &settings.icon_corner_radius, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "progress_bar", - .section = "global", - .description = "Show the progress bar", - .type = TYPE_CUSTOM, - .default_value = "true", - .value = &settings.progress_bar, - .parser = string_parse_bool, - .parser_data = boolean_enum_data, - }, - { - .name = "stack_duplicates", - .section = "global", - .description = "Stack together notifications with the same content", - .type = TYPE_CUSTOM, - .default_value = "true", - .value = &settings.stack_duplicates, - .parser = string_parse_bool, - .parser_data = boolean_enum_data, - }, - { - .name = "dmenu", - .section = "global", - .description = "path to dmenu", - .type = TYPE_PATH, - .default_value = "/usr/bin/dmenu -p dunst", - .value = &settings.dmenu, - .parser = NULL, - .parser_data = &settings.dmenu_cmd, - }, - { - .name = "browser", - .section = "global", - .description = "path to browser", - .type = TYPE_PATH, - .default_value = "/usr/bin/xdg-open", - .value = &settings.browser, - .parser = NULL, - .parser_data = &settings.browser_cmd, - }, - { - .name = "always_run_script", - .section = "global", - .description = "Always run rule-defined scripts, even if the notification is suppressed with format = \"\".", - .type = TYPE_CUSTOM, - .default_value = "true", - .value = &settings.always_run_script, - .parser = string_parse_bool, - .parser_data = boolean_enum_data, - }, - // manual extractions below - { - .name = "follow", - .section = "global", - .description = "Follow mouse, keyboard or none?", - .type = TYPE_CUSTOM, - .default_value = "none", - .value = &settings.f_mode, - .parser = string_parse_enum, - .parser_data = follow_mode_enum_data, - }, - { - .name = "scale", - .section = "global", - .description = "Scale factor, set to 0 to auto-detect, X11 only", - .type = TYPE_DOUBLE, - .default_value = "0", - .value = &settings.scale, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "separator_color", - .section = "global", - .description = "Color of the separator line (or 'auto')", - .type = TYPE_CUSTOM, - .default_value = "frame", - .value = &settings.sep_color, - .parser = string_parse_sepcolor, - .parser_data = sep_color_enum_data, - }, - { - .name = "vertical_alignment", - .section = "global", - .description = "Align icon and text top/center/bottom", - .type = TYPE_CUSTOM, - .default_value = "center", - .value = &settings.vertical_alignment, - .parser = string_parse_enum, - .parser_data = vertical_alignment_enum_data, - }, - { - .name = "layer", - .section = "global", - .description = "Select the layer where notifications should be placed", - .type = TYPE_CUSTOM, - .default_value = "overlay", - .value = &settings.layer, - .parser = string_parse_enum, - .parser_data = layer_enum_data, - }, - { - .name = "mouse_left_click", - .section = "global", - .description = "Action of left click event", - .type = TYPE_LIST, - .default_value = "close_current", - .value = &settings.mouse_left_click, - .parser = NULL, - .parser_data = GINT_TO_POINTER(MOUSE_LIST), - }, - { - .name = "mouse_middle_click", - .section = "global", - .description = "Action of middle click event", - .type = TYPE_LIST, - .default_value = "do_action, close_current", - .value = &settings.mouse_middle_click, - .parser = NULL, - .parser_data = GINT_TO_POINTER(MOUSE_LIST), - }, - { - .name = "mouse_right_click", - .section = "global", - .description = "Action of right click event", - .type = TYPE_LIST, - .default_value = "close_all", - .value = &settings.mouse_right_click, - .parser = NULL, - .parser_data = GINT_TO_POINTER(MOUSE_LIST), - }, - { - .name = "icon_theme", - .section = "global", - .description = "Name of the icon theme", - .type = TYPE_LIST, - .default_value = "Adwaita", - .value = &settings.icon_theme, - .parser = NULL, - .parser_data = GINT_TO_POINTER(STRING_LIST), - }, - { - .name = "icon_path", - .section = "global", - .description = "paths to default icons", - .type = TYPE_STRING, - .default_value = "/usr/share/icons/gnome/16x16/status/:/usr/share/icons/gnome/16x16/devices/", - .value = &settings.icon_path, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "enable_recursive_icon_lookup", - .section = "global", - .description = "Name of the icon theme", - .type = TYPE_CUSTOM, - .default_value = "false", - .value = &settings.enable_recursive_icon_lookup, - .parser = string_parse_bool, - .parser_data = boolean_enum_data, - .different_default = true, - }, - { - .name = "enable_posix_regex", - .section = "global", - .description = "Enable POSIX regex for filtering rules", - .type = TYPE_CUSTOM, - .default_value = "false", - .value = &settings.enable_regex, - .parser = string_parse_bool, - .parser_data = boolean_enum_data, - }, - { - .name = "frame_width", - .section = "global", - .description = "Width of frame around the window", - .type = TYPE_INT, - .default_value = "3", - .value = &settings.frame_width, - .parser = NULL, - .parser_data = NULL, - }, + // other settings below + { + .name = "frame_color", + .section = "*", + .description = "Color of the frame around the window", + .type = TYPE_COLOR, + .default_value = "#888888", + .value = &settings.frame_color, + .parser = NULL, + .parser_data = NULL, + .rule_offset = offsetof(struct rule, fc), + }, + { + .name = "per_monitor_dpi", + .section = "experimental", + .description = "Use a different DPI per monitor", + .type = TYPE_CUSTOM, + .default_value = "false", + .value = &settings.per_monitor_dpi, + .parser = string_parse_bool, + .parser_data = boolean_enum_data, + }, + { + .name = "force_xinerama", + .section = "global", + .description = "Force the use of the Xinerama extension", + .type = TYPE_CUSTOM, + .default_value = "false", + .value = &settings.force_xinerama, + .parser = string_parse_bool, + .parser_data = boolean_enum_data, + }, + { + .name = "force_xwayland", + .section = "global", + .description = "Force the use of the xwayland output", + .type = TYPE_CUSTOM, + .default_value = "false", + .value = &settings.force_xwayland, + .parser = string_parse_bool, + .parser_data = boolean_enum_data, + }, + { + .name = "font", + .section = "global", + .description = "The font dunst should use.", + .type = TYPE_STRING, + .default_value = "Monospace 8", + .value = &settings.font, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "sort", + .section = "global", + .description = "Sort type by id/urgency/update", + .type = TYPE_CUSTOM, + .default_value = "true", + .value = &settings.sort, + .parser = string_parse_enum, + .parser_data = sort_type_enum_data, + }, + { + .name = "indicate_hidden", + .section = "global", + .description = "Show how many notifications are hidden", + .type = TYPE_CUSTOM, + .default_value = "true", + .value = &settings.indicate_hidden, + .parser = string_parse_enum, + .parser_data = boolean_enum_data, + }, + { + .name = "ignore_dbusclose", + .section = "global", + .description = "Ignore dbus CloseNotification events", + .type = TYPE_CUSTOM, + .default_value = "false", + .value = &settings.ignore_dbusclose, + .parser = string_parse_enum, + .parser_data = boolean_enum_data, + }, + { + .name = "ignore_newline", + .section = "global", + .description = "Ignore newline characters in notifications", + .type = TYPE_CUSTOM, + .default_value = "false", + .value = &settings.ignore_newline, + .parser = string_parse_enum, + .parser_data = boolean_enum_data, + }, + { + .name = "idle_threshold", + .section = "global", + .description = + "Don't timeout notifications if user is longer idle than threshold", + .type = TYPE_TIME, + .default_value = "0", + .value = &settings.idle_threshold, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "monitor", + .section = "global", + .description = "On which monitor should the notifications be displayed", + .type = TYPE_CUSTOM, + .default_value = "0", + .value = &settings.monitor, + .parser = string_parse_maybe_int, + .parser_data = &settings.monitor_num, + }, + { + .name = "title", + .section = "global", + .description = "Define the title of windows spawned by dunst.", + .type = TYPE_STRING, + .default_value = "Dunst", + .value = &settings.title, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "class", + .section = "global", + .description = "Define the class of windows spawned by dunst.", + .type = TYPE_STRING, + .default_value = "Dunst", + .value = &settings.class, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "shrink", + .section = "global", + .description = "Shrink window if it's smaller than the width", + .type = TYPE_CUSTOM, + .default_value = "false", + .value = &settings.shrink, + .parser = string_parse_enum, + .parser_data = boolean_enum_data, + }, + { + .name = "line_height", + .section = "global", + .description = "Add spacing between lines of text", + .type = TYPE_INT, + .default_value = "0", + .value = &settings.line_height, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "show_age_threshold", + .section = "global", + .description = "When should the age of the notification be displayed?", + .type = TYPE_TIME, + .default_value = "60", + .value = &settings.show_age_threshold, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "hide_duplicate_count", + .section = "global", + .description = + "Hide the count of stacked notifications with the same content", + .type = TYPE_CUSTOM, + .default_value = "false", + .value = &settings.hide_duplicate_count, + .parser = string_parse_bool, + .parser_data = boolean_enum_data, + }, + { + .name = "sticky_history", + .section = "global", + .description = "Don't timeout notifications popped up from history", + .type = TYPE_CUSTOM, + .default_value = "true", + .value = &settings.sticky_history, + .parser = string_parse_enum, + .parser_data = boolean_enum_data, + }, + { + .name = "history_length", + .section = "global", + .description = "Max amount of notifications kept in history", + .type = TYPE_INT, + .default_value = "20", + .value = &settings.history_length, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "show_indicators", + .section = "global", + .description = "Show indicators for actions \"(A)\" and URLs \"(U)\"", + .type = TYPE_CUSTOM, + .default_value = "true", + .value = &settings.show_indicators, + .parser = string_parse_enum, + .parser_data = boolean_enum_data, + }, + { + .name = "separator_height", + .section = "global", + .description = "height of the separator line", + .type = TYPE_INT, + .default_value = "2", + .value = &settings.separator_height, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "padding", + .section = "global", + .description = "Padding between text and separator", + .type = TYPE_INT, + .default_value = "8", + .value = &settings.padding, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "horizontal_padding", + .section = "global", + .description = "horizontal padding", + .type = TYPE_INT, + .default_value = "8", + .value = &settings.h_padding, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "text_icon_padding", + .section = "global", + .description = "Padding between text and icon", + .type = TYPE_INT, + .default_value = "0", + .value = &settings.text_icon_padding, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "transparency", + .section = "global", + .description = "Transparency. Range 0-100", + .type = TYPE_INT, + .default_value = "0", + .value = &settings.transparency, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "corner_radius", + .section = "global", + .description = "Window corner radius", + .type = TYPE_INT, + .default_value = "0", + .value = &settings.corner_radius, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "progress_bar_height", + .section = "global", + .description = "Height of the progress bar", + .type = TYPE_INT, + .default_value = "10", + .value = &settings.progress_bar_height, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "progress_bar_min_width", + .section = "global", + .description = "Minimum width of the progress bar", + .type = TYPE_INT, + .default_value = "150", + .value = &settings.progress_bar_min_width, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "progress_bar_max_width", + .section = "global", + .description = "Maximum width of the progress bar", + .type = TYPE_INT, + .default_value = "300", + .value = &settings.progress_bar_max_width, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "progress_bar_frame_width", + .section = "global", + .description = "Frame width of the progress bar", + .type = TYPE_INT, + .default_value = "1", + .value = &settings.progress_bar_frame_width, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "progress_bar_corner_radius", + .section = "global", + .description = "Progress bar corner radius", + .type = TYPE_INT, + .default_value = "0", + .value = &settings.progress_bar_corner_radius, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "icon_corner_radius", + .section = "global", + .description = "Icon corner radius", + .type = TYPE_INT, + .default_value = "0", + .value = &settings.icon_corner_radius, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "progress_bar", + .section = "global", + .description = "Show the progress bar", + .type = TYPE_CUSTOM, + .default_value = "true", + .value = &settings.progress_bar, + .parser = string_parse_bool, + .parser_data = boolean_enum_data, + }, + { + .name = "stack_duplicates", + .section = "global", + .description = "Stack together notifications with the same content", + .type = TYPE_CUSTOM, + .default_value = "true", + .value = &settings.stack_duplicates, + .parser = string_parse_bool, + .parser_data = boolean_enum_data, + }, + { + .name = "dmenu", + .section = "global", + .description = "path to dmenu", + .type = TYPE_PATH, + .default_value = "/usr/bin/dmenu -p dunst", + .value = &settings.dmenu, + .parser = NULL, + .parser_data = &settings.dmenu_cmd, + }, + { + .name = "browser", + .section = "global", + .description = "path to browser", + .type = TYPE_PATH, + .default_value = "/usr/bin/xdg-open", + .value = &settings.browser, + .parser = NULL, + .parser_data = &settings.browser_cmd, + }, + { + .name = "always_run_script", + .section = "global", + .description = "Always run rule-defined scripts, even if the " + "notification is suppressed with format = \"\".", + .type = TYPE_CUSTOM, + .default_value = "true", + .value = &settings.always_run_script, + .parser = string_parse_bool, + .parser_data = boolean_enum_data, + }, + // manual extractions below + { + .name = "follow", + .section = "global", + .description = "Follow mouse, keyboard or none?", + .type = TYPE_CUSTOM, + .default_value = "none", + .value = &settings.f_mode, + .parser = string_parse_enum, + .parser_data = follow_mode_enum_data, + }, + { + .name = "scale", + .section = "global", + .description = "Scale factor, set to 0 to auto-detect, X11 only", + .type = TYPE_DOUBLE, + .default_value = "0", + .value = &settings.scale, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "separator_color", + .section = "global", + .description = "Color of the separator line (or 'auto')", + .type = TYPE_CUSTOM, + .default_value = "frame", + .value = &settings.sep_color, + .parser = string_parse_sepcolor, + .parser_data = sep_color_enum_data, + }, + { + .name = "vertical_alignment", + .section = "global", + .description = "Align icon and text top/center/bottom", + .type = TYPE_CUSTOM, + .default_value = "center", + .value = &settings.vertical_alignment, + .parser = string_parse_enum, + .parser_data = vertical_alignment_enum_data, + }, + { + .name = "layer", + .section = "global", + .description = "Select the layer where notifications should be placed", + .type = TYPE_CUSTOM, + .default_value = "overlay", + .value = &settings.layer, + .parser = string_parse_enum, + .parser_data = layer_enum_data, + }, + { + .name = "mouse_left_click", + .section = "global", + .description = "Action of left click event", + .type = TYPE_LIST, + .default_value = "close_current", + .value = &settings.mouse_left_click, + .parser = NULL, + .parser_data = GINT_TO_POINTER(MOUSE_LIST), + }, + { + .name = "mouse_middle_click", + .section = "global", + .description = "Action of middle click event", + .type = TYPE_LIST, + .default_value = "do_action, close_current", + .value = &settings.mouse_middle_click, + .parser = NULL, + .parser_data = GINT_TO_POINTER(MOUSE_LIST), + }, + { + .name = "mouse_right_click", + .section = "global", + .description = "Action of right click event", + .type = TYPE_LIST, + .default_value = "close_all", + .value = &settings.mouse_right_click, + .parser = NULL, + .parser_data = GINT_TO_POINTER(MOUSE_LIST), + }, + { + .name = "icon_theme", + .section = "global", + .description = "Name of the icon theme", + .type = TYPE_LIST, + .default_value = "Adwaita", + .value = &settings.icon_theme, + .parser = NULL, + .parser_data = GINT_TO_POINTER(STRING_LIST), + }, + { + .name = "icon_path", + .section = "global", + .description = "paths to default icons", + .type = TYPE_STRING, + .default_value = "/usr/share/icons/gnome/16x16/status/:/usr/share/" + "icons/gnome/16x16/devices/", + .value = &settings.icon_path, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "enable_recursive_icon_lookup", + .section = "global", + .description = "Name of the icon theme", + .type = TYPE_CUSTOM, + .default_value = "false", + .value = &settings.enable_recursive_icon_lookup, + .parser = string_parse_bool, + .parser_data = boolean_enum_data, + .different_default = true, + }, + { + .name = "enable_posix_regex", + .section = "global", + .description = "Enable POSIX regex for filtering rules", + .type = TYPE_CUSTOM, + .default_value = "false", + .value = &settings.enable_regex, + .parser = string_parse_bool, + .parser_data = boolean_enum_data, + }, + { + .name = "frame_width", + .section = "global", + .description = "Width of frame around the window", + .type = TYPE_INT, + .default_value = "3", + .value = &settings.frame_width, + .parser = NULL, + .parser_data = NULL, + }, - // These are only used for setting defaults, since there is a rule - // above doing the same. - // TODO it's probably better to create an array with default rules. - { - .name = "background", - .section = "urgency_low", - .description = "Background color for notifications with low urgency", - .type = TYPE_COLOR, - .default_value = "#222222", - .value = &settings.colors_low.bg, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "foreground", - .section = "urgency_low", - .description = "Foreground color for notifications with low urgency", - .type = TYPE_COLOR, - .default_value = "#888888", - .value = &settings.colors_low.fg, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "highlight", - .section = "urgency_low", - .description = "Highlight color for notifications with low urgency", - .type = TYPE_GRADIENT, - .default_value = "#7f7fff", - .value = &settings.colors_low.highlight, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "frame_color", - .section = "urgency_low", - .description = "Frame color for notifications with low urgency", - .type = TYPE_COLOR, - .default_value = "#888888", - .value = &settings.colors_low.frame, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "timeout", - .section = "urgency_low", - .description = "Timeout for notifications with low urgency", - .type = TYPE_TIME, - .default_value = "10", // in seconds - .value = &settings.timeouts[URG_LOW], - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "background", - .section = "urgency_normal", - .description = "Background color for notifications with normal urgency", - .type = TYPE_COLOR, - .default_value = "#285577", - .value = &settings.colors_norm.bg, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "foreground", - .section = "urgency_normal", - .description = "Foreground color for notifications with normal urgency", - .type = TYPE_COLOR, - .default_value = "#ffffff", - .value = &settings.colors_norm.fg, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "highlight", - .section = "urgency_normal", - .description = "Highlight color for notifications with normal urgency", - .type = TYPE_GRADIENT, - .default_value = "#1745d1", - .value = &settings.colors_norm.highlight, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "frame_color", - .section = "urgency_normal", - .description = "Frame color for notifications with normal urgency", - .type = TYPE_COLOR, - .default_value = "#888888", - .value = &settings.colors_norm.frame, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "timeout", - .section = "urgency_normal", - .description = "Timeout for notifications with normal urgency", - .type = TYPE_TIME, - .default_value = "10", - .value = &settings.timeouts[URG_NORM], - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "background", - .section = "urgency_critical", - .description = "Background color for notifications with critical urgency", - .type = TYPE_COLOR, - .default_value = "#900000", - .value = &settings.colors_crit.bg, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "foreground", - .section = "urgency_critical", - .description = "Foreground color for notifications with ciritical urgency", - .type = TYPE_COLOR, - .default_value = "#ffffff", - .value = &settings.colors_crit.fg, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "highlight", - .section = "urgency_critical", - .description = "Highlight color for notifications with ciritical urgency", - .type = TYPE_GRADIENT, - .default_value = "#ff6666", - .value = &settings.colors_crit.highlight, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "frame_color", - .section = "urgency_critical", - .description = "Frame color for notifications with critical urgency", - .type = TYPE_COLOR, - .default_value = "#ff0000", - .value = &settings.colors_crit.frame, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "timeout", - .section = "urgency_critical", - .description = "Timeout for notifications with critical urgency", - .type = TYPE_TIME, - .default_value = "0", - .value = &settings.timeouts[URG_CRIT], - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "origin", - .section = "global", - .description = "Specifies the where the notification is positioned before offsetting.", - .type = TYPE_CUSTOM, - .default_value = "top-right", - .value = &settings.origin, - .parser = string_parse_enum, - .parser_data = origin_enum_data, - }, - { - .name = "width", - .section = "global", - .description = "The width of the notification, excluding the frame.", - .type = TYPE_LENGTH, - .default_value = "300", - .value = &settings.width, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "height", - .section = "global", - .description = "The height of a notification, excluding the frame.", - .type = TYPE_LENGTH, - .default_value = "(0, 300)", - .value = &settings.height, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "offset", - .section = "global", - .description = "The offset of the notification from the origin.", - .type = TYPE_LENGTH, - .default_value = "(10, 50)", - .value = &settings.offset, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "notification_limit", - .section = "global", - .description = "Maximum number of notifications allowed", - .type = TYPE_INT, - .default_value = "20", - .value = &settings.notification_limit, - .parser = NULL, - .parser_data = NULL, - }, + // These are only used for setting defaults, since there is a rule + // above doing the same. + // TODO it's probably better to create an array with default rules. + { + .name = "background", + .section = "urgency_low", + .description = "Background color for notifications with low urgency", + .type = TYPE_COLOR, + .default_value = "#222222", + .value = &settings.colors_low.bg, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "foreground", + .section = "urgency_low", + .description = "Foreground color for notifications with low urgency", + .type = TYPE_COLOR, + .default_value = "#888888", + .value = &settings.colors_low.fg, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "highlight", + .section = "urgency_low", + .description = "Highlight color for notifications with low urgency", + .type = TYPE_GRADIENT, + .default_value = "#7f7fff", + .value = &settings.colors_low.highlight, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "frame_color", + .section = "urgency_low", + .description = "Frame color for notifications with low urgency", + .type = TYPE_COLOR, + .default_value = "#888888", + .value = &settings.colors_low.frame, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "timeout", + .section = "urgency_low", + .description = "Timeout for notifications with low urgency", + .type = TYPE_TIME, + .default_value = "10", // in seconds + .value = &settings.timeouts[URG_LOW], + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "background", + .section = "urgency_normal", + .description = "Background color for notifications with normal urgency", + .type = TYPE_COLOR, + .default_value = "#285577", + .value = &settings.colors_norm.bg, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "foreground", + .section = "urgency_normal", + .description = "Foreground color for notifications with normal urgency", + .type = TYPE_COLOR, + .default_value = "#ffffff", + .value = &settings.colors_norm.fg, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "highlight", + .section = "urgency_normal", + .description = "Highlight color for notifications with normal urgency", + .type = TYPE_GRADIENT, + .default_value = "#1745d1", + .value = &settings.colors_norm.highlight, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "frame_color", + .section = "urgency_normal", + .description = "Frame color for notifications with normal urgency", + .type = TYPE_COLOR, + .default_value = "#888888", + .value = &settings.colors_norm.frame, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "timeout", + .section = "urgency_normal", + .description = "Timeout for notifications with normal urgency", + .type = TYPE_TIME, + .default_value = "10", + .value = &settings.timeouts[URG_NORM], + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "background", + .section = "urgency_critical", + .description = + "Background color for notifications with critical urgency", + .type = TYPE_COLOR, + .default_value = "#900000", + .value = &settings.colors_crit.bg, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "foreground", + .section = "urgency_critical", + .description = + "Foreground color for notifications with ciritical urgency", + .type = TYPE_COLOR, + .default_value = "#ffffff", + .value = &settings.colors_crit.fg, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "highlight", + .section = "urgency_critical", + .description = + "Highlight color for notifications with ciritical urgency", + .type = TYPE_GRADIENT, + .default_value = "#ff6666", + .value = &settings.colors_crit.highlight, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "frame_color", + .section = "urgency_critical", + .description = "Frame color for notifications with critical urgency", + .type = TYPE_COLOR, + .default_value = "#ff0000", + .value = &settings.colors_crit.frame, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "timeout", + .section = "urgency_critical", + .description = "Timeout for notifications with critical urgency", + .type = TYPE_TIME, + .default_value = "0", + .value = &settings.timeouts[URG_CRIT], + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "origin", + .section = "global", + .description = "Specifies the where the notification is positioned " + "before offsetting.", + .type = TYPE_CUSTOM, + .default_value = "top-right", + .value = &settings.origin, + .parser = string_parse_enum, + .parser_data = origin_enum_data, + }, + { + .name = "width", + .section = "global", + .description = "The width of the notification, excluding the frame.", + .type = TYPE_LENGTH, + .default_value = "300", + .value = &settings.width, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "height", + .section = "global", + .description = "The height of a notification, excluding the frame.", + .type = TYPE_LENGTH, + .default_value = "(0, 300)", + .value = &settings.height, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "offset", + .section = "global", + .description = "The offset of the notification from the origin.", + .type = TYPE_LENGTH, + .default_value = "(10, 50)", + .value = &settings.offset, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "notification_limit", + .section = "global", + .description = "Maximum number of notifications allowed", + .type = TYPE_INT, + .default_value = "20", + .value = &settings.notification_limit, + .parser = NULL, + .parser_data = NULL, + }, - // Keyboard shortcuts (still in global section) - { - .name = "close", - .section = "global", - .description = "Shortcut for closing one notification", - .type = TYPE_STRING, - .default_value = "none", - .value = &settings.close_ks.str, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "close_all", - .section = "global", - .description = "Shortcut for closing all notifications", - .type = TYPE_STRING, - .default_value = "none", - .value = &settings.close_all_ks.str, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "history", - .section = "global", - .description = "Shortcut to pop the last notification from history", - .type = TYPE_STRING, - .default_value = "none", - .value = &settings.history_ks.str, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "context", - .section = "global", - .description = "Shortcut for context menu", - .type = TYPE_STRING, - .default_value = "none", - .value = &settings.context_ks.str, - .parser = NULL, - .parser_data = NULL, - }, - { - .name = "gap_size", - .section = "global", - .description = "Size of gap between notifications", - .type = TYPE_INT, - .default_value = "0", - .value = &settings.gap_size, - .parser = NULL, - .parser_data = NULL, - }, + // Keyboard shortcuts (still in global section) + { + .name = "close", + .section = "global", + .description = "Shortcut for closing one notification", + .type = TYPE_STRING, + .default_value = "none", + .value = &settings.close_ks.str, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "close_all", + .section = "global", + .description = "Shortcut for closing all notifications", + .type = TYPE_STRING, + .default_value = "none", + .value = &settings.close_all_ks.str, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "history", + .section = "global", + .description = "Shortcut to pop the last notification from history", + .type = TYPE_STRING, + .default_value = "none", + .value = &settings.history_ks.str, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "context", + .section = "global", + .description = "Shortcut for context menu", + .type = TYPE_STRING, + .default_value = "none", + .value = &settings.context_ks.str, + .parser = NULL, + .parser_data = NULL, + }, + { + .name = "gap_size", + .section = "global", + .description = "Size of gap between notifications", + .type = TYPE_INT, + .default_value = "0", + .value = &settings.gap_size, + .parser = NULL, + .parser_data = NULL, + }, }; #endif /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/utils.c b/src/utils.c index 1642f22ed..2ac325d44 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,4 +1,5 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ #include "utils.h" #include @@ -9,8 +10,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -21,472 +22,495 @@ /* see utils.h */ char *string_replace_char(char needle, char replacement, char *haystack) { - ASSERT_OR_RET(haystack, NULL); + ASSERT_OR_RET(haystack, NULL); - char *current = haystack; - while ((current = strchr(current, needle))) - *current++ = replacement; - return haystack; + char *current = haystack; + while ((current = strchr(current, needle))) + *current++ = replacement; + return haystack; } /* see utils.h */ char *string_replace_at(char *buf, int pos, int len, const char *repl) { - assert(buf); - assert(repl); + assert(buf); + assert(repl); - char *tmp; - int size, buf_len, repl_len; + char *tmp; + int size, buf_len, repl_len; - buf_len = strlen(buf); - repl_len = strlen(repl); - size = (buf_len - len) + repl_len + 1; + buf_len = strlen(buf); + repl_len = strlen(repl); + size = (buf_len - len) + repl_len + 1; - if (repl_len <= len) { - tmp = buf; - } else { - tmp = g_malloc(size); - memcpy(tmp, buf, pos); - } + if (repl_len <= len) { + tmp = buf; + } else { + tmp = g_malloc(size); + memcpy(tmp, buf, pos); + } - memcpy(tmp + pos, repl, repl_len); - memmove(tmp + pos + repl_len, buf + pos + len, buf_len - (pos + len) + 1); + memcpy(tmp + pos, repl, repl_len); + memmove(tmp + pos + repl_len, buf + pos + len, buf_len - (pos + len) + 1); - if (tmp != buf) { - g_free(buf); - } + if (tmp != buf) { + g_free(buf); + } - return tmp; + return tmp; } /* see utils.h */ -char *string_replace_all(const char *needle, const char *replacement, char *haystack) +char * +string_replace_all(const char *needle, const char *replacement, char *haystack) { - ASSERT_OR_RET(haystack, NULL); - assert(needle); - assert(replacement); - - char *start; - int needle_pos; - int needle_len, repl_len; + ASSERT_OR_RET(haystack, NULL); + assert(needle); + assert(replacement); - needle_len = strlen(needle); - if (needle_len == 0) { - return haystack; - } + char *start; + int needle_pos; + int needle_len, repl_len; - start = strstr(haystack, needle); - repl_len = strlen(replacement); - - while (start) { - needle_pos = start - haystack; - haystack = string_replace_at(haystack, needle_pos, needle_len, replacement); - start = strstr(haystack + needle_pos + repl_len, needle); - } + needle_len = strlen(needle); + if (needle_len == 0) { return haystack; + } + + start = strstr(haystack, needle); + repl_len = strlen(replacement); + + while (start) { + needle_pos = start - haystack; + haystack = + string_replace_at(haystack, needle_pos, needle_len, replacement); + start = strstr(haystack + needle_pos + repl_len, needle); + } + return haystack; } /* see utils.h */ char *string_append(char *a, const char *b, const char *sep) { - if (STR_EMPTY(a)) { - g_free(a); - return g_strdup(b); - } - if (STR_EMPTY(b)) - return a; - - char *new; - if (!sep) - new = g_strconcat(a, b, NULL); - else - new = g_strconcat(a, sep, b, NULL); + if (STR_EMPTY(a)) { g_free(a); - - return new; + return g_strdup(b); + } + if (STR_EMPTY(b)) + return a; + + char *new; + if (!sep) + new = g_strconcat(a, b, NULL); + else + new = g_strconcat(a, sep, b, NULL); + g_free(a); + + return new; } /* see utils.h */ char *string_strip_quotes(const char *value) { - ASSERT_OR_RET(value, NULL); + ASSERT_OR_RET(value, NULL); - size_t len = strlen(value); - char *s; + size_t len = strlen(value); + char *s; - if (value[0] == '"' && value[len-1] == '"') - s = g_strndup(value + 1, len-2); - else - s = g_strdup(value); + if (value[0] == '"' && value[len - 1] == '"') + s = g_strndup(value + 1, len - 2); + else + s = g_strdup(value); - return s; + return s; } /* see utils.h */ void string_strip_delimited(char *str, char a, char b) { - assert(str); - - int iread=-1, iwrite=0, copen=0; - int cskip = 0; - while (str[++iread] != 0) { - if (str[iread] == a) { - ++copen; - } else if (str[iread] == b && copen > 0) { - --copen; - } else if (copen == 0) { - cskip = 0; - str[iwrite++] = str[iread]; - } - if (copen > 0) { - cskip++; - } + assert(str); + + int iread = -1, iwrite = 0, copen = 0; + int cskip = 0; + while (str[++iread] != 0) { + if (str[iread] == a) { + ++copen; + } else if (str[iread] == b && copen > 0) { + --copen; + } else if (copen == 0) { + cskip = 0; + str[iwrite++] = str[iread]; } if (copen > 0) { - iread -= cskip; - for (int i = 0; i < cskip; i++) { - str[iwrite++] = str[iread++]; - } + cskip++; + } + } + if (copen > 0) { + iread -= cskip; + for (int i = 0; i < cskip; i++) { + str[iwrite++] = str[iread++]; } - str[iwrite] = 0; + } + str[iwrite] = 0; } /* see utils.h */ char **string_to_array(const char *string, const char *delimiter) { - char **arr = NULL; - if (string) { - arr = g_strsplit(string, delimiter, 0); - for (int i = 0; arr[i]; i++) { - g_strstrip(arr[i]); - } + char **arr = NULL; + if (string) { + arr = g_strsplit(string, delimiter, 0); + for (int i = 0; arr[i]; i++) { + g_strstrip(arr[i]); } - return arr; + } + return arr; } /* see utils.h */ int string_array_length(char **s) { - if (!s) - return -1; + if (!s) + return -1; - int len = 0; - while (s[len]) - len++; + int len = 0; + while (s[len]) + len++; - return len; + return len; } /* see utils.h */ char *string_to_path(char *string) { - ASSERT_OR_RET(string, string); - - wordexp_t we; - switch (wordexp(string, &we, WRDE_NOCMD | WRDE_UNDEF)) { - case 0: - break; - case WRDE_BADCHAR: - LOG_W("Expansion of \"%s\" failed. It contains invalid characters.", string); - return string; - case WRDE_BADVAL: - LOG_W("Expansion of \"%s\" failed. It contains an undefined variable.", string); - return string; - case WRDE_CMDSUB: - LOG_W("Expansion of \"%s\" failed. The requested command substitution is currently not supported.", string); - return string; - case WRDE_NOSPACE: - LOG_W("Expansion of \"%s\" failed. We ran out of memory.", string); - return string; - case WRDE_SYNTAX: - LOG_W("Expansion of \"%s\" failed. It contains invalid syntax.", string); - return string; - } - g_free(string); - - char *res = g_strjoinv(" ", we.we_wordv); - wordfree(&we); - - return res; + ASSERT_OR_RET(string, string); + + wordexp_t we; + switch (wordexp(string, &we, WRDE_NOCMD | WRDE_UNDEF)) { + case 0: break; + case WRDE_BADCHAR: + LOG_W("Expansion of \"%s\" failed. It contains invalid characters.", + string); + return string; + case WRDE_BADVAL: + LOG_W("Expansion of \"%s\" failed. It contains an undefined variable.", + string); + return string; + case WRDE_CMDSUB: + LOG_W("Expansion of \"%s\" failed. The requested command substitution " + "is currently not supported.", + string); + return string; + case WRDE_NOSPACE: + LOG_W("Expansion of \"%s\" failed. We ran out of memory.", string); + return string; + case WRDE_SYNTAX: + LOG_W("Expansion of \"%s\" failed. It contains invalid syntax.", + string); + return string; + } + g_free(string); + + char *res = g_strjoinv(" ", we.we_wordv); + wordfree(&we); + + return res; } /* see utils.h */ -bool safe_string_to_long_long(long long *in, const char *str) { - errno = 0; - char *endptr; - long long val = g_ascii_strtoll(str, &endptr, 10); - - if (errno != 0) { - LOG_W("'%s': %s.", str, strerror(errno)); - return false; - } else if (str == endptr) { - LOG_W("'%s': No digits found.", str); - return false; - } else if (*endptr != '\0') { - LOG_W("'%s': String contains non-digits.", str); - return false; - } - *in = val; - return true; +bool safe_string_to_long_long(long long *in, const char *str) +{ + errno = 0; + char *endptr; + long long val = g_ascii_strtoll(str, &endptr, 10); + + if (errno != 0) { + LOG_W("'%s': %s.", str, strerror(errno)); + return false; + } else if (str == endptr) { + LOG_W("'%s': No digits found.", str); + return false; + } else if (*endptr != '\0') { + LOG_W("'%s': String contains non-digits.", str); + return false; + } + *in = val; + return true; } /* see utils.h */ -bool safe_string_to_int(int *in, const char *str) { - long long l; - if (!safe_string_to_long_long(&l, str)) - return false; - - // Check if it's in int range - if (l < INT_MIN || l > INT_MAX) { - errno = ERANGE; - LOG_W("'%s': %s.", str, strerror(errno)); - return false; - } +bool safe_string_to_int(int *in, const char *str) +{ + long long l; + if (!safe_string_to_long_long(&l, str)) + return false; + + // Check if it's in int range + if (l < INT_MIN || l > INT_MAX) { + errno = ERANGE; + LOG_W("'%s': %s.", str, strerror(errno)); + return false; + } - *in = (int) l; - return true; + *in = (int)l; + return true; } /* see utils.h */ -bool safe_string_to_double(double *in, const char *str) { - errno = 0; - char *endptr; - double val = g_ascii_strtod(str, &endptr); - if (errno != 0) { - LOG_W("'%s': %s.", str, strerror(errno)); - return false; - } else if (str == endptr) { - LOG_W("'%s': No digits found.", str); - return false; - } else if (*endptr != '\0') { - LOG_W("'%s': String contains non-digits.", str); - return false; - } - *in = val; - return true; +bool safe_string_to_double(double *in, const char *str) +{ + errno = 0; + char *endptr; + double val = g_ascii_strtod(str, &endptr); + if (errno != 0) { + LOG_W("'%s': %s.", str, strerror(errno)); + return false; + } else if (str == endptr) { + LOG_W("'%s': No digits found.", str); + return false; + } else if (*endptr != '\0') { + LOG_W("'%s': String contains non-digits.", str); + return false; + } + *in = val; + return true; } /* see utils.h */ gint64 string_to_time(const char *string) { - assert(string); - - errno = 0; - char *endptr; - gint64 val = strtol(string, &endptr, 10); - - if (errno != 0) { - LOG_W("Time: '%s': %s.", string, strerror(errno)); - return 0; - } else if (string == endptr) { - errno = EINVAL; - LOG_W("Time: '%s': No digits found.", string); - return 0; - } else if (val < -1) { - // most times should not be negative, but show_age_threshhold - // can be -1 - LOG_W("Time: '%s': Time should be positive (-1 is allowed too sometimes)", - string); - errno = EINVAL; - } - else if (errno == 0 && !*endptr) { - return S2US(val); - } - // endptr may point to a separating space - while (isspace(*endptr)) - endptr++; - - if (val < 0) { - LOG_W("Time: '%s' signal value -1 should not have a suffix", string); - errno = EINVAL; - return 0; - } - - if (STRN_EQ(endptr, "ms", 2)) - return val * 1000; - else if (STRN_EQ(endptr, "s", 1)) - return S2US(val); - else if (STRN_EQ(endptr, "m", 1)) - return S2US(val) * 60; - else if (STRN_EQ(endptr, "h", 1)) - return S2US(val) * 60 * 60; - else if (STRN_EQ(endptr, "d", 1)) - return S2US(val) * 60 * 60 * 24; - else - { - errno = EINVAL; - return 0; - } + assert(string); + + errno = 0; + char *endptr; + gint64 val = strtol(string, &endptr, 10); + + if (errno != 0) { + LOG_W("Time: '%s': %s.", string, strerror(errno)); + return 0; + } else if (string == endptr) { + errno = EINVAL; + LOG_W("Time: '%s': No digits found.", string); + return 0; + } else if (val < -1) { + // most times should not be negative, but show_age_threshhold + // can be -1 + LOG_W( + "Time: '%s': Time should be positive (-1 is allowed too sometimes)", + string); + errno = EINVAL; + } else if (errno == 0 && !*endptr) { + return S2US(val); + } + // endptr may point to a separating space + while (isspace(*endptr)) + endptr++; + + if (val < 0) { + LOG_W("Time: '%s' signal value -1 should not have a suffix", string); + errno = EINVAL; + return 0; + } + + if (STRN_EQ(endptr, "ms", 2)) + return val * 1000; + else if (STRN_EQ(endptr, "s", 1)) + return S2US(val); + else if (STRN_EQ(endptr, "m", 1)) + return S2US(val) * 60; + else if (STRN_EQ(endptr, "h", 1)) + return S2US(val) * 60 * 60; + else if (STRN_EQ(endptr, "d", 1)) + return S2US(val) * 60 * 60 * 24; + else { + errno = EINVAL; + return 0; + } } /* see utils.h */ gint64 time_monotonic_now(void) { - struct timespec tv_now; + struct timespec tv_now; - /* On Linux, BOOTTIME is the correct monotonic time, - * as BOOTTIME counts onwards during sleep. For all other - * POSIX compliant OSes, MONOTONIC should also count onwards - * during system sleep. */ + /* On Linux, BOOTTIME is the correct monotonic time, + * as BOOTTIME counts onwards during sleep. For all other + * POSIX compliant OSes, MONOTONIC should also count onwards + * during system sleep. */ #ifdef __linux__ - clock_gettime(CLOCK_BOOTTIME, &tv_now); + clock_gettime(CLOCK_BOOTTIME, &tv_now); #else - clock_gettime(CLOCK_MONOTONIC, &tv_now); + clock_gettime(CLOCK_MONOTONIC, &tv_now); #endif - return S2US(tv_now.tv_sec) + tv_now.tv_nsec / 1000; + return S2US(tv_now.tv_sec) + tv_now.tv_nsec / 1000; } /* see utils.h */ const char *user_get_home(void) { - static const char *home_directory = NULL; - ASSERT_OR_RET(!home_directory, home_directory); + static const char *home_directory = NULL; + ASSERT_OR_RET(!home_directory, home_directory); - // Check the HOME variable for the user's home - home_directory = getenv("HOME"); - ASSERT_OR_RET(!home_directory, home_directory); + // Check the HOME variable for the user's home + home_directory = getenv("HOME"); + ASSERT_OR_RET(!home_directory, home_directory); - // Check the /etc/passwd entry for the user's home - home_directory = getpwuid(getuid())->pw_dir; + // Check the /etc/passwd entry for the user's home + home_directory = getpwuid(getuid())->pw_dir; - return home_directory; + return home_directory; } /* see utils.h */ -bool safe_setenv(const char* key, const char* value){ - if (!key) - return false; +bool safe_setenv(const char *key, const char *value) +{ + if (!key) + return false; - if (!value) - setenv(key, "", 1); - else - setenv(key, value, 1); + if (!value) + setenv(key, "", 1); + else + setenv(key, value, 1); - return true; + return true; } // These sections are not interpreted as rules -static const char* special_sections[] = { - "global", - "frame", - "experimental", - "shortcuts", - "urgency_low", - "urgency_normal", - "urgency_critical", +static const char *special_sections[] = { + "global", + "frame", + "experimental", + "shortcuts", + "urgency_low", + "urgency_normal", + "urgency_critical", }; -static const char* deprecated_sections[] = { - "frame", - "shortcuts", +static const char *deprecated_sections[] = { + "frame", + "shortcuts", }; -static const char* deprecated_sections_message[] = { - "The settings from the frame section have been moved to the global section.", // frame - "Settings in the shortcuts sections have been moved to the global section.\nAlternatively you can bind shortcuts in your window manager to dunstctl commands. For that, see the manual for dunstctl.", // shortcuts +static const char *deprecated_sections_message[] = { + "The settings from the frame section have been moved to the global " + "section.", // frame + "Settings in the shortcuts sections have been moved to the global " + "section.\nAlternatively you can bind shortcuts in your window manager to " + "dunstctl commands. For that, see the manual for dunstctl.", // shortcuts }; /* see utils.h */ -bool is_special_section(const char* s) { - for (size_t i = 0; i < G_N_ELEMENTS(special_sections); i++) { - if (STR_EQ(special_sections[i], s)) { - return true; - } +bool is_special_section(const char *s) +{ + for (size_t i = 0; i < G_N_ELEMENTS(special_sections); i++) { + if (STR_EQ(special_sections[i], s)) { + return true; } - return false; + } + return false; } /* see utils.h */ -bool is_deprecated_section(const char* s) { - for (size_t i = 0; i < G_N_ELEMENTS(deprecated_sections); i++) { - if (STR_EQ(deprecated_sections[i], s)) { - return true; - } +bool is_deprecated_section(const char *s) +{ + for (size_t i = 0; i < G_N_ELEMENTS(deprecated_sections); i++) { + if (STR_EQ(deprecated_sections[i], s)) { + return true; } - return false; + } + return false; } -const char *get_section_deprecation_message(const char *s) { - for (size_t i = 0; i < G_N_ELEMENTS(deprecated_sections); i++) { - if (STR_EQ(deprecated_sections[i], s)) { - return deprecated_sections_message[i]; - } +const char *get_section_deprecation_message(const char *s) +{ + for (size_t i = 0; i < G_N_ELEMENTS(deprecated_sections); i++) { + if (STR_EQ(deprecated_sections[i], s)) { + return deprecated_sections_message[i]; } - return ""; + } + return ""; } /* see utils.h */ -char *string_strip_brackets(const char* s) { - if (!s) - return NULL; - - size_t len = strlen(s); - if (s[0] == '(' && s[len-1] == ')') - return g_strndup(s + 1, len-2); - else - return NULL; - +char *string_strip_brackets(const char *s) +{ + if (!s) + return NULL; + + size_t len = strlen(s); + if (s[0] == '(' && s[len - 1] == ')') + return g_strndup(s + 1, len - 2); + else + return NULL; } /* see utils.h */ -bool is_readable_file(const char * const path) +bool is_readable_file(const char *const path) { - struct stat statbuf; - bool result = false; - - if (0 == stat(path, &statbuf)) { - /** See what intersting stuff can be done with FIFOs */ - if (!(statbuf.st_mode & (S_IFIFO | S_IFREG))) { - /** Sets errno if stat() was successful but @p path [in] - * does not point to a regular file or FIFO. This - * just in case someone queries errno which would - * otherwise indicate success. */ - errno = EINVAL; - } else if (0 == access(path, R_OK)) { /* must also be readable */ - result = true; - } + struct stat statbuf; + bool result = false; + + if (0 == stat(path, &statbuf)) { + /** See what intersting stuff can be done with FIFOs */ + if (!(statbuf.st_mode & (S_IFIFO | S_IFREG))) { + /** Sets errno if stat() was successful but @p path [in] + * does not point to a regular file or FIFO. This + * just in case someone queries errno which would + * otherwise indicate success. */ + errno = EINVAL; + } else if (0 == access(path, R_OK)) { /* must also be readable */ + result = true; } + } - return result; + return result; } /* see utils.h */ -FILE *fopen_verbose(const char * const path) +FILE *fopen_verbose(const char *const path) { - FILE *f = NULL; - char *real_path = string_to_path(g_strdup(path)); + FILE *f = NULL; + char *real_path = string_to_path(g_strdup(path)); - if (is_readable_file(real_path) && (f = fopen(real_path, "r"))) - LOG_I(MSG_FOPEN_SUCCESS(path, f)); - else - LOG_W(MSG_FOPEN_FAILURE(path)); + if (is_readable_file(real_path) && (f = fopen(real_path, "r"))) + LOG_I(MSG_FOPEN_SUCCESS(path, f)); + else + LOG_W(MSG_FOPEN_FAILURE(path)); - g_free(real_path); - return f; + g_free(real_path); + return f; } /* see utils.h */ -void add_paths_from_env(GPtrArray *arr, char *env_name, char *subdir, char *alternative) { - const char *xdg_data_dirs = g_getenv(env_name); - if (!xdg_data_dirs) - xdg_data_dirs = alternative; - - char **xdg_data_dirs_arr = string_to_array(xdg_data_dirs, ":"); - for (int i = 0; xdg_data_dirs_arr[i] != NULL; i++) { - char *loc = g_build_filename(xdg_data_dirs_arr[i], subdir, NULL); - g_ptr_array_add(arr, loc); - } - g_strfreev(xdg_data_dirs_arr); +void add_paths_from_env(GPtrArray *arr, + char *env_name, + char *subdir, + char *alternative) +{ + const char *xdg_data_dirs = g_getenv(env_name); + if (!xdg_data_dirs) + xdg_data_dirs = alternative; + + char **xdg_data_dirs_arr = string_to_array(xdg_data_dirs, ":"); + for (int i = 0; xdg_data_dirs_arr[i] != NULL; i++) { + char *loc = g_build_filename(xdg_data_dirs_arr[i], subdir, NULL); + g_ptr_array_add(arr, loc); + } + g_strfreev(xdg_data_dirs_arr); } -bool string_is_int(const char *str) { - if (str != NULL) { - while (isspace(*str)) str++; - while (isdigit(*str)) str++; - while (isspace(*str)) str++; - return *str == '\0'; - } - return true; +bool string_is_int(const char *str) +{ + if (str != NULL) { + while (isspace(*str)) + str++; + while (isdigit(*str)) + str++; + while (isspace(*str)) + str++; + return *str == '\0'; + } + return true; } /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/utils.h b/src/utils.h index 8a160104b..68ec785cf 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,4 +1,5 @@ -/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing + * information) */ #ifndef DUNST_UTILS_H #define DUNST_UTILS_H @@ -22,21 +23,24 @@ //! Stringify the given expression or macro #define STR_TO(...) _STR_TO(__VA_ARGS__) -#define _STR_TO(...) "" # __VA_ARGS__ +#define _STR_TO(...) "" #__VA_ARGS__ //! Make a gboolean from a boolean value // See https://github.com/dunst-project/dunst/issues/1421 #define BOOL2G(x) ((x) ? TRUE : FALSE) //! Assert that expr evaluates to true, if not return with val -#define ASSERT_OR_RET(expr, val) if (!(expr)) return val; +#define ASSERT_OR_RET(expr, val) \ + if (!(expr)) \ + return val; //! Convert a second into the internal time representation #define S2US(s) (((gint64)(s)) * G_USEC_PER_SEC) #define US2S(s) (((gint64)(s)) / G_USEC_PER_SEC) /** - * Replaces all occurrences of the char \p needle with the char \p replacement in \p haystack. + * Replaces all occurrences of the char \p needle with the char \p replacement + * in \p haystack. * * Does not allocate a new string. * @@ -67,10 +71,12 @@ char *string_replace_at(char *buf, int pos, int len, const char *repl); * @param replacement The substring to replace * @param haystack (nullable) The string to search the substring for */ -char *string_replace_all(const char *needle, const char *replacement, char *haystack); +char * +string_replace_all(const char *needle, const char *replacement, char *haystack); /** - * Append \p b to string \p a. And concatenate both strings with \p concat, if both are non-empty. + * Append \p b to string \p a. And concatenate both strings with \p concat, if + * both are non-empty. * * @param a (nullable) The left side of the string * @param b (nullable) The right side of the string @@ -111,7 +117,8 @@ char **string_to_array(const char *string, const char *delimiter); /** * Replace tilde and path-specific values with its equivalents * - * The string gets invalidated. The new valid representation is the return value. + * The string gets invalidated. The new valid representation is the return + * value. * * @param string (nullable) The string to convert to a path. * @returns The tilde-replaced string. @@ -174,7 +181,7 @@ const char *user_get_home(void); * @param value (nullable) The value to change it to. * @returns: A bool that is true when it succeeds */ -bool safe_setenv(const char* key, const char* value); +bool safe_setenv(const char *key, const char *value); /** * Some sections are handled differently in dunst. This function tells wether a @@ -183,7 +190,7 @@ bool safe_setenv(const char* key, const char* value); * @param s The name of the section * @returns A bool wether this section is one of the special sections */ -bool is_special_section(const char* s); +bool is_special_section(const char *s); /** * This function tells if a section is deprecated. @@ -191,11 +198,10 @@ bool is_special_section(const char* s); * @param s The name of the section * @returns A bool wether this section is deprecated */ -bool is_deprecated_section(const char* s); +bool is_deprecated_section(const char *s); const char *get_section_deprecation_message(const char *s); - /** * Strips a string of it's brackets if the first and last character are a * bracket. Returns NULL on error. @@ -203,8 +209,7 @@ const char *get_section_deprecation_message(const char *s); * @param s String to strip * @returns Newly allocated string without the brackets, or NULL. */ -char *string_strip_brackets(const char* s); - +char *string_strip_brackets(const char *s); /** * Returns the length of a string array, -1 if the input is NULL. @@ -228,7 +233,7 @@ int string_array_length(char **s); * @retval true in case of success. * @retval false in case of failure, errno will be set appropriately. */ -bool is_readable_file(const char * const path); +bool is_readable_file(const char *const path); /** @brief Open files verbosely. * @@ -240,7 +245,7 @@ bool is_readable_file(const char * const path); * @retval NULL if the fopen() call failed or @p path does not satisfy the * conditions of is_readable_file(). */ -FILE * fopen_verbose(const char * const path); +FILE *fopen_verbose(const char *const path); /** * Adds the contents of env_name with subdir to the array, interpreting the @@ -255,7 +260,10 @@ FILE * fopen_verbose(const char * const path); * @param alternative A colon-separated list of paths to use as alternative * when the environment variable doesn't exits. */ -void add_paths_from_env(GPtrArray *arr, char *env_name, char *subdir, char *alternative); +void add_paths_from_env(GPtrArray *arr, + char *env_name, + char *subdir, + char *alternative); bool string_is_int(const char *str); diff --git a/src/wayland/wl.c b/src/wayland/wl.c index 4d89ad279..42d3fea27 100644 --- a/src/wayland/wl.c +++ b/src/wayland/wl.c @@ -684,7 +684,7 @@ bool wl_have_fullscreen_window(void) { output_name = current_output->global_name; struct toplevel_v1 *toplevel; - wl_list_for_each(toplevel, &toplevel_list, link) { + wl_list_for_each(toplevel, &toplevel_list, link) { if (!(toplevel->current.state & TOPLEVEL_STATE_FULLSCREEN && toplevel->current.state & TOPLEVEL_STATE_ACTIVATED)) diff --git a/test/dbus.c b/test/dbus.c index d675111ea..e5052c6d2 100644 --- a/test/dbus.c +++ b/test/dbus.c @@ -12,47 +12,53 @@ extern const char *base; -void wake_up_void(void) { } +void wake_up_void(void) {} -struct signal_actioninvoked { - guint id; - gchar *key; - guint subscription_id; - GDBusConnection *conn; +struct signal_actioninvoked +{ + guint id; + gchar *key; + guint subscription_id; + GDBusConnection *conn; }; -struct signal_propertieschanged { - gchar *interface; - GVariant *array_dict_sv_data; - GVariant *array_s_data; - guint subscription_id; - GDBusConnection *conn; +struct signal_propertieschanged +{ + gchar *interface; + GVariant *array_dict_sv_data; + GVariant *array_s_data; + guint subscription_id; + GDBusConnection *conn; }; -struct signal_closed { - guint32 id; - guint32 reason; - guint subscription_id; - GDBusConnection *conn; +struct signal_closed +{ + guint32 id; + guint32 reason; + guint subscription_id; + GDBusConnection *conn; }; -struct signal_historyremoved { - guint32 id; - bool removed; - guint subscription_id; - GDBusConnection *conn; +struct signal_historyremoved +{ + guint32 id; + bool removed; + guint subscription_id; + GDBusConnection *conn; }; -struct signal_historycleared { - guint32 count; - guint subscription_id; - GDBusConnection *conn; +struct signal_historycleared +{ + guint32 count; + guint subscription_id; + GDBusConnection *conn; }; -struct signal_configreloaded { - gchar **configs; - guint subscription_id; - GDBusConnection *conn; +struct signal_configreloaded +{ + gchar **configs; + guint subscription_id; + GDBusConnection *conn; }; void dbus_signal_cb_actioninvoked(GDBusConnection *connection, @@ -63,450 +69,457 @@ void dbus_signal_cb_actioninvoked(GDBusConnection *connection, GVariant *parameters, gpointer user_data) { - g_return_if_fail(user_data); + g_return_if_fail(user_data); - guint32 id; - gchar *key; + guint32 id; + gchar *key; - struct signal_actioninvoked *sig = (struct signal_actioninvoked*) user_data; + struct signal_actioninvoked *sig = (struct signal_actioninvoked *)user_data; - g_variant_get(parameters, "(us)", &id, &key); + g_variant_get(parameters, "(us)", &id, &key); - if (id == sig->id) { - sig->id = id; - sig->key = key; - } + if (id == sig->id) { + sig->id = id; + sig->key = key; + } } -void dbus_signal_subscribe_actioninvoked(struct signal_actioninvoked *actioninvoked) -{ - assert(actioninvoked); - - actioninvoked->conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); - actioninvoked->subscription_id = - g_dbus_connection_signal_subscribe( - actioninvoked->conn, - FDN_NAME, - FDN_IFAC, - "ActionInvoked", - FDN_PATH, - NULL, - G_DBUS_SIGNAL_FLAGS_NONE, - dbus_signal_cb_actioninvoked, - actioninvoked, - NULL); +void dbus_signal_subscribe_actioninvoked( + struct signal_actioninvoked *actioninvoked) +{ + assert(actioninvoked); + + actioninvoked->conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); + actioninvoked->subscription_id = + g_dbus_connection_signal_subscribe(actioninvoked->conn, + FDN_NAME, + FDN_IFAC, + "ActionInvoked", + FDN_PATH, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + dbus_signal_cb_actioninvoked, + actioninvoked, + NULL); } -void dbus_signal_unsubscribe_actioninvoked(struct signal_actioninvoked *actioninvoked) +void dbus_signal_unsubscribe_actioninvoked( + struct signal_actioninvoked *actioninvoked) { - assert(actioninvoked); + assert(actioninvoked); - g_dbus_connection_signal_unsubscribe(actioninvoked->conn, actioninvoked->subscription_id); - g_object_unref(actioninvoked->conn); + g_dbus_connection_signal_unsubscribe(actioninvoked->conn, + actioninvoked->subscription_id); + g_object_unref(actioninvoked->conn); - actioninvoked->conn = NULL; - actioninvoked->subscription_id = -1; + actioninvoked->conn = NULL; + actioninvoked->subscription_id = -1; } void dbus_signal_cb_propertieschanged(GDBusConnection *connection, - const gchar *sender_name, - const gchar *object_path, - const gchar *interface_name, - const gchar *signal_name, - GVariant *parameters, - gpointer user_data) + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) { - g_return_if_fail(user_data); - - gchar *interface; - GVariant *array_dict_sv_data; - GVariant *array_s_data; - - struct signal_propertieschanged *sig = (struct signal_propertieschanged*) user_data; - - g_variant_get(parameters, "(s@a{sv}@as)", &interface, &array_dict_sv_data, &array_s_data); - - if (g_strcmp0(interface, DUNST_IFAC) == 0) { - sig->interface = interface; - sig->array_dict_sv_data = array_dict_sv_data; - sig->array_s_data = array_s_data; - } - + g_return_if_fail(user_data); + + gchar *interface; + GVariant *array_dict_sv_data; + GVariant *array_s_data; + + struct signal_propertieschanged *sig = + (struct signal_propertieschanged *)user_data; + + g_variant_get(parameters, + "(s@a{sv}@as)", + &interface, + &array_dict_sv_data, + &array_s_data); + + if (g_strcmp0(interface, DUNST_IFAC) == 0) { + sig->interface = interface; + sig->array_dict_sv_data = array_dict_sv_data; + sig->array_s_data = array_s_data; + } } -void dbus_signal_subscribe_propertieschanged(struct signal_propertieschanged *propertieschanged) -{ - assert(propertieschanged); - - propertieschanged->conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); - propertieschanged->subscription_id = - g_dbus_connection_signal_subscribe( - // GDBusConnection *connection, - propertieschanged->conn, - // const gchar *sender, - FDN_NAME, - // const gchar *interface_name, - PROPERTIES_IFAC, - // const gchar *member, - "PropertiesChanged", - // const gchar *object_path, - FDN_PATH, - // const gchar *arg0, - NULL, - // GDBusSignalFlags flags, - G_DBUS_SIGNAL_FLAGS_NONE, - // GDBusSignalCallback callback, - dbus_signal_cb_propertieschanged, - // gpointer user_data, - propertieschanged, - // GDestroyNotify user_data_free_func - NULL); - +void dbus_signal_subscribe_propertieschanged( + struct signal_propertieschanged *propertieschanged) +{ + assert(propertieschanged); + + propertieschanged->conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); + propertieschanged->subscription_id = g_dbus_connection_signal_subscribe( + // GDBusConnection *connection, + propertieschanged->conn, + // const gchar *sender, + FDN_NAME, + // const gchar *interface_name, + PROPERTIES_IFAC, + // const gchar *member, + "PropertiesChanged", + // const gchar *object_path, + FDN_PATH, + // const gchar *arg0, + NULL, + // GDBusSignalFlags flags, + G_DBUS_SIGNAL_FLAGS_NONE, + // GDBusSignalCallback callback, + dbus_signal_cb_propertieschanged, + // gpointer user_data, + propertieschanged, + // GDestroyNotify user_data_free_func + NULL); } -void dbus_signal_unsubscribe_propertieschanged(struct signal_propertieschanged *propertieschanged) +void dbus_signal_unsubscribe_propertieschanged( + struct signal_propertieschanged *propertieschanged) { - assert(propertieschanged); + assert(propertieschanged); - g_dbus_connection_signal_unsubscribe(propertieschanged->conn, propertieschanged->subscription_id); - g_object_unref(propertieschanged->conn); + g_dbus_connection_signal_unsubscribe(propertieschanged->conn, + propertieschanged->subscription_id); + g_object_unref(propertieschanged->conn); - propertieschanged->conn = NULL; - propertieschanged->subscription_id = -1; + propertieschanged->conn = NULL; + propertieschanged->subscription_id = -1; } void dbus_signal_cb_closed(GDBusConnection *connection, - const gchar *sender_name, - const gchar *object_path, - const gchar *interface_name, - const gchar *signal_name, - GVariant *parameters, - gpointer user_data) + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) { - g_return_if_fail(user_data); + g_return_if_fail(user_data); - guint32 id; - guint32 reason; + guint32 id; + guint32 reason; - struct signal_closed *sig = (struct signal_closed*) user_data; - g_variant_get(parameters, "(uu)", &id, &reason); + struct signal_closed *sig = (struct signal_closed *)user_data; + g_variant_get(parameters, "(uu)", &id, &reason); - if (id == sig->id) { - sig->id = id; - sig->reason = reason; - } + if (id == sig->id) { + sig->id = id; + sig->reason = reason; + } } void dbus_signal_subscribe_closed(struct signal_closed *closed) { - assert(closed); - - closed->conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); - closed->subscription_id = - g_dbus_connection_signal_subscribe( - closed->conn, - FDN_NAME, - FDN_IFAC, - "NotificationClosed", - FDN_PATH, - NULL, - G_DBUS_SIGNAL_FLAGS_NONE, - dbus_signal_cb_closed, - closed, - NULL); + assert(closed); + + closed->conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); + closed->subscription_id = + g_dbus_connection_signal_subscribe(closed->conn, + FDN_NAME, + FDN_IFAC, + "NotificationClosed", + FDN_PATH, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + dbus_signal_cb_closed, + closed, + NULL); } void dbus_signal_unsubscribe_closed(struct signal_closed *closed) { - assert(closed); + assert(closed); - g_dbus_connection_signal_unsubscribe(closed->conn, closed->subscription_id); - g_object_unref(closed->conn); + g_dbus_connection_signal_unsubscribe(closed->conn, closed->subscription_id); + g_object_unref(closed->conn); - closed->conn = NULL; - closed->subscription_id = -1; + closed->conn = NULL; + closed->subscription_id = -1; } void dbus_signal_cb_historyremoved(GDBusConnection *connection, - const gchar *sender_name, - const gchar *object_path, - const gchar *interface_name, - const gchar *signal_name, - GVariant *parameters, - gpointer user_data) + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) { - g_return_if_fail(user_data); + g_return_if_fail(user_data); - guint32 id; + guint32 id; - struct signal_historyremoved *sig = (struct signal_historyremoved*) user_data; - g_variant_get(parameters, "(u)", &id); + struct signal_historyremoved *sig = + (struct signal_historyremoved *)user_data; + g_variant_get(parameters, "(u)", &id); - if (id == sig->id) { - sig->removed = true; - } + if (id == sig->id) { + sig->removed = true; + } } void dbus_signal_subscribe_historyremoved(struct signal_historyremoved *sig) { - assert(sig); - - sig->conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); - sig->subscription_id = - g_dbus_connection_signal_subscribe( - sig->conn, - FDN_NAME, - DUNST_IFAC, - "NotificationHistoryRemoved", - FDN_PATH, - NULL, - G_DBUS_SIGNAL_FLAGS_NONE, - dbus_signal_cb_historyremoved, - sig, - NULL); + assert(sig); + + sig->conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); + sig->subscription_id = + g_dbus_connection_signal_subscribe(sig->conn, + FDN_NAME, + DUNST_IFAC, + "NotificationHistoryRemoved", + FDN_PATH, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + dbus_signal_cb_historyremoved, + sig, + NULL); } void dbus_signal_unsubscribe_historyremoved(struct signal_historyremoved *sig) { - assert(sig); + assert(sig); - g_dbus_connection_signal_unsubscribe(sig->conn, sig->subscription_id); - g_object_unref(sig->conn); + g_dbus_connection_signal_unsubscribe(sig->conn, sig->subscription_id); + g_object_unref(sig->conn); - sig->conn = NULL; - sig->subscription_id = -1; + sig->conn = NULL; + sig->subscription_id = -1; } void dbus_signal_cb_historycleared(GDBusConnection *connection, - const gchar *sender_name, - const gchar *object_path, - const gchar *interface_name, - const gchar *signal_name, - GVariant *parameters, - gpointer user_data) + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) { - g_return_if_fail(user_data); + g_return_if_fail(user_data); - guint32 count; + guint32 count; - struct signal_historycleared *sig = (struct signal_historycleared*) user_data; - g_variant_get(parameters, "(u)", &count); + struct signal_historycleared *sig = + (struct signal_historycleared *)user_data; + g_variant_get(parameters, "(u)", &count); - sig->count = count; + sig->count = count; } void dbus_signal_subscribe_historycleared(struct signal_historycleared *sig) { - assert(sig); - - sig->conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); - sig->subscription_id = - g_dbus_connection_signal_subscribe( - sig->conn, - FDN_NAME, - DUNST_IFAC, - "NotificationHistoryCleared", - FDN_PATH, - NULL, - G_DBUS_SIGNAL_FLAGS_NONE, - dbus_signal_cb_historycleared, - sig, - NULL); + assert(sig); + + sig->conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); + sig->subscription_id = + g_dbus_connection_signal_subscribe(sig->conn, + FDN_NAME, + DUNST_IFAC, + "NotificationHistoryCleared", + FDN_PATH, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + dbus_signal_cb_historycleared, + sig, + NULL); } void dbus_signal_unsubscribe_historycleared(struct signal_historycleared *sig) { - assert(sig); + assert(sig); - g_dbus_connection_signal_unsubscribe(sig->conn, sig->subscription_id); - g_object_unref(sig->conn); + g_dbus_connection_signal_unsubscribe(sig->conn, sig->subscription_id); + g_object_unref(sig->conn); - sig->conn = NULL; - sig->subscription_id = -1; + sig->conn = NULL; + sig->subscription_id = -1; } - void dbus_signal_cb_configreloaded(GDBusConnection *connection, - const gchar *sender_name, - const gchar *object_path, - const gchar *interface_name, - const gchar *signal_name, - GVariant *parameters, - gpointer user_data) + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) { - g_return_if_fail(user_data); + g_return_if_fail(user_data); - gchar **configs; + gchar **configs; - struct signal_configreloaded *sig = (struct signal_configreloaded*) user_data; - g_variant_get(parameters, "(^as)", &configs); + struct signal_configreloaded *sig = + (struct signal_configreloaded *)user_data; + g_variant_get(parameters, "(^as)", &configs); - sig->configs = configs; + sig->configs = configs; } void dbus_signal_subscribe_configreloaded(struct signal_configreloaded *sig) { - assert(sig); - - sig->conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); - sig->subscription_id = - g_dbus_connection_signal_subscribe( - sig->conn, - FDN_NAME, - DUNST_IFAC, - "ConfigReloaded", - FDN_PATH, - NULL, - G_DBUS_SIGNAL_FLAGS_NONE, - dbus_signal_cb_configreloaded, - sig, - NULL); + assert(sig); + + sig->conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); + sig->subscription_id = + g_dbus_connection_signal_subscribe(sig->conn, + FDN_NAME, + DUNST_IFAC, + "ConfigReloaded", + FDN_PATH, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + dbus_signal_cb_configreloaded, + sig, + NULL); } void dbus_signal_unsubscribe_configreloaded(struct signal_configreloaded *sig) { - assert(sig); + assert(sig); - g_dbus_connection_signal_unsubscribe(sig->conn, sig->subscription_id); - g_object_unref(sig->conn); + g_dbus_connection_signal_unsubscribe(sig->conn, sig->subscription_id); + g_object_unref(sig->conn); - sig->conn = NULL; - sig->subscription_id = -1; + sig->conn = NULL; + sig->subscription_id = -1; } -static GVariant *dbus_invoke_ifac(const char *method, GVariant *params, const char *ifac) -{ - GDBusConnection *connection_client; - GVariant *retdata; - GError *error = NULL; - - connection_client = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); - retdata = g_dbus_connection_call_sync( - connection_client, - FDN_NAME, - FDN_PATH, - ifac, - method, - params, - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - &error); - if (error) { - printf("Error while calling GTestDBus instance: %s\n", error->message); - g_error_free(error); - } - - g_object_unref(connection_client); - - return retdata; +static GVariant * +dbus_invoke_ifac(const char *method, GVariant *params, const char *ifac) +{ + GDBusConnection *connection_client; + GVariant *retdata; + GError *error = NULL; + + connection_client = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); + retdata = g_dbus_connection_call_sync(connection_client, + FDN_NAME, + FDN_PATH, + ifac, + method, + params, + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (error) { + printf("Error while calling GTestDBus instance: %s\n", error->message); + g_error_free(error); + } + + g_object_unref(connection_client); + + return retdata; } GVariant *dbus_invoke(const char *method, GVariant *params) { - return dbus_invoke_ifac(method, params, FDN_IFAC); + return dbus_invoke_ifac(method, params, FDN_IFAC); } -struct dbus_notification { - const char* app_name; - guint replaces_id; - const char* app_icon; - const char* summary; - const char* body; - GHashTable *actions; - GHashTable *hints; - int expire_timeout; +struct dbus_notification +{ + const char *app_name; + guint replaces_id; + const char *app_icon; + const char *summary; + const char *body; + GHashTable *actions; + GHashTable *hints; + int expire_timeout; }; void g_free_variant_value(gpointer tofree) { - g_variant_unref((GVariant*) tofree); + g_variant_unref((GVariant *)tofree); } struct dbus_notification *dbus_notification_new(void) { - struct dbus_notification *n = g_malloc0(sizeof(struct dbus_notification)); - n->expire_timeout = -1; - n->replaces_id = 0; - n->actions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - n->hints = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free_variant_value); - return n; + struct dbus_notification *n = g_malloc0(sizeof(struct dbus_notification)); + n->expire_timeout = -1; + n->replaces_id = 0; + n->actions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + n->hints = g_hash_table_new_full( + g_str_hash, g_str_equal, g_free, g_free_variant_value); + return n; } void dbus_notification_free(struct dbus_notification *n) { - g_hash_table_unref(n->hints); - g_hash_table_unref(n->actions); - g_free(n); + g_hash_table_unref(n->hints); + g_hash_table_unref(n->actions); + g_free(n); } bool dbus_notification_fire(struct dbus_notification *n, uint *id) { - assert(n); - assert(id); - GVariantBuilder b; - GVariantType *t; - - gpointer p_key; - gpointer p_value; - GHashTableIter iter; - - t = g_variant_type_new("(susssasa{sv}i)"); - g_variant_builder_init(&b, t); - g_variant_type_free(t); - - g_variant_builder_add(&b, "s", n->app_name); - g_variant_builder_add(&b, "u", n->replaces_id); - g_variant_builder_add(&b, "s", n->app_icon); - g_variant_builder_add(&b, "s", n->summary); - g_variant_builder_add(&b, "s", n->body); - - // Add the actions - t = g_variant_type_new("as"); - g_variant_builder_open(&b, t); - g_hash_table_iter_init(&iter, n->actions); - while (g_hash_table_iter_next(&iter, &p_key, &p_value)) { - g_variant_builder_add(&b, "s", (char*)p_key); - g_variant_builder_add(&b, "s", (char*)p_value); - } - // Add an invalid appendix to cover odd numbered action arrays - // Shouldn't interfere with normal testing - g_variant_builder_add(&b, "s", "invalid appendix"); - g_variant_builder_close(&b); - g_variant_type_free(t); - - // Add the hints - t = g_variant_type_new("a{sv}"); - g_variant_builder_open(&b, t); - g_hash_table_iter_init(&iter, n->hints); - while (g_hash_table_iter_next(&iter, &p_key, &p_value)) { - g_variant_builder_add(&b, "{sv}", (char*)p_key, (GVariant*)p_value); - } - g_variant_builder_close(&b); - g_variant_type_free(t); - - g_variant_builder_add(&b, "i", n->expire_timeout); - - GVariant *reply = dbus_invoke("Notify", g_variant_builder_end(&b)); - if (reply) { - g_variant_get(reply, "(u)", id); - g_variant_unref(reply); - return true; - } else { - return false; - } + assert(n); + assert(id); + GVariantBuilder b; + GVariantType *t; + + gpointer p_key; + gpointer p_value; + GHashTableIter iter; + + t = g_variant_type_new("(susssasa{sv}i)"); + g_variant_builder_init(&b, t); + g_variant_type_free(t); + + g_variant_builder_add(&b, "s", n->app_name); + g_variant_builder_add(&b, "u", n->replaces_id); + g_variant_builder_add(&b, "s", n->app_icon); + g_variant_builder_add(&b, "s", n->summary); + g_variant_builder_add(&b, "s", n->body); + + // Add the actions + t = g_variant_type_new("as"); + g_variant_builder_open(&b, t); + g_hash_table_iter_init(&iter, n->actions); + while (g_hash_table_iter_next(&iter, &p_key, &p_value)) { + g_variant_builder_add(&b, "s", (char *)p_key); + g_variant_builder_add(&b, "s", (char *)p_value); + } + // Add an invalid appendix to cover odd numbered action arrays + // Shouldn't interfere with normal testing + g_variant_builder_add(&b, "s", "invalid appendix"); + g_variant_builder_close(&b); + g_variant_type_free(t); + + // Add the hints + t = g_variant_type_new("a{sv}"); + g_variant_builder_open(&b, t); + g_hash_table_iter_init(&iter, n->hints); + while (g_hash_table_iter_next(&iter, &p_key, &p_value)) { + g_variant_builder_add(&b, "{sv}", (char *)p_key, (GVariant *)p_value); + } + g_variant_builder_close(&b); + g_variant_type_free(t); + + g_variant_builder_add(&b, "i", n->expire_timeout); + + GVariant *reply = dbus_invoke("Notify", g_variant_builder_end(&b)); + if (reply) { + g_variant_get(reply, "(u)", id); + g_variant_unref(reply); + return true; + } else { + return false; + } } -void dbus_notification_set_raw_image(struct dbus_notification *n_dbus, const char *path) +void dbus_notification_set_raw_image(struct dbus_notification *n_dbus, + const char *path) { - GVariant *hint = notification_setup_raw_image(path); - if (!hint) - return; + GVariant *hint = notification_setup_raw_image(path); + if (!hint) + return; - g_hash_table_insert(n_dbus->hints, - g_strdup("image-data"), - g_variant_ref_sink(hint)); + g_hash_table_insert( + n_dbus->hints, g_strdup("image-data"), g_variant_ref_sink(hint)); } /////// TESTS @@ -514,734 +527,754 @@ gint owner_id; TEST test_dbus_init(void) { - owner_id = dbus_init(); - uint waiting = 0; - while (!dbus_conn && waiting < 2000) { - usleep(500); - waiting++; - } - ASSERTm("After 1s, there is still no dbus connection available.", - dbus_conn); - PASS(); + owner_id = dbus_init(); + uint waiting = 0; + while (!dbus_conn && waiting < 2000) { + usleep(500); + waiting++; + } + ASSERTm("After 1s, there is still no dbus connection available.", + dbus_conn); + PASS(); } TEST test_dbus_teardown(void) { - dbus_teardown(owner_id); - PASS(); + dbus_teardown(owner_id); + PASS(); } TEST test_invalid_notification(void) { - GVariant *faulty = g_variant_new_boolean(true); + GVariant *faulty = g_variant_new_boolean(true); - ASSERT(NULL == dbus_message_to_notification(":123", faulty)); - ASSERT(NULL == dbus_invoke("Notify", faulty)); + ASSERT(NULL == dbus_message_to_notification(":123", faulty)); + ASSERT(NULL == dbus_invoke("Notify", faulty)); - g_variant_unref(faulty); - PASS(); + g_variant_unref(faulty); + PASS(); } TEST test_dbus_cb_dunst_Properties_Get(void) { - GDBusConnection *connection_client; - GError *error = NULL; - - connection_client = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); - - GVariant *pause_variant = dbus_cb_dunst_Properties_Get(connection_client, - FDN_NAME, - FDN_PATH, - DUNST_IFAC, - "paused", - &error, - NULL); - - if (error) { - printf("Error while calling dbus_cb_dunst_Properties_Get: %s\n", error->message); - g_error_free(error); - } - - ASSERT_FALSE(g_variant_get_boolean(pause_variant)); - g_variant_unref(pause_variant); - - dunst_status_int(S_PAUSE_LEVEL, 100); - - pause_variant = dbus_cb_dunst_Properties_Get(connection_client, - FDN_NAME, - FDN_PATH, - DUNST_IFAC, - "paused", - &error, - NULL); - - if (error) { - printf("Error while calling dbus_cb_dunst_Properties_Get: %s\n", error->message); - g_error_free(error); - } - - ASSERT(g_variant_get_boolean(pause_variant)); - g_variant_unref(pause_variant); - - g_object_unref(connection_client); - PASS(); + GDBusConnection *connection_client; + GError *error = NULL; + + connection_client = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); + + GVariant *pause_variant = dbus_cb_dunst_Properties_Get(connection_client, + FDN_NAME, + FDN_PATH, + DUNST_IFAC, + "paused", + &error, + NULL); + + if (error) { + printf("Error while calling dbus_cb_dunst_Properties_Get: %s\n", + error->message); + g_error_free(error); + } + + ASSERT_FALSE(g_variant_get_boolean(pause_variant)); + g_variant_unref(pause_variant); + + dunst_status_int(S_PAUSE_LEVEL, 100); + + pause_variant = dbus_cb_dunst_Properties_Get(connection_client, + FDN_NAME, + FDN_PATH, + DUNST_IFAC, + "paused", + &error, + NULL); + + if (error) { + printf("Error while calling dbus_cb_dunst_Properties_Get: %s\n", + error->message); + g_error_free(error); + } + + ASSERT(g_variant_get_boolean(pause_variant)); + g_variant_unref(pause_variant); + + g_object_unref(connection_client); + PASS(); } TEST test_dbus_cb_dunst_Properties_Set(void) { - GDBusConnection *connection_client; - GError *error = NULL; - struct signal_propertieschanged sig = {NULL, NULL, NULL, -1}; - - dbus_signal_subscribe_propertieschanged(&sig); + GDBusConnection *connection_client; + GError *error = NULL; + struct signal_propertieschanged sig = {NULL, NULL, NULL, -1}; - connection_client = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); + dbus_signal_subscribe_propertieschanged(&sig); - GVariant *pause_variant = g_variant_new_boolean(TRUE); + connection_client = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); + GVariant *pause_variant = g_variant_new_boolean(TRUE); - ASSERT(dbus_cb_dunst_Properties_Set(connection_client, - FDN_NAME, - FDN_PATH, - DUNST_IFAC, - "paused", - pause_variant, - &error, - NULL)); + ASSERT(dbus_cb_dunst_Properties_Set(connection_client, + FDN_NAME, + FDN_PATH, + DUNST_IFAC, + "paused", + pause_variant, + &error, + NULL)); - if (error) { - printf("Error while calling dbus_cb_dunst_Properties_Set: %s\n", error->message); - g_error_free(error); - } + if (error) { + printf("Error while calling dbus_cb_dunst_Properties_Set: %s\n", + error->message); + g_error_free(error); + } - uint waiting = 0; - while (!sig.interface && waiting < 2000) { - usleep(500); - waiting++; - } + uint waiting = 0; + while (!sig.interface && waiting < 2000) { + usleep(500); + waiting++; + } - ASSERT_STR_EQ(sig.interface, DUNST_IFAC); + ASSERT_STR_EQ(sig.interface, DUNST_IFAC); - gboolean paused; - g_variant_lookup(sig.array_dict_sv_data, "paused", "b", &paused); + gboolean paused; + g_variant_lookup(sig.array_dict_sv_data, "paused", "b", &paused); - ASSERT(paused); + ASSERT(paused); - g_variant_unref(pause_variant); - g_free(sig.interface); - g_variant_unref(sig.array_dict_sv_data); - g_variant_unref(sig.array_s_data); - dbus_signal_unsubscribe_propertieschanged(&sig); - g_object_unref(connection_client); - PASS(); + g_variant_unref(pause_variant); + g_free(sig.interface); + g_variant_unref(sig.array_dict_sv_data); + g_variant_unref(sig.array_s_data); + dbus_signal_unsubscribe_propertieschanged(&sig); + g_object_unref(connection_client); + PASS(); } TEST test_dbus_cb_dunst_Properties_Set_pause_level(void) { - GDBusConnection *connection_client; - GError *error = NULL; - struct signal_propertieschanged sig = {NULL, NULL, NULL, -1}; - - dbus_signal_subscribe_propertieschanged(&sig); + GDBusConnection *connection_client; + GError *error = NULL; + struct signal_propertieschanged sig = {NULL, NULL, NULL, -1}; - connection_client = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); + dbus_signal_subscribe_propertieschanged(&sig); - GVariant *pause_variant = g_variant_new_uint32(33); + connection_client = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); + GVariant *pause_variant = g_variant_new_uint32(33); - ASSERT(dbus_cb_dunst_Properties_Set(connection_client, - FDN_NAME, - FDN_PATH, - DUNST_IFAC, - "pauseLevel", - pause_variant, - &error, - NULL)); + ASSERT(dbus_cb_dunst_Properties_Set(connection_client, + FDN_NAME, + FDN_PATH, + DUNST_IFAC, + "pauseLevel", + pause_variant, + &error, + NULL)); - if (error) { - printf("Error while calling dbus_cb_dunst_Properties_Set: %s\n", error->message); - g_error_free(error); - } + if (error) { + printf("Error while calling dbus_cb_dunst_Properties_Set: %s\n", + error->message); + g_error_free(error); + } - uint waiting = 0; - while (!sig.interface && waiting < 2000) { - usleep(500); - waiting++; - } + uint waiting = 0; + while (!sig.interface && waiting < 2000) { + usleep(500); + waiting++; + } - ASSERT_STR_EQ(sig.interface, DUNST_IFAC); + ASSERT_STR_EQ(sig.interface, DUNST_IFAC); - guint pauseLevel; - g_variant_lookup(sig.array_dict_sv_data, "pauseLevel", "u", &pauseLevel); + guint pauseLevel; + g_variant_lookup(sig.array_dict_sv_data, "pauseLevel", "u", &pauseLevel); - ASSERT(pauseLevel == 33); + ASSERT(pauseLevel == 33); - g_variant_unref(pause_variant); - g_free(sig.interface); - g_variant_unref(sig.array_dict_sv_data); - g_variant_unref(sig.array_s_data); - dbus_signal_unsubscribe_propertieschanged(&sig); - g_object_unref(connection_client); - PASS(); + g_variant_unref(pause_variant); + g_free(sig.interface); + g_variant_unref(sig.array_dict_sv_data); + g_variant_unref(sig.array_s_data); + dbus_signal_unsubscribe_propertieschanged(&sig); + g_object_unref(connection_client); + PASS(); } TEST test_dbus_cb_dunst_NotificationListHistory(void) { - struct notification *n = notification_create(); - gint64 timestamp1 = n->timestamp; - n->appname = g_strdup("dunstify"); - n->summary = g_strdup("Testing"); - n->urgency = 2; - n->stack_tag = g_strdup("test-stack-tag"); - n->urls = g_strdup("https://dunst-project.org/"); - const char *urgency1 = notification_urgency_to_string(n->urgency); - queues_history_push(n); - - n = notification_create(); - gint64 timestamp2 = n->timestamp; - n->appname = g_strdup("notify-send"); - n->summary = g_strdup("More testing"); - n->urgency = 0; - n->stack_tag = g_strdup("test-stack-tag"); - n->urls = g_strdup("https://dunst-project.org/"); - const char *urgency2 = notification_urgency_to_string(n->urgency); - queues_history_push(n); - - GVariant *result = dbus_invoke_ifac("NotificationListHistory", NULL, DUNST_IFAC); - ASSERT(result != NULL); - ASSERT_STR_EQ("(aa{sv})", g_variant_get_type_string(result)); - - GVariantIter tuple_iter; - g_variant_iter_init(&tuple_iter, result); - GVariant *array = g_variant_iter_next_value(&tuple_iter); - - GVariantIter array_iter; - g_variant_iter_init(&array_iter, array); - GVariant *dict = g_variant_iter_next_value(&array_iter); - - GVariantDict d; - g_variant_dict_init(&d, dict); - - char *str; - gint64 int64; - - ASSERT(g_variant_dict_lookup(&d, "appname", "s", &str)); - ASSERT_STR_EQ("notify-send", str); - g_free(str); - - ASSERT(g_variant_dict_lookup(&d, "summary", "s", &str)); - ASSERT_STR_EQ("More testing", str); - g_free(str); - - ASSERT(g_variant_dict_lookup(&d, "timestamp", "x", &int64)); - ASSERT_EQ(timestamp2, int64); - - ASSERT(g_variant_dict_lookup(&d, "urgency", "s", &str)); - ASSERT_STR_EQ(urgency2, str); - g_free(str); - - ASSERT(g_variant_dict_lookup(&d, "stack_tag", "s", &str)); - ASSERT_STR_EQ("test-stack-tag", str); - g_free(str); - - ASSERT(g_variant_dict_lookup(&d, "urls", "s", &str)); - ASSERT_STR_EQ("https://dunst-project.org/", str); - g_free(str); - - g_variant_unref(dict); - dict = g_variant_iter_next_value(&array_iter); - g_variant_dict_clear(&d); - g_variant_dict_init(&d, dict); - - ASSERT(g_variant_dict_lookup(&d, "appname", "s", &str)); - ASSERT_STR_EQ("dunstify", str); - g_free(str); - - ASSERT(g_variant_dict_lookup(&d, "summary", "s", &str)); - ASSERT_STR_EQ("Testing", str); - g_free(str); - - ASSERT(g_variant_dict_lookup(&d, "timestamp", "x", &int64)); - ASSERT_EQ(timestamp1, int64); - - ASSERT(g_variant_dict_lookup(&d, "urgency", "s", &str)); - ASSERT_STR_EQ(urgency1, str); - g_free(str); - - ASSERT(g_variant_dict_lookup(&d, "stack_tag", "s", &str)); - ASSERT_STR_EQ("test-stack-tag", str); - g_free(str); - - ASSERT(g_variant_dict_lookup(&d, "urls", "s", &str)); - ASSERT_STR_EQ("https://dunst-project.org/", str); - g_free(str); - - g_variant_dict_clear(&d); - g_variant_unref(dict); - g_variant_unref(array); - g_variant_unref(result); - queues_history_clear(); - PASS(); + struct notification *n = notification_create(); + gint64 timestamp1 = n->timestamp; + n->appname = g_strdup("dunstify"); + n->summary = g_strdup("Testing"); + n->urgency = 2; + n->stack_tag = g_strdup("test-stack-tag"); + n->urls = g_strdup("https://dunst-project.org/"); + const char *urgency1 = notification_urgency_to_string(n->urgency); + queues_history_push(n); + + n = notification_create(); + gint64 timestamp2 = n->timestamp; + n->appname = g_strdup("notify-send"); + n->summary = g_strdup("More testing"); + n->urgency = 0; + n->stack_tag = g_strdup("test-stack-tag"); + n->urls = g_strdup("https://dunst-project.org/"); + const char *urgency2 = notification_urgency_to_string(n->urgency); + queues_history_push(n); + + GVariant *result = + dbus_invoke_ifac("NotificationListHistory", NULL, DUNST_IFAC); + ASSERT(result != NULL); + ASSERT_STR_EQ("(aa{sv})", g_variant_get_type_string(result)); + + GVariantIter tuple_iter; + g_variant_iter_init(&tuple_iter, result); + GVariant *array = g_variant_iter_next_value(&tuple_iter); + + GVariantIter array_iter; + g_variant_iter_init(&array_iter, array); + GVariant *dict = g_variant_iter_next_value(&array_iter); + + GVariantDict d; + g_variant_dict_init(&d, dict); + + char *str; + gint64 int64; + + ASSERT(g_variant_dict_lookup(&d, "appname", "s", &str)); + ASSERT_STR_EQ("notify-send", str); + g_free(str); + + ASSERT(g_variant_dict_lookup(&d, "summary", "s", &str)); + ASSERT_STR_EQ("More testing", str); + g_free(str); + + ASSERT(g_variant_dict_lookup(&d, "timestamp", "x", &int64)); + ASSERT_EQ(timestamp2, int64); + + ASSERT(g_variant_dict_lookup(&d, "urgency", "s", &str)); + ASSERT_STR_EQ(urgency2, str); + g_free(str); + + ASSERT(g_variant_dict_lookup(&d, "stack_tag", "s", &str)); + ASSERT_STR_EQ("test-stack-tag", str); + g_free(str); + + ASSERT(g_variant_dict_lookup(&d, "urls", "s", &str)); + ASSERT_STR_EQ("https://dunst-project.org/", str); + g_free(str); + + g_variant_unref(dict); + dict = g_variant_iter_next_value(&array_iter); + g_variant_dict_clear(&d); + g_variant_dict_init(&d, dict); + + ASSERT(g_variant_dict_lookup(&d, "appname", "s", &str)); + ASSERT_STR_EQ("dunstify", str); + g_free(str); + + ASSERT(g_variant_dict_lookup(&d, "summary", "s", &str)); + ASSERT_STR_EQ("Testing", str); + g_free(str); + + ASSERT(g_variant_dict_lookup(&d, "timestamp", "x", &int64)); + ASSERT_EQ(timestamp1, int64); + + ASSERT(g_variant_dict_lookup(&d, "urgency", "s", &str)); + ASSERT_STR_EQ(urgency1, str); + g_free(str); + + ASSERT(g_variant_dict_lookup(&d, "stack_tag", "s", &str)); + ASSERT_STR_EQ("test-stack-tag", str); + g_free(str); + + ASSERT(g_variant_dict_lookup(&d, "urls", "s", &str)); + ASSERT_STR_EQ("https://dunst-project.org/", str); + g_free(str); + + g_variant_dict_clear(&d); + g_variant_unref(dict); + g_variant_unref(array); + g_variant_unref(result); + queues_history_clear(); + PASS(); } TEST test_dbus_cb_dunst_RuleEnable(void) { - struct rule *rule = rule_new("test_rule_enable"); - ASSERT(rule->enabled); - - GVariant *result = dbus_invoke_ifac("RuleEnable", g_variant_new("(si)", "test_rule_enable", 0), DUNST_IFAC); - ASSERT(result != NULL); - ASSERT(!rule->enabled); - g_variant_unref(result); - - result = dbus_invoke_ifac("RuleEnable", g_variant_new("(si)", "test_rule_enable", 1), DUNST_IFAC); - ASSERT(result != NULL); - ASSERT(rule->enabled); - g_variant_unref(result); - - result = dbus_invoke_ifac("RuleEnable", g_variant_new("(si)", "test_rule_enable", 2), DUNST_IFAC); - ASSERT(result != NULL); - ASSERT(!rule->enabled); - g_variant_unref(result); - - rules = g_slist_remove(rules, rule); - g_free(rule->name); - g_free(rule); - - PASS(); + struct rule *rule = rule_new("test_rule_enable"); + ASSERT(rule->enabled); + + GVariant *result = dbus_invoke_ifac( + "RuleEnable", g_variant_new("(si)", "test_rule_enable", 0), DUNST_IFAC); + ASSERT(result != NULL); + ASSERT(!rule->enabled); + g_variant_unref(result); + + result = dbus_invoke_ifac( + "RuleEnable", g_variant_new("(si)", "test_rule_enable", 1), DUNST_IFAC); + ASSERT(result != NULL); + ASSERT(rule->enabled); + g_variant_unref(result); + + result = dbus_invoke_ifac( + "RuleEnable", g_variant_new("(si)", "test_rule_enable", 2), DUNST_IFAC); + ASSERT(result != NULL); + ASSERT(!rule->enabled); + g_variant_unref(result); + + rules = g_slist_remove(rules, rule); + g_free(rule->name); + g_free(rule); + + PASS(); } TEST test_dbus_cb_dunst_RuleList(void) { - struct rule *rule = rule_new("testing RuleList"); - rule->appname = "dunstify"; - rule->urgency = URG_CRIT; - rule->match_transient = true; - rule->fg = (struct color){.r = 0.1, .g = 0.1, .b = 0.1, .a = 1.0}; + struct rule *rule = rule_new("testing RuleList"); + rule->appname = "dunstify"; + rule->urgency = URG_CRIT; + rule->match_transient = true; + rule->fg = (struct color){.r = 0.1, .g = 0.1, .b = 0.1, .a = 1.0}; - GVariant *result = dbus_invoke_ifac("RuleList", NULL, DUNST_IFAC); - ASSERT(result != NULL); - ASSERT_STR_EQ("(aa{sv})", g_variant_get_type_string(result)); + GVariant *result = dbus_invoke_ifac("RuleList", NULL, DUNST_IFAC); + ASSERT(result != NULL); + ASSERT_STR_EQ("(aa{sv})", g_variant_get_type_string(result)); - GVariantIter tuple_iter; - g_variant_iter_init(&tuple_iter, result); - GVariant *array = g_variant_iter_next_value(&tuple_iter); + GVariantIter tuple_iter; + g_variant_iter_init(&tuple_iter, result); + GVariant *array = g_variant_iter_next_value(&tuple_iter); - GVariantIter array_iter; - g_variant_iter_init(&array_iter, array); - GVariant *dict = g_variant_iter_next_value(&array_iter); + GVariantIter array_iter; + g_variant_iter_init(&array_iter, array); + GVariant *dict = g_variant_iter_next_value(&array_iter); - GVariantDict d; - g_variant_dict_init(&d, dict); + GVariantDict d; + g_variant_dict_init(&d, dict); - char *str; - gboolean boolean; + char *str; + gboolean boolean; - ASSERT(g_variant_dict_lookup(&d, "name", "s", &str)); - ASSERT_STR_EQ("testing RuleList", str); - g_free(str); + ASSERT(g_variant_dict_lookup(&d, "name", "s", &str)); + ASSERT_STR_EQ("testing RuleList", str); + g_free(str); - ASSERT(g_variant_dict_lookup(&d, "enabled", "b", &boolean)); - ASSERT(boolean); + ASSERT(g_variant_dict_lookup(&d, "enabled", "b", &boolean)); + ASSERT(boolean); - ASSERT(!g_variant_dict_lookup(&d, "hide_text", "b", &boolean)); - ASSERT(!g_variant_dict_lookup(&d, "history_ignore", "b", &boolean)); + ASSERT(!g_variant_dict_lookup(&d, "hide_text", "b", &boolean)); + ASSERT(!g_variant_dict_lookup(&d, "history_ignore", "b", &boolean)); - ASSERT(g_variant_dict_lookup(&d, "match_transient", "b", &boolean)); - ASSERT(boolean); + ASSERT(g_variant_dict_lookup(&d, "match_transient", "b", &boolean)); + ASSERT(boolean); - ASSERT(g_variant_dict_lookup(&d, "appname", "s", &str)); - ASSERT_STR_EQ("dunstify", str); - g_free(str); + ASSERT(g_variant_dict_lookup(&d, "appname", "s", &str)); + ASSERT_STR_EQ("dunstify", str); + g_free(str); - ASSERT(g_variant_dict_lookup(&d, "urgency", "s", &str)); - ASSERT_STR_EQ("critical", str); - g_free(str); + ASSERT(g_variant_dict_lookup(&d, "urgency", "s", &str)); + ASSERT_STR_EQ("critical", str); + g_free(str); - ASSERT(g_variant_dict_lookup(&d, "fg", "s", &str)); - ASSERT_STR_EQ("#191919ff", str); - g_free(str); + ASSERT(g_variant_dict_lookup(&d, "fg", "s", &str)); + ASSERT_STR_EQ("#191919ff", str); + g_free(str); - ASSERT_FALSE(g_variant_dict_lookup(&d, "bg", "s", &str)); + ASSERT_FALSE(g_variant_dict_lookup(&d, "bg", "s", &str)); - g_variant_dict_clear(&d); - g_variant_unref(dict); - g_variant_unref(array); - g_variant_unref(result); - rules = g_slist_remove(rules, rule); - g_free(rule->name); - g_free(rule); + g_variant_dict_clear(&d); + g_variant_unref(dict); + g_variant_unref(array); + g_variant_unref(result); + rules = g_slist_remove(rules, rule); + g_free(rule->name); + g_free(rule); - PASS(); + PASS(); } TEST test_empty_notification(void) { - struct dbus_notification *n = dbus_notification_new(); - gsize len = queues_length_waiting(); + struct dbus_notification *n = dbus_notification_new(); + gsize len = queues_length_waiting(); - guint id; - ASSERT(dbus_notification_fire(n, &id)); - ASSERT(id != 0); + guint id; + ASSERT(dbus_notification_fire(n, &id)); + ASSERT(id != 0); - ASSERT_EQ(queues_length_waiting(), len+1); - dbus_notification_free(n); - PASS(); + ASSERT_EQ(queues_length_waiting(), len + 1); + dbus_notification_free(n); + PASS(); } TEST test_basic_notification(void) { - struct dbus_notification *n = dbus_notification_new(); - gsize len = queues_length_waiting(); - n->app_name = "dunstteststack"; - n->app_icon = "NONE"; - n->summary = "Headline"; - n->body = "Text"; - g_hash_table_insert(n->actions, g_strdup("actionid"), g_strdup("Print this text")); - g_hash_table_insert(n->hints, - g_strdup("x-dunst-stack-tag"), - g_variant_ref_sink(g_variant_new_string("volume"))); - - n->replaces_id = 10; - - guint id; - ASSERT(dbus_notification_fire(n, &id)); - ASSERT(id != 0); - - ASSERT_EQ(queues_length_waiting(), len+1); - dbus_notification_free(n); - PASS(); + struct dbus_notification *n = dbus_notification_new(); + gsize len = queues_length_waiting(); + n->app_name = "dunstteststack"; + n->app_icon = "NONE"; + n->summary = "Headline"; + n->body = "Text"; + g_hash_table_insert( + n->actions, g_strdup("actionid"), g_strdup("Print this text")); + g_hash_table_insert(n->hints, + g_strdup("x-dunst-stack-tag"), + g_variant_ref_sink(g_variant_new_string("volume"))); + + n->replaces_id = 10; + + guint id; + ASSERT(dbus_notification_fire(n, &id)); + ASSERT(id != 0); + + ASSERT_EQ(queues_length_waiting(), len + 1); + dbus_notification_free(n); + PASS(); } TEST test_dbus_notify_colors(void) { - // Valid - const char *color_frame = "#ffaaccbb"; - const char *color_fg = "#fab"; - // Junk - const char *color_bg = "#ff00axaldjnkfs"; - const char *color_highlight = "Whatever this is "; - - struct notification *n; - struct dbus_notification *n_dbus; - - gsize len = queues_length_waiting(); + // Valid + const char *color_frame = "#ffaaccbb"; + const char *color_fg = "#fab"; + // Junk + const char *color_bg = "#ff00axaldjnkfs"; + const char *color_highlight = "Whatever this is "; + + struct notification *n; + struct dbus_notification *n_dbus; + + gsize len = queues_length_waiting(); + + n_dbus = dbus_notification_new(); + n_dbus->app_name = "dunstteststack"; + n_dbus->app_icon = "NONE"; + n_dbus->summary = "test_dbus_notify_colors"; + n_dbus->body = "Summary of it"; + g_hash_table_insert(n_dbus->hints, + g_strdup("frcolor"), + g_variant_ref_sink(g_variant_new_string(color_frame))); + g_hash_table_insert(n_dbus->hints, + g_strdup("bgcolor"), + g_variant_ref_sink(g_variant_new_string(color_bg))); + g_hash_table_insert(n_dbus->hints, + g_strdup("fgcolor"), + g_variant_ref_sink(g_variant_new_string(color_fg))); + g_hash_table_insert( + n_dbus->hints, + g_strdup("hlcolor"), + g_variant_ref_sink(g_variant_new_string(color_highlight))); + + guint id; + ASSERT(dbus_notification_fire(n_dbus, &id)); + ASSERT(id != 0); + + ASSERT_EQ(queues_length_waiting(), len + 1); + + n = queues_debug_find_notification_by_id(id); + + // Valid color strings get converted + struct color frame = { + 1.0, (double)0xaa / 0xff, (double)0xcc / 0xff, (double)0xbb / 0xff}; + struct color fg = {1.0, (double)0xaa / 0xff, (double)0xbb / 0xff, 1.0}; + + ASSERTm("Valid color strings should change the notification color", + COLOR_SAME(n->colors.frame, frame)); + ASSERTm("Valid color strings should change the notification color", + COLOR_SAME(n->colors.fg, fg)); + + // Invalid color strings are ignored + ASSERTm("Invalid color strings should not change the color struct", + COLOR_SAME(n->colors.bg, settings.colors_norm.bg)); + + ASSERTm("Invalid color strings should not change the gradient struct", + n->colors.highlight->length + == settings.colors_norm.highlight->length); + + for (size_t i = 0; i < settings.colors_norm.highlight->length; i++) + ASSERTm("Invalid color strings should not change the gradient struct", + COLOR_SAME(n->colors.highlight->colors[i], + settings.colors_norm.highlight->colors[i])); + + dbus_notification_free(n_dbus); + + PASS(); +} - n_dbus = dbus_notification_new(); - n_dbus->app_name = "dunstteststack"; - n_dbus->app_icon = "NONE"; - n_dbus->summary = "test_dbus_notify_colors"; - n_dbus->body = "Summary of it"; - g_hash_table_insert(n_dbus->hints, - g_strdup("frcolor"), - g_variant_ref_sink(g_variant_new_string(color_frame))); - g_hash_table_insert(n_dbus->hints, - g_strdup("bgcolor"), - g_variant_ref_sink(g_variant_new_string(color_bg))); - g_hash_table_insert(n_dbus->hints, - g_strdup("fgcolor"), - g_variant_ref_sink(g_variant_new_string(color_fg))); +TEST test_hint_transient(void) +{ + static char msg[50]; + struct notification *n; + struct dbus_notification *n_dbus; + + gsize len = queues_length_waiting(); + + n_dbus = dbus_notification_new(); + n_dbus->app_name = "dunstteststack"; + n_dbus->app_icon = "NONE"; + n_dbus->summary = "test_hint_transient"; + n_dbus->body = "Summary of it"; + + bool values[] = {true, true, true, false, false, false, false}; + GVariant *variants[] = { + g_variant_new_boolean(true), + g_variant_new_int32(1), + g_variant_new_uint32(1), + g_variant_new_boolean(false), + g_variant_new_int32(0), + g_variant_new_uint32(0), + g_variant_new_int32(-1), + }; + for (size_t i = 0; i < G_N_ELEMENTS(variants); i++) { g_hash_table_insert(n_dbus->hints, - g_strdup("hlcolor"), - g_variant_ref_sink(g_variant_new_string(color_highlight))); + g_strdup("transient"), + g_variant_ref_sink(variants[i])); guint id; ASSERT(dbus_notification_fire(n_dbus, &id)); ASSERT(id != 0); - ASSERT_EQ(queues_length_waiting(), len+1); + snprintf(msg, sizeof(msg), "In round %zu", i); + ASSERT_EQm(msg, queues_length_waiting(), len + 1); n = queues_debug_find_notification_by_id(id); - // Valid color strings get converted - struct color frame = { 1.0, (double)0xaa/0xff, (double)0xcc/0xff, (double)0xbb/0xff }; - struct color fg = { 1.0, (double)0xaa/0xff, (double)0xbb/0xff, 1.0 }; - - ASSERTm("Valid color strings should change the notification color", COLOR_SAME(n->colors.frame, frame)); - ASSERTm("Valid color strings should change the notification color", COLOR_SAME(n->colors.fg, fg)); - - // Invalid color strings are ignored - ASSERTm("Invalid color strings should not change the color struct", COLOR_SAME(n->colors.bg, settings.colors_norm.bg)); - - ASSERTm("Invalid color strings should not change the gradient struct", n->colors.highlight->length == settings.colors_norm.highlight->length); - - for (size_t i = 0; i < settings.colors_norm.highlight->length; i++) - ASSERTm("Invalid color strings should not change the gradient struct", - COLOR_SAME(n->colors.highlight->colors[i], settings.colors_norm.highlight->colors[i])); - - dbus_notification_free(n_dbus); - - PASS(); -} - -TEST test_hint_transient(void) -{ - static char msg[50]; - struct notification *n; - struct dbus_notification *n_dbus; - - gsize len = queues_length_waiting(); - - n_dbus = dbus_notification_new(); - n_dbus->app_name = "dunstteststack"; - n_dbus->app_icon = "NONE"; - n_dbus->summary = "test_hint_transient"; - n_dbus->body = "Summary of it"; - - bool values[] = { true, true, true, false, false, false, false }; - GVariant *variants[] = { - g_variant_new_boolean(true), - g_variant_new_int32(1), - g_variant_new_uint32(1), - g_variant_new_boolean(false), - g_variant_new_int32(0), - g_variant_new_uint32(0), - g_variant_new_int32(-1), - }; - for (size_t i = 0; i < G_N_ELEMENTS(variants); i++) { - g_hash_table_insert(n_dbus->hints, - g_strdup("transient"), - g_variant_ref_sink(variants[i])); - - guint id; - ASSERT(dbus_notification_fire(n_dbus, &id)); - ASSERT(id != 0); - - snprintf(msg, sizeof(msg), "In round %zu", i); - ASSERT_EQm(msg, queues_length_waiting(), len+1); + ASSERT_EQm(msg, values[i], n->transient); + } - n = queues_debug_find_notification_by_id(id); + dbus_notification_free(n_dbus); - ASSERT_EQm(msg, values[i], n->transient); - } - - dbus_notification_free(n_dbus); - - PASS(); + PASS(); } TEST test_hint_progress(void) { - static char msg[50]; - struct notification *n; - struct dbus_notification *n_dbus; - - gsize len = queues_length_waiting(); - - n_dbus = dbus_notification_new(); - n_dbus->app_name = "dunstteststack"; - n_dbus->app_icon = "NONE"; - n_dbus->summary = "test_hint_progress"; - n_dbus->body = "Summary of it"; + static char msg[50]; + struct notification *n; + struct dbus_notification *n_dbus; + + gsize len = queues_length_waiting(); + + n_dbus = dbus_notification_new(); + n_dbus->app_name = "dunstteststack"; + n_dbus->app_icon = "NONE"; + n_dbus->summary = "test_hint_progress"; + n_dbus->body = "Summary of it"; + + int values[] = {99, 12, 123, 123, -1, -1}; + GVariant *variants[] = { + g_variant_new_int32(99), + g_variant_new_uint32(12), + g_variant_new_int32(123), // allow higher than 100 + g_variant_new_uint32(123), + g_variant_new_int32(-192), + g_variant_new_uint32(-192), + }; + for (size_t i = 0; i < G_N_ELEMENTS(variants); i++) { + g_hash_table_insert( + n_dbus->hints, g_strdup("value"), g_variant_ref_sink(variants[i])); - int values[] = { 99, 12, 123, 123, -1, -1 }; - GVariant *variants[] = { - g_variant_new_int32(99), - g_variant_new_uint32(12), - g_variant_new_int32(123), // allow higher than 100 - g_variant_new_uint32(123), - g_variant_new_int32(-192), - g_variant_new_uint32(-192), - }; - for (size_t i = 0; i < G_N_ELEMENTS(variants); i++) { - g_hash_table_insert(n_dbus->hints, - g_strdup("value"), - g_variant_ref_sink(variants[i])); - - guint id; - ASSERT(dbus_notification_fire(n_dbus, &id)); - ASSERT(id != 0); + guint id; + ASSERT(dbus_notification_fire(n_dbus, &id)); + ASSERT(id != 0); - snprintf(msg, sizeof(msg), "In round %zu", i); - ASSERT_EQm(msg, queues_length_waiting(), len+1); + snprintf(msg, sizeof(msg), "In round %zu", i); + ASSERT_EQm(msg, queues_length_waiting(), len + 1); - n = queues_debug_find_notification_by_id(id); + n = queues_debug_find_notification_by_id(id); - snprintf(msg, sizeof(msg), "In round %zu progress should be %i, but is %i", i, n->progress, values[i]); - ASSERT_EQm(msg, values[i], n->progress); - } + snprintf(msg, + sizeof(msg), + "In round %zu progress should be %i, but is %i", + i, + n->progress, + values[i]); + ASSERT_EQm(msg, values[i], n->progress); + } - dbus_notification_free(n_dbus); + dbus_notification_free(n_dbus); - PASS(); + PASS(); } TEST test_hint_icons(void) { - struct notification *n; - struct dbus_notification *n_dbus; - const char *iconname = "NEWICON"; + struct notification *n; + struct dbus_notification *n_dbus; + const char *iconname = "NEWICON"; - gsize len = queues_length_waiting(); + gsize len = queues_length_waiting(); - n_dbus = dbus_notification_new(); - n_dbus->app_name = "dunstteststack"; - n_dbus->app_icon = "NONE"; - n_dbus->summary = "test_hint_icons"; - n_dbus->body = "Summary of it"; + n_dbus = dbus_notification_new(); + n_dbus->app_name = "dunstteststack"; + n_dbus->app_icon = "NONE"; + n_dbus->summary = "test_hint_icons"; + n_dbus->body = "Summary of it"; - g_hash_table_insert(n_dbus->hints, - g_strdup("image-path"), - g_variant_ref_sink(g_variant_new_string(iconname))); + g_hash_table_insert(n_dbus->hints, + g_strdup("image-path"), + g_variant_ref_sink(g_variant_new_string(iconname))); - guint id; - ASSERT(dbus_notification_fire(n_dbus, &id)); - ASSERT(id != 0); + guint id; + ASSERT(dbus_notification_fire(n_dbus, &id)); + ASSERT(id != 0); - ASSERT_EQ(queues_length_waiting(), len+1); + ASSERT_EQ(queues_length_waiting(), len + 1); - n = queues_debug_find_notification_by_id(id); + n = queues_debug_find_notification_by_id(id); - ASSERT_STR_EQ(iconname, n->iconname); + ASSERT_STR_EQ(iconname, n->iconname); - dbus_notification_free(n_dbus); + dbus_notification_free(n_dbus); - PASS(); + PASS(); } TEST test_hint_category(void) { - struct notification *n; - struct dbus_notification *n_dbus; - const char *category = "VOLUME"; + struct notification *n; + struct dbus_notification *n_dbus; + const char *category = "VOLUME"; - gsize len = queues_length_waiting(); + gsize len = queues_length_waiting(); - n_dbus = dbus_notification_new(); - n_dbus->app_name = "dunstteststack"; - n_dbus->app_icon = "NONE"; - n_dbus->summary = "test_hint_category"; - n_dbus->body = "Summary of it"; + n_dbus = dbus_notification_new(); + n_dbus->app_name = "dunstteststack"; + n_dbus->app_icon = "NONE"; + n_dbus->summary = "test_hint_category"; + n_dbus->body = "Summary of it"; - g_hash_table_insert(n_dbus->hints, - g_strdup("category"), - g_variant_ref_sink(g_variant_new_string(category))); + g_hash_table_insert(n_dbus->hints, + g_strdup("category"), + g_variant_ref_sink(g_variant_new_string(category))); - guint id; - ASSERT(dbus_notification_fire(n_dbus, &id)); - ASSERT(id != 0); + guint id; + ASSERT(dbus_notification_fire(n_dbus, &id)); + ASSERT(id != 0); - ASSERT_EQ(queues_length_waiting(), len+1); + ASSERT_EQ(queues_length_waiting(), len + 1); - n = queues_debug_find_notification_by_id(id); + n = queues_debug_find_notification_by_id(id); - ASSERT_STR_EQ(category, n->category); + ASSERT_STR_EQ(category, n->category); - dbus_notification_free(n_dbus); + dbus_notification_free(n_dbus); - PASS(); + PASS(); } TEST test_hint_desktop_entry(void) { - struct notification *n; - struct dbus_notification *n_dbus; - const char *desktop_entry = "org.dunst-project.dunst"; + struct notification *n; + struct dbus_notification *n_dbus; + const char *desktop_entry = "org.dunst-project.dunst"; - gsize len = queues_length_waiting(); + gsize len = queues_length_waiting(); - n_dbus = dbus_notification_new(); - n_dbus->app_name = "dunstteststack"; - n_dbus->app_icon = "NONE"; - n_dbus->summary = "test_hint_desktopentry"; - n_dbus->body = "Summary of my desktop_entry"; + n_dbus = dbus_notification_new(); + n_dbus->app_name = "dunstteststack"; + n_dbus->app_icon = "NONE"; + n_dbus->summary = "test_hint_desktopentry"; + n_dbus->body = "Summary of my desktop_entry"; - g_hash_table_insert(n_dbus->hints, - g_strdup("desktop-entry"), - g_variant_ref_sink(g_variant_new_string(desktop_entry))); + g_hash_table_insert( + n_dbus->hints, + g_strdup("desktop-entry"), + g_variant_ref_sink(g_variant_new_string(desktop_entry))); - guint id; - ASSERT(dbus_notification_fire(n_dbus, &id)); - ASSERT(id != 0); + guint id; + ASSERT(dbus_notification_fire(n_dbus, &id)); + ASSERT(id != 0); - ASSERT_EQ(queues_length_waiting(), len+1); + ASSERT_EQ(queues_length_waiting(), len + 1); - n = queues_debug_find_notification_by_id(id); + n = queues_debug_find_notification_by_id(id); - ASSERT_STR_EQ(desktop_entry, n->desktop_entry); + ASSERT_STR_EQ(desktop_entry, n->desktop_entry); - dbus_notification_free(n_dbus); + dbus_notification_free(n_dbus); - PASS(); + PASS(); } TEST test_hint_urgency(void) { - static char msg[50]; - struct notification *n; - struct dbus_notification *n_dbus; - - gsize len = queues_length_waiting(); - - n_dbus = dbus_notification_new(); - n_dbus->app_name = "dunstteststack"; - n_dbus->app_icon = "NONE"; - n_dbus->summary = "test_hint_urgency"; - n_dbus->body = "Summary of it"; - - enum urgency values[] = { URG_MAX, URG_LOW, URG_NORM, URG_CRIT }; - GVariant *variants[] = { - g_variant_new_byte(10), - g_variant_new_byte(0), - g_variant_new_byte(1), - g_variant_new_byte(2), - }; - for (size_t i = 0; i < G_N_ELEMENTS(variants); i++) { - g_hash_table_insert(n_dbus->hints, - g_strdup("urgency"), - g_variant_ref_sink(variants[i])); + static char msg[50]; + struct notification *n; + struct dbus_notification *n_dbus; + + gsize len = queues_length_waiting(); + + n_dbus = dbus_notification_new(); + n_dbus->app_name = "dunstteststack"; + n_dbus->app_icon = "NONE"; + n_dbus->summary = "test_hint_urgency"; + n_dbus->body = "Summary of it"; + + enum urgency values[] = {URG_MAX, URG_LOW, URG_NORM, URG_CRIT}; + GVariant *variants[] = { + g_variant_new_byte(10), + g_variant_new_byte(0), + g_variant_new_byte(1), + g_variant_new_byte(2), + }; + for (size_t i = 0; i < G_N_ELEMENTS(variants); i++) { + g_hash_table_insert(n_dbus->hints, + g_strdup("urgency"), + g_variant_ref_sink(variants[i])); - guint id; - ASSERT(dbus_notification_fire(n_dbus, &id)); - ASSERT(id != 0); + guint id; + ASSERT(dbus_notification_fire(n_dbus, &id)); + ASSERT(id != 0); - ASSERT_EQ(queues_length_waiting(), len+1); + ASSERT_EQ(queues_length_waiting(), len + 1); - n = queues_debug_find_notification_by_id(id); + n = queues_debug_find_notification_by_id(id); - snprintf(msg, sizeof(msg), "In round %zu", i); - ASSERT_EQm(msg, values[i], n->urgency); + snprintf(msg, sizeof(msg), "In round %zu", i); + ASSERT_EQm(msg, values[i], n->urgency); - queues_notification_close_id(id, REASON_UNDEF); - } + queues_notification_close_id(id, REASON_UNDEF); + } - dbus_notification_free(n_dbus); + dbus_notification_free(n_dbus); - PASS(); + PASS(); } TEST test_hint_raw_image(void) { - guint id; - struct notification *n; - struct dbus_notification *n_dbus; + guint id; + struct notification *n; + struct dbus_notification *n_dbus; - char *path = g_strconcat(base, "/data/icons/valid.png", NULL); - gsize len = queues_length_waiting(); + char *path = g_strconcat(base, "/data/icons/valid.png", NULL); + gsize len = queues_length_waiting(); - n_dbus = dbus_notification_new(); - dbus_notification_set_raw_image(n_dbus, path); - n_dbus->app_name = "dunstteststack"; - n_dbus->app_icon = "NONE"; - n_dbus->summary = "test_hint_raw_image"; - n_dbus->body = "Summary of it"; + n_dbus = dbus_notification_new(); + dbus_notification_set_raw_image(n_dbus, path); + n_dbus->app_name = "dunstteststack"; + n_dbus->app_icon = "NONE"; + n_dbus->summary = "test_hint_raw_image"; + n_dbus->body = "Summary of it"; - ASSERT(dbus_notification_fire(n_dbus, &id)); - ASSERT(id != 0); + ASSERT(dbus_notification_fire(n_dbus, &id)); + ASSERT(id != 0); - ASSERT_EQ(queues_length_waiting(), len+1); - n = queues_debug_find_notification_by_id(id); + ASSERT_EQ(queues_length_waiting(), len + 1); + n = queues_debug_find_notification_by_id(id); - ASSERT(n->icon); - ASSERT(!STR_EQ(n->icon_id, n_dbus->app_icon)); + ASSERT(n->icon); + ASSERT(!STR_EQ(n->icon_id, n_dbus->app_icon)); - dbus_notification_free(n_dbus); - g_free(path); + dbus_notification_free(n_dbus); + g_free(path); - PASS(); + PASS(); } /* We didn't process the timeout parameter via DBus correctly @@ -1249,384 +1282,385 @@ TEST test_hint_raw_image(void) * See: Issue #646 (The timeout value in dunst wraps around) */ TEST test_timeout_overflow(void) { - struct notification *n; - struct dbus_notification *n_dbus; + struct notification *n; + struct dbus_notification *n_dbus; - n_dbus = dbus_notification_new(); - n_dbus->app_name = "dunstteststack"; - n_dbus->app_icon = "NONE"; - n_dbus->summary = "test_hint_urgency"; - n_dbus->body = "Summary of it"; - n_dbus->expire_timeout = 2147484; - gint64 expected_timeout = G_GINT64_CONSTANT(2147484000); + n_dbus = dbus_notification_new(); + n_dbus->app_name = "dunstteststack"; + n_dbus->app_icon = "NONE"; + n_dbus->summary = "test_hint_urgency"; + n_dbus->body = "Summary of it"; + n_dbus->expire_timeout = 2147484; + gint64 expected_timeout = G_GINT64_CONSTANT(2147484000); - guint id; - ASSERT(dbus_notification_fire(n_dbus, &id)); - ASSERT(id != 0); + guint id; + ASSERT(dbus_notification_fire(n_dbus, &id)); + ASSERT(id != 0); - n = queues_debug_find_notification_by_id(id); - ASSERT_EQ_FMT(expected_timeout, n->timeout, "%" G_GINT64_FORMAT); + n = queues_debug_find_notification_by_id(id); + ASSERT_EQ_FMT(expected_timeout, n->timeout, "%" G_GINT64_FORMAT); - dbus_notification_free(n_dbus); + dbus_notification_free(n_dbus); - PASS(); + PASS(); } TEST test_server_caps(enum markup_mode markup) { - GVariant *reply; - GVariant *caps = NULL; - const char **capsarray; - - struct rule *global_rule = get_rule("global"); - if (!global_rule) { - global_rule = rule_new("global"); - } - global_rule->markup = markup; - - reply = dbus_invoke("GetCapabilities", NULL); - - caps = g_variant_get_child_value(reply, 0); - capsarray = g_variant_get_strv(caps, NULL); - - ASSERT(capsarray); - ASSERT(g_strv_contains(capsarray, "actions")); - ASSERT(g_strv_contains(capsarray, "body")); - ASSERT(g_strv_contains(capsarray, "body-hyperlinks")); - ASSERT(g_strv_contains(capsarray, "icon-static")); - ASSERT(g_strv_contains(capsarray, "x-dunst-stack-tag")); - - if (markup != MARKUP_NO) - ASSERT(g_strv_contains(capsarray, "body-markup")); - else - ASSERT_FALSE(g_strv_contains(capsarray, "body-markup")); - - g_free(capsarray); - g_variant_unref(caps); - g_variant_unref(reply); - PASS(); + GVariant *reply; + GVariant *caps = NULL; + const char **capsarray; + + struct rule *global_rule = get_rule("global"); + if (!global_rule) { + global_rule = rule_new("global"); + } + global_rule->markup = markup; + + reply = dbus_invoke("GetCapabilities", NULL); + + caps = g_variant_get_child_value(reply, 0); + capsarray = g_variant_get_strv(caps, NULL); + + ASSERT(capsarray); + ASSERT(g_strv_contains(capsarray, "actions")); + ASSERT(g_strv_contains(capsarray, "body")); + ASSERT(g_strv_contains(capsarray, "body-hyperlinks")); + ASSERT(g_strv_contains(capsarray, "icon-static")); + ASSERT(g_strv_contains(capsarray, "x-dunst-stack-tag")); + + if (markup != MARKUP_NO) + ASSERT(g_strv_contains(capsarray, "body-markup")); + else + ASSERT_FALSE(g_strv_contains(capsarray, "body-markup")); + + g_free(capsarray); + g_variant_unref(caps); + g_variant_unref(reply); + PASS(); } TEST test_signal_actioninvoked(void) { - const struct notification *n; - struct dbus_notification *n_dbus; - struct signal_actioninvoked sig = {0, NULL, -1}; + const struct notification *n; + struct dbus_notification *n_dbus; + struct signal_actioninvoked sig = {0, NULL, -1}; - dbus_signal_subscribe_actioninvoked(&sig); + dbus_signal_subscribe_actioninvoked(&sig); - n_dbus = dbus_notification_new(); - n_dbus->app_name = "dunstteststack"; - n_dbus->app_icon = "NONE2"; - n_dbus->summary = "Headline for New"; - n_dbus->body = "Text"; - g_hash_table_insert(n_dbus->actions, g_strdup("actionkey"), g_strdup("Print this text")); + n_dbus = dbus_notification_new(); + n_dbus->app_name = "dunstteststack"; + n_dbus->app_icon = "NONE2"; + n_dbus->summary = "Headline for New"; + n_dbus->body = "Text"; + g_hash_table_insert( + n_dbus->actions, g_strdup("actionkey"), g_strdup("Print this text")); - dbus_notification_fire(n_dbus, &sig.id); - n = queues_debug_find_notification_by_id(sig.id); + dbus_notification_fire(n_dbus, &sig.id); + n = queues_debug_find_notification_by_id(sig.id); - signal_action_invoked(n, "actionkey"); + signal_action_invoked(n, "actionkey"); - uint waiting = 0; - while (!sig.key && waiting < 2000) { - usleep(500); - waiting++; - } + uint waiting = 0; + while (!sig.key && waiting < 2000) { + usleep(500); + waiting++; + } - ASSERT_STR_EQ("actionkey", sig.key); + ASSERT_STR_EQ("actionkey", sig.key); - g_free(sig.key); - dbus_notification_free(n_dbus); - dbus_signal_unsubscribe_actioninvoked(&sig); - PASS(); + g_free(sig.key); + dbus_notification_free(n_dbus); + dbus_signal_unsubscribe_actioninvoked(&sig); + PASS(); } TEST test_signal_length_propertieschanged(void) { - struct dbus_notification *n_dbus; - struct signal_propertieschanged sig = {NULL, NULL, NULL, -1}; + struct dbus_notification *n_dbus; + struct signal_propertieschanged sig = {NULL, NULL, NULL, -1}; - dbus_signal_subscribe_propertieschanged(&sig); + dbus_signal_subscribe_propertieschanged(&sig); - n_dbus = dbus_notification_new(); - n_dbus->app_name = "dunstteststack"; - n_dbus->app_icon = "NONE2"; - n_dbus->summary = "Headline for New"; - n_dbus->body = "Text"; - g_hash_table_insert(n_dbus->actions, g_strdup("actionkey"), g_strdup("Print this text")); + n_dbus = dbus_notification_new(); + n_dbus->app_name = "dunstteststack"; + n_dbus->app_icon = "NONE2"; + n_dbus->summary = "Headline for New"; + n_dbus->body = "Text"; + g_hash_table_insert( + n_dbus->actions, g_strdup("actionkey"), g_strdup("Print this text")); - guint id; - ASSERT(dbus_notification_fire(n_dbus, &id)); - ASSERT(id != 0); + guint id; + ASSERT(dbus_notification_fire(n_dbus, &id)); + ASSERT(id != 0); - queues_update(STATUS_NORMAL, time_monotonic_now()); + queues_update(STATUS_NORMAL, time_monotonic_now()); - uint waiting = 0; - while (!sig.interface && waiting < 2000) { - usleep(500); - waiting++; - } + uint waiting = 0; + while (!sig.interface && waiting < 2000) { + usleep(500); + waiting++; + } - ASSERT_STR_EQ(sig.interface, DUNST_IFAC); + ASSERT_STR_EQ(sig.interface, DUNST_IFAC); - guint32 displayed_length; - g_variant_lookup(sig.array_dict_sv_data, "displayedLength", "u", &displayed_length); + guint32 displayed_length; + g_variant_lookup( + sig.array_dict_sv_data, "displayedLength", "u", &displayed_length); - ASSERT_EQ(displayed_length, queues_length_displayed()); + ASSERT_EQ(displayed_length, queues_length_displayed()); - g_free(sig.interface); - g_variant_unref(sig.array_dict_sv_data); - g_variant_unref(sig.array_s_data); - dbus_notification_free(n_dbus); - dbus_signal_unsubscribe_propertieschanged(&sig); - PASS(); + g_free(sig.interface); + g_variant_unref(sig.array_dict_sv_data); + g_variant_unref(sig.array_s_data); + dbus_notification_free(n_dbus); + dbus_signal_unsubscribe_propertieschanged(&sig); + PASS(); } TEST test_close_and_signal(void) { - GVariant *data, *ret; - struct dbus_notification *n; - struct signal_closed sig = {0, REASON_MIN-1, -1}; + GVariant *data, *ret; + struct dbus_notification *n; + struct signal_closed sig = {0, REASON_MIN - 1, -1}; - dbus_signal_subscribe_closed(&sig); + dbus_signal_subscribe_closed(&sig); - n = dbus_notification_new(); - n->app_name = "dunstteststack"; - n->app_icon = "NONE2"; - n->summary = "Headline for New"; - n->body = "Text"; + n = dbus_notification_new(); + n->app_name = "dunstteststack"; + n->app_icon = "NONE2"; + n->summary = "Headline for New"; + n->body = "Text"; - dbus_notification_fire(n, &sig.id); + dbus_notification_fire(n, &sig.id); - data = g_variant_new("(u)", sig.id); - ret = dbus_invoke("CloseNotification", data); + data = g_variant_new("(u)", sig.id); + ret = dbus_invoke("CloseNotification", data); - ASSERT(ret); + ASSERT(ret); - uint waiting = 0; - while (sig.reason == REASON_MIN-1 && waiting < 2000) { - usleep(500); - waiting++; - } + uint waiting = 0; + while (sig.reason == REASON_MIN - 1 && waiting < 2000) { + usleep(500); + waiting++; + } - ASSERT(sig.reason != REASON_MIN-1); + ASSERT(sig.reason != REASON_MIN - 1); - dbus_notification_free(n); - dbus_signal_unsubscribe_closed(&sig); - g_variant_unref(ret); - PASS(); + dbus_notification_free(n); + dbus_signal_unsubscribe_closed(&sig); + g_variant_unref(ret); + PASS(); } TEST test_get_fdn_daemon_info(void) { - guint pid_is; - pid_t pid_should; - char *name, *vendor; - GDBusConnection *conn; + guint pid_is; + pid_t pid_should; + char *name, *vendor; + GDBusConnection *conn; - pid_should = getpid(); - conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); + pid_should = getpid(); + conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); - ASSERT(dbus_get_fdn_daemon_info(conn, &pid_is, &name, &vendor)); + ASSERT(dbus_get_fdn_daemon_info(conn, &pid_is, &name, &vendor)); - ASSERT_EQ_FMT(pid_should, (pid_t)pid_is, "%d"); - ASSERT_STR_EQ("dunst", name); - ASSERT_STR_EQ("knopwob", vendor); + ASSERT_EQ_FMT(pid_should, (pid_t)pid_is, "%d"); + ASSERT_STR_EQ("dunst", name); + ASSERT_STR_EQ("knopwob", vendor); - g_free(name); - g_free(vendor); + g_free(name); + g_free(vendor); - g_object_unref(conn); - PASS(); + g_object_unref(conn); + PASS(); } TEST assert_methodlists_sorted(void) { - for (size_t i = 0; i+1 < G_N_ELEMENTS(methods_fdn); i++) { - ASSERT(0 > strcmp( - methods_fdn[i].method_name, - methods_fdn[i+1].method_name)); - } + for (size_t i = 0; i + 1 < G_N_ELEMENTS(methods_fdn); i++) { + ASSERT(0 > strcmp(methods_fdn[i].method_name, + methods_fdn[i + 1].method_name)); + } - for (size_t i = 0; i+1 < G_N_ELEMENTS(methods_dunst); i++) { - ASSERT(0 > strcmp( - methods_dunst[i].method_name, - methods_dunst[i+1].method_name)); - } + for (size_t i = 0; i + 1 < G_N_ELEMENTS(methods_dunst); i++) { + ASSERT(0 > strcmp(methods_dunst[i].method_name, + methods_dunst[i + 1].method_name)); + } - PASS(); + PASS(); } TEST test_override_dbus_timeout(void) { - struct notification *n; - struct dbus_notification *n_dbus; - struct rule *rule; + struct notification *n; + struct dbus_notification *n_dbus; + struct rule *rule; - n_dbus = dbus_notification_new(); - n_dbus->app_name = "dunstteststack"; - n_dbus->expire_timeout = 2147484; + n_dbus = dbus_notification_new(); + n_dbus->app_name = "dunstteststack"; + n_dbus->expire_timeout = 2147484; - rule = rule_new("test_override_dbus_timeout"); - rule->appname = "dunstteststack"; - rule->override_dbus_timeout = 100000; + rule = rule_new("test_override_dbus_timeout"); + rule->appname = "dunstteststack"; + rule->override_dbus_timeout = 100000; - gint64 expected_timeout = rule->override_dbus_timeout; + gint64 expected_timeout = rule->override_dbus_timeout; - guint id; - ASSERT(dbus_notification_fire(n_dbus, &id)); - ASSERT(id != 0); + guint id; + ASSERT(dbus_notification_fire(n_dbus, &id)); + ASSERT(id != 0); - n = queues_debug_find_notification_by_id(id); - ASSERT_EQ_FMT(expected_timeout, n->timeout, "%" G_GINT64_FORMAT); + n = queues_debug_find_notification_by_id(id); + ASSERT_EQ_FMT(expected_timeout, n->timeout, "%" G_GINT64_FORMAT); - dbus_notification_free(n_dbus); - rules = g_slist_remove(rules, rule); - g_free(rule->name); - g_free(rule); + dbus_notification_free(n_dbus); + rules = g_slist_remove(rules, rule); + g_free(rule->name); + g_free(rule); - PASS(); + PASS(); } TEST test_match_dbus_timeout(void) { - struct notification *n; - struct dbus_notification *n_dbus; - struct rule *rule; + struct notification *n; + struct dbus_notification *n_dbus; + struct rule *rule; - n_dbus = dbus_notification_new(); - n_dbus->app_name = "dunstteststack"; - n_dbus->expire_timeout = 2147484; + n_dbus = dbus_notification_new(); + n_dbus->app_name = "dunstteststack"; + n_dbus->expire_timeout = 2147484; - rule = rule_new("test_match_dbus_timeout"); - rule->match_dbus_timeout = 2147484000; - rule->override_dbus_timeout = 100000; + rule = rule_new("test_match_dbus_timeout"); + rule->match_dbus_timeout = 2147484000; + rule->override_dbus_timeout = 100000; - gint64 expected_timeout = rule->override_dbus_timeout; + gint64 expected_timeout = rule->override_dbus_timeout; - guint id; - ASSERT(dbus_notification_fire(n_dbus, &id)); - ASSERT(id != 0); + guint id; + ASSERT(dbus_notification_fire(n_dbus, &id)); + ASSERT(id != 0); - n = queues_debug_find_notification_by_id(id); - ASSERT_EQ_FMT(expected_timeout, n->timeout, "%" G_GINT64_FORMAT); + n = queues_debug_find_notification_by_id(id); + ASSERT_EQ_FMT(expected_timeout, n->timeout, "%" G_GINT64_FORMAT); - dbus_notification_free(n_dbus); - rules = g_slist_remove(rules, rule); - g_free(rule->name); - g_free(rule); + dbus_notification_free(n_dbus); + rules = g_slist_remove(rules, rule); + g_free(rule->name); + g_free(rule); - PASS(); + PASS(); } TEST test_timeout(void) { - struct notification *n; - struct dbus_notification *n_dbus; - struct rule *rule; + struct notification *n; + struct dbus_notification *n_dbus; + struct rule *rule; - n_dbus = dbus_notification_new(); - n_dbus->app_name = "dunstteststack"; + n_dbus = dbus_notification_new(); + n_dbus->app_name = "dunstteststack"; - rule = rule_new("test_timeout"); - rule->appname = "dunstteststack"; - rule->timeout = 100001; + rule = rule_new("test_timeout"); + rule->appname = "dunstteststack"; + rule->timeout = 100001; - gint64 expected_timeout = rule->timeout; + gint64 expected_timeout = rule->timeout; - guint id; - ASSERT(dbus_notification_fire(n_dbus, &id)); - ASSERT(id != 0); + guint id; + ASSERT(dbus_notification_fire(n_dbus, &id)); + ASSERT(id != 0); - n = queues_debug_find_notification_by_id(id); - ASSERT_EQ_FMT(expected_timeout, n->timeout, "%" G_GINT64_FORMAT); + n = queues_debug_find_notification_by_id(id); + ASSERT_EQ_FMT(expected_timeout, n->timeout, "%" G_GINT64_FORMAT); - dbus_notification_free(n_dbus); - rules = g_slist_remove(rules, rule); - g_free(rule->name); - g_free(rule); + dbus_notification_free(n_dbus); + rules = g_slist_remove(rules, rule); + g_free(rule->name); + g_free(rule); - PASS(); + PASS(); } TEST test_clearhistory_and_signal(void) { - GVariant *ret; - struct signal_historycleared sig = {0, -1}; + GVariant *ret; + struct signal_historycleared sig = {0, -1}; - dbus_signal_subscribe_historycleared(&sig); + dbus_signal_subscribe_historycleared(&sig); - guint count = queues_length_history(); + guint count = queues_length_history(); - ret = dbus_invoke_ifac("NotificationClearHistory", NULL, DUNST_IFAC); + ret = dbus_invoke_ifac("NotificationClearHistory", NULL, DUNST_IFAC); - ASSERT(ret); - g_variant_unref(ret); + ASSERT(ret); + g_variant_unref(ret); - uint waiting = 0; - while (sig.count == 0 && waiting < 2000) { - usleep(500); - waiting++; - } + uint waiting = 0; + while (sig.count == 0 && waiting < 2000) { + usleep(500); + waiting++; + } - ASSERT(sig.count == count); + ASSERT(sig.count == count); - sig.count = 0; - queues_history_clear(); + sig.count = 0; + queues_history_clear(); - struct notification *n = notification_create(); - n->appname = g_strdup("dunstify"); - n->summary = g_strdup("Testing"); - queues_history_push(n); + struct notification *n = notification_create(); + n->appname = g_strdup("dunstify"); + n->summary = g_strdup("Testing"); + queues_history_push(n); - ret = dbus_invoke_ifac("NotificationClearHistory", NULL, DUNST_IFAC); - ASSERT(ret); - g_variant_unref(ret); + ret = dbus_invoke_ifac("NotificationClearHistory", NULL, DUNST_IFAC); + ASSERT(ret); + g_variant_unref(ret); - waiting = 0; - while (sig.count == 0 && waiting < 2000) { - usleep(500); - waiting++; - } + waiting = 0; + while (sig.count == 0 && waiting < 2000) { + usleep(500); + waiting++; + } - ASSERT(sig.count == 1); + ASSERT(sig.count == 1); - queues_history_clear(); - dbus_signal_unsubscribe_historycleared(&sig); - PASS(); + queues_history_clear(); + dbus_signal_unsubscribe_historycleared(&sig); + PASS(); } TEST test_removehistory_and_signal(void) { - GVariant *data, *ret; - struct signal_historyremoved sig = {0, false, -1}; + GVariant *data, *ret; + struct signal_historyremoved sig = {0, false, -1}; - dbus_signal_subscribe_historyremoved(&sig); - queues_history_clear(); + dbus_signal_subscribe_historyremoved(&sig); + queues_history_clear(); - struct notification *n = notification_create(); - n->appname = g_strdup("dunstify"); - n->summary = g_strdup("Testing"); - queues_history_push(n); + struct notification *n = notification_create(); + n->appname = g_strdup("dunstify"); + n->summary = g_strdup("Testing"); + queues_history_push(n); - data = g_variant_new("(u)", sig.id); - ret = dbus_invoke_ifac("NotificationRemoveFromHistory", data, DUNST_IFAC); + data = g_variant_new("(u)", sig.id); + ret = dbus_invoke_ifac("NotificationRemoveFromHistory", data, DUNST_IFAC); - ASSERT(ret); + ASSERT(ret); - uint waiting = 0; - while (!sig.removed && waiting < 2000) { - usleep(500); - waiting++; - } + uint waiting = 0; + while (!sig.removed && waiting < 2000) { + usleep(500); + waiting++; + } - ASSERT(sig.removed); - ASSERT(queues_length_history() == 0); + ASSERT(sig.removed); + ASSERT(queues_length_history() == 0); - queues_history_clear(); - dbus_signal_unsubscribe_historyremoved(&sig); - g_variant_unref(ret); - PASS(); + queues_history_clear(); + dbus_signal_unsubscribe_historyremoved(&sig); + g_variant_unref(ret); + PASS(); } // TESTS END @@ -1636,70 +1670,70 @@ GThread *thread_tests; gpointer run_threaded_tests(gpointer data) { - RUN_TEST(test_dbus_init); - - RUN_TEST(test_get_fdn_daemon_info); - RUN_TEST(test_dbus_cb_dunst_Properties_Get); - RUN_TEST(test_dbus_cb_dunst_Properties_Set); - RUN_TEST(test_dbus_cb_dunst_Properties_Set_pause_level); - - RUN_TEST(test_empty_notification); - RUN_TEST(test_basic_notification); - RUN_TEST(test_invalid_notification); - RUN_TEST(test_hint_transient); - RUN_TEST(test_hint_progress); - RUN_TEST(test_hint_icons); - RUN_TEST(test_hint_category); - RUN_TEST(test_hint_desktop_entry); - RUN_TEST(test_hint_urgency); - RUN_TEST(test_hint_raw_image); - RUN_TEST(test_dbus_notify_colors); - RUN_TESTp(test_server_caps, MARKUP_FULL); - RUN_TESTp(test_server_caps, MARKUP_STRIP); - RUN_TESTp(test_server_caps, MARKUP_NO); - RUN_TEST(test_close_and_signal); - RUN_TEST(test_signal_actioninvoked); - RUN_TEST(test_signal_length_propertieschanged); - RUN_TEST(test_timeout_overflow); - RUN_TEST(test_override_dbus_timeout); - RUN_TEST(test_match_dbus_timeout); - RUN_TEST(test_timeout); - RUN_TEST(test_clearhistory_and_signal); - RUN_TEST(test_removehistory_and_signal); - RUN_TEST(test_dbus_cb_dunst_NotificationListHistory); - RUN_TEST(test_dbus_cb_dunst_RuleEnable); - RUN_TEST(test_dbus_cb_dunst_RuleList); - - RUN_TEST(assert_methodlists_sorted); - - RUN_TEST(test_dbus_teardown); - g_main_loop_quit(loop); - return NULL; + RUN_TEST(test_dbus_init); + + RUN_TEST(test_get_fdn_daemon_info); + RUN_TEST(test_dbus_cb_dunst_Properties_Get); + RUN_TEST(test_dbus_cb_dunst_Properties_Set); + RUN_TEST(test_dbus_cb_dunst_Properties_Set_pause_level); + + RUN_TEST(test_empty_notification); + RUN_TEST(test_basic_notification); + RUN_TEST(test_invalid_notification); + RUN_TEST(test_hint_transient); + RUN_TEST(test_hint_progress); + RUN_TEST(test_hint_icons); + RUN_TEST(test_hint_category); + RUN_TEST(test_hint_desktop_entry); + RUN_TEST(test_hint_urgency); + RUN_TEST(test_hint_raw_image); + RUN_TEST(test_dbus_notify_colors); + RUN_TESTp(test_server_caps, MARKUP_FULL); + RUN_TESTp(test_server_caps, MARKUP_STRIP); + RUN_TESTp(test_server_caps, MARKUP_NO); + RUN_TEST(test_close_and_signal); + RUN_TEST(test_signal_actioninvoked); + RUN_TEST(test_signal_length_propertieschanged); + RUN_TEST(test_timeout_overflow); + RUN_TEST(test_override_dbus_timeout); + RUN_TEST(test_match_dbus_timeout); + RUN_TEST(test_timeout); + RUN_TEST(test_clearhistory_and_signal); + RUN_TEST(test_removehistory_and_signal); + RUN_TEST(test_dbus_cb_dunst_NotificationListHistory); + RUN_TEST(test_dbus_cb_dunst_RuleEnable); + RUN_TEST(test_dbus_cb_dunst_RuleList); + + RUN_TEST(assert_methodlists_sorted); + + RUN_TEST(test_dbus_teardown); + g_main_loop_quit(loop); + return NULL; } SUITE(suite_dbus) { - GTestDBus *dbus_bus; - g_test_dbus_unset(); - queues_init(); + GTestDBus *dbus_bus; + g_test_dbus_unset(); + queues_init(); - loop = g_main_loop_new(NULL, false); + loop = g_main_loop_new(NULL, false); - dbus_bus = g_test_dbus_new(G_TEST_DBUS_NONE); + dbus_bus = g_test_dbus_new(G_TEST_DBUS_NONE); - // workaround bug in glib where stdout output is duplicated - // See https://gitlab.gnome.org/GNOME/glib/-/issues/2322 - fflush(stdout); - g_test_dbus_up(dbus_bus); + // workaround bug in glib where stdout output is duplicated + // See https://gitlab.gnome.org/GNOME/glib/-/issues/2322 + fflush(stdout); + g_test_dbus_up(dbus_bus); - thread_tests = g_thread_new("testexecutor", run_threaded_tests, loop); - g_main_loop_run(loop); + thread_tests = g_thread_new("testexecutor", run_threaded_tests, loop); + g_main_loop_run(loop); - queues_teardown(); - g_test_dbus_down(dbus_bus); - g_object_unref(dbus_bus); - g_thread_unref(thread_tests); - g_main_loop_unref(loop); + queues_teardown(); + g_test_dbus_down(dbus_bus); + g_object_unref(dbus_bus); + g_thread_unref(thread_tests); + g_main_loop_unref(loop); } /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/test/draw.c b/test/draw.c index df31ccc9a..1bfdcaae5 100644 --- a/test/draw.c +++ b/test/draw.c @@ -11,385 +11,397 @@ cairo_t *c; -double get_dummy_scale(void) { return 1; } +double get_dummy_scale(void) +{ + return 1; +} -const struct screen_info* noop_screen(void) { - static struct screen_info i; - return &i; +const struct screen_info *noop_screen(void) +{ + static struct screen_info i; + return &i; } const struct output dummy_output = { #if !X11_SUPPORT - wl_init, - wl_deinit, + wl_init, + wl_deinit, - wl_win_create, - wl_win_destroy, + wl_win_create, + wl_win_destroy, - wl_win_show, - wl_win_hide, + wl_win_show, + wl_win_hide, - wl_display_surface, - wl_win_get_context, + wl_display_surface, + wl_win_get_context, - noop_screen, + noop_screen, - wl_is_idle, - wl_have_fullscreen_window, + wl_is_idle, + wl_have_fullscreen_window, #else - x_setup, - x_free, + x_setup, + x_free, - x_win_create, - x_win_destroy, + x_win_create, + x_win_destroy, - x_win_show, - x_win_hide, + x_win_show, + x_win_hide, - x_display_surface, - x_win_get_context, + x_display_surface, + x_win_get_context, - noop_screen, + noop_screen, - x_is_idle, - have_fullscreen_window, + x_is_idle, + have_fullscreen_window, #endif - get_dummy_scale, + get_dummy_scale, }; GSList *get_dummy_layouts(GSList *notifications) { - GSList *layouts = NULL; - - for (GSList *iter = notifications; iter; iter = iter->next) { - struct colored_layout *cl = layout_from_notification(c, iter->data); - layouts = g_slist_append(layouts, cl); + GSList *layouts = NULL; - } - return layouts; + for (GSList *iter = notifications; iter; iter = iter->next) { + struct colored_layout *cl = layout_from_notification(c, iter->data); + layouts = g_slist_append(layouts, cl); + } + return layouts; } struct length get_small_max_height(void) { - // to keep test calculations simpler, set max height small to - // only test cases where height is not dynamically determined - // by notification content - // future tests targeting dynamic sizing logic could be added - // to address this limitation - struct length height = { 0, 10 }; - return height; + // to keep test calculations simpler, set max height small to + // only test cases where height is not dynamically determined + // by notification content + // future tests targeting dynamic sizing logic could be added + // to address this limitation + struct length height = {0, 10}; + return height; } int get_expected_dimension_height(int layout_count, int height) { - // assumes height == notification height, see get_small_max_height - int separator_height = (layout_count - 1) * settings.separator_height; - int total_gap_size = (layout_count - 1) * settings.gap_size; - height *= layout_count; - int frame_width_total_height; - int expected_height; - if(settings.gap_size) { - frame_width_total_height = layout_count * (2 * settings.frame_width); - expected_height = height + frame_width_total_height + total_gap_size; - } else { - frame_width_total_height = 2 * settings.frame_width; - expected_height = separator_height + height + frame_width_total_height; - } - return expected_height; + // assumes height == notification height, see get_small_max_height + int separator_height = (layout_count - 1) * settings.separator_height; + int total_gap_size = (layout_count - 1) * settings.gap_size; + height *= layout_count; + int frame_width_total_height; + int expected_height; + if (settings.gap_size) { + frame_width_total_height = layout_count * (2 * settings.frame_width); + expected_height = height + frame_width_total_height + total_gap_size; + } else { + frame_width_total_height = 2 * settings.frame_width; + expected_height = separator_height + height + frame_width_total_height; + } + return expected_height; } int get_expected_dimension_y_offset(int layout_count) { - // assumes settings.height == notification height, see get_small_max_height - int expected_y = layout_count * settings.height.max; - if(settings.gap_size) { - expected_y += (layout_count * (2 * settings.frame_width)); - expected_y += (layout_count * settings.gap_size); - } else { - expected_y += (2 * settings.frame_width); - expected_y += (layout_count * settings.separator_height); - } - return expected_y; + // assumes settings.height == notification height, see get_small_max_height + int expected_y = layout_count * settings.height.max; + if (settings.gap_size) { + expected_y += (layout_count * (2 * settings.frame_width)); + expected_y += (layout_count * settings.gap_size); + } else { + expected_y += (2 * settings.frame_width); + expected_y += (layout_count * settings.separator_height); + } + return expected_y; } TEST test_layout_from_notification(void) { - struct notification *n = test_notification_with_icon("test", 10); - n->icon_position = ICON_LEFT; - ASSERT(n->icon); - n->text_to_render = g_strdup(""); - struct colored_layout *cl = layout_from_notification(c, n); - ASSERT(cl->icon); - free_colored_layout(cl); - notification_unref(n); - PASS(); + struct notification *n = test_notification_with_icon("test", 10); + n->icon_position = ICON_LEFT; + ASSERT(n->icon); + n->text_to_render = g_strdup(""); + struct colored_layout *cl = layout_from_notification(c, n); + ASSERT(cl->icon); + free_colored_layout(cl); + notification_unref(n); + PASS(); } TEST test_layout_from_notification_icon_off(void) { - struct notification *n = test_notification_with_icon("test", 10); - n->icon_position = ICON_OFF; - ASSERT(n->icon); - n->text_to_render = g_strdup(""); - struct colored_layout *cl = layout_from_notification(c, n); - ASSERT_FALSE(cl->icon); - free_colored_layout(cl); - notification_unref(n); - PASS(); + struct notification *n = test_notification_with_icon("test", 10); + n->icon_position = ICON_OFF; + ASSERT(n->icon); + n->text_to_render = g_strdup(""); + struct colored_layout *cl = layout_from_notification(c, n); + ASSERT_FALSE(cl->icon); + free_colored_layout(cl); + notification_unref(n); + PASS(); } TEST test_layout_from_notification_no_icon(void) { - struct notification *n = test_notification("test", 10); - n->icon_position = ICON_LEFT; - ASSERT_FALSE(n->icon); - n->text_to_render = g_strdup(""); - struct colored_layout *cl = layout_from_notification(c, n); - ASSERT_FALSE(cl->icon); - - free_colored_layout(cl); - notification_unref(n); - PASS(); + struct notification *n = test_notification("test", 10); + n->icon_position = ICON_LEFT; + ASSERT_FALSE(n->icon); + n->text_to_render = g_strdup(""); + struct colored_layout *cl = layout_from_notification(c, n); + ASSERT_FALSE(cl->icon); + + free_colored_layout(cl); + notification_unref(n); + PASS(); } TEST test_calculate_dimensions_height_no_gaps(void) { - struct length original_height = settings.height; - bool orginal_gap_size = settings.gap_size; - settings.height = get_small_max_height(); - settings.gap_size = 10; - - int layout_count; - GSList *notifications; - GSList *layouts; - struct dimensions dim; - int expected_height; - - layout_count = 1; - notifications = get_dummy_notifications(layout_count); - layouts = get_dummy_layouts(notifications); - dim = calculate_dimensions(layouts); - expected_height = get_expected_dimension_height(layout_count, settings.height.max); - ASSERT(dim.h == expected_height); - g_slist_free_full(layouts, free_colored_layout); - g_slist_free_full(notifications, free_dummy_notification); - - layout_count = 2; - notifications = get_dummy_notifications(layout_count); - layouts = get_dummy_layouts(notifications); - dim = calculate_dimensions(layouts); - expected_height = get_expected_dimension_height(layout_count, settings.height.max); - ASSERT(dim.h == expected_height); - g_slist_free_full(layouts, free_colored_layout); - g_slist_free_full(notifications, free_dummy_notification); - - layout_count = 3; - notifications = get_dummy_notifications(layout_count); - layouts = get_dummy_layouts(notifications); - dim = calculate_dimensions(layouts); - expected_height = get_expected_dimension_height(layout_count, settings.height.max); - ASSERT(dim.h == expected_height); - g_slist_free_full(layouts, free_colored_layout); - g_slist_free_full(notifications, free_dummy_notification); - - settings.gap_size = orginal_gap_size; - settings.height = original_height; - - PASS(); + struct length original_height = settings.height; + bool orginal_gap_size = settings.gap_size; + settings.height = get_small_max_height(); + settings.gap_size = 10; + + int layout_count; + GSList *notifications; + GSList *layouts; + struct dimensions dim; + int expected_height; + + layout_count = 1; + notifications = get_dummy_notifications(layout_count); + layouts = get_dummy_layouts(notifications); + dim = calculate_dimensions(layouts); + expected_height = + get_expected_dimension_height(layout_count, settings.height.max); + ASSERT(dim.h == expected_height); + g_slist_free_full(layouts, free_colored_layout); + g_slist_free_full(notifications, free_dummy_notification); + + layout_count = 2; + notifications = get_dummy_notifications(layout_count); + layouts = get_dummy_layouts(notifications); + dim = calculate_dimensions(layouts); + expected_height = + get_expected_dimension_height(layout_count, settings.height.max); + ASSERT(dim.h == expected_height); + g_slist_free_full(layouts, free_colored_layout); + g_slist_free_full(notifications, free_dummy_notification); + + layout_count = 3; + notifications = get_dummy_notifications(layout_count); + layouts = get_dummy_layouts(notifications); + dim = calculate_dimensions(layouts); + expected_height = + get_expected_dimension_height(layout_count, settings.height.max); + ASSERT(dim.h == expected_height); + g_slist_free_full(layouts, free_colored_layout); + g_slist_free_full(notifications, free_dummy_notification); + + settings.gap_size = orginal_gap_size; + settings.height = original_height; + + PASS(); } TEST test_calculate_dimensions_height_gaps(void) { - struct length original_height = settings.height; - bool orginal_gap_size = settings.gap_size; - settings.height = get_small_max_height(); - settings.gap_size = 10; - - int layout_count; - GSList *notifications; - GSList *layouts; - struct dimensions dim; - int expected_height; - - layout_count = 1; - notifications = get_dummy_notifications(layout_count); - layouts = get_dummy_layouts(notifications); - dim = calculate_dimensions(layouts); - expected_height = get_expected_dimension_height(layout_count, settings.height.max); - ASSERT(dim.h == expected_height); - g_slist_free_full(layouts, free_colored_layout); - g_slist_free_full(notifications, free_dummy_notification); - - layout_count = 2; - notifications = get_dummy_notifications(layout_count); - layouts = get_dummy_layouts(notifications); - dim = calculate_dimensions(layouts); - expected_height = get_expected_dimension_height(layout_count, settings.height.max); - ASSERT(dim.h == expected_height); - g_slist_free_full(layouts, free_colored_layout); - g_slist_free_full(notifications, free_dummy_notification); - - layout_count = 3; - notifications = get_dummy_notifications(layout_count); - layouts = get_dummy_layouts(notifications); - dim = calculate_dimensions(layouts); - expected_height = get_expected_dimension_height(layout_count, settings.height.max); - ASSERT(dim.h == expected_height); - - g_slist_free_full(layouts, free_colored_layout); - g_slist_free_full(notifications, free_dummy_notification); - settings.gap_size = orginal_gap_size; - settings.height = original_height; - - PASS(); + struct length original_height = settings.height; + bool orginal_gap_size = settings.gap_size; + settings.height = get_small_max_height(); + settings.gap_size = 10; + + int layout_count; + GSList *notifications; + GSList *layouts; + struct dimensions dim; + int expected_height; + + layout_count = 1; + notifications = get_dummy_notifications(layout_count); + layouts = get_dummy_layouts(notifications); + dim = calculate_dimensions(layouts); + expected_height = + get_expected_dimension_height(layout_count, settings.height.max); + ASSERT(dim.h == expected_height); + g_slist_free_full(layouts, free_colored_layout); + g_slist_free_full(notifications, free_dummy_notification); + + layout_count = 2; + notifications = get_dummy_notifications(layout_count); + layouts = get_dummy_layouts(notifications); + dim = calculate_dimensions(layouts); + expected_height = + get_expected_dimension_height(layout_count, settings.height.max); + ASSERT(dim.h == expected_height); + g_slist_free_full(layouts, free_colored_layout); + g_slist_free_full(notifications, free_dummy_notification); + + layout_count = 3; + notifications = get_dummy_notifications(layout_count); + layouts = get_dummy_layouts(notifications); + dim = calculate_dimensions(layouts); + expected_height = + get_expected_dimension_height(layout_count, settings.height.max); + ASSERT(dim.h == expected_height); + + g_slist_free_full(layouts, free_colored_layout); + g_slist_free_full(notifications, free_dummy_notification); + settings.gap_size = orginal_gap_size; + settings.height = original_height; + + PASS(); } TEST test_layout_render_no_gaps(void) { - struct length original_height = settings.height; - bool orginal_gap_size = settings.gap_size; - settings.height = get_small_max_height(); - settings.gap_size = 0; - - int layout_count; - GSList *notifications; - GSList *layouts; - struct dimensions dim; - cairo_surface_t *image_surface; - int expected_y; - - layout_count = 3; - notifications = get_dummy_notifications(layout_count); - layouts = get_dummy_layouts(notifications); - dim = calculate_dimensions(layouts); - image_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); - - enum corner_pos corners = C_TOP | _C_FIRST; - for (GSList *iter = layouts; iter; iter = iter->next) { - struct colored_layout *cl_this = iter->data; - struct colored_layout *cl_next = iter->next ? iter->next->data : NULL; - - if (!cl_next) - corners |= C_BOT | _C_LAST; - dim = layout_render(image_surface, cl_this, cl_next, dim, corners); - - corners &= ~(C_TOP | _C_FIRST); - } - - expected_y = get_expected_dimension_y_offset(layout_count); - ASSERT(dim.y == expected_y); - - g_slist_free_full(layouts, free_colored_layout); - g_slist_free_full(notifications, free_dummy_notification); - cairo_surface_destroy(image_surface); - settings.gap_size = orginal_gap_size; - settings.height = original_height; - - PASS(); + struct length original_height = settings.height; + bool orginal_gap_size = settings.gap_size; + settings.height = get_small_max_height(); + settings.gap_size = 0; + + int layout_count; + GSList *notifications; + GSList *layouts; + struct dimensions dim; + cairo_surface_t *image_surface; + int expected_y; + + layout_count = 3; + notifications = get_dummy_notifications(layout_count); + layouts = get_dummy_layouts(notifications); + dim = calculate_dimensions(layouts); + image_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); + + enum corner_pos corners = C_TOP | _C_FIRST; + for (GSList *iter = layouts; iter; iter = iter->next) { + struct colored_layout *cl_this = iter->data; + struct colored_layout *cl_next = iter->next ? iter->next->data : NULL; + + if (!cl_next) + corners |= C_BOT | _C_LAST; + dim = layout_render(image_surface, cl_this, cl_next, dim, corners); + + corners &= ~(C_TOP | _C_FIRST); + } + + expected_y = get_expected_dimension_y_offset(layout_count); + ASSERT(dim.y == expected_y); + + g_slist_free_full(layouts, free_colored_layout); + g_slist_free_full(notifications, free_dummy_notification); + cairo_surface_destroy(image_surface); + settings.gap_size = orginal_gap_size; + settings.height = original_height; + + PASS(); } TEST test_calculate_dimensions_height_min(void) { - struct length original_height = settings.height; - bool orginal_gap_size = settings.gap_size; - // NOTE: Should be big enough to fit the notification nicely - settings.height.min = 100; - settings.height.max = 200; - settings.gap_size = 0; - - int layout_count; - GSList *notifications; - GSList *layouts; - struct dimensions dim; - int expected_height; - - layout_count = 1; - notifications = get_dummy_notifications(layout_count); - layouts = get_dummy_layouts(notifications); - dim = calculate_dimensions(layouts); - expected_height = get_expected_dimension_height(layout_count, settings.height.min); - ASSERT(dim.h == expected_height); - g_slist_free_full(layouts, free_colored_layout); - g_slist_free_full(notifications, free_dummy_notification); - - layout_count = 2; - notifications = get_dummy_notifications(layout_count); - layouts = get_dummy_layouts(notifications); - dim = calculate_dimensions(layouts); - expected_height = get_expected_dimension_height(layout_count, settings.height.min); - ASSERT(dim.h == expected_height); - g_slist_free_full(layouts, free_colored_layout); - g_slist_free_full(notifications, free_dummy_notification); - - layout_count = 3; - notifications = get_dummy_notifications(layout_count); - layouts = get_dummy_layouts(notifications); - dim = calculate_dimensions(layouts); - expected_height = get_expected_dimension_height(layout_count, settings.height.min); - ASSERT(dim.h == expected_height); - - g_slist_free_full(layouts, free_colored_layout); - g_slist_free_full(notifications, free_dummy_notification); - settings.gap_size = orginal_gap_size; - settings.height = original_height; - - PASS(); + struct length original_height = settings.height; + bool orginal_gap_size = settings.gap_size; + // NOTE: Should be big enough to fit the notification nicely + settings.height.min = 100; + settings.height.max = 200; + settings.gap_size = 0; + + int layout_count; + GSList *notifications; + GSList *layouts; + struct dimensions dim; + int expected_height; + + layout_count = 1; + notifications = get_dummy_notifications(layout_count); + layouts = get_dummy_layouts(notifications); + dim = calculate_dimensions(layouts); + expected_height = + get_expected_dimension_height(layout_count, settings.height.min); + ASSERT(dim.h == expected_height); + g_slist_free_full(layouts, free_colored_layout); + g_slist_free_full(notifications, free_dummy_notification); + + layout_count = 2; + notifications = get_dummy_notifications(layout_count); + layouts = get_dummy_layouts(notifications); + dim = calculate_dimensions(layouts); + expected_height = + get_expected_dimension_height(layout_count, settings.height.min); + ASSERT(dim.h == expected_height); + g_slist_free_full(layouts, free_colored_layout); + g_slist_free_full(notifications, free_dummy_notification); + + layout_count = 3; + notifications = get_dummy_notifications(layout_count); + layouts = get_dummy_layouts(notifications); + dim = calculate_dimensions(layouts); + expected_height = + get_expected_dimension_height(layout_count, settings.height.min); + ASSERT(dim.h == expected_height); + + g_slist_free_full(layouts, free_colored_layout); + g_slist_free_full(notifications, free_dummy_notification); + settings.gap_size = orginal_gap_size; + settings.height = original_height; + + PASS(); } TEST test_layout_render_gaps(void) { - struct length original_height = settings.height; - bool orginal_gap_size = settings.gap_size; - settings.height = get_small_max_height(); - settings.gap_size = 10; - - int layout_count; - GSList *notifications; - GSList *layouts; - struct dimensions dim; - cairo_surface_t *image_surface; - int expected_y; - - layout_count = 3; - notifications = get_dummy_notifications(layout_count); - layouts = get_dummy_layouts(notifications); - dim = calculate_dimensions(layouts); - image_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); - - for (GSList *iter = layouts; iter; iter = iter->next) { - struct colored_layout *cl_this = iter->data; - struct colored_layout *cl_next = iter->next ? iter->next->data : NULL; - - dim = layout_render(image_surface, cl_this, cl_next, dim, C_ALL); - } - - expected_y = get_expected_dimension_y_offset(layout_count); - ASSERT(dim.y == expected_y); - - g_slist_free_full(layouts, free_colored_layout); - g_slist_free_full(notifications, free_dummy_notification); - cairo_surface_destroy(image_surface); - settings.gap_size = orginal_gap_size; - settings.height = original_height; - - PASS(); + struct length original_height = settings.height; + bool orginal_gap_size = settings.gap_size; + settings.height = get_small_max_height(); + settings.gap_size = 10; + + int layout_count; + GSList *notifications; + GSList *layouts; + struct dimensions dim; + cairo_surface_t *image_surface; + int expected_y; + + layout_count = 3; + notifications = get_dummy_notifications(layout_count); + layouts = get_dummy_layouts(notifications); + dim = calculate_dimensions(layouts); + image_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); + + for (GSList *iter = layouts; iter; iter = iter->next) { + struct colored_layout *cl_this = iter->data; + struct colored_layout *cl_next = iter->next ? iter->next->data : NULL; + + dim = layout_render(image_surface, cl_this, cl_next, dim, C_ALL); + } + + expected_y = get_expected_dimension_y_offset(layout_count); + ASSERT(dim.y == expected_y); + + g_slist_free_full(layouts, free_colored_layout); + g_slist_free_full(notifications, free_dummy_notification); + cairo_surface_destroy(image_surface); + settings.gap_size = orginal_gap_size; + settings.height = original_height; + + PASS(); } SUITE(suite_draw) { - output = &dummy_output; - cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); - c = cairo_create(s); - - SHUFFLE_TESTS(time(NULL), { - RUN_TEST(test_layout_from_notification); - RUN_TEST(test_layout_from_notification_icon_off); - RUN_TEST(test_layout_from_notification_no_icon); - RUN_TEST(test_calculate_dimensions_height_no_gaps); - RUN_TEST(test_calculate_dimensions_height_gaps); - RUN_TEST(test_calculate_dimensions_height_min); - RUN_TEST(test_layout_render_no_gaps); - RUN_TEST(test_layout_render_gaps); - }); + output = &dummy_output; + cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); + c = cairo_create(s); + + SHUFFLE_TESTS(time(NULL), { + RUN_TEST(test_layout_from_notification); + RUN_TEST(test_layout_from_notification_icon_off); + RUN_TEST(test_layout_from_notification_no_icon); + RUN_TEST(test_calculate_dimensions_height_no_gaps); + RUN_TEST(test_calculate_dimensions_height_gaps); + RUN_TEST(test_calculate_dimensions_height_min); + RUN_TEST(test_layout_render_no_gaps); + RUN_TEST(test_layout_render_gaps); + }); } diff --git a/test/dunst.c b/test/dunst.c index 3c949e662..1d56edb7b 100644 --- a/test/dunst.c +++ b/test/dunst.c @@ -3,21 +3,21 @@ TEST test_dunst_status(void) { - status = (struct dunst_status) {false, false, false}; + 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_int(S_PAUSE_LEVEL, 0); - ASSERT(status.pause_level == 0); + dunst_status(S_FULLSCREEN, true); + ASSERT(status.fullscreen); + dunst_status(S_IDLE, true); + ASSERT(status.idle); + dunst_status_int(S_PAUSE_LEVEL, 0); + ASSERT(status.pause_level == 0); - PASS(); + PASS(); } SUITE(suite_dunst) { - RUN_TEST(test_dunst_status); + RUN_TEST(test_dunst_status); } /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/test/functional-tests/test.sh b/test/functional-tests/test.sh index bec97d246..252a2f2e5 100755 --- a/test/functional-tests/test.sh +++ b/test/functional-tests/test.sh @@ -16,8 +16,8 @@ function keypress { } function tmp_dunstrc { - cp "$TESTDIR/$1" "$TESTDIR/dunstrc.tmp" - echo -e "\n$2" >> "$TESTDIR/dunstrc.tmp" + cp "$TESTDIR/$1" "$TESTDIR/dunstrc.tmp" + echo -e "\n$2" >> "$TESTDIR/dunstrc.tmp" } function tmp_clean { @@ -25,9 +25,9 @@ function tmp_clean { } function start_dunst { - killall dunst 2>/dev/null - $DUNST -config "$TESTDIR/$1" & - sleep 0.05 + killall dunst 2>/dev/null + $DUNST -config "$TESTDIR/$1" & + sleep 0.05 } function basic_notifications { diff --git a/test/greatest.h b/test/greatest.h index af0c0537c..53104a19d 100644 --- a/test/greatest.h +++ b/test/greatest.h @@ -18,7 +18,8 @@ #define GREATEST_H #if defined(__cplusplus) && !defined(GREATEST_NO_EXTERN_CPLUSPLUS) -extern "C" { +extern "C" +{ #endif /* 1.5.0 */ @@ -34,7 +35,6 @@ extern "C" { * https://github.com/silentbicycle/greatest/ */ - /********************************************************************* * Minimal test runner template *********************************************************************/ @@ -90,13 +90,12 @@ int main(int argc, char **argv) { } #endif -/*********************************************************************/ - + /*********************************************************************/ -#include +#include #include +#include #include -#include /*********** * Options * @@ -152,206 +151,214 @@ int main(int argc, char **argv) { #define GREATEST_TESTNAME_BUF_SIZE 128 #endif + /********* + * Types * + *********/ -/********* - * Types * - *********/ - -/* Info for the current running suite. */ -typedef struct greatest_suite_info { - unsigned int tests_run; - unsigned int passed; - unsigned int failed; - unsigned int skipped; + /* Info for the current running suite. */ + typedef struct greatest_suite_info + { + unsigned int tests_run; + unsigned int passed; + unsigned int failed; + unsigned int skipped; #if GREATEST_USE_TIME - /* timers, pre/post running suite and individual tests */ - clock_t pre_suite; - clock_t post_suite; - clock_t pre_test; - clock_t post_test; + /* timers, pre/post running suite and individual tests */ + clock_t pre_suite; + clock_t post_suite; + clock_t pre_test; + clock_t post_test; #endif -} greatest_suite_info; - -/* Type for a suite function. */ -typedef void greatest_suite_cb(void); - -/* Types for setup/teardown callbacks. If non-NULL, these will be run - * and passed the pointer to their additional data. */ -typedef void greatest_setup_cb(void *udata); -typedef void greatest_teardown_cb(void *udata); - -/* Type for an equality comparison between two pointers of the same type. - * Should return non-0 if equal, otherwise 0. - * UDATA is a closure value, passed through from ASSERT_EQUAL_T[m]. */ -typedef int greatest_equal_cb(const void *expd, const void *got, void *udata); - -/* Type for a callback that prints a value pointed to by T. - * Return value has the same meaning as printf's. - * UDATA is a closure value, passed through from ASSERT_EQUAL_T[m]. */ -typedef int greatest_printf_cb(const void *t, void *udata); - -/* Callbacks for an arbitrary type; needed for type-specific - * comparisons via GREATEST_ASSERT_EQUAL_T[m].*/ -typedef struct greatest_type_info { - greatest_equal_cb *equal; - greatest_printf_cb *print; -} greatest_type_info; - -typedef struct greatest_memory_cmp_env { - const unsigned char *exp; - const unsigned char *got; - size_t size; -} greatest_memory_cmp_env; - -/* Callbacks for string and raw memory types. */ -extern greatest_type_info greatest_type_info_string; -extern greatest_type_info greatest_type_info_memory; - -typedef enum { - GREATEST_FLAG_FIRST_FAIL = 0x01, - GREATEST_FLAG_LIST_ONLY = 0x02, - GREATEST_FLAG_ABORT_ON_FAIL = 0x04 -} greatest_flag_t; - -/* Internal state for a PRNG, used to shuffle test order. */ -struct greatest_prng { - unsigned char random_order; /* use random ordering? */ - unsigned char initialized; /* is random ordering initialized? */ - unsigned char pad_0[6]; - unsigned long state; /* PRNG state */ - unsigned long count; /* how many tests, this pass */ - unsigned long count_ceil; /* total number of tests */ - unsigned long count_run; /* total tests run */ - unsigned long a; /* LCG multiplier */ - unsigned long c; /* LCG increment */ - unsigned long m; /* LCG modulus, based on count_ceil */ -}; - -/* Struct containing all test runner state. */ -typedef struct greatest_run_info { - unsigned char flags; - unsigned char verbosity; - unsigned char running_test; /* guard for nested RUN_TEST calls */ - unsigned char exact_name_match; - - unsigned int tests_run; /* total test count */ - - /* currently running test suite */ - greatest_suite_info suite; - - /* overall pass/fail/skip counts */ - unsigned int passed; - unsigned int failed; - unsigned int skipped; - unsigned int assertions; - - /* info to print about the most recent failure */ - unsigned int fail_line; - unsigned int pad_1; - const char *fail_file; - const char *msg; - - /* current setup/teardown hooks and userdata */ - greatest_setup_cb *setup; - void *setup_udata; - greatest_teardown_cb *teardown; - void *teardown_udata; - - /* formatting info for ".....s...F"-style output */ - unsigned int col; - unsigned int width; - - /* only run a specific suite or test */ - const char *suite_filter; - const char *test_filter; - const char *test_exclude; - const char *name_suffix; /* print suffix with test name */ - char name_buf[GREATEST_TESTNAME_BUF_SIZE]; - - struct greatest_prng prng[2]; /* 0: suites, 1: tests */ + } greatest_suite_info; + + /* Type for a suite function. */ + typedef void greatest_suite_cb(void); + + /* Types for setup/teardown callbacks. If non-NULL, these will be run + * and passed the pointer to their additional data. */ + typedef void greatest_setup_cb(void *udata); + typedef void greatest_teardown_cb(void *udata); + + /* Type for an equality comparison between two pointers of the same type. + * Should return non-0 if equal, otherwise 0. + * UDATA is a closure value, passed through from ASSERT_EQUAL_T[m]. */ + typedef int + greatest_equal_cb(const void *expd, const void *got, void *udata); + + /* Type for a callback that prints a value pointed to by T. + * Return value has the same meaning as printf's. + * UDATA is a closure value, passed through from ASSERT_EQUAL_T[m]. */ + typedef int greatest_printf_cb(const void *t, void *udata); + + /* Callbacks for an arbitrary type; needed for type-specific + * comparisons via GREATEST_ASSERT_EQUAL_T[m].*/ + typedef struct greatest_type_info + { + greatest_equal_cb *equal; + greatest_printf_cb *print; + } greatest_type_info; + + typedef struct greatest_memory_cmp_env + { + const unsigned char *exp; + const unsigned char *got; + size_t size; + } greatest_memory_cmp_env; + + /* Callbacks for string and raw memory types. */ + extern greatest_type_info greatest_type_info_string; + extern greatest_type_info greatest_type_info_memory; + + typedef enum + { + GREATEST_FLAG_FIRST_FAIL = 0x01, + GREATEST_FLAG_LIST_ONLY = 0x02, + GREATEST_FLAG_ABORT_ON_FAIL = 0x04 + } greatest_flag_t; + + /* Internal state for a PRNG, used to shuffle test order. */ + struct greatest_prng + { + unsigned char random_order; /* use random ordering? */ + unsigned char initialized; /* is random ordering initialized? */ + unsigned char pad_0[6]; + unsigned long state; /* PRNG state */ + unsigned long count; /* how many tests, this pass */ + unsigned long count_ceil; /* total number of tests */ + unsigned long count_run; /* total tests run */ + unsigned long a; /* LCG multiplier */ + unsigned long c; /* LCG increment */ + unsigned long m; /* LCG modulus, based on count_ceil */ + }; + + /* Struct containing all test runner state. */ + typedef struct greatest_run_info + { + unsigned char flags; + unsigned char verbosity; + unsigned char running_test; /* guard for nested RUN_TEST calls */ + unsigned char exact_name_match; + + unsigned int tests_run; /* total test count */ + + /* currently running test suite */ + greatest_suite_info suite; + + /* overall pass/fail/skip counts */ + unsigned int passed; + unsigned int failed; + unsigned int skipped; + unsigned int assertions; + + /* info to print about the most recent failure */ + unsigned int fail_line; + unsigned int pad_1; + const char *fail_file; + const char *msg; + + /* current setup/teardown hooks and userdata */ + greatest_setup_cb *setup; + void *setup_udata; + greatest_teardown_cb *teardown; + void *teardown_udata; + + /* formatting info for ".....s...F"-style output */ + unsigned int col; + unsigned int width; + + /* only run a specific suite or test */ + const char *suite_filter; + const char *test_filter; + const char *test_exclude; + const char *name_suffix; /* print suffix with test name */ + char name_buf[GREATEST_TESTNAME_BUF_SIZE]; + + struct greatest_prng prng[2]; /* 0: suites, 1: tests */ #if GREATEST_USE_TIME - /* overall timers */ - clock_t begin; - clock_t end; + /* overall timers */ + clock_t begin; + clock_t end; #endif #if GREATEST_USE_LONGJMP - int pad_jmp_buf; - unsigned char pad_2[4]; - jmp_buf jump_dest; + int pad_jmp_buf; + unsigned char pad_2[4]; + jmp_buf jump_dest; #endif -} greatest_run_info; - -struct greatest_report_t { - /* overall pass/fail/skip counts */ - unsigned int passed; - unsigned int failed; - unsigned int skipped; - unsigned int assertions; -}; - -/* Global var for the current testing context. - * Initialized by GREATEST_MAIN_DEFS(). */ -extern greatest_run_info greatest_info; - -/* Type for ASSERT_ENUM_EQ's ENUM_STR argument. */ -typedef const char *greatest_enum_str_fun(int value); - - -/********************** - * Exported functions * - **********************/ - -/* These are used internally by greatest macros. */ -int greatest_test_pre(const char *name); -void greatest_test_post(int res); -int greatest_do_assert_equal_t(const void *expd, const void *got, - greatest_type_info *type_info, void *udata); -void greatest_prng_init_first_pass(int id); -int greatest_prng_init_second_pass(int id, unsigned long seed); -void greatest_prng_step(int id); - -/* These are part of the public greatest API. */ -void GREATEST_SET_SETUP_CB(greatest_setup_cb *cb, void *udata); -void GREATEST_SET_TEARDOWN_CB(greatest_teardown_cb *cb, void *udata); -void GREATEST_INIT(void); -void GREATEST_PRINT_REPORT(void); -int greatest_all_passed(void); -void greatest_set_suite_filter(const char *filter); -void greatest_set_test_filter(const char *filter); -void greatest_set_test_exclude(const char *filter); -void greatest_set_exact_name_match(void); -void greatest_stop_at_first_fail(void); -void greatest_abort_on_fail(void); -void greatest_list_only(void); -void greatest_get_report(struct greatest_report_t *report); -unsigned int greatest_get_verbosity(void); -void greatest_set_verbosity(unsigned int verbosity); -void greatest_set_flag(greatest_flag_t flag); -void greatest_set_test_suffix(const char *suffix); - + } greatest_run_info; + + struct greatest_report_t + { + /* overall pass/fail/skip counts */ + unsigned int passed; + unsigned int failed; + unsigned int skipped; + unsigned int assertions; + }; + + /* Global var for the current testing context. + * Initialized by GREATEST_MAIN_DEFS(). */ + extern greatest_run_info greatest_info; + + /* Type for ASSERT_ENUM_EQ's ENUM_STR argument. */ + typedef const char *greatest_enum_str_fun(int value); + + /********************** + * Exported functions * + **********************/ + + /* These are used internally by greatest macros. */ + int greatest_test_pre(const char *name); + void greatest_test_post(int res); + int greatest_do_assert_equal_t(const void *expd, + const void *got, + greatest_type_info *type_info, + void *udata); + void greatest_prng_init_first_pass(int id); + int greatest_prng_init_second_pass(int id, unsigned long seed); + void greatest_prng_step(int id); + + /* These are part of the public greatest API. */ + void GREATEST_SET_SETUP_CB(greatest_setup_cb *cb, void *udata); + void GREATEST_SET_TEARDOWN_CB(greatest_teardown_cb *cb, void *udata); + void GREATEST_INIT(void); + void GREATEST_PRINT_REPORT(void); + int greatest_all_passed(void); + void greatest_set_suite_filter(const char *filter); + void greatest_set_test_filter(const char *filter); + void greatest_set_test_exclude(const char *filter); + void greatest_set_exact_name_match(void); + void greatest_stop_at_first_fail(void); + void greatest_abort_on_fail(void); + void greatest_list_only(void); + void greatest_get_report(struct greatest_report_t *report); + unsigned int greatest_get_verbosity(void); + void greatest_set_verbosity(unsigned int verbosity); + void greatest_set_flag(greatest_flag_t flag); + void greatest_set_test_suffix(const char *suffix); /******************** -* Language Support * -********************/ + * Language Support * + ********************/ /* If __VA_ARGS__ (C99) is supported, allow parametric testing -* without needing to manually manage the argument struct. */ -#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 19901L) || \ - (defined(_MSC_VER) && _MSC_VER >= 1800) + * without needing to manually manage the argument struct. */ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 19901L) \ + || (defined(_MSC_VER) && _MSC_VER >= 1800) #define GREATEST_VA_ARGS #endif - /********** * Macros * **********/ /* Define a suite. (The duplication is intentional -- it eliminates * a warning from -Wmissing-declarations.) */ -#define GREATEST_SUITE(NAME) void NAME(void); void NAME(void) +#define GREATEST_SUITE(NAME) \ + void NAME(void); \ + void NAME(void) /* Declare a suite, provided by another compilation unit. */ #define GREATEST_SUITE_EXTERN(NAME) void NAME(void) @@ -360,26 +367,27 @@ void greatest_set_test_suffix(const char *suffix); * The arguments are not included, to allow parametric testing. */ #define GREATEST_TEST static enum greatest_test_res -/* PASS/FAIL/SKIP result from a test. Used internally. */ -typedef enum greatest_test_res { - GREATEST_TEST_RES_PASS = 0, - GREATEST_TEST_RES_FAIL = -1, - GREATEST_TEST_RES_SKIP = 1 -} greatest_test_res; + /* PASS/FAIL/SKIP result from a test. Used internally. */ + typedef enum greatest_test_res + { + GREATEST_TEST_RES_PASS = 0, + GREATEST_TEST_RES_FAIL = -1, + GREATEST_TEST_RES_SKIP = 1 + } greatest_test_res; /* Run a suite. */ #define GREATEST_RUN_SUITE(S_NAME) greatest_run_suite(S_NAME, #S_NAME) /* Run a test in the current suite. */ -#define GREATEST_RUN_TEST(TEST) \ - do { \ - if (greatest_test_pre(#TEST) == 1) { \ - enum greatest_test_res res = GREATEST_SAVE_CONTEXT(); \ - if (res == GREATEST_TEST_RES_PASS) { \ - res = TEST(); \ - } \ - greatest_test_post(res); \ - } \ +#define GREATEST_RUN_TEST(TEST) \ + do { \ + if (greatest_test_pre(#TEST) == 1) { \ + enum greatest_test_res res = GREATEST_SAVE_CONTEXT(); \ + if (res == GREATEST_TEST_RES_PASS) { \ + res = TEST(); \ + } \ + greatest_test_post(res); \ + } \ } while (0) /* Ignore a test, don't warn about it being unused. */ @@ -387,285 +395,292 @@ typedef enum greatest_test_res { /* Run a test in the current suite with one void * argument, * which can be a pointer to a struct with multiple arguments. */ -#define GREATEST_RUN_TEST1(TEST, ENV) \ - do { \ - if (greatest_test_pre(#TEST) == 1) { \ - enum greatest_test_res res = GREATEST_SAVE_CONTEXT(); \ - if (res == GREATEST_TEST_RES_PASS) { \ - res = TEST(ENV); \ - } \ - greatest_test_post(res); \ - } \ +#define GREATEST_RUN_TEST1(TEST, ENV) \ + do { \ + if (greatest_test_pre(#TEST) == 1) { \ + enum greatest_test_res res = GREATEST_SAVE_CONTEXT(); \ + if (res == GREATEST_TEST_RES_PASS) { \ + res = TEST(ENV); \ + } \ + greatest_test_post(res); \ + } \ } while (0) #ifdef GREATEST_VA_ARGS -#define GREATEST_RUN_TESTp(TEST, ...) \ - do { \ - if (greatest_test_pre(#TEST) == 1) { \ - enum greatest_test_res res = GREATEST_SAVE_CONTEXT(); \ - if (res == GREATEST_TEST_RES_PASS) { \ - res = TEST(__VA_ARGS__); \ - } \ - greatest_test_post(res); \ - } \ +#define GREATEST_RUN_TESTp(TEST, ...) \ + do { \ + if (greatest_test_pre(#TEST) == 1) { \ + enum greatest_test_res res = GREATEST_SAVE_CONTEXT(); \ + if (res == GREATEST_TEST_RES_PASS) { \ + res = TEST(__VA_ARGS__); \ + } \ + greatest_test_post(res); \ + } \ } while (0) #endif - /* Check if the test runner is in verbose mode. */ #define GREATEST_IS_VERBOSE() ((greatest_info.verbosity) > 0) -#define GREATEST_LIST_ONLY() \ - (greatest_info.flags & GREATEST_FLAG_LIST_ONLY) -#define GREATEST_FIRST_FAIL() \ - (greatest_info.flags & GREATEST_FLAG_FIRST_FAIL) -#define GREATEST_ABORT_ON_FAIL() \ +#define GREATEST_LIST_ONLY() (greatest_info.flags & GREATEST_FLAG_LIST_ONLY) +#define GREATEST_FIRST_FAIL() (greatest_info.flags & GREATEST_FLAG_FIRST_FAIL) +#define GREATEST_ABORT_ON_FAIL() \ (greatest_info.flags & GREATEST_FLAG_ABORT_ON_FAIL) -#define GREATEST_FAILURE_ABORT() \ - (GREATEST_FIRST_FAIL() && \ - (greatest_info.suite.failed > 0 || greatest_info.failed > 0)) +#define GREATEST_FAILURE_ABORT() \ + (GREATEST_FIRST_FAIL() \ + && (greatest_info.suite.failed > 0 || greatest_info.failed > 0)) /* Message-less forms of tests defined below. */ #define GREATEST_PASS() GREATEST_PASSm(NULL) #define GREATEST_FAIL() GREATEST_FAILm(NULL) #define GREATEST_SKIP() GREATEST_SKIPm(NULL) -#define GREATEST_ASSERT(COND) \ - GREATEST_ASSERTm(#COND, COND) -#define GREATEST_ASSERT_OR_LONGJMP(COND) \ +#define GREATEST_ASSERT(COND) GREATEST_ASSERTm(#COND, COND) +#define GREATEST_ASSERT_OR_LONGJMP(COND) \ GREATEST_ASSERT_OR_LONGJMPm(#COND, COND) -#define GREATEST_ASSERT_FALSE(COND) \ - GREATEST_ASSERT_FALSEm(#COND, COND) -#define GREATEST_ASSERT_EQ(EXP, GOT) \ +#define GREATEST_ASSERT_FALSE(COND) GREATEST_ASSERT_FALSEm(#COND, COND) +#define GREATEST_ASSERT_EQ(EXP, GOT) \ GREATEST_ASSERT_EQm(#EXP " != " #GOT, EXP, GOT) -#define GREATEST_ASSERT_NEQ(EXP, GOT) \ +#define GREATEST_ASSERT_NEQ(EXP, GOT) \ GREATEST_ASSERT_NEQm(#EXP " == " #GOT, EXP, GOT) -#define GREATEST_ASSERT_GT(EXP, GOT) \ +#define GREATEST_ASSERT_GT(EXP, GOT) \ GREATEST_ASSERT_GTm(#EXP " <= " #GOT, EXP, GOT) -#define GREATEST_ASSERT_GTE(EXP, GOT) \ +#define GREATEST_ASSERT_GTE(EXP, GOT) \ GREATEST_ASSERT_GTEm(#EXP " < " #GOT, EXP, GOT) -#define GREATEST_ASSERT_LT(EXP, GOT) \ +#define GREATEST_ASSERT_LT(EXP, GOT) \ GREATEST_ASSERT_LTm(#EXP " >= " #GOT, EXP, GOT) -#define GREATEST_ASSERT_LTE(EXP, GOT) \ +#define GREATEST_ASSERT_LTE(EXP, GOT) \ GREATEST_ASSERT_LTEm(#EXP " > " #GOT, EXP, GOT) -#define GREATEST_ASSERT_EQ_FMT(EXP, GOT, FMT) \ +#define GREATEST_ASSERT_EQ_FMT(EXP, GOT, FMT) \ GREATEST_ASSERT_EQ_FMTm(#EXP " != " #GOT, EXP, GOT, FMT) -#define GREATEST_ASSERT_IN_RANGE(EXP, GOT, TOL) \ +#define GREATEST_ASSERT_IN_RANGE(EXP, GOT, TOL) \ GREATEST_ASSERT_IN_RANGEm(#EXP " != " #GOT " +/- " #TOL, EXP, GOT, TOL) -#define GREATEST_ASSERT_EQUAL_T(EXP, GOT, TYPE_INFO, UDATA) \ +#define GREATEST_ASSERT_EQUAL_T(EXP, GOT, TYPE_INFO, UDATA) \ GREATEST_ASSERT_EQUAL_Tm(#EXP " != " #GOT, EXP, GOT, TYPE_INFO, UDATA) -#define GREATEST_ASSERT_STR_EQ(EXP, GOT) \ +#define GREATEST_ASSERT_STR_EQ(EXP, GOT) \ GREATEST_ASSERT_STR_EQm(#EXP " != " #GOT, EXP, GOT) -#define GREATEST_ASSERT_STRN_EQ(EXP, GOT, SIZE) \ +#define GREATEST_ASSERT_STRN_EQ(EXP, GOT, SIZE) \ GREATEST_ASSERT_STRN_EQm(#EXP " != " #GOT, EXP, GOT, SIZE) -#define GREATEST_ASSERT_MEM_EQ(EXP, GOT, SIZE) \ +#define GREATEST_ASSERT_MEM_EQ(EXP, GOT, SIZE) \ GREATEST_ASSERT_MEM_EQm(#EXP " != " #GOT, EXP, GOT, SIZE) -#define GREATEST_ASSERT_ENUM_EQ(EXP, GOT, ENUM_STR) \ +#define GREATEST_ASSERT_ENUM_EQ(EXP, GOT, ENUM_STR) \ GREATEST_ASSERT_ENUM_EQm(#EXP " != " #GOT, EXP, GOT, ENUM_STR) /* The following forms take an additional message argument first, * to be displayed by the test runner. */ /* Fail if a condition is not true, with message. */ -#define GREATEST_ASSERTm(MSG, COND) \ - do { \ - greatest_info.assertions++; \ - if (!(COND)) { GREATEST_FAILm(MSG); } \ +#define GREATEST_ASSERTm(MSG, COND) \ + do { \ + greatest_info.assertions++; \ + if (!(COND)) { \ + GREATEST_FAILm(MSG); \ + } \ } while (0) /* Fail if a condition is not true, longjmping out of test. */ -#define GREATEST_ASSERT_OR_LONGJMPm(MSG, COND) \ - do { \ - greatest_info.assertions++; \ - if (!(COND)) { GREATEST_FAIL_WITH_LONGJMPm(MSG); } \ +#define GREATEST_ASSERT_OR_LONGJMPm(MSG, COND) \ + do { \ + greatest_info.assertions++; \ + if (!(COND)) { \ + GREATEST_FAIL_WITH_LONGJMPm(MSG); \ + } \ } while (0) /* Fail if a condition is not false, with message. */ -#define GREATEST_ASSERT_FALSEm(MSG, COND) \ - do { \ - greatest_info.assertions++; \ - if ((COND)) { GREATEST_FAILm(MSG); } \ +#define GREATEST_ASSERT_FALSEm(MSG, COND) \ + do { \ + greatest_info.assertions++; \ + if ((COND)) { \ + GREATEST_FAILm(MSG); \ + } \ } while (0) /* Internal macro for relational assertions */ -#define GREATEST__REL(REL, MSG, EXP, GOT) \ - do { \ - greatest_info.assertions++; \ - if (!((EXP) REL (GOT))) { GREATEST_FAILm(MSG); } \ +#define GREATEST__REL(REL, MSG, EXP, GOT) \ + do { \ + greatest_info.assertions++; \ + if (!((EXP)REL(GOT))) { \ + GREATEST_FAILm(MSG); \ + } \ } while (0) /* Fail if EXP is not ==, !=, >, <, >=, or <= to GOT. */ -#define GREATEST_ASSERT_EQm(MSG,E,G) GREATEST__REL(==, MSG,E,G) -#define GREATEST_ASSERT_NEQm(MSG,E,G) GREATEST__REL(!=, MSG,E,G) -#define GREATEST_ASSERT_GTm(MSG,E,G) GREATEST__REL(>, MSG,E,G) -#define GREATEST_ASSERT_GTEm(MSG,E,G) GREATEST__REL(>=, MSG,E,G) -#define GREATEST_ASSERT_LTm(MSG,E,G) GREATEST__REL(<, MSG,E,G) -#define GREATEST_ASSERT_LTEm(MSG,E,G) GREATEST__REL(<=, MSG,E,G) +#define GREATEST_ASSERT_EQm(MSG, E, G) GREATEST__REL(==, MSG, E, G) +#define GREATEST_ASSERT_NEQm(MSG, E, G) GREATEST__REL(!=, MSG, E, G) +#define GREATEST_ASSERT_GTm(MSG, E, G) GREATEST__REL(>, MSG, E, G) +#define GREATEST_ASSERT_GTEm(MSG, E, G) GREATEST__REL(>=, MSG, E, G) +#define GREATEST_ASSERT_LTm(MSG, E, G) GREATEST__REL(<, MSG, E, G) +#define GREATEST_ASSERT_LTEm(MSG, E, G) GREATEST__REL(<=, MSG, E, G) /* Fail if EXP != GOT (equality comparison by ==). * Warning: FMT, EXP, and GOT will be evaluated more * than once on failure. */ -#define GREATEST_ASSERT_EQ_FMTm(MSG, EXP, GOT, FMT) \ - do { \ - greatest_info.assertions++; \ - if ((EXP) != (GOT)) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\nExpected: "); \ - GREATEST_FPRINTF(GREATEST_STDOUT, FMT, EXP); \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\n Got: "); \ - GREATEST_FPRINTF(GREATEST_STDOUT, FMT, GOT); \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ - GREATEST_FAILm(MSG); \ - } \ +#define GREATEST_ASSERT_EQ_FMTm(MSG, EXP, GOT, FMT) \ + do { \ + greatest_info.assertions++; \ + if ((EXP) != (GOT)) { \ + GREATEST_FPRINTF(GREATEST_STDOUT, "\nExpected: "); \ + GREATEST_FPRINTF(GREATEST_STDOUT, FMT, EXP); \ + GREATEST_FPRINTF(GREATEST_STDOUT, "\n Got: "); \ + GREATEST_FPRINTF(GREATEST_STDOUT, FMT, GOT); \ + GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ + GREATEST_FAILm(MSG); \ + } \ } while (0) /* Fail if EXP is not equal to GOT, printing enum IDs. */ -#define GREATEST_ASSERT_ENUM_EQm(MSG, EXP, GOT, ENUM_STR) \ - do { \ - int greatest_EXP = (int)(EXP); \ - int greatest_GOT = (int)(GOT); \ - greatest_enum_str_fun *greatest_ENUM_STR = ENUM_STR; \ - if (greatest_EXP != greatest_GOT) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\nExpected: %s", \ - greatest_ENUM_STR(greatest_EXP)); \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\n Got: %s\n", \ - greatest_ENUM_STR(greatest_GOT)); \ - GREATEST_FAILm(MSG); \ - } \ - } while (0) \ +#define GREATEST_ASSERT_ENUM_EQm(MSG, EXP, GOT, ENUM_STR) \ + do { \ + int greatest_EXP = (int)(EXP); \ + int greatest_GOT = (int)(GOT); \ + greatest_enum_str_fun *greatest_ENUM_STR = ENUM_STR; \ + if (greatest_EXP != greatest_GOT) { \ + GREATEST_FPRINTF(GREATEST_STDOUT, \ + "\nExpected: %s", \ + greatest_ENUM_STR(greatest_EXP)); \ + GREATEST_FPRINTF(GREATEST_STDOUT, \ + "\n Got: %s\n", \ + greatest_ENUM_STR(greatest_GOT)); \ + GREATEST_FAILm(MSG); \ + } \ + } while (0) /* Fail if GOT not in range of EXP +|- TOL. */ -#define GREATEST_ASSERT_IN_RANGEm(MSG, EXP, GOT, TOL) \ - do { \ - GREATEST_FLOAT greatest_EXP = (EXP); \ - GREATEST_FLOAT greatest_GOT = (GOT); \ - GREATEST_FLOAT greatest_TOL = (TOL); \ - greatest_info.assertions++; \ - if ((greatest_EXP > greatest_GOT && \ - greatest_EXP - greatest_GOT > greatest_TOL) || \ - (greatest_EXP < greatest_GOT && \ - greatest_GOT - greatest_EXP > greatest_TOL)) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, \ - "\nExpected: " GREATEST_FLOAT_FMT \ - " +/- " GREATEST_FLOAT_FMT \ - "\n Got: " GREATEST_FLOAT_FMT \ - "\n", \ - greatest_EXP, greatest_TOL, greatest_GOT); \ - GREATEST_FAILm(MSG); \ - } \ +#define GREATEST_ASSERT_IN_RANGEm(MSG, EXP, GOT, TOL) \ + do { \ + GREATEST_FLOAT greatest_EXP = (EXP); \ + GREATEST_FLOAT greatest_GOT = (GOT); \ + GREATEST_FLOAT greatest_TOL = (TOL); \ + greatest_info.assertions++; \ + if ((greatest_EXP > greatest_GOT \ + && greatest_EXP - greatest_GOT > greatest_TOL) \ + || (greatest_EXP < greatest_GOT \ + && greatest_GOT - greatest_EXP > greatest_TOL)) { \ + GREATEST_FPRINTF(GREATEST_STDOUT, \ + "\nExpected: " GREATEST_FLOAT_FMT \ + " +/- " GREATEST_FLOAT_FMT \ + "\n Got: " GREATEST_FLOAT_FMT "\n", \ + greatest_EXP, \ + greatest_TOL, \ + greatest_GOT); \ + GREATEST_FAILm(MSG); \ + } \ } while (0) /* Fail if EXP is not equal to GOT, according to strcmp. */ -#define GREATEST_ASSERT_STR_EQm(MSG, EXP, GOT) \ - do { \ - GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT, \ - &greatest_type_info_string, NULL); \ - } while (0) \ +#define GREATEST_ASSERT_STR_EQm(MSG, EXP, GOT) \ + do { \ + GREATEST_ASSERT_EQUAL_Tm( \ + MSG, EXP, GOT, &greatest_type_info_string, NULL); \ + } while (0) /* Fail if EXP is not equal to GOT, according to strncmp. */ -#define GREATEST_ASSERT_STRN_EQm(MSG, EXP, GOT, SIZE) \ - do { \ - size_t size = SIZE; \ - GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT, \ - &greatest_type_info_string, &size); \ - } while (0) \ +#define GREATEST_ASSERT_STRN_EQm(MSG, EXP, GOT, SIZE) \ + do { \ + size_t size = SIZE; \ + GREATEST_ASSERT_EQUAL_Tm( \ + MSG, EXP, GOT, &greatest_type_info_string, &size); \ + } while (0) /* Fail if EXP is not equal to GOT, according to memcmp. */ -#define GREATEST_ASSERT_MEM_EQm(MSG, EXP, GOT, SIZE) \ - do { \ - greatest_memory_cmp_env env; \ - env.exp = (const unsigned char *)EXP; \ - env.got = (const unsigned char *)GOT; \ - env.size = SIZE; \ - GREATEST_ASSERT_EQUAL_Tm(MSG, env.exp, env.got, \ - &greatest_type_info_memory, &env); \ - } while (0) \ +#define GREATEST_ASSERT_MEM_EQm(MSG, EXP, GOT, SIZE) \ + do { \ + greatest_memory_cmp_env env; \ + env.exp = (const unsigned char *)EXP; \ + env.got = (const unsigned char *)GOT; \ + env.size = SIZE; \ + GREATEST_ASSERT_EQUAL_Tm( \ + MSG, env.exp, env.got, &greatest_type_info_memory, &env); \ + } while (0) /* Fail if EXP is not equal to GOT, according to a comparison * callback in TYPE_INFO. If they are not equal, optionally use a * print callback in TYPE_INFO to print them. */ -#define GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT, TYPE_INFO, UDATA) \ - do { \ - greatest_type_info *type_info = (TYPE_INFO); \ - greatest_info.assertions++; \ - if (!greatest_do_assert_equal_t(EXP, GOT, \ - type_info, UDATA)) { \ - if (type_info == NULL || type_info->equal == NULL) { \ - GREATEST_FAILm("type_info->equal callback missing!"); \ - } else { \ - GREATEST_FAILm(MSG); \ - } \ - } \ - } while (0) \ +#define GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT, TYPE_INFO, UDATA) \ + do { \ + greatest_type_info *type_info = (TYPE_INFO); \ + greatest_info.assertions++; \ + if (!greatest_do_assert_equal_t(EXP, GOT, type_info, UDATA)) { \ + if (type_info == NULL || type_info->equal == NULL) { \ + GREATEST_FAILm("type_info->equal callback missing!"); \ + } else { \ + GREATEST_FAILm(MSG); \ + } \ + } \ + } while (0) /* Pass. */ -#define GREATEST_PASSm(MSG) \ - do { \ - greatest_info.msg = MSG; \ - return GREATEST_TEST_RES_PASS; \ +#define GREATEST_PASSm(MSG) \ + do { \ + greatest_info.msg = MSG; \ + return GREATEST_TEST_RES_PASS; \ } while (0) /* Fail. */ -#define GREATEST_FAILm(MSG) \ - do { \ - greatest_info.fail_file = __FILE__; \ - greatest_info.fail_line = __LINE__; \ - greatest_info.msg = MSG; \ - if (GREATEST_ABORT_ON_FAIL()) { abort(); } \ - return GREATEST_TEST_RES_FAIL; \ +#define GREATEST_FAILm(MSG) \ + do { \ + greatest_info.fail_file = __FILE__; \ + greatest_info.fail_line = __LINE__; \ + greatest_info.msg = MSG; \ + if (GREATEST_ABORT_ON_FAIL()) { \ + abort(); \ + } \ + return GREATEST_TEST_RES_FAIL; \ } while (0) /* Optional GREATEST_FAILm variant that longjmps. */ #if GREATEST_USE_LONGJMP #define GREATEST_FAIL_WITH_LONGJMP() GREATEST_FAIL_WITH_LONGJMPm(NULL) -#define GREATEST_FAIL_WITH_LONGJMPm(MSG) \ - do { \ - greatest_info.fail_file = __FILE__; \ - greatest_info.fail_line = __LINE__; \ - greatest_info.msg = MSG; \ - longjmp(greatest_info.jump_dest, GREATEST_TEST_RES_FAIL); \ +#define GREATEST_FAIL_WITH_LONGJMPm(MSG) \ + do { \ + greatest_info.fail_file = __FILE__; \ + greatest_info.fail_line = __LINE__; \ + greatest_info.msg = MSG; \ + longjmp(greatest_info.jump_dest, GREATEST_TEST_RES_FAIL); \ } while (0) #endif /* Skip the current test. */ -#define GREATEST_SKIPm(MSG) \ - do { \ - greatest_info.msg = MSG; \ - return GREATEST_TEST_RES_SKIP; \ +#define GREATEST_SKIPm(MSG) \ + do { \ + greatest_info.msg = MSG; \ + return GREATEST_TEST_RES_SKIP; \ } while (0) /* Check the result of a subfunction using ASSERT, etc. */ -#define GREATEST_CHECK_CALL(RES) \ - do { \ - enum greatest_test_res greatest_RES = RES; \ - if (greatest_RES != GREATEST_TEST_RES_PASS) { \ - return greatest_RES; \ - } \ - } while (0) \ +#define GREATEST_CHECK_CALL(RES) \ + do { \ + enum greatest_test_res greatest_RES = RES; \ + if (greatest_RES != GREATEST_TEST_RES_PASS) { \ + return greatest_RES; \ + } \ + } while (0) #if GREATEST_USE_TIME -#define GREATEST_SET_TIME(NAME) \ - NAME = clock(); \ - if (NAME == (clock_t) -1) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, \ - "clock error: %s\n", #NAME); \ - exit(EXIT_FAILURE); \ +#define GREATEST_SET_TIME(NAME) \ + NAME = clock(); \ + if (NAME == (clock_t)-1) { \ + GREATEST_FPRINTF(GREATEST_STDOUT, "clock error: %s\n", #NAME); \ + exit(EXIT_FAILURE); \ } -#define GREATEST_CLOCK_DIFF(C1, C2) \ - GREATEST_FPRINTF(GREATEST_STDOUT, " (%lu ticks, %.3f sec)", \ - (long unsigned int) (C2) - (long unsigned int)(C1), \ - (double)((C2) - (C1)) / (1.0 * (double)CLOCKS_PER_SEC)) +#define GREATEST_CLOCK_DIFF(C1, C2) \ + GREATEST_FPRINTF(GREATEST_STDOUT, \ + " (%lu ticks, %.3f sec)", \ + (long unsigned int)(C2) - (long unsigned int)(C1), \ + (double)((C2) - (C1)) / (1.0 * (double)CLOCKS_PER_SEC)) #else #define GREATEST_SET_TIME(UNUSED) #define GREATEST_CLOCK_DIFF(UNUSED1, UNUSED2) #endif #if GREATEST_USE_LONGJMP -#define GREATEST_SAVE_CONTEXT() \ - /* setjmp returns 0 (GREATEST_TEST_RES_PASS) on first call * \ - * so the test runs, then RES_FAIL from FAIL_WITH_LONGJMP. */ \ - ((enum greatest_test_res)(setjmp(greatest_info.jump_dest))) +#define GREATEST_SAVE_CONTEXT() \ + /* setjmp returns 0 (GREATEST_TEST_RES_PASS) on first call * \ + * so the test runs, then RES_FAIL from FAIL_WITH_LONGJMP. */ \ + ((enum greatest_test_res)(setjmp(greatest_info.jump_dest))) #else -#define GREATEST_SAVE_CONTEXT() \ - /*a no-op, since setjmp/longjmp aren't being used */ \ +#define GREATEST_SAVE_CONTEXT() \ + /*a no-op, since setjmp/longjmp aren't being used */ \ GREATEST_TEST_RES_PASS #endif @@ -683,550 +698,642 @@ typedef enum greatest_test_res { * multiple times. */ #define GREATEST_SHUFFLE_SUITES(SD, BODY) GREATEST_SHUFFLE(0, SD, BODY) #define GREATEST_SHUFFLE_TESTS(SD, BODY) GREATEST_SHUFFLE(1, SD, BODY) -#define GREATEST_SHUFFLE(ID, SD, BODY) \ - do { \ - struct greatest_prng *prng = &greatest_info.prng[ID]; \ - greatest_prng_init_first_pass(ID); \ - do { \ - prng->count = 0; \ - if (prng->initialized) { greatest_prng_step(ID); } \ - BODY; \ - if (!prng->initialized) { \ - if (!greatest_prng_init_second_pass(ID, SD)) { break; } \ - } else if (prng->count_run == prng->count_ceil) { \ - break; \ - } \ - } while (!GREATEST_FAILURE_ABORT()); \ - prng->count_run = prng->random_order = prng->initialized = 0; \ - } while(0) +#define GREATEST_SHUFFLE(ID, SD, BODY) \ + do { \ + struct greatest_prng *prng = &greatest_info.prng[ID]; \ + greatest_prng_init_first_pass(ID); \ + do { \ + prng->count = 0; \ + if (prng->initialized) { \ + greatest_prng_step(ID); \ + } \ + BODY; \ + if (!prng->initialized) { \ + if (!greatest_prng_init_second_pass(ID, SD)) { \ + break; \ + } \ + } else if (prng->count_run == prng->count_ceil) { \ + break; \ + } \ + } while (!GREATEST_FAILURE_ABORT()); \ + prng->count_run = prng->random_order = prng->initialized = 0; \ + } while (0) /* Include several function definitions in the main test file. */ -#define GREATEST_MAIN_DEFS() \ - \ -/* Is FILTER a subset of NAME? */ \ -static int greatest_name_match(const char *name, const char *filter, \ - int res_if_none) { \ - size_t offset = 0; \ - size_t filter_len = filter ? strlen(filter) : 0; \ - if (filter_len == 0) { return res_if_none; } /* no filter */ \ - if (greatest_info.exact_name_match && strlen(name) != filter_len) { \ - return 0; /* ignore substring matches */ \ - } \ - while (name[offset] != '\0') { \ - if (name[offset] == filter[0]) { \ - if (0 == strncmp(&name[offset], filter, filter_len)) { \ - return 1; \ - } \ - } \ - offset++; \ - } \ - \ - return 0; \ -} \ - \ -static void greatest_buffer_test_name(const char *name) { \ - struct greatest_run_info *g = &greatest_info; \ - size_t len = strlen(name), size = sizeof(g->name_buf); \ - memset(g->name_buf, 0x00, size); \ - (void)strncat(g->name_buf, name, size - 1); \ - if (g->name_suffix && (len + 1 < size)) { \ - g->name_buf[len] = '_'; \ - strncat(&g->name_buf[len+1], g->name_suffix, size-(len+2)); \ - } \ -} \ - \ -/* Before running a test, check the name filtering and \ - * test shuffling state, if applicable, and then call setup hooks. */ \ -int greatest_test_pre(const char *name) { \ - struct greatest_run_info *g = &greatest_info; \ - int match; \ - greatest_buffer_test_name(name); \ - match = greatest_name_match(g->name_buf, g->test_filter, 1) && \ - !greatest_name_match(g->name_buf, g->test_exclude, 0); \ - if (GREATEST_LIST_ONLY()) { /* just listing test names */ \ - if (match) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, " %s\n", g->name_buf); \ - } \ - goto clear; \ - } \ - if (match && (!GREATEST_FIRST_FAIL() || g->suite.failed == 0)) { \ - struct greatest_prng *p = &g->prng[1]; \ - if (p->random_order) { \ - p->count++; \ - if (!p->initialized || ((p->count - 1) != p->state)) { \ - goto clear; /* don't run this test yet */ \ - } \ - } \ - if (g->running_test) { \ - fprintf(stderr, "Error: Test run inside another test.\n"); \ - return 0; \ - } \ - GREATEST_SET_TIME(g->suite.pre_test); \ - if (g->setup) { g->setup(g->setup_udata); } \ - p->count_run++; \ - g->running_test = 1; \ - return 1; /* test should be run */ \ - } else { \ - goto clear; /* skipped */ \ - } \ -clear: \ - g->name_suffix = NULL; \ - return 0; \ -} \ - \ -static void greatest_do_pass(void) { \ - struct greatest_run_info *g = &greatest_info; \ - if (GREATEST_IS_VERBOSE()) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, "PASS %s: %s", \ - g->name_buf, g->msg ? g->msg : ""); \ - } else { \ - GREATEST_FPRINTF(GREATEST_STDOUT, "."); \ - } \ - g->suite.passed++; \ -} \ - \ -static void greatest_do_fail(void) { \ - struct greatest_run_info *g = &greatest_info; \ - if (GREATEST_IS_VERBOSE()) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, \ - "FAIL %s: %s (%s:%u)", g->name_buf, \ - g->msg ? g->msg : "", g->fail_file, g->fail_line); \ - } else { \ - GREATEST_FPRINTF(GREATEST_STDOUT, "F"); \ - g->col++; /* add linebreak if in line of '.'s */ \ - if (g->col != 0) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ - g->col = 0; \ - } \ - GREATEST_FPRINTF(GREATEST_STDOUT, "FAIL %s: %s (%s:%u)\n", \ - g->name_buf, g->msg ? g->msg : "", \ - g->fail_file, g->fail_line); \ - } \ - g->suite.failed++; \ -} \ - \ -static void greatest_do_skip(void) { \ - struct greatest_run_info *g = &greatest_info; \ - if (GREATEST_IS_VERBOSE()) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, "SKIP %s: %s", \ - g->name_buf, g->msg ? g->msg : ""); \ - } else { \ - GREATEST_FPRINTF(GREATEST_STDOUT, "s"); \ - } \ - g->suite.skipped++; \ -} \ - \ -void greatest_test_post(int res) { \ - GREATEST_SET_TIME(greatest_info.suite.post_test); \ - if (greatest_info.teardown) { \ - void *udata = greatest_info.teardown_udata; \ - greatest_info.teardown(udata); \ - } \ - \ - greatest_info.running_test = 0; \ - if (res <= GREATEST_TEST_RES_FAIL) { \ - greatest_do_fail(); \ - } else if (res >= GREATEST_TEST_RES_SKIP) { \ - greatest_do_skip(); \ - } else if (res == GREATEST_TEST_RES_PASS) { \ - greatest_do_pass(); \ - } \ - greatest_info.name_suffix = NULL; \ - greatest_info.suite.tests_run++; \ - greatest_info.col++; \ - if (GREATEST_IS_VERBOSE()) { \ - GREATEST_CLOCK_DIFF(greatest_info.suite.pre_test, \ - greatest_info.suite.post_test); \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ - } else if (greatest_info.col % greatest_info.width == 0) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ - greatest_info.col = 0; \ - } \ - fflush(GREATEST_STDOUT); \ -} \ - \ -static void report_suite(void) { \ - if (greatest_info.suite.tests_run > 0) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, \ - "\n%u test%s - %u passed, %u failed, %u skipped", \ - greatest_info.suite.tests_run, \ - greatest_info.suite.tests_run == 1 ? "" : "s", \ - greatest_info.suite.passed, \ - greatest_info.suite.failed, \ - greatest_info.suite.skipped); \ - GREATEST_CLOCK_DIFF(greatest_info.suite.pre_suite, \ - greatest_info.suite.post_suite); \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ - } \ -} \ - \ -static void update_counts_and_reset_suite(void) { \ - greatest_info.setup = NULL; \ - greatest_info.setup_udata = NULL; \ - greatest_info.teardown = NULL; \ - greatest_info.teardown_udata = NULL; \ - greatest_info.passed += greatest_info.suite.passed; \ - greatest_info.failed += greatest_info.suite.failed; \ - greatest_info.skipped += greatest_info.suite.skipped; \ - greatest_info.tests_run += greatest_info.suite.tests_run; \ - memset(&greatest_info.suite, 0, sizeof(greatest_info.suite)); \ - greatest_info.col = 0; \ -} \ - \ -static int greatest_suite_pre(const char *suite_name) { \ - struct greatest_prng *p = &greatest_info.prng[0]; \ - if (!greatest_name_match(suite_name, greatest_info.suite_filter, 1) \ - || (GREATEST_FAILURE_ABORT())) { return 0; } \ - if (p->random_order) { \ - p->count++; \ - if (!p->initialized || ((p->count - 1) != p->state)) { \ - return 0; /* don't run this suite yet */ \ - } \ - } \ - p->count_run++; \ - update_counts_and_reset_suite(); \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\n* Suite %s:\n", suite_name); \ - GREATEST_SET_TIME(greatest_info.suite.pre_suite); \ - return 1; \ -} \ - \ -static void greatest_suite_post(void) { \ - GREATEST_SET_TIME(greatest_info.suite.post_suite); \ - report_suite(); \ -} \ - \ -static void greatest_run_suite(greatest_suite_cb *suite_cb, \ - const char *suite_name) { \ - if (greatest_suite_pre(suite_name)) { \ - suite_cb(); \ - greatest_suite_post(); \ - } \ -} \ - \ -int greatest_do_assert_equal_t(const void *expd, const void *got, \ - greatest_type_info *type_info, void *udata) { \ - int eq = 0; \ - if (type_info == NULL || type_info->equal == NULL) { return 0; } \ - eq = type_info->equal(expd, got, udata); \ - if (!eq) { \ - if (type_info->print != NULL) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\nExpected: "); \ - (void)type_info->print(expd, udata); \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\n Got: "); \ - (void)type_info->print(got, udata); \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ - } \ - } \ - return eq; \ -} \ - \ -static void greatest_usage(const char *name) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, \ - "Usage: %s [-hlfavex] [-s SUITE] [-t TEST] [-x EXCLUDE]\n" \ - " -h, --help print this Help\n" \ - " -l List suites and tests, then exit (dry run)\n" \ - " -f Stop runner after first failure\n" \ - " -a Abort on first failure (implies -f)\n" \ - " -v Verbose output\n" \ - " -s SUITE only run suites containing substring SUITE\n" \ - " -t TEST only run tests containing substring TEST\n" \ - " -e only run exact name match for -s or -t\n" \ - " -x EXCLUDE exclude tests containing substring EXCLUDE\n", \ - name); \ -} \ - \ -static void greatest_parse_options(int argc, char **argv) { \ - int i = 0; \ - for (i = 1; i < argc; i++) { \ - if (argv[i][0] == '-') { \ - char f = argv[i][1]; \ - if ((f == 's' || f == 't' || f == 'x') && argc <= i + 1) { \ - greatest_usage(argv[0]); exit(EXIT_FAILURE); \ - } \ - switch (f) { \ - case 's': /* suite name filter */ \ - greatest_set_suite_filter(argv[i + 1]); i++; break; \ - case 't': /* test name filter */ \ - greatest_set_test_filter(argv[i + 1]); i++; break; \ - case 'x': /* test name exclusion */ \ - greatest_set_test_exclude(argv[i + 1]); i++; break; \ - case 'e': /* exact name match */ \ - greatest_set_exact_name_match(); break; \ - case 'f': /* first fail flag */ \ - greatest_stop_at_first_fail(); break; \ - case 'a': /* abort() on fail flag */ \ - greatest_abort_on_fail(); break; \ - case 'l': /* list only (dry run) */ \ - greatest_list_only(); break; \ - case 'v': /* first fail flag */ \ - greatest_info.verbosity++; break; \ - case 'h': /* help */ \ - greatest_usage(argv[0]); exit(EXIT_SUCCESS); \ - default: \ - case '-': \ - if (0 == strncmp("--help", argv[i], 6)) { \ - greatest_usage(argv[0]); exit(EXIT_SUCCESS); \ - } else if (0 == strcmp("--", argv[i])) { \ - return; /* ignore following arguments */ \ - } \ - GREATEST_FPRINTF(GREATEST_STDOUT, \ - "Unknown argument '%s'\n", argv[i]); \ - greatest_usage(argv[0]); \ - exit(EXIT_FAILURE); \ - } \ - } \ - } \ -} \ - \ -int greatest_all_passed(void) { return (greatest_info.failed == 0); } \ - \ -void greatest_set_test_filter(const char *filter) { \ - greatest_info.test_filter = filter; \ -} \ - \ -void greatest_set_test_exclude(const char *filter) { \ - greatest_info.test_exclude = filter; \ -} \ - \ -void greatest_set_suite_filter(const char *filter) { \ - greatest_info.suite_filter = filter; \ -} \ - \ -void greatest_set_exact_name_match(void) { \ - greatest_info.exact_name_match = 1; \ -} \ - \ -void greatest_stop_at_first_fail(void) { \ - greatest_set_flag(GREATEST_FLAG_FIRST_FAIL); \ -} \ - \ -void greatest_abort_on_fail(void) { \ - greatest_set_flag(GREATEST_FLAG_ABORT_ON_FAIL); \ -} \ - \ -void greatest_list_only(void) { \ - greatest_set_flag(GREATEST_FLAG_LIST_ONLY); \ -} \ - \ -void greatest_get_report(struct greatest_report_t *report) { \ - if (report) { \ - report->passed = greatest_info.passed; \ - report->failed = greatest_info.failed; \ - report->skipped = greatest_info.skipped; \ - report->assertions = greatest_info.assertions; \ - } \ -} \ - \ -unsigned int greatest_get_verbosity(void) { \ - return greatest_info.verbosity; \ -} \ - \ -void greatest_set_verbosity(unsigned int verbosity) { \ - greatest_info.verbosity = (unsigned char)verbosity; \ -} \ - \ -void greatest_set_flag(greatest_flag_t flag) { \ - greatest_info.flags = (unsigned char)(greatest_info.flags | flag); \ -} \ - \ -void greatest_set_test_suffix(const char *suffix) { \ - greatest_info.name_suffix = suffix; \ -} \ - \ -void GREATEST_SET_SETUP_CB(greatest_setup_cb *cb, void *udata) { \ - greatest_info.setup = cb; \ - greatest_info.setup_udata = udata; \ -} \ - \ -void GREATEST_SET_TEARDOWN_CB(greatest_teardown_cb *cb, void *udata) { \ - greatest_info.teardown = cb; \ - greatest_info.teardown_udata = udata; \ -} \ - \ -static int greatest_string_equal_cb(const void *expd, const void *got, \ - void *udata) { \ - size_t *size = (size_t *)udata; \ - return (size != NULL \ - ? (0 == strncmp((const char *)expd, (const char *)got, *size)) \ - : (0 == strcmp((const char *)expd, (const char *)got))); \ -} \ - \ -static int greatest_string_printf_cb(const void *t, void *udata) { \ - (void)udata; /* note: does not check \0 termination. */ \ - return GREATEST_FPRINTF(GREATEST_STDOUT, "%s", (const char *)t); \ -} \ - \ -greatest_type_info greatest_type_info_string = { \ - greatest_string_equal_cb, greatest_string_printf_cb, \ -}; \ - \ -static int greatest_memory_equal_cb(const void *expd, const void *got, \ - void *udata) { \ - greatest_memory_cmp_env *env = (greatest_memory_cmp_env *)udata; \ - return (0 == memcmp(expd, got, env->size)); \ -} \ - \ -/* Hexdump raw memory, with differences highlighted */ \ -static int greatest_memory_printf_cb(const void *t, void *udata) { \ - greatest_memory_cmp_env *env = (greatest_memory_cmp_env *)udata; \ - const unsigned char *buf = (const unsigned char *)t; \ - unsigned char diff_mark = ' '; \ - FILE *out = GREATEST_STDOUT; \ - size_t i, line_i, line_len = 0; \ - int len = 0; /* format hexdump with differences highlighted */ \ - for (i = 0; i < env->size; i+= line_len) { \ - diff_mark = ' '; \ - line_len = env->size - i; \ - if (line_len > 16) { line_len = 16; } \ - for (line_i = i; line_i < i + line_len; line_i++) { \ - if (env->exp[line_i] != env->got[line_i]) diff_mark = 'X'; \ - } \ - len += GREATEST_FPRINTF(out, "\n%04x %c ", \ - (unsigned int)i, diff_mark); \ - for (line_i = i; line_i < i + line_len; line_i++) { \ - int m = env->exp[line_i] == env->got[line_i]; /* match? */ \ - len += GREATEST_FPRINTF(out, "%02x%c", \ - buf[line_i], m ? ' ' : '<'); \ - } \ - for (line_i = 0; line_i < 16 - line_len; line_i++) { \ - len += GREATEST_FPRINTF(out, " "); \ - } \ - GREATEST_FPRINTF(out, " "); \ - for (line_i = i; line_i < i + line_len; line_i++) { \ - unsigned char c = buf[line_i]; \ - len += GREATEST_FPRINTF(out, "%c", isprint(c) ? c : '.'); \ - } \ - } \ - len += GREATEST_FPRINTF(out, "\n"); \ - return len; \ -} \ - \ -void greatest_prng_init_first_pass(int id) { \ - greatest_info.prng[id].random_order = 1; \ - greatest_info.prng[id].count_run = 0; \ -} \ - \ -int greatest_prng_init_second_pass(int id, unsigned long seed) { \ - struct greatest_prng *p = &greatest_info.prng[id]; \ - if (p->count == 0) { return 0; } \ - p->count_ceil = p->count; \ - for (p->m = 1; p->m < p->count; p->m <<= 1) {} \ - p->state = seed & 0x1fffffff; /* only use lower 29 bits */ \ - p->a = 4LU * p->state; /* to avoid overflow when */ \ - p->a = (p->a ? p->a : 4) | 1; /* multiplied by 4 */ \ - p->c = 2147483647; /* and so p->c ((2 ** 31) - 1) is */ \ - p->initialized = 1; /* always relatively prime to p->a. */ \ - fprintf(stderr, "init_second_pass: a %lu, c %lu, state %lu\n", \ - p->a, p->c, p->state); \ - return 1; \ -} \ - \ -/* Step the pseudorandom number generator until its state reaches \ - * another test ID between 0 and the test count. \ - * This use a linear congruential pseudorandom number generator, \ - * with the power-of-two ceiling of the test count as the modulus, the \ - * masked seed as the multiplier, and a prime as the increment. For \ - * each generated value < the test count, run the corresponding test. \ - * This will visit all IDs 0 <= X < mod once before repeating, \ - * with a starting position chosen based on the initial seed. \ - * For details, see: Knuth, The Art of Computer Programming \ - * Volume. 2, section 3.2.1. */ \ -void greatest_prng_step(int id) { \ - struct greatest_prng *p = &greatest_info.prng[id]; \ - do { \ - p->state = ((p->a * p->state) + p->c) & (p->m - 1); \ - } while (p->state >= p->count_ceil); \ -} \ - \ -void GREATEST_INIT(void) { \ - /* Suppress unused function warning if features aren't used */ \ - (void)greatest_run_suite; \ - (void)greatest_parse_options; \ - (void)greatest_prng_step; \ - (void)greatest_prng_init_first_pass; \ - (void)greatest_prng_init_second_pass; \ - (void)greatest_set_test_suffix; \ - \ - memset(&greatest_info, 0, sizeof(greatest_info)); \ - greatest_info.width = GREATEST_DEFAULT_WIDTH; \ - GREATEST_SET_TIME(greatest_info.begin); \ -} \ - \ -/* Report passes, failures, skipped tests, the number of \ - * assertions, and the overall run time. */ \ -void GREATEST_PRINT_REPORT(void) { \ - if (!GREATEST_LIST_ONLY()) { \ - update_counts_and_reset_suite(); \ - GREATEST_SET_TIME(greatest_info.end); \ - GREATEST_FPRINTF(GREATEST_STDOUT, \ - "\nTotal: %u test%s", \ - greatest_info.tests_run, \ - greatest_info.tests_run == 1 ? "" : "s"); \ - GREATEST_CLOCK_DIFF(greatest_info.begin, \ - greatest_info.end); \ - GREATEST_FPRINTF(GREATEST_STDOUT, ", %u assertion%s\n", \ - greatest_info.assertions, \ - greatest_info.assertions == 1 ? "" : "s"); \ - GREATEST_FPRINTF(GREATEST_STDOUT, \ - "Pass: %u, fail: %u, skip: %u.\n", \ - greatest_info.passed, \ - greatest_info.failed, greatest_info.skipped); \ - } \ -} \ - \ -greatest_type_info greatest_type_info_memory = { \ - greatest_memory_equal_cb, greatest_memory_printf_cb, \ -}; \ - \ -greatest_run_info greatest_info +#define GREATEST_MAIN_DEFS() \ + \ + /* Is FILTER a subset of NAME? */ \ + static int greatest_name_match( \ + const char *name, const char *filter, int res_if_none) \ + { \ + size_t offset = 0; \ + size_t filter_len = filter ? strlen(filter) : 0; \ + if (filter_len == 0) { \ + return res_if_none; \ + } /* no filter */ \ + if (greatest_info.exact_name_match && strlen(name) != filter_len) { \ + return 0; /* ignore substring matches */ \ + } \ + while (name[offset] != '\0') { \ + if (name[offset] == filter[0]) { \ + if (0 == strncmp(&name[offset], filter, filter_len)) { \ + return 1; \ + } \ + } \ + offset++; \ + } \ + \ + return 0; \ + } \ + \ + static void greatest_buffer_test_name(const char *name) \ + { \ + struct greatest_run_info *g = &greatest_info; \ + size_t len = strlen(name), size = sizeof(g->name_buf); \ + memset(g->name_buf, 0x00, size); \ + (void)strncat(g->name_buf, name, size - 1); \ + if (g->name_suffix && (len + 1 < size)) { \ + g->name_buf[len] = '_'; \ + strncat(&g->name_buf[len + 1], g->name_suffix, size - (len + 2)); \ + } \ + } \ + \ + /* Before running a test, check the name filtering and \ + * test shuffling state, if applicable, and then call setup hooks. */ \ + int greatest_test_pre(const char *name) \ + { \ + struct greatest_run_info *g = &greatest_info; \ + int match; \ + greatest_buffer_test_name(name); \ + match = greatest_name_match(g->name_buf, g->test_filter, 1) \ + && !greatest_name_match(g->name_buf, g->test_exclude, 0); \ + if (GREATEST_LIST_ONLY()) { /* just listing test names */ \ + if (match) { \ + GREATEST_FPRINTF(GREATEST_STDOUT, " %s\n", g->name_buf); \ + } \ + goto clear; \ + } \ + if (match && (!GREATEST_FIRST_FAIL() || g->suite.failed == 0)) { \ + struct greatest_prng *p = &g->prng[1]; \ + if (p->random_order) { \ + p->count++; \ + if (!p->initialized || ((p->count - 1) != p->state)) { \ + goto clear; /* don't run this test yet */ \ + } \ + } \ + if (g->running_test) { \ + fprintf(stderr, "Error: Test run inside another test.\n"); \ + return 0; \ + } \ + GREATEST_SET_TIME(g->suite.pre_test); \ + if (g->setup) { \ + g->setup(g->setup_udata); \ + } \ + p->count_run++; \ + g->running_test = 1; \ + return 1; /* test should be run */ \ + } else { \ + goto clear; /* skipped */ \ + } \ + clear: \ + g->name_suffix = NULL; \ + return 0; \ + } \ + \ + static void greatest_do_pass(void) \ + { \ + struct greatest_run_info *g = &greatest_info; \ + if (GREATEST_IS_VERBOSE()) { \ + GREATEST_FPRINTF(GREATEST_STDOUT, \ + "PASS %s: %s", \ + g->name_buf, \ + g->msg ? g->msg : ""); \ + } else { \ + GREATEST_FPRINTF(GREATEST_STDOUT, "."); \ + } \ + g->suite.passed++; \ + } \ + \ + static void greatest_do_fail(void) \ + { \ + struct greatest_run_info *g = &greatest_info; \ + if (GREATEST_IS_VERBOSE()) { \ + GREATEST_FPRINTF(GREATEST_STDOUT, \ + "FAIL %s: %s (%s:%u)", \ + g->name_buf, \ + g->msg ? g->msg : "", \ + g->fail_file, \ + g->fail_line); \ + } else { \ + GREATEST_FPRINTF(GREATEST_STDOUT, "F"); \ + g->col++; /* add linebreak if in line of '.'s */ \ + if (g->col != 0) { \ + GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ + g->col = 0; \ + } \ + GREATEST_FPRINTF(GREATEST_STDOUT, \ + "FAIL %s: %s (%s:%u)\n", \ + g->name_buf, \ + g->msg ? g->msg : "", \ + g->fail_file, \ + g->fail_line); \ + } \ + g->suite.failed++; \ + } \ + \ + static void greatest_do_skip(void) \ + { \ + struct greatest_run_info *g = &greatest_info; \ + if (GREATEST_IS_VERBOSE()) { \ + GREATEST_FPRINTF(GREATEST_STDOUT, \ + "SKIP %s: %s", \ + g->name_buf, \ + g->msg ? g->msg : ""); \ + } else { \ + GREATEST_FPRINTF(GREATEST_STDOUT, "s"); \ + } \ + g->suite.skipped++; \ + } \ + \ + void greatest_test_post(int res) \ + { \ + GREATEST_SET_TIME(greatest_info.suite.post_test); \ + if (greatest_info.teardown) { \ + void *udata = greatest_info.teardown_udata; \ + greatest_info.teardown(udata); \ + } \ + \ + greatest_info.running_test = 0; \ + if (res <= GREATEST_TEST_RES_FAIL) { \ + greatest_do_fail(); \ + } else if (res >= GREATEST_TEST_RES_SKIP) { \ + greatest_do_skip(); \ + } else if (res == GREATEST_TEST_RES_PASS) { \ + greatest_do_pass(); \ + } \ + greatest_info.name_suffix = NULL; \ + greatest_info.suite.tests_run++; \ + greatest_info.col++; \ + if (GREATEST_IS_VERBOSE()) { \ + GREATEST_CLOCK_DIFF(greatest_info.suite.pre_test, \ + greatest_info.suite.post_test); \ + GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ + } else if (greatest_info.col % greatest_info.width == 0) { \ + GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ + greatest_info.col = 0; \ + } \ + fflush(GREATEST_STDOUT); \ + } \ + \ + static void report_suite(void) \ + { \ + if (greatest_info.suite.tests_run > 0) { \ + GREATEST_FPRINTF(GREATEST_STDOUT, \ + "\n%u test%s - %u passed, %u failed, %u skipped", \ + greatest_info.suite.tests_run, \ + greatest_info.suite.tests_run == 1 ? "" : "s", \ + greatest_info.suite.passed, \ + greatest_info.suite.failed, \ + greatest_info.suite.skipped); \ + GREATEST_CLOCK_DIFF(greatest_info.suite.pre_suite, \ + greatest_info.suite.post_suite); \ + GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ + } \ + } \ + \ + static void update_counts_and_reset_suite(void) \ + { \ + greatest_info.setup = NULL; \ + greatest_info.setup_udata = NULL; \ + greatest_info.teardown = NULL; \ + greatest_info.teardown_udata = NULL; \ + greatest_info.passed += greatest_info.suite.passed; \ + greatest_info.failed += greatest_info.suite.failed; \ + greatest_info.skipped += greatest_info.suite.skipped; \ + greatest_info.tests_run += greatest_info.suite.tests_run; \ + memset(&greatest_info.suite, 0, sizeof(greatest_info.suite)); \ + greatest_info.col = 0; \ + } \ + \ + static int greatest_suite_pre(const char *suite_name) \ + { \ + struct greatest_prng *p = &greatest_info.prng[0]; \ + if (!greatest_name_match(suite_name, greatest_info.suite_filter, 1) \ + || (GREATEST_FAILURE_ABORT())) { \ + return 0; \ + } \ + if (p->random_order) { \ + p->count++; \ + if (!p->initialized || ((p->count - 1) != p->state)) { \ + return 0; /* don't run this suite yet */ \ + } \ + } \ + p->count_run++; \ + update_counts_and_reset_suite(); \ + GREATEST_FPRINTF(GREATEST_STDOUT, "\n* Suite %s:\n", suite_name); \ + GREATEST_SET_TIME(greatest_info.suite.pre_suite); \ + return 1; \ + } \ + \ + static void greatest_suite_post(void) \ + { \ + GREATEST_SET_TIME(greatest_info.suite.post_suite); \ + report_suite(); \ + } \ + \ + static void greatest_run_suite(greatest_suite_cb *suite_cb, \ + const char *suite_name) \ + { \ + if (greatest_suite_pre(suite_name)) { \ + suite_cb(); \ + greatest_suite_post(); \ + } \ + } \ + \ + int greatest_do_assert_equal_t(const void *expd, \ + const void *got, \ + greatest_type_info *type_info, \ + void *udata) \ + { \ + int eq = 0; \ + if (type_info == NULL || type_info->equal == NULL) { \ + return 0; \ + } \ + eq = type_info->equal(expd, got, udata); \ + if (!eq) { \ + if (type_info->print != NULL) { \ + GREATEST_FPRINTF(GREATEST_STDOUT, "\nExpected: "); \ + (void)type_info->print(expd, udata); \ + GREATEST_FPRINTF(GREATEST_STDOUT, "\n Got: "); \ + (void)type_info->print(got, udata); \ + GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ + } \ + } \ + return eq; \ + } \ + \ + static void greatest_usage(const char *name) \ + { \ + GREATEST_FPRINTF( \ + GREATEST_STDOUT, \ + "Usage: %s [-hlfavex] [-s SUITE] [-t TEST] [-x EXCLUDE]\n" \ + " -h, --help print this Help\n" \ + " -l List suites and tests, then exit (dry run)\n" \ + " -f Stop runner after first failure\n" \ + " -a Abort on first failure (implies -f)\n" \ + " -v Verbose output\n" \ + " -s SUITE only run suites containing substring SUITE\n" \ + " -t TEST only run tests containing substring TEST\n" \ + " -e only run exact name match for -s or -t\n" \ + " -x EXCLUDE exclude tests containing substring EXCLUDE\n", \ + name); \ + } \ + \ + static void greatest_parse_options(int argc, char **argv) \ + { \ + int i = 0; \ + for (i = 1; i < argc; i++) { \ + if (argv[i][0] == '-') { \ + char f = argv[i][1]; \ + if ((f == 's' || f == 't' || f == 'x') && argc <= i + 1) { \ + greatest_usage(argv[0]); \ + exit(EXIT_FAILURE); \ + } \ + switch (f) { \ + case 's': /* suite name filter */ \ + greatest_set_suite_filter(argv[i + 1]); \ + i++; \ + break; \ + case 't': /* test name filter */ \ + greatest_set_test_filter(argv[i + 1]); \ + i++; \ + break; \ + case 'x': /* test name exclusion */ \ + greatest_set_test_exclude(argv[i + 1]); \ + i++; \ + break; \ + case 'e': /* exact name match */ \ + greatest_set_exact_name_match(); \ + break; \ + case 'f': /* first fail flag */ \ + greatest_stop_at_first_fail(); \ + break; \ + case 'a': /* abort() on fail flag */ \ + greatest_abort_on_fail(); \ + break; \ + case 'l': /* list only (dry run) */ greatest_list_only(); \ + break; \ + case 'v': /* first fail flag */ \ + greatest_info.verbosity++; \ + break; \ + case 'h': /* help */ \ + greatest_usage(argv[0]); \ + exit(EXIT_SUCCESS); \ + default: \ + case '-': \ + if (0 == strncmp("--help", argv[i], 6)) { \ + greatest_usage(argv[0]); \ + exit(EXIT_SUCCESS); \ + } else if (0 == strcmp("--", argv[i])) { \ + return; /* ignore following arguments */ \ + } \ + GREATEST_FPRINTF( \ + GREATEST_STDOUT, "Unknown argument '%s'\n", argv[i]); \ + greatest_usage(argv[0]); \ + exit(EXIT_FAILURE); \ + } \ + } \ + } \ + } \ + \ + int greatest_all_passed(void) \ + { \ + return (greatest_info.failed == 0); \ + } \ + \ + void greatest_set_test_filter(const char *filter) \ + { \ + greatest_info.test_filter = filter; \ + } \ + \ + void greatest_set_test_exclude(const char *filter) \ + { \ + greatest_info.test_exclude = filter; \ + } \ + \ + void greatest_set_suite_filter(const char *filter) \ + { \ + greatest_info.suite_filter = filter; \ + } \ + \ + void greatest_set_exact_name_match(void) \ + { \ + greatest_info.exact_name_match = 1; \ + } \ + \ + void greatest_stop_at_first_fail(void) \ + { \ + greatest_set_flag(GREATEST_FLAG_FIRST_FAIL); \ + } \ + \ + void greatest_abort_on_fail(void) \ + { \ + greatest_set_flag(GREATEST_FLAG_ABORT_ON_FAIL); \ + } \ + \ + void greatest_list_only(void) \ + { \ + greatest_set_flag(GREATEST_FLAG_LIST_ONLY); \ + } \ + \ + void greatest_get_report(struct greatest_report_t *report) \ + { \ + if (report) { \ + report->passed = greatest_info.passed; \ + report->failed = greatest_info.failed; \ + report->skipped = greatest_info.skipped; \ + report->assertions = greatest_info.assertions; \ + } \ + } \ + \ + unsigned int greatest_get_verbosity(void) \ + { \ + return greatest_info.verbosity; \ + } \ + \ + void greatest_set_verbosity(unsigned int verbosity) \ + { \ + greatest_info.verbosity = (unsigned char)verbosity; \ + } \ + \ + void greatest_set_flag(greatest_flag_t flag) \ + { \ + greatest_info.flags = (unsigned char)(greatest_info.flags | flag); \ + } \ + \ + void greatest_set_test_suffix(const char *suffix) \ + { \ + greatest_info.name_suffix = suffix; \ + } \ + \ + void GREATEST_SET_SETUP_CB(greatest_setup_cb *cb, void *udata) \ + { \ + greatest_info.setup = cb; \ + greatest_info.setup_udata = udata; \ + } \ + \ + void GREATEST_SET_TEARDOWN_CB(greatest_teardown_cb *cb, void *udata) \ + { \ + greatest_info.teardown = cb; \ + greatest_info.teardown_udata = udata; \ + } \ + \ + static int greatest_string_equal_cb( \ + const void *expd, const void *got, void *udata) \ + { \ + size_t *size = (size_t *)udata; \ + return ( \ + size != NULL \ + ? (0 == strncmp((const char *)expd, (const char *)got, *size)) \ + : (0 == strcmp((const char *)expd, (const char *)got))); \ + } \ + \ + static int greatest_string_printf_cb(const void *t, void *udata) \ + { \ + (void)udata; /* note: does not check \0 termination. */ \ + return GREATEST_FPRINTF(GREATEST_STDOUT, "%s", (const char *)t); \ + } \ + \ + greatest_type_info greatest_type_info_string = { \ + greatest_string_equal_cb, \ + greatest_string_printf_cb, \ + }; \ + \ + static int greatest_memory_equal_cb( \ + const void *expd, const void *got, void *udata) \ + { \ + greatest_memory_cmp_env *env = (greatest_memory_cmp_env *)udata; \ + return (0 == memcmp(expd, got, env->size)); \ + } \ + \ + /* Hexdump raw memory, with differences highlighted */ \ + static int greatest_memory_printf_cb(const void *t, void *udata) \ + { \ + greatest_memory_cmp_env *env = (greatest_memory_cmp_env *)udata; \ + const unsigned char *buf = (const unsigned char *)t; \ + unsigned char diff_mark = ' '; \ + FILE *out = GREATEST_STDOUT; \ + size_t i, line_i, line_len = 0; \ + int len = 0; /* format hexdump with differences highlighted */ \ + for (i = 0; i < env->size; i += line_len) { \ + diff_mark = ' '; \ + line_len = env->size - i; \ + if (line_len > 16) { \ + line_len = 16; \ + } \ + for (line_i = i; line_i < i + line_len; line_i++) { \ + if (env->exp[line_i] != env->got[line_i]) \ + diff_mark = 'X'; \ + } \ + len += GREATEST_FPRINTF( \ + out, "\n%04x %c ", (unsigned int)i, diff_mark); \ + for (line_i = i; line_i < i + line_len; line_i++) { \ + int m = env->exp[line_i] == env->got[line_i]; /* match? */ \ + len += GREATEST_FPRINTF( \ + out, "%02x%c", buf[line_i], m ? ' ' : '<'); \ + } \ + for (line_i = 0; line_i < 16 - line_len; line_i++) { \ + len += GREATEST_FPRINTF(out, " "); \ + } \ + GREATEST_FPRINTF(out, " "); \ + for (line_i = i; line_i < i + line_len; line_i++) { \ + unsigned char c = buf[line_i]; \ + len += GREATEST_FPRINTF(out, "%c", isprint(c) ? c : '.'); \ + } \ + } \ + len += GREATEST_FPRINTF(out, "\n"); \ + return len; \ + } \ + \ + void greatest_prng_init_first_pass(int id) \ + { \ + greatest_info.prng[id].random_order = 1; \ + greatest_info.prng[id].count_run = 0; \ + } \ + \ + int greatest_prng_init_second_pass(int id, unsigned long seed) \ + { \ + struct greatest_prng *p = &greatest_info.prng[id]; \ + if (p->count == 0) { \ + return 0; \ + } \ + p->count_ceil = p->count; \ + for (p->m = 1; p->m < p->count; p->m <<= 1) { \ + } \ + p->state = seed & 0x1fffffff; /* only use lower 29 bits */ \ + p->a = 4LU * p->state; /* to avoid overflow when */ \ + p->a = (p->a ? p->a : 4) | 1; /* multiplied by 4 */ \ + p->c = 2147483647; /* and so p->c ((2 ** 31) - 1) is */ \ + p->initialized = 1; /* always relatively prime to p->a. */ \ + fprintf(stderr, \ + "init_second_pass: a %lu, c %lu, state %lu\n", \ + p->a, \ + p->c, \ + p->state); \ + return 1; \ + } \ + \ + /* Step the pseudorandom number generator until its state reaches \ + * another test ID between 0 and the test count. \ + * This use a linear congruential pseudorandom number generator, \ + * with the power-of-two ceiling of the test count as the modulus, the \ + * masked seed as the multiplier, and a prime as the increment. For \ + * each generated value < the test count, run the corresponding test. \ + * This will visit all IDs 0 <= X < mod once before repeating, \ + * with a starting position chosen based on the initial seed. \ + * For details, see: Knuth, The Art of Computer Programming \ + * Volume. 2, section 3.2.1. */ \ + void greatest_prng_step(int id) \ + { \ + struct greatest_prng *p = &greatest_info.prng[id]; \ + do { \ + p->state = ((p->a * p->state) + p->c) & (p->m - 1); \ + } while (p->state >= p->count_ceil); \ + } \ + \ + void GREATEST_INIT(void) \ + { \ + /* Suppress unused function warning if features aren't used */ \ + (void)greatest_run_suite; \ + (void)greatest_parse_options; \ + (void)greatest_prng_step; \ + (void)greatest_prng_init_first_pass; \ + (void)greatest_prng_init_second_pass; \ + (void)greatest_set_test_suffix; \ + \ + memset(&greatest_info, 0, sizeof(greatest_info)); \ + greatest_info.width = GREATEST_DEFAULT_WIDTH; \ + GREATEST_SET_TIME(greatest_info.begin); \ + } \ + \ + /* Report passes, failures, skipped tests, the number of \ + * assertions, and the overall run time. */ \ + void GREATEST_PRINT_REPORT(void) \ + { \ + if (!GREATEST_LIST_ONLY()) { \ + update_counts_and_reset_suite(); \ + GREATEST_SET_TIME(greatest_info.end); \ + GREATEST_FPRINTF(GREATEST_STDOUT, \ + "\nTotal: %u test%s", \ + greatest_info.tests_run, \ + greatest_info.tests_run == 1 ? "" : "s"); \ + GREATEST_CLOCK_DIFF(greatest_info.begin, greatest_info.end); \ + GREATEST_FPRINTF(GREATEST_STDOUT, \ + ", %u assertion%s\n", \ + greatest_info.assertions, \ + greatest_info.assertions == 1 ? "" : "s"); \ + GREATEST_FPRINTF(GREATEST_STDOUT, \ + "Pass: %u, fail: %u, skip: %u.\n", \ + greatest_info.passed, \ + greatest_info.failed, \ + greatest_info.skipped); \ + } \ + } \ + \ + greatest_type_info greatest_type_info_memory = { \ + greatest_memory_equal_cb, \ + greatest_memory_printf_cb, \ + }; \ + \ + greatest_run_info greatest_info /* Handle command-line arguments, etc. */ -#define GREATEST_MAIN_BEGIN() \ - do { \ - GREATEST_INIT(); \ - greatest_parse_options(argc, argv); \ +#define GREATEST_MAIN_BEGIN() \ + do { \ + GREATEST_INIT(); \ + greatest_parse_options(argc, argv); \ } while (0) /* Report results, exit with exit status based on results. */ -#define GREATEST_MAIN_END() \ - do { \ - GREATEST_PRINT_REPORT(); \ - return (greatest_all_passed() ? EXIT_SUCCESS : EXIT_FAILURE); \ +#define GREATEST_MAIN_END() \ + do { \ + GREATEST_PRINT_REPORT(); \ + return (greatest_all_passed() ? EXIT_SUCCESS : EXIT_FAILURE); \ } while (0) /* Make abbreviations without the GREATEST_ prefix for the * most commonly used symbols. */ #if GREATEST_USE_ABBREVS -#define TEST GREATEST_TEST -#define SUITE GREATEST_SUITE -#define SUITE_EXTERN GREATEST_SUITE_EXTERN -#define RUN_TEST GREATEST_RUN_TEST -#define RUN_TEST1 GREATEST_RUN_TEST1 -#define RUN_SUITE GREATEST_RUN_SUITE -#define IGNORE_TEST GREATEST_IGNORE_TEST -#define ASSERT GREATEST_ASSERT -#define ASSERTm GREATEST_ASSERTm -#define ASSERT_FALSE GREATEST_ASSERT_FALSE -#define ASSERT_EQ GREATEST_ASSERT_EQ -#define ASSERT_NEQ GREATEST_ASSERT_NEQ -#define ASSERT_GT GREATEST_ASSERT_GT -#define ASSERT_GTE GREATEST_ASSERT_GTE -#define ASSERT_LT GREATEST_ASSERT_LT -#define ASSERT_LTE GREATEST_ASSERT_LTE -#define ASSERT_EQ_FMT GREATEST_ASSERT_EQ_FMT +#define TEST GREATEST_TEST +#define SUITE GREATEST_SUITE +#define SUITE_EXTERN GREATEST_SUITE_EXTERN +#define RUN_TEST GREATEST_RUN_TEST +#define RUN_TEST1 GREATEST_RUN_TEST1 +#define RUN_SUITE GREATEST_RUN_SUITE +#define IGNORE_TEST GREATEST_IGNORE_TEST +#define ASSERT GREATEST_ASSERT +#define ASSERTm GREATEST_ASSERTm +#define ASSERT_FALSE GREATEST_ASSERT_FALSE +#define ASSERT_EQ GREATEST_ASSERT_EQ +#define ASSERT_NEQ GREATEST_ASSERT_NEQ +#define ASSERT_GT GREATEST_ASSERT_GT +#define ASSERT_GTE GREATEST_ASSERT_GTE +#define ASSERT_LT GREATEST_ASSERT_LT +#define ASSERT_LTE GREATEST_ASSERT_LTE +#define ASSERT_EQ_FMT GREATEST_ASSERT_EQ_FMT #define ASSERT_IN_RANGE GREATEST_ASSERT_IN_RANGE #define ASSERT_EQUAL_T GREATEST_ASSERT_EQUAL_T -#define ASSERT_STR_EQ GREATEST_ASSERT_STR_EQ +#define ASSERT_STR_EQ GREATEST_ASSERT_STR_EQ #define ASSERT_STRN_EQ GREATEST_ASSERT_STRN_EQ -#define ASSERT_MEM_EQ GREATEST_ASSERT_MEM_EQ +#define ASSERT_MEM_EQ GREATEST_ASSERT_MEM_EQ #define ASSERT_ENUM_EQ GREATEST_ASSERT_ENUM_EQ -#define ASSERT_FALSEm GREATEST_ASSERT_FALSEm -#define ASSERT_EQm GREATEST_ASSERT_EQm -#define ASSERT_NEQm GREATEST_ASSERT_NEQm -#define ASSERT_GTm GREATEST_ASSERT_GTm -#define ASSERT_GTEm GREATEST_ASSERT_GTEm -#define ASSERT_LTm GREATEST_ASSERT_LTm -#define ASSERT_LTEm GREATEST_ASSERT_LTEm +#define ASSERT_FALSEm GREATEST_ASSERT_FALSEm +#define ASSERT_EQm GREATEST_ASSERT_EQm +#define ASSERT_NEQm GREATEST_ASSERT_NEQm +#define ASSERT_GTm GREATEST_ASSERT_GTm +#define ASSERT_GTEm GREATEST_ASSERT_GTEm +#define ASSERT_LTm GREATEST_ASSERT_LTm +#define ASSERT_LTEm GREATEST_ASSERT_LTEm #define ASSERT_EQ_FMTm GREATEST_ASSERT_EQ_FMTm #define ASSERT_IN_RANGEm GREATEST_ASSERT_IN_RANGEm #define ASSERT_EQUAL_Tm GREATEST_ASSERT_EQUAL_Tm @@ -1234,26 +1341,26 @@ greatest_run_info greatest_info #define ASSERT_STRN_EQm GREATEST_ASSERT_STRN_EQm #define ASSERT_MEM_EQm GREATEST_ASSERT_MEM_EQm #define ASSERT_ENUM_EQm GREATEST_ASSERT_ENUM_EQm -#define PASS GREATEST_PASS -#define FAIL GREATEST_FAIL -#define SKIP GREATEST_SKIP -#define PASSm GREATEST_PASSm -#define FAILm GREATEST_FAILm -#define SKIPm GREATEST_SKIPm -#define SET_SETUP GREATEST_SET_SETUP_CB -#define SET_TEARDOWN GREATEST_SET_TEARDOWN_CB -#define CHECK_CALL GREATEST_CHECK_CALL -#define SHUFFLE_TESTS GREATEST_SHUFFLE_TESTS +#define PASS GREATEST_PASS +#define FAIL GREATEST_FAIL +#define SKIP GREATEST_SKIP +#define PASSm GREATEST_PASSm +#define FAILm GREATEST_FAILm +#define SKIPm GREATEST_SKIPm +#define SET_SETUP GREATEST_SET_SETUP_CB +#define SET_TEARDOWN GREATEST_SET_TEARDOWN_CB +#define CHECK_CALL GREATEST_CHECK_CALL +#define SHUFFLE_TESTS GREATEST_SHUFFLE_TESTS #define SHUFFLE_SUITES GREATEST_SHUFFLE_SUITES #ifdef GREATEST_VA_ARGS -#define RUN_TESTp GREATEST_RUN_TESTp +#define RUN_TESTp GREATEST_RUN_TESTp #endif #if GREATEST_USE_LONGJMP -#define ASSERT_OR_LONGJMP GREATEST_ASSERT_OR_LONGJMP +#define ASSERT_OR_LONGJMP GREATEST_ASSERT_OR_LONGJMP #define ASSERT_OR_LONGJMPm GREATEST_ASSERT_OR_LONGJMPm -#define FAIL_WITH_LONGJMP GREATEST_FAIL_WITH_LONGJMP +#define FAIL_WITH_LONGJMP GREATEST_FAIL_WITH_LONGJMP #define FAIL_WITH_LONGJMPm GREATEST_FAIL_WITH_LONGJMPm #endif diff --git a/test/helpers.c b/test/helpers.c index 74381d851..88103ff9c 100644 --- a/test/helpers.c +++ b/test/helpers.c @@ -1,91 +1,91 @@ #include -#include "helpers.h" #include "../src/notification.h" #include "../src/utils.h" +#include "helpers.h" GVariant *notification_setup_raw_image(const char *path) { - GdkPixbuf *pb = gdk_pixbuf_new_from_file(path, NULL); + GdkPixbuf *pb = gdk_pixbuf_new_from_file(path, NULL); - if (!pb) - return NULL; + if (!pb) + return NULL; - GVariant *hint_data = g_variant_new_from_data( - G_VARIANT_TYPE("ay"), + GVariant *hint_data = + g_variant_new_from_data(G_VARIANT_TYPE("ay"), gdk_pixbuf_read_pixels(pb), gdk_pixbuf_get_byte_length(pb), TRUE, - (GDestroyNotify) g_object_unref, + (GDestroyNotify)g_object_unref, g_object_ref(pb)); - GVariant *hint = g_variant_new( - "(iiibii@ay)", - gdk_pixbuf_get_width(pb), - gdk_pixbuf_get_height(pb), - gdk_pixbuf_get_rowstride(pb), - gdk_pixbuf_get_has_alpha(pb), - gdk_pixbuf_get_bits_per_sample(pb), - gdk_pixbuf_get_n_channels(pb), - hint_data); + GVariant *hint = g_variant_new("(iiibii@ay)", + gdk_pixbuf_get_width(pb), + gdk_pixbuf_get_height(pb), + gdk_pixbuf_get_rowstride(pb), + gdk_pixbuf_get_has_alpha(pb), + gdk_pixbuf_get_bits_per_sample(pb), + gdk_pixbuf_get_n_channels(pb), + hint_data); - g_object_unref(pb); + g_object_unref(pb); - return hint; + return hint; } struct notification *test_notification_uninitialized(const char *name) { - struct notification *n = notification_create(); + struct notification *n = notification_create(); - 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->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); - return n; + return n; } struct notification *test_notification(const char *name, gint64 timeout) { - struct notification *n = test_notification_uninitialized(name); + struct notification *n = test_notification_uninitialized(name); - notification_init(n); - notification_replace_format(n, "%s\n%b"); + notification_init(n); + notification_replace_format(n, "%s\n%b"); - if (timeout != -1) - n->timeout = S2US(timeout); + if (timeout != -1) + n->timeout = S2US(timeout); - return n; + return n; } -struct notification *test_notification_with_icon(const char *name, gint64 timeout) +struct notification *test_notification_with_icon(const char *name, + gint64 timeout) { - struct notification *n = test_notification(name, timeout); - n->icon = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); - return n; + struct notification *n = test_notification(name, timeout); + n->icon = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); + return n; } GSList *get_dummy_notifications(int count) { - GSList *notifications = NULL; - - int message_size = 24; - for (int i = 0; i < count; i++) { - char msg[message_size]; - snprintf(msg, message_size, "test %d", i); - struct notification *n = test_notification(msg, 10); - n->icon_position = ICON_LEFT; - n->text_to_render = g_strdup("dummy layout"); - notifications = g_slist_append(notifications, n); - } - return notifications; + GSList *notifications = NULL; + + int message_size = 24; + for (int i = 0; i < count; i++) { + char msg[message_size]; + snprintf(msg, message_size, "test %d", i); + struct notification *n = test_notification(msg, 10); + n->icon_position = ICON_LEFT; + n->text_to_render = g_strdup("dummy layout"); + notifications = g_slist_append(notifications, n); + } + return notifications; } void free_dummy_notification(void *notification) { - // wrapper function to work with g_slist_free_full - notification_unref((struct notification *) notification); + // wrapper function to work with g_slist_free_full + notification_unref((struct notification *)notification); } /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/test/helpers.h b/test/helpers.h index 2a42c7549..0a1c04f47 100644 --- a/test/helpers.h +++ b/test/helpers.h @@ -6,7 +6,8 @@ GVariant *notification_setup_raw_image(const char *path); struct notification *test_notification_uninitialized(const char *name); struct notification *test_notification(const char *name, gint64 timeout); -struct notification *test_notification_with_icon(const char *name, gint64 timeout); +struct notification *test_notification_with_icon(const char *name, + gint64 timeout); GSList *get_dummy_notifications(int count); void free_dummy_notification(void *notification); diff --git a/test/icon-lookup.c b/test/icon-lookup.c index 819a9d711..8b27a7e09 100644 --- a/test/icon-lookup.c +++ b/test/icon-lookup.c @@ -1,155 +1,161 @@ -#include "greatest.h" #include "../src/icon-lookup.c" -#include "helpers.h" #include "../src/notification.h" #include "../src/settings_data.h" +#include "greatest.h" +#include "helpers.h" extern const char *base; #define ICONPREFIX "data", "icons" -int setup_test_theme(void) { - char *theme_path = g_build_filename(base, ICONPREFIX, NULL); - int theme_index = load_icon_theme_from_dir(theme_path, "theme"); - add_default_theme(theme_index); - g_free(theme_path); - return theme_index; +int setup_test_theme(void) +{ + char *theme_path = g_build_filename(base, ICONPREFIX, NULL); + int theme_index = load_icon_theme_from_dir(theme_path, "theme"); + add_default_theme(theme_index); + g_free(theme_path); + return theme_index; } -#define find_icon_test(iconname, size, ...) { \ - char *icon = find_icon_path(iconname, size); \ - char *expected = g_build_filename(base, ICONPREFIX, "theme", __VA_ARGS__, NULL); \ - ASSERTm("Could not find icon", icon); \ - ASSERT_STR_EQ(expected, icon); \ - g_free(expected); \ - g_free(icon); \ -} +#define find_icon_test(iconname, size, ...) \ + { \ + char *icon = find_icon_path(iconname, size); \ + char *expected = \ + g_build_filename(base, ICONPREFIX, "theme", __VA_ARGS__, NULL); \ + ASSERTm("Could not find icon", icon); \ + ASSERT_STR_EQ(expected, icon); \ + g_free(expected); \ + g_free(icon); \ + } TEST test_load_theme_from_dir(void) { - setup_test_theme(); - free_all_themes(); - PASS(); + setup_test_theme(); + free_all_themes(); + PASS(); } TEST test_find_icon(void) { - setup_test_theme(); - find_icon_test("edit", 8, "16x16", "actions", "edit.png"); - find_icon_test("edit", 16, "16x16", "actions", "edit.png"); - find_icon_test("edit", 32, "16x16", "actions", "edit.png"); - find_icon_test("edit", 48, "16x16", "actions", "edit.png"); - find_icon_test("edit", 49, "32x32", "actions", "edit.png"); - find_icon_test("edit", 64, "32x32", "actions", "edit.png"); - find_icon_test("preferences", 16, "16x16", "apps", "preferences.png"); - find_icon_test("preferences", 32, "16x16", "apps", "preferences.png"); - free_all_themes(); - PASS(); + setup_test_theme(); + find_icon_test("edit", 8, "16x16", "actions", "edit.png"); + find_icon_test("edit", 16, "16x16", "actions", "edit.png"); + find_icon_test("edit", 32, "16x16", "actions", "edit.png"); + find_icon_test("edit", 48, "16x16", "actions", "edit.png"); + find_icon_test("edit", 49, "32x32", "actions", "edit.png"); + find_icon_test("edit", 64, "32x32", "actions", "edit.png"); + find_icon_test("preferences", 16, "16x16", "apps", "preferences.png"); + find_icon_test("preferences", 32, "16x16", "apps", "preferences.png"); + free_all_themes(); + PASS(); } -TEST test_new_icon_overrides_raw_icon(void) { - setup_test_theme(); - - struct notification *n = test_notification_with_icon("new_icon", 10); - struct rule *rule = g_malloc(sizeof(struct rule)); - *rule = empty_rule; - rule->summary = g_strdup("new_icon"); - rule->new_icon = g_strdup("edit"); - - ASSERT(n->icon); - int old_width = cairo_image_surface_get_width(n->icon); - rule_apply(rule, n, true); - - ASSERT(n->icon); - ASSERT(old_width != cairo_image_surface_get_width(n->icon)); - - cairo_surface_destroy(n->icon); - n->icon = NULL; - - notification_unref(n); - g_free(rule->summary); - g_free(rule->new_icon); - g_free(rule); - free_all_themes(); - PASS(); +TEST test_new_icon_overrides_raw_icon(void) +{ + setup_test_theme(); + + struct notification *n = test_notification_with_icon("new_icon", 10); + struct rule *rule = g_malloc(sizeof(struct rule)); + *rule = empty_rule; + rule->summary = g_strdup("new_icon"); + rule->new_icon = g_strdup("edit"); + + ASSERT(n->icon); + int old_width = cairo_image_surface_get_width(n->icon); + rule_apply(rule, n, true); + + ASSERT(n->icon); + ASSERT(old_width != cairo_image_surface_get_width(n->icon)); + + cairo_surface_destroy(n->icon); + n->icon = NULL; + + notification_unref(n); + g_free(rule->summary); + g_free(rule->new_icon); + g_free(rule); + free_all_themes(); + PASS(); } // TODO move this out of the test suite, since this isn't a real test TEST test_bench_search(void) { - printf("Starting benchmark\n"); - // At the time of committing, I get numbers like 0.25 second for 1000 icon lookups - int index = load_icon_theme("Papirus"); - add_default_theme(index); - printf("Benchmarking icons\n"); - clock_t start_time = clock(); - for (int i = 0; i < 1000; i++) { - // icon is part of papirus, right at the end of index.theme - char *icon = find_icon_path("weather-windy-symbolic", 512); - ASSERT(icon); - g_free(icon); - } - double elapsed_time = (double)(clock() - start_time) / CLOCKS_PER_SEC; - printf("Done in %f seconds\n", elapsed_time); - free_all_themes(); - PASS(); + printf("Starting benchmark\n"); + // At the time of committing, I get numbers like 0.25 second for 1000 icon + // lookups + int index = load_icon_theme("Papirus"); + add_default_theme(index); + printf("Benchmarking icons\n"); + clock_t start_time = clock(); + for (int i = 0; i < 1000; i++) { + // icon is part of papirus, right at the end of index.theme + char *icon = find_icon_path("weather-windy-symbolic", 512); + ASSERT(icon); + g_free(icon); + } + double elapsed_time = (double)(clock() - start_time) / CLOCKS_PER_SEC; + printf("Done in %f seconds\n", elapsed_time); + free_all_themes(); + PASS(); } TEST test_bench_multiple_search(void) { - printf("Starting benchmark\n"); - // At the time of committing, I get numbers like 2 second for 1000 icon lookups - int index = load_icon_theme("Adwaita"); - add_default_theme(index); - index = load_icon_theme("Papirus"); - add_default_theme(index); - printf("Benchmarking icons\n"); - clock_t start_time = clock(); - for (int i = 0; i < 1000; i++) { - // icon is part of papirus, right at the end of index.theme - char *icon = find_icon_path("view-wrapped-rtl-symbolic", 512); - /* printf("%s\n", icon); */ - ASSERT(icon); - g_free(icon); - } - double elapsed_time = (double)(clock() - start_time) / CLOCKS_PER_SEC; - printf("Done in %f seconds\n", elapsed_time); - free_all_themes(); - PASS(); + printf("Starting benchmark\n"); + // At the time of committing, I get numbers like 2 second for 1000 icon + // lookups + int index = load_icon_theme("Adwaita"); + add_default_theme(index); + index = load_icon_theme("Papirus"); + add_default_theme(index); + printf("Benchmarking icons\n"); + clock_t start_time = clock(); + for (int i = 0; i < 1000; i++) { + // icon is part of papirus, right at the end of index.theme + char *icon = find_icon_path("view-wrapped-rtl-symbolic", 512); + /* printf("%s\n", icon); */ + ASSERT(icon); + g_free(icon); + } + double elapsed_time = (double)(clock() - start_time) / CLOCKS_PER_SEC; + printf("Done in %f seconds\n", elapsed_time); + free_all_themes(); + PASS(); } TEST test_bench_doesnt_exist(void) { - printf("Starting benchmark\n"); - // At the time of committing, I get numbers like 9 seconds for 1000 icon lookups - int index = load_icon_theme("Adwaita"); - add_default_theme(index); - index = load_icon_theme("Papirus"); - add_default_theme(index); - printf("Benchmarking icons\n"); - clock_t start_time = clock(); - for (int i = 0; i < 1000; i++) { - // Icon size is chosen as some common icon size. - char *icon = find_icon_path("doesn't exist", 48); - /* printf("%s\n", icon); */ - ASSERT_FALSE(icon); - g_free(icon); - } - double elapsed_time = (double)(clock() - start_time) / CLOCKS_PER_SEC; - printf("Done in %f seconds\n", elapsed_time); - free_all_themes(); - PASS(); + printf("Starting benchmark\n"); + // At the time of committing, I get numbers like 9 seconds for 1000 icon + // lookups + int index = load_icon_theme("Adwaita"); + add_default_theme(index); + index = load_icon_theme("Papirus"); + add_default_theme(index); + printf("Benchmarking icons\n"); + clock_t start_time = clock(); + for (int i = 0; i < 1000; i++) { + // Icon size is chosen as some common icon size. + char *icon = find_icon_path("doesn't exist", 48); + /* printf("%s\n", icon); */ + ASSERT_FALSE(icon); + g_free(icon); + } + double elapsed_time = (double)(clock() - start_time) / CLOCKS_PER_SEC; + printf("Done in %f seconds\n", elapsed_time); + free_all_themes(); + PASS(); } - -SUITE (suite_icon_lookup) +SUITE(suite_icon_lookup) { - RUN_TEST(test_load_theme_from_dir); - RUN_TEST(test_find_icon); - RUN_TEST(test_new_icon_overrides_raw_icon); - bool bench = false; - if (bench) { - RUN_TEST(test_bench_search); - RUN_TEST(test_bench_multiple_search); - RUN_TEST(test_bench_doesnt_exist); - } + RUN_TEST(test_load_theme_from_dir); + RUN_TEST(test_find_icon); + RUN_TEST(test_new_icon_overrides_raw_icon); + bool bench = false; + if (bench) { + RUN_TEST(test_bench_search); + RUN_TEST(test_bench_multiple_search); + RUN_TEST(test_bench_doesnt_exist); + } } diff --git a/test/icon.c b/test/icon.c index 8bc3a4d3a..47a252762 100644 --- a/test/icon.c +++ b/test/icon.c @@ -8,7 +8,7 @@ * read from a PNG or an SVG file, the sample icons in the * test structure have different sizes */ -#define IS_ICON_PNG(pb) 4 == gdk_pixbuf_get_width(pb) +#define IS_ICON_PNG(pb) 4 == gdk_pixbuf_get_width(pb) #define IS_ICON_SVG(pb) 16 == gdk_pixbuf_get_width(pb) extern const char *base; @@ -18,91 +18,93 @@ int size = 16; TEST test_get_path_from_icon_null(void) { - char *result = get_path_from_icon_name(NULL, 16); - ASSERT_EQ(result, NULL); - PASS(); + char *result = get_path_from_icon_name(NULL, 16); + ASSERT_EQ(result, NULL); + PASS(); } TEST test_get_path_from_icon_name_full(void) { - const char *iconpath = ICONPATH; + const char *iconpath = ICONPATH; - gchar *path = g_build_filename(base, iconpath, "16x16", "actions", "edit.png", NULL); + gchar *path = + g_build_filename(base, iconpath, "16x16", "actions", "edit.png", NULL); - char *result = get_path_from_icon_name(path, size); - ASSERT(result); - ASSERT_STR_EQ(result, path); + char *result = get_path_from_icon_name(path, size); + ASSERT(result); + ASSERT_STR_EQ(result, path); - g_free(path); - g_free(result); - PASS(); + g_free(path); + g_free(result); + PASS(); } TEST test_icon_size_clamp_too_small(int min_icon_size, int max_icon_size) { - int w = 12, h = 24; - bool resized = icon_size_clamp(&w, &h, min_icon_size, max_icon_size); - ASSERT(resized); - ASSERT_EQ(w, 16); - ASSERT_EQ(h, 32); + int w = 12, h = 24; + bool resized = icon_size_clamp(&w, &h, min_icon_size, max_icon_size); + ASSERT(resized); + ASSERT_EQ(w, 16); + ASSERT_EQ(h, 32); - PASS(); + PASS(); } TEST test_icon_size_clamp_not_necessary(int min_icon_size, int max_icon_size) { - int w = 20, h = 30; - bool resized = icon_size_clamp(&w, &h, min_icon_size, max_icon_size); - ASSERT(!resized); - ASSERT_EQ(w, 20); - ASSERT_EQ(h, 30); + int w = 20, h = 30; + bool resized = icon_size_clamp(&w, &h, min_icon_size, max_icon_size); + ASSERT(!resized); + ASSERT_EQ(w, 20); + ASSERT_EQ(h, 30); - PASS(); + PASS(); } TEST test_icon_size_clamp_too_big(int min_icon_size, int max_icon_size) { - int w = 75, h = 150; - bool resized = icon_size_clamp(&w, &h, min_icon_size, max_icon_size); - ASSERT(resized); - ASSERT_EQ(w, 50); - ASSERT_EQ(h, 100); + int w = 75, h = 150; + bool resized = icon_size_clamp(&w, &h, min_icon_size, max_icon_size); + ASSERT(resized); + ASSERT_EQ(w, 50); + ASSERT_EQ(h, 100); - PASS(); + PASS(); } -TEST test_icon_size_clamp_too_small_then_too_big(int min_icon_size, int max_icon_size) +TEST test_icon_size_clamp_too_small_then_too_big(int min_icon_size, + int max_icon_size) { - int w = 8, h = 80; - bool resized = icon_size_clamp(&w, &h, min_icon_size, max_icon_size); - ASSERT(resized); - ASSERT_EQ(w, 10); - ASSERT_EQ(h, 100); + int w = 8, h = 80; + bool resized = icon_size_clamp(&w, &h, min_icon_size, max_icon_size); + ASSERT(resized); + ASSERT_EQ(w, 10); + ASSERT_EQ(h, 100); - PASS(); + PASS(); } SUITE(suite_icon) { - // set only valid icons in the path - char *icon_path = g_build_filename(base, DATAPREFIX, NULL); - setenv("XDG_DATA_HOME", icon_path, 1); - printf("Icon path: %s\n", icon_path); - RUN_TEST(test_get_path_from_icon_null); - RUN_TEST(test_get_path_from_icon_name_full); - RUN_TESTp(test_icon_size_clamp_not_necessary, 0, 100); - - RUN_TESTp(test_icon_size_clamp_too_small, 16, 100); - RUN_TESTp(test_icon_size_clamp_not_necessary, 16, 100); - RUN_TESTp(test_icon_size_clamp_too_big, 16, 100); - RUN_TESTp(test_icon_size_clamp_too_small_then_too_big, 16, 100); - - RUN_TESTp(test_icon_size_clamp_too_small, 16, 0); - RUN_TESTp(test_icon_size_clamp_not_necessary, 16, 0); - - RUN_TESTp(test_icon_size_clamp_not_necessary, 0, 100); - RUN_TESTp(test_icon_size_clamp_too_big, 0, 100); - - g_clear_pointer(&icon_path, g_free); + // set only valid icons in the path + char *icon_path = g_build_filename(base, DATAPREFIX, NULL); + setenv("XDG_DATA_HOME", icon_path, 1); + printf("Icon path: %s\n", icon_path); + RUN_TEST(test_get_path_from_icon_null); + RUN_TEST(test_get_path_from_icon_name_full); + RUN_TESTp(test_icon_size_clamp_not_necessary, 0, 100); + + RUN_TESTp(test_icon_size_clamp_too_small, 16, 100); + RUN_TESTp(test_icon_size_clamp_not_necessary, 16, 100); + RUN_TESTp(test_icon_size_clamp_too_big, 16, 100); + RUN_TESTp(test_icon_size_clamp_too_small_then_too_big, 16, 100); + + RUN_TESTp(test_icon_size_clamp_too_small, 16, 0); + RUN_TESTp(test_icon_size_clamp_not_necessary, 16, 0); + + RUN_TESTp(test_icon_size_clamp_not_necessary, 0, 100); + RUN_TESTp(test_icon_size_clamp_too_big, 0, 100); + + g_clear_pointer(&icon_path, g_free); } /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/test/ini.c b/test/ini.c index d7a569dc2..0006fecae 100644 --- a/test/ini.c +++ b/test/ini.c @@ -1,35 +1,36 @@ -#include "greatest.h" #include "../src/ini.c" +#include "greatest.h" #include extern const char *base; TEST test_next_section(void) { - char *config_path = g_strconcat(base, "/data/test-ini", NULL); - FILE *config_file = fopen(config_path, "r"); - if (!config_file) { - ASSERTm(false, "Test config file 'data/test-ini' couldn't be opened, failing.\n"); - } - struct ini * ini = load_ini_file(config_file); - ASSERT(ini); - fclose(config_file); - free(config_path); + char *config_path = g_strconcat(base, "/data/test-ini", NULL); + FILE *config_file = fopen(config_path, "r"); + if (!config_file) { + ASSERTm( + false, + "Test config file 'data/test-ini' couldn't be opened, failing.\n"); + } + struct ini *ini = load_ini_file(config_file); + ASSERT(ini); + fclose(config_file); + free(config_path); - const char *section = NULL; - ASSERT_STR_EQ("bool", (section = next_section(ini, section))); - ASSERT_STR_EQ("string", (section = next_section(ini, section))); - ASSERT_STR_EQ("list", (section = next_section(ini, section))); - ASSERT_STR_EQ("path", (section = next_section(ini, section))); - ASSERT_STR_EQ("int", (section = next_section(ini, section))); - ASSERT_STR_EQ("double", (section = next_section(ini, section))); - finish_ini(ini); - free(ini); - PASS(); + const char *section = NULL; + ASSERT_STR_EQ("bool", (section = next_section(ini, section))); + ASSERT_STR_EQ("string", (section = next_section(ini, section))); + ASSERT_STR_EQ("list", (section = next_section(ini, section))); + ASSERT_STR_EQ("path", (section = next_section(ini, section))); + ASSERT_STR_EQ("int", (section = next_section(ini, section))); + ASSERT_STR_EQ("double", (section = next_section(ini, section))); + finish_ini(ini); + free(ini); + PASS(); } - SUITE(suite_ini) { - RUN_TEST(test_next_section); + RUN_TEST(test_next_section); } diff --git a/test/input.c b/test/input.c index 21deae9f8..6a68e2dec 100644 --- a/test/input.c +++ b/test/input.c @@ -1,162 +1,168 @@ #include "../src/input.c" -#include "queues.h" +#include "../src/utils.h" #include "greatest.h" #include "helpers.h" -#include "../src/utils.h" +#include "queues.h" TEST test_get_notification_clickable_height_first(void) { - bool orginal_gap_size = settings.gap_size; - settings.gap_size = 0; + bool orginal_gap_size = settings.gap_size; + settings.gap_size = 0; - struct notification *n = test_notification("test", 10); - n->displayed_height = 12; + struct notification *n = test_notification("test", 10); + n->displayed_height = 12; - int expected_size = n->displayed_height + settings.frame_width; - expected_size += (settings.separator_height / 2.0); - int result = get_notification_clickable_height(n, true, false); + int expected_size = n->displayed_height + settings.frame_width; + expected_size += (settings.separator_height / 2.0); + int result = get_notification_clickable_height(n, true, false); - ASSERT(result == expected_size); + ASSERT(result == expected_size); - settings.gap_size = orginal_gap_size; - notification_unref(n); - PASS(); + settings.gap_size = orginal_gap_size; + notification_unref(n); + PASS(); } TEST test_get_notification_clickable_height_middle(void) { - bool orginal_gap_size = settings.gap_size; - settings.gap_size = 0; + bool orginal_gap_size = settings.gap_size; + settings.gap_size = 0; - struct notification *n = test_notification("test", 10); - n->displayed_height = 12; + struct notification *n = test_notification("test", 10); + n->displayed_height = 12; - int expected_size = n->displayed_height + settings.separator_height; - int result = get_notification_clickable_height(n, false, false); + int expected_size = n->displayed_height + settings.separator_height; + int result = get_notification_clickable_height(n, false, false); - ASSERT(result == expected_size); + ASSERT(result == expected_size); - settings.gap_size = orginal_gap_size; - notification_unref(n); - PASS(); + settings.gap_size = orginal_gap_size; + notification_unref(n); + PASS(); } TEST test_get_notification_clickable_height_last(void) { - bool orginal_gap_size = settings.gap_size; - settings.gap_size = 0; + bool orginal_gap_size = settings.gap_size; + settings.gap_size = 0; - struct notification *n = test_notification("test", 10); - n->displayed_height = 12; + struct notification *n = test_notification("test", 10); + n->displayed_height = 12; - int expected_size = n->displayed_height + settings.frame_width; - expected_size += (settings.separator_height / 2.0); - int result = get_notification_clickable_height(n, false, true); + int expected_size = n->displayed_height + settings.frame_width; + expected_size += (settings.separator_height / 2.0); + int result = get_notification_clickable_height(n, false, true); - ASSERT(result == expected_size); + ASSERT(result == expected_size); - settings.gap_size = orginal_gap_size; - notification_unref(n); - PASS(); + settings.gap_size = orginal_gap_size; + notification_unref(n); + PASS(); } TEST test_get_notification_clickable_height_gaps(void) { - bool orginal_gap_size = settings.gap_size; - settings.gap_size = 7; + bool orginal_gap_size = settings.gap_size; + settings.gap_size = 7; - struct notification *n = test_notification("test", 10); - n->displayed_height = 12; + struct notification *n = test_notification("test", 10); + n->displayed_height = 12; - int expected_size = n->displayed_height + (settings.frame_width * 2); + int expected_size = n->displayed_height + (settings.frame_width * 2); - int result_first = get_notification_clickable_height(n, true, false); - ASSERT(result_first == expected_size); + int result_first = get_notification_clickable_height(n, true, false); + ASSERT(result_first == expected_size); - int result_middle = get_notification_clickable_height(n, false, false); - ASSERT(result_middle == expected_size); + int result_middle = get_notification_clickable_height(n, false, false); + ASSERT(result_middle == expected_size); - int result_last = get_notification_clickable_height(n, false, true); - ASSERT(result_last == expected_size); + int result_last = get_notification_clickable_height(n, false, true); + ASSERT(result_last == expected_size); - settings.gap_size = orginal_gap_size; - notification_unref(n); - PASS(); + settings.gap_size = orginal_gap_size; + notification_unref(n); + PASS(); } TEST test_notification_at(void) { - int total_notifications = 3; - GSList *notifications = get_dummy_notifications(total_notifications); - - queues_init(); - - int display_height = 12; - struct notification *n; - for (GSList *iter = notifications; iter; iter = iter->next) { - n = iter->data; - n->displayed_height = display_height; - queues_notification_insert(n); - } - - queues_update(STATUS_NORMAL, time_monotonic_now()); - - struct notification *top_notification = g_slist_nth_data(notifications, 0); - int top_notification_height = get_notification_clickable_height(top_notification, true, false); - - struct notification *middle_notification = g_slist_nth_data(notifications, 1); - int middle_notification_height = get_notification_clickable_height(middle_notification, false, false); - - struct notification *bottom_notification = g_slist_nth_data(notifications, 2); - int bottom_notification_height = get_notification_clickable_height(bottom_notification, false, true); - - struct notification *result; - - int top_y_coord; - top_y_coord = 0; - result = get_notification_at(top_y_coord); - ASSERT(result != NULL); - ASSERT(result == top_notification); - - top_y_coord = top_notification_height - 1; - result = get_notification_at(top_y_coord); - ASSERT(result != NULL); - ASSERT(result == top_notification); - - int middle_y_coord; - middle_y_coord = top_notification_height; - result = get_notification_at(middle_y_coord); - ASSERT(result != NULL); - ASSERT(result == middle_notification); - - middle_y_coord = top_notification_height; - result = get_notification_at(middle_y_coord); - ASSERT(result != NULL); - ASSERT(result == middle_notification); - - int bottom_y_coord; - bottom_y_coord = top_notification_height + middle_notification_height; - result = get_notification_at(bottom_y_coord); - ASSERT(result != NULL); - ASSERT(result == bottom_notification); - - bottom_y_coord = top_notification_height + middle_notification_height + bottom_notification_height - 1; - result = get_notification_at(bottom_y_coord); - ASSERT(result != NULL); - ASSERT(result == bottom_notification); - - queues_teardown(); - g_slist_free(notifications); - PASS(); + int total_notifications = 3; + GSList *notifications = get_dummy_notifications(total_notifications); + + queues_init(); + + int display_height = 12; + struct notification *n; + for (GSList *iter = notifications; iter; iter = iter->next) { + n = iter->data; + n->displayed_height = display_height; + queues_notification_insert(n); + } + + queues_update(STATUS_NORMAL, time_monotonic_now()); + + struct notification *top_notification = g_slist_nth_data(notifications, 0); + int top_notification_height = + get_notification_clickable_height(top_notification, true, false); + + struct notification *middle_notification = + g_slist_nth_data(notifications, 1); + int middle_notification_height = + get_notification_clickable_height(middle_notification, false, false); + + struct notification *bottom_notification = + g_slist_nth_data(notifications, 2); + int bottom_notification_height = + get_notification_clickable_height(bottom_notification, false, true); + + struct notification *result; + + int top_y_coord; + top_y_coord = 0; + result = get_notification_at(top_y_coord); + ASSERT(result != NULL); + ASSERT(result == top_notification); + + top_y_coord = top_notification_height - 1; + result = get_notification_at(top_y_coord); + ASSERT(result != NULL); + ASSERT(result == top_notification); + + int middle_y_coord; + middle_y_coord = top_notification_height; + result = get_notification_at(middle_y_coord); + ASSERT(result != NULL); + ASSERT(result == middle_notification); + + middle_y_coord = top_notification_height; + result = get_notification_at(middle_y_coord); + ASSERT(result != NULL); + ASSERT(result == middle_notification); + + int bottom_y_coord; + bottom_y_coord = top_notification_height + middle_notification_height; + result = get_notification_at(bottom_y_coord); + ASSERT(result != NULL); + ASSERT(result == bottom_notification); + + bottom_y_coord = top_notification_height + middle_notification_height + + bottom_notification_height - 1; + result = get_notification_at(bottom_y_coord); + ASSERT(result != NULL); + ASSERT(result == bottom_notification); + + queues_teardown(); + g_slist_free(notifications); + PASS(); } SUITE(suite_input) { - SHUFFLE_TESTS(time(NULL), { - RUN_TEST(test_get_notification_clickable_height_first); - RUN_TEST(test_get_notification_clickable_height_middle); - RUN_TEST(test_get_notification_clickable_height_last); - RUN_TEST(test_get_notification_clickable_height_gaps); - RUN_TEST(test_notification_at); - }); + SHUFFLE_TESTS(time(NULL), { + RUN_TEST(test_get_notification_clickable_height_first); + RUN_TEST(test_get_notification_clickable_height_middle); + RUN_TEST(test_get_notification_clickable_height_last); + RUN_TEST(test_get_notification_clickable_height_gaps); + RUN_TEST(test_notification_at); + }); } diff --git a/test/log.c b/test/log.c index a5ab81ec2..f16622758 100644 --- a/test/log.c +++ b/test/log.c @@ -1,35 +1,37 @@ #include "../src/log.c" #include "greatest.h" -TEST test_log_level(GLogLevelFlags level, const char *shortstr, const char *longstr) +TEST test_log_level(GLogLevelFlags level, + const char *shortstr, + const char *longstr) { - ASSERT_STR_EQ(log_level_to_string(level), longstr); + ASSERT_STR_EQ(log_level_to_string(level), longstr); - log_set_level_from_string(shortstr); + log_set_level_from_string(shortstr); - if (level != G_LOG_LEVEL_ERROR) - ASSERT_ENUM_EQ(level, log_level, log_level_to_string); + if (level != G_LOG_LEVEL_ERROR) + ASSERT_ENUM_EQ(level, log_level, log_level_to_string); - log_set_level_from_string(longstr); + log_set_level_from_string(longstr); - if (level != G_LOG_LEVEL_ERROR) - ASSERT_ENUM_EQ(level, log_level, log_level_to_string); + if (level != G_LOG_LEVEL_ERROR) + ASSERT_ENUM_EQ(level, log_level, log_level_to_string); - PASS(); + PASS(); } SUITE(suite_log) { - GLogLevelFlags oldlevel = log_level; + GLogLevelFlags oldlevel = log_level; - RUN_TESTp(test_log_level, G_LOG_LEVEL_ERROR, NULL, "ERROR"); - RUN_TESTp(test_log_level, G_LOG_LEVEL_CRITICAL, "crit", "CRITICAL"); - RUN_TESTp(test_log_level, G_LOG_LEVEL_WARNING, "warn", "WARNING"); - RUN_TESTp(test_log_level, G_LOG_LEVEL_MESSAGE, "mesg", "MESSAGE"); - RUN_TESTp(test_log_level, G_LOG_LEVEL_INFO, "info", "INFO"); - RUN_TESTp(test_log_level, G_LOG_LEVEL_DEBUG, "deb", "DEBUG"); + RUN_TESTp(test_log_level, G_LOG_LEVEL_ERROR, NULL, "ERROR"); + RUN_TESTp(test_log_level, G_LOG_LEVEL_CRITICAL, "crit", "CRITICAL"); + RUN_TESTp(test_log_level, G_LOG_LEVEL_WARNING, "warn", "WARNING"); + RUN_TESTp(test_log_level, G_LOG_LEVEL_MESSAGE, "mesg", "MESSAGE"); + RUN_TESTp(test_log_level, G_LOG_LEVEL_INFO, "info", "INFO"); + RUN_TESTp(test_log_level, G_LOG_LEVEL_DEBUG, "deb", "DEBUG"); - log_level = oldlevel; + log_level = oldlevel; } /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/test/markup.c b/test/markup.c index 9aa490972..66f06c9ee 100644 --- a/test/markup.c +++ b/test/markup.c @@ -3,154 +3,233 @@ TEST test_markup_strip(void) { - char *ptr; - - ASSERT_STR_EQ(""", (ptr=markup_strip(g_strdup("&quot;")))); - g_free(ptr); - ASSERT_STR_EQ("'", (ptr=markup_strip(g_strdup("&apos;")))); - g_free(ptr); - ASSERT_STR_EQ("<", (ptr=markup_strip(g_strdup("&lt;")))); - g_free(ptr); - ASSERT_STR_EQ(">", (ptr=markup_strip(g_strdup("&gt;")))); - g_free(ptr); - ASSERT_STR_EQ("&", (ptr=markup_strip(g_strdup("&amp;")))); - g_free(ptr); - ASSERT_STR_EQ(">A A A A foo
bar\nbaz"), MARKUP_NO))); - g_free(ptr); - ASSERT_STR_EQ("foo\nbar\nbaz", (ptr=markup_transform(g_strdup("foo
bar\nbaz"), MARKUP_STRIP))); - g_free(ptr); - ASSERT_STR_EQ("foo\nbar\nbaz", (ptr=markup_transform(g_strdup("foo
bar\nbaz"), MARKUP_FULL))); - g_free(ptr); - - settings.ignore_newline = true; - ASSERT_STR_EQ("<i>foo</i><br>bar baz", (ptr=markup_transform(g_strdup("foo
bar\nbaz"), MARKUP_NO))); - g_free(ptr); - ASSERT_STR_EQ("foo bar baz", (ptr=markup_transform(g_strdup("foo
bar\nbaz"), MARKUP_STRIP))); - g_free(ptr); - ASSERT_STR_EQ("foo bar baz", (ptr=markup_transform(g_strdup("foo
bar\nbaz"), MARKUP_FULL))); - g_free(ptr); - - // Test replacement of img and a tags, not renderable by pango - ASSERT_STR_EQ("foo bar bar baz", (ptr=markup_transform(g_strdup("\"foo
bar\nbaz"), MARKUP_FULL))); - g_free(ptr); - ASSERT_STR_EQ("test ", (ptr=markup_transform(g_strdup("test \"foo image"), MARKUP_FULL))); - g_free(ptr); - ASSERT_STR_EQ("bar baz", (ptr=markup_transform(g_strdup("bar baz"), MARKUP_FULL))); - g_free(ptr); - - ASSERT_STR_EQ("Ψ", (ptr=markup_transform(g_strdup("Ψ"), MARKUP_FULL))); - free(ptr); - ASSERT_STR_EQ("Ψ Ψ", (ptr=markup_transform(g_strdup("Ψ Ψ"), MARKUP_FULL))); - free(ptr); - ASSERT_STR_EQ("> <", (ptr=markup_transform(g_strdup("> <"), MARKUP_FULL))); - free(ptr); - ASSERT_STR_EQ("&invalid; &#abc; &#xG;", (ptr=markup_transform(g_strdup("&invalid; &#abc; &#xG;"), MARKUP_FULL))); - free(ptr); - ASSERT_STR_EQ("&; &#; &#x;", (ptr=markup_transform(g_strdup("&; &#; &#x;"), MARKUP_FULL))); - free(ptr); - - PASS(); + char *ptr; + + settings.ignore_newline = false; + ASSERT_STR_EQ("<i>foo</i><br>bar\nbaz", + (ptr = markup_transform(g_strdup("foo
bar\nbaz"), + MARKUP_NO))); + g_free(ptr); + ASSERT_STR_EQ("foo\nbar\nbaz", + (ptr = markup_transform(g_strdup("foo
bar\nbaz"), + MARKUP_STRIP))); + g_free(ptr); + ASSERT_STR_EQ("foo\nbar\nbaz", + (ptr = markup_transform(g_strdup("foo
bar\nbaz"), + MARKUP_FULL))); + g_free(ptr); + + settings.ignore_newline = true; + ASSERT_STR_EQ("<i>foo</i><br>bar baz", + (ptr = markup_transform(g_strdup("foo
bar\nbaz"), + MARKUP_NO))); + g_free(ptr); + ASSERT_STR_EQ("foo bar baz", + (ptr = markup_transform(g_strdup("foo
bar\nbaz"), + MARKUP_STRIP))); + g_free(ptr); + ASSERT_STR_EQ("foo bar baz", + (ptr = markup_transform(g_strdup("foo
bar\nbaz"), + MARKUP_FULL))); + g_free(ptr); + + // Test replacement of img and a tags, not renderable by pango + ASSERT_STR_EQ( + "foo bar bar baz", + (ptr = markup_transform(g_strdup("\"foo
bar\nbaz"), + MARKUP_FULL))); + g_free(ptr); + ASSERT_STR_EQ("test ", + (ptr = markup_transform(g_strdup("test \"foo image"), MARKUP_FULL))); + g_free(ptr); + ASSERT_STR_EQ("bar baz", + (ptr = markup_transform( + g_strdup("bar baz"), MARKUP_FULL))); + g_free(ptr); + + ASSERT_STR_EQ("Ψ", + (ptr = markup_transform(g_strdup("Ψ"), MARKUP_FULL))); + free(ptr); + ASSERT_STR_EQ( + "Ψ Ψ", + (ptr = markup_transform(g_strdup("Ψ Ψ"), MARKUP_FULL))); + free(ptr); + ASSERT_STR_EQ("> <", + (ptr = markup_transform(g_strdup("> <"), MARKUP_FULL))); + free(ptr); + ASSERT_STR_EQ("&invalid; &#abc; &#xG;", + (ptr = markup_transform(g_strdup("&invalid; &#abc; &#xG;"), + MARKUP_FULL))); + free(ptr); + ASSERT_STR_EQ( + "&; &#; &#x;", + (ptr = markup_transform(g_strdup("&; &#; &#x;"), MARKUP_FULL))); + free(ptr); + + PASS(); } -TEST helper_markup_strip_a (const char *in, const char *exp, const char *urls) +TEST helper_markup_strip_a(const char *in, const char *exp, const char *urls) { - // out_urls is a return parameter and the content should be ignored - char *out_urls = (char *)0x04; //Chosen by a fair dice roll - char *out = g_strdup(in); - char *msg = g_strconcat("url: ", in, NULL); + // out_urls is a return parameter and the content should be ignored + char *out_urls = (char *)0x04; // Chosen by a fair dice roll + char *out = g_strdup(in); + char *msg = g_strconcat("url: ", in, NULL); - markup_strip_a(&out, &out_urls); + markup_strip_a(&out, &out_urls); - ASSERT_STR_EQm(msg, exp, out); + ASSERT_STR_EQm(msg, exp, out); - if (urls) { - ASSERT_STR_EQm(msg, urls, out_urls); - } else { - ASSERT_EQm(msg, urls, out_urls); - } + if (urls) { + ASSERT_STR_EQm(msg, urls, out_urls); + } else { + ASSERT_EQm(msg, urls, out_urls); + } - g_free(out_urls); - g_free(out); - g_free(msg); + g_free(out_urls); + g_free(out); + g_free(msg); - PASS(); + PASS(); } SUITE(test_markup_strip_a_suite) { - RUN_TESTp(helper_markup_strip_a, "valid link", "valid link", "[valid] https://url.com"); - RUN_TESTp(helper_markup_strip_a, "valid link", "valid link", "[valid] "); - RUN_TESTp(helper_markup_strip_a, "valid link", "valid link", NULL); - RUN_TESTp(helper_markup_strip_a, "valid link", "valid link", "[valid link] https://url.com"); - - RUN_TESTp(helper_markup_strip_a, " link", " link", NULL); - RUN_TESTp(helper_markup_strip_a, " link", " link", NULL); + RUN_TESTp(helper_markup_strip_a, + "valid link", + "valid link", + "[valid] https://url.com"); + RUN_TESTp(helper_markup_strip_a, + "valid link", + "valid link", + "[valid] "); + RUN_TESTp(helper_markup_strip_a, "valid link", "valid link", NULL); + RUN_TESTp(helper_markup_strip_a, + "valid link", + "valid link", + "[valid link] https://url.com"); + + RUN_TESTp(helper_markup_strip_a, + " link", + " link", + NULL); + RUN_TESTp(helper_markup_strip_a, " link", " link", NULL); } -TEST helper_markup_strip_img (const char *in, const char *exp, const char *urls) +TEST helper_markup_strip_img(const char *in, const char *exp, const char *urls) { - // out_urls is a return parameter and the content should be ignored - char *out_urls = (char *)0x04; //Chosen by a fair dice roll - char *out = g_strdup(in); - char *msg = g_strconcat("url: ", in, NULL); + // out_urls is a return parameter and the content should be ignored + char *out_urls = (char *)0x04; // Chosen by a fair dice roll + char *out = g_strdup(in); + char *msg = g_strconcat("url: ", in, NULL); - markup_strip_img(&out, &out_urls); + markup_strip_img(&out, &out_urls); - ASSERT_STR_EQm(msg, exp, out); + ASSERT_STR_EQm(msg, exp, out); - if (urls) { - ASSERT_STR_EQm(msg, urls, out_urls); - } else { - ASSERT_EQm(msg, urls, out_urls); - } + if (urls) { + ASSERT_STR_EQm(msg, urls, out_urls); + } else { + ASSERT_EQm(msg, urls, out_urls); + } - g_free(out_urls); - g_free(out); - g_free(msg); + g_free(out_urls); + g_free(out); + g_free(msg); - PASS(); + PASS(); } SUITE(test_markup_strip_img_suite) { - RUN_TESTp(helper_markup_strip_img, "v img", "v [image] img", NULL); - RUN_TESTp(helper_markup_strip_img, "v \"valid\" img", "v valid img", NULL); - RUN_TESTp(helper_markup_strip_img, "v img", "v [image] img", "[image] url.com"); - - RUN_TESTp(helper_markup_strip_img, "v \"valid\" img", "v valid img", "[valid] url.com"); - RUN_TESTp(helper_markup_strip_img, "v \"valid\" img", "v valid img", "[valid] url.com"); - RUN_TESTp(helper_markup_strip_img, "v \"valid\" img", "v valid img", "[valid] url.com"); - - RUN_TESTp(helper_markup_strip_img, "i \"invalid img", "i [image] img", "[image] https://url.com"); - RUN_TESTp(helper_markup_strip_img, "i \"broken\" img", "i broken img", NULL); - RUN_TESTp(helper_markup_strip_img, "i \"invalid img", "i [image] img", NULL); - - RUN_TESTp(helper_markup_strip_img, "i \"broken\" img", "i broken img", NULL); - RUN_TESTp(helper_markup_strip_img, "i \"invalid img", "i [image] img", "[image] url.com"); - RUN_TESTp(helper_markup_strip_img, "i \"invalid img", "i [image] img", NULL); - - RUN_TESTp(helper_markup_strip_img, "i \"invalid\" img", "v [image] img", NULL); + RUN_TESTp(helper_markup_strip_img, + "v \"valid\" img", + "v valid img", + NULL); + RUN_TESTp(helper_markup_strip_img, + "v img", + "v [image] img", + "[image] url.com"); + + RUN_TESTp(helper_markup_strip_img, + "v \"valid\" img", + "v valid img", + "[valid] url.com"); + RUN_TESTp(helper_markup_strip_img, + "v \"valid\" img", + "v valid img", + "[valid] url.com"); + RUN_TESTp(helper_markup_strip_img, + "v \"valid\" img", + "v valid img", + "[valid] url.com"); + + RUN_TESTp(helper_markup_strip_img, + "i \"invalid img", + "i [image] img", + "[image] https://url.com"); + RUN_TESTp(helper_markup_strip_img, + "i \"broken\" img", + "i broken img", + NULL); + RUN_TESTp(helper_markup_strip_img, + "i \"invalid img", + "i [image] img", + NULL); + + RUN_TESTp(helper_markup_strip_img, + "i \"broken\" img", + "i broken img", + NULL); + RUN_TESTp(helper_markup_strip_img, + "i \"invalid img", + "i [image] img", + "[image] url.com"); + RUN_TESTp(helper_markup_strip_img, + "i \"invalid img", + "i [image] img", + NULL); + + RUN_TESTp(helper_markup_strip_img, + "i \"invalid\"appname = g_strdup("Test"); - a->summary = g_strdup("Summary"); - a->body = g_strdup("Body"); - a->iconname = g_strdup("Icon"); - a->icon_id = g_strdup("Icon"); - a->urgency = URG_NORM; - - struct notification *b = notification_create(); - b->appname = g_strdup("Test"); - b->summary = g_strdup("Summary"); - b->body = g_strdup("Body"); - b->iconname = g_strdup("Icon"); - b->icon_id = g_strdup("Icon"); - b->urgency = URG_NORM; - - ASSERT(notification_is_duplicate(a, b)); - - CHECK_CALL(test_notification_is_duplicate_field(&(b->appname), a, b)); - CHECK_CALL(test_notification_is_duplicate_field(&(b->summary), a, b)); - CHECK_CALL(test_notification_is_duplicate_field(&(b->body), a, b)); - - ASSERTm("One of the notifications got corrupted during test", - notification_is_duplicate(a, b)); - - enum icon_position icon_setting_tmp = a->icon_position; - - a->icon_position = ICON_OFF; - ASSERT(notification_is_duplicate(a, b)); - //Setting pointer to a random value since we are checking for null - char *icon_id = b->icon_id; - b->icon_id = "false"; - ASSERTm("Icons have to get ignored for duplicate check when icons are off", - notification_is_duplicate(a, b)); - b->icon_id = icon_id; - - a->icon_position = ICON_LEFT; - b->icon_position = ICON_LEFT; - CHECK_CALL(test_notification_is_duplicate_field(&(b->icon_id), a, b)); - - a->icon_position = ICON_RIGHT; - b->icon_position = ICON_RIGHT; - CHECK_CALL(test_notification_is_duplicate_field(&(b->icon_id), a, b)); - - a->icon_position = icon_setting_tmp; - - ASSERT(notification_is_duplicate(a, b)); - - b->urgency = URG_LOW; - ASSERT_FALSE(notification_is_duplicate(a, b)); - b->urgency = URG_NORM; - ASSERT(notification_is_duplicate(a, b)); - b->urgency = URG_CRIT; - ASSERT_FALSE(notification_is_duplicate(a, b)); - - notification_unref(a); - notification_unref(b); - PASS(); + struct notification *a = notification_create(); + a->appname = g_strdup("Test"); + a->summary = g_strdup("Summary"); + a->body = g_strdup("Body"); + a->iconname = g_strdup("Icon"); + a->icon_id = g_strdup("Icon"); + a->urgency = URG_NORM; + + struct notification *b = notification_create(); + b->appname = g_strdup("Test"); + b->summary = g_strdup("Summary"); + b->body = g_strdup("Body"); + b->iconname = g_strdup("Icon"); + b->icon_id = g_strdup("Icon"); + b->urgency = URG_NORM; + + ASSERT(notification_is_duplicate(a, b)); + + CHECK_CALL(test_notification_is_duplicate_field(&(b->appname), a, b)); + CHECK_CALL(test_notification_is_duplicate_field(&(b->summary), a, b)); + CHECK_CALL(test_notification_is_duplicate_field(&(b->body), a, b)); + + ASSERTm("One of the notifications got corrupted during test", + notification_is_duplicate(a, b)); + + enum icon_position icon_setting_tmp = a->icon_position; + + a->icon_position = ICON_OFF; + ASSERT(notification_is_duplicate(a, b)); + // Setting pointer to a random value since we are checking for null + char *icon_id = b->icon_id; + b->icon_id = "false"; + ASSERTm("Icons have to get ignored for duplicate check when icons are off", + notification_is_duplicate(a, b)); + b->icon_id = icon_id; + + a->icon_position = ICON_LEFT; + b->icon_position = ICON_LEFT; + CHECK_CALL(test_notification_is_duplicate_field(&(b->icon_id), a, b)); + + a->icon_position = ICON_RIGHT; + b->icon_position = ICON_RIGHT; + CHECK_CALL(test_notification_is_duplicate_field(&(b->icon_id), a, b)); + + a->icon_position = icon_setting_tmp; + + ASSERT(notification_is_duplicate(a, b)); + + b->urgency = URG_LOW; + ASSERT_FALSE(notification_is_duplicate(a, b)); + b->urgency = URG_NORM; + ASSERT(notification_is_duplicate(a, b)); + b->urgency = URG_CRIT; + ASSERT_FALSE(notification_is_duplicate(a, b)); + + notification_unref(a); + notification_unref(b); + PASS(); } TEST test_notification_replace_single_field(void) { - char *str = g_malloc(128 * sizeof(char)); - char *substr = NULL; - - strcpy(str, "Markup %a preserved"); - substr = strchr(str, '%'); - notification_replace_single_field(&str, &substr, "and & is", MARKUP_FULL); - ASSERT_STR_EQ("Markup and & is preserved", str); - ASSERT_EQ(26, substr - str); - - strcpy(str, "Markup %a escaped"); - substr = strchr(str, '%'); - notification_replace_single_field(&str, &substr, "and & is", MARKUP_NO); - ASSERT_STR_EQ("Markup and & <i>is</i> escaped", str); - ASSERT_EQ(38, substr - str); - - strcpy(str, "Markup %a"); - substr = strchr(str, '%'); - notification_replace_single_field(&str, &substr, "is removed and & escaped", MARKUP_STRIP); - ASSERT_STR_EQ("Markup is removed and & escaped", str); - ASSERT_EQ(35, substr - str); - - g_free(str); - PASS(); + char *str = g_malloc(128 * sizeof(char)); + char *substr = NULL; + + strcpy(str, "Markup %a preserved"); + substr = strchr(str, '%'); + notification_replace_single_field( + &str, &substr, "and & is", MARKUP_FULL); + ASSERT_STR_EQ("Markup and & is preserved", str); + ASSERT_EQ(26, substr - str); + + strcpy(str, "Markup %a escaped"); + substr = strchr(str, '%'); + notification_replace_single_field( + &str, &substr, "and & is", MARKUP_NO); + ASSERT_STR_EQ("Markup and & <i>is</i> escaped", str); + ASSERT_EQ(38, substr - str); + + strcpy(str, "Markup %a"); + substr = strchr(str, '%'); + notification_replace_single_field( + &str, &substr, "is removed and & escaped", MARKUP_STRIP); + ASSERT_STR_EQ("Markup is removed and & escaped", str); + ASSERT_EQ(35, substr - str); + + g_free(str); + PASS(); } TEST test_notification_referencing(void) { - struct notification *n = notification_create(); - ASSERT(notification_refcount_get(n) == 1); + struct notification *n = notification_create(); + ASSERT(notification_refcount_get(n) == 1); - notification_ref(n); - ASSERT(notification_refcount_get(n) == 2); + notification_ref(n); + ASSERT(notification_refcount_get(n) == 2); - notification_unref(n); - ASSERT(notification_refcount_get(n) == 1); + notification_unref(n); + ASSERT(notification_refcount_get(n) == 1); - // Now we have to rely on valgrind to test, that - // it gets actually freed - notification_unref(n); + // Now we have to rely on valgrind to test, that + // it gets actually freed + notification_unref(n); - PASS(); + PASS(); } -static struct notification *notification_load_icon_with_scaling(int min_icon_size, int max_icon_size) +static struct notification * +notification_load_icon_with_scaling(int min_icon_size, int max_icon_size) { - static bool svg_failed = false; + static bool svg_failed = false; - struct notification *n = notification_create(); + struct notification *n = notification_create(); - char *path; - GVariant *raw_icon = NULL; + char *path; + GVariant *raw_icon = NULL; - if (!svg_failed) { - path = g_strconcat(base, "/data/icons/valid.svg", NULL); // 16x16 - raw_icon = notification_setup_raw_image(path); - - if (raw_icon == NULL) { - svg_failed = true; - printf("Failed to load svg icon, using png\n"); - g_free(path); - } - } + if (!svg_failed) { + path = g_strconcat(base, "/data/icons/valid.svg", NULL); // 16x16 + raw_icon = notification_setup_raw_image(path); if (raw_icon == NULL) { - path = g_strconcat(base, "/data/icons/valid.png", NULL); // 16x16 - raw_icon = notification_setup_raw_image(path); + svg_failed = true; + printf("Failed to load svg icon, using png\n"); + g_free(path); } + } + + if (raw_icon == NULL) { + path = g_strconcat(base, "/data/icons/valid.png", NULL); // 16x16 + raw_icon = notification_setup_raw_image(path); + } - n->min_icon_size = min_icon_size; - n->max_icon_size = max_icon_size; - notification_icon_replace_data(n, raw_icon); + n->min_icon_size = min_icon_size; + n->max_icon_size = max_icon_size; + notification_icon_replace_data(n, raw_icon); - g_variant_unref(raw_icon); - g_free(path); + g_variant_unref(raw_icon); + g_free(path); - return n; + return n; } TEST test_notification_icon_scaling_toosmall(void) { - struct notification *n = notification_load_icon_with_scaling(20, 100); + struct notification *n = notification_load_icon_with_scaling(20, 100); - ASSERT(n->icon); - ASSERT_EQ(get_icon_width(n->icon, 1), 20); - ASSERT_EQ(get_icon_height(n->icon, 1), 20); + ASSERT(n->icon); + ASSERT_EQ(get_icon_width(n->icon, 1), 20); + ASSERT_EQ(get_icon_height(n->icon, 1), 20); - notification_unref(n); + notification_unref(n); - PASS(); + PASS(); } - TEST test_notification_icon_scaling_toolarge(void) { - struct notification *n = notification_load_icon_with_scaling(5, 10); + struct notification *n = notification_load_icon_with_scaling(5, 10); - ASSERT(n->icon); - ASSERT_EQ(get_icon_width(n->icon, 1), 10); - ASSERT_EQ(get_icon_height(n->icon, 1), 10); + ASSERT(n->icon); + ASSERT_EQ(get_icon_width(n->icon, 1), 10); + ASSERT_EQ(get_icon_height(n->icon, 1), 10); - notification_unref(n); + notification_unref(n); - PASS(); + PASS(); } TEST test_notification_icon_scaling_notconfigured(void) { - struct notification *n = notification_load_icon_with_scaling(0, 0); + struct notification *n = notification_load_icon_with_scaling(0, 0); - ASSERT(n->icon); - ASSERT_EQ(get_icon_width(n->icon, 1), 16); - ASSERT_EQ(get_icon_height(n->icon, 1), 16); + ASSERT(n->icon); + ASSERT_EQ(get_icon_width(n->icon, 1), 16); + ASSERT_EQ(get_icon_height(n->icon, 1), 16); - notification_unref(n); + notification_unref(n); - PASS(); + PASS(); } TEST test_notification_icon_scaling_notneeded(void) { - struct notification *n = notification_load_icon_with_scaling(10, 20); + struct notification *n = notification_load_icon_with_scaling(10, 20); - ASSERT(n->icon); - ASSERT_EQ(get_icon_width(n->icon, 1), 16); - ASSERT_EQ(get_icon_height(n->icon, 1), 16); + ASSERT(n->icon); + ASSERT_EQ(get_icon_width(n->icon, 1), 16); + ASSERT_EQ(get_icon_height(n->icon, 1), 16); - notification_unref(n); + notification_unref(n); - PASS(); + PASS(); } -TEST test_notification_format_message(struct notification *n, const char *format, const char *exp) +TEST test_notification_format_message(struct notification *n, + const char *format, + const char *exp) { - notification_replace_format(n, format); - notification_format_message(n); + notification_replace_format(n, format); + notification_format_message(n); - ASSERT_STR_EQ(exp, n->msg); + ASSERT_STR_EQ(exp, n->msg); - PASS(); + PASS(); } TEST test_notification_maxlength(void) { - unsigned int len = 5005; - struct notification *n = notification_create(); - notification_replace_format(n, "%a"); + unsigned int len = 5005; + struct notification *n = notification_create(); + notification_replace_format(n, "%a"); - n->appname = g_malloc(len + 1); - n->appname[len] = '\0'; + n->appname = g_malloc(len + 1); + n->appname[len] = '\0'; - static const char sigma[] = - " 0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; - for (size_t i = 0; i < len; ++i) - n->appname[i] = sigma[rand() % (sizeof(sigma) - 1)]; + static const char sigma[] = " 0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + for (size_t i = 0; i < len; ++i) + n->appname[i] = sigma[rand() % (sizeof(sigma) - 1)]; - notification_format_message(n); - ASSERT(STRN_EQ(n->appname, n->msg, 5000)); + notification_format_message(n); + ASSERT(STRN_EQ(n->appname, n->msg, 5000)); - notification_unref(n); - PASS(); + notification_unref(n); + PASS(); } - SUITE(suite_notification) { - cmdline_load(0, NULL); - - RUN_TEST(test_notification_is_duplicate); - RUN_TEST(test_notification_replace_single_field); - RUN_TEST(test_notification_referencing); - RUN_TEST(test_notification_icon_scaling_toosmall); - RUN_TEST(test_notification_icon_scaling_toolarge); - RUN_TEST(test_notification_icon_scaling_notconfigured); - RUN_TEST(test_notification_icon_scaling_notneeded); - - // TEST notification_format_message - struct notification *a = notification_create(); - a->appname = g_strdup("MyApp"); - a->summary = g_strdup("I've got a summary!"); - a->body = g_strdup("Look at my shiny "); - a->iconname = g_strdup("/this/is/my/icoknpath.png"); - a->progress = 95; - - const char *strings[] = { - "%a", "MyApp", - "%s", "I've got a summary!", - "%b", "Look at my shiny ", - "%I", "icoknpath.png", - "%i", "/this/is/my/icoknpath.png", - "%p", "[ 95%]", - "%n", "95", - "%%", "%", - "%", "%", - "%UNKNOWN", "%UNKNOWN", - NULL - }; - - const char **in = strings; - const char **out = strings+1; - while (*in && *out) { - RUN_TESTp(test_notification_format_message, a, *in, *out); - in +=2; - out+=2; - } - g_clear_pointer(&a, notification_unref); - - RUN_TEST(test_notification_maxlength); + cmdline_load(0, NULL); + + RUN_TEST(test_notification_is_duplicate); + RUN_TEST(test_notification_replace_single_field); + RUN_TEST(test_notification_referencing); + RUN_TEST(test_notification_icon_scaling_toosmall); + RUN_TEST(test_notification_icon_scaling_toolarge); + RUN_TEST(test_notification_icon_scaling_notconfigured); + RUN_TEST(test_notification_icon_scaling_notneeded); + + // TEST notification_format_message + struct notification *a = notification_create(); + a->appname = g_strdup("MyApp"); + a->summary = g_strdup("I've got a summary!"); + a->body = g_strdup("Look at my shiny "); + a->iconname = g_strdup("/this/is/my/icoknpath.png"); + a->progress = 95; + + const char *strings[] = {"%a", "MyApp", + "%s", "I've got a summary!", + "%b", "Look at my shiny ", + "%I", "icoknpath.png", + "%i", "/this/is/my/icoknpath.png", + "%p", "[ 95%]", + "%n", "95", + "%%", "%", + "%", "%", + "%UNKNOWN", "%UNKNOWN", + NULL}; + + const char **in = strings; + const char **out = strings + 1; + while (*in && *out) { + RUN_TESTp(test_notification_format_message, a, *in, *out); + in += 2; + out += 2; + } + g_clear_pointer(&a, notification_unref); + + RUN_TEST(test_notification_maxlength); } /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/test/option_parser.c b/test/option_parser.c index a8d1a18cf..7946e8bb3 100644 --- a/test/option_parser.c +++ b/test/option_parser.c @@ -1,1073 +1,1106 @@ #include "../src/option_parser.c" #include "greatest.h" -#define ARRAY_SAME_LENGTH(a, b) { \ - ASSERT_EQm("Test is invalid. Input data has to be the same length",\ - G_N_ELEMENTS(a), G_N_ELEMENTS(b));\ -} - -enum greatest_test_res ARRAY_EQ(char **a, char **b){ - ASSERT(a); - ASSERT(b); - int i = 0; - while (a[i] && b[i]) { - ASSERT_STR_EQ(a[i], b[i]); - i++; - } - ASSERT_FALSE(a[i]); - ASSERT_FALSE(b[i]); - PASS(); +#define ARRAY_SAME_LENGTH(a, b) \ + { \ + ASSERT_EQm("Test is invalid. Input data has to be the same length", \ + G_N_ELEMENTS(a), \ + G_N_ELEMENTS(b)); \ + } + +enum greatest_test_res ARRAY_EQ(char **a, char **b) +{ + ASSERT(a); + ASSERT(b); + int i = 0; + while (a[i] && b[i]) { + ASSERT_STR_EQ(a[i], b[i]); + i++; + } + ASSERT_FALSE(a[i]); + ASSERT_FALSE(b[i]); + PASS(); } TEST test_cmdline_get_path(void) { - char *ptr, *exp; - char *home = getenv("HOME"); - - // return default, if nonexistent key - ASSERT_EQ(NULL, (ptr = cmdline_get_path("-nonexistent", NULL, "desc"))); - ASSERT_STR_EQ("default", (ptr = cmdline_get_path("-nonexistent", "default", "desc"))); - g_free(ptr); - - // return path with replaced home - ASSERT_STR_EQ((exp = g_strconcat(home, "/path/from/cmdline", NULL)), - (ptr = cmdline_get_path("-path", NULL, "desc"))); - g_free(ptr); - g_free(exp); - - PASS(); + char *ptr, *exp; + char *home = getenv("HOME"); + + // return default, if nonexistent key + ASSERT_EQ(NULL, (ptr = cmdline_get_path("-nonexistent", NULL, "desc"))); + ASSERT_STR_EQ("default", + (ptr = cmdline_get_path("-nonexistent", "default", "desc"))); + g_free(ptr); + + // return path with replaced home + ASSERT_STR_EQ((exp = g_strconcat(home, "/path/from/cmdline", NULL)), + (ptr = cmdline_get_path("-path", NULL, "desc"))); + g_free(ptr); + g_free(exp); + + PASS(); } TEST test_cmdline_get_string(void) { - char *ptr; - ASSERT_STR_EQ("A simple string from the cmdline", (ptr =cmdline_get_string("-string", "", ""))); - free(ptr); - ASSERT_STR_EQ("Single_word_string", (ptr = cmdline_get_string("-str/-s", "", ""))); - free(ptr); - ASSERT_STR_EQ("Default", (ptr = cmdline_get_string("-nonexistent", "Default", ""))); - free(ptr); - PASS(); + char *ptr; + ASSERT_STR_EQ("A simple string from the cmdline", + (ptr = cmdline_get_string("-string", "", ""))); + free(ptr); + ASSERT_STR_EQ("Single_word_string", + (ptr = cmdline_get_string("-str/-s", "", ""))); + free(ptr); + ASSERT_STR_EQ("Default", + (ptr = cmdline_get_string("-nonexistent", "Default", ""))); + free(ptr); + PASS(); } TEST test_cmdline_get_list(void) { - char **ptr; - char *cmp1[] = {"A", "simple", "list", "from", "the", "cmdline", NULL}; - char *cmp2[] = {"A", "list", "with", "spaces", NULL}; - char *cmp3[] = {"A", "default", "list", NULL}; - - CHECK_CALL(ARRAY_EQ(cmp1, (ptr = cmdline_get_list("-list", "", "")))); - g_strfreev(ptr); - CHECK_CALL(ARRAY_EQ(cmp2, (ptr = cmdline_get_list("-list2", "", "")))); - g_strfreev(ptr); - CHECK_CALL(ARRAY_EQ(cmp3, (ptr = cmdline_get_list("-nonexistent", "A, default, list", "")))); - g_strfreev(ptr); - PASS(); + char **ptr; + char *cmp1[] = {"A", "simple", "list", "from", "the", "cmdline", NULL}; + char *cmp2[] = {"A", "list", "with", "spaces", NULL}; + char *cmp3[] = {"A", "default", "list", NULL}; + + CHECK_CALL(ARRAY_EQ(cmp1, (ptr = cmdline_get_list("-list", "", "")))); + g_strfreev(ptr); + CHECK_CALL(ARRAY_EQ(cmp2, (ptr = cmdline_get_list("-list2", "", "")))); + g_strfreev(ptr); + CHECK_CALL(ARRAY_EQ( + cmp3, + (ptr = cmdline_get_list("-nonexistent", "A, default, list", "")))); + g_strfreev(ptr); + PASS(); } TEST test_cmdline_get_int(void) { - ASSERT_EQ(3, cmdline_get_int("-int", 0, "")); - ASSERT_EQ(2, cmdline_get_int("-int2/-i", 0, "")); - ASSERT_EQ(-7, cmdline_get_int("-negative", 0, "")); - ASSERT_EQ(4, cmdline_get_int("-zeroes", 0, "")); - ASSERT_EQ(2, cmdline_get_int("-intdecim", 0, "")); - ASSERT_EQ(10, cmdline_get_int("-nonexistent", 10, "")); - PASS(); + ASSERT_EQ(3, cmdline_get_int("-int", 0, "")); + ASSERT_EQ(2, cmdline_get_int("-int2/-i", 0, "")); + ASSERT_EQ(-7, cmdline_get_int("-negative", 0, "")); + ASSERT_EQ(4, cmdline_get_int("-zeroes", 0, "")); + ASSERT_EQ(2, cmdline_get_int("-intdecim", 0, "")); + ASSERT_EQ(10, cmdline_get_int("-nonexistent", 10, "")); + PASS(); } TEST test_cmdline_get_double(void) { - if (2.3 != atof("2.3")) { - SKIPm("Skipping test_cmdline_get_double, as it seems we're running under musl+valgrind!"); - } - - ASSERT_EQ(2, cmdline_get_double("-simple_double", 0, "")); - ASSERT_EQ(5.2, cmdline_get_double("-double", 0, "")); - ASSERT_EQ(3.14, cmdline_get_double("-nonexistent", 3.14, "")); - PASS(); + if (2.3 != atof("2.3")) { + SKIPm("Skipping test_cmdline_get_double, as it seems we're running " + "under musl+valgrind!"); + } + + ASSERT_EQ(2, cmdline_get_double("-simple_double", 0, "")); + ASSERT_EQ(5.2, cmdline_get_double("-double", 0, "")); + ASSERT_EQ(3.14, cmdline_get_double("-nonexistent", 3.14, "")); + PASS(); } TEST test_cmdline_get_bool(void) { - ASSERT(cmdline_get_bool("-bool", false, "")); - ASSERT(cmdline_get_bool("-shortbool/-b", false, "")); - ASSERT(cmdline_get_bool("-boolnd/-n", true, "")); - ASSERT_FALSE(cmdline_get_bool("-boolnd/-n", false, "")); - PASS(); + ASSERT(cmdline_get_bool("-bool", false, "")); + ASSERT(cmdline_get_bool("-shortbool/-b", false, "")); + ASSERT(cmdline_get_bool("-boolnd/-n", true, "")); + ASSERT_FALSE(cmdline_get_bool("-boolnd/-n", false, "")); + PASS(); } TEST test_cmdline_create_usage(void) { - g_free(cmdline_get_string("-msgstring/-ms", "", "A string to test usage creation")); - cmdline_get_int("-msgint/-mi", 0, "An int to test usage creation"); - cmdline_get_double("-msgdouble/-md", 0, "A double to test usage creation"); - cmdline_get_bool("-msgbool/-mb", false, "A bool to test usage creation"); - const char *usage = cmdline_create_usage(); - ASSERT(strstr(usage, "-msgstring/-ms")); - ASSERT(strstr(usage, "A string to test usage creation")); - ASSERT(strstr(usage, "-msgint/-mi")); - ASSERT(strstr(usage, "An int to test usage creation")); - ASSERT(strstr(usage, "-msgdouble/-md")); - ASSERT(strstr(usage, "A double to test usage creation")); - ASSERT(strstr(usage, "-msgbool/-mb")); - ASSERT(strstr(usage, "A bool to test usage creation")); - PASS(); + g_free(cmdline_get_string( + "-msgstring/-ms", "", "A string to test usage creation")); + cmdline_get_int("-msgint/-mi", 0, "An int to test usage creation"); + cmdline_get_double("-msgdouble/-md", 0, "A double to test usage creation"); + cmdline_get_bool("-msgbool/-mb", false, "A bool to test usage creation"); + const char *usage = cmdline_create_usage(); + ASSERT(strstr(usage, "-msgstring/-ms")); + ASSERT(strstr(usage, "A string to test usage creation")); + ASSERT(strstr(usage, "-msgint/-mi")); + ASSERT(strstr(usage, "An int to test usage creation")); + ASSERT(strstr(usage, "-msgdouble/-md")); + ASSERT(strstr(usage, "A double to test usage creation")); + ASSERT(strstr(usage, "-msgbool/-mb")); + ASSERT(strstr(usage, "A bool to test usage creation")); + PASS(); } TEST test_string_to_int(void) { - int val = -123; - const char* inputs[] = { - "0", - "1", - "-1", - "12345678", - "-12345678" - }; - const int results[] = { - 0, - 1, - -1, - 12345678, - -12345678 - }; - - ARRAY_SAME_LENGTH(inputs, results); - - struct setting s; - s.type = TYPE_INT; - - static char buf[50]; - for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { - sprintf(buf, "Failed in round %zu", i); - ASSERTm(buf, set_from_string(&val, s, inputs[i])); - ASSERT_EQm(buf, val, results[i]); - } - PASS(); + int val = -123; + const char *inputs[] = {"0", "1", "-1", "12345678", "-12345678"}; + const int results[] = {0, 1, -1, 12345678, -12345678}; + + ARRAY_SAME_LENGTH(inputs, results); + + struct setting s; + s.type = TYPE_INT; + + static char buf[50]; + for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { + sprintf(buf, "Failed in round %zu", i); + ASSERTm(buf, set_from_string(&val, s, inputs[i])); + ASSERT_EQm(buf, val, results[i]); + } + PASS(); } TEST test_string_to_int_invalid(void) { - int val = -123; - const char* inputs[] = { - "a0", - "something", - "x674asdf", - "-dsf4544asdf", - "0x145", - "64a567", - "(5678)", - "5678)", - }; - - struct setting s; - s.type = TYPE_INT; - s.name = "test_int"; - - static char buf[50]; - for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { - sprintf(buf, "Failed in round %zu", i); - ASSERT_FALSEm(buf, set_from_string(&val, s, inputs[i])); - } - ASSERT_EQm("Value should not be changed for invalid ints", val, -123); - PASS(); + int val = -123; + const char *inputs[] = { + "a0", + "something", + "x674asdf", + "-dsf4544asdf", + "0x145", + "64a567", + "(5678)", + "5678)", + }; + + struct setting s; + s.type = TYPE_INT; + s.name = "test_int"; + + static char buf[50]; + for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { + sprintf(buf, "Failed in round %zu", i); + ASSERT_FALSEm(buf, set_from_string(&val, s, inputs[i])); + } + ASSERT_EQm("Value should not be changed for invalid ints", val, -123); + PASS(); } TEST test_string_to_double(void) { - if (2.3 != atof("2.3")) { - SKIPm("Skipping test_string_to_double, as it seems we're running under musl+valgrind!"); - } - - double val = -100.0; - const char* inputs[] = { - "0", - "1", - "-1", - "45.8", - "-45.8" - }; - const double results[] = { - 0, - 1, - -1, - 45.8, - -45.8 - }; - struct setting s; - s.type = TYPE_DOUBLE; - - static char buf[50]; - for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { - sprintf(buf, "Failed in round %zu", i); - ASSERTm(buf, set_from_string(&val, s, inputs[i])); - ASSERT_EQm(buf, val, results[i]); - } - PASS(); + if (2.3 != atof("2.3")) { + SKIPm("Skipping test_string_to_double, as it seems we're running under " + "musl+valgrind!"); + } + + double val = -100.0; + const char *inputs[] = {"0", "1", "-1", "45.8", "-45.8"}; + const double results[] = {0, 1, -1, 45.8, -45.8}; + struct setting s; + s.type = TYPE_DOUBLE; + + static char buf[50]; + for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { + sprintf(buf, "Failed in round %zu", i); + ASSERTm(buf, set_from_string(&val, s, inputs[i])); + ASSERT_EQm(buf, val, results[i]); + } + PASS(); } TEST test_string_to_double_invalid(void) { - double val = -100.0; - const char* inputs[] = { - "a0", - "something", - "x1234asdf", - "-dsf1234asdf", - "1234a567", - "12.34a567", - "56.7.1", - }; - - struct setting s; - s.type = TYPE_DOUBLE; - s.name = "test_double"; - - static char buf[50]; - for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { - sprintf(buf, "Failed in round %zu", i); - ASSERT_FALSEm(buf, set_from_string(&val, s, inputs[i])); - } - ASSERT_EQm("Value should not be changed for invalid doubles", val, -100.0); - PASS(); + double val = -100.0; + const char *inputs[] = { + "a0", + "something", + "x1234asdf", + "-dsf1234asdf", + "1234a567", + "12.34a567", + "56.7.1", + }; + + struct setting s; + s.type = TYPE_DOUBLE; + s.name = "test_double"; + + static char buf[50]; + for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { + sprintf(buf, "Failed in round %zu", i); + ASSERT_FALSEm(buf, set_from_string(&val, s, inputs[i])); + } + ASSERT_EQm("Value should not be changed for invalid doubles", val, -100.0); + PASS(); } TEST test_string_to_boolean(void) { - bool val; - - struct setting s; - s.type = TYPE_CUSTOM; - s.parser = string_parse_bool; - s.parser_data = boolean_enum_data; - s.value = &val; - - const char* inputs[] = { - "0", - "1", - "true", - "True", - "false", - "off" - }; - const int results[] = { - 0, - 1, - 1, - 1, - 0, - 0 - }; - - ARRAY_SAME_LENGTH(inputs, results); - - static char buf[50]; - for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { - sprintf(buf, "Failed in round %zu", i); - ASSERTm(buf, set_from_string(&val, s, inputs[i])); - sprintf(buf, "Failed in round %zu. %i should be %i", i, val, results[i]); - ASSERT_EQm(buf, val, results[i]); - } - PASS(); + bool val; + + struct setting s; + s.type = TYPE_CUSTOM; + s.parser = string_parse_bool; + s.parser_data = boolean_enum_data; + s.value = &val; + + const char *inputs[] = {"0", "1", "true", "True", "false", "off"}; + const int results[] = {0, 1, 1, 1, 0, 0}; + + ARRAY_SAME_LENGTH(inputs, results); + + static char buf[50]; + for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { + sprintf(buf, "Failed in round %zu", i); + ASSERTm(buf, set_from_string(&val, s, inputs[i])); + sprintf( + buf, "Failed in round %zu. %i should be %i", i, val, results[i]); + ASSERT_EQm(buf, val, results[i]); + } + PASS(); } TEST test_string_to_boolean_invalid(void) { - bool val = true; - - struct setting s = {0}; - s.type = TYPE_CUSTOM; - s.parser = string_parse_bool; - s.parser_data = boolean_enum_data; - s.value = &val; - s.name = "test_boolean"; - - const char* invalid_inputs[] = { - "-1", - "123", - "something", - "else", - }; - - static char buf[50]; - for (size_t i = 0; i < G_N_ELEMENTS(invalid_inputs); i++) { - sprintf(buf, "Failed in round %zu", i); - bool success = set_from_string(&val, s, invalid_inputs[i]); - ASSERT_FALSEm(buf, success); - } - ASSERT_EQm("Boolean should not change from invalid values", val, true); - PASS(); + bool val = true; + + struct setting s = {0}; + s.type = TYPE_CUSTOM; + s.parser = string_parse_bool; + s.parser_data = boolean_enum_data; + s.value = &val; + s.name = "test_boolean"; + + const char *invalid_inputs[] = { + "-1", + "123", + "something", + "else", + }; + + static char buf[50]; + for (size_t i = 0; i < G_N_ELEMENTS(invalid_inputs); i++) { + sprintf(buf, "Failed in round %zu", i); + bool success = set_from_string(&val, s, invalid_inputs[i]); + ASSERT_FALSEm(buf, success); + } + ASSERT_EQm("Boolean should not change from invalid values", val, true); + PASS(); } TEST test_string_to_enum(void) { - int val = -123; - - struct setting s; - s.type = TYPE_CUSTOM; - s.value = &val; - s.parser = string_parse_enum; - s.parser_data = ellipsize_enum_data; - - static char buf[50]; - - // do not go until last element, since it's ENUM_END (all 0) - for (size_t i = 0; i < G_N_ELEMENTS(ellipsize_enum_data)-1; i++) { - sprintf(buf, "Failed in round %zu", i); - ASSERTm(buf, set_from_string(&val, s, ellipsize_enum_data[i].string)); - ASSERT_EQm(buf, val, ellipsize_enum_data[i].enum_value); - } - PASS(); + int val = -123; + + struct setting s; + s.type = TYPE_CUSTOM; + s.value = &val; + s.parser = string_parse_enum; + s.parser_data = ellipsize_enum_data; + + static char buf[50]; + + // do not go until last element, since it's ENUM_END (all 0) + for (size_t i = 0; i < G_N_ELEMENTS(ellipsize_enum_data) - 1; i++) { + sprintf(buf, "Failed in round %zu", i); + ASSERTm(buf, set_from_string(&val, s, ellipsize_enum_data[i].string)); + ASSERT_EQm(buf, val, ellipsize_enum_data[i].enum_value); + } + PASS(); } TEST test_string_to_enum_invalid(void) { - int val = -123; - - struct setting s; - s.name = "test_enum"; - s.type = TYPE_CUSTOM; - s.value = &val; - s.parser = string_parse_enum; - s.parser_data = ellipsize_enum_data; - - const char* invalid_inputs[] = { - "0", - "1", - "-1", - "something", - "else" - }; - - static char buf[50]; - - for (size_t i = 0; i < G_N_ELEMENTS(invalid_inputs); i++) { - sprintf(buf, "Failed in round %zu", i); - ASSERT_FALSEm(buf, set_from_string(&val, s, invalid_inputs[i])); - } - ASSERT_EQm("Enum should not change from invalid values", val, -123); - PASS(); + int val = -123; + + struct setting s; + s.name = "test_enum"; + s.type = TYPE_CUSTOM; + s.value = &val; + s.parser = string_parse_enum; + s.parser_data = ellipsize_enum_data; + + const char *invalid_inputs[] = {"0", "1", "-1", "something", "else"}; + + static char buf[50]; + + for (size_t i = 0; i < G_N_ELEMENTS(invalid_inputs); i++) { + sprintf(buf, "Failed in round %zu", i); + ASSERT_FALSEm(buf, set_from_string(&val, s, invalid_inputs[i])); + } + ASSERT_EQm("Enum should not change from invalid values", val, -123); + PASS(); } -int get_list_len(const enum mouse_action *in) { - int len = 0; - while (in[len] != MOUSE_ACTION_END) - len++; - return len; +int get_list_len(const enum mouse_action *in) +{ + int len = 0; + while (in[len] != MOUSE_ACTION_END) + len++; + return len; } TEST test_string_to_list(void) { - enum mouse_action *val = NULL; - - struct setting s; - s.type = TYPE_LIST; - s.value = &val; - s.parser_data = GINT_TO_POINTER(MOUSE_LIST); - - const char* inputs[] = { - "close_current", - "none", - "none, close_current", - "close_all,close_current", - "close_all,close_current,close_all", - }; - const enum mouse_action results[][4] = { - {MOUSE_CLOSE_CURRENT, MOUSE_ACTION_END}, - {MOUSE_NONE, MOUSE_ACTION_END}, - {MOUSE_NONE, MOUSE_CLOSE_CURRENT, MOUSE_ACTION_END}, - {MOUSE_CLOSE_ALL, MOUSE_CLOSE_CURRENT, MOUSE_ACTION_END}, - {MOUSE_CLOSE_ALL, MOUSE_CLOSE_CURRENT, MOUSE_CLOSE_ALL, MOUSE_ACTION_END}, - }; - - static char buf[100]; - for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { - sprintf(buf, "Failed in round %zu", i); - ASSERTm(buf, set_from_string(s.value, s, inputs[i])); - ASSERT_EQm(buf, get_list_len(val), get_list_len(results[i])); - for (size_t j = 0; val[j] != MOUSE_ACTION_END; j++) { - sprintf(buf, "Failed in round %zu, element %zu. Is %i, should be %i", i, j, val[j], results[i][j]); - ASSERT_EQm(buf, val[j], results[i][j]); - } + enum mouse_action *val = NULL; + + struct setting s; + s.type = TYPE_LIST; + s.value = &val; + s.parser_data = GINT_TO_POINTER(MOUSE_LIST); + + const char *inputs[] = { + "close_current", + "none", + "none, close_current", + "close_all,close_current", + "close_all,close_current,close_all", + }; + const enum mouse_action results[][4] = { + {MOUSE_CLOSE_CURRENT, MOUSE_ACTION_END}, + {MOUSE_NONE, MOUSE_ACTION_END}, + {MOUSE_NONE, MOUSE_CLOSE_CURRENT, MOUSE_ACTION_END}, + {MOUSE_CLOSE_ALL, MOUSE_CLOSE_CURRENT, MOUSE_ACTION_END}, + {MOUSE_CLOSE_ALL, + MOUSE_CLOSE_CURRENT, + MOUSE_CLOSE_ALL, + MOUSE_ACTION_END}, + }; + + static char buf[100]; + for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { + sprintf(buf, "Failed in round %zu", i); + ASSERTm(buf, set_from_string(s.value, s, inputs[i])); + ASSERT_EQm(buf, get_list_len(val), get_list_len(results[i])); + for (size_t j = 0; val[j] != MOUSE_ACTION_END; j++) { + sprintf(buf, + "Failed in round %zu, element %zu. Is %i, should be %i", + i, + j, + val[j], + results[i][j]); + ASSERT_EQm(buf, val[j], results[i][j]); } - free(val); - PASS(); + } + free(val); + PASS(); } TEST test_string_to_list_invalid(void) { - enum mouse_action val_initial[] = {123, MOUSE_ACTION_END}; - enum mouse_action *val; - - // set the list to some initial value - int len = get_list_len(val_initial); - val = g_malloc_n(len+1, sizeof(enum mouse_action)); - for (int i = 0; i < len + 1; i++) { - val[i] = val_initial[i]; - } - - struct setting s; - s.name = "test_list"; - s.type = TYPE_LIST; - s.value = &val; - s.parser_data = GINT_TO_POINTER(MOUSE_LIST); - - const char* invalid_inputs[] = { - "0", - "1", - "-1", - "something", - "else" - "close_all,close_current,close_all,invalid", - "close_all,invalid,close_current,close_all", - }; - - static char buf[256]; - for (size_t i = 0; i < G_N_ELEMENTS(invalid_inputs); i++) { - sprintf(buf, "Failed in round %zu", i); - ASSERT_FALSEm(buf, set_from_string(&val, s, invalid_inputs[i])); - } - sprintf(buf,"List should not change from invalid values. Expected length %i, got %i", len, get_list_len(val)); - ASSERT_EQm(buf, get_list_len(val), len); - ASSERT_EQm("List should not change from invalid values", (int) val[0], 123); - g_free(val); - PASS(); + enum mouse_action val_initial[] = {123, MOUSE_ACTION_END}; + enum mouse_action *val; + + // set the list to some initial value + int len = get_list_len(val_initial); + val = g_malloc_n(len + 1, sizeof(enum mouse_action)); + for (int i = 0; i < len + 1; i++) { + val[i] = val_initial[i]; + } + + struct setting s; + s.name = "test_list"; + s.type = TYPE_LIST; + s.value = &val; + s.parser_data = GINT_TO_POINTER(MOUSE_LIST); + + const char *invalid_inputs[] = { + "0", + "1", + "-1", + "something", + "else" + "close_all,close_current,close_all,invalid", + "close_all,invalid,close_current,close_all", + }; + + static char buf[256]; + for (size_t i = 0; i < G_N_ELEMENTS(invalid_inputs); i++) { + sprintf(buf, "Failed in round %zu", i); + ASSERT_FALSEm(buf, set_from_string(&val, s, invalid_inputs[i])); + } + sprintf(buf, + "List should not change from invalid values. Expected length %i, " + "got %i", + len, + get_list_len(val)); + ASSERT_EQm(buf, get_list_len(val), len); + ASSERT_EQm("List should not change from invalid values", (int)val[0], 123); + g_free(val); + PASS(); } TEST test_string_to_time(void) { - gint64 val; - struct setting s; - s.type = TYPE_TIME; - s.value = &val; - s.name = "test_time"; - - const char* inputs[] = { - "-1", - "0", - "1", - "3s", - "100ms", - "2m", - }; - const int results[] = { - S2US(-1), - S2US(0), - S2US(1), - S2US(3), - 100 * 1000, - S2US(120), - }; - - ARRAY_SAME_LENGTH(inputs, results); - - static char buf[50]; - for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { - sprintf(buf, "Failed in round %zu", i); - ASSERTm(buf, set_from_string(&val, s, inputs[i])); - sprintf(buf, "Failed in round %zu. %"G_GINT64_FORMAT" should be %i", i, val, results[i]); - ASSERT_EQm(buf, val, results[i]); - } - PASS(); + gint64 val; + struct setting s; + s.type = TYPE_TIME; + s.value = &val; + s.name = "test_time"; + + const char *inputs[] = { + "-1", + "0", + "1", + "3s", + "100ms", + "2m", + }; + const int results[] = { + S2US(-1), + S2US(0), + S2US(1), + S2US(3), + 100 * 1000, + S2US(120), + }; + + ARRAY_SAME_LENGTH(inputs, results); + + static char buf[50]; + for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { + sprintf(buf, "Failed in round %zu", i); + ASSERTm(buf, set_from_string(&val, s, inputs[i])); + sprintf(buf, + "Failed in round %zu. %" G_GINT64_FORMAT " should be %i", + i, + val, + results[i]); + ASSERT_EQm(buf, val, results[i]); + } + PASS(); } TEST test_string_to_time_invalid(void) { - gint64 val = 1234; - struct setting s; - s.type = TYPE_TIME; - s.value = &val; - - const char* invalid_inputs[] = { - // -1 is allowed, but only without suffix - "-1s", - "-1ms", - "-2", - "-4s", - "-2ms", - "3basdf", - "100asdf", - "anything", - "s", - }; - - static char buf[50]; - for (size_t i = 0; i < G_N_ELEMENTS(invalid_inputs); i++) { - sprintf(buf, "Failed in round %zu", i); - ASSERT_FALSEm(buf, set_from_string(&val, s, invalid_inputs[i])); - } - ASSERT_EQm("Time should not change from invalid values", val, 1234); - PASS(); + gint64 val = 1234; + struct setting s; + s.type = TYPE_TIME; + s.value = &val; + + const char *invalid_inputs[] = { + // -1 is allowed, but only without suffix + "-1s", + "-1ms", + "-2", + "-4s", + "-2ms", + "3basdf", + "100asdf", + "anything", + "s", + }; + + static char buf[50]; + for (size_t i = 0; i < G_N_ELEMENTS(invalid_inputs); i++) { + sprintf(buf, "Failed in round %zu", i); + ASSERT_FALSEm(buf, set_from_string(&val, s, invalid_inputs[i])); + } + ASSERT_EQm("Time should not change from invalid values", val, 1234); + PASS(); } TEST test_string_to_path(void) { - char *val = NULL; - char **val2 = NULL; - struct setting s; - s.type = TYPE_PATH; - s.value = &val; - s.name = "test_path"; - s.parser_data = &val2; - - const char* inputs[] = { - "/bin/something", - "something", - "/path/path/path/", - "/path/p argument", - "p with multiple arguments", - "~/p/p", - "$HOME/p/p", - "$TEST_ENV/p/p", - }; - - setenv("TEST_ENV", "foobar", 1); - - char *expanded_home = g_strconcat(user_get_home(), "/", "p/p", NULL); - char *expanded_env = g_strconcat("foobar", "/p/p", NULL); - const char* results[] = { - "/bin/something", - "something", - "/path/path/path/", - "/path/p argument", - "p with multiple arguments", - expanded_home, - expanded_home, - expanded_env, - }; - - const char* results2[][5] = { - {"/bin/something", NULL}, - {"something", NULL}, - {"/path/path/path/", NULL}, - {"/path/p", "argument", NULL}, - {"p", "with", "multiple", "arguments", NULL}, - {expanded_home}, - {expanded_home}, - {expanded_env}, - }; - - ARRAY_SAME_LENGTH(inputs, results); - ARRAY_SAME_LENGTH(inputs, results2); - - static char buf[256]; - for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { - sprintf(buf, "Failed in round %zu", i); - ASSERTm(buf, set_from_string(&val, s, inputs[i])); - sprintf(buf, "Failed in round %zu. %s should be %s", i, val, results[i]); - ASSERTm(buf, STR_EQ(val, results[i])); - for (size_t j = 0; results2[i][j] != NULL; j++) { - ASSERT_STR_EQ(results2[i][j], val2[j]); - } + char *val = NULL; + char **val2 = NULL; + struct setting s; + s.type = TYPE_PATH; + s.value = &val; + s.name = "test_path"; + s.parser_data = &val2; + + const char *inputs[] = { + "/bin/something", + "something", + "/path/path/path/", + "/path/p argument", + "p with multiple arguments", + "~/p/p", + "$HOME/p/p", + "$TEST_ENV/p/p", + }; + + setenv("TEST_ENV", "foobar", 1); + + char *expanded_home = g_strconcat(user_get_home(), "/", "p/p", NULL); + char *expanded_env = g_strconcat("foobar", "/p/p", NULL); + const char *results[] = { + "/bin/something", + "something", + "/path/path/path/", + "/path/p argument", + "p with multiple arguments", + expanded_home, + expanded_home, + expanded_env, + }; + + const char *results2[][5] = { + {"/bin/something", NULL}, + {"something", NULL}, + {"/path/path/path/", NULL}, + {"/path/p", "argument", NULL}, + {"p", "with", "multiple", "arguments", NULL}, + {expanded_home}, + {expanded_home}, + {expanded_env}, + }; + + ARRAY_SAME_LENGTH(inputs, results); + ARRAY_SAME_LENGTH(inputs, results2); + + static char buf[256]; + for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { + sprintf(buf, "Failed in round %zu", i); + ASSERTm(buf, set_from_string(&val, s, inputs[i])); + sprintf( + buf, "Failed in round %zu. %s should be %s", i, val, results[i]); + ASSERTm(buf, STR_EQ(val, results[i])); + for (size_t j = 0; results2[i][j] != NULL; j++) { + ASSERT_STR_EQ(results2[i][j], val2[j]); } + } - g_free(val); - g_free(expanded_env); - g_free(expanded_home); - g_strfreev(val2); - PASS(); + g_free(val); + g_free(expanded_env); + g_free(expanded_home); + g_strfreev(val2); + PASS(); } TEST test_string_to_sepcolor(void) { - struct separator_color_data val = {0}; - struct setting s; - s.type = TYPE_CUSTOM; - s.value = &val; - s.name = "test_sepcolor"; - s.parser = string_parse_sepcolor; - s.parser_data = sep_color_enum_data; - - const char* inputs[] = { - "auto", - "foreground", - "frame", - "#123456", - "#ab123c", - "#AB123C", - }; - - const struct separator_color_data results[] = { - {SEP_AUTO, COLOR_UNINIT}, - {SEP_FOREGROUND, COLOR_UNINIT}, - {SEP_FRAME, COLOR_UNINIT}, - {SEP_CUSTOM, { (double)0x12 / 0xff, (double)0x34 / 0xff, (double)0x56 / 0xff, 1.0}}, - {SEP_CUSTOM, { (double)0xab / 0xff, (double)0x12 / 0xff, (double)0x3c / 0xff, 1.0}}, - {SEP_CUSTOM, { (double)0xab / 0xff, (double)0x12 / 0xff, (double)0x3c / 0xff, 1.0}}, - }; - - ARRAY_SAME_LENGTH(inputs, results); - - static char buf[100]; - char buf1[10], buf2[10]; - - for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { - sprintf(buf, "Failed in round %zu. Expected %i, got %i", i, results[i].type, val.type); - ASSERTm(buf, set_from_string(&val, s, inputs[i])); - ASSERT_EQm(buf, results[i].type, val.type); - - sprintf(buf, "Failed in round %zu. Expected %s, got %s", i, - color_to_string(results[i].color, buf1), color_to_string(val.color, buf2)); - ASSERTm(buf, (!COLOR_VALID(val.color) && !COLOR_VALID(results[i].color)) || COLOR_SAME(results[i].color, val.color)); - } - - PASS(); + struct separator_color_data val = {0}; + struct setting s; + s.type = TYPE_CUSTOM; + s.value = &val; + s.name = "test_sepcolor"; + s.parser = string_parse_sepcolor; + s.parser_data = sep_color_enum_data; + + const char *inputs[] = { + "auto", + "foreground", + "frame", + "#123456", + "#ab123c", + "#AB123C", + }; + + const struct separator_color_data results[] = { + {SEP_AUTO, COLOR_UNINIT}, + {SEP_FOREGROUND, COLOR_UNINIT}, + {SEP_FRAME, COLOR_UNINIT}, + {SEP_CUSTOM, + {(double)0x12 / 0xff, (double)0x34 / 0xff, (double)0x56 / 0xff, 1.0}}, + {SEP_CUSTOM, + {(double)0xab / 0xff, (double)0x12 / 0xff, (double)0x3c / 0xff, 1.0}}, + {SEP_CUSTOM, + {(double)0xab / 0xff, (double)0x12 / 0xff, (double)0x3c / 0xff, 1.0}}, + }; + + ARRAY_SAME_LENGTH(inputs, results); + + static char buf[100]; + char buf1[10], buf2[10]; + + for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { + sprintf(buf, + "Failed in round %zu. Expected %i, got %i", + i, + results[i].type, + val.type); + ASSERTm(buf, set_from_string(&val, s, inputs[i])); + ASSERT_EQm(buf, results[i].type, val.type); + + sprintf(buf, + "Failed in round %zu. Expected %s, got %s", + i, + color_to_string(results[i].color, buf1), + color_to_string(val.color, buf2)); + ASSERTm(buf, + (!COLOR_VALID(val.color) && !COLOR_VALID(results[i].color)) + || COLOR_SAME(results[i].color, val.color)); + } + + PASS(); } TEST test_string_to_sepcolor_invalid(void) { - struct separator_color_data val = {123, COLOR_UNINIT}; - struct setting s; - s.type = TYPE_CUSTOM; - s.value = &val; - s.name = "test_sepcolor"; - s.parser = string_parse_sepcolor; - s.parser_data = sep_color_enum_data; - - const char* inputs[] = { - "", - "f00reground", - "fraame", - "123456", - "#ab", - "#gg123c", - "#AB123C123212", - }; - - static char buf[50]; - for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { - sprintf(buf, "Failed in round %zu", i); - ASSERT_FALSEm(buf, set_from_string(&val, s, inputs[i])); - } - - ASSERT_EQm("Sep color shouldn't changed from invalid inputs", 123, (int) val.type); - ASSERTm("Sep color shouldn't changed from invalid inputs", !COLOR_VALID(val.color)); - PASS(); + struct separator_color_data val = {123, COLOR_UNINIT}; + struct setting s; + s.type = TYPE_CUSTOM; + s.value = &val; + s.name = "test_sepcolor"; + s.parser = string_parse_sepcolor; + s.parser_data = sep_color_enum_data; + + const char *inputs[] = { + "", + "f00reground", + "fraame", + "123456", + "#ab", + "#gg123c", + "#AB123C123212", + }; + + static char buf[50]; + for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { + sprintf(buf, "Failed in round %zu", i); + ASSERT_FALSEm(buf, set_from_string(&val, s, inputs[i])); + } + + ASSERT_EQm( + "Sep color shouldn't changed from invalid inputs", 123, (int)val.type); + ASSERTm("Sep color shouldn't changed from invalid inputs", + !COLOR_VALID(val.color)); + PASS(); } TEST test_string_to_color(void) { - struct color val = COLOR_UNINIT; - struct setting s; - s.type = TYPE_COLOR; - s.value = &val; - s.name = "test_color"; - - const char* inputs[] = { - "#123456", - "#ab123c", - "#AB123C", - "#abc", - "#faf", - "#AABBCC10", - }; - - const struct color results[] = { - { (double)0x12 / 0xff, (double)0x34 / 0xff, (double)0x56 / 0xff, 1.0}, - { (double)0xab / 0xff, (double)0x12 / 0xff, (double)0x3c / 0xff, 1.0}, - { (double)0xab / 0xff, (double)0x12 / 0xff, (double)0x3c / 0xff, 1.0}, - { (double)0xaa / 0xff, (double)0xbb / 0xff, (double)0xcc / 0xff, 1.0}, - { 1.0, (double)0xaa / 0xff, 1.0, 1.0}, - { (double)0xaa / 0xff, (double)0xbb / 0xff, (double)0xcc / 0xff, (double)0x10 / 0xff}, - }; - - ARRAY_SAME_LENGTH(inputs, results); - - static char buf[100]; - char buf1[10], buf2[10]; - - for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { - sprintf(buf, "Failed in round %zu. Expected %s, got %s", i, - color_to_string(results[i], buf1), color_to_string(val, buf2)); - ASSERTm(buf, set_from_string(&val, s, inputs[i])); - ASSERTm(buf, COLOR_SAME(results[i], val)); - } - - PASS(); + struct color val = COLOR_UNINIT; + struct setting s; + s.type = TYPE_COLOR; + s.value = &val; + s.name = "test_color"; + + const char *inputs[] = { + "#123456", + "#ab123c", + "#AB123C", + "#abc", + "#faf", + "#AABBCC10", + }; + + const struct color results[] = { + {(double)0x12 / 0xff, (double)0x34 / 0xff, (double)0x56 / 0xff, 1.0}, + {(double)0xab / 0xff, (double)0x12 / 0xff, (double)0x3c / 0xff, 1.0}, + {(double)0xab / 0xff, (double)0x12 / 0xff, (double)0x3c / 0xff, 1.0}, + {(double)0xaa / 0xff, (double)0xbb / 0xff, (double)0xcc / 0xff, 1.0}, + {1.0, (double)0xaa / 0xff, 1.0, 1.0}, + {(double)0xaa / 0xff, + (double)0xbb / 0xff, + (double)0xcc / 0xff, + (double)0x10 / 0xff}, + }; + + ARRAY_SAME_LENGTH(inputs, results); + + static char buf[100]; + char buf1[10], buf2[10]; + + for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { + sprintf(buf, + "Failed in round %zu. Expected %s, got %s", + i, + color_to_string(results[i], buf1), + color_to_string(val, buf2)); + ASSERTm(buf, set_from_string(&val, s, inputs[i])); + ASSERTm(buf, COLOR_SAME(results[i], val)); + } + + PASS(); } TEST test_string_to_color_invalid(void) { - struct color val = COLOR_UNINIT; - struct setting s; - s.type = TYPE_COLOR; - s.value = &val; - s.name = "test_color_invalid"; - - const char* inputs[] = { - "", - "not color", - "####", - "@#4x", - "#abx", - "#gg123c", - "#AB123C123212", - "#sjdsnc", - "#00#", - "#ab+cd", - "#fffffffffffffffff", - " ## ", - "#xzky", - "#abacgg", - "0xfaf", - "#fcb+fa", - }; - - static char buf[50]; - for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { - sprintf(buf, "Failed in round %zu", i); - ASSERT_FALSEm(buf, set_from_string(&val, s, inputs[i])); - } - - ASSERTm("Color shouldn't changed from invalid inputs", !COLOR_VALID(val)); - PASS(); + struct color val = COLOR_UNINIT; + struct setting s; + s.type = TYPE_COLOR; + s.value = &val; + s.name = "test_color_invalid"; + + const char *inputs[] = { + "", + "not color", + "####", + "@#4x", + "#abx", + "#gg123c", + "#AB123C123212", + "#sjdsnc", + "#00#", + "#ab+cd", + "#fffffffffffffffff", + " ## ", + "#xzky", + "#abacgg", + "0xfaf", + "#fcb+fa", + }; + + static char buf[50]; + for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { + sprintf(buf, "Failed in round %zu", i); + ASSERT_FALSEm(buf, set_from_string(&val, s, inputs[i])); + } + + ASSERTm("Color shouldn't changed from invalid inputs", !COLOR_VALID(val)); + PASS(); } TEST test_string_to_gradient(void) { - struct gradient *grad = NULL; - struct setting s; - s.type = TYPE_GRADIENT; - s.value = &grad; - s.name = "test_gradient"; - - const char* inputs[] = { - "#123456", - "#ab123c", - "#abc, #ebf, #aaafff", - "#abc123, #acaf8f", - }; - - // NOTE: Flexible array shenanigans - struct gradient *results[] = { - gradient_alloc(1), - gradient_alloc(1), - gradient_alloc(3), - gradient_alloc(2), - }; - - results[0]->colors[0] = (struct color) { (double)0x12 / 0xff, (double)0x34 / 0xff, (double)0x56 / 0xff, 1.0}; - - results[1]->colors[0] = (struct color) { (double)0xab / 0xff, (double)0x12 / 0xff, (double)0x3c / 0xff, 1.0}; - - results[2]->colors[0] = (struct color) { (double)0xaa / 0xff, (double)0xbb / 0xff, (double)0xcc / 0xff, 1.0}; - results[2]->colors[1] = (struct color) { (double)0xee / 0xff, (double)0xbb / 0xff, (double)0xff / 0xff, 1.0}; - results[2]->colors[2] = (struct color) { (double)0xaa / 0xff, (double)0xaf / 0xff, (double)0xff / 0xff, 1.0}; - - results[3]->colors[0] = (struct color) { (double)0xab / 0xff, (double)0xc1 / 0xff, (double)0x23 / 0xff, 1.0}; - results[3]->colors[1] = (struct color) { (double)0xac / 0xff, (double)0xaf / 0xff, (double)0x8f / 0xff, 1.0}; - - ARRAY_SAME_LENGTH(inputs, results); - - static char buf[100]; - for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { - sprintf(buf, "Failed in round %zu", i); - ASSERTm(buf, set_from_string(&grad, s, inputs[i])); - - char *t1 = gradient_to_string(results[i]); - char *t2 = gradient_to_string(grad); - - sprintf(buf, "Failed in round %zu. Expected %s, got %s", i, t1, t2); - - g_free(t1); - g_free(t2); - - ASSERTm(buf, grad != NULL); - ASSERTm(buf, grad->length == results[i]->length); - - for (size_t k = 0; k < grad->length; k++) - ASSERTm(buf, COLOR_SAME(grad->colors[k], results[i]->colors[k])); - - gradient_release(grad); - grad = NULL; - } - - for (size_t i = 0; i < G_N_ELEMENTS(results); i++) - gradient_release(results[i]); - - PASS(); + struct gradient *grad = NULL; + struct setting s; + s.type = TYPE_GRADIENT; + s.value = &grad; + s.name = "test_gradient"; + + const char *inputs[] = { + "#123456", + "#ab123c", + "#abc, #ebf, #aaafff", + "#abc123, #acaf8f", + }; + + // NOTE: Flexible array shenanigans + struct gradient *results[] = { + gradient_alloc(1), + gradient_alloc(1), + gradient_alloc(3), + gradient_alloc(2), + }; + + results[0]->colors[0] = (struct color){ + (double)0x12 / 0xff, (double)0x34 / 0xff, (double)0x56 / 0xff, 1.0}; + + results[1]->colors[0] = (struct color){ + (double)0xab / 0xff, (double)0x12 / 0xff, (double)0x3c / 0xff, 1.0}; + + results[2]->colors[0] = (struct color){ + (double)0xaa / 0xff, (double)0xbb / 0xff, (double)0xcc / 0xff, 1.0}; + results[2]->colors[1] = (struct color){ + (double)0xee / 0xff, (double)0xbb / 0xff, (double)0xff / 0xff, 1.0}; + results[2]->colors[2] = (struct color){ + (double)0xaa / 0xff, (double)0xaf / 0xff, (double)0xff / 0xff, 1.0}; + + results[3]->colors[0] = (struct color){ + (double)0xab / 0xff, (double)0xc1 / 0xff, (double)0x23 / 0xff, 1.0}; + results[3]->colors[1] = (struct color){ + (double)0xac / 0xff, (double)0xaf / 0xff, (double)0x8f / 0xff, 1.0}; + + ARRAY_SAME_LENGTH(inputs, results); + + static char buf[100]; + for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { + sprintf(buf, "Failed in round %zu", i); + ASSERTm(buf, set_from_string(&grad, s, inputs[i])); + + char *t1 = gradient_to_string(results[i]); + char *t2 = gradient_to_string(grad); + + sprintf(buf, "Failed in round %zu. Expected %s, got %s", i, t1, t2); + + g_free(t1); + g_free(t2); + + ASSERTm(buf, grad != NULL); + ASSERTm(buf, grad->length == results[i]->length); + + for (size_t k = 0; k < grad->length; k++) + ASSERTm(buf, COLOR_SAME(grad->colors[k], results[i]->colors[k])); + + gradient_release(grad); + grad = NULL; + } + + for (size_t i = 0; i < G_N_ELEMENTS(results); i++) + gradient_release(results[i]); + + PASS(); } TEST test_string_to_length(void) { - struct length val = {0}; - struct setting s; - s.type = TYPE_LENGTH; - s.value = &val.min; - s.name = "test_length"; - s.parser = NULL; - s.parser_data = NULL; - - const char* inputs[] = { - "123", - "021", - "(123, 1234)", - "(-123, 1234)", - "(123, -1234)", - "(-123, -1234)", - "( , )", - "(234, )", - "(, 123)", - "(0, )", - }; - - const struct length results[] = { - { 123, 123 }, - { 21, 21 }, - { 123, 1234 }, - { -123, 1234 }, - { 123, -1234 }, - { -123, -1234 }, - { INT_MIN, INT_MAX }, - { 234, INT_MAX }, - { INT_MIN, 123 }, - { 0, INT_MAX }, - }; - - ARRAY_SAME_LENGTH(inputs, results); - - static char buf[500]; - for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { - sprintf(buf, "Failed in round %zu.", i); - ASSERTm(buf, set_from_string(&val, s, inputs[i])); - sprintf(buf, "Failed in round %zu. Expected min to be %i, got %i", i, results[i].min, val.min); - ASSERT_EQm(buf, results[i].min, val.min); - sprintf(buf, "Failed in round %zu. Expected max to be %i, got %i", i, results[i].max, val.max); - ASSERT_EQm(buf, results[i].max, val.max); - } - - PASS(); + struct length val = {0}; + struct setting s; + s.type = TYPE_LENGTH; + s.value = &val.min; + s.name = "test_length"; + s.parser = NULL; + s.parser_data = NULL; + + const char *inputs[] = { + "123", + "021", + "(123, 1234)", + "(-123, 1234)", + "(123, -1234)", + "(-123, -1234)", + "( , )", + "(234, )", + "(, 123)", + "(0, )", + }; + + const struct length results[] = { + {123, 123}, + {21, 21}, + {123, 1234}, + {-123, 1234}, + {123, -1234}, + {-123, -1234}, + {INT_MIN, INT_MAX}, + {234, INT_MAX}, + {INT_MIN, 123}, + {0, INT_MAX}, + }; + + ARRAY_SAME_LENGTH(inputs, results); + + static char buf[500]; + for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { + sprintf(buf, "Failed in round %zu.", i); + ASSERTm(buf, set_from_string(&val, s, inputs[i])); + sprintf(buf, + "Failed in round %zu. Expected min to be %i, got %i", + i, + results[i].min, + val.min); + ASSERT_EQm(buf, results[i].min, val.min); + sprintf(buf, + "Failed in round %zu. Expected max to be %i, got %i", + i, + results[i].max, + val.max); + ASSERT_EQm(buf, results[i].max, val.max); + } + + PASS(); } TEST test_string_to_length_invalid(void) { - struct length val = {-123, -1234}; - struct setting s; - s.type = TYPE_LENGTH; - s.value = &val.min; - s.name = "test_length"; - s.parser = NULL; - s.parser_data = NULL; - - const char* inputs[] = { - "", - "f00reground", - "fraame", - "asb", - "#ab", - "(456", - "456)", - "(456, 567", - "456, 567", - "456, 567)", - "(-123, #1234)", - "(123, # -1234)", - }; - - static char buf[50]; - for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { - sprintf(buf, "Failed in round %zu", i); - ASSERT_FALSEm(buf, set_from_string(&val, s, inputs[i])); - } - - ASSERT_EQm("Length shouldn't change from invalid inputs", -123, val.min); - ASSERT_EQm("Length shouldn't change from invalid inputs", -1234, val.max); - PASS(); + struct length val = {-123, -1234}; + struct setting s; + s.type = TYPE_LENGTH; + s.value = &val.min; + s.name = "test_length"; + s.parser = NULL; + s.parser_data = NULL; + + const char *inputs[] = { + "", + "f00reground", + "fraame", + "asb", + "#ab", + "(456", + "456)", + "(456, 567", + "456, 567", + "456, 567)", + "(-123, #1234)", + "(123, # -1234)", + }; + + static char buf[50]; + for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { + sprintf(buf, "Failed in round %zu", i); + ASSERT_FALSEm(buf, set_from_string(&val, s, inputs[i])); + } + + ASSERT_EQm("Length shouldn't change from invalid inputs", -123, val.min); + ASSERT_EQm("Length shouldn't change from invalid inputs", -1234, val.max); + PASS(); } TEST test_string_to_corners(void) { - enum corner_pos corners = C_NONE; - - struct setting s; - s.type = TYPE_CUSTOM; - s.value = &corners; - s.parser = string_parse_corners; - s.parser_data = corners_enum_data; - - static char buf[50]; - - // do not go until last element, since it's ENUM_END (all 0) - for (size_t i = 0; i < G_N_ELEMENTS(ellipsize_enum_data)-1; i++) { - sprintf(buf, "Failed in round %zu", i); - ASSERTm(buf, set_from_string(&corners, s, corners_enum_data[i].string)); - ASSERT_EQm(buf, corners, corners_enum_data[i].enum_value); - } - - const char* inputs[] = { - "bottom,right", - "top-left, top-right", - "all", - "right,left,top,bottom", - "bottom-left,top-right", - "all,all", // still accepted - "all,top-right", - }; - const enum corner_pos results[] = { - C_BOT | C_RIGHT, - C_TOP_LEFT | C_TOP_RIGHT, - C_ALL, - C_ALL, - C_BOT_LEFT | C_TOP_RIGHT, - C_ALL, - C_ALL, - }; - - ARRAY_SAME_LENGTH(inputs, results); - - for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { - sprintf(buf, "Failed in round %zu", i); - ASSERTm(buf, set_from_string(&corners, s, inputs[i])); - ASSERT_EQm(buf, corners, results[i]); - } - PASS(); + enum corner_pos corners = C_NONE; + + struct setting s; + s.type = TYPE_CUSTOM; + s.value = &corners; + s.parser = string_parse_corners; + s.parser_data = corners_enum_data; + + static char buf[50]; + + // do not go until last element, since it's ENUM_END (all 0) + for (size_t i = 0; i < G_N_ELEMENTS(ellipsize_enum_data) - 1; i++) { + sprintf(buf, "Failed in round %zu", i); + ASSERTm(buf, set_from_string(&corners, s, corners_enum_data[i].string)); + ASSERT_EQm(buf, corners, corners_enum_data[i].enum_value); + } + + const char *inputs[] = { + "bottom,right", + "top-left, top-right", + "all", + "right,left,top,bottom", + "bottom-left,top-right", + "all,all", // still accepted + "all,top-right", + }; + const enum corner_pos results[] = { + C_BOT | C_RIGHT, + C_TOP_LEFT | C_TOP_RIGHT, + C_ALL, + C_ALL, + C_BOT_LEFT | C_TOP_RIGHT, + C_ALL, + C_ALL, + }; + + ARRAY_SAME_LENGTH(inputs, results); + + for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { + sprintf(buf, "Failed in round %zu", i); + ASSERTm(buf, set_from_string(&corners, s, inputs[i])); + ASSERT_EQm(buf, corners, results[i]); + } + PASS(); } TEST test_string_to_corners_invalid(void) { - enum corner_pos corners = C_ALL + 1; - - struct setting s = {0}; - s.type = TYPE_CUSTOM; - s.parser = string_parse_corners; - s.parser_data = corners_enum_data; - s.value = &corners; - s.name = "test_corners"; - - const char* invalid_inputs[] = { - "123", - "something", - "else", - "al l", - "right;right", - "bot-left", - "top right, bottom left" - }; - - static char buf[50]; - for (size_t i = 0; i < G_N_ELEMENTS(invalid_inputs); i++) { - sprintf(buf, "Failed in round %zu", i); - bool success = set_from_string(&corners, s, invalid_inputs[i]); - ASSERT_FALSEm(buf, success); - } - ASSERT_EQm("Enum should not change from invalid values", corners, C_ALL + 1); - PASS(); + enum corner_pos corners = C_ALL + 1; + + struct setting s = {0}; + s.type = TYPE_CUSTOM; + s.parser = string_parse_corners; + s.parser_data = corners_enum_data; + s.value = &corners; + s.name = "test_corners"; + + const char *invalid_inputs[] = {"123", + "something", + "else", + "al l", + "right;right", + "bot-left", + "top right, bottom left"}; + + static char buf[50]; + for (size_t i = 0; i < G_N_ELEMENTS(invalid_inputs); i++) { + sprintf(buf, "Failed in round %zu", i); + bool success = set_from_string(&corners, s, invalid_inputs[i]); + ASSERT_FALSEm(buf, success); + } + ASSERT_EQm( + "Enum should not change from invalid values", corners, C_ALL + 1); + PASS(); } TEST test_string_to_maybe_int(void) { - char *val = NULL; - int intval; - struct setting s; - s.type = TYPE_CUSTOM; - s.value = &val; - s.name = "test_maybe_int"; - s.parser = string_parse_maybe_int; - s.parser_data = &intval; - - const char* inputs[] = { - "0", - "1", - "HDMI-0", - "0TEST", - }; - - const struct { const char *s; int i; } results[] = { - { "0", 0 }, - { "1", 1 }, - { "HDMI-0", INT_MIN }, - { "0TEST", INT_MIN }, - }; - static char buf[500]; - - for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { - sprintf(buf, "Failed in round %zu", i); - ASSERTm(buf, set_from_string(&val, s, inputs[i])); - sprintf(buf, "Failed in round %zu. Expected val to be %s, got %s", i, results[i].s, val); - ASSERTm(buf, STR_EQ(val, results[i].s)); - sprintf(buf, "Failed in round %zu. Expected intval to be %i, got %i", i, results[i].i, intval); - ASSERT_EQm(buf, results[i].i, intval); - } - - g_free(val); - - PASS(); + char *val = NULL; + int intval; + struct setting s; + s.type = TYPE_CUSTOM; + s.value = &val; + s.name = "test_maybe_int"; + s.parser = string_parse_maybe_int; + s.parser_data = &intval; + + const char *inputs[] = { + "0", + "1", + "HDMI-0", + "0TEST", + }; + + const struct + { + const char *s; + int i; + } results[] = { + {"0", 0}, + {"1", 1}, + {"HDMI-0", INT_MIN}, + {"0TEST", INT_MIN}, + }; + static char buf[500]; + + for (size_t i = 0; i < G_N_ELEMENTS(inputs); i++) { + sprintf(buf, "Failed in round %zu", i); + ASSERTm(buf, set_from_string(&val, s, inputs[i])); + sprintf(buf, + "Failed in round %zu. Expected val to be %s, got %s", + i, + results[i].s, + val); + ASSERTm(buf, STR_EQ(val, results[i].s)); + sprintf(buf, + "Failed in round %zu. Expected intval to be %i, got %i", + i, + results[i].i, + intval); + ASSERT_EQm(buf, results[i].i, intval); + } + + g_free(val); + + PASS(); } -#define TEST_ENUM(t) { \ -ASSERT_EQ(sizeof(t), sizeof(int)); \ -} +#define TEST_ENUM(t) \ + { \ + ASSERT_EQ(sizeof(t), sizeof(int)); \ + } // The settings code relies on the enums being the same size as an int. If // they're bigger it's not a big problem, but if they're smaller, other parts // of the memory may be overwritten. TEST test_enum_size(void) { - TEST_ENUM(enum markup_mode); - TEST_ENUM(enum alignment); - TEST_ENUM(enum icon_position); - TEST_ENUM(enum vertical_alignment); - TEST_ENUM(enum follow_mode); - TEST_ENUM(enum mouse_action ); - TEST_ENUM(enum zwlr_layer_shell_v1_layer); - TEST_ENUM(enum corner_pos); - PASS(); + TEST_ENUM(enum markup_mode); + TEST_ENUM(enum alignment); + TEST_ENUM(enum icon_position); + TEST_ENUM(enum vertical_alignment); + TEST_ENUM(enum follow_mode); + TEST_ENUM(enum mouse_action); + TEST_ENUM(enum zwlr_layer_shell_v1_layer); + TEST_ENUM(enum corner_pos); + PASS(); } SUITE(suite_option_parser) { - char cmdline[] = "dunst -bool -b " - "-string \"A simple string from the cmdline\" -s Single_word_string " - "-list A,simple,list,from,the,cmdline -list2 \"A, list, with, spaces\" " - "-int 3 -i 2 -negative -7 -zeroes 04 -intdecim 2.5 " - "-path ~/path/from/cmdline " - "-simple_double 2 -double 5.2" - ; - int argc; - char **argv; - g_shell_parse_argv(&cmdline[0], &argc, &argv, NULL); - cmdline_load(argc, argv); - RUN_TEST(test_cmdline_get_string); - RUN_TEST(test_cmdline_get_list); - RUN_TEST(test_cmdline_get_path); - RUN_TEST(test_cmdline_get_int); - RUN_TEST(test_cmdline_get_double); - RUN_TEST(test_cmdline_get_bool); - RUN_TEST(test_cmdline_create_usage); - - - // These test try out the parsing of set_from_string for different - // config types. - // Non-stripped strings should not be passed to set_from_string. These - // are normally stripped out by the ini parser. - RUN_TEST(test_string_to_int); - RUN_TEST(test_string_to_int_invalid); - RUN_TEST(test_string_to_double); - RUN_TEST(test_string_to_double_invalid); - RUN_TEST(test_string_to_enum); - RUN_TEST(test_string_to_enum_invalid); - RUN_TEST(test_string_to_boolean); - RUN_TEST(test_string_to_boolean_invalid); - RUN_TEST(test_string_to_list); - RUN_TEST(test_string_to_list_invalid); - RUN_TEST(test_string_to_time); - RUN_TEST(test_string_to_time_invalid); - RUN_TEST(test_string_to_path); - RUN_TEST(test_string_to_corners); - RUN_TEST(test_string_to_corners_invalid); - // Paths are now almost always considered valid - RUN_TEST(test_string_to_sepcolor); - RUN_TEST(test_string_to_sepcolor_invalid); - RUN_TEST(test_string_to_color); - RUN_TEST(test_string_to_color_invalid); - RUN_TEST(test_string_to_gradient); - RUN_TEST(test_enum_size); - RUN_TEST(test_string_to_length); - RUN_TEST(test_string_to_length_invalid); - RUN_TEST(test_string_to_maybe_int); - - g_strfreev(argv); + char cmdline[] = + "dunst -bool -b " + "-string \"A simple string from the cmdline\" -s Single_word_string " + "-list A,simple,list,from,the,cmdline -list2 \"A, list, with, spaces\" " + "-int 3 -i 2 -negative -7 -zeroes 04 -intdecim 2.5 " + "-path ~/path/from/cmdline " + "-simple_double 2 -double 5.2"; + int argc; + char **argv; + g_shell_parse_argv(&cmdline[0], &argc, &argv, NULL); + cmdline_load(argc, argv); + RUN_TEST(test_cmdline_get_string); + RUN_TEST(test_cmdline_get_list); + RUN_TEST(test_cmdline_get_path); + RUN_TEST(test_cmdline_get_int); + RUN_TEST(test_cmdline_get_double); + RUN_TEST(test_cmdline_get_bool); + RUN_TEST(test_cmdline_create_usage); + + // These test try out the parsing of set_from_string for different + // config types. + // Non-stripped strings should not be passed to set_from_string. These + // are normally stripped out by the ini parser. + RUN_TEST(test_string_to_int); + RUN_TEST(test_string_to_int_invalid); + RUN_TEST(test_string_to_double); + RUN_TEST(test_string_to_double_invalid); + RUN_TEST(test_string_to_enum); + RUN_TEST(test_string_to_enum_invalid); + RUN_TEST(test_string_to_boolean); + RUN_TEST(test_string_to_boolean_invalid); + RUN_TEST(test_string_to_list); + RUN_TEST(test_string_to_list_invalid); + RUN_TEST(test_string_to_time); + RUN_TEST(test_string_to_time_invalid); + RUN_TEST(test_string_to_path); + RUN_TEST(test_string_to_corners); + RUN_TEST(test_string_to_corners_invalid); + // Paths are now almost always considered valid + RUN_TEST(test_string_to_sepcolor); + RUN_TEST(test_string_to_sepcolor_invalid); + RUN_TEST(test_string_to_color); + RUN_TEST(test_string_to_color_invalid); + RUN_TEST(test_string_to_gradient); + RUN_TEST(test_enum_size); + RUN_TEST(test_string_to_length); + RUN_TEST(test_string_to_length_invalid); + RUN_TEST(test_string_to_maybe_int); + + g_strfreev(argv); } /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/test/queues.c b/test/queues.c index 0402486c0..4cd9913ee 100644 --- a/test/queues.c +++ b/test/queues.c @@ -4,1169 +4,1224 @@ #define GREATEST_FLOAT_FMT "%ld" #include "greatest.h" -#include "queues.h" #include "helpers.h" +#include "queues.h" struct notification *queues_debug_find_notification_by_id(gint id) { - assert(id > 0); - - GQueue *allqueues[] = { displayed, waiting, history }; - for (size_t i = 0; i < sizeof(allqueues)/sizeof(GQueue*); i++) { - for (GList *iter = g_queue_peek_head_link(allqueues[i]); iter; - iter = iter->next) { - struct notification *cur = iter->data; - if (cur->id == id) - return cur; - } + assert(id > 0); + + GQueue *allqueues[] = {displayed, waiting, history}; + for (size_t i = 0; i < sizeof(allqueues) / sizeof(GQueue *); i++) { + for (GList *iter = g_queue_peek_head_link(allqueues[i]); iter; + iter = iter->next) { + struct notification *cur = iter->data; + if (cur->id == id) + return cur; } + } - return NULL; + return NULL; } TEST test_queue_length(void) { - queues_init(); + queues_init(); - struct notification *n; + struct notification *n; - n = test_notification("n1", 0); - queues_notification_insert(n); - queues_notification_close(n, REASON_UNDEF); + 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, time_monotonic_now()); + n = test_notification("n2", 0); + queues_notification_insert(n); + queues_update(STATUS_NORMAL, time_monotonic_now()); - n = test_notification("n3", 0); - queues_notification_insert(n); + n = test_notification("n3", 0); + queues_notification_insert(n); - QUEUE_LEN_ALL(1,1,1); + 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()); + 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(); + queues_teardown(); + PASS(); } TEST test_queue_insert_id_valid_newid(void) { - struct notification *n; - queues_init(); + struct notification *n; + queues_init(); - n = test_notification("n", -1); - n->id = 0; + n = test_notification("n", -1); + n->id = 0; - queues_notification_insert(n); + queues_notification_insert(n); - QUEUE_LEN_ALL(1, 0, 0); - ASSERT(n->id > 0); + QUEUE_LEN_ALL(1, 0, 0); + ASSERT(n->id > 0); - queues_teardown(); - PASS(); + 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(); + 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(); + struct notification *a, *b, *c; + queues_init(); - a = test_notification("a", -1); - notification_ref(a); + a = test_notification("a", -1); + notification_ref(a); - queues_notification_insert(a); - QUEUE_LEN_ALL(1, 0, 0); + queues_notification_insert(a); + QUEUE_LEN_ALL(1, 0, 0); - b = test_notification("b", -1); - notification_ref(b); - b->id = a->id; + b = test_notification("b", -1); + notification_ref(b); + b->id = a->id; - queues_notification_insert(b); - QUEUE_LEN_ALL(1, 0, 0); + queues_notification_insert(b); + QUEUE_LEN_ALL(1, 0, 0); - ASSERT_EQ(a->id, b->id); - NOT_LAST(a); + ASSERT_EQ(a->id, b->id); + NOT_LAST(a); - queues_update(STATUS_NORMAL, time_monotonic_now()); - c = test_notification("c", -1); - c->id = b->id; + queues_update(STATUS_NORMAL, time_monotonic_now()); + c = test_notification("c", -1); + c->id = b->id; - queues_notification_insert(c); + queues_notification_insert(c); - QUEUE_LEN_ALL(0, 1, 0); - ASSERT_EQ(b->id, c->id); - NOT_LAST(b); + QUEUE_LEN_ALL(0, 1, 0); + ASSERT_EQ(b->id, c->id); + NOT_LAST(b); - queues_teardown(); - PASS(); + 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, time_monotonic_now()); - 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, time_monotonic_now()); - QUEUE_LEN_ALL(0, 1, 0); - queues_notification_close(n, REASON_UNDEF); - queues_update(STATUS_NORMAL, time_monotonic_now()); - QUEUE_LEN_ALL(0, 0, 1); - queues_teardown(); - - PASS(); + 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, time_monotonic_now()); + 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, time_monotonic_now()); + QUEUE_LEN_ALL(0, 1, 0); + queues_notification_close(n, REASON_UNDEF); + queues_update(STATUS_NORMAL, time_monotonic_now()); + 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, time_monotonic_now()); - 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, time_monotonic_now()); - QUEUE_LEN_ALL(0, 1, 0); - queues_notification_close(n, REASON_UNDEF); - queues_update(STATUS_NORMAL, time_monotonic_now()); - QUEUE_LEN_ALL(0, 0, 0); - queues_teardown(); - - PASS(); + 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, time_monotonic_now()); + 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, time_monotonic_now()); + QUEUE_LEN_ALL(0, 1, 0); + queues_notification_close(n, REASON_UNDEF); + queues_update(STATUS_NORMAL, time_monotonic_now()); + QUEUE_LEN_ALL(0, 0, 0); + queues_teardown(); + + PASS(); } TEST test_queue_notification_skip_display(void) { - struct notification *n; + struct notification *n; - // Test skipping display - n = test_notification("n", -1); - n->skip_display = true; + // Test skipping display + n = test_notification("n", -1); + n->skip_display = true; - queues_init(); - queues_notification_insert(n); - QUEUE_LEN_ALL(1, 0, 0); - queues_update(STATUS_NORMAL, time_monotonic_now()); - QUEUE_LEN_ALL(0, 0, 1); - queues_teardown(); + queues_init(); + queues_notification_insert(n); + QUEUE_LEN_ALL(1, 0, 0); + queues_update(STATUS_NORMAL, time_monotonic_now()); + QUEUE_LEN_ALL(0, 0, 1); + queues_teardown(); - PASS(); + PASS(); } TEST test_queue_notification_skip_display_redisplayed(void) { - struct notification *n; + struct notification *n; - // Test skipping display - n = test_notification("n", -1); - n->skip_display = true; + // Test skipping display + n = test_notification("n", -1); + n->skip_display = true; - queues_init(); - queues_notification_insert(n); - QUEUE_LEN_ALL(1, 0, 0); - queues_update(STATUS_NORMAL, time_monotonic_now()); - QUEUE_LEN_ALL(0, 0, 1); + queues_init(); + queues_notification_insert(n); + QUEUE_LEN_ALL(1, 0, 0); + queues_update(STATUS_NORMAL, time_monotonic_now()); + QUEUE_LEN_ALL(0, 0, 1); - queues_history_pop(); - QUEUE_LEN_ALL(1, 0, 0); - queues_update(STATUS_NORMAL, time_monotonic_now()); - QUEUE_CONTAINSm("A skip display notification should stay in displayed " - "queue when it got pulled out of history queue", - DISP, n); + queues_history_pop(); + QUEUE_LEN_ALL(1, 0, 0); + queues_update(STATUS_NORMAL, time_monotonic_now()); + QUEUE_CONTAINSm("A skip display notification should stay in displayed " + "queue when it got pulled out of history queue", + DISP, + n); - queues_teardown(); + queues_teardown(); - PASS(); + PASS(); } -TEST test_queue_notification_skip_display_redisplayed_by_random_id(void) { - // breaks if the notification_buffer_size is above 5, - // possible bug?????? - size_t notification_buffer_size = 5; +TEST test_queue_notification_skip_display_redisplayed_by_random_id(void) +{ + // breaks if the notification_buffer_size is above 5, + // possible bug?????? + size_t notification_buffer_size = 5; - struct notification *n[notification_buffer_size]; - bool is_n_popped[notification_buffer_size]; + struct notification *n[notification_buffer_size]; + bool is_n_popped[notification_buffer_size]; - // insert notifications - char string[128]; - for(size_t i=0; iskip_display = true; - n[i]->id = i+1; + n[i] = test_notification(string, -1); + n[i]->skip_display = true; + n[i]->id = i + 1; - // generate a noisy pop table - is_n_popped[i] = rand() > RAND_MAX/4; - } + // generate a noisy pop table + is_n_popped[i] = rand() > RAND_MAX / 4; + } - queues_init(); - for(size_t i=0; i - n = test_notification(name, -1); - queues_notification_insert(n); - queues_update(STATUS_NORMAL, time_monotonic_now()); - queues_notification_close(n, REASON_UNDEF); - } + struct notification *n; - QUEUE_LEN_ALL(0, 0, 10); - - n = test_notification("n", -1); + for (size_t i = 0; i < 10; i++) { + char name[] = {'n', '0' + i, '\0'}; // n + n = test_notification(name, -1); queues_notification_insert(n); + queues_update(STATUS_NORMAL, time_monotonic_now()); queues_notification_close(n, REASON_UNDEF); + } - QUEUE_CONTAINS(HIST, n); - QUEUE_LEN_ALL(0, 0, 10); + QUEUE_LEN_ALL(0, 0, 10); - queues_teardown(); - PASS(); + 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.notification_limit = 0; + settings.history_length = 5; + settings.indicate_hidden = false; + settings.notification_limit = 0; - queues_init(); + queues_init(); - struct notification *n; + struct notification *n; - for (size_t i = 0; i < 10; i++) { - char name[] = { 'n', '0'+i, '\0' }; // n - n = test_notification(name, -1); - queues_notification_insert(n); - } - queues_update(STATUS_NORMAL, time_monotonic_now()); + for (size_t i = 0; i < 10; i++) { + char name[] = {'n', '0' + i, '\0'}; // n + n = test_notification(name, -1); + queues_notification_insert(n); + } + queues_update(STATUS_NORMAL, time_monotonic_now()); - for (size_t i = 0; i < 10; i++) { - char name[] = { '2', 'n', '0'+i, '\0' }; // 2n - n = test_notification(name, -1); - queues_notification_insert(n); - } + for (size_t i = 0; i < 10; i++) { + char name[] = {'2', 'n', '0' + i, '\0'}; // 2n + n = test_notification(name, -1); + queues_notification_insert(n); + } - QUEUE_LEN_ALL(10, 10, 0); + QUEUE_LEN_ALL(10, 10, 0); - queues_history_push_all(); + queues_history_push_all(); - QUEUE_CONTAINS(HIST, n); - QUEUE_LEN_ALL(0, 0, 5); + QUEUE_CONTAINS(HIST, n); + QUEUE_LEN_ALL(0, 0, 5); - queues_teardown(); - PASS(); + queues_teardown(); + PASS(); } TEST test_queue_history_remove_by_id(void) { - settings.history_length = 5; - settings.indicate_hidden = false; - settings.notification_limit = 0; - - queues_init(); + settings.history_length = 5; + settings.indicate_hidden = false; + settings.notification_limit = 0; - struct notification *n; - struct notification *n1 = NULL; + queues_init(); + struct notification *n; + struct notification *n1 = NULL; - for (size_t i = 0; i < 5; i++) { - char name[] = { 'n', '0'+i, '\0' }; // n - n = test_notification(name, -1); - queues_notification_insert(n); + for (size_t i = 0; i < 5; i++) { + char name[] = {'n', '0' + i, '\0'}; // n + n = test_notification(name, -1); + queues_notification_insert(n); - // Store notification at arbitrary position to remove - if(i==1) { - n1 = n; - } + // Store notification at arbitrary position to remove + if (i == 1) { + n1 = n; } - queues_history_push_all(); + } + queues_history_push_all(); - queues_history_remove_by_id(n->id); - queues_history_remove_by_id(n1->id); + queues_history_remove_by_id(n->id); + queues_history_remove_by_id(n1->id); - QUEUE_LEN_ALL(0, 0, 3); + QUEUE_LEN_ALL(0, 0, 3); - QUEUE_NOT_CONTAINS(HIST, n); - QUEUE_NOT_CONTAINS(HIST, n1); + QUEUE_NOT_CONTAINS(HIST, n); + QUEUE_NOT_CONTAINS(HIST, n1); - queues_teardown(); - PASS(); + queues_teardown(); + PASS(); } TEST test_queue_init(void) { - queues_init(); + queues_init(); - QUEUE_LEN_ALL(0, 0, 0); + QUEUE_LEN_ALL(0, 0, 0); - queues_teardown(); - PASS(); + queues_teardown(); + PASS(); } TEST test_queue_teardown(void) { - queues_init(); - QUEUE_LEN_ALL(0, 0, 0); + queues_init(); + QUEUE_LEN_ALL(0, 0, 0); - struct notification *n = test_notification("n", -1); - queues_notification_insert(n); + struct notification *n = test_notification("n", -1); + queues_notification_insert(n); - queues_teardown(); + queues_teardown(); - ASSERT(waiting == NULL); - ASSERT(displayed == NULL); - ASSERT(history == NULL); + ASSERT(waiting == NULL); + ASSERT(displayed == NULL); + ASSERT(history == NULL); - PASS(); + PASS(); } TEST test_datachange_beginning_empty(void) { - queues_init(); + 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); + 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(); + queues_teardown(); + PASS(); } TEST test_datachange_endless(void) { - queues_init(); + queues_init(); - settings.show_age_threshold = -1; + settings.show_age_threshold = -1; - struct notification *n = test_notification("n", 0); + struct notification *n = test_notification("n", 0); - queues_notification_insert(n); - queues_update(STATUS_NORMAL, time_monotonic_now()); + queues_notification_insert(n); + queues_update(STATUS_NORMAL, time_monotonic_now()); - ASSERTm("Age threshold is deactivated and the notification is infinite, there is no wakeup necessary.", - queues_get_next_datachange(time_monotonic_now()) < 0); + 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(); + queues_teardown(); + PASS(); } TEST test_datachange_endless_agethreshold(void) { - const gint64 AGE_THRESHOLD = S2US(5); - settings.show_age_threshold = AGE_THRESHOLD; - - gint64 cur_time = 0; - queues_init(); - - struct notification *n = test_notification("n", 0); - n->timestamp = cur_time; - - queues_notification_insert(n); - queues_update(STATUS_NORMAL, cur_time); - - ASSERT_IN_RANGEm("Age threshold is activated and the next wakeup should be less than a second away", - AGE_THRESHOLD - S2US(1)/2, queues_get_next_datachange(cur_time + AGE_THRESHOLD - S2US(1)), S2US(1)/2); - - ASSERT_IN_RANGEm("Age threshold is activated and the next wakeup should be less than the age threshold", - AGE_THRESHOLD / 2, queues_get_next_datachange(cur_time), 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(cur_time), S2US(1)/2); - - queues_teardown(); - PASS(); + const gint64 AGE_THRESHOLD = S2US(5); + settings.show_age_threshold = AGE_THRESHOLD; + + gint64 cur_time = 0; + queues_init(); + + struct notification *n = test_notification("n", 0); + n->timestamp = cur_time; + + queues_notification_insert(n); + queues_update(STATUS_NORMAL, cur_time); + + ASSERT_IN_RANGEm( + "Age threshold is activated and the next wakeup should be less than a " + "second away", + AGE_THRESHOLD - S2US(1) / 2, + queues_get_next_datachange(cur_time + AGE_THRESHOLD - S2US(1)), + S2US(1) / 2); + + ASSERT_IN_RANGEm("Age threshold is activated and the next wakeup should be " + "less than the age threshold", + AGE_THRESHOLD / 2, + queues_get_next_datachange(cur_time), + 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(cur_time), + S2US(1) / 2); + + queues_teardown(); + PASS(); } TEST test_datachange_agethreshold_at_second(void) { - settings.show_age_threshold = S2US(5); - - queues_init(); - - const gint64 NOTIF_DELTA = 200; - - gint64 cur_time = 500*1000; // T = 0.5s - struct notification *n = test_notification("n0", 0); - n->timestamp = cur_time; - queues_notification_insert(n); - - cur_time += NOTIF_DELTA; - n = test_notification("n1", 0); - n->timestamp = cur_time; - queues_notification_insert(n); - - queues_update(STATUS_NORMAL, cur_time); - - // The next update should be when age must be first displayed, at T=5.5s - ASSERTm("Age threshold is activated, first wakeup should be at 5.5s", - queues_get_next_datachange(cur_time) == S2US(5) + 500000); - - const int NB_MICROSECS = 6; - const gint64 MICROSECS[] = { - 0, 10, NOTIF_DELTA, NOTIF_DELTA + 1, 124131, S2US(1)-1 - }; - for(gint64 base_time = S2US(5); base_time <= S2US(7); base_time += S2US(1)) { - for(int musec_id = 0; musec_id < NB_MICROSECS; ++musec_id) { - cur_time = base_time + MICROSECS[musec_id]; - gint64 next_wakeup = queues_get_next_datachange(cur_time); - ASSERTm("Age threshold is activated, next wakeup should be at next turn of second", - next_wakeup == base_time + S2US(1)); - } + settings.show_age_threshold = S2US(5); + + queues_init(); + + const gint64 NOTIF_DELTA = 200; + + gint64 cur_time = 500 * 1000; // T = 0.5s + struct notification *n = test_notification("n0", 0); + n->timestamp = cur_time; + queues_notification_insert(n); + + cur_time += NOTIF_DELTA; + n = test_notification("n1", 0); + n->timestamp = cur_time; + queues_notification_insert(n); + + queues_update(STATUS_NORMAL, cur_time); + + // The next update should be when age must be first displayed, at T=5.5s + ASSERTm("Age threshold is activated, first wakeup should be at 5.5s", + queues_get_next_datachange(cur_time) == S2US(5) + 500000); + + const int NB_MICROSECS = 6; + const gint64 MICROSECS[] = { + 0, 10, NOTIF_DELTA, NOTIF_DELTA + 1, 124131, S2US(1) - 1}; + for (gint64 base_time = S2US(5); base_time <= S2US(7); + base_time += S2US(1)) { + for (int musec_id = 0; musec_id < NB_MICROSECS; ++musec_id) { + cur_time = base_time + MICROSECS[musec_id]; + gint64 next_wakeup = queues_get_next_datachange(cur_time); + ASSERTm("Age threshold is activated, next wakeup should be at next " + "turn of second", + next_wakeup == base_time + S2US(1)); } + } - queues_teardown(); - PASS(); + queues_teardown(); + PASS(); } TEST test_datachange_queues(void) { - queues_init(); - - gint64 cur_time = 0; - struct notification *n = test_notification("n", 10); - n->timestamp = cur_time; - - queues_notification_insert(n); - ASSERTm("The inserted notification is inside the waiting queue, so it should get ignored.", - queues_get_next_datachange(cur_time) < 0); - - queues_update(STATUS_NORMAL, time_monotonic_now()); - ASSERT_IN_RANGEm("The notification has to get closed in less than its timeout", - S2US(10)/2, queues_get_next_datachange(cur_time), 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(cur_time) < 0); - - queues_teardown(); - PASS(); + queues_init(); + + gint64 cur_time = 0; + struct notification *n = test_notification("n", 10); + n->timestamp = cur_time; + + queues_notification_insert(n); + ASSERTm("The inserted notification is inside the waiting queue, so it " + "should get ignored.", + queues_get_next_datachange(cur_time) < 0); + + queues_update(STATUS_NORMAL, time_monotonic_now()); + ASSERT_IN_RANGEm( + "The notification has to get closed in less than its timeout", + S2US(10) / 2, + queues_get_next_datachange(cur_time), + 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(cur_time) < 0); + + queues_teardown(); + PASS(); } TEST test_datachange_ttl(void) { - struct notification *n; - queues_init(); - gint64 cur_time = 0; - - n = test_notification("n1", 15); - n->timestamp = cur_time; - - queues_notification_insert(n); - queues_update(STATUS_NORMAL, cur_time); - ASSERT_IN_RANGEm("The notification has to get closed in less than its timeout.", - n->timeout/2, queues_get_next_datachange(cur_time), n->timeout/2); - - cur_time += 500; // microseconds - n = test_notification("n2", 10); - n->timestamp = cur_time; - - queues_notification_insert(n); - queues_update(STATUS_NORMAL, cur_time); - ASSERT_IN_RANGEm("The timeout of the second notification has to get used as sleep time now.", - cur_time + n->timeout/2, queues_get_next_datachange(cur_time), n->timeout/2); - - cur_time += S2US(10); - - ASSERT_EQm("The notification already timed out. You have to answer with the current time.", - cur_time, queues_get_next_datachange(cur_time)); - - queues_teardown(); - PASS(); + struct notification *n; + queues_init(); + gint64 cur_time = 0; + + n = test_notification("n1", 15); + n->timestamp = cur_time; + + queues_notification_insert(n); + queues_update(STATUS_NORMAL, cur_time); + ASSERT_IN_RANGEm( + "The notification has to get closed in less than its timeout.", + n->timeout / 2, + queues_get_next_datachange(cur_time), + n->timeout / 2); + + cur_time += 500; // microseconds + n = test_notification("n2", 10); + n->timestamp = cur_time; + + queues_notification_insert(n); + queues_update(STATUS_NORMAL, cur_time); + ASSERT_IN_RANGEm("The timeout of the second notification has to get used " + "as sleep time now.", + cur_time + n->timeout / 2, + queues_get_next_datachange(cur_time), + n->timeout / 2); + + cur_time += S2US(10); + + ASSERT_EQm("The notification already timed out. You have to answer with " + "the current time.", + cur_time, + queues_get_next_datachange(cur_time)); + + queues_teardown(); + PASS(); } TEST test_queue_stacking(void) { - settings.stack_duplicates = true; - struct notification *n1, *n2, *n3; + settings.stack_duplicates = true; + struct notification *n1, *n2, *n3; - queues_init(); + queues_init(); - n1 = test_notification("n1", -1); - n2 = test_notification("n1", -1); - n3 = test_notification("n1", -1); + 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); + queues_notification_insert(n1); + QUEUE_LEN_ALL(1, 0, 0); - notification_ref(n1); - queues_notification_insert(n2); - NOT_LAST(n1); + notification_ref(n1); + queues_notification_insert(n2); + NOT_LAST(n1); - notification_ref(n2); - queues_update(STATUS_NORMAL, time_monotonic_now()); - queues_notification_insert(n3); - QUEUE_LEN_ALL(0, 1, 0); - NOT_LAST(n2); + notification_ref(n2); + queues_update(STATUS_NORMAL, time_monotonic_now()); + queues_notification_insert(n3); + QUEUE_LEN_ALL(0, 1, 0); + NOT_LAST(n2); - queues_teardown(); - PASS(); + queues_teardown(); + PASS(); } TEST test_queue_stacktag(void) { - const char *stacktag = "THIS IS A SUPER WIERD STACK TAG"; - struct notification *n1, *n2, *n3; + const char *stacktag = "THIS IS A SUPER WIERD STACK TAG"; + struct notification *n1, *n2, *n3; - queues_init(); + queues_init(); - n1 = test_notification("n1", 1); - n2 = test_notification("n1", 1); - n3 = test_notification("n1", 1); - n1->stack_tag = g_strdup(stacktag); - n2->stack_tag = g_strdup(stacktag); - n3->stack_tag = g_strdup(stacktag); + n1 = test_notification("n1", 1); + n2 = test_notification("n1", 1); + n3 = test_notification("n1", 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); + queues_notification_insert(n1); + QUEUE_LEN_ALL(1, 0, 0); - notification_ref(n1); - queues_notification_insert(n2); - NOT_LAST(n1); + notification_ref(n1); + queues_notification_insert(n2); + NOT_LAST(n1); - notification_ref(n2); - queues_update(STATUS_NORMAL, time_monotonic_now()); - queues_notification_insert(n3); - QUEUE_LEN_ALL(0, 1, 0); - NOT_LAST(n2); + notification_ref(n2); + queues_update(STATUS_NORMAL, time_monotonic_now()); + queues_notification_insert(n3); + QUEUE_LEN_ALL(0, 1, 0); + NOT_LAST(n2); - queues_teardown(); - PASS(); + queues_teardown(); + PASS(); } TEST test_queue_different_stacktag(void) { - const char *stacktag = "asdf"; - const char *stacktag2 = "something else"; - struct notification *n1, *n2, *n3; - settings.stack_duplicates = false; - - queues_init(); - - n1 = test_notification("n1", 1); - n2 = test_notification("n1", 1); - n3 = test_notification("n1", 1); - n1->stack_tag = g_strdup(stacktag); - n2->stack_tag = g_strdup(stacktag); - n3->stack_tag = g_strdup(stacktag2); - - queues_notification_insert(n1); - QUEUE_LEN_ALL(1, 0, 0); - - notification_ref(n1); - queues_notification_insert(n2); - NOT_LAST(n1); - - queues_notification_insert(n3); - queues_update(STATUS_NORMAL, time_monotonic_now()); - printf("queue %i\n",g_queue_get_length(QUEUE(HIST))); - QUEUE_LEN_ALL(0, 2, 0); - - queues_teardown(); - PASS(); + const char *stacktag = "asdf"; + const char *stacktag2 = "something else"; + struct notification *n1, *n2, *n3; + settings.stack_duplicates = false; + + queues_init(); + + n1 = test_notification("n1", 1); + n2 = test_notification("n1", 1); + n3 = test_notification("n1", 1); + n1->stack_tag = g_strdup(stacktag); + n2->stack_tag = g_strdup(stacktag); + n3->stack_tag = g_strdup(stacktag2); + + queues_notification_insert(n1); + QUEUE_LEN_ALL(1, 0, 0); + + notification_ref(n1); + queues_notification_insert(n2); + NOT_LAST(n1); + + queues_notification_insert(n3); + queues_update(STATUS_NORMAL, time_monotonic_now()); + printf("queue %i\n", g_queue_get_length(QUEUE(HIST))); + QUEUE_LEN_ALL(0, 2, 0); + + queues_teardown(); + PASS(); } TEST test_queue_stacktag_different_appid(void) { - const char *stacktag = "THIS IS A SUPER WIERD STACK TAG"; - struct notification *n1, *n2, *n3; + const char *stacktag = "THIS IS A SUPER WIERD STACK TAG"; + struct notification *n1, *n2, *n3; - queues_init(); + queues_init(); - n1 = test_notification("n1", 1); - n2 = test_notification("n2", 1); - n3 = test_notification("n2", 1); - n1->stack_tag = g_strdup(stacktag); - n2->stack_tag = g_strdup(stacktag); - n3->stack_tag = g_strdup(stacktag); + n1 = test_notification("n1", 1); + n2 = test_notification("n2", 1); + n3 = test_notification("n2", 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); + queues_notification_insert(n1); + QUEUE_LEN_ALL(1, 0, 0); - queues_notification_insert(n2); + queues_notification_insert(n2); - notification_ref(n2); - queues_update(STATUS_NORMAL, time_monotonic_now()); - queues_notification_insert(n3); - QUEUE_LEN_ALL(0, 2, 0); - NOT_LAST(n2); + notification_ref(n2); + queues_update(STATUS_NORMAL, time_monotonic_now()); + queues_notification_insert(n3); + QUEUE_LEN_ALL(0, 2, 0); + NOT_LAST(n2); - queues_teardown(); - PASS(); + queues_teardown(); + PASS(); } TEST test_queue_timeout(void) { - settings.notification_limit = 5; - struct notification *n1, *n2, *n3; + settings.notification_limit = 5; + struct notification *n1, *n2, *n3; - queues_init(); + queues_init(); - n1 = test_notification("n1", 0); - n2 = test_notification("n2", 10); - n3 = test_notification("n3", 10); - n3->transient = true; + 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_notification_insert(n1); + queues_notification_insert(n2); + queues_notification_insert(n3); - queues_update(STATUS_NORMAL, time_monotonic_now()); + queues_update(STATUS_NORMAL, time_monotonic_now()); - // hacky way to shift time - n1->start -= S2US(11); - n2->start -= S2US(11); - n3->start -= S2US(11); - queues_update(STATUS_IDLE, time_monotonic_now()); + // hacky way to shift time + n1->start -= S2US(11); + n2->start -= S2US(11); + n3->start -= S2US(11); + queues_update(STATUS_IDLE, time_monotonic_now()); - QUEUE_LEN_ALL(0,2,1); - QUEUE_CONTAINS(HIST, n3); + 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, time_monotonic_now()); + // hacky way to shift time + n1->start -= S2US(11); + n2->start -= S2US(11); + queues_update(STATUS_NORMAL, time_monotonic_now()); - QUEUE_LEN_ALL(0,1,2); - QUEUE_CONTAINS(DISP, n1); - QUEUE_CONTAINS(HIST, n2); - QUEUE_CONTAINS(HIST, n3); + QUEUE_LEN_ALL(0, 1, 2); + QUEUE_CONTAINS(DISP, n1); + QUEUE_CONTAINS(HIST, n2); + QUEUE_CONTAINS(HIST, n3); - queues_teardown(); - PASS(); + queues_teardown(); + PASS(); } TEST test_queues_update_fullscreen(void) { - settings.notification_limit = 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, time_monotonic_now()); - QUEUE_CONTAINS(DISP, n_show); - QUEUE_CONTAINS(WAIT, n_dela); - QUEUE_CONTAINS(WAIT, n_push); - - queues_update(STATUS_NORMAL, time_monotonic_now()); - QUEUE_CONTAINS(DISP, n_show); - QUEUE_CONTAINS(DISP, n_dela); - QUEUE_CONTAINS(DISP, n_push); - - queues_update(STATUS_FS, time_monotonic_now()); - QUEUE_CONTAINS(DISP, n_show); - QUEUE_CONTAINS(DISP, n_dela); - QUEUE_CONTAINS(WAIT, n_push); - - queues_teardown(); - PASS(); + settings.notification_limit = 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, time_monotonic_now()); + QUEUE_CONTAINS(DISP, n_show); + QUEUE_CONTAINS(WAIT, n_dela); + QUEUE_CONTAINS(WAIT, n_push); + + queues_update(STATUS_NORMAL, time_monotonic_now()); + QUEUE_CONTAINS(DISP, n_show); + QUEUE_CONTAINS(DISP, n_dela); + QUEUE_CONTAINS(DISP, n_push); + + queues_update(STATUS_FS, time_monotonic_now()); + 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.notification_limit = 5; - struct notification *n1, *n2, *n3; - queues_init(); + settings.notification_limit = 5; + struct notification *n1, *n2, *n3; + queues_init(); - n1 = test_notification("n1", 0); - n2 = test_notification("n2", 0); - n3 = test_notification("n3", 0); + 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); + queues_notification_insert(n1); + queues_notification_insert(n2); + queues_notification_insert(n3); - QUEUE_LEN_ALL(3,0,0); + QUEUE_LEN_ALL(3, 0, 0); - queues_update(STATUS_PAUSE, time_monotonic_now()); - QUEUE_LEN_ALL(3,0,0); + queues_update(STATUS_PAUSE, time_monotonic_now()); + QUEUE_LEN_ALL(3, 0, 0); - queues_update(STATUS_NORMAL, time_monotonic_now()); - QUEUE_LEN_ALL(0,3,0); + queues_update(STATUS_NORMAL, time_monotonic_now()); + QUEUE_LEN_ALL(0, 3, 0); - queues_update(STATUS_PAUSE, time_monotonic_now()); - QUEUE_LEN_ALL(3,0,0); + queues_update(STATUS_PAUSE, time_monotonic_now()); + QUEUE_LEN_ALL(3, 0, 0); - queues_teardown(); - PASS(); + queues_teardown(); + PASS(); } TEST test_queues_update_pause_level(void) { - settings.notification_limit = 5; - struct notification *n1, *n2, *n3; - queues_init(); - - n1 = test_notification("n1", 0); - n2 = test_notification("n2", 0); - n3 = test_notification("n3", 0); - - n1->override_pause_level = 0; - n2->override_pause_level = 5; - n3->override_pause_level = 10; - - queues_notification_insert(n1); - queues_notification_insert(n2); - queues_notification_insert(n3); - - queues_update(STATUS_PAUSE_7, time_monotonic_now()); - QUEUE_LEN_ALL(2,1,0); - ASSERT(strcmp(((struct notification*) g_queue_peek_nth(QUEUE(DISP), 0))->summary, "n3") == 0); - ASSERT(strcmp(((struct notification*) g_queue_peek_nth(QUEUE(WAIT), 0))->summary, "n1") == 0); - ASSERT(strcmp(((struct notification*) g_queue_peek_nth(QUEUE(WAIT), 1))->summary, "n2") == 0); - - queues_update(STATUS_NORMAL, time_monotonic_now()); - QUEUE_LEN_ALL(0,3,0); - - queues_update(STATUS_PAUSE_7, time_monotonic_now()); - QUEUE_LEN_ALL(2,1,0); - ASSERT(strcmp(((struct notification*) g_queue_peek_nth(QUEUE(DISP), 0))->summary, "n3") == 0); - ASSERT(strcmp(((struct notification*) g_queue_peek_nth(QUEUE(WAIT), 0))->summary, "n1") == 0); - ASSERT(strcmp(((struct notification*) g_queue_peek_nth(QUEUE(WAIT), 1))->summary, "n2") == 0); - - queues_teardown(); - PASS(); + settings.notification_limit = 5; + struct notification *n1, *n2, *n3; + queues_init(); + + n1 = test_notification("n1", 0); + n2 = test_notification("n2", 0); + n3 = test_notification("n3", 0); + + n1->override_pause_level = 0; + n2->override_pause_level = 5; + n3->override_pause_level = 10; + + queues_notification_insert(n1); + queues_notification_insert(n2); + queues_notification_insert(n3); + + queues_update(STATUS_PAUSE_7, time_monotonic_now()); + QUEUE_LEN_ALL(2, 1, 0); + ASSERT( + strcmp( + ((struct notification *)g_queue_peek_nth(QUEUE(DISP), 0))->summary, + "n3") + == 0); + ASSERT( + strcmp( + ((struct notification *)g_queue_peek_nth(QUEUE(WAIT), 0))->summary, + "n1") + == 0); + ASSERT( + strcmp( + ((struct notification *)g_queue_peek_nth(QUEUE(WAIT), 1))->summary, + "n2") + == 0); + + queues_update(STATUS_NORMAL, time_monotonic_now()); + QUEUE_LEN_ALL(0, 3, 0); + + queues_update(STATUS_PAUSE_7, time_monotonic_now()); + QUEUE_LEN_ALL(2, 1, 0); + ASSERT( + strcmp( + ((struct notification *)g_queue_peek_nth(QUEUE(DISP), 0))->summary, + "n3") + == 0); + ASSERT( + strcmp( + ((struct notification *)g_queue_peek_nth(QUEUE(WAIT), 0))->summary, + "n1") + == 0); + ASSERT( + strcmp( + ((struct notification *)g_queue_peek_nth(QUEUE(WAIT), 1))->summary, + "n2") + == 0); + + queues_teardown(); + PASS(); } TEST test_queues_update_seeping(void) { - settings.notification_limit = 5; - settings.sort = SORT_TYPE_URGENCY_DESCENDING; - 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, time_monotonic_now()); - 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, time_monotonic_now()); - 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(); + settings.notification_limit = 5; + settings.sort = SORT_TYPE_URGENCY_DESCENDING; + 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, time_monotonic_now()); + 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, time_monotonic_now()); + 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.notification_limit = 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, time_monotonic_now()); - QUEUE_LEN_ALL(0,3,0); - - queues_notification_insert(n4); - queues_update(STATUS_NORMAL, time_monotonic_now()); - QUEUE_LEN_ALL(0,4,0); - - queues_notification_insert(n5); - queues_update(STATUS_NORMAL, time_monotonic_now()); - QUEUE_LEN_ALL(2,3,0); - - queues_teardown(); - PASS(); + settings.indicate_hidden = true; + settings.notification_limit = 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, time_monotonic_now()); + QUEUE_LEN_ALL(0, 3, 0); + + queues_notification_insert(n4); + queues_update(STATUS_NORMAL, time_monotonic_now()); + QUEUE_LEN_ALL(0, 4, 0); + + queues_notification_insert(n5); + queues_update(STATUS_NORMAL, time_monotonic_now()); + 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.notification_limit = 4; - struct notification *n1, *n2, *n3; - queues_init(); + // Test 3 notifications during fullscreen and only the one + // with the lowest priority is eligible to get shown + settings.notification_limit = 4; + struct notification *n1, *n2, *n3; + queues_init(); - n1 = test_notification("n1", 0); - n2 = test_notification("n2", 0); - n3 = test_notification("n3", 0); + 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; + n1->fullscreen = FS_DELAY; + n2->fullscreen = FS_DELAY; + n3->fullscreen = FS_SHOW; - n3->urgency = URG_LOW; + n3->urgency = URG_LOW; - queues_notification_insert(n1); - queues_notification_insert(n2); - queues_update(STATUS_FS, time_monotonic_now()); - QUEUE_LEN_ALL(2,0,0); + queues_notification_insert(n1); + queues_notification_insert(n2); + queues_update(STATUS_FS, time_monotonic_now()); + QUEUE_LEN_ALL(2, 0, 0); - queues_notification_insert(n3); + queues_notification_insert(n3); - queues_update(STATUS_FS, time_monotonic_now()); + queues_update(STATUS_FS, time_monotonic_now()); - QUEUE_LEN_ALL(2,1,0); - QUEUE_CONTAINS(WAIT, n1); - QUEUE_CONTAINS(WAIT, n2); - QUEUE_CONTAINS(DISP, n3); + QUEUE_LEN_ALL(2, 1, 0); + QUEUE_CONTAINS(WAIT, n1); + QUEUE_CONTAINS(WAIT, n2); + QUEUE_CONTAINS(DISP, n3); - queues_teardown(); - PASS(); + queues_teardown(); + PASS(); } TEST test_queues_timeout_before_paused(void) { - struct notification *n; - queues_init(); + struct notification *n; + queues_init(); - n = test_notification("n", 10); + n = test_notification("n", 10); - queues_notification_insert(n); - queues_update(STATUS_NORMAL, time_monotonic_now()); + queues_notification_insert(n); + queues_update(STATUS_NORMAL, time_monotonic_now()); - n->start -= S2US(11); - queues_update(STATUS_PAUSE, time_monotonic_now()); + n->start -= S2US(11); + queues_update(STATUS_PAUSE, time_monotonic_now()); - QUEUE_LEN_ALL(0,0,1); + QUEUE_LEN_ALL(0, 0, 1); - queues_teardown(); - PASS(); + queues_teardown(); + PASS(); } TEST test_queue_find_by_id(void) { - struct notification *n; - gint id; - queues_init(); + struct notification *n; + gint id; + queues_init(); - n = test_notification("n", 0); - queues_notification_insert(n); - n = test_notification("n1", 0); - queues_notification_insert(n); - id = n->id; - n = test_notification("n2", 0); - queues_notification_insert(n); + n = test_notification("n", 0); + queues_notification_insert(n); + n = test_notification("n1", 0); + queues_notification_insert(n); + id = n->id; + n = test_notification("n2", 0); + queues_notification_insert(n); - n = queues_get_by_id(id); + n = queues_get_by_id(id); - ASSERT(n->id == id); - ASSERT(!strncmp(n->summary, "n1", 2)); + ASSERT(n->id == id); + ASSERT(!strncmp(n->summary, "n1", 2)); - queues_teardown(); - PASS(); + queues_teardown(); + PASS(); } TEST test_queue_get_history(void) { - struct notification *n; - queues_init(); + struct notification *n; + queues_init(); - n = test_notification("n", -1); - n->skip_display = true; - queues_notification_insert(n); - n = test_notification("n1", -1); - n->skip_display = true; - queues_notification_insert(n); - n = test_notification("n3", -1); - n->skip_display = true; - queues_notification_insert(n); + n = test_notification("n", -1); + n->skip_display = true; + queues_notification_insert(n); + n = test_notification("n1", -1); + n->skip_display = true; + queues_notification_insert(n); + n = test_notification("n3", -1); + n->skip_display = true; + queues_notification_insert(n); - queues_update(STATUS_NORMAL, time_monotonic_now()); + queues_update(STATUS_NORMAL, time_monotonic_now()); - QUEUE_LEN_ALL(0, 0, 3); + QUEUE_LEN_ALL(0, 0, 3); - GList *h = queues_get_history(); - ASSERT(g_list_length(h) == 3); + GList *h = queues_get_history(); + ASSERT(g_list_length(h) == 3); - queues_teardown(); - PASS(); + queues_teardown(); + PASS(); } - -void print_queues(void) { - printf("\nQueues:\n"); - for (GList *iter = g_queue_peek_head_link(QUEUE_WAIT); iter; - iter = iter->next) { - struct notification *notif = iter->data; - printf("waiting %s\n", notif->summary); - } +void print_queues(void) +{ + printf("\nQueues:\n"); + for (GList *iter = g_queue_peek_head_link(QUEUE_WAIT); iter; + iter = iter->next) { + struct notification *notif = iter->data; + printf("waiting %s\n", notif->summary); + } } // Test if notifications are correctly sorted, even if dunst is paused in // between. See #838 for the issue. TEST test_queue_no_sort_and_pause(void) { - // Setting sort to false, this means that notifications will only be - // sorted based on time - settings.sort = false; - settings.notification_limit = 0; - struct notification *n; - queues_init(); - - n = test_notification("n0", 0); - queues_notification_insert(n); - queues_update(STATUS_NORMAL, time_monotonic_now()); - - n = test_notification("n1", 0); - queues_notification_insert(n); - queues_update(STATUS_NORMAL, time_monotonic_now()); - - n = test_notification("n2", 0); - queues_notification_insert(n); - queues_update(STATUS_PAUSE, time_monotonic_now()); - - n = test_notification("n3", 0); - queues_notification_insert(n); - queues_update(STATUS_PAUSE, time_monotonic_now()); - /* queues_update(STATUS_NORMAL, time_monotonic_now()); */ - - n = test_notification("n4", 0); - queues_notification_insert(n); - queues_update(STATUS_NORMAL, time_monotonic_now()); - - QUEUE_LEN_ALL(0, 5, 0); - - const char* order[] = { - "n0", - "n1", - "n2", - "n3", - "n4", - }; - - for (size_t i = 0; i < g_queue_get_length(QUEUE_DISP); i++) { - struct notification *notif = g_queue_peek_nth(QUEUE_DISP, i); - ASSERTm("Notifications are not in the right order", - STR_EQ(notif->summary, order[i])); - } - - queues_teardown(); - PASS(); + // Setting sort to false, this means that notifications will only be + // sorted based on time + settings.sort = false; + settings.notification_limit = 0; + struct notification *n; + queues_init(); + + n = test_notification("n0", 0); + queues_notification_insert(n); + queues_update(STATUS_NORMAL, time_monotonic_now()); + + n = test_notification("n1", 0); + queues_notification_insert(n); + queues_update(STATUS_NORMAL, time_monotonic_now()); + + n = test_notification("n2", 0); + queues_notification_insert(n); + queues_update(STATUS_PAUSE, time_monotonic_now()); + + n = test_notification("n3", 0); + queues_notification_insert(n); + queues_update(STATUS_PAUSE, time_monotonic_now()); + /* queues_update(STATUS_NORMAL, time_monotonic_now()); */ + + n = test_notification("n4", 0); + queues_notification_insert(n); + queues_update(STATUS_NORMAL, time_monotonic_now()); + + QUEUE_LEN_ALL(0, 5, 0); + + const char *order[] = { + "n0", + "n1", + "n2", + "n3", + "n4", + }; + + for (size_t i = 0; i < g_queue_get_length(QUEUE_DISP); i++) { + struct notification *notif = g_queue_peek_nth(QUEUE_DISP, i); + ASSERTm("Notifications are not in the right order", + STR_EQ(notif->summary, order[i])); + } + + queues_teardown(); + PASS(); } SUITE(suite_queues) { - bool store = settings.stack_duplicates; - settings.stack_duplicates = false; - - RUN_TEST(test_datachange_beginning_empty); - RUN_TEST(test_datachange_endless); - RUN_TEST(test_datachange_endless_agethreshold); - RUN_TEST(test_datachange_agethreshold_at_second); - RUN_TEST(test_datachange_queues); - RUN_TEST(test_datachange_ttl); - RUN_TEST(test_queue_history_clear); - RUN_TEST(test_queue_history_overfull); - RUN_TEST(test_queue_history_pushall); - RUN_TEST(test_queue_history_remove_by_id); - 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_notification_skip_display); - RUN_TEST(test_queue_notification_skip_display_redisplayed); - RUN_TEST(test_queue_notification_skip_display_redisplayed_by_random_id); - RUN_TEST(test_queue_stacking); - RUN_TEST(test_queue_stacktag); - RUN_TEST(test_queue_different_stacktag); - RUN_TEST(test_queue_stacktag_different_appid); - 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_pause_level - ); - 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); - RUN_TEST(test_queue_find_by_id); - RUN_TEST(test_queue_no_sort_and_pause); - RUN_TEST(test_queue_get_history); - - settings.stack_duplicates = store; + bool store = settings.stack_duplicates; + settings.stack_duplicates = false; + + RUN_TEST(test_datachange_beginning_empty); + RUN_TEST(test_datachange_endless); + RUN_TEST(test_datachange_endless_agethreshold); + RUN_TEST(test_datachange_agethreshold_at_second); + RUN_TEST(test_datachange_queues); + RUN_TEST(test_datachange_ttl); + RUN_TEST(test_queue_history_clear); + RUN_TEST(test_queue_history_overfull); + RUN_TEST(test_queue_history_pushall); + RUN_TEST(test_queue_history_remove_by_id); + 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_notification_skip_display); + RUN_TEST(test_queue_notification_skip_display_redisplayed); + RUN_TEST(test_queue_notification_skip_display_redisplayed_by_random_id); + RUN_TEST(test_queue_stacking); + RUN_TEST(test_queue_stacktag); + RUN_TEST(test_queue_different_stacktag); + RUN_TEST(test_queue_stacktag_different_appid); + 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_pause_level); + 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); + RUN_TEST(test_queue_find_by_id); + RUN_TEST(test_queue_no_sort_and_pause); + RUN_TEST(test_queue_get_history); + + settings.stack_duplicates = store; } /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/test/queues.h b/test/queues.h index 86e5863d1..05689f695 100644 --- a/test/queues.h +++ b/test/queues.h @@ -3,37 +3,62 @@ #ifndef DUNST_TEST_QUEUES_H #define DUNST_TEST_QUEUES_H -#include #include +#include #include "../src/notification.h" #include "../src/queues.h" -#define STATUS_NORMAL ((struct dunst_status) {.fullscreen=false, .pause_level=0, .idle=false}) -#define STATUS_IDLE ((struct dunst_status) {.fullscreen=false, .pause_level=0, .idle=true}) -#define STATUS_FSIDLE ((struct dunst_status) {.fullscreen=true, .pause_level=0, .idle=true}) -#define STATUS_FS ((struct dunst_status) {.fullscreen=true, .pause_level=0, .idle=false}) -#define STATUS_PAUSE ((struct dunst_status) {.fullscreen=false, .pause_level=100, .idle=false}) -#define STATUS_PAUSE_7 ((struct dunst_status) {.fullscreen=false, .pause_level=7, .idle=false}) +#define STATUS_NORMAL \ + ((struct dunst_status){ \ + .fullscreen = false, .pause_level = 0, .idle = false}) +#define STATUS_IDLE \ + ((struct dunst_status){.fullscreen = false, .pause_level = 0, .idle = true}) +#define STATUS_FSIDLE \ + ((struct dunst_status){.fullscreen = true, .pause_level = 0, .idle = true}) +#define STATUS_FS \ + ((struct dunst_status){.fullscreen = true, .pause_level = 0, .idle = false}) +#define STATUS_PAUSE \ + ((struct dunst_status){ \ + .fullscreen = false, .pause_level = 100, .idle = false}) +#define STATUS_PAUSE_7 \ + ((struct dunst_status){ \ + .fullscreen = false, .pause_level = 7, .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_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_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 QUEUE_NOT_CONTAINS(q, n) QUEUE_NOT_CONTAINSm("QUEUE_NOT_CONTAINS(" #q "," #n ")", q, n) -#define QUEUE_NOT_CONTAINSm(msg, q, n) ASSERTm(msg, g_queue_find(QUEUE(q), n) == NULL) +#define QUEUE_NOT_CONTAINS(q, n) \ + QUEUE_NOT_CONTAINSm("QUEUE_NOT_CONTAINS(" #q "," #n ")", q, n) +#define QUEUE_NOT_CONTAINSm(msg, q, n) \ + ASSERTm(msg, g_queue_find(QUEUE(q), n) == NULL) -#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) +#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) /* Retrieve a notification by its id. Solely for debugging purposes */ struct notification *queues_debug_find_notification_by_id(int id); diff --git a/test/rules.c b/test/rules.c index 04df52147..a92353ddb 100644 --- a/test/rules.c +++ b/test/rules.c @@ -6,85 +6,87 @@ extern const char *base; // test filtering rules matching -TEST test_pattern_match(void) { - // NULL should match everything - ASSERT(rule_field_matches_string("anything", NULL)); - - // Literal matches - ASSERT(rule_field_matches_string("asdf", "asdf")); - ASSERT(rule_field_matches_string("test123", "test123")); - - ASSERT(rule_field_matches_string("!", "!")); - ASSERT(rule_field_matches_string("!asd", "!asd")); - ASSERT(rule_field_matches_string("/as/d", "/as/d")); - ASSERT(rule_field_matches_string("/as/d", "/as/d")); - - // ranges - ASSERT(rule_field_matches_string("ac", "[a-z][a-z]")); - - // Non-matches - ASSERT_FALSE(rule_field_matches_string("asd", "!asd")); - ASSERT_FALSE(rule_field_matches_string("ffff", "*asd")); - ASSERT_FALSE(rule_field_matches_string("ffff", "?")); - ASSERT_FALSE(rule_field_matches_string("Ac", "[a-z][a-z]")); - - // Things that differ between fnmatch(3) and regex(3) - - if (settings.enable_regex) { - // Single character matching - ASSERT(rule_field_matches_string("a", ".")); - - // Wildcard matching - ASSERT(rule_field_matches_string("anything", ".*")); - ASSERT(rule_field_matches_string("*", ".*")); - ASSERT(rule_field_matches_string("", ".*")); - ASSERT(rule_field_matches_string("ffffasd", ".*asd")); - - // Substring matching - ASSERT(rule_field_matches_string("asd", "")); - ASSERT(rule_field_matches_string("asd", "sd")); - ASSERT(rule_field_matches_string("asd", "a")); - ASSERT(rule_field_matches_string("asd", "d")); - ASSERT(rule_field_matches_string("asd", "asd")); - - // Match multiple strings - ASSERT(rule_field_matches_string("ghj", "asd|dfg|ghj")); - ASSERT(rule_field_matches_string("asd", "asd|dfg|ghj")); - ASSERT(rule_field_matches_string("dfg", "asd|dfg|ghj")); - ASSERT_FALSE(rule_field_matches_string("azd", "asd|dfg|ghj")); - - // Special characters - ASSERT_FALSE(rule_field_matches_string("{", "{")); - ASSERT(rule_field_matches_string("{", "\\{")); - ASSERT(rule_field_matches_string("a", "(a)")); - } else { - // Single character matching - ASSERT(rule_field_matches_string("a", "?")); - - // Wildcard matching - ASSERT(rule_field_matches_string("anything", "*")); - ASSERT(rule_field_matches_string("*", "*")); - ASSERT(rule_field_matches_string("", "*")); - ASSERT(rule_field_matches_string("ffffasd", "*asd")); - - // Substring matching - ASSERT_FALSE(rule_field_matches_string("asd", "")); - ASSERT_FALSE(rule_field_matches_string("asd", "sd")); - ASSERT_FALSE(rule_field_matches_string("asd", "a")); - ASSERT_FALSE(rule_field_matches_string("asd", "d")); - ASSERT(rule_field_matches_string("asd", "asd")); - } - PASS(); +TEST test_pattern_match(void) +{ + // NULL should match everything + ASSERT(rule_field_matches_string("anything", NULL)); + + // Literal matches + ASSERT(rule_field_matches_string("asdf", "asdf")); + ASSERT(rule_field_matches_string("test123", "test123")); + + ASSERT(rule_field_matches_string("!", "!")); + ASSERT(rule_field_matches_string("!asd", "!asd")); + ASSERT(rule_field_matches_string("/as/d", "/as/d")); + ASSERT(rule_field_matches_string("/as/d", "/as/d")); + + // ranges + ASSERT(rule_field_matches_string("ac", "[a-z][a-z]")); + + // Non-matches + ASSERT_FALSE(rule_field_matches_string("asd", "!asd")); + ASSERT_FALSE(rule_field_matches_string("ffff", "*asd")); + ASSERT_FALSE(rule_field_matches_string("ffff", "?")); + ASSERT_FALSE(rule_field_matches_string("Ac", "[a-z][a-z]")); + + // Things that differ between fnmatch(3) and regex(3) + + if (settings.enable_regex) { + // Single character matching + ASSERT(rule_field_matches_string("a", ".")); + + // Wildcard matching + ASSERT(rule_field_matches_string("anything", ".*")); + ASSERT(rule_field_matches_string("*", ".*")); + ASSERT(rule_field_matches_string("", ".*")); + ASSERT(rule_field_matches_string("ffffasd", ".*asd")); + + // Substring matching + ASSERT(rule_field_matches_string("asd", "")); + ASSERT(rule_field_matches_string("asd", "sd")); + ASSERT(rule_field_matches_string("asd", "a")); + ASSERT(rule_field_matches_string("asd", "d")); + ASSERT(rule_field_matches_string("asd", "asd")); + + // Match multiple strings + ASSERT(rule_field_matches_string("ghj", "asd|dfg|ghj")); + ASSERT(rule_field_matches_string("asd", "asd|dfg|ghj")); + ASSERT(rule_field_matches_string("dfg", "asd|dfg|ghj")); + ASSERT_FALSE(rule_field_matches_string("azd", "asd|dfg|ghj")); + + // Special characters + ASSERT_FALSE(rule_field_matches_string("{", "{")); + ASSERT(rule_field_matches_string("{", "\\{")); + ASSERT(rule_field_matches_string("a", "(a)")); + } else { + // Single character matching + ASSERT(rule_field_matches_string("a", "?")); + + // Wildcard matching + ASSERT(rule_field_matches_string("anything", "*")); + ASSERT(rule_field_matches_string("*", "*")); + ASSERT(rule_field_matches_string("", "*")); + ASSERT(rule_field_matches_string("ffffasd", "*asd")); + + // Substring matching + ASSERT_FALSE(rule_field_matches_string("asd", "")); + ASSERT_FALSE(rule_field_matches_string("asd", "sd")); + ASSERT_FALSE(rule_field_matches_string("asd", "a")); + ASSERT_FALSE(rule_field_matches_string("asd", "d")); + ASSERT(rule_field_matches_string("asd", "asd")); + } + PASS(); } -SUITE(suite_rules) { - bool store = settings.enable_regex; +SUITE(suite_rules) +{ + bool store = settings.enable_regex; - settings.enable_regex = false; - RUN_TEST(test_pattern_match); + settings.enable_regex = false; + RUN_TEST(test_pattern_match); - settings.enable_regex = true; - RUN_TEST(test_pattern_match); + settings.enable_regex = true; + RUN_TEST(test_pattern_match); - settings.enable_regex = store; + settings.enable_regex = store; } diff --git a/test/setting.c b/test/setting.c index 208e44dd7..e171a6b0b 100644 --- a/test/setting.c +++ b/test/setting.c @@ -1,5 +1,5 @@ -#include "../src/settings.h" #include "../src/option_parser.h" +#include "../src/settings.h" #include "../src/settings_data.h" #include "greatest.h" @@ -11,117 +11,122 @@ extern const char *base; char *test_paths[2] = {0}; -TEST test_dunstrc_markup(void) { - settings_free(&settings); +TEST test_dunstrc_markup(void) +{ + settings_free(&settings); - test_paths[0] = g_strconcat(base, "/data/dunstrc.markup", NULL); - load_settings(test_paths); + test_paths[0] = g_strconcat(base, "/data/dunstrc.markup", NULL); + load_settings(test_paths); - ASSERT_STR_EQ(settings.font, "Monospace 8"); + ASSERT_STR_EQ(settings.font, "Monospace 8"); + const char *e_format = + "%s\\n%b"; // escape the \n since it would otherwise result in + // the newline character + const struct rule *r = get_rule("global"); + const char *got_format = r->format; + ASSERT_STR_EQ(e_format, got_format); + ASSERT(settings.indicate_hidden); - const char *e_format = "%s\\n%b"; // escape the \n since it would otherwise result in the newline character - const struct rule * r = get_rule("global"); - const char *got_format = r->format; - ASSERT_STR_EQ(e_format, got_format); - ASSERT(settings.indicate_hidden); - - g_clear_pointer(&test_paths[0], g_free); - PASS(); + g_clear_pointer(&test_paths[0], g_free); + PASS(); } -TEST test_dunstrc_nomarkup(void) { - settings_free(&settings); - - test_paths[0] = g_strconcat(base, "/data/dunstrc.nomarkup", NULL); - load_settings(test_paths); +TEST test_dunstrc_nomarkup(void) +{ + settings_free(&settings); - ASSERT_STR_EQ(settings.font, "Monospace 8"); + test_paths[0] = g_strconcat(base, "/data/dunstrc.nomarkup", NULL); + load_settings(test_paths); + ASSERT_STR_EQ(settings.font, "Monospace 8"); - const char *e_format = "%s\\n%b"; // escape the \n since it would otherwise result in the newline character - const struct rule * r = get_rule("global"); - const char *got_format = r->format; - ASSERT_STR_EQ(e_format, got_format); - ASSERT(settings.indicate_hidden); + const char *e_format = + "%s\\n%b"; // escape the \n since it would otherwise + // result in the newline character + const struct rule *r = get_rule("global"); + const char *got_format = r->format; + ASSERT_STR_EQ(e_format, got_format); + ASSERT(settings.indicate_hidden); - g_clear_pointer(&test_paths[0], g_free); - PASS(); + g_clear_pointer(&test_paths[0], g_free); + PASS(); } // Test if the defaults in code and in dunstrc match -TEST test_dunstrc_defaults(void) { - struct settings s_old = settings; - struct settings s_default; - struct settings s_dunstrc; +TEST test_dunstrc_defaults(void) +{ + struct settings s_old = settings; + struct settings s_default; + struct settings s_dunstrc; - test_paths[0] = g_strconcat(base, "/data/dunstrc.default", NULL); - set_defaults(); - s_default = settings; + test_paths[0] = g_strconcat(base, "/data/dunstrc.default", NULL); + set_defaults(); + s_default = settings; - load_settings(test_paths); - s_dunstrc = settings; + load_settings(test_paths); + s_dunstrc = settings; - ASSERT_EQ(s_default.corner_radius, s_dunstrc.corner_radius); - char message[500]; + ASSERT_EQ(s_default.corner_radius, s_dunstrc.corner_radius); + char message[500]; - for (size_t i = 0; i < G_N_ELEMENTS(allowed_settings); i++) { - if (!allowed_settings[i].value) { - continue; // it's a rule, that's harder to test - } - if (allowed_settings[i].different_default) { - continue; // Skip testing, since it's an intended difference. - } - size_t offset = (char*)allowed_settings[i].value - (char*)&settings; - enum setting_type type = allowed_settings[i].type; - snprintf(message, 500, "The default of setting %s does not match. Different defaults are set in code and dunstrc" - , allowed_settings[i].name); - switch (type) { - case TYPE_CUSTOM: - if (allowed_settings[i].parser == string_parse_bool) { - { - bool a = *(bool*) ((char*) &s_default + offset); - bool b = *(bool*) ((char*) &s_dunstrc + offset); - ASSERT_EQm(message, a, b); - } - break; - } else if (allowed_settings[i].parser == string_parse_maybe_int) { - // not a number - break; - } - break; - case TYPE_TIME: - case TYPE_INT: - { - int a = *(int*) ((char*) &s_default + offset); - int b = *(int*) ((char*) &s_dunstrc + offset); - ASSERT_EQm(message, a, b); - } - break; - case TYPE_DOUBLE: - case TYPE_STRING: - case TYPE_PATH: - case TYPE_LIST: - case TYPE_LENGTH: - case TYPE_COLOR: - case TYPE_GRADIENT: - break; // TODO implement these checks as well - default: - printf("Type unknown %s:%d\n", __FILE__, __LINE__); + for (size_t i = 0; i < G_N_ELEMENTS(allowed_settings); i++) { + if (!allowed_settings[i].value) { + continue; // it's a rule, that's harder to test + } + if (allowed_settings[i].different_default) { + continue; // Skip testing, since it's an intended difference. + } + size_t offset = (char *)allowed_settings[i].value - (char *)&settings; + enum setting_type type = allowed_settings[i].type; + snprintf(message, + 500, + "The default of setting %s does not match. Different defaults " + "are set in code and dunstrc", + allowed_settings[i].name); + switch (type) { + case TYPE_CUSTOM: + if (allowed_settings[i].parser == string_parse_bool) { + { + bool a = *(bool *)((char *)&s_default + offset); + bool b = *(bool *)((char *)&s_dunstrc + offset); + ASSERT_EQm(message, a, b); } - /* printf("%zu\n", offset); */ + break; + } else if (allowed_settings[i].parser == string_parse_maybe_int) { + // not a number + break; + } + break; + case TYPE_TIME: + case TYPE_INT: { + int a = *(int *)((char *)&s_default + offset); + int b = *(int *)((char *)&s_dunstrc + offset); + ASSERT_EQm(message, a, b); + } break; + case TYPE_DOUBLE: + case TYPE_STRING: + case TYPE_PATH: + case TYPE_LIST: + case TYPE_LENGTH: + case TYPE_COLOR: + case TYPE_GRADIENT: break; // TODO implement these checks as well + default: printf("Type unknown %s:%d\n", __FILE__, __LINE__); } + /* printf("%zu\n", offset); */ + } - // NOTE: The last loaded settings should not be freed here - settings_free(&s_old); - settings_free(&s_default); + // NOTE: The last loaded settings should not be freed here + settings_free(&s_old); + settings_free(&s_default); - g_clear_pointer(&test_paths[0], g_free); - PASS(); + g_clear_pointer(&test_paths[0], g_free); + PASS(); } -SUITE(suite_setting) { - RUN_TEST(test_dunstrc_markup); - RUN_TEST(test_dunstrc_nomarkup); - RUN_TEST(test_dunstrc_defaults); +SUITE(suite_setting) +{ + RUN_TEST(test_dunstrc_markup); + RUN_TEST(test_dunstrc_nomarkup); + RUN_TEST(test_dunstrc_defaults); } diff --git a/test/settings_data.c b/test/settings_data.c index 25c92172c..5b3c3fffb 100644 --- a/test/settings_data.c +++ b/test/settings_data.c @@ -7,142 +7,183 @@ extern const char *base; TEST test_names_valid(void) { - for (size_t i = 0; i < G_N_ELEMENTS(allowed_settings); i++) { - gchar *error1 = g_strdup_printf("Setting name is null (setting description is \"%s\")", allowed_settings[i].description); - gchar *error2 = g_strdup_printf("Setting name is empty (setting description is \"%s\")", allowed_settings[i].description); - ASSERTm(error1, allowed_settings[i].name); - ASSERTm(error2, strlen(allowed_settings[i].name)); - g_free(error1); - g_free(error2); - } - PASS(); + for (size_t i = 0; i < G_N_ELEMENTS(allowed_settings); i++) { + gchar *error1 = g_strdup_printf( + "Setting name is null (setting description is \"%s\")", + allowed_settings[i].description); + gchar *error2 = g_strdup_printf( + "Setting name is empty (setting description is \"%s\")", + allowed_settings[i].description); + ASSERTm(error1, allowed_settings[i].name); + ASSERTm(error2, strlen(allowed_settings[i].name)); + g_free(error1); + g_free(error2); + } + PASS(); } TEST test_description_valid(void) { - for (size_t i = 0; i < G_N_ELEMENTS(allowed_settings); i++) { - gchar *error1 = g_strdup_printf("Description of setting %s is null", allowed_settings[i].name); - gchar *error2 = g_strdup_printf("Description of setting %s is empty", allowed_settings[i].name); - ASSERTm(error1, allowed_settings[i].description); - ASSERTm(error2, strlen(allowed_settings[i].description)); - g_free(error1); - g_free(error2); - } - PASS(); + for (size_t i = 0; i < G_N_ELEMENTS(allowed_settings); i++) { + gchar *error1 = g_strdup_printf("Description of setting %s is null", + allowed_settings[i].name); + gchar *error2 = g_strdup_printf("Description of setting %s is empty", + allowed_settings[i].name); + ASSERTm(error1, allowed_settings[i].description); + ASSERTm(error2, strlen(allowed_settings[i].description)); + g_free(error1); + g_free(error2); + } + PASS(); } -#define BETWEEN(arg, low, high) (((arg) > (low) ) && ((arg) < (high))) +#define BETWEEN(arg, low, high) (((arg) > (low)) && ((arg) < (high))) TEST test_type_valid(void) { - for (size_t i = 0; i < G_N_ELEMENTS(allowed_settings); i++) { - gchar *error1 = g_strdup_printf("Type of setting %s is not valid: %i", allowed_settings[i].name, allowed_settings[i].type); - ASSERTm(error1, BETWEEN(allowed_settings[i].type, TYPE_MIN, TYPE_MAX)); - g_free(error1); - } - PASS(); + for (size_t i = 0; i < G_N_ELEMENTS(allowed_settings); i++) { + gchar *error1 = g_strdup_printf("Type of setting %s is not valid: %i", + allowed_settings[i].name, + allowed_settings[i].type); + ASSERTm(error1, BETWEEN(allowed_settings[i].type, TYPE_MIN, TYPE_MAX)); + g_free(error1); + } + PASS(); } TEST test_section_valid(void) { - for (size_t i = 0; i < G_N_ELEMENTS(allowed_settings); i++) { - gchar *error1 = g_strdup_printf("Section of setting %s is null", allowed_settings[i].name); - gchar *error2 = g_strdup_printf("Section of setting %s is empty", allowed_settings[i].name); - ASSERTm(error1, allowed_settings[i].section); - ASSERTm(error2, strlen(allowed_settings[i].section)); - g_free(error1); - g_free(error2); - } - PASS(); + for (size_t i = 0; i < G_N_ELEMENTS(allowed_settings); i++) { + gchar *error1 = g_strdup_printf("Section of setting %s is null", + allowed_settings[i].name); + gchar *error2 = g_strdup_printf("Section of setting %s is empty", + allowed_settings[i].name); + ASSERTm(error1, allowed_settings[i].section); + ASSERTm(error2, strlen(allowed_settings[i].section)); + g_free(error1); + g_free(error2); + } + PASS(); } TEST test_default_value_valid(void) { - for (size_t i = 0; i < G_N_ELEMENTS(allowed_settings); i++) { - gchar *error1 = g_strdup_printf("Default_value of setting %s is null", allowed_settings[i].name); - gchar *error2 = g_strdup_printf("Default_value of setting %s is empty", allowed_settings[i].name); - ASSERTm(error1, allowed_settings[i].default_value); - if (allowed_settings[i].type != TYPE_STRING) - ASSERTm(error2, strlen(allowed_settings[i].default_value)); - g_free(error1); - g_free(error2); - } - PASS(); + for (size_t i = 0; i < G_N_ELEMENTS(allowed_settings); i++) { + gchar *error1 = g_strdup_printf("Default_value of setting %s is null", + allowed_settings[i].name); + gchar *error2 = g_strdup_printf("Default_value of setting %s is empty", + allowed_settings[i].name); + ASSERTm(error1, allowed_settings[i].default_value); + if (allowed_settings[i].type != TYPE_STRING) + ASSERTm(error2, strlen(allowed_settings[i].default_value)); + g_free(error1); + g_free(error2); + } + PASS(); } TEST test_value_non_null(void) { - for (size_t i = 0; i < G_N_ELEMENTS(allowed_settings); i++) { - gchar *error1 = g_strdup_printf("Error in settting %s. A setting must have a 'value' or a 'rule_offset', or both.", - allowed_settings[i].name); - ASSERTm(error1, allowed_settings[i].value || - allowed_settings[i].rule_offset); - g_free(error1); - } - PASS(); + for (size_t i = 0; i < G_N_ELEMENTS(allowed_settings); i++) { + gchar *error1 = + g_strdup_printf("Error in settting %s. A setting must have a " + "'value' or a 'rule_offset', or both.", + allowed_settings[i].name); + ASSERTm(error1, + allowed_settings[i].value || allowed_settings[i].rule_offset); + g_free(error1); + } + PASS(); } TEST test_valid_parser_and_data_per_type(void) { - for (size_t i = 0; i < G_N_ELEMENTS(allowed_settings); i++) { - struct setting curr = allowed_settings[i]; - switch (curr.type) { - case TYPE_STRING: - case TYPE_TIME: - case TYPE_DOUBLE: - case TYPE_LENGTH: - case TYPE_COLOR: - case TYPE_GRADIENT: - case TYPE_INT: ; // no parser and no parser data needed - gchar *error1 = g_strdup_printf("Parser of setting %s should be NULL. It's not needed for this type", curr.name); - gchar *error2 = g_strdup_printf("Parser data of setting %s should be NULL. It's not needed for this type", curr.name); - ASSERTm(error1, !curr.parser); - ASSERTm(error2, !curr.parser_data); - g_free(error1); - g_free(error2); - break; - case TYPE_CUSTOM: ; // both parser data and parser are needed - gchar *error3 = g_strdup_printf("Parser of setting %s should not be NULL. It's needed for this type", curr.name); - gchar *error4 = g_strdup_printf("Parser data of setting %s should not be NULL. It's needed for this type", curr.name); - ASSERTm(error3, curr.parser); - ASSERTm(error4, curr.parser_data); - g_free(error3); - g_free(error4); - break; - case TYPE_LIST: ; // only parser data is needed - gchar *error5 = g_strdup_printf("Parser of setting %s should be NULL. It's needed not for this type", curr.name); - gchar *error6 = g_strdup_printf("Parser data of setting %s should not be NULL. It's needed for this type", curr.name); - ASSERTm(error5, !curr.parser); - ASSERTm(error6, curr.parser_data); - g_free(error5); - g_free(error6); - break; - case TYPE_PATH: ; // only parser data is neede, but when it's a rule none is needed. - gchar *error7 = g_strdup_printf("Parser of setting %s should be NULL. It's needed not for this type", curr.name); - gchar *error8 = g_strdup_printf("Parser data of setting %s should not be NULL. It's needed for this type", curr.name); - bool is_rule = !curr.value; // if it doesn't have a 'value' it's a rule - ASSERTm(error7, !curr.parser); - ASSERTm(error8, is_rule || curr.parser_data); - g_free(error7); - g_free(error8); - break; - default: ; - gchar *error20 = g_strdup_printf("You should make a test for type %i", curr.type); - FAILm(error20); - break; - } + for (size_t i = 0; i < G_N_ELEMENTS(allowed_settings); i++) { + struct setting curr = allowed_settings[i]; + switch (curr.type) { + case TYPE_STRING: + case TYPE_TIME: + case TYPE_DOUBLE: + case TYPE_LENGTH: + case TYPE_COLOR: + case TYPE_GRADIENT: + case TYPE_INT: ; // no parser and no parser data needed + gchar *error1 = + g_strdup_printf("Parser of setting %s should be NULL. It's not " + "needed for this type", + curr.name); + gchar *error2 = + g_strdup_printf("Parser data of setting %s should be NULL. " + "It's not needed for this type", + curr.name); + ASSERTm(error1, !curr.parser); + ASSERTm(error2, !curr.parser_data); + g_free(error1); + g_free(error2); + break; + case TYPE_CUSTOM:; // both parser data and parser are needed + gchar *error3 = + g_strdup_printf("Parser of setting %s should not be NULL. It's " + "needed for this type", + curr.name); + gchar *error4 = + g_strdup_printf("Parser data of setting %s should not be NULL. " + "It's needed for this type", + curr.name); + ASSERTm(error3, curr.parser); + ASSERTm(error4, curr.parser_data); + g_free(error3); + g_free(error4); + break; + case TYPE_LIST:; // only parser data is needed + gchar *error5 = + g_strdup_printf("Parser of setting %s should be NULL. It's " + "needed not for this type", + curr.name); + gchar *error6 = + g_strdup_printf("Parser data of setting %s should not be NULL. " + "It's needed for this type", + curr.name); + ASSERTm(error5, !curr.parser); + ASSERTm(error6, curr.parser_data); + g_free(error5); + g_free(error6); + break; + case TYPE_PATH:; // only parser data is neede, but when it's a rule none + // is needed. + gchar *error7 = + g_strdup_printf("Parser of setting %s should be NULL. It's " + "needed not for this type", + curr.name); + gchar *error8 = + g_strdup_printf("Parser data of setting %s should not be NULL. " + "It's needed for this type", + curr.name); + bool is_rule = + !curr.value; // if it doesn't have a 'value' it's a rule + ASSERTm(error7, !curr.parser); + ASSERTm(error8, is_rule || curr.parser_data); + g_free(error7); + g_free(error8); + break; + default:; + gchar *error20 = g_strdup_printf( + "You should make a test for type %i", curr.type); + FAILm(error20); + break; } - PASS(); + } + PASS(); } SUITE(suite_settings_data) { - RUN_TEST(test_names_valid); - RUN_TEST(test_description_valid); - RUN_TEST(test_type_valid); - RUN_TEST(test_section_valid); - RUN_TEST(test_default_value_valid); - RUN_TEST(test_value_non_null); - RUN_TEST(test_valid_parser_and_data_per_type); + RUN_TEST(test_names_valid); + RUN_TEST(test_description_valid); + RUN_TEST(test_type_valid); + RUN_TEST(test_section_valid); + RUN_TEST(test_default_value_valid); + RUN_TEST(test_value_non_null); + RUN_TEST(test_valid_parser_and_data_per_type); } /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/test/test-install.sh b/test/test-install.sh index bf366cc07..2e933e74c 100755 --- a/test/test-install.sh +++ b/test/test-install.sh @@ -14,12 +14,12 @@ export SERVICEDIR_SYSTEMD="/systemd" export SERVICEDIR_DBUS="/dbus" do_make() { # for convenience/conciseness - make -C "${BASE}" "$@" + make -C "${BASE}" "$@" } check_dest() { - # Check file list given on stdin and see if all are actually present - diff -u <(find "${DESTDIR}" -type f -printf "%P\n" | sort) <(sort -) + # Check file list given on stdin and see if all are actually present + diff -u <(find "${DESTDIR}" -type f -printf "%P\n" | sort) <(sort -) } do_make install diff --git a/test/test.c b/test/test.c index 5dd6db8ef..bec26b3e9 100644 --- a/test/test.c +++ b/test/test.c @@ -32,44 +32,46 @@ SUITE_EXTERN(suite_input); GREATEST_MAIN_DEFS(); -int main(int argc, char *argv[]) { - base = getenv("TESTDIR"); - base = realpath(base ? base : "./test", NULL); +int main(int argc, char *argv[]) +{ + base = getenv("TESTDIR"); + base = realpath(base ? base : "./test", NULL); - /* By default do not print out warning messages, when executing tests. - * But if DUNST_TEST_LOG=1 is set in environment, print everything. */ - const char *log = getenv("DUNST_TEST_LOG"); - enum log_mask printlog = (log && atoi(log)) ? DUNST_LOG_ALL : DUNST_LOG_NONE; - dunst_log_init(printlog); + /* By default do not print out warning messages, when executing tests. + * But if DUNST_TEST_LOG=1 is set in environment, print everything. */ + const char *log = getenv("DUNST_TEST_LOG"); + enum log_mask printlog = + (log && atoi(log)) ? DUNST_LOG_ALL : DUNST_LOG_NONE; + dunst_log_init(printlog); - // initialize settings - char **configs = g_malloc0(2 * sizeof(char *)); - configs[0] = g_strconcat(base, "/data/dunstrc.default", NULL); - load_settings(configs); + // initialize settings + char **configs = g_malloc0(2 * sizeof(char *)); + configs[0] = g_strconcat(base, "/data/dunstrc.default", NULL); + load_settings(configs); - GREATEST_MAIN_BEGIN(); - RUN_SUITE(suite_utils); - RUN_SUITE(suite_option_parser); - RUN_SUITE(suite_notification); - RUN_SUITE(suite_markup); - RUN_SUITE(suite_misc); - RUN_SUITE(suite_icon); - RUN_SUITE(suite_queues); - RUN_SUITE(suite_dunst); - RUN_SUITE(suite_log); - RUN_SUITE(suite_menu); - RUN_SUITE(suite_settings_data); - RUN_SUITE(suite_dbus); - RUN_SUITE(suite_setting); - RUN_SUITE(suite_icon_lookup); - RUN_SUITE(suite_draw); - RUN_SUITE(suite_rules); - RUN_SUITE(suite_input); + GREATEST_MAIN_BEGIN(); + RUN_SUITE(suite_utils); + RUN_SUITE(suite_option_parser); + RUN_SUITE(suite_notification); + RUN_SUITE(suite_markup); + RUN_SUITE(suite_misc); + RUN_SUITE(suite_icon); + RUN_SUITE(suite_queues); + RUN_SUITE(suite_dunst); + RUN_SUITE(suite_log); + RUN_SUITE(suite_menu); + RUN_SUITE(suite_settings_data); + RUN_SUITE(suite_dbus); + RUN_SUITE(suite_setting); + RUN_SUITE(suite_icon_lookup); + RUN_SUITE(suite_draw); + RUN_SUITE(suite_rules); + RUN_SUITE(suite_input); - settings_free(&settings); - g_strfreev(configs); + settings_free(&settings); + g_strfreev(configs); - // this returns the error code - GREATEST_MAIN_END(); + // this returns the error code + GREATEST_MAIN_END(); } /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/test/utils.c b/test/utils.c index 0a2c46f7c..d3b763c70 100644 --- a/test/utils.c +++ b/test/utils.c @@ -7,19 +7,19 @@ TEST test_string_replace_char(void) { - char *text = g_malloc(128 * sizeof(char)); + char *text = g_malloc(128 * sizeof(char)); - strcpy(text, "a aa aaa"); - ASSERT_STR_EQ("b bb bbb", string_replace_char('a', 'b', text)); + strcpy(text, "a aa aaa"); + ASSERT_STR_EQ("b bb bbb", string_replace_char('a', 'b', text)); - strcpy(text, "Nothing to replace"); - ASSERT_STR_EQ("Nothing to replace", string_replace_char('s', 'a', text)); + strcpy(text, "Nothing to replace"); + ASSERT_STR_EQ("Nothing to replace", string_replace_char('s', 'a', text)); - strcpy(text, ""); - ASSERT_STR_EQ("", string_replace_char('a', 'b', text)); + strcpy(text, ""); + ASSERT_STR_EQ("", string_replace_char('a', 'b', text)); - g_free(text); - PASS(); + g_free(text); + PASS(); } /* @@ -30,185 +30,210 @@ TEST test_string_replace_char(void) TEST test_string_replace_all(void) { - char *text = g_malloc(128 * sizeof(char)); + char *text = g_malloc(128 * sizeof(char)); - strcpy(text, "aaaaa"); - ASSERT_STR_EQ("bbbbb", (text = string_replace_all("a", "b", text))); + strcpy(text, "aaaaa"); + ASSERT_STR_EQ("bbbbb", (text = string_replace_all("a", "b", text))); - strcpy(text, ""); - ASSERT_STR_EQ("", (text = string_replace_all("a", "b", text))); + strcpy(text, ""); + ASSERT_STR_EQ("", (text = string_replace_all("a", "b", text))); - strcpy(text, "Nothing to replace"); - ASSERT_STR_EQ((text = string_replace_all("z", "a", text)), "Nothing to replace"); + strcpy(text, "Nothing to replace"); + ASSERT_STR_EQ((text = string_replace_all("z", "a", text)), + "Nothing to replace"); - strcpy(text, "Reverse this"); - ASSERT_STR_EQ("Reverse sith", (text = string_replace_all("this", "sith", text))); + strcpy(text, "Reverse this"); + ASSERT_STR_EQ("Reverse sith", + (text = string_replace_all("this", "sith", text))); - strcpy(text, "abcdabc"); - ASSERT_STR_EQ("xyzabcdxyzabc", (text = string_replace_all("a", "xyza", text))); + strcpy(text, "abcdabc"); + ASSERT_STR_EQ("xyzabcdxyzabc", + (text = string_replace_all("a", "xyza", text))); - g_free(text); - PASS(); + g_free(text); + PASS(); } TEST test_string_append(void) { - char *exp; - - ASSERT_STR_EQ("text_sep_bit", (exp = string_append(g_strdup("text"), "bit", "_sep_"))); - g_free(exp); - ASSERT_STR_EQ("textbit", (exp = string_append(g_strdup("text"), "bit", NULL))); - g_free(exp); - ASSERT_STR_EQ("textbit", (exp = string_append(g_strdup("text"), "bit", ""))); - g_free(exp); - - ASSERT_STR_EQ("text", (exp = string_append(g_strdup("text"), "", NULL))); - g_free(exp); - ASSERT_STR_EQ("text", (exp = string_append(g_strdup("text"), "", "_sep_"))); - g_free(exp); - - ASSERT_STR_EQ("b", (exp = string_append(g_strdup(""), "b", NULL))); - g_free(exp); - ASSERT_STR_EQ("b", (exp = string_append(NULL, "b", "_sep_"))); - g_free(exp); - - ASSERT_STR_EQ("a", (exp = string_append(g_strdup("a"), "", NULL))); - g_free(exp); - ASSERT_STR_EQ("a", (exp = string_append(g_strdup("a"), NULL, "_sep_"))); - g_free(exp); - - ASSERT_STR_EQ("", (exp = string_append(g_strdup(""), "", "_sep_"))); - g_free(exp); - ASSERT_EQ(NULL, (exp = string_append(NULL, NULL, "_sep_"))); - g_free(exp); - - PASS(); + char *exp; + + ASSERT_STR_EQ("text_sep_bit", + (exp = string_append(g_strdup("text"), "bit", "_sep_"))); + g_free(exp); + ASSERT_STR_EQ("textbit", + (exp = string_append(g_strdup("text"), "bit", NULL))); + g_free(exp); + ASSERT_STR_EQ("textbit", + (exp = string_append(g_strdup("text"), "bit", ""))); + g_free(exp); + + ASSERT_STR_EQ("text", (exp = string_append(g_strdup("text"), "", NULL))); + g_free(exp); + ASSERT_STR_EQ("text", (exp = string_append(g_strdup("text"), "", "_sep_"))); + g_free(exp); + + ASSERT_STR_EQ("b", (exp = string_append(g_strdup(""), "b", NULL))); + g_free(exp); + ASSERT_STR_EQ("b", (exp = string_append(NULL, "b", "_sep_"))); + g_free(exp); + + ASSERT_STR_EQ("a", (exp = string_append(g_strdup("a"), "", NULL))); + g_free(exp); + ASSERT_STR_EQ("a", (exp = string_append(g_strdup("a"), NULL, "_sep_"))); + g_free(exp); + + ASSERT_STR_EQ("", (exp = string_append(g_strdup(""), "", "_sep_"))); + g_free(exp); + ASSERT_EQ(NULL, (exp = string_append(NULL, NULL, "_sep_"))); + g_free(exp); + + PASS(); } TEST test_string_strip_quotes(void) { - char *exp = string_strip_quotes(NULL); - ASSERT_FALSE(exp); + char *exp = string_strip_quotes(NULL); + ASSERT_FALSE(exp); - ASSERT_STR_EQ("NewString", (exp = string_strip_quotes("NewString"))); - g_free(exp); + ASSERT_STR_EQ("NewString", (exp = string_strip_quotes("NewString"))); + g_free(exp); - ASSERT_STR_EQ("becomes unquoted", (exp = string_strip_quotes("\"becomes unquoted\""))); - g_free(exp); + ASSERT_STR_EQ("becomes unquoted", + (exp = string_strip_quotes("\"becomes unquoted\""))); + g_free(exp); - ASSERT_STR_EQ("\"stays quoted", (exp = string_strip_quotes("\"stays quoted"))); - g_free(exp); + ASSERT_STR_EQ("\"stays quoted", + (exp = string_strip_quotes("\"stays quoted"))); + g_free(exp); - ASSERT_STR_EQ("stays quoted\"", (exp = string_strip_quotes("stays quoted\""))); - g_free(exp); + ASSERT_STR_EQ("stays quoted\"", + (exp = string_strip_quotes("stays quoted\""))); + g_free(exp); - ASSERT_STR_EQ("stays \"quoted\"", (exp = string_strip_quotes("stays \"quoted\""))); - g_free(exp); + ASSERT_STR_EQ("stays \"quoted\"", + (exp = string_strip_quotes("stays \"quoted\""))); + g_free(exp); - ASSERT_STR_EQ(" \"stays quoted\"", (exp = string_strip_quotes(" \"stays quoted\""))); - g_free(exp); + ASSERT_STR_EQ(" \"stays quoted\"", + (exp = string_strip_quotes(" \"stays quoted\""))); + g_free(exp); - PASS(); + PASS(); } TEST test_string_strip_delimited(void) { - char *text = g_malloc(128 * sizeof(char)); + char *text = g_malloc(128 * sizeof(char)); - strcpy(text, "A string_strip_delimited test"); - string_strip_delimited(text, '<', '>'); - ASSERT_STR_EQ("A string_strip_delimited test", text); + strcpy(text, "A string_strip_delimited test"); + string_strip_delimited(text, '<', '>'); + ASSERT_STR_EQ("A string_strip_delimited test", text); - strcpy(text, "Remove html tags"); - string_strip_delimited(text, '<', '>'); - ASSERT_STR_EQ("Remove html tags", text); + strcpy(text, "Remove html tags"); + string_strip_delimited(text, '<', '>'); + ASSERT_STR_EQ("Remove html tags", text); - strcpy(text, ""); - string_strip_delimited(text, '<', '>'); - ASSERT_STR_EQ("", text); + strcpy(text, ""); + string_strip_delimited(text, '<', '>'); + ASSERT_STR_EQ("", text); - strcpy(text, "Nothing is done if there are no delimiters in the string"); - string_strip_delimited(text, '<', '>'); - ASSERT_STR_EQ("Nothing is done if there are no delimiters in the string", text); + strcpy(text, "Nothing is done if there are no delimiters in the string"); + string_strip_delimited(text, '<', '>'); + ASSERT_STR_EQ("Nothing is done if there are no delimiters in the string", + text); - strcpy(text, "We <3 dunst"); - string_strip_delimited(text, '<', '>'); - ASSERT_STR_EQ("We <3 dunst", text); + strcpy(text, "We <3 dunst"); + string_strip_delimited(text, '<', '>'); + ASSERT_STR_EQ("We <3 dunst", text); - strcpy(text, "We <3 dunst"); - string_strip_delimited(text, '<', '>'); - ASSERT_STR_EQ("We <3 dunst", text); + strcpy(text, "We <3 dunst"); + string_strip_delimited(text, '<', '>'); + ASSERT_STR_EQ("We <3 dunst", text); - strcpy(text, "dunst > the rest"); - string_strip_delimited(text, '<', '>'); - ASSERT_STR_EQ("dunst > the rest", text); + strcpy(text, "dunst > the rest"); + string_strip_delimited(text, '<', '>'); + ASSERT_STR_EQ("dunst > the rest", text); - g_free(text); - PASS(); + g_free(text); + PASS(); } TEST test_string_to_path(void) { - char *ptr, *exp; - char *home = getenv("HOME"); - - exp = "/usr/local/bin/script"; - ASSERT_STR_EQ(exp, (ptr = string_to_path(g_strdup(exp)))); - free(ptr); - - // This might fail, when a user named path exists on the host running the tests. - exp = "~path/with/wrong/tilde"; - ASSERT_STR_EQ(exp, (ptr = string_to_path(g_strdup(exp)))); - free(ptr); - - ASSERT_STR_EQ((exp = g_strconcat(home, "/.path/with/tilde", NULL)), - (ptr = string_to_path(g_strdup("~/.path/with/tilde")))); - free(exp); - free(ptr); - - ASSERT_STR_EQ((exp = g_strconcat(home, "/.path/with/tilde and some space", NULL)), - (ptr = string_to_path(g_strdup("~/.path/with/tilde and some space")))); - free(exp); - free(ptr); - - ASSERT_STR_EQ((exp = g_strconcat(home, "/.path/with/HOME environment variable", NULL)), - (ptr = string_to_path(g_strdup("$HOME/.path/with/HOME environment variable")))); - free(exp); - free(ptr); + char *ptr, *exp; + char *home = getenv("HOME"); + + exp = "/usr/local/bin/script"; + ASSERT_STR_EQ(exp, (ptr = string_to_path(g_strdup(exp)))); + free(ptr); + + // This might fail, when a user named path exists on the host running the + // tests. + exp = "~path/with/wrong/tilde"; + ASSERT_STR_EQ(exp, (ptr = string_to_path(g_strdup(exp)))); + free(ptr); + + ASSERT_STR_EQ((exp = g_strconcat(home, "/.path/with/tilde", NULL)), + (ptr = string_to_path(g_strdup("~/.path/with/tilde")))); + free(exp); + free(ptr); + + ASSERT_STR_EQ( + (exp = g_strconcat(home, "/.path/with/tilde and some space", NULL)), + (ptr = string_to_path(g_strdup("~/.path/with/tilde and some space")))); + free(exp); + free(ptr); + + ASSERT_STR_EQ((exp = g_strconcat( + home, "/.path/with/HOME environment variable", NULL)), + (ptr = string_to_path(g_strdup( + "$HOME/.path/with/HOME environment variable")))); + free(exp); + free(ptr); // Just glibc properly returns an error when using `WRDE_UNDEF` and an // undefined variable is found. musl accepts this flag and ignores it. #ifdef __GLIBC__ - exp = "/some/$UNDEFINED/variable"; - ASSERT_STR_EQ(exp, (ptr = string_to_path(g_strdup(exp)))); - free(ptr); + exp = "/some/$UNDEFINED/variable"; + ASSERT_STR_EQ(exp, (ptr = string_to_path(g_strdup(exp)))); + free(ptr); #endif - PASS(); + PASS(); } TEST test_string_to_time(void) { - char *input[] = { "5000 ms", "5000ms", "100", "10s", "2m", "11h", "9d", " 5 ms ", NULL }; - gint64 exp[] = { 5000, 5000, 100000, 10000, 120000, 39600000, 777600000, 5, 0}; - - int i = 0; - while (input[i]) { - ASSERT_EQ_FMT(string_to_time(input[i]), exp[i]*1000, "%ld"); - i++; - } - - PASS(); + char *input[] = {"5000 ms", + "5000ms", + "100", + "10s", + "2m", + "11h", + "9d", + " 5 ms ", + NULL}; + gint64 exp[] = { + 5000, 5000, 100000, 10000, 120000, 39600000, 777600000, 5, 0}; + + int i = 0; + while (input[i]) { + ASSERT_EQ_FMT(string_to_time(input[i]), exp[i] * 1000, "%ld"); + i++; + } + + PASS(); } SUITE(suite_utils) { - RUN_TEST(test_string_replace_char); - RUN_TEST(test_string_replace_all); - RUN_TEST(test_string_append); - RUN_TEST(test_string_strip_quotes); - RUN_TEST(test_string_strip_delimited); - RUN_TEST(test_string_to_path); - RUN_TEST(test_string_to_time); + RUN_TEST(test_string_replace_char); + RUN_TEST(test_string_replace_all); + RUN_TEST(test_string_append); + RUN_TEST(test_string_strip_quotes); + RUN_TEST(test_string_strip_delimited); + RUN_TEST(test_string_to_path); + RUN_TEST(test_string_to_time); } /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */