From 3e92361534cdd02e8da8a5f7e8112361b1d6eb67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 9 May 2021 12:13:14 +0200 Subject: [PATCH 1/7] xdg-activation: initial support for setting urgency using XDG activation --- meson.build | 1 + terminal.c | 18 ++++++++++---- wayland.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++---- wayland.h | 13 ++++++++++- 4 files changed, 89 insertions(+), 10 deletions(-) diff --git a/meson.build b/meson.build index c36d7644..b78079c3 100644 --- a/meson.build +++ b/meson.build @@ -95,6 +95,7 @@ foreach prot : [ wayland_protocols_datadir + '/unstable/primary-selection/primary-selection-unstable-v1.xml', wayland_protocols_datadir + '/stable/presentation-time/presentation-time.xml', wayland_protocols_datadir + '/unstable/text-input/text-input-unstable-v3.xml', + wayland_protocols_datadir + '/staging/xdg-activation/xdg-activation-v1.xml', ] wl_proto_headers += custom_target( diff --git a/terminal.c b/terminal.c index f3513a08..a9712789 100644 --- a/terminal.c +++ b/terminal.c @@ -2632,16 +2632,24 @@ term_bell(struct terminal *term) 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 (!wayl_win_set_urgent(term->window)) { + /* + * Urgency (xdg-activation) is relatively new in + * Wayland. Fallback to our old, “faked”, urgency - + * rendering our window margins in red + */ + term->render.urgency = true; + term_damage_margins(term); + } } + if (term->conf->bell.notify) notify_notify(term, "Bell", "Bell in terminal"); } - if ((term->conf->bell.command.argv != NULL) && (!term->kbd_focus || term->conf->bell.command_focused)) { + if ((term->conf->bell.command.argv != NULL) && + (!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); diff --git a/wayland.c b/wayland.c index 102b29c5..f7f89d72 100644 --- a/wayland.c +++ b/wayland.c @@ -12,13 +12,9 @@ #include #include -#include #include #include -#include -#include -#include #define LOG_MODULE "wayland" #define LOG_ENABLE_DBG 0 @@ -989,6 +985,15 @@ handle_global(void *data, struct wl_registry *registry, } } + else if (strcmp(interface, xdg_activation_v1_interface.name) == 0) { + const uint32_t required = 1; + if (!verify_iface_version(interface, version, required)) + return; + + wayl->xdg_activation = wl_registry_bind( + wayl->registry, name, &xdg_activation_v1_interface, required); + } + #if defined(FOOT_IME_ENABLED) && FOOT_IME_ENABLED else if (strcmp(interface, zwp_text_input_manager_v3_interface.name) == 0) { const uint32_t required = 1; @@ -1187,6 +1192,12 @@ wayl_init(const struct config *conf, struct fdm *fdm) if (wayl->primary_selection_device_manager == NULL) LOG_WARN("no primary selection available"); + if (wayl->xdg_activation == NULL && conf->bell.urgent) { + LOG_WARN( + "no XDG activation support; " + "bell.urgent will fall back to coloring the window margins red"); + } + if (conf->presentation_timings && wayl->presentation == NULL) { LOG_ERR("presentation time interface not implemented by compositor"); goto out; @@ -1275,6 +1286,8 @@ wayl_destroy(struct wayland *wayl) zwp_text_input_manager_v3_destroy(wayl->text_input_manager); #endif + if (wayl->xdg_activation != NULL) + xdg_activation_v1_destroy(wayl->xdg_activation); if (wayl->xdg_output_manager != NULL) zxdg_output_manager_v1_destroy(wayl->xdg_output_manager); if (wayl->shell != NULL) @@ -1452,6 +1465,8 @@ wayl_win_destroy(struct wl_window *win) wayl_win_subsurface_destroy(&win->scrollback_indicator); wayl_win_subsurface_destroy(&win->render_timer); + if (win->xdg_activation_token != NULL) + xdg_activation_token_v1_destroy(win->xdg_activation_token); if (win->frame_callback != NULL) wl_callback_destroy(win->frame_callback); if (win->xdg_toplevel_decoration != NULL) @@ -1573,6 +1588,50 @@ wayl_roundtrip(struct wayland *wayl) wayl_flush(wayl); } +static void +activation_token_done(void *data, struct xdg_activation_token_v1 *xdg_token, const char *token) +{ + struct wl_window *win = data; + struct wayland *wayl = win->term->wl; + + LOG_DBG("activation token: %s", token); + + xdg_activation_v1_activate(wayl->xdg_activation, token, win->surface); + + xassert(win->xdg_activation_token == xdg_token); + xdg_activation_token_v1_destroy(xdg_token); + win->xdg_activation_token = NULL; +} + +static const struct xdg_activation_token_v1_listener activation_token_listener = { + .done = &activation_token_done, +}; + +bool +wayl_win_set_urgent(struct wl_window *win) +{ + struct wayland *wayl = win->term->wl; + + if (wayl->xdg_activation == NULL) + return false; + + if (win->xdg_activation_token != NULL) + return true; + + struct xdg_activation_token_v1 *token = + xdg_activation_v1_get_activation_token(wayl->xdg_activation); + + if (token == NULL) { + LOG_ERR("failed to retrieve XDG activation token"); + return false; + } + + xdg_activation_token_v1_add_listener(token, &activation_token_listener, win); + xdg_activation_token_v1_commit(token); + win->xdg_activation_token = token; + return true; +} + bool wayl_win_subsurface_new_with_custom_parent( struct wl_window *win, struct wl_surface *parent, diff --git a/wayland.h b/wayland.h index 0b916ccc..dd6637cd 100644 --- a/wayland.h +++ b/wayland.h @@ -8,8 +8,14 @@ #include #include -#include +/* Wayland protocols */ #include +#include +#include +#include +#include +#include +#include #include @@ -377,6 +383,7 @@ struct wl_window { struct wl_surface *surface; struct xdg_surface *xdg_surface; struct xdg_toplevel *xdg_toplevel; + struct xdg_activation_token_v1 *xdg_activation_token; struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration; @@ -444,6 +451,8 @@ struct wayland { struct wl_data_device_manager *data_device_manager; struct zwp_primary_selection_device_manager_v1 *primary_selection_device_manager; + struct xdg_activation_v1 *xdg_activation; + struct wp_presentation *presentation; uint32_t presentation_clock_id; @@ -469,6 +478,8 @@ void wayl_roundtrip(struct wayland *wayl); struct wl_window *wayl_win_init(struct terminal *term); void wayl_win_destroy(struct wl_window *win); +bool wayl_win_set_urgent(struct wl_window *win); + bool wayl_win_subsurface_new( struct wl_window *win, struct wl_surf_subsurf *surf); bool wayl_win_subsurface_new_with_custom_parent( From f5f1bc8dd95b319aa7574db139c40c0697025d0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 10 May 2021 18:01:59 +0200 Subject: [PATCH 2/7] wayland: set xdg activation token surface to our top-level --- wayland.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wayland.c b/wayland.c index f7f89d72..35ed35dd 100644 --- a/wayland.c +++ b/wayland.c @@ -1589,7 +1589,8 @@ wayl_roundtrip(struct wayland *wayl) } static void -activation_token_done(void *data, struct xdg_activation_token_v1 *xdg_token, const char *token) +activation_token_done(void *data, struct xdg_activation_token_v1 *xdg_token, + const char *token) { struct wl_window *win = data; struct wayland *wayl = win->term->wl; @@ -1627,6 +1628,7 @@ wayl_win_set_urgent(struct wl_window *win) } xdg_activation_token_v1_add_listener(token, &activation_token_listener, win); + xdg_activation_token_v1_set_surface(token, win->surface); xdg_activation_token_v1_commit(token); win->xdg_activation_token = token; return true; From bf44f3f5949a4c49b4c79763350eb0f08ced36f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 11 May 2021 07:56:04 +0200 Subject: [PATCH 3/7] pgo: add wayl_win_set_urgent() stub --- pgo/pgo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/pgo/pgo.c b/pgo/pgo.c index ec8a7883..c1620b04 100644 --- a/pgo/pgo.c +++ b/pgo/pgo.c @@ -81,6 +81,7 @@ wayl_win_init(struct terminal *term) } void wayl_win_destroy(struct wl_window *win) {} +bool wayl_win_set_urgent(struct wl_window *win) { return true; } bool spawn(struct reaper *reaper, const char *cwd, char *const argv[], From 03e1b906abc6b29bb4b76b6e0429b8da9e2e2c0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 11 May 2021 17:58:40 +0200 Subject: [PATCH 4/7] meson: add xdg-activation-v1.xml conditionally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only enable XDG activation when compiling against wayland-protocols 1.21. Older versions don’t have this protocol. When available, define HAVE_XDG_ACTIVATION. Make all usages of xdg_activation_v1 and xdg_activation_token_v1 conditional. --- meson.build | 9 +++++++-- wayland.c | 16 ++++++++++++++++ wayland.h | 9 ++++++++- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index b78079c3..0c48929a 100644 --- a/meson.build +++ b/meson.build @@ -88,16 +88,21 @@ wscanner_prog = find_program( wl_proto_headers = [] wl_proto_src = [] -foreach prot : [ +wl_proto_xml = [ wayland_protocols_datadir + '/stable/xdg-shell/xdg-shell.xml', wayland_protocols_datadir + '/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml', wayland_protocols_datadir + '/unstable/xdg-output/xdg-output-unstable-v1.xml', wayland_protocols_datadir + '/unstable/primary-selection/primary-selection-unstable-v1.xml', wayland_protocols_datadir + '/stable/presentation-time/presentation-time.xml', wayland_protocols_datadir + '/unstable/text-input/text-input-unstable-v3.xml', - wayland_protocols_datadir + '/staging/xdg-activation/xdg-activation-v1.xml', ] +if wayland_protocols.version().version_compare('>=1.21') + add_project_arguments('-DHAVE_XDG_ACTIVATION', language: 'c') + wl_proto_xml += [wayland_protocols_datadir + '/staging/xdg-activation/xdg-activation-v1.xml'] +endif + +foreach prot : wl_proto_xml wl_proto_headers += custom_target( prot.underscorify() + '-client-header', output: '@BASENAME@.h', diff --git a/wayland.c b/wayland.c index 35ed35dd..cbceb576 100644 --- a/wayland.c +++ b/wayland.c @@ -985,6 +985,7 @@ handle_global(void *data, struct wl_registry *registry, } } +#if defined(HAVE_XDG_ACTIVATION) else if (strcmp(interface, xdg_activation_v1_interface.name) == 0) { const uint32_t required = 1; if (!verify_iface_version(interface, version, required)) @@ -993,6 +994,7 @@ handle_global(void *data, struct wl_registry *registry, wayl->xdg_activation = wl_registry_bind( wayl->registry, name, &xdg_activation_v1_interface, required); } +#endif #if defined(FOOT_IME_ENABLED) && FOOT_IME_ENABLED else if (strcmp(interface, zwp_text_input_manager_v3_interface.name) == 0) { @@ -1192,7 +1194,11 @@ wayl_init(const struct config *conf, struct fdm *fdm) if (wayl->primary_selection_device_manager == NULL) LOG_WARN("no primary selection available"); +#if defined(HAVE_XDG_ACTIVATION) if (wayl->xdg_activation == NULL && conf->bell.urgent) { +#else + if (conf->bell.urgent) { +#endif LOG_WARN( "no XDG activation support; " "bell.urgent will fall back to coloring the window margins red"); @@ -1286,8 +1292,10 @@ wayl_destroy(struct wayland *wayl) zwp_text_input_manager_v3_destroy(wayl->text_input_manager); #endif +#if defined(HAVE_XDG_ACTIVATION) if (wayl->xdg_activation != NULL) xdg_activation_v1_destroy(wayl->xdg_activation); +#endif if (wayl->xdg_output_manager != NULL) zxdg_output_manager_v1_destroy(wayl->xdg_output_manager); if (wayl->shell != NULL) @@ -1465,8 +1473,10 @@ wayl_win_destroy(struct wl_window *win) wayl_win_subsurface_destroy(&win->scrollback_indicator); wayl_win_subsurface_destroy(&win->render_timer); +#if defined(HAVE_XDG_ACTIVATION) if (win->xdg_activation_token != NULL) xdg_activation_token_v1_destroy(win->xdg_activation_token); +#endif if (win->frame_callback != NULL) wl_callback_destroy(win->frame_callback); if (win->xdg_toplevel_decoration != NULL) @@ -1588,6 +1598,7 @@ wayl_roundtrip(struct wayland *wayl) wayl_flush(wayl); } +#if defined(HAVE_XDG_ACTIVATION) static void activation_token_done(void *data, struct xdg_activation_token_v1 *xdg_token, const char *token) @@ -1607,10 +1618,12 @@ activation_token_done(void *data, struct xdg_activation_token_v1 *xdg_token, static const struct xdg_activation_token_v1_listener activation_token_listener = { .done = &activation_token_done, }; +#endif /* HAVE_XDG_ACTIVATION */ bool wayl_win_set_urgent(struct wl_window *win) { +#if defined(HAVE_XDG_ACTIVATION) struct wayland *wayl = win->term->wl; if (wayl->xdg_activation == NULL) @@ -1632,6 +1645,9 @@ wayl_win_set_urgent(struct wl_window *win) xdg_activation_token_v1_commit(token); win->xdg_activation_token = token; return true; +#else + return false; +#endif } bool diff --git a/wayland.h b/wayland.h index dd6637cd..4ec09544 100644 --- a/wayland.h +++ b/wayland.h @@ -12,11 +12,14 @@ #include #include #include -#include #include #include #include +#if defined(HAVE_XDG_ACTIVATION) + #include +#endif + #include #include "fdm.h" @@ -383,7 +386,9 @@ struct wl_window { struct wl_surface *surface; struct xdg_surface *xdg_surface; struct xdg_toplevel *xdg_toplevel; +#if defined(HAVE_XDG_ACTIVATION) struct xdg_activation_token_v1 *xdg_activation_token; +#endif struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration; @@ -451,7 +456,9 @@ struct wayland { struct wl_data_device_manager *data_device_manager; struct zwp_primary_selection_device_manager_v1 *primary_selection_device_manager; +#if defined(HAVE_XDG_ACTIVATION) struct xdg_activation_v1 *xdg_activation; +#endif struct wp_presentation *presentation; uint32_t presentation_clock_id; From 584d2cacf18e885c8b88e5e8472f62ded00881e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 11 May 2021 22:02:20 +0200 Subject: [PATCH 5/7] wayland: workaround epoll-shim defining the macro close --- wayland.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wayland.c b/wayland.c index cbceb576..24d22359 100644 --- a/wayland.c +++ b/wayland.c @@ -626,7 +626,7 @@ xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel) static const struct xdg_toplevel_listener xdg_toplevel_listener = { .configure = &xdg_toplevel_configure, - .close = &xdg_toplevel_close, + /*.close = */&xdg_toplevel_close, /* epoll-shim defines a macro ‘close’... */ }; static void From 3c898770cb72eeaa4cec09383aff000067bcc16c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 12 May 2021 19:25:37 +0200 Subject: [PATCH 6/7] ci: try switching the gitlab CI from alpine:latest -> alpine:edge --- .gitlab-ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3037cd03..bf61ada4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -14,7 +14,7 @@ before_script: - apk add ttf-hack font-noto-emoji debug-x64: - image: alpine:latest + image: alpine:edge stage: build script: - mkdir -p bld/debug @@ -27,7 +27,7 @@ debug-x64: junit: bld/debug/meson-logs/testlog.junit.xml release-x64: - image: alpine:latest + image: alpine:edge stage: build script: - mkdir -p bld/release @@ -40,7 +40,7 @@ release-x64: junit: bld/release/meson-logs/testlog.junit.xml debug-x86: - image: i386/alpine:latest + image: i386/alpine:edge stage: build script: - mkdir -p bld/debug @@ -53,7 +53,7 @@ debug-x86: junit: bld/debug/meson-logs/testlog.junit.xml release-x86: - image: i386/alpine:latest + image: i386/alpine:edge stage: build script: - mkdir -p bld/release @@ -66,7 +66,7 @@ release-x86: junit: bld/release/meson-logs/testlog.junit.xml codespell: - image: alpine:latest + image: alpine:edge stage: build script: - apk add python3 From 82114841857eae0fa9b6b84bb993afc712537eb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 14 May 2021 14:22:43 +0200 Subject: [PATCH 7/7] changeloge: xdg-activation support --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c27eb646..c225a576 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,9 @@ (https://codeberg.org/dnkl/foot/pulls/483) * Support for setting the full 256 color palette in foot.ini (https://codeberg.org/dnkl/foot/issues/489) +* XDG activation support, will be used by `[bell].urgent` when + available (falling back to coloring the window margins red when + unavailable) (https://codeberg.org/dnkl/foot/issues/487). ### Changed