diff --git a/ChangeLog b/ChangeLog index 6837a91f4..1c163038c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,38 @@ +2008-04-04 Emmanuele Bassi + + 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 Applied patch from bug #810. diff --git a/clutter/Makefile.am b/clutter/Makefile.am index d13ccbaf3..df0aadcd6 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -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 = \ diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index db9c1ea97..961d5b1f8 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -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)); } /** diff --git a/clutter/clutter-backend.c b/clutter/clutter-backend.c index 2209060ef..4c259dd87 100644 --- a/clutter/clutter-backend.c +++ b/clutter/clutter-backend.c @@ -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)) - stage = NULL; + 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 diff --git a/clutter/clutter-backend.h b/clutter/clutter-backend.h index 08b53e914..ffccf4ee3 100644 --- a/clutter/clutter-backend.h +++ b/clutter/clutter-backend.h @@ -47,31 +47,33 @@ typedef struct _ClutterBackendClass ClutterBackendClass; struct _ClutterBackend { + /*< private >*/ GObject parent_instance; ClutterBackendPrivate *priv; - }; struct _ClutterBackendClass { + /*< private >*/ GObjectClass parent_class; /* vfuncs */ - gboolean (* pre_parse) (ClutterBackend *backend, - GError **error); - gboolean (* post_parse) (ClutterBackend *backend, - GError **error); - ClutterActor *(* create_stage) (ClutterBackend *backend, - GError **error); - void (* init_events) (ClutterBackend *backend); - void (* init_features) (ClutterBackend *backend); - void (* add_options) (ClutterBackend *backend, - GOptionGroup *group); - ClutterFeatureFlags (* get_features) (ClutterBackend *backend); - void (* redraw) (ClutterBackend *backend, - ClutterStage *stage); - void (* ensure_context) (ClutterBackend *backend, - ClutterStage *stage); + gboolean (* pre_parse) (ClutterBackend *backend, + GError **error); + gboolean (* post_parse) (ClutterBackend *backend, + GError **error); + ClutterActor * (* create_stage) (ClutterBackend *backend, + ClutterStage *wrapper, + GError **error); + void (* init_events) (ClutterBackend *backend); + void (* init_features) (ClutterBackend *backend); + void (* add_options) (ClutterBackend *backend, + GOptionGroup *group); + ClutterFeatureFlags (* get_features) (ClutterBackend *backend); + void (* redraw) (ClutterBackend *backend, + ClutterStage *stage); + void (* ensure_context) (ClutterBackend *backend, + ClutterStage *stage); }; GType clutter_backend_get_type (void) G_GNUC_CONST; diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c index 5f47c1ee1..77fdb271a 100644 --- a/clutter/clutter-main.c +++ b/clutter/clutter-main.c @@ -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) - */ - 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); - } + /* The code below can't go in stage paint as base actor_paint + * will get called before it (and break picking, etc) + */ + 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,10 +268,10 @@ _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); + return CLUTTER_ACTOR (stage); cogl_get_bitmasks (&r, &g, &b, NULL); @@ -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; } diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h index 375b06363..cd76115a0 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -40,12 +40,13 @@ #include -#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 - * viewport / perspective etc - * needs (re)setting. - */ + 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,29 +136,31 @@ 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 */ -GType _clutter_backend_impl_get_type (void); +void _clutter_stage_set_window (ClutterStage *stage, + ClutterStageWindow *stage_window); +ClutterStageWindow *_clutter_stage_get_window (ClutterStage *stage); +ClutterStageWindow *_clutter_stage_get_default_window (void); -void _clutter_backend_redraw (ClutterBackend *backend, - ClutterStage *stage); +/* vfuncs implemented by backend */ +GType _clutter_backend_impl_get_type (void); -ClutterActor* _clutter_backend_create_stage (ClutterBackend *backend, - GError **error); +void _clutter_backend_redraw (ClutterBackend *backend, + ClutterStage *stage); +ClutterActor *_clutter_backend_create_stage (ClutterBackend *backend, + ClutterStage *wrapper, + GError **error); +void _clutter_backend_ensure_context (ClutterBackend *backend, + ClutterStage *stage); -void _clutter_backend_redraw (ClutterBackend *backend, - ClutterStage *stage); - -void _clutter_backend_add_options (ClutterBackend *backend, - GOptionGroup *group); -gboolean _clutter_backend_pre_parse (ClutterBackend *backend, - GError **error); -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); +void _clutter_backend_add_options (ClutterBackend *backend, + GOptionGroup *group); +gboolean _clutter_backend_pre_parse (ClutterBackend *backend, + GError **error); +gboolean _clutter_backend_post_parse (ClutterBackend *backend, + GError **error); +void _clutter_backend_init_events (ClutterBackend *backend); ClutterFeatureFlags _clutter_backend_get_features (ClutterBackend *backend); @@ -172,10 +175,10 @@ ClutterActor *_clutter_do_pick (ClutterStage *stage, * a G_TYPE_BOOLEAN return value; this will stop the emission as * soon as one handler returns TRUE */ -gboolean _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint, - GValue *return_accu, - const GValue *handler_return, - gpointer dummy); +gboolean _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + gpointer dummy); G_END_DECLS diff --git a/clutter/clutter-stage-manager.c b/clutter/clutter-stage-manager.c index c14059449..9e8225993 100644 --- a/clutter/clutter-stage-manager.c +++ b/clutter/clutter-stage-manager.c @@ -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; - } + return; stage_manager->stages = g_slist_remove (stage_manager->stages, stage); diff --git a/clutter/clutter-stage-window.c b/clutter/clutter-stage-window.c new file mode 100644 index 000000000..e74810503 --- /dev/null +++ b/clutter/clutter-stage-window.c @@ -0,0 +1,33 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#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; +} diff --git a/clutter/clutter-stage-window.h b/clutter/clutter-stage-window.h new file mode 100644 index 000000000..d70858d38 --- /dev/null +++ b/clutter/clutter-stage-window.h @@ -0,0 +1,43 @@ +#ifndef __CLUTTER_STAGE_WINDOW_H__ +#define __CLUTTER_STAGE_WINDOW_H__ + +#include +#include + +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__ */ diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index 5d560735b..7b71686d3 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -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,14 +906,20 @@ 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) { - priv->is_user_resizable = resizable; + ClutterStageWindow *impl = CLUTTER_STAGE_WINDOW (priv->impl); + ClutterStageWindowIface *iface; - CLUTTER_STAGE_GET_CLASS (stage)->set_user_resize (stage, resizable); + iface = CLUTTER_STAGE_WINDOW_GET_IFACE (impl); + if (iface->set_user_resizable) + { + priv->is_user_resizable = resizable; - g_object_notify (G_OBJECT (stage), "user-resizable"); + iface->set_user_resizable (impl, resizable); + + g_object_notify (G_OBJECT (stage), "user-resizable"); + } } } @@ -789,12 +957,18 @@ clutter_stage_show_cursor (ClutterStage *stage) priv = stage->priv; if (!priv->is_cursor_visible) { - priv->is_cursor_visible = TRUE; + 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, TRUE); + iface = CLUTTER_STAGE_WINDOW_GET_IFACE (impl); + if (iface->set_cursor_visible) + { + priv->is_cursor_visible = TRUE; - g_object_notify (G_OBJECT (stage), "cursor-visible"); + iface->set_cursor_visible (impl, TRUE); + + g_object_notify (G_OBJECT (stage), "cursor-visible"); + } } } @@ -816,12 +990,18 @@ 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; - g_object_notify (G_OBJECT (stage), "cursor-visible"); + 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. + * + * Applications should call clutter_actor_queue_redraw() and not + * this function. * * Since: 0.8 */ @@ -1479,7 +1660,36 @@ clutter_stage_queue_redraw (ClutterStage *stage) stage->priv->update_idle = clutter_threads_add_idle_full (G_PRIORITY_DEFAULT + 10, redraw_update_idle, - stage, + 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)); +} diff --git a/clutter/clutter-stage.h b/clutter/clutter-stage.h index 0973cbe96..eeb8ec4c8 100644 --- a/clutter/clutter-stage.h +++ b/clutter/clutter-stage.h @@ -99,26 +99,11 @@ 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 */ - void (* fullscreen) (ClutterStage *stage); - void (* unfullscreen) (ClutterStage *stage); - void (* activate) (ClutterStage *stage); - void (* deactivate) (ClutterStage *stage); + /* signals */ + void (* fullscreen) (ClutterStage *stage); + void (* unfullscreen) (ClutterStage *stage); + void (* activate) (ClutterStage *stage); + void (* deactivate) (ClutterStage *stage); /*< private >*/ /* padding for future expansion */ @@ -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 */ diff --git a/clutter/eglx/clutter-backend-egl.c b/clutter/eglx/clutter-backend-egl.c index c7c7ae143..daba3540f 100644 --- a/clutter/eglx/clutter-backend-egl.c +++ b/clutter/eglx/clutter-backend-egl.c @@ -23,11 +23,12 @@ 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, - &backend_egl->egl_version_major, - &backend_egl->egl_version_minor); + status = eglInitialize (backend_egl->edpy, + &backend_egl->egl_version_major, + &backend_egl->egl_version_minor); if (status != EGL_TRUE) { @@ -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); - ClutterStageEGL *stage_egl; - ClutterStageX11 *stage_x11; - stage_x11 = CLUTTER_STAGE_X11(backend_x11->stage); - stage_egl = CLUTTER_STAGE_EGL(backend_x11->stage); + 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; - clutter_actor_paint (CLUTTER_ACTOR(stage_egl)); + 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_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,46 +203,46 @@ 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, - GError **error) +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; - - stage = g_object_new (CLUTTER_TYPE_STAGE_EGL, NULL); - - /* copy backend data into the stage */ - stage_x11 = CLUTTER_STAGE_X11 (stage); - stage_x11->xdpy = backend_x11->xdpy; - stage_x11->xwin_root = backend_x11->xwin_root; - stage_x11->xscreen = backend_x11->xscreen_num; - stage_x11->backend = backend_x11; - - CLUTTER_NOTE (MISC, "X11 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_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 */ + stage_x11 = CLUTTER_STAGE_X11 (stage); + stage_x11->xdpy = backend_x11->xdpy; + stage_x11->xwin_root = backend_x11->xwin_root; + stage_x11->xscreen = backend_x11->xscreen_num; + stage_x11->backend = backend_x11; + stage_x11->wrapper = wrapper; + + /* 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); clutter_actor_realize (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 @@ -194,19 +265,20 @@ clutter_backend_egl_class_init (ClutterBackendEGLClass *klass) ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass); gobject_class->constructor = clutter_backend_egl_constructor; - gobject_class->dispose = clutter_backend_egl_dispose; - gobject_class->finalize = clutter_backend_egl_finalize; + gobject_class->dispose = clutter_backend_egl_dispose; + gobject_class->finalize = clutter_backend_egl_finalize; - 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->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->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 diff --git a/clutter/eglx/clutter-backend-egl.h b/clutter/eglx/clutter-backend-egl.h index dde6a13ad..43894dd39 100644 --- a/clutter/eglx/clutter-backend-egl.h +++ b/clutter/eglx/clutter-backend-egl.h @@ -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; }; diff --git a/clutter/eglx/clutter-stage-egl.c b/clutter/eglx/clutter-stage-egl.c index 7559761d0..a430e0837 100644 --- a/clutter/eglx/clutter-stage-egl.c +++ b/clutter/eglx/clutter-stage-egl.c @@ -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,134 +58,137 @@ 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 clutter_stage_egl_realize (ClutterActor *actor) { - ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (actor); - ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor); - - EGLConfig configs[2]; - EGLint config_count; - EGLBoolean status; - - gboolean is_offscreen; + 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 = 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, - EGL_RED_SIZE, 5, - EGL_GREEN_SIZE, 6, - EGL_BLUE_SIZE, 5, - EGL_NONE }; + EGLint cfg_attribs[] = { + EGL_BUFFER_SIZE, EGL_DONT_CARE, + EGL_RED_SIZE, 5, + EGL_GREEN_SIZE, 6, + EGL_BLUE_SIZE, 5, + 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_root, - 0, 0, - stage_x11->xwin_width, - stage_x11->xwin_height, - 0, 0, - WhitePixel (stage_x11->xdpy, - stage_x11->xscreen)); + stage_x11->xwin = + XCreateSimpleWindow (stage_x11->xdpy, + stage_x11->xwin_root, + 0, 0, + stage_x11->xwin_width, + stage_x11->xwin_height, + 0, 0, + WhitePixel (stage_x11->xdpy, + stage_x11->xscreen)); - XSelectInput(stage_x11->xdpy, - stage_x11->xwin, - StructureNotifyMask - |ExposureMask - /* FIXME: we may want to eplicity enable MotionMask */ - |PointerMotionMask - |KeyPressMask - |KeyReleaseMask - |ButtonPressMask - |ButtonReleaseMask - |PropertyChangeMask); + XSelectInput (stage_x11->xdpy, stage_x11->xwin, + StructureNotifyMask + | ExposureMask + /* FIXME: we may want to eplicity enable MotionMask */ + | 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(), - configs[0], - (NativeWindowType)stage_x11->xwin, - NULL); + stage_egl->egl_surface = + eglCreateWindowSurface (backend_egl->edpy, + configs[0], + (NativeWindowType) stage_x11->xwin, + NULL); if (stage_egl->egl_surface == EGL_NO_SURFACE) - g_warning ("eglCreateWindowSurface"); + { + g_critical ("Unable to create an EGL surface"); - stage_egl->egl_context = eglCreateContext (clutter_eglx_display(), - configs[0], - EGL_NO_CONTEXT, - NULL); + CLUTTER_ACTOR_UNSET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_REALIZED); + CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED); + return; + } - if (stage_egl->egl_context == EGL_NO_CONTEXT) - g_warning ("eglCreateContext"); + if (G_UNLIKELY (backend_egl->egl_context == None)) + { + CLUTTER_NOTE (GL, "Creating EGL Context"); - status = eglMakeCurrent (clutter_eglx_display(), - stage_egl->egl_surface, - stage_egl->egl_surface, - stage_egl->egl_context); + backend_egl->egl_context = eglCreateContext (backend_egl->edpy, + configs[0], + EGL_NO_CONTEXT, + NULL); - if (status != EGL_TRUE) - g_warning ("eglMakeCurrent"); + 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("EGL Backend does not yet support offscreen rendering\n"); + g_warning("EGLX Backend does not support offscreen rendering"); CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED); return; } - CLUTTER_SET_PRIVATE_FLAGS(actor, CLUTTER_ACTOR_SYNC_MATRICES); -} - -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; + 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) { - ; } - - diff --git a/clutter/eglx/clutter-stage-egl.h b/clutter/eglx/clutter-stage-egl.h index 4ad02636a..8e9896257 100644 --- a/clutter/eglx/clutter-stage-egl.h +++ b/clutter/eglx/clutter-stage-egl.h @@ -27,8 +27,7 @@ struct _ClutterStageEGL { ClutterStageX11 parent_instance; - EGLSurface egl_surface; - EGLContext egl_context; + EGLSurface egl_surface; }; struct _ClutterStageEGLClass diff --git a/clutter/glx/clutter-backend-glx.c b/clutter/glx/clutter-backend-glx.c index 9d17252ef..f612413e3 100644 --- a/clutter/glx/clutter-backend-glx.c +++ b/clutter/glx/clutter-backend-glx.c @@ -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; + + flags = clutter_backend_x11_get_features (backend); + flags |= CLUTTER_FEATURE_STAGE_MULTIPLE; - /* this will make sure that the GL context exists and its - * bound to a drawable + /* 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,59 +356,88 @@ 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; - glXMakeCurrent (stage_x11->xdpy, - stage_x11->xwin, - backend_glx->gl_context); + 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); } } static void -clutter_backend_glx_redraw (ClutterBackend *backend, ClutterStage *stage) +clutter_backend_glx_redraw (ClutterBackend *backend, + ClutterStage *stage) { - ClutterStageGLX *stage_glx; - ClutterStageX11 *stage_x11; + 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) { @@ -456,19 +508,19 @@ clutter_backend_glx_class_init (ClutterBackendGLXClass *klass) gobject_class->dispose = clutter_backend_glx_dispose; gobject_class->finalize = clutter_backend_glx_finalize; - backend_class->pre_parse = clutter_backend_glx_pre_parse; - backend_class->post_parse = clutter_backend_glx_post_parse; - backend_class->create_stage = clutter_backend_glx_create_stage; - backend_class->add_options = clutter_backend_glx_add_options; - backend_class->get_features = clutter_backend_glx_get_features; - backend_class->redraw = clutter_backend_glx_redraw; + backend_class->pre_parse = clutter_backend_glx_pre_parse; + backend_class->post_parse = clutter_backend_glx_post_parse; + backend_class->create_stage = clutter_backend_glx_create_stage; + backend_class->add_options = clutter_backend_glx_add_options; + backend_class->get_features = clutter_backend_glx_get_features; + backend_class->redraw = clutter_backend_glx_redraw; backend_class->ensure_context = clutter_backend_glx_ensure_context; } static void clutter_backend_glx_init (ClutterBackendGLX *backend_glx) { - ; + } /* every backend must implement this function */ diff --git a/clutter/glx/clutter-stage-glx.c b/clutter/glx/clutter-stage-glx.c index d7eb02b62..82b174a8d 100644 --- a/clutter/glx/clutter-stage-glx.c +++ b/clutter/glx/clutter-stage-glx.c @@ -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 -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; + { + XFree (stage_x11->xvisinfo); + 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; } @@ -169,15 +178,15 @@ clutter_stage_glx_realize (ClutterActor *actor) AllocNone); mask = CWBackPixel | CWBorderPixel | CWColormap; stage_x11->xwin = XCreateWindow (stage_x11->xdpy, - stage_x11->xwin_root, - 0, 0, - stage_x11->xwin_width, - stage_x11->xwin_height, - 0, - stage_x11->xvisinfo->depth, - InputOutput, - stage_x11->xvisinfo->visual, - mask, &xattr); + stage_x11->xwin_root, + 0, 0, + stage_x11->xwin_width, + stage_x11->xwin_height, + 0, + stage_x11->xvisinfo->depth, + InputOutput, + stage_x11->xvisinfo->visual, + mask, &xattr); } CLUTTER_NOTE (MISC, "XSelectInput"); @@ -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,12 +321,12 @@ snapshot_pixbuf_free (guchar *pixels, g_free (pixels); } -static GdkPixbuf* -clutter_stage_glx_draw_to_pixbuf (ClutterStage *stage, - gint x, - gint y, - gint width, - gint height) +static GdkPixbuf * +clutter_stage_glx_draw_to_pixbuf (ClutterStageWindow *stage_window, + gint x, + gint y, + gint width, + gint height) { guchar *data; GdkPixbuf *pixb; @@ -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 */ } diff --git a/clutter/x11/clutter-event-x11.c b/clutter/x11/clutter-event-x11.c index bb5d30157..32a562df8 100644 --- a/clutter/x11/clutter-event-x11.c +++ b/clutter/x11/clutter-event-x11.c @@ -328,11 +328,12 @@ event_translate (ClutterBackend *backend, ClutterEvent *event, XEvent *xevent) { - ClutterBackendX11 *backend_x11; - ClutterStageX11 *stage_x11; - ClutterStage *stage; - gboolean res; - Window xwindow, stage_xwindow; + ClutterBackendX11 *backend_x11; + ClutterStageX11 *stage_x11; + ClutterStage *stage; + ClutterStageWindow *impl; + gboolean res; + Window xwindow, stage_xwindow; backend_x11 = CLUTTER_BACKEND_X11 (backend); @@ -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; diff --git a/clutter/x11/clutter-stage-x11.c b/clutter/x11/clutter-stage-x11.c index bb52d4d0f..c0d945ded 100644 --- a/clutter/x11/clutter-stage-x11.c +++ b/clutter/x11/clutter-stage-x11.c @@ -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 -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); @@ -153,8 +160,8 @@ clutter_stage_x11_set_wm_protocols (ClutterStageX11 *stage_x11) } static void -clutter_stage_x11_query_coords (ClutterActor *self, - ClutterActorBox *box) +clutter_stage_x11_query_coords (ClutterActor *self, + ClutterActorBox *box) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (self); @@ -164,8 +171,8 @@ clutter_stage_x11_query_coords (ClutterActor *self, } static void -clutter_stage_x11_request_coords (ClutterActor *self, - ClutterActorBox *box) +clutter_stage_x11_request_coords (ClutterActor *self, + ClutterActorBox *box) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (self); gint new_width, new_height; @@ -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) { @@ -248,7 +259,7 @@ clutter_stage_x11_set_fullscreen (ClutterStage *stage, width = DisplayWidth (stage_x11->xdpy, stage_x11->xscreen); height = DisplayHeight (stage_x11->xdpy, stage_x11->xscreen); - clutter_actor_set_size (CLUTTER_ACTOR (stage_x11), + clutter_actor_set_size (CLUTTER_ACTOR (stage_x11), width, height); /* FIXME: This wont work if we support more states */ @@ -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, - const gchar *title) +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); } diff --git a/clutter/x11/clutter-stage-x11.h b/clutter/x11/clutter-stage-x11.h index 8f3269190..9d023d04c 100644 --- a/clutter/x11/clutter-stage-x11.h +++ b/clutter/x11/clutter-stage-x11.h @@ -22,7 +22,7 @@ #ifndef __CLUTTER_STAGE_X11_H__ #define __CLUTTER_STAGE_X11_H__ -#include +#include #include #include #include @@ -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,9 +74,8 @@ 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); +void clutter_stage_x11_map (ClutterStageX11 *stage_x11); +void clutter_stage_x11_unmap (ClutterStageX11 *stage_x11); G_END_DECLS diff --git a/tests/test-multistage.c b/tests/test-multistage.c index ac6e7fe9d..9dfbd9af7 100644 --- a/tests/test-multistage.c +++ b/tests/test-multistage.c @@ -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)); */