[clutter] gdk: stage window: reset framebuffer on foreign window unrealize



commit 13dbb74c81bec861d3a135fb53966ae5562831a7
Author: Lionel Landwerlin <llandwerlin gmail com>
Date:   Fri Sep 11 17:24:05 2015 +0200

    gdk: stage window: reset framebuffer on foreign window unrealize
    
    Clutter still uses part of the deprecated stateful API of Cogl (in
    particulart cogl_set_framebuffer). It means Cogl can keep an internal
    reference to the onscreen object we rendered to. In the case of
    foreign window, we want to avoid this, as we don't know what's going
    to happen to that window.
    
    This change sets the current Cogl framebuffer to a dummy 1x1
    framebuffer if the current Cogl framebuffer is the one we're
    unrealizing.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=754890

 clutter/gdk/clutter-backend-gdk.c |   29 ++++++++++++++++++++++++++++-
 clutter/gdk/clutter-backend-gdk.h |    4 ++++
 clutter/gdk/clutter-stage-gdk.c   |   21 ++++++++++++++++++++-
 3 files changed, 52 insertions(+), 2 deletions(-)
---
diff --git a/clutter/gdk/clutter-backend-gdk.c b/clutter/gdk/clutter-backend-gdk.c
index a464e68..fab7bf0 100644
--- a/clutter/gdk/clutter-backend-gdk.c
+++ b/clutter/gdk/clutter-backend-gdk.c
@@ -23,6 +23,8 @@
 #include "config.h"
 #endif
 
+#define CLUTTER_ENABLE_EXPERIMENTAL_API
+
 #include <glib/gi18n-lib.h>
 
 #include <string.h>
@@ -83,6 +85,29 @@ static GdkDisplay  *_foreign_dpy = NULL;
 
 static gboolean disable_event_retrieval = FALSE;
 
+void
+_clutter_backend_gdk_reset_framebuffer (ClutterBackendGdk *backend_gdk)
+{
+  if (backend_gdk->dummy_onscreen == COGL_INVALID_HANDLE)
+    {
+      CoglContext *context =
+        clutter_backend_get_cogl_context (CLUTTER_BACKEND (backend_gdk));
+      CoglError *internal_error = NULL;
+
+      backend_gdk->dummy_onscreen = cogl_onscreen_new (context, 1, 1);
+
+      if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (backend_gdk->dummy_onscreen),
+                                      &internal_error))
+        {
+          g_error ("Unable to create dummy onscreen: %s", internal_error->message);
+          cogl_error_free (internal_error);
+          return;
+        }
+    }
+
+  cogl_set_framebuffer (COGL_FRAMEBUFFER (backend_gdk->dummy_onscreen));
+}
+
 static void
 clutter_backend_gdk_init_settings (ClutterBackendGdk *backend_gdk)
 {
@@ -226,6 +251,8 @@ clutter_backend_gdk_finalize (GObject *gobject)
 {
   ClutterBackendGdk *backend_gdk = CLUTTER_BACKEND_GDK (gobject);
 
+  g_clear_pointer (&backend_gdk->dummy_onscreen, cogl_object_unref);
+
   gdk_window_remove_filter (NULL, cogl_gdk_filter, backend_gdk);
   g_object_unref (backend_gdk->display);
 
@@ -413,7 +440,7 @@ clutter_backend_gdk_class_init (ClutterBackendGdkClass *klass)
 static void
 clutter_backend_gdk_init (ClutterBackendGdk *backend_gdk)
 {
-  /* nothing to do here */
+  backend_gdk->dummy_onscreen = COGL_INVALID_HANDLE;
 }
 
 /**
diff --git a/clutter/gdk/clutter-backend-gdk.h b/clutter/gdk/clutter-backend-gdk.h
index fb54113..7f23459 100644
--- a/clutter/gdk/clutter-backend-gdk.h
+++ b/clutter/gdk/clutter-backend-gdk.h
@@ -50,6 +50,8 @@ struct _ClutterBackendGdk
   GdkDisplay *display;
   GdkScreen  *screen;
 
+  CoglOnscreen *dummy_onscreen;
+
   ClutterDeviceManager *device_manager;
 };
 
@@ -67,6 +69,8 @@ void   _clutter_backend_gdk_events_init (ClutterBackend *backend);
 void   _clutter_backend_gdk_update_setting (ClutterBackendGdk *backend,
                                             const gchar *name);
 
+void   _clutter_backend_gdk_reset_framebuffer (ClutterBackendGdk *backend);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_BACKEND_GDK_H__ */
diff --git a/clutter/gdk/clutter-stage-gdk.c b/clutter/gdk/clutter-stage-gdk.c
index 5cf3947..7152b11 100644
--- a/clutter/gdk/clutter-stage-gdk.c
+++ b/clutter/gdk/clutter-stage-gdk.c
@@ -182,7 +182,26 @@ clutter_stage_gdk_unrealize (ClutterStageWindow *stage_window)
                         "clutter-stage-window", NULL);
 
       if (stage_gdk->foreign_window)
-       g_object_unref (stage_gdk->window);
+        {
+          ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
+          ClutterBackendGdk *backend_gdk = CLUTTER_BACKEND_GDK (stage_cogl->backend);
+
+          g_object_unref (stage_gdk->window);
+
+          /* Clutter still uses part of the deprecated stateful API of
+           * Cogl (in particulart cogl_set_framebuffer). It means Cogl
+           * can keep an internal reference to the onscreen object we
+           * rendered to. In the case of foreign window, we want to
+           * avoid this, as we don't know what's going to happen to
+           * that window.
+           *
+           * The following call sets the current Cogl framebuffer to a
+           * dummy 1x1 one if we're unrealizing the current one, so
+           * Cogl doesn't keep any reference to the foreign window.
+           */
+          if (cogl_get_draw_framebuffer () == COGL_FRAMEBUFFER (stage_cogl->onscreen))
+            _clutter_backend_gdk_reset_framebuffer (backend_gdk);
+        }
       else
        gdk_window_destroy (stage_gdk->window);
 


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