[gtk+] wayland: Add support for custom surfaces



commit 8d884bb4fb31872766bfa6f33f667e0a4fbf0e26
Author: Jan Arne Petersen <jpetersen openismus com>
Date:   Wed Mar 20 16:38:36 2013 +0100

    wayland: Add support for custom surfaces
    
    Allow to set a GdkWindow to use a custom surface instead of a
    wl_shell_surface. It allows to register the surface as a custom type
    with some Wayland interface.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=695861

 gdk/wayland/gdkwaylandwindow.h  |    2 +
 gdk/wayland/gdkwindow-wayland.c |  133 ++++++++++++++++++++++++++++++++++-----
 2 files changed, 119 insertions(+), 16 deletions(-)
---
diff --git a/gdk/wayland/gdkwaylandwindow.h b/gdk/wayland/gdkwaylandwindow.h
index f0fb552..e1930d3 100644
--- a/gdk/wayland/gdkwaylandwindow.h
+++ b/gdk/wayland/gdkwaylandwindow.h
@@ -47,6 +47,8 @@ GType                    gdk_wayland_window_get_type             (void);
 struct wl_surface       *gdk_wayland_window_get_wl_surface       (GdkWindow *window);
 struct wl_shell_surface *gdk_wayland_window_get_wl_shell_surface (GdkWindow *window);
 
+void                     gdk_wayland_window_set_use_custom_surface (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 d65f86d..8f824ed 100644
--- a/gdk/wayland/gdkwindow-wayland.c
+++ b/gdk/wayland/gdkwindow-wayland.c
@@ -140,6 +140,8 @@ struct _GdkWindowImplWayland
     {
       int width, height;
     } saved_fullscreen, saved_maximized;
+
+  gboolean use_custom_surface;
 };
 
 struct _GdkWindowImplWaylandClass
@@ -565,13 +567,13 @@ gdk_wayland_window_map (GdkWindow *window)
     GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
   GdkWindow *transient_for;
 
-  if (!impl->mapped)
+  if (!impl->mapped && !impl->use_custom_surface)
     {
       /* Popup menus can appear without a transient parent, which means they
        * cannot be positioned properly on Wayland. This attempts to guess the
        * surface they should be positioned with by finding the surface beneath
-       * the device that created the grab for the popup window */
-
+       * the device that created the grab for the popup window
+       */
       if (!impl->transient_for && impl->hint == GDK_WINDOW_TYPE_HINT_POPUP_MENU)
         {
           transient_for = gdk_device_get_window_at_position (impl->grab_device, NULL, NULL);
@@ -710,15 +712,21 @@ gdk_wayland_window_show (GdkWindow *window, gboolean already_mapped)
       XSERVER_TIME_IS_LATER (display_wayland->user_time, impl->user_time))
     gdk_wayland_window_set_user_time (window, impl->user_time);
 
-  impl->surface = wl_compositor_create_surface(display_wayland->compositor);
-  wl_surface_set_user_data(impl->surface, window);
+  if (!impl->surface)
+    {
+      impl->surface = wl_compositor_create_surface(display_wayland->compositor);
+      wl_surface_set_user_data(impl->surface, window);
+    }
 
-  impl->shell_surface = wl_shell_get_shell_surface (display_wayland->shell,
-                                                    impl->surface);
-  wl_shell_surface_add_listener(impl->shell_surface,
-                                &shell_surface_listener, window);
+  if (!impl->use_custom_surface && display_wayland->shell)
+    {
+      impl->shell_surface = wl_shell_get_shell_surface (display_wayland->shell,
+                                                        impl->surface);
+      wl_shell_surface_add_listener(impl->shell_surface,
+                                    &shell_surface_listener, window);
+    }
 
-  gdk_window_set_type_hint (window, impl->hint);  
+  gdk_window_set_type_hint (window, impl->hint);
 
   _gdk_make_event (window, GDK_MAP, NULL, FALSE);
   event = _gdk_make_event (window, GDK_VISIBILITY_NOTIFY, NULL, FALSE);
@@ -740,10 +748,17 @@ gdk_wayland_window_hide (GdkWindow *window)
     {
       if (impl->shell_surface)
         wl_shell_surface_destroy(impl->shell_surface);
-      if (impl->surface)
-        wl_surface_destroy(impl->surface);
+      if (impl->use_custom_surface)
+        {
+          wl_surface_attach (impl->surface, NULL, 0, 0);
+          wl_surface_commit (impl->surface);
+        }
+      else if (impl->surface)
+        {
+          wl_surface_destroy(impl->surface);
+          impl->surface = NULL;
+        }
       impl->shell_surface = NULL;
-      impl->surface = NULL;
       cairo_surface_destroy(impl->server_surface);
       impl->server_surface = NULL;
       impl->mapped = FALSE;
@@ -769,10 +784,17 @@ gdk_window_wayland_withdraw (GdkWindow *window)
         {
           if (impl->shell_surface)
             wl_shell_surface_destroy(impl->shell_surface);
-          if (impl->surface)
-            wl_surface_destroy(impl->surface);
+          if (impl->use_custom_surface)
+            {
+              wl_surface_attach (impl->surface, NULL, 0, 0);
+              wl_surface_commit (impl->surface);
+            }
+          else if (impl->surface)
+            {
+              wl_surface_destroy(impl->surface);
+              impl->surface = NULL;
+            }
           impl->shell_surface = NULL;
-          impl->surface = NULL;
           cairo_surface_destroy(impl->server_surface);
           impl->server_surface = NULL;
           impl->mapped = FALSE;
@@ -1364,8 +1386,12 @@ gdk_wayland_window_fullscreen (GdkWindow *window)
   if (impl->fullscreen)
     return;
 
+  if (!impl->shell_surface)
+    return;
+
   impl->saved_fullscreen.width = gdk_window_get_width (window);
   impl->saved_fullscreen.height = gdk_window_get_height (window);
+    
   wl_shell_surface_set_fullscreen (impl->shell_surface,
                                    WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
                                    0,
@@ -1387,6 +1413,9 @@ gdk_wayland_window_unfullscreen (GdkWindow *window)
   if (!impl->fullscreen)
     return;
 
+  if (!impl->shell_surface)
+    return;
+
   wl_shell_surface_set_toplevel (impl->shell_surface);
   gdk_synthesize_window_state (window, GDK_WINDOW_STATE_FULLSCREEN, 0);
   gdk_wayland_window_configure (window,
@@ -1515,6 +1544,9 @@ gdk_wayland_window_begin_resize_drag (GdkWindow     *window,
 
   impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
 
+  if (!impl->shell_surface)
+    return;
+    
   wl_shell_surface_resize (impl->shell_surface,
                            gdk_wayland_device_get_wl_seat (device),
                            _gdk_wayland_display_get_serial (wayland_display),
@@ -1544,6 +1576,9 @@ gdk_wayland_window_begin_move_drag (GdkWindow *window,
 
   impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
 
+  if (!impl->shell_surface)
+    return;
+
   wl_shell_surface_move (impl->shell_surface,
                          gdk_wayland_device_get_wl_seat (device),
                          _gdk_wayland_display_get_serial (wayland_display));
@@ -1813,3 +1848,69 @@ gdk_wayland_window_get_wl_shell_surface (GdkWindow *window)
 
   return impl->shell_surface;
 }
+
+/**
+ * gdk_wayland_window_set_use_custom_surface:
+ * @window: (type GdkWaylandWindow): a #GdkWindow
+ *
+ * Marks a #GdkWindow as a custom Wayland surface. The application is
+ * expected to register the surface as some type of surface using
+ * some Wayland interface.
+ *
+ * Agood example would be writing a panel or on-screen-keyboard as an
+ * out-of-process helper - as opposed to having those in the compositor
+ * process. In this case the underlying surface isn't a wl_shell
+ * surface and the panel or OSK client need to identify the wl_surface
+ * as a panel or OSK to the compositor. The assumption is that the
+ * compositor will expose a private interface to the special client
+ * that lets the client identify the wl_surface as a panel or such.
+ *
+ * This function should be called before a #GdkWindow is shown. This is
+ * best done by connecting to the #GtkWidget::realized signal:
+ *
+ * <informalexample>
+ * <programlisting>
+ *   static void
+ *   widget_realize_cb (GtkWidget *widget)
+ *   {
+ *     GdkWindow *window;
+ *     struct wl_surface *surface;
+ *     struct input_panel_surface *ip_surface;
+ *
+ *     window = gtk_widget_get_window (widget);
+ *     gdk_wayland_window_set_custom_surface (window);
+ *
+ *     surface = gdk_wayland_window_get_wl_surface (window);
+ *     ip_surface = input_panel_get_input_panel_surface (input_panel, surface);
+ *     input_panel_surface_set_panel (ip_surface);
+ *   }
+ *
+ *   static void
+ *   setup_window (GtkWindow *window)
+ *   {
+ *     g_signal_connect (window, "realize", G_CALLBACK (widget_realize_cb), NULL);
+ *   }
+ * </programlisting>
+ * </informalexample>
+ *
+ * Since: 3.10
+ */
+void
+gdk_wayland_window_set_use_custom_surface (GdkWindow *window)
+{
+  GdkWindowImplWayland *impl;
+  GdkWaylandDisplay *display;
+
+  g_return_if_fail (GDK_IS_WAYLAND_WINDOW (window));
+
+  impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
+
+  if (!impl->surface)
+    {
+      display = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
+      impl->surface = wl_compositor_create_surface (display->compositor);
+      wl_surface_set_user_data (impl->surface, window);
+    }
+
+  impl->use_custom_surface = TRUE;
+}


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