2008-04-04 Emmanuele Bassi <ebassi@openedhand.com>

Bug #864 - Allow instantiating and subclassing of ClutterStage

	* clutter/Makefile.am: Add clutter-stage-window.[ch]

	* clutter/clutter-stage-manager.c:
	(_clutter_stage_manager_remove_stage): Do not warn if removing
	a stage we don't manage, as we might be invoked multiple times
	during a ClutterState dispose sequence.

	* clutter/clutter-actor.c:
	* clutter/clutter-backend.[ch]:
	* clutter/clutter-main.c:
	* clutter/clutter-private.h:
	* clutter/clutter-stage.[ch]: Make ClutterStage a proxy actor,
	with a private actor implementing the ClutterStageWindow
	interface for handling the per-backend realization, painting
	and unrealization, plus all the windowing system abstraction.

	* clutter/x11/clutter-event-x11.c:
	* clutter/x11/clutter-stage-x11.[ch]: Port the X11 backend
	to the new backend and stage API and semantics.

	* clutter/glx/clutter-backend-glx.c:
	* clutter/glx/clutter-stage-glx.c: Port the GLX backend to
	the new backend and stage API and semantics.

	* clutter/eglx/clutter-backend-egl.[ch]:
	* clutter/eglx/clutter-stage-egl.[ch]: Port the EGLX backend
	to the new backend and stage API and semantics (untested).

	* tests/test-multistage.c (on_button_press): Rename
	clutter_stage_create_new() to clutter_stage_new().
This commit is contained in:
Emmanuele Bassi 2008-04-04 15:02:11 +00:00
parent beb03b9750
commit f859135082
22 changed files with 1037 additions and 510 deletions

View File

@ -1,3 +1,38 @@
2008-04-04 Emmanuele Bassi <ebassi@openedhand.com>
Bug #864 - Allow instantiating and subclassing of ClutterStage
* clutter/Makefile.am: Add clutter-stage-window.[ch]
* clutter/clutter-stage-manager.c:
(_clutter_stage_manager_remove_stage): Do not warn if removing
a stage we don't manage, as we might be invoked multiple times
during a ClutterState dispose sequence.
* clutter/clutter-actor.c:
* clutter/clutter-backend.[ch]:
* clutter/clutter-main.c:
* clutter/clutter-private.h:
* clutter/clutter-stage.[ch]: Make ClutterStage a proxy actor,
with a private actor implementing the ClutterStageWindow
interface for handling the per-backend realization, painting
and unrealization, plus all the windowing system abstraction.
* clutter/x11/clutter-event-x11.c:
* clutter/x11/clutter-stage-x11.[ch]: Port the X11 backend
to the new backend and stage API and semantics.
* clutter/glx/clutter-backend-glx.c:
* clutter/glx/clutter-stage-glx.c: Port the GLX backend to
the new backend and stage API and semantics.
* clutter/eglx/clutter-backend-egl.[ch]:
* clutter/eglx/clutter-stage-egl.[ch]: Port the EGLX backend
to the new backend and stage API and semantics (untested).
* tests/test-multistage.c (on_button_press): Rename
clutter_stage_create_new() to clutter_stage_new().
2008-04-04 Neil Roberts <neil@o-hand.com>
Applied patch from bug #810.

View File

@ -162,6 +162,7 @@ source_c = \
clutter-shader.c \
clutter-stage.c \
clutter-stage-manager.c \
clutter-stage-window.c \
clutter-texture.c \
clutter-timeline.c \
clutter-timeout-pool.c \
@ -175,6 +176,7 @@ source_h_priv = \
clutter-private.h \
clutter-id-pool.h \
clutter-script-private.h \
clutter-stage-window.h \
$(NULL)
libclutter_@CLUTTER_FLAVOUR@_@CLUTTER_API_VERSION@_la_LIBADD = \

View File

@ -2447,7 +2447,7 @@ clutter_actor_queue_redraw (ClutterActor *self)
/* FIXME: should we check we're visible here? */
if ((stage = clutter_actor_get_stage (self)) != NULL)
clutter_stage_queue_redraw (CLUTTER_STAGE(stage));
clutter_stage_queue_redraw (CLUTTER_STAGE (stage));
}
/**

View File

@ -44,6 +44,7 @@
#include "clutter-fixed.h"
#include "clutter-backend.h"
#include "clutter-private.h"
#include "clutter-debug.h"
G_DEFINE_ABSTRACT_TYPE (ClutterBackend, clutter_backend, G_TYPE_OBJECT);
@ -138,8 +139,9 @@ _clutter_backend_post_parse (ClutterBackend *backend,
return TRUE;
}
ClutterActor*
ClutterActor *
_clutter_backend_create_stage (ClutterBackend *backend,
ClutterStage *wrapper,
GError **error)
{
ClutterMainContext *context;
@ -147,6 +149,7 @@ _clutter_backend_create_stage (ClutterBackend *backend,
ClutterActor *stage = NULL;
g_return_val_if_fail (CLUTTER_IS_BACKEND (backend), FALSE);
g_return_val_if_fail (CLUTTER_IS_STAGE (wrapper), FALSE);
context = clutter_context_get_default ();
@ -155,28 +158,30 @@ _clutter_backend_create_stage (ClutterBackend *backend,
klass = CLUTTER_BACKEND_GET_CLASS (backend);
if (klass->create_stage)
stage = klass->create_stage (backend, error);
stage = klass->create_stage (backend, wrapper, error);
if (!stage)
return NULL;
_clutter_stage_manager_add_stage (context->stage_manager,
CLUTTER_STAGE(stage));
_clutter_stage_manager_add_stage (context->stage_manager, wrapper);
return stage;
}
void
_clutter_backend_redraw (ClutterBackend *backend, ClutterStage *stage)
_clutter_backend_redraw (ClutterBackend *backend,
ClutterStage *stage)
{
ClutterBackendClass *klass;
klass = CLUTTER_BACKEND_GET_CLASS (backend);
if (G_LIKELY(klass->redraw))
if (G_LIKELY (klass->redraw))
klass->redraw (backend, stage);
}
void
_clutter_backend_ensure_context (ClutterBackend *backend, ClutterStage *stage)
_clutter_backend_ensure_context (ClutterBackend *backend,
ClutterStage *stage)
{
ClutterBackendClass *klass;
static ClutterStage *current_context_stage = NULL;
@ -184,13 +189,16 @@ _clutter_backend_ensure_context (ClutterBackend *backend, ClutterStage *stage)
g_return_if_fail (CLUTTER_IS_BACKEND (backend));
g_return_if_fail (CLUTTER_IS_STAGE (stage));
if (stage != current_context_stage || !CLUTTER_ACTOR_IS_REALIZED(stage))
if (stage != current_context_stage || !CLUTTER_ACTOR_IS_REALIZED (stage))
{
if (!CLUTTER_ACTOR_IS_REALIZED(stage))
if (!CLUTTER_ACTOR_IS_REALIZED (stage))
{
CLUTTER_NOTE (MULTISTAGE, "Stage is not realized");
stage = NULL;
}
klass = CLUTTER_BACKEND_GET_CLASS (backend);
if (G_LIKELY(klass->ensure_context))
if (G_LIKELY (klass->ensure_context))
klass->ensure_context (backend, stage);
/* FIXME: With a NULL stage and thus no active context it may make more

View File

@ -47,13 +47,14 @@ typedef struct _ClutterBackendClass ClutterBackendClass;
struct _ClutterBackend
{
/*< private >*/
GObject parent_instance;
ClutterBackendPrivate *priv;
};
struct _ClutterBackendClass
{
/*< private >*/
GObjectClass parent_class;
/* vfuncs */
@ -61,7 +62,8 @@ struct _ClutterBackendClass
GError **error);
gboolean (* post_parse) (ClutterBackend *backend,
GError **error);
ClutterActor *(* create_stage) (ClutterBackend *backend,
ClutterActor * (* create_stage) (ClutterBackend *backend,
ClutterStage *wrapper,
GError **error);
void (* init_events) (ClutterBackend *backend);
void (* init_features) (ClutterBackend *backend);

View File

@ -104,6 +104,28 @@ clutter_get_show_fps (void)
return clutter_show_fps;
}
static inline void
clutter_maybe_setup_viewport (ClutterStage *stage)
{
if (CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_SYNC_MATRICES)
{
ClutterPerspective perspective;
guint width, height;
clutter_actor_get_size (CLUTTER_ACTOR (stage), &width, &height);
clutter_stage_get_perspectivex (stage, &perspective);
CLUTTER_NOTE (PAINT, "Setting up the viewport");
cogl_setup_viewport (width, height,
perspective.fovy,
perspective.aspect,
perspective.z_near,
perspective.z_far);
CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
}
}
/**
* clutter_redraw:
@ -122,35 +144,21 @@ clutter_redraw (ClutterStage *stage)
CLUTTER_TIMESTAMP (SCHEDULER, "Redraw start for stage:%p", stage);
CLUTTER_NOTE (PAINT, " Redraw enter for stage:%p", stage);
CLUTTER_NOTE (MULTISTAGE, "redraw called for stage:%p", stage);
CLUTTER_NOTE (MULTISTAGE, "Redraw called for stage:%p", stage);
_clutter_backend_ensure_context (ctx->backend, stage);
/* Setup FPS count - not currently across *all* stages rather than per */
if (clutter_get_show_fps ())
if (G_UNLIKELY (clutter_get_show_fps ()))
{
if (!timer)
timer = g_timer_new ();
}
/* The below cant go in stage paint as base actor_paint will get
* called before the below (and break picking etc)
/* The code below can't go in stage paint as base actor_paint
* will get called before it (and break picking, etc)
*/
if (CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_SYNC_MATRICES)
{
ClutterPerspective perspective;
clutter_stage_get_perspectivex (CLUTTER_STAGE (stage), &perspective);
cogl_setup_viewport (clutter_actor_get_width (CLUTTER_ACTOR(stage)),
clutter_actor_get_height (CLUTTER_ACTOR(stage)),
perspective.fovy,
perspective.aspect,
perspective.z_near,
perspective.z_far);
CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
}
clutter_maybe_setup_viewport (stage);
/* Call through to the actual backend to do the painting down from
* the stage. It will likely need to swap buffers, vblank sync etc
@ -159,7 +167,7 @@ clutter_redraw (ClutterStage *stage)
_clutter_backend_redraw (ctx->backend, stage);
/* Complete FPS info */
if (clutter_get_show_fps ())
if (G_UNLIKELY (clutter_get_show_fps ()))
{
timer_n_frames++;
@ -234,24 +242,8 @@ _clutter_do_pick (ClutterStage *stage,
_clutter_backend_ensure_context (context->backend, stage);
/* FIXME: needed for when a context switch happens - probably
* should put into its own function somewhere..
*/
if (CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_SYNC_MATRICES)
{
ClutterPerspective perspective;
clutter_stage_get_perspectivex (CLUTTER_STAGE (stage), &perspective);
cogl_setup_viewport (clutter_actor_get_width (CLUTTER_ACTOR(stage)),
clutter_actor_get_height (CLUTTER_ACTOR(stage)),
perspective.fovy,
perspective.aspect,
perspective.z_near,
perspective.z_far);
CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
}
/* needed for when a context switch happens */
clutter_maybe_setup_viewport (stage);
cogl_paint_init (&white);
cogl_enable (0);
@ -276,7 +268,7 @@ _clutter_do_pick (ClutterStage *stage,
/* glEnable (GL_DITHER); we never enabled this originally, so its
probably not safe to then enable it */
glReadPixels(x, viewport[3] - y -1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
glReadPixels (x, viewport[3] - y -1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff)
return CLUTTER_ACTOR (stage);
@ -988,7 +980,6 @@ clutter_init_with_args (int *argc,
GOptionContext *context;
GOptionGroup *group;
gboolean res;
GError *stage_error;
ClutterActor *stage;
if (clutter_is_initialized)
@ -1018,13 +1009,13 @@ clutter_init_with_args (int *argc,
clutter_context = clutter_context_get_default ();
stage_error = NULL;
stage = _clutter_backend_create_stage (clutter_context->backend,
&stage_error);
stage = clutter_stage_get_default ();
if (!stage)
{
g_propagate_error (error, stage_error);
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_INTERNAL,
"Unable to create the default stage");
return CLUTTER_INIT_ERROR_INTERNAL;
}
@ -1032,8 +1023,7 @@ clutter_init_with_args (int *argc,
_clutter_feature_init ();
clutter_stage_set_title (CLUTTER_STAGE(clutter_stage_get_default()),
g_get_prgname ());
clutter_stage_set_title (CLUTTER_STAGE (stage), g_get_prgname ());
return CLUTTER_INIT_SUCCESS;
}
@ -1089,7 +1079,6 @@ clutter_init (int *argc,
{
ClutterMainContext *context;
ClutterActor *stage;
GError *stage_error;
if (clutter_is_initialized)
return CLUTTER_INIT_SUCCESS;
@ -1115,15 +1104,10 @@ clutter_init (int *argc,
context = clutter_context_get_default ();
/* Stage will give us a GL Context etc */
stage_error = NULL;
stage = _clutter_backend_create_stage (context->backend, &stage_error);
stage = clutter_stage_get_default ();
if (!stage)
{
CLUTTER_NOTE (MISC, "stage failed to initialise.");
g_critical (stage_error->message);
g_error_free (stage_error);
g_critical ("Unable to create the default stage");
return CLUTTER_INIT_ERROR_INTERNAL;
}
@ -1133,8 +1117,7 @@ clutter_init (int *argc,
/* finally features - will call to backend and cogl */
_clutter_feature_init ();
clutter_stage_set_title (CLUTTER_STAGE(clutter_stage_get_default()),
g_get_prgname());
clutter_stage_set_title (CLUTTER_STAGE (stage), g_get_prgname ());
return CLUTTER_INIT_SUCCESS;
}

View File

@ -40,12 +40,13 @@
#include <pango/pangoft2.h>
#include "clutter-stage-manager.h"
#include "clutter-event.h"
#include "clutter-backend.h"
#include "clutter-stage.h"
#include "clutter-event.h"
#include "clutter-feature.h"
#include "clutter-id-pool.h"
#include "clutter-stage-manager.h"
#include "clutter-stage-window.h"
#include "clutter-stage.h"
G_BEGIN_DECLS
@ -55,10 +56,11 @@ typedef enum {
CLUTTER_ACTOR_IN_DESTRUCTION = 1 << 0,
CLUTTER_ACTOR_IS_TOPLEVEL = 1 << 1,
CLUTTER_ACTOR_IN_REPARENT = 1 << 2,
CLUTTER_ACTOR_SYNC_MATRICES = 1 << 3 /* Used by stage to indicate GL
CLUTTER_ACTOR_SYNC_MATRICES = 1 << 3, /* Used by stage to indicate GL
* viewport / perspective etc
* needs (re)setting.
*/
CLUTTER_ACTOR_IN_PAINT = 1 << 4 /* Used to avoid recursion */
} ClutterPrivateFlags;
typedef enum {
@ -122,7 +124,6 @@ ClutterMainContext *clutter_context_get_default (void);
#define I_(str) (g_intern_static_string ((str)))
/* stage manager */
struct _ClutterStageManager
{
GObject parent_instance;
@ -135,17 +136,22 @@ void _clutter_stage_manager_add_stage (ClutterStageManager *stage_manager,
void _clutter_stage_manager_remove_stage (ClutterStageManager *stage_manager,
ClutterStage *stage);
/* vfuncs implemnted by backend */
/* stage */
void _clutter_stage_set_window (ClutterStage *stage,
ClutterStageWindow *stage_window);
ClutterStageWindow *_clutter_stage_get_window (ClutterStage *stage);
ClutterStageWindow *_clutter_stage_get_default_window (void);
/* vfuncs implemented by backend */
GType _clutter_backend_impl_get_type (void);
void _clutter_backend_redraw (ClutterBackend *backend,
ClutterStage *stage);
ClutterActor* _clutter_backend_create_stage (ClutterBackend *backend,
ClutterActor *_clutter_backend_create_stage (ClutterBackend *backend,
ClutterStage *wrapper,
GError **error);
void _clutter_backend_redraw (ClutterBackend *backend,
void _clutter_backend_ensure_context (ClutterBackend *backend,
ClutterStage *stage);
void _clutter_backend_add_options (ClutterBackend *backend,
@ -156,9 +162,6 @@ gboolean _clutter_backend_post_parse (ClutterBackend *backend,
GError **error);
void _clutter_backend_init_events (ClutterBackend *backend);
void _clutter_backend_ensure_context (ClutterBackend *backend,
ClutterStage *stage);
ClutterFeatureFlags _clutter_backend_get_features (ClutterBackend *backend);
void _clutter_feature_init (void);

View File

@ -267,12 +267,11 @@ void
_clutter_stage_manager_remove_stage (ClutterStageManager *stage_manager,
ClutterStage *stage)
{
/* this might be called multiple times from a ::dispose, so it
* needs to just return without warning
*/
if (!g_slist_find (stage_manager->stages, stage))
{
g_warning ("Trying to remove an unknown stage from the list "
"of managed stages, aborting.");
return;
}
stage_manager->stages = g_slist_remove (stage_manager->stages, stage);

View File

@ -0,0 +1,33 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <glib-object.h>
#include "clutter-actor.h"
#include "clutter-stage-window.h"
#include "clutter-private.h"
GType
clutter_stage_window_get_type (void)
{
static GType stage_window_type = 0;
if (G_UNLIKELY (stage_window_type == 0))
{
const GTypeInfo stage_window_info = {
sizeof (ClutterStageWindowIface),
NULL,
NULL,
};
stage_window_type =
g_type_register_static (G_TYPE_INTERFACE, I_("ClutterStageWindow"),
&stage_window_info, 0);
g_type_interface_add_prerequisite (stage_window_type,
CLUTTER_TYPE_ACTOR);
}
return stage_window_type;
}

View File

@ -0,0 +1,43 @@
#ifndef __CLUTTER_STAGE_WINDOW_H__
#define __CLUTTER_STAGE_WINDOW_H__
#include <clutter/clutter-actor.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_STAGE_WINDOW (clutter_stage_window_get_type ())
#define CLUTTER_STAGE_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE_WINDOW, ClutterStageWindow))
#define CLUTTER_IS_STAGE_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STAGE_WINDOW))
#define CLUTTER_STAGE_WINDOW_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), CLUTTER_TYPE_STAGE_WINDOW, ClutterStageWindowIface))
typedef struct _ClutterStageWindow ClutterStageWindow; /* dummy */
typedef struct _ClutterStageWindowIface ClutterStageWindowIface;
struct _ClutterStageWindowIface
{
GTypeInterface parent_iface;
ClutterActor *(* get_wrapper) (ClutterStageWindow *stage_window);
void (* set_title) (ClutterStageWindow *stage_window,
const gchar *title);
void (* set_fullscreen) (ClutterStageWindow *stage_window,
gboolean is_fullscreen);
void (* set_cursor_visible) (ClutterStageWindow *stage_window,
gboolean cursor_visible);
void (* set_user_resizable) (ClutterStageWindow *stage_window,
gboolean is_resizable);
GdkPixbuf * (* draw_to_pixbuf) (ClutterStageWindow *stage_window,
gint x,
gint y,
gint width,
gint height);
};
GType clutter_stage_window_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __CLUTTER_STAGE_WINDOW_H__ */

View File

@ -29,6 +29,24 @@
*
* #ClutterStage is a top level 'window' on which child actors are placed
* and manipulated.
*
* Clutter creates a default stage upon initialization, which can be retrieved
* using clutter_stage_get_default(). Clutter always provides the default
* stage, unless the backend is unable to create one. The stage returned
* by clutter_stage_get_default() is guaranteed to always be the same.
*
* Backends might provide support for multiple stages. The support for this
* feature can be checked at run-time using the clutter_feature_available()
* function and the %CLUTTER_FEATURE_STAGE_MULTIPLE flag. If the backend used
* supports multiple stages, new #ClutterStage instances can be created
* using clutter_stage_new(). These stages must be managed by the developer
* using clutter_actor_destroy(), which will take care of destroying all the
* actors contained inside them.
*
* #ClutterStage is a proxy actor, wrapping the backend-specific
* implementation of the windowing system. It is possible to subclass
* #ClutterStage, as long as every overridden virtual function chains up to
* the parent class corresponding function.
*/
#ifdef HAVE_CONFIG_H
@ -45,32 +63,36 @@
#include "clutter-private.h"
#include "clutter-debug.h"
#include "clutter-stage-manager.h"
#include "clutter-stage-window.h"
#include "clutter-version.h" /* For flavour */
#include "clutter-id-pool.h"
#include "cogl.h"
G_DEFINE_ABSTRACT_TYPE (ClutterStage, clutter_stage, CLUTTER_TYPE_GROUP);
G_DEFINE_TYPE (ClutterStage, clutter_stage, CLUTTER_TYPE_GROUP);
#define CLUTTER_STAGE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_STAGE, ClutterStagePrivate))
struct _ClutterStagePrivate
{
/* the stage implementation */
ClutterActor *impl;
ClutterColor color;
ClutterPerspective perspective;
ClutterFog fog;
gchar *title;
ClutterActor *key_focused_actor;
guint update_idle; /* repaint idler id */
guint is_fullscreen : 1;
guint is_offscreen : 1;
guint is_cursor_visible : 1;
guint is_user_resizable : 1;
guint use_fog : 1;
gchar *title;
ClutterActor *key_focused_actor;
guint update_idle; /* repaint idler id */
};
enum
@ -98,11 +120,37 @@ enum
static guint stage_signals[LAST_SIGNAL] = { 0, };
static void
clutter_stage_request_coords (ClutterActor *self,
ClutterActorBox *box)
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
g_assert (priv->impl != NULL);
CLUTTER_ACTOR_GET_CLASS (priv->impl)->request_coords (priv->impl, box);
CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->request_coords (self, box);
}
static void
clutter_stage_query_coords (ClutterActor *self,
ClutterActorBox *box)
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
g_assert (priv->impl != NULL);
CLUTTER_ACTOR_GET_CLASS (priv->impl)->query_coords (priv->impl, box);
}
static void
clutter_stage_paint (ClutterActor *self)
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_IN_PAINT);
CLUTTER_NOTE (PAINT, "Initializing stage paint");
cogl_paint_init (&priv->color);
if (priv->use_fog)
@ -113,6 +161,12 @@ clutter_stage_paint (ClutterActor *self)
priv->fog.z_far);
}
CLUTTER_NOTE (PAINT, "Proxying the paint to the stage implementation");
clutter_actor_paint (priv->impl);
CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_IN_PAINT);
/* this will take care of painting every child */
CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->paint (self);
}
@ -128,6 +182,53 @@ clutter_stage_pick (ClutterActor *self,
CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->paint (self);
}
static void
clutter_stage_realize (ClutterActor *self)
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
/* then realize the implementation */
CLUTTER_ACTOR_GET_CLASS (priv->impl)->realize (priv->impl);
/* set the flag on the wrapper if the implementation was successful */
if (CLUTTER_ACTOR_IS_REALIZED (priv->impl))
CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
}
static void
clutter_stage_unrealize (ClutterActor *self)
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
/* unset the flag */
CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
/* and then unrealize the implementation */
CLUTTER_ACTOR_GET_CLASS (priv->impl)->unrealize (priv->impl);
}
static void
clutter_stage_show (ClutterActor *self)
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
g_assert (priv->impl != NULL);
clutter_actor_show (priv->impl);
CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->show (self);
}
static void
clutter_stage_hide (ClutterActor *self)
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
g_assert (priv->impl != NULL);
clutter_actor_hide (priv->impl);
CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->hide (self);
}
static void
clutter_stage_set_property (GObject *object,
guint prop_id,
@ -248,6 +349,24 @@ clutter_stage_get_property (GObject *object,
static void
clutter_stage_dispose (GObject *object)
{
ClutterStage *stage = CLUTTER_STAGE (object);
ClutterStagePrivate *priv = stage->priv;
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
if (priv->update_idle)
{
g_source_remove (priv->update_idle);
priv->update_idle = 0;
}
_clutter_stage_manager_remove_stage (stage_manager, stage);
if (priv->impl)
{
CLUTTER_NOTE (MISC, "Disposing of the stage implementation");
g_object_unref (priv->impl);
priv->impl = NULL;
}
G_OBJECT_CLASS (clutter_stage_parent_class)->dispose (object);
}
@ -255,11 +374,6 @@ clutter_stage_dispose (GObject *object)
static void
clutter_stage_finalize (GObject *object)
{
ClutterStage *stage = CLUTTER_STAGE(object);
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
_clutter_stage_manager_remove_stage (stage_manager, stage);
G_OBJECT_CLASS (clutter_stage_parent_class)->finalize (object);
}
@ -275,8 +389,14 @@ clutter_stage_class_init (ClutterStageClass *klass)
gobject_class->dispose = clutter_stage_dispose;
gobject_class->finalize = clutter_stage_finalize;
actor_class->request_coords = clutter_stage_request_coords;
actor_class->query_coords = clutter_stage_query_coords;
actor_class->paint = clutter_stage_paint;
actor_class->pick = clutter_stage_pick;
actor_class->realize = clutter_stage_realize;
actor_class->unrealize = clutter_stage_unrealize;
actor_class->show = clutter_stage_show;
actor_class->hide = clutter_stage_hide;
/**
* ClutterStage:fullscreen:
@ -447,12 +567,28 @@ static void
clutter_stage_init (ClutterStage *self)
{
ClutterStagePrivate *priv;
ClutterBackend *backend;
/* a stage is a top-level object */
CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_IS_TOPLEVEL);
self->priv = priv = CLUTTER_STAGE_GET_PRIVATE (self);
CLUTTER_NOTE (BACKEND, "Creating stage from the default backend");
backend = clutter_get_default_backend ();
priv->impl = _clutter_backend_create_stage (backend, self, NULL);
if (!priv->impl)
{
g_warning ("Unable to create a new stage, falling back to the "
"default stage.");
priv->impl = CLUTTER_ACTOR (_clutter_stage_get_default_window ());
/* at this point we must have a default stage, or we're screwed */
g_assert (priv->impl != NULL);
}
else
g_object_ref_sink (priv->impl);
priv->is_offscreen = FALSE;
priv->is_fullscreen = FALSE;
priv->is_user_resizable = FALSE;
@ -482,11 +618,12 @@ clutter_stage_init (ClutterStage *self)
/**
* clutter_stage_get_default:
*
* Returns the main stage. #ClutterStage is a singleton, so
* the stage will be created the first time this function is
* Returns the main stage. The default #ClutterStage is a singleton,
* so the stage will be created the first time this function is
* called (typically, inside clutter_init()); all the subsequent
* calls to clutter_stage_get_default() will return the same
* instance.
* calls to clutter_stage_get_default() will return the same instance.
*
* Clutter guarantess the existence of the default stage.
*
* Return value: the main #ClutterStage. You should never
* destroy or unref the returned actor.
@ -495,8 +632,19 @@ ClutterActor *
clutter_stage_get_default (void)
{
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
ClutterStage *stage;
return CLUTTER_ACTOR(clutter_stage_manager_get_default_stage(stage_manager));
stage = clutter_stage_manager_get_default_stage (stage_manager);
if (G_UNLIKELY (stage == NULL))
{
/* this will take care of automatically adding the stage
* to the stage manager and setting it as the default
*/
stage = g_object_new (CLUTTER_TYPE_STAGE, NULL);
g_object_ref_sink (stage);
}
return CLUTTER_ACTOR (stage);
}
/**
@ -516,10 +664,8 @@ clutter_stage_set_color (ClutterStage *stage,
g_return_if_fail (color != NULL);
priv = stage->priv;
priv->color.red = color->red;
priv->color.green = color->green;
priv->color.blue = color->blue;
priv->color.alpha = color->alpha;
priv->color = *color;
if (CLUTTER_ACTOR_IS_VISIBLE (stage))
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
@ -545,10 +691,7 @@ clutter_stage_get_color (ClutterStage *stage,
priv = stage->priv;
color->red = priv->color.red;
color->green = priv->color.green;
color->blue = priv->color.blue;
color->alpha = priv->color.alpha;
*color = priv->color;
}
/**
@ -572,6 +715,9 @@ clutter_stage_set_perspectivex (ClutterStage *stage,
priv->perspective = *perspective;
/* this will cause the viewport to be reset; see
* clutter_maybe_setup_viewport() inside clutter-main.c
*/
CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
}
@ -604,7 +750,7 @@ clutter_stage_get_perspectivex (ClutterStage *stage,
* @z_far: the distance from the viewer to the far clipping
* plane (always positive)
*
* Set the stage perspective.
* Sets the stage perspective.
*
* Since: 0.4
*/
@ -621,11 +767,14 @@ clutter_stage_set_perspective (ClutterStage *stage,
priv = stage->priv;
priv->perspective.fovy = CLUTTER_FLOAT_TO_FIXED(fovy);
priv->perspective.aspect = CLUTTER_FLOAT_TO_FIXED(aspect);
priv->perspective.z_near = CLUTTER_FLOAT_TO_FIXED(z_near);
priv->perspective.z_far = CLUTTER_FLOAT_TO_FIXED(z_far);
priv->perspective.fovy = CLUTTER_FLOAT_TO_FIXED (fovy);
priv->perspective.aspect = CLUTTER_FLOAT_TO_FIXED (aspect);
priv->perspective.z_near = CLUTTER_FLOAT_TO_FIXED (z_near);
priv->perspective.z_far = CLUTTER_FLOAT_TO_FIXED (z_far);
/* this will cause the viewport to be reset; see
* clutter_maybe_setup_viewport() inside clutter-main.c
*/
CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
}
@ -688,12 +837,17 @@ clutter_stage_fullscreen (ClutterStage *stage)
priv = stage->priv;
if (!priv->is_fullscreen)
{
ClutterStageWindow *impl = CLUTTER_STAGE_WINDOW (priv->impl);
ClutterStageWindowIface *iface;
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (impl);
/* Only set if backend implements.
* Also see clutter_stage_event() for setting priv->is_fullscreen
* on state change event.
*/
if (CLUTTER_STAGE_GET_CLASS (stage)->set_fullscreen)
CLUTTER_STAGE_GET_CLASS (stage)->set_fullscreen (stage, TRUE);
if (iface->set_fullscreen)
iface->set_fullscreen (impl, TRUE);
}
}
@ -717,9 +871,17 @@ clutter_stage_unfullscreen (ClutterStage *stage)
priv = stage->priv;
if (priv->is_fullscreen)
{
/* Only set if backend implements */
if (CLUTTER_STAGE_GET_CLASS (stage)->set_fullscreen)
CLUTTER_STAGE_GET_CLASS (stage)->set_fullscreen (stage, FALSE);
ClutterStageWindow *impl = CLUTTER_STAGE_WINDOW (priv->impl);
ClutterStageWindowIface *iface;
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (impl);
/* Only set if backend implements.
* Also see clutter_stage_event() for setting priv->is_fullscreen
* on state change event.
*/
if (iface->set_fullscreen)
iface->set_fullscreen (impl, FALSE);
}
}
@ -744,15 +906,21 @@ clutter_stage_set_user_resizable (ClutterStage *stage,
priv = stage->priv;
if (clutter_feature_available (CLUTTER_FEATURE_STAGE_USER_RESIZE)
&& priv->is_user_resizable != resizable
&& CLUTTER_STAGE_GET_CLASS (stage)->set_user_resize)
&& priv->is_user_resizable != resizable)
{
ClutterStageWindow *impl = CLUTTER_STAGE_WINDOW (priv->impl);
ClutterStageWindowIface *iface;
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (impl);
if (iface->set_user_resizable)
{
priv->is_user_resizable = resizable;
CLUTTER_STAGE_GET_CLASS (stage)->set_user_resize (stage, resizable);
iface->set_user_resizable (impl, resizable);
g_object_notify (G_OBJECT (stage), "user-resizable");
}
}
}
/**
@ -788,14 +956,20 @@ clutter_stage_show_cursor (ClutterStage *stage)
priv = stage->priv;
if (!priv->is_cursor_visible)
{
ClutterStageWindow *impl = CLUTTER_STAGE_WINDOW (priv->impl);
ClutterStageWindowIface *iface;
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (impl);
if (iface->set_cursor_visible)
{
priv->is_cursor_visible = TRUE;
if (CLUTTER_STAGE_GET_CLASS (stage)->set_cursor_visible)
CLUTTER_STAGE_GET_CLASS (stage)->set_cursor_visible (stage, TRUE);
iface->set_cursor_visible (impl, TRUE);
g_object_notify (G_OBJECT (stage), "cursor-visible");
}
}
}
/**
@ -816,13 +990,19 @@ clutter_stage_hide_cursor (ClutterStage *stage)
priv = stage->priv;
if (priv->is_cursor_visible)
{
priv->is_cursor_visible = FALSE;
ClutterStageWindow *impl = CLUTTER_STAGE_WINDOW (priv->impl);
ClutterStageWindowIface *iface;
if (CLUTTER_STAGE_GET_CLASS (stage)->set_cursor_visible)
CLUTTER_STAGE_GET_CLASS (stage)->set_cursor_visible (stage, FALSE);
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (impl);
if (iface->set_cursor_visible)
{
priv->is_cursor_visible = TRUE;
iface->set_cursor_visible (impl, FALSE);
g_object_notify (G_OBJECT (stage), "cursor-visible");
}
}
}
/**
@ -837,8 +1017,9 @@ clutter_stage_hide_cursor (ClutterStage *stage)
*
* Gets a pixel based representation of the current rendered stage.
*
* Return value: pixel representation as a #GdkPixbuf
**/
* Return value: pixel representation as a #GdkPixbuf, or %NULL if
* the backend does not support this operation
*/
GdkPixbuf *
clutter_stage_snapshot (ClutterStage *stage,
gint x,
@ -846,14 +1027,17 @@ clutter_stage_snapshot (ClutterStage *stage,
gint width,
gint height)
{
ClutterStageClass *klass;
ClutterStageWindow *impl;
ClutterStageWindowIface *iface;
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
g_return_val_if_fail (x >= 0 && y >= 0, NULL);
klass = CLUTTER_STAGE_GET_CLASS (stage);
if (klass->draw_to_pixbuf)
return klass->draw_to_pixbuf (stage, x, y, width, height);
impl = CLUTTER_STAGE_WINDOW (stage->priv->impl);
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (impl);
if (iface->draw_to_pixbuf)
return iface->draw_to_pixbuf (impl, x, y, width, height);
return NULL;
}
@ -883,8 +1067,9 @@ clutter_stage_get_actor_at_pos (ClutterStage *stage,
* @event: a #ClutterEvent
*
* This function is used to emit an event on the main stage.
*
* You should rarely need to use this function, except for
* synthetising events.
* synthetised events.
*
* Return value: the return value from the signal emission
*
@ -960,6 +1145,7 @@ clutter_stage_set_title (ClutterStage *stage,
const gchar *title)
{
ClutterStagePrivate *priv;
ClutterStageWindow *impl;
g_return_if_fail (CLUTTER_IS_STAGE (stage));
@ -968,8 +1154,8 @@ clutter_stage_set_title (ClutterStage *stage,
g_free (priv->title);
priv->title = g_strdup (title);
if (CLUTTER_STAGE_GET_CLASS (stage)->set_title)
CLUTTER_STAGE_GET_CLASS (stage)->set_title (stage, priv->title);
impl = CLUTTER_STAGE_WINDOW (priv->impl);
CLUTTER_STAGE_WINDOW_GET_IFACE (impl)->set_title (impl, priv->title);
g_object_notify (G_OBJECT (stage), "title");
}
@ -1373,7 +1559,7 @@ clutter_fog_get_type (void)
}
/**
* clutter_stage_create_new:
* clutter_stage_new:
*
* Creates a new, non-default stage. A non-default stage is a new
* top-level actor which can be used as another container. It works
@ -1388,15 +1574,13 @@ clutter_fog_get_type (void)
*
* Return value: a new stage, or %NULL if the default backend does
* not support multiple stages. Use clutter_actor_destroy() to
* close the returned stage.
* programmatically close the returned stage.
*
* Since: 0.8
*/
ClutterActor*
clutter_stage_create_new (void)
ClutterActor *
clutter_stage_new (void)
{
ClutterBackend *backend = clutter_get_default_backend ();
GError *error = NULL;
ClutterActor *retval;
if (!clutter_feature_available (CLUTTER_FEATURE_STAGE_MULTIPLE))
@ -1407,15 +1591,11 @@ clutter_stage_create_new (void)
return NULL;
}
retval = _clutter_backend_create_stage (backend, &error);
if (error)
{
g_warning ("Unable to create a secondary stage: %s", error->message);
g_error_free (error);
retval = NULL;
}
retval = g_object_new (CLUTTER_TYPE_STAGE, NULL);
if (retval)
return g_object_ref_sink (retval);
return retval;
return NULL;
}
/**
@ -1431,24 +1611,23 @@ clutter_stage_create_new (void)
void
clutter_stage_ensure_current (ClutterStage *stage)
{
ClutterMainContext *ctx;
ClutterMainContext *ctx = clutter_context_get_default ();
g_return_if_fail (CLUTTER_IS_STAGE (stage));
ctx = clutter_context_get_default ();
_clutter_backend_ensure_context (ctx->backend, stage);
}
static gboolean
redraw_update_idle (gpointer data)
redraw_update_idle (gpointer user_data)
{
ClutterStage *stage = CLUTTER_STAGE(data);
ClutterStage *stage = user_data;
ClutterStagePrivate *priv = stage->priv;
if (stage->priv->update_idle)
if (priv->update_idle)
{
g_source_remove (stage->priv->update_idle);
stage->priv->update_idle = 0;
g_source_remove (priv->update_idle);
priv->update_idle = 0;
}
CLUTTER_NOTE (MULTISTAGE, "redrawing via idle for stage:%p", stage);
@ -1461,8 +1640,10 @@ redraw_update_idle (gpointer data)
* clutter_stage_queue_redraw:
* @stage: the #ClutterStage
*
* Queues a redraw for the passed stage. Note applications should call
* #clutter_actor_queue_redraw over this.
* Queues a redraw for the passed stage.
*
* <note>Applications should call clutter_actor_queue_redraw() and not
* this function.</note>
*
* Since: 0.8
*/
@ -1483,3 +1664,32 @@ clutter_stage_queue_redraw (ClutterStage *stage)
NULL);
}
}
void
_clutter_stage_set_window (ClutterStage *stage,
ClutterStageWindow *stage_window)
{
g_return_if_fail (CLUTTER_IS_STAGE (stage));
g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (stage_window));
if (stage->priv->impl)
g_object_unref (stage->priv->impl);
stage->priv->impl = CLUTTER_ACTOR (stage_window);
}
ClutterStageWindow *
_clutter_stage_get_window (ClutterStage *stage)
{
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
return CLUTTER_STAGE_WINDOW (stage->priv->impl);
}
ClutterStageWindow *
_clutter_stage_get_default_window (void)
{
ClutterActor *stage = clutter_stage_get_default ();
return _clutter_stage_get_window (CLUTTER_STAGE (stage));
}

View File

@ -99,22 +99,7 @@ struct _ClutterStageClass
ClutterGroupClass parent_class;
/*< public >*/
/* vfuncs, not signals */
void (* set_fullscreen) (ClutterStage *stage,
gboolean fullscreen);
void (* set_cursor_visible) (ClutterStage *stage,
gboolean visible);
GdkPixbuf* (* draw_to_pixbuf) (ClutterStage *stage,
gint x,
gint y,
gint width,
gint height);
void (* set_title) (ClutterStage *stage,
const gchar *title);
void (* set_user_resize) (ClutterStage *stage,
gboolean value);
/* events */
/* signals */
void (* fullscreen) (ClutterStage *stage);
void (* unfullscreen) (ClutterStage *stage);
void (* activate) (ClutterStage *stage);
@ -175,6 +160,8 @@ GType clutter_fog_get_type (void) G_GNUC_CONST;
GType clutter_stage_get_type (void) G_GNUC_CONST;
ClutterActor *clutter_stage_get_default (void);
ClutterActor *clutter_stage_new (void);
void clutter_stage_set_color (ClutterStage *stage,
const ClutterColor *color);
void clutter_stage_get_color (ClutterStage *stage,
@ -233,15 +220,12 @@ void clutter_stage_get_fogx (ClutterStage *stage,
gdouble clutter_stage_get_resolution (ClutterStage *stage);
ClutterFixed clutter_stage_get_resolutionx (ClutterStage *stage);
/* New experiental calls */
void clutter_stage_set_key_focus (ClutterStage *stage,
ClutterActor *actor);
ClutterActor * clutter_stage_get_key_focus (ClutterStage *stage);
ClutterActor* clutter_stage_create_new (void);
/* New experiental calls */
void clutter_stage_ensure_current (ClutterStage *stage);
void clutter_stage_queue_redraw (ClutterStage *stage);
/* Commodity macro */

View File

@ -23,9 +23,10 @@ clutter_backend_egl_post_parse (ClutterBackend *backend,
{
EGLBoolean status;
backend_egl->edpy = eglGetDisplay((NativeDisplayType)backend_x11->xdpy);
backend_egl->edpy =
eglGetDisplay ((NativeDisplayType) backend_x11->xdpy);
status = eglInitialize(backend_egl->edpy,
status = eglInitialize (backend_egl->edpy,
&backend_egl->egl_version_major,
&backend_egl->egl_version_minor);
@ -47,17 +48,80 @@ clutter_backend_egl_post_parse (ClutterBackend *backend,
}
static void
clutter_backend_egl_redraw (ClutterBackend *backend)
clutter_backend_egl_ensure_context (ClutterBackend *backend,
ClutterStage *stage)
{
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
if (stage == NULL)
{
CLUTTER_NOTE (BACKEND, "Clearing EGL context");
eglMakeCurrent (backend_egl->edpy,
EGL_NO_SURFACE,
EGL_NO_SURFACE,
EGL_NO_CONTEXT);
}
else
{
ClutterStageWindow *impl;
ClutterStageEGL *stage_egl;
ClutterStageX11 *stage_x11;
stage_x11 = CLUTTER_STAGE_X11(backend_x11->stage);
stage_egl = CLUTTER_STAGE_EGL(backend_x11->stage);
impl = _clutter_stage_get_window (stage);
g_assert (impl != NULL);
clutter_actor_paint (CLUTTER_ACTOR(stage_egl));
CLUTTER_NOTE (MULTISTAGE, "Setting context for stage of type %s [%p]",
g_type_name (G_OBJECT_TYPE (impl)),
impl);
stage_egl = CLUTTER_STAGE_EGL (impl);
stage_x11 = CLUTTER_STAGE_X11 (impl);
g_return_if_fail (backend_egl->egl_context != NULL);
/* we might get here inside the final dispose cycle, so we
* need to handle this gracefully
*/
if (stage_x11->xwin == None ||
stage_egl->egl_surface == EGL_NO_SURFACE)
{
CLUTTER_NOTE (MULTISTAGE,
"Received a stale stage, clearing all context");
eglMakeCurrent (backend_egl->edpy,
EGL_NO_SURFACE,
EGL_NO_SURFACE,
EGL_NO_CONTEXT);
}
else
eglMakeCurrent (backend_egl->edpy,
stage_egl->egl_surface,
stage_egl->egl_surface,
backend_egl->egl_context);
}
}
static void
clutter_backend_egl_redraw (ClutterBackend *backend,
ClutterStage *stage)
{
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
ClutterStageWindow *impl;
ClutterStageEGL *stage_egl;
ClutterStageX11 *stage_x11;
impl = _clutter_stage_get_window (stage);
if (!impl)
return;
g_assert (CLUTTER_IS_STAGE_EGL (impl));
stage_x11 = CLUTTER_STAGE_X11 (impl);
stage_egl = CLUTTER_STAGE_EGL (impl);
/* this will cause the stage implementation to be painted as well */
clutter_actor_paint (CLUTTER_ACTOR (stage));
/* Why this paint is done in backend as likely GL windowing system
* specific calls, like swapping buffers.
@ -88,6 +152,12 @@ clutter_backend_egl_dispose (GObject *gobject)
{
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (gobject);
if (backend_egl->egl_context)
{
eglDestroyContext (backend_egl->edpy, backend_egl->egl_context);
backend_egl->egl_context = NULL;
}
if (backend_egl->edpy)
{
eglTerminate (backend_egl->edpy);
@ -133,29 +203,28 @@ clutter_backend_egl_get_features (ClutterBackend *backend)
"EGL_VENDOR: %s\n",
"EGL_VERSION: %s\n",
"EGL_EXTENSIONS: %s\n",
glGetString(GL_VENDOR),
glGetString(GL_RENDERER),
glGetString(GL_VERSION),
eglQueryString(backend_egl->edpy, EGL_VENDOR),
eglQueryString(backend_egl->edpy, EGL_VERSION),
eglQueryString(backend_egl->edpy, EGL_EXTENSIONS));
glGetString (GL_VENDOR),
glGetString (GL_RENDERER),
glGetString (GL_VERSION),
eglQueryString (backend_egl->edpy, EGL_VENDOR),
eglQueryString (backend_egl->edpy, EGL_VERSION),
eglQueryString (backend_egl->edpy, EGL_EXTENSIONS));
/* We can actually resize too */
return CLUTTER_FEATURE_STAGE_CURSOR|CLUTTER_FEATURE_STAGE_MULTIPLE;
}
static gboolean
clutter_backend_egl_init_stage (ClutterBackend *backend,
static ClutterActor *
clutter_backend_egl_create_stage (ClutterBackend *backend,
ClutterStage *wrapper,
GError **error)
{
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
if (!backend_x11->stage)
{
ClutterStageX11 *stage_x11;
ClutterActor *stage;
CLUTTER_NOTE (BACKEND, "Creating stage of type `%s'",
g_type_name (CLUTTER_STAGE_TYPE));
stage = g_object_new (CLUTTER_TYPE_STAGE_EGL, NULL);
stage = g_object_new (CLUTTER_STAGE_TYPE, NULL);
/* copy backend data into the stage */
stage_x11 = CLUTTER_STAGE_X11 (stage);
@ -163,17 +232,18 @@ clutter_backend_egl_init_stage (ClutterBackend *backend,
stage_x11->xwin_root = backend_x11->xwin_root;
stage_x11->xscreen = backend_x11->xscreen_num;
stage_x11->backend = backend_x11;
stage_x11->wrapper = wrapper;
CLUTTER_NOTE (MISC, "X11 stage created (display:%p, screen:%d, root:%u)",
/* set the pointer back into the wrapper */
_clutter_stage_set_window (wrapper, CLUTTER_STAGE_WINDOW (stage));
CLUTTER_NOTE (MISC, "EGLX stage created (display:%p, screen:%d, root:%u)",
stage_x11->xdpy,
stage_x11->xscreen,
(unsigned int) stage_x11->xwin_root);
g_object_set_data (G_OBJECT (stage), "clutter-backend", backend);
backend_x11->stage = g_object_ref_sink (stage);
}
clutter_actor_realize (backend_x11->stage);
if (!CLUTTER_ACTOR_IS_REALIZED (backend_x11->stage))
@ -181,10 +251,11 @@ clutter_backend_egl_init_stage (ClutterBackend *backend,
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_INTERNAL,
"Unable to realize the main stage");
return FALSE;
g_object_unref (stage);
return NULL;
}
return TRUE;
return stage;
}
static void
@ -200,13 +271,14 @@ clutter_backend_egl_class_init (ClutterBackendEGLClass *klass)
backend_class->post_parse = clutter_backend_egl_post_parse;
backend_class->redraw = clutter_backend_egl_redraw;
backend_class->get_features = clutter_backend_egl_get_features;
backend_class->init_stage = clutter_backend_egl_init_stage;
backend_class->create_stage = clutter_backend_egl_create_stage;
backend_class->ensure_context = clutter_backend_egl_ensure_context;
}
static void
clutter_backend_egl_init (ClutterBackendEGL *backend_egl)
{
;
}
GType

View File

@ -52,7 +52,11 @@ struct _ClutterBackendEGL
/* EGL Specific */
EGLDisplay edpy;
gint egl_version_major, egl_version_minor;
EGLSurface egl_surface;
EGLContext egl_context;
gint egl_version_major;
gint egl_version_minor;
};

View File

@ -2,6 +2,7 @@
#include "config.h"
#endif
#include "clutter-backend-egl.h"
#include "clutter-stage-egl.h"
#include "clutter-eglx.h"
@ -14,8 +15,17 @@
#include "../clutter-private.h"
#include "../clutter-debug.h"
#include "../clutter-units.h"
#include "../clutter-container.h"
#include "../clutter-stage.h"
#include "../clutter-stage-window.h"
G_DEFINE_TYPE (ClutterStageEGL, clutter_stage_egl, CLUTTER_TYPE_STAGE_X11);
static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
G_DEFINE_TYPE_WITH_CODE (ClutterStageEGL,
clutter_stage_egl,
CLUTTER_TYPE_STAGE_X11,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
clutter_stage_window_iface_init));
static void
clutter_stage_egl_unrealize (ClutterActor *actor)
@ -26,17 +36,19 @@ clutter_stage_egl_unrealize (ClutterActor *actor)
CLUTTER_MARK();
g_object_get (actor, "offscreen", &was_offscreen, NULL);
g_object_get (stage_x11->wrapper, "offscreen", &was_offscreen, NULL);
CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->unrealize (actor);
clutter_x11_trap_x_errors ()
if (G_UNLIKELY (was_offscreen))
{
/* No support as yet for this */
}
else
{
if (stage_x11->xwin != None)
if (!stage_X11->is_foreign_xwin && stage_x11->xwin != None)
{
XDestroyWindow (stage_x11->xdpy, stage_x11->xwin);
stage_x11->xwin = None;
@ -46,17 +58,18 @@ clutter_stage_egl_unrealize (ClutterActor *actor)
}
if (stage_egl->egl_surface)
eglDestroySurface (clutter_eglx_display(), stage_egl->egl_surface);
stage_egl->egl_surface = NULL;
{
eglDestroySurface (clutter_eglx_display (), stage_egl->egl_surface);
stage_egl->egl_surface = EGL_NO_SURFACE;
}
if (stage_egl->egl_context)
eglDestroyContext (clutter_eglx_display(), stage_egl->egl_context);
stage_egl->egl_context = NULL;
clutter_stage_ensure_current (stage_x11->wrapper);
eglMakeCurrent (clutter_eglx_display(),
EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
/* XSync (stage_x11->xdpy, False); */
stage_egl->egl_context = None;
clutter_x11_untrap_x_errors ();
CLUTTER_MARK ();
}
static void
@ -64,45 +77,48 @@ clutter_stage_egl_realize (ClutterActor *actor)
{
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (actor);
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
ClutterBackendEGL *backend_egl;
EGLConfig configs[2];
EGLint config_count;
EGLBoolean status;
gboolean is_offscreen;
gboolean is_offscreen = FALSE;
CLUTTER_NOTE (BACKEND, "Realizing main stage");
g_object_get (actor, "offscreen", &is_offscreen, NULL);
g_object_get (stage_x11->wrapper, "offscreen", &is_offscreen, NULL);
backend_egl = CLUTTER_BACKEND_EGL (clutter_get_default_backend ());
if (G_LIKELY (!is_offscreen))
{
EGLint cfg_attribs[] = { EGL_BUFFER_SIZE, EGL_DONT_CARE,
EGLint cfg_attribs[] = {
EGL_BUFFER_SIZE, EGL_DONT_CARE,
EGL_RED_SIZE, 5,
EGL_GREEN_SIZE, 6,
EGL_BLUE_SIZE, 5,
EGL_NONE };
EGL_NONE
};
status = eglGetConfigs (clutter_eglx_display(),
status = eglGetConfigs (backend_egl->edpy,
configs,
2,
&config_count);
if (status != EGL_TRUE)
g_warning ("eglGetConfigs");
g_warning ("eglGetConfigs failed");
status = eglChooseConfig (clutter_eglx_display(),
status = eglChooseConfig (backend_egl->edpy,
cfg_attribs,
configs,
sizeof configs / sizeof configs[0],
G_N_ELEMENTS (configs),
&config_count);
if (status != EGL_TRUE)
g_warning ("eglChooseConfig");
g_warning ("eglChooseConfig failed");
if (stage_x11->xwin == None)
stage_x11->xwin
= XCreateSimpleWindow(stage_x11->xdpy,
stage_x11->xwin =
XCreateSimpleWindow (stage_x11->xdpy,
stage_x11->xwin_root,
0, 0,
stage_x11->xwin_width,
@ -111,69 +127,68 @@ clutter_stage_egl_realize (ClutterActor *actor)
WhitePixel (stage_x11->xdpy,
stage_x11->xscreen));
XSelectInput(stage_x11->xdpy,
stage_x11->xwin,
XSelectInput (stage_x11->xdpy, stage_x11->xwin,
StructureNotifyMask
|ExposureMask
| ExposureMask
/* FIXME: we may want to eplicity enable MotionMask */
|PointerMotionMask
|KeyPressMask
|KeyReleaseMask
|ButtonPressMask
|ButtonReleaseMask
|PropertyChangeMask);
| PointerMotionMask
| KeyPressMask
| KeyReleaseMask
| ButtonPressMask
| ButtonReleaseMask
| PropertyChangeMask);
if (stage_egl->egl_context)
eglDestroyContext (clutter_eglx_display(), stage_egl->egl_context);
if (stage_egl->egl_surface != EGL_NO_SURFACE)
{
eglDestroySurface (backend_egl->edpy, stage_egl->egl_surface);
stage_egl->egl_surface = EGL_NO_SURFACE;
}
if (stage_egl->egl_surface)
eglDestroySurface (clutter_eglx_display(), stage_egl->egl_surface);
stage_egl->egl_surface
= eglCreateWindowSurface (clutter_eglx_display(),
stage_egl->egl_surface =
eglCreateWindowSurface (backend_egl->edpy,
configs[0],
(NativeWindowType)stage_x11->xwin,
(NativeWindowType) stage_x11->xwin,
NULL);
if (stage_egl->egl_surface == EGL_NO_SURFACE)
g_warning ("eglCreateWindowSurface");
stage_egl->egl_context = eglCreateContext (clutter_eglx_display(),
configs[0],
EGL_NO_CONTEXT,
NULL);
if (stage_egl->egl_context == EGL_NO_CONTEXT)
g_warning ("eglCreateContext");
status = eglMakeCurrent (clutter_eglx_display(),
stage_egl->egl_surface,
stage_egl->egl_surface,
stage_egl->egl_context);
if (status != EGL_TRUE)
g_warning ("eglMakeCurrent");
}
else
{
g_warning("EGL Backend does not yet support offscreen rendering\n");
g_critical ("Unable to create an EGL surface");
CLUTTER_ACTOR_UNSET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_REALIZED);
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
}
CLUTTER_SET_PRIVATE_FLAGS(actor, CLUTTER_ACTOR_SYNC_MATRICES);
}
if (G_UNLIKELY (backend_egl->egl_context == None))
{
CLUTTER_NOTE (GL, "Creating EGL Context");
static GdkPixbuf*
clutter_stage_egl_draw_to_pixbuf (ClutterStage *stage,
gint x,
gint y,
gint width,
gint height)
{
g_warning ("Stage of type `%s' do not support ClutterStage::draw_to_pixbuf",
G_OBJECT_TYPE_NAME (stage));
return NULL;
backend_egl->egl_context = eglCreateContext (backend_egl->edpy,
configs[0],
EGL_NO_CONTEXT,
NULL);
if (backend_egl->egl_context == EGL_NO_CONTEXT)
{
g_critical ("Unable to create a suitable EGL context");
CLUTTER_ACTOR_UNSET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_REALIZED);
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
}
}
CLUTTER_ACTOR_SET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_REALIZED);
clutter_stage_ensure_current (stage_x11->wrapper);
}
else
{
g_warning("EGLX Backend does not support offscreen rendering");
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
}
CLUTTER_SET_PRIVATE_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_SYNC_MATRICES);
}
static void
@ -188,24 +203,40 @@ clutter_stage_egl_dispose (GObject *gobject)
G_OBJECT_CLASS (clutter_stage_egl_parent_class)->dispose (gobject);
}
static GdkPixbuf *
clutter_stage_egl_draw_to_pixbuf (ClutterStageWindow *stage_window,
gint x,
gint y,
gint width,
gint height)
{
g_warning ("Stages of type `%s' do not support "
"ClutterStageWindow::draw_to_pixbuf",
G_OBJECT_TYPE_NAME (stage));
return NULL;
}
static void
clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
{
iface->draw_to_pixbuf = clutter_stage_egl_draw_to_pixbuf;
/* the rest is inherited from ClutterStageX11 */
}
static void
clutter_stage_egl_class_init (ClutterStageEGLClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
ClutterStageClass *stage_class = CLUTTER_STAGE_CLASS (klass);
gobject_class->dispose = clutter_stage_egl_dispose;
actor_class->realize = clutter_stage_egl_realize;
actor_class->unrealize = clutter_stage_egl_unrealize;
stage_class->draw_to_pixbuf = clutter_stage_egl_draw_to_pixbuf;
}
static void
clutter_stage_egl_init (ClutterStageEGL *stage)
{
;
}

View File

@ -28,7 +28,6 @@ struct _ClutterStageEGL
ClutterStageX11 parent_instance;
EGLSurface egl_surface;
EGLContext egl_context;
};
struct _ClutterStageEGLClass

View File

@ -173,6 +173,15 @@ clutter_backend_glx_finalize (GObject *gobject)
static void
clutter_backend_glx_dispose (GObject *gobject)
{
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (gobject);
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (gobject);
if (backend_glx->gl_context)
{
glXDestroyContext (backend_x11->xdpy, backend_glx->gl_context);
backend_glx->gl_context = None;
}
G_OBJECT_CLASS (clutter_backend_glx_parent_class)->dispose (gobject);
}
@ -214,10 +223,13 @@ clutter_backend_glx_get_features (ClutterBackend *backend)
{
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
const gchar *glx_extensions = NULL;
ClutterFeatureFlags flags = CLUTTER_FEATURE_STAGE_MULTIPLE;
ClutterFeatureFlags flags;
/* this will make sure that the GL context exists and its
* bound to a drawable
flags = clutter_backend_x11_get_features (backend);
flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;
/* this will make sure that the GL context exists and
* it's bound to a drawable
*/
g_assert (backend_glx->gl_context != None);
g_assert (glXGetCurrentDrawable () != None);
@ -344,36 +356,56 @@ clutter_backend_glx_get_features (ClutterBackend *backend)
CLUTTER_NOTE (MISC, "backend features checked");
return flags|clutter_backend_x11_get_features (backend);
return flags;
}
static void
clutter_backend_glx_ensure_context (ClutterBackend *backend,
ClutterStage *stage)
{
ClutterBackendGLX *backend_glx;
ClutterStageGLX *stage_glx;
ClutterStageX11 *stage_x11;
ClutterBackendX11 *backend_x11;
if (stage == NULL)
{
backend_x11 = CLUTTER_BACKEND_X11(backend);
ClutterBackendX11 *backend_x11;
backend_x11 = CLUTTER_BACKEND_X11 (backend);
CLUTTER_NOTE (MULTISTAGE, "Clearing all context");
glXMakeCurrent (backend_x11->xdpy, None, NULL);
}
else
{
stage_glx = CLUTTER_STAGE_GLX(stage);
stage_x11 = CLUTTER_STAGE_X11(stage);
backend_glx = CLUTTER_BACKEND_GLX(backend);
ClutterBackendGLX *backend_glx;
ClutterStageGLX *stage_glx;
ClutterStageX11 *stage_x11;
ClutterStageWindow *impl;
impl = _clutter_stage_get_window (stage);
g_assert (impl != NULL);
CLUTTER_NOTE (MULTISTAGE, "Setting context for stage of type %s [%p]",
g_type_name (G_OBJECT_TYPE (impl)),
impl);
stage_glx = CLUTTER_STAGE_GLX (impl);
stage_x11 = CLUTTER_STAGE_X11 (impl);
backend_glx = CLUTTER_BACKEND_GLX (backend);
g_return_if_fail (stage_x11->xwin != None);
g_return_if_fail (backend_glx->gl_context != None);
CLUTTER_NOTE (MULTISTAGE, "setting context for stage:%p", stage );
/* we might get here inside the final dispose cycle, so we
* need to handle this gracefully
*/
if (stage_x11->xwin == None)
{
ClutterBackendX11 *backend_x11;
backend_x11 = CLUTTER_BACKEND_X11 (backend);
CLUTTER_NOTE (MULTISTAGE,
"Received a stale stage, clearing all context");
glXMakeCurrent (backend_x11->xdpy, None, NULL);
}
else
glXMakeCurrent (stage_x11->xdpy,
stage_x11->xwin,
backend_glx->gl_context);
@ -381,22 +413,31 @@ clutter_backend_glx_ensure_context (ClutterBackend *backend,
}
static void
clutter_backend_glx_redraw (ClutterBackend *backend, ClutterStage *stage)
clutter_backend_glx_redraw (ClutterBackend *backend,
ClutterStage *stage)
{
ClutterStageGLX *stage_glx;
ClutterStageX11 *stage_x11;
ClutterStageWindow *impl;
stage_x11 = CLUTTER_STAGE_X11(stage);
stage_glx = CLUTTER_STAGE_GLX(stage);
impl = _clutter_stage_get_window (stage);
if (!impl)
return;
clutter_actor_paint (CLUTTER_ACTOR (stage_glx));
g_assert (CLUTTER_IS_STAGE_GLX (impl));
stage_x11 = CLUTTER_STAGE_X11 (impl);
stage_glx = CLUTTER_STAGE_GLX (impl);
/* this will cause the stage implementation to be painted */
clutter_actor_paint (CLUTTER_ACTOR (stage));
/* Why this paint is done in backend as likely GL windowing system
* specific calls, like swapping buffers.
*/
if (stage_x11->xwin)
{
clutter_backend_glx_wait_for_vblank (CLUTTER_BACKEND_GLX(backend));
clutter_backend_glx_wait_for_vblank (CLUTTER_BACKEND_GLX (backend));
glXSwapBuffers (stage_x11->xdpy, stage_x11->xwin);
}
else
@ -409,12 +450,16 @@ clutter_backend_glx_redraw (ClutterBackend *backend, ClutterStage *stage)
static ClutterActor*
clutter_backend_glx_create_stage (ClutterBackend *backend,
ClutterStage *wrapper,
GError **error)
{
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
ClutterStageX11 *stage_x11;
ClutterActor *stage;
CLUTTER_NOTE (BACKEND, "Creating stage of type `%s'",
g_type_name (CLUTTER_STAGE_TYPE));
stage = g_object_new (CLUTTER_STAGE_TYPE, NULL);
/* copy backend data into the stage */
@ -423,8 +468,12 @@ clutter_backend_glx_create_stage (ClutterBackend *backend,
stage_x11->xwin_root = backend_x11->xwin_root;
stage_x11->xscreen = backend_x11->xscreen_num;
stage_x11->backend = backend_x11;
stage_x11->wrapper = wrapper;
CLUTTER_NOTE (MISC, "X11 stage created (display:%p, screen:%d, root:%u)",
/* set the pointer back into the wrapper */
_clutter_stage_set_window (wrapper, CLUTTER_STAGE_WINDOW (stage));
CLUTTER_NOTE (BACKEND, "GLX stage created (display:%p, screen:%d, root:%u)",
stage_x11->xdpy,
stage_x11->xscreen,
(unsigned int) stage_x11->xwin_root);
@ -432,6 +481,10 @@ clutter_backend_glx_create_stage (ClutterBackend *backend,
/* needed ? */
g_object_set_data (G_OBJECT (stage), "clutter-backend", backend);
/* FIXME - is this needed? we should call realize inside the clutter
* init sequence for the default stage, and let the usual realization
* sequence be used for any other stage
*/
clutter_actor_realize (stage);
if (!CLUTTER_ACTOR_IS_REALIZED (stage))
@ -445,7 +498,6 @@ clutter_backend_glx_create_stage (ClutterBackend *backend,
return stage;
}
static void
clutter_backend_glx_class_init (ClutterBackendGLXClass *klass)
{
@ -468,7 +520,7 @@ clutter_backend_glx_class_init (ClutterBackendGLXClass *klass)
static void
clutter_backend_glx_init (ClutterBackendGLX *backend_glx)
{
;
}
/* every backend must implement this function */

View File

@ -40,6 +40,7 @@
#include "../clutter-group.h"
#include "../clutter-container.h"
#include "../clutter-stage.h"
#include "../clutter-stage-window.h"
#include "cogl.h"
@ -48,21 +49,25 @@
#include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
G_DEFINE_TYPE (ClutterStageGLX, clutter_stage_glx, CLUTTER_TYPE_STAGE_X11);
static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
G_DEFINE_TYPE_WITH_CODE (ClutterStageGLX,
clutter_stage_glx,
CLUTTER_TYPE_STAGE_X11,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
clutter_stage_window_iface_init));
static void
clutter_stage_glx_unrealize (ClutterActor *actor)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (actor);
/* Note unrealize should free up any backend stage related resources */
gboolean was_offscreen;
/* Note unrealize should free up any backend stage related resources */
CLUTTER_MARK();
g_object_get (actor, "offscreen", &was_offscreen, NULL);
g_object_get (stage_x11->wrapper, "offscreen", &was_offscreen, NULL);
/* Chain up so all children get unrealized, needed to move texture data
* across contexts
@ -100,7 +105,7 @@ clutter_stage_glx_unrealize (ClutterActor *actor)
}
/* As unrealised the context will now get cleared */
clutter_stage_ensure_current (CLUTTER_STAGE(stage_glx));
clutter_stage_ensure_current (stage_x11->wrapper);
XSync (stage_x11->xdpy, False);
@ -119,9 +124,9 @@ clutter_stage_glx_realize (ClutterActor *actor)
CLUTTER_NOTE (MISC, "Realizing main stage");
g_object_get (actor, "offscreen", &is_offscreen, NULL);
g_object_get (stage_x11->wrapper, "offscreen", &is_offscreen, NULL);
backend_glx = CLUTTER_BACKEND_GLX(clutter_get_default_backend());
backend_glx = CLUTTER_BACKEND_GLX (clutter_get_default_backend ());
if (G_LIKELY (!is_offscreen))
{
@ -137,8 +142,10 @@ clutter_stage_glx_realize (ClutterActor *actor)
};
if (stage_x11->xvisinfo)
{
XFree (stage_x11->xvisinfo);
stage_x11->xvisinfo = NULL;
stage_x11->xvisinfo = None;
}
/* The following check seems strange */
if (stage_x11->xvisinfo == None)
@ -148,6 +155,8 @@ clutter_stage_glx_realize (ClutterActor *actor)
if (!stage_x11->xvisinfo)
{
g_critical ("Unable to find suitable GL visual.");
CLUTTER_ACTOR_UNSET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_REALIZED);
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
}
@ -193,7 +202,6 @@ clutter_stage_glx_realize (ClutterActor *actor)
/* no user resize.. */
clutter_stage_x11_fix_window_size (stage_x11);
clutter_stage_x11_set_wm_protocols (stage_x11);
if (backend_glx->gl_context == None)
@ -208,6 +216,7 @@ clutter_stage_glx_realize (ClutterActor *actor)
{
g_critical ("Unable to create suitable GL context.");
CLUTTER_ACTOR_UNSET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_REALIZED);
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
@ -215,8 +224,8 @@ clutter_stage_glx_realize (ClutterActor *actor)
}
CLUTTER_NOTE (GL, "glXMakeCurrent");
clutter_stage_ensure_current (CLUTTER_STAGE(stage_glx));
CLUTTER_ACTOR_SET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_REALIZED);
clutter_stage_ensure_current (stage_x11->wrapper);
}
else
{
@ -276,6 +285,7 @@ clutter_stage_glx_realize (ClutterActor *actor)
{
g_critical ("Unable to create suitable GL context.");
CLUTTER_ACTOR_UNSET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_REALIZED);
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
@ -285,7 +295,7 @@ clutter_stage_glx_realize (ClutterActor *actor)
clutter_x11_trap_x_errors ();
/* below will call glxMakeCurrent */
clutter_stage_ensure_current (CLUTTER_STAGE(stage_glx));
clutter_stage_ensure_current (stage_x11->wrapper);
if (clutter_x11_untrap_x_errors ())
{
@ -295,14 +305,13 @@ clutter_stage_glx_realize (ClutterActor *actor)
}
/* Make sure the viewport gets set up correctly */
CLUTTER_SET_PRIVATE_FLAGS (actor, CLUTTER_ACTOR_SYNC_MATRICES);
CLUTTER_SET_PRIVATE_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_SYNC_MATRICES);
return;
fail:
fail:
/* For one reason or another we cant realize the stage.. */
CLUTTER_ACTOR_UNSET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_REALIZED);
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
}
static void
@ -312,8 +321,8 @@ snapshot_pixbuf_free (guchar *pixels,
g_free (pixels);
}
static GdkPixbuf*
clutter_stage_glx_draw_to_pixbuf (ClutterStage *stage,
static GdkPixbuf *
clutter_stage_glx_draw_to_pixbuf (ClutterStageWindow *stage_window,
gint x,
gint y,
gint width,
@ -326,9 +335,9 @@ clutter_stage_glx_draw_to_pixbuf (ClutterStage *stage,
ClutterStageX11 *stage_x11;
gboolean is_offscreen = FALSE;
stage_glx = CLUTTER_STAGE_GLX (stage);
stage_x11 = CLUTTER_STAGE_X11 (stage);
actor = CLUTTER_ACTOR (stage);
stage_glx = CLUTTER_STAGE_GLX (stage_window);
stage_x11 = CLUTTER_STAGE_X11 (stage_window);
actor = CLUTTER_ACTOR (stage_window);
if (width < 0)
width = clutter_actor_get_width (actor);
@ -336,7 +345,7 @@ clutter_stage_glx_draw_to_pixbuf (ClutterStage *stage,
if (height < 0)
height = clutter_actor_get_height (actor);
g_object_get (stage, "offscreen", &is_offscreen, NULL);
g_object_get (stage_x11->wrapper, "offscreen", &is_offscreen, NULL);
if (G_UNLIKELY (is_offscreen))
{
@ -401,17 +410,22 @@ clutter_stage_glx_class_init (ClutterStageGLXClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
ClutterStageClass *stage_class = CLUTTER_STAGE_CLASS (klass);
gobject_class->dispose = clutter_stage_glx_dispose;
actor_class->realize = clutter_stage_glx_realize;
actor_class->unrealize = clutter_stage_glx_unrealize;
stage_class->draw_to_pixbuf = clutter_stage_glx_draw_to_pixbuf;
}
static void
clutter_stage_glx_init (ClutterStageGLX *stage)
{
;
}
static void
clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
{
iface->draw_to_pixbuf = clutter_stage_glx_draw_to_pixbuf;
/* the rest is inherited from ClutterStageX11 */
}

View File

@ -331,6 +331,7 @@ event_translate (ClutterBackend *backend,
ClutterBackendX11 *backend_x11;
ClutterStageX11 *stage_x11;
ClutterStage *stage;
ClutterStageWindow *impl;
gboolean res;
Window xwindow, stage_xwindow;
@ -375,7 +376,8 @@ event_translate (ClutterBackend *backend,
if (stage == NULL)
return FALSE;
stage_x11 = CLUTTER_STAGE_X11 (stage);
impl = _clutter_stage_get_window (stage);
stage_x11 = CLUTTER_STAGE_X11 (impl);
stage_xwindow = xwindow; /* clutter_x11_get_stage_window (stage); */
event->any.stage = stage;

View File

@ -27,6 +27,7 @@
#include "clutter-stage-x11.h"
#include "clutter-x11.h"
#include "../clutter-stage-window.h"
#include "../clutter-main.h"
#include "../clutter-feature.h"
#include "../clutter-color.h"
@ -45,7 +46,13 @@
#include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
G_DEFINE_TYPE (ClutterStageX11, clutter_stage_x11, CLUTTER_TYPE_STAGE);
static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
G_DEFINE_TYPE_WITH_CODE (ClutterStageX11,
clutter_stage_x11,
CLUTTER_TYPE_GROUP,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
clutter_stage_window_iface_init));
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
#define _NET_WM_STATE_ADD 1 /* add/set property */
@ -84,7 +91,7 @@ clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11)
{
gboolean resize;
resize = clutter_stage_get_user_resizable (CLUTTER_STAGE (stage_x11));
resize = clutter_stage_get_user_resizable (stage_x11->wrapper);
if (stage_x11->xwin != None && stage_x11->is_foreign_xwin == FALSE)
{
@ -117,7 +124,7 @@ clutter_stage_x11_show (ClutterActor *actor)
/* Fire off a redraw to avoid flicker on first map.
* Appears not to work perfectly on intel drivers at least.
*/
clutter_redraw(CLUTTER_STAGE(actor));
clutter_redraw (stage_x11->wrapper);
XSync (stage_x11->xdpy, FALSE);
XMapWindow (stage_x11->xdpy, stage_x11->xwin);
@ -208,7 +215,8 @@ clutter_stage_x11_request_coords (ClutterActor *self,
clutter_actor_realize (self);
}
CLUTTER_SET_PRIVATE_FLAGS(self, CLUTTER_ACTOR_SYNC_MATRICES);
CLUTTER_SET_PRIVATE_FLAGS (CLUTTER_ACTOR (stage_x11->wrapper),
CLUTTER_ACTOR_SYNC_MATRICES);
}
if (stage_x11->xwin != None
@ -224,15 +232,18 @@ clutter_stage_x11_request_coords (ClutterActor *self,
}
static void
clutter_stage_x11_set_fullscreen (ClutterStage *stage,
gboolean fullscreen)
clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window,
gboolean is_fullscreen)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage);
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
ClutterBackendX11 *backend_x11 = stage_x11->backend;
ClutterStage *stage = stage_x11->wrapper;
static gboolean was_resizeable = FALSE;
if (fullscreen)
if (!stage)
return;
if (is_fullscreen)
{
if (stage_x11->xwin != None)
{
@ -311,19 +322,19 @@ clutter_stage_x11_set_fullscreen (ClutterStage *stage,
}
static void
clutter_stage_x11_set_cursor_visible (ClutterStage *stage,
gboolean show_cursor)
clutter_stage_x11_set_cursor_visible (ClutterStageWindow *stage_window,
gboolean cursor_visible)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage);
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
if (stage_x11->xwin == None)
return;
CLUTTER_NOTE (BACKEND, "setting cursor state ('%s') over stage window (%u)",
show_cursor ? "visible" : "invisible",
cursor_visible ? "visible" : "invisible",
(unsigned int) stage_x11->xwin);
if (show_cursor)
if (cursor_visible)
{
#if 0 /* HAVE_XFIXES - seems buggy/unreliable */
XFixesShowCursor (stage_x11->xdpy, stage_x11->xwin);
@ -355,10 +366,10 @@ clutter_stage_x11_set_cursor_visible (ClutterStage *stage,
}
static void
clutter_stage_x11_set_title (ClutterStage *stage,
clutter_stage_x11_set_title (ClutterStageWindow *stage_window,
const gchar *title)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage);
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
ClutterBackendX11 *backend_x11 = stage_x11->backend;
if (stage_x11->xwin == None)
@ -384,14 +395,20 @@ clutter_stage_x11_set_title (ClutterStage *stage,
}
static void
clutter_stage_x11_set_user_resize (ClutterStage *stage,
gboolean value)
clutter_stage_x11_set_user_resizable (ClutterStageWindow *stage_window,
gboolean is_resizable)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage);
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
clutter_stage_x11_fix_window_size (stage_x11);
}
static ClutterActor *
clutter_stage_x11_get_wrapper (ClutterStageWindow *stage_window)
{
return CLUTTER_ACTOR (CLUTTER_STAGE_X11 (stage_window)->wrapper);
}
static void
clutter_stage_x11_dispose (GObject *gobject)
{
@ -408,7 +425,6 @@ clutter_stage_x11_class_init (ClutterStageX11Class *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
ClutterStageClass *stage_class = CLUTTER_STAGE_CLASS (klass);
gobject_class->dispose = clutter_stage_x11_dispose;
@ -416,11 +432,6 @@ clutter_stage_x11_class_init (ClutterStageX11Class *klass)
actor_class->hide = clutter_stage_x11_hide;
actor_class->request_coords = clutter_stage_x11_request_coords;
actor_class->query_coords = clutter_stage_x11_query_coords;
stage_class->set_fullscreen = clutter_stage_x11_set_fullscreen;
stage_class->set_cursor_visible = clutter_stage_x11_set_cursor_visible;
stage_class->set_title = clutter_stage_x11_set_title;
stage_class->set_user_resize = clutter_stage_x11_set_user_resize;
}
static void
@ -439,7 +450,22 @@ clutter_stage_x11_init (ClutterStageX11 *stage)
stage->fullscreen_on_map = FALSE;
stage->handling_configure = FALSE;
stage->wrapper = NULL;
CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_IS_TOPLEVEL);
#if 0
CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
#endif
}
static void
clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
{
iface->get_wrapper = clutter_stage_x11_get_wrapper;
iface->set_title = clutter_stage_x11_set_title;
iface->set_fullscreen = clutter_stage_x11_set_fullscreen;
iface->set_cursor_visible = clutter_stage_x11_set_cursor_visible;
iface->set_user_resizable = clutter_stage_x11_set_user_resizable;
}
/**
@ -455,9 +481,14 @@ clutter_stage_x11_init (ClutterStageX11 *stage)
Window
clutter_x11_get_stage_window (ClutterStage *stage)
{
g_return_val_if_fail (CLUTTER_IS_STAGE_X11 (stage), None);
ClutterStageWindow *impl;
return CLUTTER_STAGE_X11 (stage)->xwin;
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), None);
impl = _clutter_stage_get_window (stage);
g_assert (CLUTTER_IS_STAGE_X11 (impl));
return CLUTTER_STAGE_X11 (impl)->xwin;
}
/**
@ -470,7 +501,7 @@ clutter_x11_get_stage_window (ClutterStage *stage)
*
* Since: 0.8
*/
ClutterStage*
ClutterStage *
clutter_x11_get_stage_from_window (Window win)
{
ClutterMainContext *context;
@ -484,10 +515,14 @@ clutter_x11_get_stage_from_window (Window win)
/* FIXME: use a hash here for performance resaon */
for (l = stage_manager->stages; l; l = l->next)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (l->data);
ClutterStage *stage = l->data;
ClutterStageWindow *impl;
if (stage_x11->xwin == win)
return CLUTTER_STAGE(stage_x11);
impl = _clutter_stage_get_window (stage);
g_assert (CLUTTER_IS_STAGE_X11 (impl));
if (CLUTTER_STAGE_X11 (impl)->xwin == win)
return stage;
}
return NULL;
@ -506,9 +541,14 @@ clutter_x11_get_stage_from_window (Window win)
XVisualInfo *
clutter_x11_get_stage_visual (ClutterStage *stage)
{
g_return_val_if_fail (CLUTTER_IS_STAGE_X11 (stage), NULL);
ClutterStageWindow *impl;
return CLUTTER_STAGE_X11 (stage)->xvisinfo;
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
impl = _clutter_stage_get_window (stage);
g_assert (CLUTTER_IS_STAGE_X11 (impl));
return CLUTTER_STAGE_X11 (impl)->xvisinfo;
}
/**
@ -527,6 +567,7 @@ clutter_x11_set_stage_foreign (ClutterStage *stage,
Window xwindow)
{
ClutterStageX11 *stage_x11;
ClutterStageWindow *impl;
ClutterActor *actor;
gint x, y;
guint width, height, border, depth;
@ -534,11 +575,12 @@ clutter_x11_set_stage_foreign (ClutterStage *stage,
Status status;
ClutterGeometry geom;
g_return_val_if_fail (CLUTTER_IS_STAGE_X11 (stage), FALSE);
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
g_return_val_if_fail (xwindow != None, FALSE);
stage_x11 = CLUTTER_STAGE_X11 (stage);
actor = CLUTTER_ACTOR (stage);
impl = _clutter_stage_get_window (stage);
stage_x11 = CLUTTER_STAGE_X11 (impl);
actor = CLUTTER_ACTOR (impl);
clutter_x11_trap_x_errors ();
@ -577,19 +619,27 @@ clutter_x11_set_stage_foreign (ClutterStage *stage,
void
clutter_stage_x11_map (ClutterStageX11 *stage_x11)
{
/* set the mapped flag on the implementation */
CLUTTER_ACTOR_SET_FLAGS (stage_x11, CLUTTER_ACTOR_MAPPED);
if (stage_x11->fullscreen_on_map)
clutter_stage_fullscreen (CLUTTER_STAGE (stage_x11));
else
clutter_stage_unfullscreen (CLUTTER_STAGE (stage_x11));
/* and on the wrapper itself */
CLUTTER_ACTOR_SET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_MAPPED);
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage_x11));
if (stage_x11->fullscreen_on_map)
clutter_stage_fullscreen (CLUTTER_STAGE (stage_x11->wrapper));
else
clutter_stage_unfullscreen (CLUTTER_STAGE (stage_x11->wrapper));
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage_x11->wrapper));
}
void
clutter_stage_x11_unmap (ClutterStageX11 *stage_x11)
{
/* like above, unset the MAPPED stage on both the implementation and
* the wrapper
*/
CLUTTER_ACTOR_UNSET_FLAGS (stage_x11, CLUTTER_ACTOR_MAPPED);
CLUTTER_ACTOR_UNSET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_MAPPED);
}

View File

@ -22,7 +22,7 @@
#ifndef __CLUTTER_STAGE_X11_H__
#define __CLUTTER_STAGE_X11_H__
#include <glib-object.h>
#include <clutter/clutter-group.h>
#include <clutter/clutter-stage.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
@ -43,7 +43,7 @@ typedef struct _ClutterStageX11Class ClutterStageX11Class;
struct _ClutterStageX11
{
ClutterStage parent_instance;
ClutterGroup parent_instance;
guint is_foreign_xwin : 1;
guint fullscreen_on_map : 1;
@ -60,11 +60,13 @@ struct _ClutterStageX11
ClutterBackendX11 *backend;
ClutterStageState state;
ClutterStage *wrapper;
};
struct _ClutterStageX11Class
{
ClutterStageClass parent_class;
ClutterGroupClass parent_class;
};
GType clutter_stage_x11_get_type (void) G_GNUC_CONST;
@ -72,7 +74,6 @@ GType clutter_stage_x11_get_type (void) G_GNUC_CONST;
/* Private to subclasses */
void clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11);
void clutter_stage_x11_set_wm_protocols (ClutterStageX11 *stage_x11);
void clutter_stage_x11_map (ClutterStageX11 *stage_x11);
void clutter_stage_x11_unmap (ClutterStageX11 *stage_x11);

View File

@ -26,7 +26,7 @@ on_button_press (ClutterActor *actor,
ClutterAlpha *alpha;
ClutterBehaviour *r_behave;
new_stage = clutter_stage_create_new ();
new_stage = clutter_stage_new ();
/* FIXME: below should really be automatic */
/* clutter_stage_ensure_cogl_context (CLUTTER_STAGE(new_stage)); */