summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLionel Landwerlin <llandwerlin@gmail.com>2015-08-31 22:58:11 +0100
committerLionel Landwerlin <llandwerlin@gmail.com>2015-09-07 18:17:10 +0100
commit9432e67ee8f5884d883b6ce1e3ac3e84dcd7cd22 (patch)
treeadae8d27f746276a52fbe78056f1599b7c7a0add
parent3771ef2f08054770ebc6110de14efd8fa2de3a26 (diff)
downloadclutter-9432e67ee8f5884d883b6ce1e3ac3e84dcd7cd22.tar.gz
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
-rw-r--r--clutter/gdk/clutter-event-gdk.c9
-rw-r--r--clutter/gdk/clutter-stage-gdk.c143
-rw-r--r--clutter/gdk/clutter-stage-gdk.h12
3 files changed, 154 insertions, 10 deletions
diff --git a/clutter/gdk/clutter-event-gdk.c b/clutter/gdk/clutter-event-gdk.c
index 9433418a2..a438f2f16 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 953c2b7bb..ea4f05200 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 721a7aafa..effc3098c 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);