From be4216e051658a004f1c67e7f24f95a4de469ea5 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 2 Dec 2020 17:22:41 +0100 Subject: [PATCH] gdk/wayland: Support the xdg-activation wayland protocol This protocol implements the IPC necessary to focus application windows across launcher/launchee. Add support for it. --- gdk/wayland/gdkapplaunchcontext-wayland.c | 47 ++++++++++++++++++++++- gdk/wayland/gdkdevice-wayland.c | 2 +- gdk/wayland/gdkdisplay-wayland.c | 12 +++++- gdk/wayland/gdkdisplay-wayland.h | 3 ++ gdk/wayland/gdkprivate-wayland.h | 2 + gdk/wayland/gdksurface-wayland.c | 16 ++++++-- gdk/wayland/meson.build | 5 +++ meson.build | 2 +- subprojects/wayland-protocols.wrap | 4 +- 9 files changed, 84 insertions(+), 9 deletions(-) diff --git a/gdk/wayland/gdkapplaunchcontext-wayland.c b/gdk/wayland/gdkapplaunchcontext-wayland.c index ed9e69b0eb..1e0b1b94c2 100644 --- a/gdk/wayland/gdkapplaunchcontext-wayland.c +++ b/gdk/wayland/gdkapplaunchcontext-wayland.c @@ -29,6 +29,24 @@ #include "gdkinternals.h" #include "gdkintl.h" +typedef struct { + gchar *token; +} AppLaunchData; + +static void +token_done (gpointer data, + struct xdg_activation_token_v1 *provider, + const char *token) +{ + AppLaunchData *app_launch_data = data; + + app_launch_data->token = g_strdup (token); +} + +static const struct xdg_activation_token_v1_listener token_listener = { + token_done, +}; + static char * gdk_wayland_app_launch_context_get_startup_notify_id (GAppLaunchContext *context, GAppInfo *info, @@ -39,7 +57,34 @@ gdk_wayland_app_launch_context_get_startup_notify_id (GAppLaunchContext *context g_object_get (context, "display", &display, NULL); - if (display->gtk_shell_version >= 3) + if (display->xdg_activation) + { + struct xdg_activation_token_v1 *token; + GdkWaylandSeat *seat; + GdkSurface *focus_surface; + AppLaunchData app_launch_data = { 0 }; + + seat = GDK_WAYLAND_SEAT (gdk_display_get_default_seat (GDK_DISPLAY (display))); + focus_surface = gdk_wayland_device_get_focus (gdk_seat_get_keyboard (GDK_SEAT (seat))); + token = xdg_activation_v1_get_activation_token (display->xdg_activation); + + xdg_activation_token_v1_add_listener (token, + &token_listener, + &app_launch_data); + xdg_activation_token_v1_set_serial (token, + _gdk_wayland_seat_get_last_implicit_grab_serial (seat, NULL), + gdk_wayland_seat_get_wl_seat (GDK_SEAT (seat))); + xdg_activation_token_v1_set_surface (token, + gdk_wayland_surface_get_wl_surface (focus_surface)); + xdg_activation_token_v1_commit (token); + + while (app_launch_data.token == NULL) + wl_display_roundtrip (display->wl_display); + + xdg_activation_token_v1_destroy (token); + id = app_launch_data.token; + } + else if (display->gtk_shell_version >= 3) { id = g_uuid_string_random (); gtk_shell1_notify_launch (display->gtk_shell, id); diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c index 564408dc0a..3b9c1e02da 100644 --- a/gdk/wayland/gdkdevice-wayland.c +++ b/gdk/wayland/gdkdevice-wayland.c @@ -656,7 +656,7 @@ device_emit_grab_crossing (GdkDevice *device, } } -static GdkSurface * +GdkSurface * gdk_wayland_device_get_focus (GdkDevice *device) { GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c index e04f9e8987..41b2069a77 100644 --- a/gdk/wayland/gdkdisplay-wayland.c +++ b/gdk/wayland/gdkdisplay-wayland.c @@ -90,6 +90,7 @@ #define GTK_SHELL1_VERSION 4 #define OUTPUT_VERSION_WITH_DONE 2 #define NO_XDG_OUTPUT_DONE_SINCE_VERSION 3 +#define XDG_ACTIVATION_VERSION 1 static void _gdk_wayland_display_load_cursor_theme (GdkWaylandDisplay *display_wayland); @@ -493,6 +494,15 @@ gdk_registry_handle_global (void *data, wl_registry_bind (display_wayland->wl_registry, id, &zwp_idle_inhibit_manager_v1_interface, 1); } + else if (strcmp (interface, "xdg_activation_v1") == 0) + { + display_wayland->xdg_activation_version = + MIN (version, XDG_ACTIVATION_VERSION); + display_wayland->xdg_activation = + wl_registry_bind (display_wayland->wl_registry, id, + &xdg_activation_v1_interface, + display_wayland->xdg_activation_version); + } g_hash_table_insert (display_wayland->known_globals, GUINT_TO_POINTER (id), g_strdup (interface)); @@ -857,7 +867,7 @@ gdk_wayland_display_notify_startup_complete (GdkDisplay *display, return; } - if (display_wayland->gtk_shell) + if (!display_wayland->xdg_activation && display_wayland->gtk_shell) gtk_shell1_set_startup_id (display_wayland->gtk_shell, startup_id); g_free (free_this); diff --git a/gdk/wayland/gdkdisplay-wayland.h b/gdk/wayland/gdkdisplay-wayland.h index 886210ef3c..4c27dd86a7 100644 --- a/gdk/wayland/gdkdisplay-wayland.h +++ b/gdk/wayland/gdkdisplay-wayland.h @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -112,6 +113,7 @@ struct _GdkWaylandDisplay struct org_kde_kwin_server_decoration_manager *server_decoration_manager; struct zxdg_output_manager_v1 *xdg_output_manager; struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager; + struct xdg_activation_v1 *xdg_activation; GList *async_roundtrips; @@ -139,6 +141,7 @@ struct _GdkWaylandDisplay int data_device_manager_version; int gtk_shell_version; int xdg_output_manager_version; + int xdg_activation_version; uint32_t server_decoration_mode; diff --git a/gdk/wayland/gdkprivate-wayland.h b/gdk/wayland/gdkprivate-wayland.h index eadacffbb9..908288e877 100644 --- a/gdk/wayland/gdkprivate-wayland.h +++ b/gdk/wayland/gdkprivate-wayland.h @@ -140,6 +140,8 @@ uint32_t _gdk_wayland_seat_get_implicit_grab_serial(GdkSeat *seat, GdkEvent *event); uint32_t _gdk_wayland_seat_get_last_implicit_grab_serial (GdkWaylandSeat *seat, GdkEventSequence **sequence); +GdkSurface * gdk_wayland_device_get_focus (GdkDevice *device); + struct wl_data_device * gdk_wayland_device_get_data_device (GdkDevice *gdk_device); void gdk_wayland_device_set_selection (GdkDevice *gdk_device, struct wl_data_source *source); diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index ba4d78bac2..66a8001bcd 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -3464,10 +3464,20 @@ gdk_wayland_surface_focus (GdkSurface *surface, GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); - if (display_wayland->gtk_shell_version >= 3) + if (display_wayland->startup_notification_id) { - gtk_surface1_request_focus (impl->display_server.gtk_surface, - display_wayland->startup_notification_id); + if (display_wayland->xdg_activation) + { + xdg_activation_v1_activate (display_wayland->xdg_activation, + display_wayland->startup_notification_id, + impl->display_server.wl_surface); + } + else if (display_wayland->gtk_shell_version >= 3) + { + gtk_surface1_request_focus (impl->display_server.gtk_surface, + display_wayland->startup_notification_id); + } + g_clear_pointer (&display_wayland->startup_notification_id, g_free); } } diff --git a/gdk/wayland/meson.build b/gdk/wayland/meson.build index 833945f666..28a00a959b 100644 --- a/gdk/wayland/meson.build +++ b/gdk/wayland/meson.build @@ -56,6 +56,7 @@ proto_sources = [ ['server-decoration', 'private' ], ['xdg-output', 'unstable', 'v1', ], ['idle-inhibit', 'unstable', 'v1', ], + ['xdg-activation', 'staging', 'v1', ], ] gdk_wayland_gen_headers = [] @@ -67,6 +68,10 @@ foreach p: proto_sources if proto_stability == 'stable' output_base = proto_name input = files(join_paths(wlproto_dir, '@0@/@1@/@2@.xml'.format(proto_stability, proto_name, output_base))) + elif proto_stability == 'staging' + proto_version = p.get(2) + output_base = '@0@-@1@'.format(proto_name, proto_version) + input = join_paths(wlproto_dir, '@0@/@1@/@2@.xml'.format(proto_stability, proto_name, output_base)) elif proto_stability == 'private' output_base = proto_name input = files('protocol/@0@.xml'.format(proto_name)) diff --git a/meson.build b/meson.build index 7aee079d23..d8660cbe85 100644 --- a/meson.build +++ b/meson.build @@ -16,7 +16,7 @@ fribidi_req = '>= 0.19.7' cairo_req = '>= 1.14.0' gdk_pixbuf_req = '>= 2.30.0' introspection_req = '>= 1.39.0' -wayland_proto_req = '>= 1.20' +wayland_proto_req = '>= 1.21' wayland_req = '>= 1.14.91' graphene_req = '>= 1.9.1' epoxy_req = '>= 1.4' diff --git a/subprojects/wayland-protocols.wrap b/subprojects/wayland-protocols.wrap index ba60db715d..065651db63 100644 --- a/subprojects/wayland-protocols.wrap +++ b/subprojects/wayland-protocols.wrap @@ -1,5 +1,5 @@ [wrap-git] directory=wayland-protocols -url=https://gitlab.freedesktop.org/jadahl/wayland-protocols.git -revision=wip/meson-meson-0.53 +url=https://gitlab.freedesktop.org/wayland/wayland-protocols.git +revision=main depth=1