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 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 diff --git a/meson.build b/meson.build index c36d7644..0c48929a 100644 --- a/meson.build +++ b/meson.build @@ -88,7 +88,7 @@ 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', @@ -97,6 +97,12 @@ foreach prot : [ wayland_protocols_datadir + '/unstable/text-input/text-input-unstable-v3.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/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[], 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..24d22359 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 @@ -630,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 @@ -989,6 +985,17 @@ 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)) + return; + + 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) { const uint32_t required = 1; @@ -1187,6 +1194,16 @@ 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"); + } + if (conf->presentation_timings && wayl->presentation == NULL) { LOG_ERR("presentation time interface not implemented by compositor"); goto out; @@ -1275,6 +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) @@ -1452,6 +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) @@ -1573,6 +1598,58 @@ 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) +{ + 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, +}; +#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) + 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_set_surface(token, win->surface); + xdg_activation_token_v1_commit(token); + win->xdg_activation_token = token; + return true; +#else + return false; +#endif +} + 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..4ec09544 100644 --- a/wayland.h +++ b/wayland.h @@ -8,8 +8,17 @@ #include #include -#include +/* Wayland protocols */ #include +#include +#include +#include +#include +#include + +#if defined(HAVE_XDG_ACTIVATION) + #include +#endif #include @@ -377,6 +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; @@ -444,6 +456,10 @@ 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; @@ -469,6 +485,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(