summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);