Rework the interaction between the Cogl and GDK / X11 backends.

Previously, the Cogl backend was at times a subclass of the X11
backend, and at times a standalone one. Now it is the other way
round, with GDK and X11 backends providing the concrete classes,
layered on top of the generic Cogl backend. A new EglNative backend
was introduced for direct to framebuffer rendering. This greatly
simplifies the API design (at the expense of some casts needed)
and reduces the amount of #ifdefs, without duplicating code.

https://bugzilla.gnome.org/show_bug.cgi?id=657434
This commit is contained in:
Giovanni Campagna
2011-08-27 00:16:12 +02:00
committed by Emmanuele Bassi
parent 610a9c17ba
commit 9c102b7c51
21 changed files with 996 additions and 813 deletions

View File

@ -35,10 +35,16 @@
#include <gdk/gdk.h>
#include <cogl/cogl.h>
#include <cogl/cogl-xlib.h>
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#endif
/* other backends not yet supported */
#ifdef GDK_WINDOWING_WIN32
#include <gdk/gdkwin32.h>
#endif
#include "clutter-backend-gdk.h"
#include "clutter-device-manager-gdk.h"
@ -54,10 +60,7 @@
#include "clutter-private.h"
#define clutter_backend_gdk_get_type _clutter_backend_gdk_get_type
G_DEFINE_TYPE (ClutterBackendGdk, clutter_backend_gdk, CLUTTER_TYPE_BACKEND);
/* singleton object */
static ClutterBackendGdk *backend_singleton = NULL;
G_DEFINE_TYPE (ClutterBackendGdk, clutter_backend_gdk, CLUTTER_TYPE_BACKEND_COGL);
/* global for pre init setup calls */
static GdkDisplay *_foreign_dpy = NULL;
@ -131,21 +134,13 @@ cogl_gdk_filter (GdkXEvent *xevent,
#endif
}
static gboolean
_clutter_backend_gdk_pre_parse (ClutterBackend *backend,
GError **error)
{
/* nothing to do here */
return TRUE;
}
static gboolean
_clutter_backend_gdk_post_parse (ClutterBackend *backend,
GError **error)
{
ClutterBackendGdk *backend_gdk = CLUTTER_BACKEND_GDK (backend);
if (_foreign_dpy)
if (_foreign_dpy != NULL)
backend_gdk->display = _foreign_dpy;
/* Init Gdk, if outside code did not already */
@ -181,7 +176,8 @@ _clutter_backend_gdk_post_parse (ClutterBackend *backend,
"Gdk Display '%s' opened",
gdk_display_get_name (backend_gdk->display));
return TRUE;
return CLUTTER_BACKEND_CLASS (clutter_backend_gdk_parent_class)->post_parse (backend,
error);
}
@ -201,9 +197,6 @@ clutter_backend_gdk_finalize (GObject *gobject)
gdk_window_remove_filter (NULL, cogl_gdk_filter, NULL);
g_object_unref (backend_gdk->display);
if (backend_singleton)
backend_singleton = NULL;
G_OBJECT_CLASS (clutter_backend_gdk_parent_class)->finalize (gobject);
}
@ -224,34 +217,14 @@ clutter_backend_gdk_dispose (GObject *gobject)
G_OBJECT_CLASS (clutter_backend_gdk_parent_class)->dispose (gobject);
}
static GObject *
clutter_backend_gdk_constructor (GType gtype,
guint n_params,
GObjectConstructParam *params)
{
GObjectClass *parent_class;
GObject *retval;
if (backend_singleton == NULL)
{
parent_class = G_OBJECT_CLASS (clutter_backend_gdk_parent_class);
retval = parent_class->constructor (gtype, n_params, params);
backend_singleton = CLUTTER_BACKEND_GDK (retval);
return retval;
}
g_critical ("Attempting to create a new backend object. This should "
"never happen, so we return the singleton instance.");
return g_object_ref (backend_singleton);
}
static ClutterFeatureFlags
clutter_backend_gdk_get_features (ClutterBackend *backend)
{
return CLUTTER_FEATURE_STAGE_USER_RESIZE | CLUTTER_FEATURE_STAGE_CURSOR;
ClutterFeatureFlags flags = CLUTTER_FEATURE_STAGE_USER_RESIZE | CLUTTER_FEATURE_STAGE_CURSOR;
flags |= CLUTTER_BACKEND_CLASS (clutter_backend_gdk_parent_class)->get_features (backend);
return flags;
}
static void
@ -293,23 +266,128 @@ clutter_backend_gdk_get_device_manager (ClutterBackend *backend)
return backend_gdk->device_manager;
}
static gboolean
clutter_backend_gdk_create_context (ClutterBackend *backend,
GError **error)
{
ClutterBackendGdk *backend_gdk = CLUTTER_BACKEND_GDK (backend);
CoglSwapChain *swap_chain = NULL;
CoglOnscreenTemplate *onscreen_template = NULL;
GdkVisual *rgba_visual = NULL;
if (backend->cogl_context != NULL)
return TRUE;
backend->cogl_renderer = cogl_renderer_new ();
#if defined(GDK_WINDOWING_X11) && defined(COGL_HAS_XLIB_SUPPORT)
if (GDK_IS_X11_DISPLAY (backend_gdk->display))
{
cogl_xlib_renderer_set_foreign_display (backend->cogl_renderer,
gdk_x11_display_get_xdisplay (backend_gdk->display));
}
else
#endif
#if defined(GDK_WINDOWING_WIN32)
if (GDK_IS_WIN32_DISPLAY (backend_gdk->display))
{
/* Force a WGL winsys on windows */
cogl_renderer_set_winsys_id (backend_cogl->cogl_renderer, COGL_WINSYS_ID_WGL);
}
else
#endif
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_BACKEND,
"Could not find a suitable CoglWinsys for"
"a GdkDisplay of type %s", G_OBJECT_TYPE_NAME (backend_gdk->display));
goto error;
}
if (!cogl_renderer_connect (backend->cogl_renderer, error))
goto error;
swap_chain = cogl_swap_chain_new ();
rgba_visual = gdk_screen_get_rgba_visual (backend_gdk->screen);
cogl_swap_chain_set_has_alpha (swap_chain, rgba_visual != NULL);
onscreen_template = cogl_onscreen_template_new (swap_chain);
cogl_object_unref (swap_chain);
/* XXX: I have some doubts that this is a good design.
* Conceptually should we be able to check an onscreen_template
* without more details about the CoglDisplay configuration?
*/
if (!cogl_renderer_check_onscreen_template (backend->cogl_renderer,
onscreen_template,
error))
goto error;
backend->cogl_display = cogl_display_new (backend->cogl_renderer,
onscreen_template);
cogl_object_unref (backend->cogl_renderer);
cogl_object_unref (onscreen_template);
if (!cogl_display_setup (backend->cogl_display, error))
goto error;
backend->cogl_context = cogl_context_new (backend->cogl_display, error);
if (backend->cogl_context == NULL)
goto error;
return TRUE;
error:
if (backend->cogl_display != NULL)
{
cogl_object_unref (backend->cogl_display);
backend->cogl_display = NULL;
}
if (onscreen_template != NULL)
cogl_object_unref (onscreen_template);
if (swap_chain != NULL)
cogl_object_unref (swap_chain);
if (backend->cogl_renderer != NULL)
{
cogl_object_unref (backend->cogl_renderer);
backend->cogl_renderer = NULL;
}
return FALSE;
}
static ClutterStageWindow *
clutter_backend_gdk_create_stage (ClutterBackend *backend,
ClutterStage *wrapper,
GError **error)
{
return g_object_new (CLUTTER_TYPE_STAGE_GDK,
"backend", backend,
"wrapper", wrapper,
NULL);
}
static void
clutter_backend_gdk_class_init (ClutterBackendGdkClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
gobject_class->constructor = clutter_backend_gdk_constructor;
gobject_class->dispose = clutter_backend_gdk_dispose;
gobject_class->finalize = clutter_backend_gdk_finalize;
backend_class->pre_parse = _clutter_backend_gdk_pre_parse;
backend_class->post_parse = _clutter_backend_gdk_post_parse;
backend_class->init_events = clutter_backend_gdk_init_events;
backend_class->get_features = clutter_backend_gdk_get_features;
backend_class->get_device_manager = clutter_backend_gdk_get_device_manager;
backend_class->copy_event_data = clutter_backend_gdk_copy_event_data;
backend_class->free_event_data = clutter_backend_gdk_free_event_data;
backend_class->create_context = clutter_backend_gdk_create_context;
backend_class->create_stage = clutter_backend_gdk_create_stage;
}
static void
@ -330,13 +408,15 @@ clutter_backend_gdk_init (ClutterBackendGdk *backend_gdk)
GdkDisplay *
clutter_gdk_get_default_display (void)
{
if (!backend_singleton)
ClutterBackend *backend = clutter_get_default_backend ();
if (!backend || !CLUTTER_IS_BACKEND_GDK (backend))
{
g_critical ("GDK backend has not been initialised");
return NULL;
}
return backend_singleton->display;
return CLUTTER_BACKEND_GDK (backend)->display;
}
/**
@ -366,3 +446,9 @@ clutter_gdk_set_display (GdkDisplay *display)
_foreign_dpy = g_object_ref (display);
}
GType
_clutter_backend_impl_get_type (void)
{
return _clutter_backend_gdk_get_type ();
}