diff --git a/HACKING.md b/HACKING.md new file mode 100644 index 0000000..ad488b6 --- /dev/null +++ b/HACKING.md @@ -0,0 +1,30 @@ +# Important notes on the code + +## Log messages + +### Messages + +- Keep your message in common format: `: ` +- If you have to write text, single quote values in your sentence. + +### Levels + +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. +- `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 +- `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. +- `LOG_M` (MESSAGE): + - 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 +- `LOG_D` (DEBUG): + - Only important during development or tracing some bugs (as the developer). diff --git a/docs/dunst.pod b/docs/dunst.pod index 0973fa8..d2c7a0b 100644 --- a/docs/dunst.pod +++ b/docs/dunst.pod @@ -444,6 +444,12 @@ WM_CLASS). There should be no need to modify this setting for regular use. Display a notification on startup. This is usually used for debugging and there shouldn't be any need to use this option. +=item B (values: 'crit', 'warn', 'mesg', 'info', 'debug' default 'mesg') + +Do not display log messages, which have lower precedence than specified +verbosity. This won't affect printing notifications on the terminal. Use +the '-print' option for this. + =item B (values: [true/false], default: false) Use the Xinerama extension instead of RandR for multi-monitor support. This diff --git a/dunstrc b/dunstrc index dbe7eab..0f4c4aa 100644 --- a/dunstrc +++ b/dunstrc @@ -198,6 +198,15 @@ # automatically after a crash. startup_notification = false + # Manage dunst's desire for talking + # Can be one of the following values: + # crit: Critical features. Dunst aborts + # warn: Only non-fatal warnings + # mesg: Important Messages + # info: all unimportant stuff + # debug: all less than unimportant stuff + verbosity = mesg + ### Legacy # Use the Xinerama extension instead of RandR for multi-monitor support. diff --git a/src/dbus.c b/src/dbus.c index 049ec19..e532813 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -7,6 +7,7 @@ #include #include "dunst.h" +#include "log.h" #include "notification.h" #include "queues.h" #include "settings.h" @@ -100,8 +101,9 @@ void handle_method_call(GDBusConnection *connection, } else if (g_strcmp0(method_name, "GetServerInformation") == 0) { on_get_server_information(connection, sender, parameters, invocation); } else { - fprintf(stderr, "WARNING: sender: %s; unknown method_name: %s\n", sender, - method_name); + LOG_M("Unknown method name: '%s' (sender: '%s').", + method_name, + sender); } } @@ -342,14 +344,13 @@ static void on_get_server_information(GDBusConnection *connection, void signal_notification_closed(notification *n, enum reason reason) { if (reason < REASON_MIN || REASON_MAX < reason) { - fprintf(stderr, "ERROR: Closing notification with reason '%d' not supported. " - "Closing it with reason '%d'.\n", reason, REASON_UNDEF); + LOG_W("Closing notification with reason '%d' not supported. " + "Closing it with reason '%d'.", reason, REASON_UNDEF); reason = REASON_UNDEF; } if (!dbus_conn) { - fprintf(stderr, "ERROR: Tried to close notification but dbus connection not set!\n"); - return; + LOG_E("Unable to close notification: No DBus connection."); } GVariant *body = g_variant_new("(uu)", n->id, reason); @@ -364,7 +365,7 @@ void signal_notification_closed(notification *n, enum reason reason) &err); if (err) { - fprintf(stderr, "Unable to close notification: %s\n", err->message); + LOG_W("Unable to close notification: %s", err->message); g_error_free(err); } @@ -384,7 +385,7 @@ void signal_action_invoked(notification *n, const char *identifier) &err); if (err) { - fprintf(stderr, "Unable to invoke action: %s\n", err->message); + LOG_W("Unable to invoke action: %s", err->message); g_error_free(err); } } @@ -410,8 +411,7 @@ static void on_bus_acquired(GDBusConnection *connection, &err); if (registration_id == 0) { - fprintf(stderr, "Unable to register dbus connection: %s\n", err->message); - exit(1); + DIE("Unable to register dbus connection: %s", err->message); } } @@ -536,14 +536,14 @@ static void on_name_lost(GDBusConnection *connection, if (connection) { char *name = NULL; int pid = dbus_get_fdn_daemon_info(connection, &name, NULL); - if (pid > 0) - fprintf(stderr, "Cannot acquire '"FDN_NAME"': " - "Name is acquired by '%s' with PID '%d'.\n", name, pid); - else - fprintf(stderr, "Cannot acquire '"FDN_NAME"'.\n"); - + if (pid > 0) { + DIE("Cannot acquire '"FDN_NAME"': " + "Name is acquired by '%s' with PID '%d'.", name, pid); + } else { + DIE("Cannot acquire '"FDN_NAME"'."); + } } else { - fprintf(stderr, "Cannot connect to DBus.\n"); + DIE("Cannot connect to DBus."); } exit(1); } @@ -568,10 +568,10 @@ static RawImage *get_raw_image_from_data_hint(GVariant *icon_data) * ((image->n_channels * image->bits_per_sample + 7) / 8); if (expected_len != g_variant_get_size (data_variant)) { - fprintf(stderr, "Expected image data to be of length %" G_GSIZE_FORMAT - " but got a " "length of %" G_GSIZE_FORMAT, - expected_len, - g_variant_get_size (data_variant)); + LOG_W("Expected image data to be of length %" G_GSIZE_FORMAT + " but got a length of %" G_GSIZE_FORMAT, + expected_len, + g_variant_get_size(data_variant)); g_free(image); g_variant_unref(data_variant); return NULL; diff --git a/src/dunst.c b/src/dunst.c index 38c8957..53fb2fc 100644 --- a/src/dunst.c +++ b/src/dunst.c @@ -13,6 +13,7 @@ #include #include "dbus.h" +#include "log.h" #include "menu.h" #include "notification.h" #include "option_parser.h" @@ -25,10 +26,6 @@ #define VERSION "version info needed" #endif -#define MSG 1 -#define INFO 2 -#define DEBUG 3 - typedef struct _x11_source { GSource source; Display *dpy; @@ -128,11 +125,17 @@ int dunst_main(int argc, char *argv[]) cmdline_load(argc, argv); + dunst_log_init(false); + if (cmdline_get_bool("-v/-version", false, "Print version") || cmdline_get_bool("--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 *cmdline_config_path; cmdline_config_path = cmdline_get_string("-conf/-config", NULL, diff --git a/src/dunst.h b/src/dunst.h index cdb6874..ac5cda6 100644 --- a/src/dunst.h +++ b/src/dunst.h @@ -9,8 +9,6 @@ #include "notification.h" -#define PERR(msg, errnum) printf("(%d) %s : %s\n", __LINE__, (msg), (strerror(errnum))) - #define ColLast 3 #define ColFrame 2 #define ColFG 1 diff --git a/src/log.c b/src/log.c new file mode 100644 index 0000000..ad777f6 --- /dev/null +++ b/src/log.c @@ -0,0 +1,95 @@ +/* copyright 2012 - 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ + +#include "log.h" + +#include + +static GLogLevelFlags log_level = G_LOG_LEVEL_WARNING; + +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"; + } +} + +void log_set_level_from_string(const char *level) +{ + if (!level) + return; + + if (g_ascii_strcasecmp(level, "critical") == 0) + log_level = G_LOG_LEVEL_CRITICAL; + else if (g_ascii_strcasecmp(level, "crit") == 0) + log_level = G_LOG_LEVEL_CRITICAL; + else if (g_ascii_strcasecmp(level, "warning") == 0) + log_level = G_LOG_LEVEL_WARNING; + else if (g_ascii_strcasecmp(level, "warn") == 0) + log_level = G_LOG_LEVEL_WARNING; + else if (g_ascii_strcasecmp(level, "message") == 0) + log_level = G_LOG_LEVEL_MESSAGE; + else if (g_ascii_strcasecmp(level, "mesg") == 0) + log_level = G_LOG_LEVEL_MESSAGE; + else if (g_ascii_strcasecmp(level, "info") == 0) + log_level = G_LOG_LEVEL_INFO; + else if (g_ascii_strcasecmp(level, "debug") == 0) + log_level = G_LOG_LEVEL_DEBUG; + else if (g_ascii_strcasecmp(level, "deb") == 0) + log_level = G_LOG_LEVEL_DEBUG; + else + LOG_W("Unknown log level: '%s'", level); +} + +void log_set_level(GLogLevelFlags level) +{ + log_level = level; +} + +/* + * Log handling function for GLib's logging wrapper + * + * If the gpointer is valid, do not do anything + */ +static void dunst_log_handler( + const gchar *log_domain, + GLogLevelFlags message_level, + const gchar *message, + gpointer testing) +{ + if (testing) + return; + +/* if you want to have a debug build, you want to log anything, + * unconditionally, without specifying debug log level again */ +#ifndef DEBUG_BUILD + if (log_level < message_level) + return; +#endif + const char *log_level_str = + log_level_to_string(message_level & G_LOG_LEVEL_MASK); + + /* Use stderr for warnings and higher */ + if (message_level <= G_LOG_LEVEL_WARNING) + g_printerr("%s: %s\n", log_level_str, message); + else + g_print("%s: %s\n", log_level_str, message); +} + +/* + * Initialise log handling. Can be called any time. + * + * If bool is %TRUE, it suppresses all logging output. + * Primarily used for testing + */ +void dunst_log_init(bool testing) +{ + g_log_set_default_handler(dunst_log_handler, (void*)testing); +} + +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..3ca6e9d --- /dev/null +++ b/src/log.h @@ -0,0 +1,25 @@ +/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ + +#include +#include +#include + +#ifndef DUNST_LOG_H +#define DUNST_LOG_H + +#define LOG_E g_error +#define LOG_C g_critical +#define LOG_W g_warning +#define LOG_M g_message +#define LOG_I g_info +#define LOG_D g_debug + +#define DIE(...) do { LOG_C(__VA_ARGS__); exit(EXIT_FAILURE); } while (0) + +void log_set_level(GLogLevelFlags level); +void log_set_level_from_string(const char* level); + +void dunst_log_init(bool testing); + +#endif +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/markup.c b/src/markup.c index ad4484f..4ed6585 100644 --- a/src/markup.c +++ b/src/markup.c @@ -7,6 +7,7 @@ #include #include +#include "log.h" #include "settings.h" #include "utils.h" @@ -68,17 +69,15 @@ void markup_strip_a(char **str, char **urls) // the tag is broken, ignore it if (!tag1_end) { - fprintf(stderr, - "WARNING: Given link is broken: '%s'\n", - tag1); + 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(""); - fprintf(stderr, - "WARNING: Given link is broken: '%.*s.'\n", - repl_len, tag1); + LOG_W("Given link is broken: '%.*s.'", + repl_len, tag1); string_replace_at(*str, tag1-*str, repl_len, ""); break; } @@ -147,7 +146,7 @@ void markup_strip_img(char **str, char **urls) // the tag is broken, ignore it if (!end) { - fprintf(stderr, "WARNING: Given image is broken: '%s'\n", start); + LOG_W("Given image is broken: '%s'", start); string_replace_at(*str, start-*str, strlen(start), ""); break; } @@ -188,9 +187,8 @@ void markup_strip_img(char **str, char **urls) text_src = g_strndup(src_s, src_e-src_s); } else { - fprintf(stderr, - "WARNING: Given image argument is broken: '%.*s'\n", - (int)(end-start), start); + LOG_W("Given image argument is broken: '%.*s'", + (int)(end-start), start); } // replacement text for alt diff --git a/src/menu.c b/src/menu.c index 4e2389d..2689839 100644 --- a/src/menu.c +++ b/src/menu.c @@ -14,6 +14,7 @@ #include "dbus.h" #include "dunst.h" +#include "log.h" #include "notification.h" #include "queues.h" #include "settings.h" @@ -33,7 +34,7 @@ static int regex_init(void) "(\\([-[:alnum:]_\\@;/?:&=%$.+!*\x27,~#]*\\)|[-[:alnum:]_\\@;/?:&=%$+*~])+"; int ret = regcomp(&cregex, regex, REG_EXTENDED | REG_ICASE); if (ret != 0) { - fputs("failed to compile regex", stderr); + LOG_W("Failed to compile regex."); return 0; } else { is_initialized = true; @@ -139,7 +140,7 @@ void invoke_action(const char *action) char *appname_begin = strchr(action, '['); if (!appname_begin) { - printf("invalid action: %s\n", action); + LOG_W("Invalid action: '%s'", action); return; } appname_begin++; @@ -193,7 +194,7 @@ void dispatch_menu_result(const char *input) void context_menu(void) { if (settings.dmenu_cmd == NULL) { - fprintf(stderr, "dmenu command not set properly. Cowardly refusing to open the context menu.\n"); + LOG_C("Unable to open dmenu: No dmenu command set."); return; } char *dmenu_input = NULL; @@ -218,12 +219,12 @@ void context_menu(void) int child_io[2]; int parent_io[2]; if (pipe(child_io) != 0) { - PERR("pipe()", errno); + LOG_W("pipe(): error in child: %s", strerror(errno)); g_free(dmenu_input); return; } if (pipe(parent_io) != 0) { - PERR("pipe()", errno); + LOG_W("pipe(): error in parent: %s", strerror(errno)); g_free(dmenu_input); return; } @@ -234,12 +235,12 @@ void context_menu(void) close(parent_io[0]); close(0); if (dup(child_io[0]) == -1) { - PERR("dup()", errno); + LOG_W("dup(): error in child: %s", strerror(errno)); exit(EXIT_FAILURE); } close(1); if (dup(parent_io[1]) == -1) { - PERR("dup()", errno); + LOG_W("dup(): error in parent: %s", strerror(errno)); exit(EXIT_FAILURE); } execvp(settings.dmenu_cmd[0], settings.dmenu_cmd); @@ -252,7 +253,7 @@ void context_menu(void) close(parent_io[1]); size_t wlen = strlen(dmenu_input); if (write(child_io[1], dmenu_input, wlen) != wlen) { - PERR("write()", errno); + LOG_W("write(): error: %s", strerror(errno)); } close(child_io[1]); diff --git a/src/notification.c b/src/notification.c index 13dba18..f689193 100644 --- a/src/notification.c +++ b/src/notification.c @@ -15,6 +15,7 @@ #include "dbus.h" #include "dunst.h" +#include "log.h" #include "markup.h" #include "menu.h" #include "queues.h" @@ -33,6 +34,7 @@ static void notification_dmenu_string(notification *n); */ void notification_print(notification *n) { + //TODO: use logging info for this printf("{\n"); printf("\tappname: '%s'\n", n->appname); printf("\tsummary: '%s'\n", n->summary); @@ -106,7 +108,7 @@ void notification_run_script(notification *n) urgency, (char *)NULL); if (ret != 0) { - PERR("Unable to run script", errno); + LOG_W("Unable to run script: %s", strerror(errno)); exit(EXIT_FAILURE); } } @@ -416,12 +418,11 @@ static void notification_format_message(notification *n) MARKUP_NO); break; case '\0': - fprintf(stderr, "WARNING: format_string has trailing %% character." - "To escape it use %%%%."); + LOG_W("format_string has trailing %% character. " + "To escape it use %%%%."); break; default: - fprintf(stderr, "WARNING: format_string %%%c" - " is unknown\n", substr[1]); + LOG_W("format_string %%%c is unknown.", substr[1]); // shift substr pointer forward, // as we can't interpret the format string substr++; diff --git a/src/option_parser.c b/src/option_parser.c index 7641ccb..6573d73 100644 --- a/src/option_parser.c +++ b/src/option_parser.c @@ -8,6 +8,8 @@ #include #include +#include "dunst.h" +#include "log.h" #include "utils.h" typedef struct _entry_t { @@ -42,7 +44,7 @@ section_t *new_section(const char *name) { for (int i = 0; i < section_count; i++) { if (!strcmp(name, sections[i].name)) { - die("Duplicated section in dunstrc detected.\n", -1); + DIE("Duplicated section in dunstrc detected."); } } @@ -238,10 +240,7 @@ int load_ini_file(FILE *fp) if (*start == '[') { char *end = strchr(start + 1, ']'); if (!end) { - fprintf(stderr, - "Warning: invalid config file at line %d\n", - line_num); - fprintf(stderr, "Missing ']'\n"); + LOG_W("Invalid config file at line %d: Missing ']'.", line_num); continue; } @@ -255,10 +254,7 @@ int load_ini_file(FILE *fp) char *equal = strchr(start + 1, '='); if (!equal) { - fprintf(stderr, - "Warning: invalid config file at line %d\n", - line_num); - fprintf(stderr, "Missing '='\n"); + LOG_W("Invalid config file at line %d: Missing '='.", line_num); continue; } @@ -270,10 +266,7 @@ int load_ini_file(FILE *fp) if (quote) { char *closing_quote = strchr(quote + 1, '"'); if (!closing_quote) { - fprintf(stderr, - "Warning: invalid config file at line %d\n", - line_num); - fprintf(stderr, "Missing '\"'\n"); + LOG_W("Invalid config file at line %d: Missing '\"'.", line_num); continue; } } else { @@ -284,10 +277,7 @@ int load_ini_file(FILE *fp) value = g_strstrip(value); if (!current_section) { - fprintf(stderr, - "Warning: invalid config file at line %d\n", - line_num); - fprintf(stderr, "Key value pair without a section\n"); + LOG_W("Invalid config file at line %d: Key value pair without a section.", line_num); continue; } @@ -348,8 +338,7 @@ static const char *cmdline_get_value(const char *key) if (idx + 1 >= cmdline_argc) { /* the argument is missing */ - fprintf(stderr, "Warning: %s, missing argument. Ignoring\n", - key); + LOG_W("%s: Missing argument. Ignoring.", key); return NULL; } return cmdline_argv[idx + 1]; diff --git a/src/queues.c b/src/queues.c index 67953b5..94c0c7f 100644 --- a/src/queues.c +++ b/src/queues.c @@ -7,6 +7,7 @@ #include #include +#include "log.h" #include "notification.h" #include "settings.h" @@ -59,7 +60,7 @@ int queues_notification_insert(notification *n) if (settings.always_run_script) { notification_run_script(n); } - printf("skipping notification: %s %s\n", n->body, n->summary); + LOG_M("Skipping notification: '%s' '%s'", n->body, n->summary); return 0; } /* Do not insert the message if it's a command */ diff --git a/src/settings.c b/src/settings.c index 90fc321..c9264f5 100644 --- a/src/settings.c +++ b/src/settings.c @@ -13,6 +13,7 @@ #include "rules.h" // put before config.h to fix missing include #include "config.h" #include "dunst.h" +#include "log.h" #include "notification.h" #include "option_parser.h" #include "utils.h" @@ -28,7 +29,7 @@ static void parse_follow_mode(const char *mode) else if (strcmp(mode, "none") == 0) settings.f_mode = FOLLOW_NONE; else { - fprintf(stderr, "Warning: unknown follow mode: \"%s\"\n", mode); + LOG_W("Unknown follow mode: '%s'", mode); settings.f_mode = FOLLOW_NONE; } } @@ -42,7 +43,7 @@ static enum markup_mode parse_markup_mode(const char *mode) } else if (strcmp(mode, "full") == 0 || strcmp(mode, "yes") == 0) { return MARKUP_FULL; } else { - fprintf(stderr, "Warning: unknown markup mode: \"%s\"\n", mode); + LOG_W("Unknown markup mode: '%s'", mode); return MARKUP_NO; } } @@ -60,9 +61,7 @@ static enum urgency ini_get_urgency(const char *section, const char *key, const else if (strcmp(urg, "critical") == 0) ret = URG_CRIT; else - fprintf(stderr, - "unknown urgency: %s, ignoring\n", - urg); + LOG_W("Unknown urgency: '%s'", urg); } g_free(urg); return ret; @@ -85,10 +84,7 @@ void load_settings(char *cmdline_config_path) } if(!config_file) { - char *msg = g_strdup_printf( - "Cannot find config file: '%s'\n", - cmdline_config_path); - die(msg, 1); + DIE("Cannot find config file: '%s'", cmdline_config_path); } } if (config_file == NULL) { @@ -99,17 +95,29 @@ void load_settings(char *cmdline_config_path) * (before v0.2). */ config_file = xdgConfigOpen("dunstrc", "r", &xdg); if (config_file == NULL) { - puts("no dunstrc found -> skipping\n"); + LOG_W("No dunstrc found."); xdgWipeHandle(&xdg); } } load_ini_file(config_file); #else - fprintf(stderr, "Warning: dunstrc parsing disabled. " - "Using STATIC_CONFIG is deprecated behavior.\n"); + LOG_M("dunstrc parsing disabled. " + "Using STATIC_CONFIG is deprecated behavior."); #endif + { + char *loglevel = option_get_string( + "global", + "verbosity", "-verbosity", NULL, + "The verbosity to log (one of 'crit', 'warn', 'mesg', 'info', 'debug')" + ); + + log_set_level_from_string(loglevel); + + g_free(loglevel); + } + settings.per_monitor_dpi = option_get_bool( "experimental", "per_monitor_dpi", NULL, false, @@ -138,7 +146,8 @@ void load_settings(char *cmdline_config_path) ); settings.markup = (allow_markup ? MARKUP_FULL : MARKUP_STRIP); - fprintf(stderr, "Warning: 'allow_markup' is deprecated, please use 'markup' instead.\n"); + LOG_M("'allow_markup' is deprecated, please " + "use 'markup' instead."); } char *c = option_get_string( @@ -198,7 +207,7 @@ void load_settings(char *cmdline_config_path) } else if (strcmp(c, "end") == 0) { settings.ellipsize = end; } else { - fprintf(stderr, "Warning: unknown ellipsize value: \"%s\"\n", c); + LOG_W("Unknown ellipsize value: '%s'", c); settings.ellipsize = defaults.ellipsize; } g_free(c); @@ -286,8 +295,7 @@ void load_settings(char *cmdline_config_path) else if (strcmp(c, "right") == 0) settings.align = right; else - fprintf(stderr, - "Warning: unknown alignment\n"); + LOG_W("Unknown alignment value: '%s'", c); g_free(c); } } @@ -389,8 +397,8 @@ void load_settings(char *cmdline_config_path) { GError *error = NULL; if (!g_shell_parse_argv(settings.dmenu, NULL, &settings.dmenu_cmd, &error)) { - fprintf(stderr, "Unable to parse dmenu command: %s\n", error->message); - fprintf(stderr, "dmenu functionality will be disabled.\n"); + LOG_W("Unable to parse dmenu command: '%s'." + "dmenu functionality will be disabled.", error->message); g_error_free(error); settings.dmenu_cmd = NULL; } @@ -418,8 +426,7 @@ void load_settings(char *cmdline_config_path) else if (strcmp(c, "off") == 0) settings.icon_position = icons_off; else - fprintf(stderr, - "Warning: unknown icon position: %s\n", c); + LOG_W("Unknown icon position: '%s'", c); g_free(c); } } @@ -438,7 +445,7 @@ void load_settings(char *cmdline_config_path) "icon_folders", "-icon_folders", defaults.icon_path, "folders to default icons (deprecated, please use 'icon_path' instead)" ); - fprintf(stderr, "Warning: 'icon_folders' is deprecated, please use 'icon_path' instead.\n"); + LOG_M("The option 'icon_folders' is deprecated, please use 'icon_path' instead."); } // Read value and generate usage string for icon_path. // If icon_path is set, override icon_folder. @@ -458,7 +465,9 @@ void load_settings(char *cmdline_config_path) "width", NULL, defaults.frame_width, "Width of frame around the window" ); - fprintf(stderr, "Warning: The frame section is deprecated, width has been renamed to frame_width and moved to the global section.\n"); + LOG_M("The frame section is deprecated, width has " + "been renamed to frame_width and moved to " + "the global section."); } settings.frame_width = option_get_int( @@ -474,7 +483,9 @@ void load_settings(char *cmdline_config_path) "color", NULL, defaults.frame_color, "Color of the frame around the window" ); - fprintf(stderr, "Warning: The frame section is deprecated, color has been renamed to frame_color and moved to the global section.\n"); + LOG_M("The frame section is deprecated, color " + "has been renamed to frame_color and moved " + "to the global section."); } settings.frame_color = option_get_string( diff --git a/src/test b/src/test new file mode 100755 index 0000000..66605e6 Binary files /dev/null and b/src/test differ diff --git a/src/utils.c b/src/utils.c index eff2f78..8d2f00e 100644 --- a/src/utils.c +++ b/src/utils.c @@ -8,6 +8,8 @@ #include #include +#include "log.h" + char *string_replace_char(char needle, char replacement, char *haystack) { char *current = haystack; @@ -134,13 +136,13 @@ gint64 string_to_time(const char *string) gint64 val = strtoll(string, &endptr, 10); if (errno != 0) { - fprintf(stderr, "ERROR: Time: '%s': %s.\n", string, strerror(errno)); + LOG_W("Time: '%s': %s.", string, strerror(errno)); return 0; } else if (string == endptr) { - fprintf(stderr, "ERROR: Time: No digits found.\n"); + LOG_W("Time: '%s': No digits found.", string); return 0; } else if (errno != 0 && val == 0) { - fprintf(stderr, "ERROR: Time: '%s' unknown error.\n", string); + LOG_W("Time: '%s': Unknown error.", string); return 0; } else if (errno == 0 && !*endptr) { return val * G_USEC_PER_SEC; @@ -164,10 +166,4 @@ gint64 string_to_time(const char *string) return 0; } -void die(char *text, int exit_value) -{ - fputs(text, stderr); - exit(exit_value); -} - /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/utils.h b/src/utils.h index 18333d9..874bb49 100644 --- a/src/utils.h +++ b/src/utils.h @@ -21,9 +21,6 @@ char *string_append(char *a, const char *b, const char *sep); /* strip content between two delimiter characters (inplace) */ void string_strip_delimited(char *str, char a, char b); -/* exit with an error message */ -void die(char *msg, int exit_value); - /* replace tilde and path-specific values with its equivalents */ char *string_to_path(char *string); diff --git a/src/x11/screen.c b/src/x11/screen.c index 07a22a6..51bc230 100644 --- a/src/x11/screen.c +++ b/src/x11/screen.c @@ -15,6 +15,7 @@ #include #include +#include "src/log.h" #include "src/settings.h" #include "x.h" @@ -90,7 +91,8 @@ void randr_init() { int randr_error_base = 0; if (!XRRQueryExtension(xctx.dpy, &randr_event_base, &randr_error_base)) { - fprintf(stderr, "Could not initialize the RandR extension, falling back to single monitor mode.\n"); + LOG_W("Could not initialize the RandR extension. " + "Falling back to single monitor mode."); return; } XRRQueryVersion(xctx.dpy, &randr_major_version, &randr_minor_version); @@ -101,9 +103,10 @@ void randr_update() { if (randr_major_version < 1 || (randr_major_version == 1 && randr_minor_version < 5)) { - fprintf(stderr, "Server RandR version too low (%i.%i). Falling back to single monitor mode\n", - randr_major_version, - randr_minor_version); + LOG_W("Server RandR version too low (%i.%i). " + "Falling back to single monitor mode.", + randr_major_version, + randr_minor_version); screen_update_fallback(); return; } @@ -112,7 +115,8 @@ void randr_update() XRRMonitorInfo *m = XRRGetMonitors(xctx.dpy, RootWindow(xctx.dpy, DefaultScreen(xctx.dpy)), true, &n); if (n < 1) { - fprintf(stderr, "Get monitors reported %i monitors, falling back to single monitor mode\n", n); + LOG_C("Get monitors reported %i monitors. " + "Falling back to single monitor mode.", n); screen_update_fallback(); return; } @@ -150,7 +154,8 @@ void xinerama_update() XineramaScreenInfo *info = XineramaQueryScreens(xctx.dpy, &n); if (!info) { - fprintf(stderr, "(Xinerama) Could not get screen info, falling back to single monitor mode\n"); + LOG_W("Could not get xinerama screen info. " + "Falling back to single monitor mode."); screen_update_fallback(); return; } @@ -326,8 +331,7 @@ static int FollowXErrorHandler(Display *display, XErrorEvent *e) dunst_follow_errored = true; char err_buf[BUFSIZ]; XGetErrorText(display, e->error_code, err_buf, BUFSIZ); - fputs(err_buf, stderr); - fputs("\n", stderr); + LOG_W("%s", err_buf); return 0; } diff --git a/src/x11/x.c b/src/x11/x.c index 0f38487..2df610b 100644 --- a/src/x11/x.c +++ b/src/x11/x.c @@ -26,6 +26,7 @@ #include "src/dbus.h" #include "src/dunst.h" +#include "src/log.h" #include "src/markup.h" #include "src/notification.h" #include "src/queues.h" @@ -83,7 +84,7 @@ static color_t x_string_to_color_t(const char *str) char *end; long int val = strtol(str+1, &end, 16); if (*end != '\0' && *(end+1) != '\0') { - printf("WARNING: Invalid color string: \"%s\"\n", str); + LOG_W("Invalid color string: '%s'", str); } return x_color_hex_to_double(val); @@ -132,9 +133,7 @@ static color_t x_get_separator_color(colored_layout *cl, colored_layout *cl_next case AUTO: return calculate_foreground_color(cl->bg); default: - printf("Unknown separator color type. Please file a Bugreport.\n"); - return cl->fg; - + LOG_E("Unknown separator color type."); } } @@ -378,8 +377,7 @@ static GdkPixbuf *get_pixbuf_from_path(char *icon_path) } while (*(end) != '\0'); } if (pixbuf == NULL) { - fprintf(stderr, - "Could not load icon: '%s'\n", icon_path); + LOG_W("Could not load icon: '%s'", icon_path); } if (uri_path != NULL) { g_free(uri_path); @@ -534,7 +532,7 @@ static colored_layout *r_create_layout_from_notification(cairo_t *c, notificatio cl->attr = NULL; pango_layout_set_text(cl->l, n->text_to_render, -1); if (n->first_render) { - printf("Error parsing markup: %s\n", err->message); + LOG_W("Unable to parse markup: %s", err->message); } g_error_free(err); } @@ -833,8 +831,6 @@ gboolean x_mainloop_fd_prepare(GSource *source, gint *timeout) { if (timeout) *timeout = -1; - else - g_print("BUG: x_mainloop_fd_prepare: timeout == NULL\n"); return false; } @@ -994,9 +990,9 @@ void x_setup(void) /* initialize xctx.dc, font, keyboard, colors */ if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) - fputs("no locale support\n", stderr); + LOG_W("No locale support"); if (!(xctx.dpy = XOpenDisplay(NULL))) { - die("cannot open display\n", EXIT_FAILURE); + DIE("Cannot open X11 display."); } x_shortcut_init(&settings.close_ks); @@ -1193,7 +1189,7 @@ void x_win_show(void) None, None); if (x_shortcut_tear_down_error_handler()) { - fprintf(stderr, "Unable to grab mouse button(s)\n"); + LOG_W("Unable to grab mouse button(s)."); } XMapRaised(xctx.dpy, xctx.win); @@ -1233,7 +1229,7 @@ KeySym x_shortcut_string_to_mask(const char *str) } else if (!strcmp(str, "shift")) { return ShiftMask; } else { - fprintf(stderr, "Warning: Unknown Modifier: %s\n", str); + LOG_W("Unknown Modifier: '%s'", str); return 0; } } @@ -1246,11 +1242,11 @@ static int GrabXErrorHandler(Display *display, XErrorEvent *e) dunst_grab_errored = true; char err_buf[BUFSIZ]; XGetErrorText(display, e->error_code, err_buf, BUFSIZ); - fputs(err_buf, stderr); - fputs("\n", stderr); if (e->error_code != BadAccess) { - exit(EXIT_FAILURE); + DIE("%s", err_buf); + } else { + LOG_W("%s", err_buf); } return 0; @@ -1308,7 +1304,7 @@ int x_shortcut_grab(keyboard_shortcut *ks) } if (x_shortcut_tear_down_error_handler()) { - fprintf(stderr, "Unable to grab key \"%s\"\n", ks->str); + LOG_W("Unable to grab key '%s'.", ks->str); ks->is_valid = false; return 1; } @@ -1371,8 +1367,7 @@ void x_shortcut_init(keyboard_shortcut *ks) } if (ks->sym == NoSymbol || ks->code == NoSymbol) { - fprintf(stderr, "Warning: Unknown keyboard shortcut: %s\n", - ks->str); + LOG_W("Unknown keyboard shortcut: '%s'", ks->str); ks->is_valid = false; } else { ks->is_valid = true; diff --git a/test/test.c b/test/test.c index 90959a6..935bda9 100644 --- a/test/test.c +++ b/test/test.c @@ -1,5 +1,9 @@ #include "greatest.h" +#include + +#include "src/log.h" + SUITE_EXTERN(suite_utils); SUITE_EXTERN(suite_option_parser); SUITE_EXTERN(suite_notification); @@ -8,6 +12,9 @@ SUITE_EXTERN(suite_markup); GREATEST_MAIN_DEFS(); int main(int argc, char *argv[]) { + // do not print out warning messages, when executing tests + dunst_log_init(true); + GREATEST_MAIN_BEGIN(); RUN_SUITE(suite_utils); RUN_SUITE(suite_option_parser);