From ee3b93488ec14ed938c8366b085ec3cad015cd76 Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Wed, 10 Jan 2024 00:10:11 -0800 Subject: [PATCH] Allow specifying monitor by name --- docs/dunst.5.pod | 4 ++-- src/option_parser.c | 13 +++++++++++++ src/option_parser.h | 1 + src/output.h | 1 + src/settings.h | 3 ++- src/settings_data.h | 6 +++--- src/wayland/wl.c | 32 ++++++++++++++++++++++++++------ src/x11/screen.c | 34 +++++++++++++++++++++++++++++----- test/setting.c | 3 +++ 9 files changed, 80 insertions(+), 17 deletions(-) diff --git a/docs/dunst.5.pod b/docs/dunst.5.pod index a738f829a..7d2d42448 100644 --- a/docs/dunst.5.pod +++ b/docs/dunst.5.pod @@ -28,8 +28,8 @@ All experimental settings are marked with I =item B (default: 0) -Specifies on which monitor the notifications should be displayed in, count -starts at 0. See the B setting. +Specifies on which monitor the notifications should be displayed in, either by +name or by number, starting from 0. See the B setting. =item B (values: [none/mouse/keyboard] default: none) diff --git a/src/option_parser.c b/src/option_parser.c index b1095118c..0d07b610a 100644 --- a/src/option_parser.c +++ b/src/option_parser.c @@ -205,6 +205,19 @@ int string_parse_bool(const void *data, const char *s, void *ret) 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; + } + + 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; diff --git a/src/option_parser.h b/src/option_parser.h index 38ff10367..e3183a37f 100644 --- a/src/option_parser.h +++ b/src/option_parser.h @@ -13,6 +13,7 @@ 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_bool(const void *data, const char *s, void *ret); +int string_parse_maybe_int(const void *data, const char *s, void *ret); void set_defaults(); void save_settings(struct ini *ini); diff --git a/src/output.h b/src/output.h index b89cb1dee..2044ff7b7 100644 --- a/src/output.h +++ b/src/output.h @@ -19,6 +19,7 @@ struct dimensions { }; struct screen_info { + char *name; int id; int x; int y; diff --git a/src/settings.h b/src/settings.h index 346e676d1..bca6fbd15 100644 --- a/src/settings.h +++ b/src/settings.h @@ -121,7 +121,8 @@ struct settings { int frame_width; char *frame_color; int startup_notification; - int monitor; + char *monitor; + int monitor_num; double scale; char *dmenu; char **dmenu_cmd; diff --git a/src/settings_data.h b/src/settings_data.h index 48bfb2dc5..6cd46a663 100644 --- a/src/settings_data.h +++ b/src/settings_data.h @@ -906,11 +906,11 @@ static const struct setting allowed_settings[] = { .name = "monitor", .section = "global", .description = "On which monitor should the notifications be displayed", - .type = TYPE_INT, + .type = TYPE_CUSTOM, .default_value = "0", .value = &settings.monitor, - .parser = NULL, - .parser_data = NULL, + .parser = string_parse_maybe_int, + .parser_data = &settings.monitor_num, }, { .name = "title", diff --git a/src/wayland/wl.c b/src/wayland/wl.c index da6ed6725..7a118fb11 100644 --- a/src/wayland/wl.c +++ b/src/wayland/wl.c @@ -144,11 +144,24 @@ static void output_handle_scale(void *data, struct wl_output *wl_output, wake_up(); } +#ifdef WL_OUTPUT_NAME_SINCE_VERSION +static void output_handle_name(void *data, struct wl_output *wl_output, + const char *name) { + struct dunst_output *output = data; + output->name = g_strdup(name); + LOG_D("Output global %" PRIu32 " name %s", output->global_name, name); +} +#endif + static const struct wl_output_listener output_listener = { .geometry = output_handle_geometry, .mode = output_handle_mode, .done = noop, .scale = output_handle_scale, +#ifdef WL_OUTPUT_NAME_SINCE_VERSION + .name = output_handle_name, + .description = noop, +#endif }; static void create_output(struct wl_registry *registry, uint32_t global_name, uint32_t version) { @@ -158,12 +171,16 @@ static void create_output(struct wl_registry *registry, uint32_t global_name, ui return; } + uint32_t max_version = 3; +#ifdef WL_OUTPUT_NAME_SINCE_VERSION + max_version = WL_OUTPUT_NAME_SINCE_VERSION; +#endif bool recreate_surface = false; static int number = 0; LOG_I("New output found - id %i", number); output->global_name = global_name; - output->wl_output = wl_registry_bind(registry, global_name, &wl_output_interface, 3); - + output->wl_output = wl_registry_bind(registry, global_name, &wl_output_interface, + CLAMP(version, 3, max_version)); output->scale = 1; output->fullscreen = false; @@ -190,8 +207,8 @@ static void destroy_output(struct dunst_output *output) { } wl_list_remove(&output->link); wl_output_destroy(output->wl_output); - free(output->name); - free(output); + g_free(output->name); + g_free(output); } static void touch_handle_motion(void *data, struct wl_touch *wl_touch, @@ -521,7 +538,8 @@ static void create_seat(struct wl_registry *registry, uint32_t global_name, uint // Warning, can return NULL static struct dunst_output *get_configured_output() { int n = 0; - int target_monitor = settings.monitor; + int target_monitor = settings.monitor_num; + const char *name = settings.monitor; struct dunst_output *first_output = NULL, *configured_output = NULL, *tmp_output = NULL; @@ -530,6 +548,8 @@ static struct dunst_output *get_configured_output() { first_output = tmp_output; if (n == target_monitor) configured_output = tmp_output; + if (g_strcmp0(name, tmp_output->name) == 0) + configured_output = tmp_output; n++; } @@ -540,7 +560,7 @@ static struct dunst_output *get_configured_output() { switch (settings.f_mode){ case FOLLOW_NONE: ; // this semicolon is neccesary if (!configured_output) { - LOG_W("Monitor %i doesn't exist, using focused monitor", settings.monitor); + LOG_W("Monitor %s doesn't exist, using focused monitor", settings.monitor); } return configured_output; case FOLLOW_MOUSE: diff --git a/src/x11/screen.c b/src/x11/screen.c index b069fbbf6..ba56db326 100644 --- a/src/x11/screen.c +++ b/src/x11/screen.c @@ -103,10 +103,21 @@ void init_screens(void) } } +void free_screen_ar(struct screen_info *scr, int len) +{ + if (!scr) + return; + + for (int i = 0; i < len; ++i) { + XFree(scr[i].name); + } + g_free(scr); +} + void alloc_screen_ar(int n) { assert(n > 0); - g_free(screens); + free_screen_ar(screens, screens_len); screens = g_malloc0(n * sizeof(struct screen_info)); screens_len = n; } @@ -150,6 +161,7 @@ void randr_update(void) alloc_screen_ar(n); for (int i = 0; i < n; i++) { + screens[i].name = XGetAtomName(xctx.dpy, m[i].name); screens[i].id = i; screens[i].x = m[i].x; screens[i].y = m[i].y; @@ -202,8 +214,8 @@ void screen_update_fallback(void) alloc_screen_ar(1); int screen; - if (settings.monitor >= 0) - screen = settings.monitor; + if (settings.monitor_num >= 0) + screen = settings.monitor_num; else screen = DefaultScreen(xctx.dpy); @@ -297,6 +309,16 @@ bool window_is_fullscreen(Window window) return fs; } +static int get_screen_by_name(const char *name, int defval) +{ + for (int i = 0; i < screens_len; ++i) { + if (g_strcmp0(screens[i].name, name) == 0) { + return i; + } + } + return defval; +} + /* * Select the screen on which the Window * should be displayed. @@ -307,8 +329,10 @@ const struct screen_info *get_active_screen(void) bool force_follow_mouse = false; if (settings.f_mode == FOLLOW_NONE) { - if (settings.monitor >= 0 && settings.monitor < screens_len) { - ret = settings.monitor; + if (settings.monitor_num >= 0 && settings.monitor_num < screens_len) { + ret = settings.monitor_num; + } else { + ret = get_screen_by_name(settings.monitor, 0); } goto sc_cleanup; } else { diff --git a/test/setting.c b/test/setting.c index 20100e7ef..9fd0f9878 100644 --- a/test/setting.c +++ b/test/setting.c @@ -80,6 +80,9 @@ TEST test_dunstrc_defaults(void) { ASSERT_EQm(message, a, b); } break; + } else if (allowed_settings[i].parser == string_parse_maybe_int) { + // not a number + break; } // else fall through case TYPE_TIME: case TYPE_INT:;