From 5d71ccc174aafc22053ae0ca98a58ca216737499 Mon Sep 17 00:00:00 2001 From: Ryan Farley Date: Thu, 29 Apr 2021 04:12:55 -0500 Subject: [PATCH] enhanced bell configuration Add a separate section for bell configuration, with a bell-specific command option and a setting to allow that command to run without regard to keyboard focus (for those of us who enjoy being beeped at at all times, for example). The actions are also no longer mutually exclusive; this is primarily anticipating urgency support which cannot be replicated outside the process (in server mode anyway) and would thus be complementary to any notification or arbitrary command. --- config.c | 52 ++++++++++++++++++++++++++-------------- config.h | 13 +++++----- doc/foot.ini.5.scd | 59 ++++++++++++++++++++++++++-------------------- foot.ini | 6 +++++ terminal.c | 29 +++++++++++++---------- 5 files changed, 96 insertions(+), 63 deletions(-) diff --git a/config.c b/config.c index 59534ec9..bc3dc9c0 100644 --- a/config.c +++ b/config.c @@ -593,23 +593,6 @@ parse_section_main(const char *key, const char *value, struct config *conf, } } - else if (strcmp(key, "bell") == 0) { - if (strcmp(value, "set-urgency") == 0) - conf->bell_action = BELL_ACTION_URGENT; - else if (strcmp(value, "notify") == 0) - conf->bell_action = BELL_ACTION_NOTIFY; - else if (strcmp(value, "none") == 0) - conf->bell_action = BELL_ACTION_NONE; - else { - LOG_AND_NOTIFY_ERR( - "%s:%d: [default]: bell: " - "expected either 'set-urgency', 'notify' or 'none'", - path, lineno); - conf->bell_action = BELL_ACTION_NONE; - return false; - } - } - else if (strcmp(key, "initial-window-mode") == 0) { if (strcmp(value, "windowed") == 0) conf->startup_mode = STARTUP_WINDOWED; @@ -788,6 +771,28 @@ parse_section_main(const char *key, const char *value, struct config *conf, return true; } +static bool +parse_section_bell(const char *key, const char *value, struct config *conf, + const char *path, unsigned lineno) +{ + if (strcmp(key, "urgent") == 0) + conf->bell.urgent = str_to_bool(value); + else if (strcmp(key, "notify") == 0) + conf->bell.notify = str_to_bool(value); + else if (strcmp(key, "command") == 0) { + if (!str_to_spawn_template(conf, value, &conf->bell.command, path, lineno, "bell", key)) + return false; + } + else if (strcmp(key, "command-focused") == 0) + conf->bell.command_focused = str_to_bool(value); + else { + LOG_AND_NOTIFY_ERR("%s:%u: [bell]: %s: invalid key", path, lineno, key); + return false; + } + + return true; +} + static bool parse_section_scrollback(const char *key, const char *value, struct config *conf, const char *path, unsigned lineno) @@ -1864,6 +1869,7 @@ parse_config_file(FILE *f, struct config *conf, const char *path, bool errors_ar { enum section { SECTION_MAIN, + SECTION_BELL, SECTION_SCROLLBACK, SECTION_COLORS, SECTION_CURSOR, @@ -1887,6 +1893,7 @@ parse_config_file(FILE *f, struct config *conf, const char *path, bool errors_ar const char *name; } section_info[] = { [SECTION_MAIN] = {&parse_section_main, "main"}, + [SECTION_BELL] = {&parse_section_bell, "bell"}, [SECTION_SCROLLBACK] = {&parse_section_scrollback, "scrollback"}, [SECTION_COLORS] = {&parse_section_colors, "colors"}, [SECTION_CURSOR] = {&parse_section_cursor, "cursor"}, @@ -2212,7 +2219,6 @@ config_load(struct config *conf, const char *conf_path, .enabled = false, .palette_based = false, }, - .bell_action = BELL_ACTION_NONE, .startup_mode = STARTUP_WINDOWED, .fonts = {tll_init(), tll_init(), tll_init(), tll_init()}, .line_height = { .pt = 0, .px = -1, }, @@ -2221,6 +2227,15 @@ config_load(struct config *conf, const char *conf_path, .vertical_letter_offset = {.pt = 0, .px = 0, }, .box_drawings_uses_font_glyphs = false, .dpi_aware = DPI_AWARE_AUTO, /* DPI-aware when scaling-factor == 1 */ + .bell = { + .urgent = false, + .notify = false, + .command = { + .raw_cmd = NULL, + .argv = NULL, + }, + .command_focused = false, + }, .scrollback = { .lines = 1000, .indicator = { @@ -2446,6 +2461,7 @@ config_free(struct config conf) free(conf.app_id); free(conf.word_delimiters); free(conf.jump_label_letters); + free_spawn_template(&conf.bell.command); free(conf.scrollback.indicator.text); free_spawn_template(&conf.notify); free_spawn_template(&conf.url_launch); diff --git a/config.h b/config.h index 2a5ca79d..8e67d398 100644 --- a/config.h +++ b/config.h @@ -84,12 +84,6 @@ struct config { bool palette_based; } bold_in_bright; - enum { - BELL_ACTION_NONE, - BELL_ACTION_URGENT, - BELL_ACTION_NOTIFY, - } bell_action; - enum { STARTUP_WINDOWED, STARTUP_MAXIMIZED, STARTUP_FULLSCREEN } startup_mode; enum {DPI_AWARE_AUTO, DPI_AWARE_YES, DPI_AWARE_NO} dpi_aware; @@ -105,6 +99,13 @@ struct config { bool box_drawings_uses_font_glyphs; + struct { + bool urgent; + bool notify; + struct config_spawn_template command; + bool command_focused; + } bell; + struct { int lines; diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index 9b4e3f7b..59da6f2e 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -211,32 +211,6 @@ in this order: Default: _no_. -*bell* - Action to perform when receiving a *BEL* character. Can be set to - either *set-urgency*, *notify* or *none*. - - When set to *set-urgency*, the margins will be painted in red - whenever *BEL* is received while the window does *not* have - keyboard focus. Note that Wayland currently does not have an - _urgency_ hint like X11. The value *set-urgency* was chosen for - forward-compatibility in the hopes that a corresponding Wayland - protocol is added in the future (in which case foot will use that - instead of painting its margins red). - - Applications can enable/disable this feature programmatically with - the *CSI ? 1042 h* and *CSI ? 1042 l* escape sequences. - - _Note_: expect this feature to be *replaced* with proper - compositor urgency support once/if that gets implemented. - - When set to *notify*, foot will emit a desktop notification using - the command specified in the *notify* option, but only if the foot - window does *not* have keyboard focus. - - When set to *none*, no special action is taken when receiving *BEL*. - - Default: _none_. - *word-delimiters* String of characters that act as word delimiters when selecting text. Note that whitespace characters are _always_ word @@ -288,6 +262,39 @@ in this order: Default: _url-mode_ +# SECTION: bell + +*urgent* + When set to _true_, the margins will be painted in red + whenever *BEL* is received while the window does *not* have + keyboard focus. Note that Wayland currently does not have an + _urgency_ hint like X11. The name *urgent* was chosen for + forward-compatibility in the hopes that a corresponding Wayland + protocol is added in the future (in which case foot will use that + instead of painting its margins red). + + Applications can enable/disable this feature programmatically with + the *CSI ? 1042 h* and *CSI ? 1042 l* escape sequences. + + _Note_: expect this feature to be *replaced* with proper + compositor urgency support once/if that gets implemented. + Default: _false_ + +*notify* + When set to _true_, foot will emit a desktop notification using + the command specified in the *notify* option whenever *BEL* is + received and the window does *not* have keyboard focus. Default: + _false_ + +*command* + When set, foot will execute this command when *BEL* is received. + Default: none + +*command-focused* + Whether to run the command on *BEL* even while focused. Default: + _false_ + + # SECTION: scrollback *lines* diff --git a/foot.ini b/foot.ini index 81bfb489..5b348cf1 100644 --- a/foot.ini +++ b/foot.ini @@ -32,6 +32,12 @@ # workers= # osc8-underline=url-mode +[bell] +# urgent=false +# notify=false +# command= +# command_focused=false + [scrollback] # lines=1000 # multiplier=3.0 diff --git a/terminal.c b/terminal.c index cd1ecbd9..f77a6d79 100644 --- a/terminal.c +++ b/terminal.c @@ -2627,23 +2627,26 @@ term_flash(struct terminal *term, unsigned duration_ms) void term_bell(struct terminal *term) { - if (term->kbd_focus || !term->bell_action_enabled) + if (!term->bell_action_enabled) return; - switch (term->conf->bell_action) { - case BELL_ACTION_NONE: - break; + if (!term->kbd_focus) { + if (term->conf->bell.urgent) { + /* There's no 'urgency' hint in Wayland - we just paint the + * margins red */ + term->render.urgency = true; + term_damage_margins(term); + } + if (term->conf->bell.notify) + notify_notify(term, "Bell", "Bell in terminal"); + } - case BELL_ACTION_URGENT: - /* There's no 'urgency' hint in Wayland - we just paint the - * margins red */ - term->render.urgency = true; - term_damage_margins(term); - break; + if (term->conf->bell.command.argv && (!term->kbd_focus || term->conf->bell.command_focused)) { + int devnull = open("/dev/null", O_RDONLY); + spawn(term->reaper, NULL, term->conf->bell.command.argv, devnull, -1, -1); - case BELL_ACTION_NOTIFY: - notify_notify(term, "Bell", "Bell in terminal"); - break; + if (devnull >= 0) + close(devnull); } }