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
This commit is contained in:
Lionel Landwerlin 2015-09-11 17:24:05 +02:00
parent cb4e88884b
commit 13dbb74c81
3 changed files with 52 additions and 2 deletions

View File

@ -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;
}
/**

View File

@ -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__ */

View File

@ -182,7 +182,26 @@ clutter_stage_gdk_unrealize (ClutterStageWindow *stage_window)
"clutter-stage-window", NULL);
if (stage_gdk->foreign_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);