[gtk+] Wayland: Implement KDE's SSD protocol



commit 1b279e3d4ac33ebd9a3925d1a388c28bd96232d5
Author: Drew DeVault <sir cmpwn com>
Date:   Fri Apr 28 20:35:51 2017 -0400

    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 <sir cmpwn com>
    
    https://bugzilla.gnome.org/show_bug.cgi?id=781909

 gdk/wayland/gdkdisplay-wayland.c           |   39 ++++++++++++
 gdk/wayland/gdkdisplay-wayland.h           |    4 +
 gdk/wayland/gdkwaylanddisplay.h            |    2 +
 gdk/wayland/gdkwaylandwindow.h             |    2 +
 gdk/wayland/gdkwindow-wayland.c            |   16 +++++
 gdk/wayland/meson.build                    |    3 +-
 gdk/wayland/protocol/server-decoration.xml |   94 ++++++++++++++++++++++++++++
 gtk/gtkwindow.c                            |   10 +++-
 8 files changed, 168 insertions(+), 2 deletions(-)
---
diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c
index 2154e51..ab1aa72 100644
--- a/gdk/wayland/gdkdisplay-wayland.c
+++ b/gdk/wayland/gdkdisplay-wayland.c
@@ -49,6 +49,7 @@
 #include "tablet-unstable-v2-client-protocol.h"
 #include <wayland/xdg-shell-unstable-v6-client-protocol.h>
 #include <wayland/xdg-foreign-unstable-v1-client-protocol.h>
+#include <wayland/server-decoration-client-protocol.h>
 
 /**
  * SECTION:wayland_interaction
@@ -337,6 +338,35 @@ static const struct wl_shm_listener wl_shm_listener = {
 };
 
 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,
                             uint32_t            id,
@@ -459,6 +489,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 3f53108..37083c7 100644
--- a/gdk/wayland/gdkdisplay-wayland.h
+++ b/gdk/wayland/gdkdisplay-wayland.h
@@ -32,6 +32,7 @@
 #include <gdk/wayland/xdg-shell-unstable-v6-client-protocol.h>
 #include <gdk/wayland/xdg-foreign-unstable-v1-client-protocol.h>
 #include <gdk/wayland/keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h>
+#include <gdk/wayland/server-decoration-client-protocol.h>
 
 #include <glib.h>
 #include <gdk/gdkkeys.h>
@@ -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 f4b51c8..c77da4f 100644
--- a/gdk/wayland/gdkwaylanddisplay.h
+++ b/gdk/wayland/gdkwaylanddisplay.h
@@ -57,6 +57,8 @@ GDK_AVAILABLE_IN_3_22
 void                    gdk_wayland_display_set_startup_notification_id (GdkDisplay *display,
                                                                          const char *startup_id);
 
+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 628204f..61c52da 100644
--- a/gdk/wayland/gdkwaylandwindow.h
+++ b/gdk/wayland/gdkwaylandwindow.h
@@ -81,6 +81,8 @@ GDK_AVAILABLE_IN_3_22
 gboolean                 gdk_wayland_window_set_transient_for_exported (GdkWindow *window,
                                                                         char      *parent_handle_str);
 
+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 157d41d..298435e 100644
--- a/gdk/wayland/gdkwindow-wayland.c
+++ b/gdk/wayland/gdkwindow-wayland.c
@@ -117,6 +117,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;
@@ -1663,6 +1664,21 @@ window_anchor_to_gravity (GdkGravity rect_anchor)
           ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
 }
 
+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/meson.build b/gdk/wayland/meson.build
index bab68ac..8456674 100644
--- a/gdk/wayland/meson.build
+++ b/gdk/wayland/meson.build
@@ -54,7 +54,8 @@ proto_sources = [
   ['xdg-shell', 'unstable', 'v6', ],
   ['xdg-foreign', 'unstable', 'v1', ],
   ['tablet', 'unstable', 'v2', ],
-  [ 'keyboard-shortcuts-inhibit', 'unstable', 'v1', ],
+  ['keyboard-shortcuts-inhibit', 'unstable', 'v1', ],
+  ['server-decoration', 'stable' ],
 ]
 
 gdk_wayland_gen_headers = []
diff --git a/gdk/wayland/protocol/server-decoration.xml b/gdk/wayland/protocol/server-decoration.xml
new file mode 100644
index 0000000..8bc106c
--- /dev/null
+++ b/gdk/wayland/protocol/server-decoration.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="server_decoration">
+  <copyright><![CDATA[
+    Copyright (C) 2015 Martin Gräßlin
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 2.1 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  ]]></copyright>
+  <interface  name="org_kde_kwin_server_decoration_manager" version="1">
+      <description summary="Server side window decoration manager">
+        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.
+      </description>
+      <request name="create">
+        <description summary="Create a server-side decoration object for a given surface">
+            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.
+        </description>
+        <arg name="id" type="new_id" interface="org_kde_kwin_server_decoration"/>
+        <arg name="surface" type="object" interface="wl_surface"/>
+      </request>
+      <enum name="mode">
+            <description summary="Possible values to use in request_mode and the event mode."/>
+            <entry name="None" value="0" summary="Undecorated: The surface is not decorated at all, neither 
server nor client-side. An example is a popup surface which should not be decorated."/>
+            <entry name="Client" value="1" summary="Client-side decoration: The decoration is part of the 
surface and the client."/>
+            <entry name="Server" value="2" summary="Server-side decoration: The server embeds the surface 
into a decoration frame."/>
+      </enum>
+      <event name="default_mode">
+          <description summary="The default mode used on the server">
+              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.
+          </description>
+          <arg name="mode" type="uint" summary="The default decoration mode applied to newly created server 
decorations."/>
+      </event>
+  </interface>
+  <interface name="org_kde_kwin_server_decoration" version="1">
+      <request name="release" type="destructor">
+        <description summary="release the server decoration object"/>
+      </request>
+      <enum name="mode">
+            <description summary="Possible values to use in request_mode and the event mode."/>
+            <entry name="None" value="0" summary="Undecorated: The surface is not decorated at all, neither 
server nor client-side. An example is a popup surface which should not be decorated."/>
+            <entry name="Client" value="1" summary="Client-side decoration: The decoration is part of the 
surface and the client."/>
+            <entry name="Server" value="2" summary="Server-side decoration: The server embeds the surface 
into a decoration frame."/>
+      </enum>
+      <request name="request_mode">
+          <description summary="The decoration mode the surface wants to use."/>
+          <arg name="mode" type="uint" summary="The mode this surface wants to use."/>
+      </request>
+      <event name="mode">
+          <description summary="The new decoration mode applied by the server">
+              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.
+          </description>
+          <arg name="mode" type="uint" summary="The decoration mode applied to the surface by the server."/>
+      </event>
+  </interface>
+</protocol>
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 1e87600..68de62e 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -6047,7 +6047,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
@@ -6894,6 +6897,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);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]