[clutter] gdk: stage: create subsurface when dealing with foreign windows on wayland



commit 9432e67ee8f5884d883b6ce1e3ac3e84dcd7cd22
Author: Lionel Landwerlin <llandwerlin gmail com>
Date:   Mon Aug 31 22:58:11 2015 +0100

    gdk: stage: create subsurface when dealing with foreign windows on wayland
    
    It is safer to create our own wayland surface when rendering into
    someone else GdkWindow, otherwise we might draw somewhere we didn't
    intend to.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=754697

 clutter/gdk/clutter-event-gdk.c |    9 +++
 clutter/gdk/clutter-stage-gdk.c |  143 ++++++++++++++++++++++++++++++++++++---
 clutter/gdk/clutter-stage-gdk.h |   12 +++
 3 files changed, 154 insertions(+), 10 deletions(-)
---
diff --git a/clutter/gdk/clutter-event-gdk.c b/clutter/gdk/clutter-event-gdk.c
index 9433418..a438f2f 100644
--- a/clutter/gdk/clutter-event-gdk.c
+++ b/clutter/gdk/clutter-event-gdk.c
@@ -30,6 +30,7 @@
 #include "clutter-gdk.h"
 #include "clutter-backend-gdk.h"
 #include "clutter-device-manager-gdk.h"
+#include "clutter-stage-gdk.h"
 
 #include "clutter-actor-private.h"
 #include "clutter-backend-private.h"
@@ -272,6 +273,14 @@ clutter_gdk_handle_event (GdkEvent *gdk_event)
 
         clutter_actor_get_size (CLUTTER_ACTOR (stage), &w, &h);
 
+        /* Notify gdk stage backend of the new position. This is used
+           by foreign stages to reposition themselves on wayland. */
+        _clutter_stage_gdk_notify_configure (CLUTTER_STAGE_GDK (_clutter_stage_get_window (stage)),
+                                             gdk_event->configure.x,
+                                             gdk_event->configure.y,
+                                             gdk_event->configure.width,
+                                             gdk_event->configure.height);
+
         if ((int) w != gdk_event->configure.width ||
             (int) h != gdk_event->configure.height)
           {
diff --git a/clutter/gdk/clutter-stage-gdk.c b/clutter/gdk/clutter-stage-gdk.c
index 953c2b7..ea4f052 100644
--- a/clutter/gdk/clutter-stage-gdk.c
+++ b/clutter/gdk/clutter-stage-gdk.c
@@ -146,12 +146,6 @@ clutter_stage_gdk_resize (ClutterStageWindow *stage_window,
 {
   ClutterStageGdk *stage_gdk = CLUTTER_STAGE_GDK (stage_window);
 
-  /* No need to resize foreign windows, it should be handled by the
-   * embedding framework.
-   */
-  if (stage_gdk->foreign_window)
-    return;
-
   if (width == 0 || height == 0)
     {
       /* Should not happen, if this turns up we need to debug it and
@@ -164,7 +158,17 @@ clutter_stage_gdk_resize (ClutterStageWindow *stage_window,
 
   CLUTTER_NOTE (BACKEND, "New size received: (%d, %d)", width, height);
 
-  gdk_window_resize (stage_gdk->window, width, height);
+  /* No need to resize foreign windows, it should be handled by the
+   * embedding framework, but on wayland we might need to resize our
+   * own subsurface.
+   */
+  if (!stage_gdk->foreign_window)
+    gdk_window_resize (stage_gdk->window, width, height);
+#if defined(GDK_WINDOWING_WAYLAND)
+  else if (GDK_IS_WAYLAND_WINDOW (stage_gdk->window))
+    cogl_wayland_onscreen_resize (CLUTTER_STAGE_COGL (stage_gdk)->onscreen,
+                                  width, height, 0, 0);
+#endif
 }
 
 static void
@@ -185,7 +189,79 @@ clutter_stage_gdk_unrealize (ClutterStageWindow *stage_window)
       stage_gdk->window = NULL;
     }
 
-  return clutter_stage_window_parent_iface->unrealize (stage_window);
+  clutter_stage_window_parent_iface->unrealize (stage_window);
+
+#if defined(GDK_WINDOWING_WAYLAND)
+  g_clear_pointer (&stage_gdk->subsurface, wl_subsurface_destroy);
+  g_clear_pointer (&stage_gdk->clutter_surface, wl_surface_destroy);
+#endif
+}
+
+#if defined(GDK_WINDOWING_WAYLAND)
+static struct wl_surface *
+clutter_stage_gdk_wayland_surface (ClutterStageGdk *stage_gdk)
+{
+  GdkDisplay *display;
+  struct wl_compositor *compositor;
+  struct wl_surface *parent_surface;
+  struct wl_region *input_region;
+  gint x, y;
+
+  if (!stage_gdk->foreign_window ||
+      gdk_window_get_window_type (stage_gdk->window) != GDK_WINDOW_CHILD)
+    return gdk_wayland_window_get_wl_surface (stage_gdk->window);
+
+  if (stage_gdk->clutter_surface)
+    return stage_gdk->clutter_surface;
+
+  /* On Wayland if we render to a foreign window, we setup our own
+   * surface to not render in the same buffers as the embedding
+   * framework.
+   */
+  display = gdk_display_get_default ();
+  compositor = gdk_wayland_display_get_wl_compositor (display);
+  stage_gdk->clutter_surface = wl_compositor_create_surface (compositor);
+
+  /* Since we run inside GDK, we can let the embedding framework
+   * dispatch the events to Clutter. For that to happen we need to
+   * disable input on our surface. */
+  input_region = wl_compositor_create_region (compositor);
+  wl_region_add (input_region, 0, 0, 0, 0);
+  wl_surface_set_input_region (stage_gdk->clutter_surface, input_region);
+  wl_region_destroy (input_region);
+
+  parent_surface = gdk_wayland_window_get_wl_surface (gdk_window_get_toplevel (stage_gdk->window));
+  stage_gdk->subsurface = wl_subcompositor_get_subsurface (stage_gdk->subcompositor,
+                                                           stage_gdk->clutter_surface,
+                                                           parent_surface);
+
+  gdk_window_get_origin (stage_gdk->window, &x, &y);
+  wl_subsurface_set_position (stage_gdk->subsurface, x, y);
+  wl_subsurface_set_desync (stage_gdk->subsurface);
+
+  return stage_gdk->clutter_surface;
+}
+#endif
+
+void
+_clutter_stage_gdk_notify_configure (ClutterStageGdk *stage_gdk,
+                                     gint x,
+                                     gint y,
+                                     gint width,
+                                     gint height)
+{
+#if defined(GDK_WINDOWING_WAYLAND)
+  if (x < 0 || y < 0 || width < 1 || height < 1)
+    return;
+  if (stage_gdk->foreign_window &&
+      gdk_window_get_window_type (stage_gdk->window) == GDK_WINDOW_CHILD &&
+      stage_gdk->subsurface)
+    {
+      gint rx, ry;
+      gdk_window_get_origin (stage_gdk->window, &rx, &ry);
+      wl_subsurface_set_position (stage_gdk->subsurface, rx, ry);
+    }
+#endif
 }
 
 static gboolean
@@ -320,7 +396,7 @@ clutter_stage_gdk_realize (ClutterStageWindow *stage_window)
   if (GDK_IS_WAYLAND_WINDOW (stage_gdk->window))
     {
       cogl_wayland_onscreen_set_foreign_surface (stage_cogl->onscreen,
-                                                 gdk_wayland_window_get_wl_surface (stage_gdk->window));
+                                                 clutter_stage_gdk_wayland_surface (stage_gdk));
     }
   else
 #endif
@@ -580,10 +656,57 @@ clutter_stage_gdk_class_init (ClutterStageGdkClass *klass)
   gobject_class->dispose = clutter_stage_gdk_dispose;
 }
 
+#if defined(GDK_WINDOWING_WAYLAND)
+static void
+registry_handle_global (void *data,
+                        struct wl_registry *registry,
+                        uint32_t name,
+                        const char *interface,
+                        uint32_t version)
+{
+  ClutterStageGdk *stage_gdk = data;
+
+  if (strcmp (interface, "wl_subcompositor") == 0)
+    {
+      stage_gdk->subcompositor = wl_registry_bind (registry,
+                                                   name,
+                                                   &wl_subcompositor_interface,
+                                                   1);
+    }
+}
+
+static void
+registry_handle_global_remove (void *data,
+                               struct wl_registry *registry,
+                               uint32_t name)
+{
+}
+
+static const struct wl_registry_listener registry_listener = {
+  registry_handle_global,
+  registry_handle_global_remove
+};
+#endif
+
 static void
 clutter_stage_gdk_init (ClutterStageGdk *stage)
 {
-  /* nothing to do here */
+#if defined(GDK_WINDOWING_WAYLAND)
+  {
+    GdkDisplay *gdk_display = gdk_display_get_default ();
+    if (GDK_IS_WAYLAND_DISPLAY (gdk_display))
+      {
+        struct wl_display *display;
+        struct wl_registry *registry;
+
+        display = gdk_wayland_display_get_wl_display (gdk_display);
+        registry = wl_display_get_registry (display);
+        wl_registry_add_listener (registry, &registry_listener, stage);
+
+        wl_display_roundtrip (display);
+      }
+  }
+#endif
 }
 
 static void
diff --git a/clutter/gdk/clutter-stage-gdk.h b/clutter/gdk/clutter-stage-gdk.h
index 721a7aa..effc309 100644
--- a/clutter/gdk/clutter-stage-gdk.h
+++ b/clutter/gdk/clutter-stage-gdk.h
@@ -50,6 +50,12 @@ struct _ClutterStageGdk
   GdkCursor *blank_cursor;
 
   gboolean foreign_window;
+
+#if defined(GDK_WINDOWING_WAYLAND)
+  struct wl_subcompositor *subcompositor;
+  struct wl_surface *clutter_surface;
+  struct wl_subsurface *subsurface;
+#endif
 };
 
 struct _ClutterStageGdkClass
@@ -74,6 +80,12 @@ struct _ClutterStageGdkClass
 
 GType _clutter_stage_gdk_get_type (void) G_GNUC_CONST;
 
+void _clutter_stage_gdk_notify_configure (ClutterStageGdk *stage_gdk,
+                                          gint x,
+                                          gint y,
+                                          gint width,
+                                          gint height);
+
 void _clutter_stage_gdk_update_foreign_event_mask (CoglOnscreen *onscreen,
                                                   guint32 event_mask,
                                                   void *user_data);


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