diff --git a/CHANGELOG.md b/CHANGELOG.md index be321556..3c01193a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,7 +58,14 @@ ## Unreleased + ### Added + +* Support for the new Wayland protocol `xdg-system-bell-v1` protocol + (added in wayland-protocols 1.38), via the new config option + `bell.system=no|yes` (defaults to `yes`). + + ### Changed * The `CSI 21 t` (report window title) and `OSC 176 ?` (report app-id) diff --git a/config.c b/config.c index 7f1ce055..68d49207 100644 --- a/config.c +++ b/config.c @@ -1139,6 +1139,8 @@ parse_section_bell(struct context *ctx) return value_to_bool(ctx, &conf->bell.urgent); else if (streq(key, "notify")) return value_to_bool(ctx, &conf->bell.notify); + else if (streq(key, "system")) + return value_to_bool(ctx, &conf->bell.system_bell); else if (streq(key, "visual")) return value_to_bool(ctx, &conf->bell.flash); else if (streq(key, "command")) @@ -3182,6 +3184,7 @@ config_load(struct config *conf, const char *conf_path, .urgent = false, .notify = false, .flash = false, + .system_bell = true, .command = { .argv = {.args = NULL}, }, diff --git a/config.h b/config.h index d7192970..7d9f88c3 100644 --- a/config.h +++ b/config.h @@ -186,6 +186,7 @@ struct config { bool urgent; bool notify; bool flash; + bool system_bell; struct config_spawn_template command; bool command_focused; } bell; diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index ba59050e..733168bf 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -445,10 +445,17 @@ Note: do not set *TERM* here; use the *term* option in the main # SECTION: bell +*system* + Boolean, when set to _yes_, ring the system bell. The bell is rung + independent of whether the foot window has keyboard focus or + not. Exact behavior is compositor dependent. + + Default: _yes_ + *urgent* - When set to _yes_, foot will signal urgency to the compositor - through the XDG activation protocol whenever *BEL* is received, - and the window does NOT have keyboard focus. + Boolean, when set to _yes_, foot will signal urgency to the + compositor through the XDG activation protocol whenever *BEL* is + received, and the window does NOT have keyboard focus. If the compositor does not implement this protocol, the margins will be painted in red instead. @@ -459,25 +466,25 @@ Note: do not set *TERM* here; use the *term* option in the main Default: _no_ *notify* - When set to _yes_, foot will emit a desktop notification using the - command specified in the *notify* option whenever *BEL* is - received. By default, bell notifications are shown only when the - window does *not* have keyboard focus. See + Boolean, when set to _yes_, foot will emit a desktop notification + using the command specified in the *notify* option whenever *BEL* + is received. By default, bell notifications are shown only when + the window does *not* have keyboard focus. See _desktop-notifications.inhibit-when-focused_. Default: _no_ *visual* - When set to _yes_, foot will flash the terminal window. Default: - _no_ + Boolean, when set to _yes_, foot will flash the terminal + window. Default: _no_ *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: - _no_ + Boolean, whether to run the command on *BEL* even while + focused. Default: _no_ # SECTION: desktop-notifications diff --git a/foot.ini b/foot.ini index bd4ac082..580178af 100644 --- a/foot.ini +++ b/foot.ini @@ -45,6 +45,7 @@ # osc52=enabled # disabled|copy-enabled|paste-enabled|enabled [bell] +# system=yes # urgent=no # notify=no # visual=no diff --git a/meson.build b/meson.build index ee5af2f3..f39dbc6c 100644 --- a/meson.build +++ b/meson.build @@ -179,6 +179,15 @@ else xdg_toplevel_icon = false endif +if wayland_protocols.version().version_compare('>=1.38') + add_project_arguments('-DHAVE_XDG_SYSTEM_BELL', language: 'c') + wl_proto_xml += [wayland_protocols_datadir / 'staging/xdg-system-bell/xdg-system-bell-v1.xml'] + xdg_system_bell = true +else + xdg_system_bell = false +endif + + foreach prot : wl_proto_xml wl_proto_headers += custom_target( prot.underscorify() + '-client-header', @@ -414,6 +423,7 @@ summary( 'IME': get_option('ime'), 'Grapheme clustering': utf8proc.found(), 'Wayland: xdg-toplevel-icon-v1': xdg_toplevel_icon, + 'Wayland: xdg-system-bell-v1': xdg_system_bell, 'utmp backend': utmp_backend, 'utmp helper default path': utmp_default_helper_path, 'Build terminfo': tic.found(), diff --git a/pgo/pgo.c b/pgo/pgo.c index 24154277..88e862b8 100644 --- a/pgo/pgo.c +++ b/pgo/pgo.c @@ -101,6 +101,7 @@ wayl_win_init(struct terminal *term, const char *token) void wayl_win_destroy(struct wl_window *win) {} void wayl_win_alpha_changed(struct wl_window *win) {} bool wayl_win_set_urgent(struct wl_window *win) { return true; } +bool wayl_win_ring_bell(const struct wl_window *win) { return true; } bool wayl_fractional_scaling(const struct wayland *wayl) { return true; } pid_t diff --git a/terminal.c b/terminal.c index e392c36d..6936ff29 100644 --- a/terminal.c +++ b/terminal.c @@ -3683,6 +3683,9 @@ term_bell(struct terminal *term) } } + if (term->conf->bell.system_bell) + wayl_win_ring_bell(term->window); + if (term->conf->bell.notify) { notify_notify(term, &(struct notification){ .title = xstrdup("Bell"), diff --git a/tests/test-config.c b/tests/test-config.c index a189d440..303ddd6f 100644 --- a/tests/test-config.c +++ b/tests/test-config.c @@ -579,6 +579,7 @@ test_section_bell(void) test_boolean(&ctx, &parse_section_bell, "urgent", &conf.bell.urgent); test_boolean(&ctx, &parse_section_bell, "notify", &conf.bell.notify); + test_boolean(&ctx, &parse_section_bell, "system", &conf.bell.system_bell); test_boolean(&ctx, &parse_section_bell, "command-focused", &conf.bell.command_focused); test_spawn_template(&ctx, &parse_section_bell, "command", diff --git a/wayland.c b/wayland.c index 9c184adc..3a46133f 100644 --- a/wayland.c +++ b/wayland.c @@ -1374,6 +1374,17 @@ handle_global(void *data, struct wl_registry *registry, } #endif +#if defined(HAVE_XDG_SYSTEM_BELL) + else if (streq(interface, xdg_system_bell_v1_interface.name)) { + const uint32_t required = 1; + if (!verify_iface_version(interface, version, required)) + return; + + wayl->system_bell = wl_registry_bind( + wayl->registry, name, &xdg_system_bell_v1_interface, required); + } +#endif + #if defined(FOOT_IME_ENABLED) && FOOT_IME_ENABLED else if (streq(interface, zwp_text_input_manager_v3_interface.name)) { const uint32_t required = 1; @@ -1696,6 +1707,10 @@ wayl_destroy(struct wayland *wayl) zwp_text_input_manager_v3_destroy(wayl->text_input_manager); #endif +#if defined(HAVE_XDG_SYSTEM_BELL) + if (wayl->system_bell != NULL) + xdg_system_bell_v1_destroy(wayl->system_bell); +#endif #if defined(HAVE_XDG_TOPLEVEL_ICON) if (wayl->toplevel_icon_manager != NULL) xdg_toplevel_icon_manager_v1_destroy(wayl->toplevel_icon_manager); @@ -2247,6 +2262,28 @@ wayl_win_set_urgent(struct wl_window *win) return false; } +bool +wayl_win_ring_bell(const struct wl_window *win) +{ +#if defined(HAVE_XDG_SYSTEM_BELL) + if (win->term->wl->system_bell == NULL) { + static bool have_warned = false; + + if (!have_warned) { + LOG_WARN("compositor does not implement the XDG system bell protocol"); + have_warned = true; + } + + return false; + } + + xdg_system_bell_v1_ring(win->term->wl->system_bell, win->surface.surf); + return true; +#else + return false; +#endif +} + bool wayl_win_csd_titlebar_visible(const struct wl_window *win) { diff --git a/wayland.h b/wayland.h index 227e2a68..b3ef5a2b 100644 --- a/wayland.h +++ b/wayland.h @@ -24,6 +24,10 @@ #include #endif +#if defined(HAVE_XDG_SYSTEM_BELL) + #include +#endif + #include #include @@ -451,6 +455,10 @@ struct wayland { struct xdg_toplevel_icon_manager_v1 *toplevel_icon_manager; #endif +#if defined(HAVE_XDG_SYSTEM_BELL) + struct xdg_system_bell_v1 *system_bell; +#endif + bool presentation_timings; struct wp_presentation *presentation; uint32_t presentation_clock_id; @@ -492,6 +500,7 @@ void wayl_win_destroy(struct wl_window *win); void wayl_win_scale(struct wl_window *win, const struct buffer *buf); void wayl_win_alpha_changed(struct wl_window *win); bool wayl_win_set_urgent(struct wl_window *win); +bool wayl_win_ring_bell(const struct wl_window *win); bool wayl_win_csd_titlebar_visible(const struct wl_window *win); bool wayl_win_csd_borders_visible(const struct wl_window *win);