From f2adaba237519642b88ccb42b47a95cf539a2a12 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Fri, 28 Apr 2017 20:35:51 -0400 Subject: [PATCH] Wayland: Implement KDE's SSD protocol If the compositor prefers server-side decorations and the client doesn't customize the title bar, we disable client-side decorations and let the compositor know. Otherwise, we continue to use client-side decorations. Signed-off-by: Drew DeVault https://bugzilla.gnome.org/show_bug.cgi?id=781909 --- gdk/wayland/Makefile.am | 2 + gdk/wayland/gdkdisplay-wayland.c | 39 +++++++++ gdk/wayland/gdkdisplay-wayland.h | 4 + gdk/wayland/gdkwaylanddisplay.h | 3 + gdk/wayland/gdkwaylandwindow.h | 3 + gdk/wayland/gdkwindow-wayland.c | 16 ++++ gdk/wayland/protocol/server-decoration.xml | 94 ++++++++++++++++++++++ gtk/gtkwindow.c | 10 ++- 8 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 gdk/wayland/protocol/server-decoration.xml diff --git a/gdk/wayland/Makefile.am b/gdk/wayland/Makefile.am index dbaae63673..9295b1a15b 100644 --- a/gdk/wayland/Makefile.am +++ b/gdk/wayland/Makefile.am @@ -33,6 +33,8 @@ BUILT_SOURCES = \ tablet-unstable-v2-protocol.c \ keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h \ keyboard-shortcuts-inhibit-unstable-v1-protocol.c \ + server-decoration-client-protocol.h \ + server-decoration-protocol.c \ gtk-shell-client-protocol.h \ gtk-shell-protocol.c diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c index 3814157557..8bcd6755a6 100644 --- a/gdk/wayland/gdkdisplay-wayland.c +++ b/gdk/wayland/gdkdisplay-wayland.c @@ -46,6 +46,7 @@ #include "tablet-unstable-v2-client-protocol.h" #include "xdg-shell-unstable-v6-client-protocol.h" #include "xdg-foreign-unstable-v1-client-protocol.h" +#include "server-decoration-client-protocol.h" /** * SECTION:wayland_interaction @@ -333,6 +334,35 @@ static const struct wl_shm_listener wl_shm_listener = { wl_shm_format }; +static void +server_decoration_manager_default_mode (void *data, + struct org_kde_kwin_server_decoration_manager *manager, + uint32_t mode) +{ + g_assert (mode <= ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER); + const char *modes[] = { + [ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_NONE] = "none", + [ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT] = "client", + [ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER] = "server", + }; + GdkWaylandDisplay *display_wayland = data; + g_debug ("Compositor prefers decoration mode '%s'", modes[mode]); + display_wayland->server_decoration_mode = mode; +} + +static const struct org_kde_kwin_server_decoration_manager_listener server_decoration_listener = { + .default_mode = server_decoration_manager_default_mode +}; + +gboolean +gdk_wayland_display_prefers_ssd (GdkDisplay *display) +{ + GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display); + if (display_wayland->server_decoration_manager) + return display_wayland->server_decoration_mode == ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER; + return FALSE; +} + static void gdk_registry_handle_global (void *data, struct wl_registry *registry, @@ -456,6 +486,15 @@ gdk_registry_handle_global (void *data, wl_registry_bind (display_wayland->wl_registry, id, &zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1); } + else if (strcmp (interface, "org_kde_kwin_server_decoration_manager") == 0) + { + display_wayland->server_decoration_manager = + wl_registry_bind (display_wayland->wl_registry, id, + &org_kde_kwin_server_decoration_manager_interface, 1); + org_kde_kwin_server_decoration_manager_add_listener (display_wayland->server_decoration_manager, + &server_decoration_listener, + display_wayland); + } else handled = FALSE; diff --git a/gdk/wayland/gdkdisplay-wayland.h b/gdk/wayland/gdkdisplay-wayland.h index d24a48ef5b..9b1555761c 100644 --- a/gdk/wayland/gdkdisplay-wayland.h +++ b/gdk/wayland/gdkdisplay-wayland.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -79,6 +80,7 @@ struct _GdkWaylandDisplay struct zxdg_exporter_v1 *xdg_exporter; struct zxdg_importer_v1 *xdg_importer; struct zwp_keyboard_shortcuts_inhibit_manager_v1 *keyboard_shortcuts_inhibit; + struct org_kde_kwin_server_decoration_manager *server_decoration_manager; GList *async_roundtrips; @@ -106,6 +108,8 @@ struct _GdkWaylandDisplay int data_device_manager_version; int gtk_shell_version; + uint32_t server_decoration_mode; + struct xkb_context *xkb_context; GdkWaylandSelection *selection; diff --git a/gdk/wayland/gdkwaylanddisplay.h b/gdk/wayland/gdkwaylanddisplay.h index f4b51c82d1..d980d6cf87 100644 --- a/gdk/wayland/gdkwaylanddisplay.h +++ b/gdk/wayland/gdkwaylanddisplay.h @@ -57,6 +57,9 @@ GDK_AVAILABLE_IN_3_22 void gdk_wayland_display_set_startup_notification_id (GdkDisplay *display, const char *startup_id); +GDK_AVAILABLE_IN_3_22 +gboolean gdk_wayland_display_prefers_ssd (GdkDisplay *display); + G_END_DECLS #endif /* __GDK_WAYLAND_DISPLAY_H__ */ diff --git a/gdk/wayland/gdkwaylandwindow.h b/gdk/wayland/gdkwaylandwindow.h index 566d40524c..93b7802b6e 100644 --- a/gdk/wayland/gdkwaylandwindow.h +++ b/gdk/wayland/gdkwaylandwindow.h @@ -77,6 +77,9 @@ GDK_AVAILABLE_IN_3_22 gboolean gdk_wayland_window_set_transient_for_exported (GdkWindow *window, char *parent_handle_str); +GDK_AVAILABLE_IN_3_22 +void gdk_wayland_window_announce_csd (GdkWindow *window); + G_END_DECLS #endif /* __GDK_WAYLAND_WINDOW_H__ */ diff --git a/gdk/wayland/gdkwindow-wayland.c b/gdk/wayland/gdkwindow-wayland.c index 66c19e0425..4b3fc93554 100644 --- a/gdk/wayland/gdkwindow-wayland.c +++ b/gdk/wayland/gdkwindow-wayland.c @@ -126,6 +126,7 @@ struct _GdkWindowImplWayland struct wl_egl_window *egl_window; struct wl_egl_window *dummy_egl_window; struct zxdg_exported_v1 *xdg_exported; + struct org_kde_kwin_server_decoration *server_decoration; } display_server; EGLSurface egl_surface; @@ -1681,6 +1682,21 @@ window_anchor_to_gravity (GdkGravity rect_anchor) } } +void +gdk_wayland_window_announce_csd (GdkWindow *window) +{ + GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window)); + GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl); + if (!display_wayland->server_decoration_manager) + return; + impl->display_server.server_decoration = + org_kde_kwin_server_decoration_manager_create (display_wayland->server_decoration_manager, + impl->display_server.wl_surface); + if (impl->display_server.server_decoration) + org_kde_kwin_server_decoration_request_mode (impl->display_server.server_decoration, + ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT); +} + static GdkWindow * get_real_parent_and_translate (GdkWindow *window, gint *x, diff --git a/gdk/wayland/protocol/server-decoration.xml b/gdk/wayland/protocol/server-decoration.xml new file mode 100644 index 0000000000..8bc106c7c4 --- /dev/null +++ b/gdk/wayland/protocol/server-decoration.xml @@ -0,0 +1,94 @@ + + + . + ]]> + + + This interface allows to coordinate whether the server should create + a server-side window decoration around a wl_surface representing a + shell surface (wl_shell_surface or similar). By announcing support + for this interface the server indicates that it supports server + side decorations. + + + + When a client creates a server-side decoration object it indicates + that it supports the protocol. The client is supposed to tell the + server whether it wants server-side decorations or will provide + client-side decorations. + + If the client does not create a server-side decoration object for + a surface the server interprets this as lack of support for this + protocol and considers it as client-side decorated. Nevertheless a + client-side decorated surface should use this protocol to indicate + to the server that it does not want a server-side deco. + + + + + + + + + + + + + This event is emitted directly after binding the interface. It contains + the default mode for the decoration. When a new server decoration object + is created this new object will be in the default mode until the first + request_mode is requested. + + The server may change the default mode at any time. + + + + + + + + + + + + + + + + + + + + + This event is emitted directly after the decoration is created and + represents the base decoration policy by the server. E.g. a server + which wants all surfaces to be client-side decorated will send Client, + a server which wants server-side decoration will send Server. + + The client can request a different mode through the decoration request. + The server will acknowledge this by another event with the same mode. So + even if a server prefers server-side decoration it's possible to force a + client-side decoration. + + The server may emit this event at any time. In this case the client can + again request a different mode. It's the responsibility of the server to + prevent a feedback loop. + + + + + diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index a4ba098224..33f81d21c7 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -6100,7 +6100,10 @@ gtk_window_should_use_csd (GtkWindow *window) #ifdef GDK_WINDOWING_WAYLAND if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window)))) - return TRUE; + { + GdkDisplay *gdk_display = gtk_widget_get_display (GTK_WIDGET (window)); + return !gdk_wayland_display_prefers_ssd (gdk_display); + } #endif #ifdef GDK_WINDOWING_MIR @@ -7477,6 +7480,11 @@ gtk_window_realize (GtkWidget *widget) if (!priv->decorated || priv->client_decorated) gdk_window_set_decorations (gdk_window, 0); +#ifdef GDK_WINDOWING_WAYLAND + if (priv->client_decorated && GDK_IS_WAYLAND_WINDOW (gdk_window)) + gdk_wayland_window_announce_csd (gdk_window); +#endif + if (!priv->deletable) gdk_window_set_functions (gdk_window, GDK_FUNC_ALL | GDK_FUNC_CLOSE); -- GitLab