summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLionel Landwerlin <llandwerlin@gmail.com>2015-08-26 22:41:24 +0100
committerLionel Landwerlin <llandwerlin@gmail.com>2015-09-12 00:51:51 +0200
commitf53e60361a1cb37b6653ca6bf4fc77d4baa2d73d (patch)
treefd056b6bb2bca3bb9bb5d7f7ec7ba23be4825aba
parent2a7e58a8b9f92bd5e23c71f8fb87c545c951bc72 (diff)
downloadclutter-gtk-f53e60361a1cb37b6653ca6bf4fc77d4baa2d73d.tar.gz
embed: rework foreign stage setup to work on gdk/wayland
On hide/unmap the GDK wayland backend might decide to destroy its wayland surface [1]. There is no event notifying Clutter/Cogl of this. We need to notify Clutter/Cogl that the surface has changed when the embed widget becomes visible/invisible. So instead of mapping the different mapped/visible/realized properties of the GtkWidget to the ClutterStage, we take a different approach by considering that an invisible GtkWidget means an unrealized ClutterStage. [1] : https://git.gnome.org/browse/gtk+/commit/?id=87e2a7d4b23e633d0f2263d6ebd205c113eede0f https://bugzilla.gnome.org/show_bug.cgi?id=754891
-rw-r--r--clutter-gtk/gtk-clutter-embed.c296
-rw-r--r--configure.ac2
2 files changed, 182 insertions, 116 deletions
diff --git a/clutter-gtk/gtk-clutter-embed.c b/clutter-gtk/gtk-clutter-embed.c
index 64542bb..21050d0 100644
--- a/clutter-gtk/gtk-clutter-embed.c
+++ b/clutter-gtk/gtk-clutter-embed.c
@@ -158,11 +158,169 @@ gtk_clutter_embed_send_configure (GtkClutterEmbed *embed)
event->configure.y = allocation.y;
event->configure.width = allocation.width;
event->configure.height = allocation.height;
-
+
gtk_widget_event (widget, event);
gdk_event_free (event);
}
+#if defined(GDK_WINDOWING_WAYLAND) && defined(CLUTTER_WINDOWING_WAYLAND)
+static void
+get_window_position_relative_to_parent (GdkWindow *window,
+ GdkWindow *parent,
+ gint *x,
+ gint *y)
+{
+ gint lx, ly;
+
+ if (window == parent ||
+ gdk_window_get_window_type (window) == GDK_WINDOW_TOPLEVEL)
+ {
+ *x = 0;
+ *y = 0;
+ return;
+ }
+
+ get_window_position_relative_to_parent (gdk_window_get_parent (window),
+ parent,
+ &lx, &ly);
+ gdk_window_get_position (window, x, y);
+
+ *x += lx;
+ *y += ly;
+}
+
+static void
+gtk_clutter_embed_ensure_surface (GtkClutterEmbed *embed)
+{
+ GtkClutterEmbedPrivate *priv = embed->priv;
+
+ if (priv->subcompositor && !priv->clutter_surface)
+ {
+ GdkDisplay *display;
+ struct wl_compositor *compositor;
+
+ display = gtk_widget_get_display (GTK_WIDGET (embed));
+ compositor = gdk_wayland_display_get_wl_compositor (display);
+ priv->clutter_surface = wl_compositor_create_surface (compositor);
+ }
+}
+
+static void
+gtk_clutter_embed_ensure_subsurface (GtkClutterEmbed *embed)
+{
+ GtkClutterEmbedPrivate *priv;
+ GtkWidget *widget;
+ struct wl_surface *gtk_surface;
+ GdkWindow *window;
+ gint x, y;
+
+ widget = GTK_WIDGET (embed);
+ priv = embed->priv;
+
+ if (priv->subsurface)
+ return;
+
+ window = gtk_widget_get_window (widget);
+ gtk_surface = gdk_wayland_window_get_wl_surface (gdk_window_get_toplevel (window));
+ priv->subsurface =
+ wl_subcompositor_get_subsurface (priv->subcompositor,
+ priv->clutter_surface,
+ gtk_surface);
+
+ gdk_window_get_origin (window, &x, &y);
+ wl_subsurface_set_position (priv->subsurface, x, y);
+ wl_subsurface_set_desync (priv->subsurface);
+}
+#endif
+
+static void
+gtk_clutter_embed_ensure_stage_realized (GtkClutterEmbed *embed)
+{
+ GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (embed)->priv;
+
+ if (!gtk_widget_get_realized (GTK_WIDGET (embed)))
+ return;
+
+ if (!clutter_actor_is_realized (priv->stage))
+ {
+ GdkWindow *window = gtk_widget_get_window (GTK_WIDGET (embed));
+
+#if defined(CLUTTER_WINDOWING_GDK)
+ if (clutter_check_windowing_backend (CLUTTER_WINDOWING_GDK))
+ {
+ clutter_gdk_set_stage_foreign (CLUTTER_STAGE (priv->stage), window);
+ }
+ else
+#endif
+#if defined(GDK_WINDOWING_X11) && defined(CLUTTER_WINDOWING_X11)
+ if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11) &&
+ GDK_IS_X11_WINDOW (window))
+ {
+ clutter_x11_set_stage_foreign (CLUTTER_STAGE (priv->stage),
+ GDK_WINDOW_XID (window));
+ }
+ else
+#endif
+#if defined(GDK_WINDOWING_WIN32) && defined(CLUTTER_WINDOWING_WIN32)
+ if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WIN32) &&
+ GDK_IS_WIN32_WINDOW (window))
+ {
+ clutter_win32_set_stage_foreign (CLUTTER_STAGE (priv->stage),
+ GDK_WINDOW_HWND (window));
+ }
+ else
+#endif
+#if defined(GDK_WINDOWING_WAYLAND) && defined (CLUTTER_WINDOWING_WAYLAND)
+ if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WAYLAND))
+ {
+ gtk_clutter_embed_ensure_surface (embed);
+ clutter_wayland_stage_set_wl_surface (CLUTTER_STAGE (priv->stage),
+ priv->clutter_surface);
+ }
+ else
+#endif
+ {
+ g_warning ("No backend found!");
+ }
+
+ clutter_actor_realize (priv->stage);
+ }
+
+ /* A stage cannot really be unmapped because it is the top of
+ * Clutter's scene tree. So if the Gtk embedder is mapped, we
+ * translate this as visible for the ClutterStage. */
+ if (gtk_widget_get_mapped (GTK_WIDGET (embed)))
+ clutter_actor_show (priv->stage);
+
+ clutter_actor_queue_relayout (priv->stage);
+
+ gtk_clutter_embed_send_configure (embed);
+
+#if defined(GDK_WINDOWING_WAYLAND) && defined (CLUTTER_WINDOWING_WAYLAND)
+ if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WAYLAND))
+ gtk_clutter_embed_ensure_subsurface (embed);
+#endif
+}
+
+static void
+gtk_clutter_embed_stage_unrealize (GtkClutterEmbed *embed)
+{
+ GtkClutterEmbedPrivate *priv = embed->priv;
+
+#if defined(GDK_WINDOWING_WAYLAND) && defined(CLUTTER_WINDOWING_WAYLAND)
+ g_clear_pointer (&priv->subsurface, wl_subsurface_destroy);
+ g_clear_pointer (&priv->clutter_surface, wl_surface_destroy);
+#endif
+
+ /* gtk may emit an unmap signal after dispose, so it's possible we
+ * may have already disposed priv->stage. */
+ if (priv->stage != NULL)
+ {
+ clutter_actor_hide (priv->stage);
+ clutter_actor_unrealize (priv->stage);
+ }
+}
+
static void
on_stage_queue_redraw (ClutterStage *stage,
ClutterActor *origin,
@@ -221,23 +379,10 @@ gtk_clutter_embed_show (GtkWidget *widget)
{
GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (widget)->priv;
- if (gtk_widget_get_realized (widget) && priv->stage != NULL)
- clutter_actor_show (priv->stage);
GTK_WIDGET_CLASS (gtk_clutter_embed_parent_class)->show (widget);
-}
-
-static void
-gtk_clutter_embed_hide (GtkWidget *widget)
-{
- GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (widget)->priv;
-
- /* gtk emits a hide signal during dispose, so it's possible we may
- * have already disposed priv->stage. */
- if (priv->stage != NULL)
- clutter_actor_hide (priv->stage);
- GTK_WIDGET_CLASS (gtk_clutter_embed_parent_class)->hide (widget);
+ gtk_clutter_embed_ensure_stage_realized (GTK_CLUTTER_EMBED (widget));
}
static GdkWindow *
@@ -309,38 +454,6 @@ gtk_clutter_embed_draw (GtkWidget *widget, cairo_t *cr)
return GTK_WIDGET_CLASS (gtk_clutter_embed_parent_class)->draw (widget, cr);
}
-#if defined(GDK_WINDOWING_WAYLAND) && defined(CLUTTER_WINDOWING_WAYLAND)
-static void
-gtk_clutter_embed_ensure_subsurface (GtkClutterEmbed *embed)
-{
- GtkClutterEmbedPrivate *priv;
- GtkWidget *widget;
- struct wl_surface *gtk_surface;
- GtkAllocation allocation;
- GdkWindow *window;
- gint x, y;
-
- widget = GTK_WIDGET (embed);
- priv = embed->priv;
-
- if (priv->subsurface)
- return;
-
- gtk_widget_get_allocation (widget, &allocation);
- window = gtk_widget_get_window (widget);
- gtk_surface = gdk_wayland_window_get_wl_surface (gdk_window_get_toplevel(window));
-
- priv->subsurface =
- wl_subcompositor_get_subsurface (priv->subcompositor,
- priv->clutter_surface,
- gtk_surface);
-
- gdk_window_get_origin (gtk_widget_get_parent_window (widget), &x, &y);
- wl_subsurface_set_position (priv->subsurface, x + allocation.x, y + allocation.y);
- wl_subsurface_set_desync (priv->subsurface);
-}
-#endif
-
static void
gtk_clutter_embed_realize (GtkWidget *widget)
{
@@ -395,7 +508,7 @@ gtk_clutter_embed_realize (GtkWidget *widget)
attributes.visual = gtk_widget_get_visual (widget);
/* NOTE: GDK_MOTION_NOTIFY above should be safe as Clutter does its own
- * throttling.
+ * throttling.
*/
attributes.event_mask = gtk_widget_get_events (widget)
| GDK_EXPOSURE_MASK
@@ -429,19 +542,10 @@ gtk_clutter_embed_realize (GtkWidget *widget)
style_context = gtk_widget_get_style_context (widget);
gtk_style_context_set_background (style_context, window);
-#if defined(CLUTTER_WINDOWING_GDK)
- if (clutter_check_windowing_backend (CLUTTER_WINDOWING_GDK))
- {
- clutter_gdk_set_stage_foreign (CLUTTER_STAGE (priv->stage), window);
- }
- else
-#endif
#if defined(GDK_WINDOWING_X11) && defined(CLUTTER_WINDOWING_X11)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11) &&
GDK_IS_X11_WINDOW (window))
{
- clutter_x11_set_stage_foreign (CLUTTER_STAGE (priv->stage), GDK_WINDOW_XID (window));
-
if (num_filter == 0)
gdk_window_add_filter (NULL, gtk_clutter_filter_func, widget);
num_filter++;
@@ -452,40 +556,22 @@ gtk_clutter_embed_realize (GtkWidget *widget)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WIN32) &&
GDK_IS_WIN32_WINDOW (window))
{
- clutter_win32_set_stage_foreign (CLUTTER_STAGE (priv->stage), GDK_WINDOW_HWND (window));
-
if (num_filter == 0)
gdk_window_add_filter (NULL, gtk_clutter_filter_func, widget);
num_filter++;
}
+ else
#endif
-
-#if defined(GDK_WINDOWING_WAYLAND) && defined(CLUTTER_WINDOWING_WAYLAND)
- if (priv->subcompositor)
{
- GdkDisplay *display;
- struct wl_compositor *compositor;
-
- display = gtk_widget_get_display (widget);
- compositor = gdk_wayland_display_get_wl_compositor (display);
- priv->clutter_surface = wl_compositor_create_surface (compositor);
- clutter_wayland_stage_set_wl_surface (CLUTTER_STAGE (priv->stage),
- priv->clutter_surface);
+ /* Nothing to do. */
}
-#endif
-
- clutter_actor_realize (priv->stage);
-
- if (gtk_widget_get_visible (widget))
- clutter_actor_show (priv->stage);
-
- gtk_clutter_embed_send_configure (GTK_CLUTTER_EMBED (widget));
}
static void
gtk_clutter_embed_unrealize (GtkWidget *widget)
{
- GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (widget)->priv;
+ GtkClutterEmbed *embed = GTK_CLUTTER_EMBED (widget);
+ GtkClutterEmbedPrivate *priv = embed->priv;
if (num_filter > 0)
{
@@ -494,8 +580,7 @@ gtk_clutter_embed_unrealize (GtkWidget *widget)
gdk_window_remove_filter (NULL, gtk_clutter_filter_func, widget);
}
- if (priv->stage != NULL)
- clutter_actor_hide (priv->stage);
+ gtk_clutter_embed_stage_unrealize (embed);
GTK_WIDGET_CLASS (gtk_clutter_embed_parent_class)->unrealize (widget);
}
@@ -660,7 +745,8 @@ static gboolean
gtk_clutter_embed_map_event (GtkWidget *widget,
GdkEventAny *event)
{
- GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (widget)->priv;
+ GtkClutterEmbed *embed = GTK_CLUTTER_EMBED (widget);
+ GtkClutterEmbedPrivate *priv = embed->priv;
GtkWidgetClass *parent_class;
gboolean res = FALSE;
@@ -668,7 +754,7 @@ gtk_clutter_embed_map_event (GtkWidget *widget,
if (parent_class->map_event)
res = parent_class->map_event (widget, event);
- clutter_actor_map (priv->stage);
+ gtk_clutter_embed_ensure_stage_realized (embed);
clutter_actor_queue_redraw (priv->stage);
@@ -679,7 +765,8 @@ static gboolean
gtk_clutter_embed_unmap_event (GtkWidget *widget,
GdkEventAny *event)
{
- GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (widget)->priv;
+ GtkClutterEmbed *embed = GTK_CLUTTER_EMBED (widget);
+ GtkClutterEmbedPrivate *priv = embed->priv;
GtkWidgetClass *parent_class;
gboolean res = FALSE;
@@ -687,11 +774,7 @@ gtk_clutter_embed_unmap_event (GtkWidget *widget,
if (parent_class->unmap_event)
res = parent_class->unmap_event (widget, event);
- clutter_actor_unmap (priv->stage);
-
-#if defined(GDK_WINDOWING_WAYLAND) && defined(CLUTTER_WINDOWING_WAYLAND)
- g_clear_pointer (&priv->subsurface, wl_subsurface_destroy);
-#endif
+ gtk_clutter_embed_stage_unrealize (embed);
return res;
}
@@ -699,40 +782,24 @@ gtk_clutter_embed_unmap_event (GtkWidget *widget,
static void
gtk_clutter_embed_map (GtkWidget *widget)
{
- GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (widget)->priv;
+ GtkClutterEmbed *embed = GTK_CLUTTER_EMBED (widget);
+ GtkClutterEmbedPrivate *priv = embed->priv;
-#if defined(GDK_WINDOWING_WAYLAND) && defined(CLUTTER_WINDOWING_WAYLAND)
- {
- GdkDisplay *gdk_display = gtk_widget_get_display (widget);
-
- if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WAYLAND) &&
- GDK_IS_WAYLAND_DISPLAY (gdk_display))
- {
- gtk_clutter_embed_ensure_subsurface (GTK_CLUTTER_EMBED (widget));
- }
- }
-#endif
GTK_WIDGET_CLASS (gtk_clutter_embed_parent_class)->map (widget);
- clutter_actor_map (priv->stage);
+ gtk_clutter_embed_ensure_stage_realized (embed);
}
static void
gtk_clutter_embed_unmap (GtkWidget *widget)
{
- GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (widget)->priv;
+ GtkClutterEmbed *embed = GTK_CLUTTER_EMBED (widget);
+ GtkClutterEmbedPrivate *priv = embed->priv;
GTK_WIDGET_CLASS (gtk_clutter_embed_parent_class)->unmap (widget);
- /* gtk may emit an unmap signal after dispose, so it's possible we may
- * have already disposed priv->stage. */
- if (priv->stage != NULL)
- clutter_actor_unmap (priv->stage);
-
-#if defined(GDK_WINDOWING_WAYLAND) && defined(CLUTTER_WINDOWING_WAYLAND)
- g_clear_pointer (&priv->subsurface, wl_subsurface_destroy);
-#endif
+ gtk_clutter_embed_stage_unrealize (embed);
}
static gboolean
@@ -921,7 +988,7 @@ _gtk_clutter_embed_set_child_active (GtkClutterEmbed *embed,
gdk_offscreen_window_set_embedder (child_window,
NULL);
}
-
+
}
static void
@@ -1051,7 +1118,6 @@ gtk_clutter_embed_class_init (GtkClutterEmbedClass *klass)
widget_class->realize = gtk_clutter_embed_realize;
widget_class->unrealize = gtk_clutter_embed_unrealize;
widget_class->show = gtk_clutter_embed_show;
- widget_class->hide = gtk_clutter_embed_hide;
widget_class->map = gtk_clutter_embed_map;
widget_class->unmap = gtk_clutter_embed_unmap;
widget_class->map_event = gtk_clutter_embed_map_event;
@@ -1251,7 +1317,7 @@ gtk_clutter_embed_set_use_layout_size (GtkClutterEmbed *embed,
GtkClutterEmbedPrivate *priv = embed->priv;
g_return_if_fail (GTK_CLUTTER_IS_EMBED (embed));
-
+
use_layout_size = !!use_layout_size;
if (use_layout_size != priv->use_layout_size)
{
@@ -1278,6 +1344,6 @@ gtk_clutter_embed_get_honor_stage_size (GtkClutterEmbed *embed)
GtkClutterEmbedPrivate *priv = embed->priv;
g_return_val_if_fail (GTK_CLUTTER_IS_EMBED (embed), FALSE);
-
+
return priv->use_layout_size;
}
diff --git a/configure.ac b/configure.ac
index 7f2c21e..60eb29e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -82,7 +82,7 @@ AC_HEADER_STDC
AC_CHECK_LIBM
AC_SUBST(LIBM)
-m4_define([clutter_req_version], [1.22.3])
+m4_define([clutter_req_version], [1.23.7])
m4_define([gtk_req_version], [3.6.0])
PKG_CHECK_MODULES([CLUTTER_GTK_DEPS], [clutter-1.0 >= clutter_req_version gtk+-3.0 >= gtk_req_version])