2008-03-28 Matthew Allum <mallum@openedhand.com>

* clutter/Makefile.am:
        * clutter/clutter-actor.c:
        * clutter/clutter-actor.h:
        * clutter/clutter-backend.c:
        * clutter/clutter-backend.h:
        * clutter/clutter-debug.h:
        * clutter/clutter-event.c:
        * clutter/clutter-event.h:
        * clutter/clutter-feature.h:
        * clutter/clutter-group.h:
        * clutter/clutter-main.c:
        * clutter/clutter-main.h:
        * clutter/clutter-private.h:
        * clutter/clutter-stage.c:
        * clutter/clutter-stage.h:
        * clutter/clutter-stage-manager.c
        * clutter/clutter-stage-manager.h
        * clutter/clutter-types.h:
        * clutter/glx/clutter-backend-glx.c:
        * clutter/glx/clutter-backend-glx.h:
        * clutter/glx/clutter-stage-glx.c:
        * clutter/glx/clutter-stage-glx.h:
        * clutter/x11/clutter-backend-x11.c:
        * clutter/x11/clutter-backend-x11.h:
        * clutter/x11/clutter-event-x11.c:
        * clutter/x11/clutter-stage-x11.c:
        * clutter/x11/clutter-x11.h:
        * tests/Makefile.am:
        * tests/test-multistage.c:
        Initial commit of multi stage support (mostly a merge from the
        clutter-multistage branch).
        Note, this commit will break all backends except glx.
This commit is contained in:
Matthew Allum 2008-03-28 22:50:55 +00:00
parent dd7ff3e829
commit 8847bcd195
30 changed files with 1038 additions and 208 deletions

View File

@ -1,3 +1,38 @@
2008-03-28 Matthew Allum <mallum@openedhand.com>
* clutter/Makefile.am:
* clutter/clutter-actor.c:
* clutter/clutter-actor.h:
* clutter/clutter-backend.c:
* clutter/clutter-backend.h:
* clutter/clutter-debug.h:
* clutter/clutter-event.c:
* clutter/clutter-event.h:
* clutter/clutter-feature.h:
* clutter/clutter-group.h:
* clutter/clutter-main.c:
* clutter/clutter-main.h:
* clutter/clutter-private.h:
* clutter/clutter-stage.c:
* clutter/clutter-stage.h:
* clutter/clutter-stage-manager.c
* clutter/clutter-stage-manager.h
* clutter/clutter-types.h:
* clutter/glx/clutter-backend-glx.c:
* clutter/glx/clutter-backend-glx.h:
* clutter/glx/clutter-stage-glx.c:
* clutter/glx/clutter-stage-glx.h:
* clutter/x11/clutter-backend-x11.c:
* clutter/x11/clutter-backend-x11.h:
* clutter/x11/clutter-event-x11.c:
* clutter/x11/clutter-stage-x11.c:
* clutter/x11/clutter-x11.h:
* tests/Makefile.am:
* tests/test-multistage.c:
Initial commit of multi stage support (mostly a merge from the
clutter-multistage branch).
Note, this commit will break all backends except glx.
2008-03-26 Neil Roberts <neil@o-hand.com>
* clutter/win32/clutter-win32.h: Added gtk-doc documentation for

View File

@ -72,6 +72,7 @@ source_h = \
$(srcdir)/clutter-scriptable.h \
$(srcdir)/clutter-shader.h \
$(srcdir)/clutter-stage.h \
$(srcdir)/clutter-stage-manager.h \
$(srcdir)/clutter-texture.h \
$(srcdir)/clutter-timeline.h \
$(srcdir)/clutter-timeout-pool.h \
@ -159,6 +160,7 @@ source_c = \
clutter-scriptable.c \
clutter-shader.c \
clutter-stage.c \
clutter-stage-manager.c \
clutter-texture.c \
clutter-timeline.c \
clutter-timeout-pool.c \

View File

@ -198,6 +198,8 @@ struct _ClutterActorPrivate
ClutterFixed scale_y;
ShaderData *shader_data;
ClutterStage *stage;
};
enum
@ -278,21 +280,6 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ClutterActor,
static gboolean
redraw_update_idle (gpointer data)
{
ClutterMainContext *ctx = CLUTTER_CONTEXT();
if (ctx->update_idle)
{
g_source_remove (ctx->update_idle);
ctx->update_idle = 0;
}
clutter_redraw ();
return FALSE;
}
static void
clutter_actor_real_show (ClutterActor *self)
@ -423,7 +410,7 @@ clutter_actor_hide_all (ClutterActor *self)
void
clutter_actor_realize (ClutterActor *self)
{
ClutterActorClass *klass;
ClutterActorClass *klass;
if (CLUTTER_ACTOR_IS_REALIZED (self))
return;
@ -447,6 +434,9 @@ void
clutter_actor_unrealize (ClutterActor *self)
{
ClutterActorClass *klass;
ClutterActorPrivate *priv;
priv = self->priv;
if (!CLUTTER_ACTOR_IS_REALIZED (self))
return;
@ -457,6 +447,8 @@ clutter_actor_unrealize (ClutterActor *self)
if (klass->unrealize)
(klass->unrealize) (self);
priv->stage = NULL;
}
static void
@ -910,7 +902,15 @@ clutter_actor_get_relative_vertices (ClutterActor *self,
* Simply duping code for now in wait for Cogl cleanup that can hopefully
* address this in a nicer way.
*/
stage = clutter_stage_get_default ();
stage = clutter_actor_get_stage (self);
/* FIXME: if were not yet added to a stage, its probably unsafe to
* return default - idealy the func should fail.
*/
if (stage == NULL)
stage = clutter_stage_get_default ();
clutter_stage_ensure_current (CLUTTER_STAGE(stage));
if (CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_SYNC_MATRICES)
{
@ -991,7 +991,15 @@ clutter_actor_get_vertices (ClutterActor *self,
* Simply duping code for now in wait for Cogl cleanup that can hopefully
* address this in a nicer way.
*/
stage = clutter_stage_get_default ();
stage = clutter_actor_get_stage (self);
/* FIXME: if were not yet added to a stage, its probably unsafe to
* return default - idealy the func should fail.
*/
if (stage == NULL)
stage = clutter_stage_get_default ();
clutter_stage_ensure_current (CLUTTER_STAGE(stage));
if (CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_SYNC_MATRICES)
{
@ -1146,7 +1154,7 @@ static void
_clutter_actor_apply_modelview_transform_recursive (ClutterActor *self,
ClutterActor *ancestor)
{
ClutterActor * parent;
ClutterActor *parent, *stage;
parent = clutter_actor_get_parent (self);
@ -1158,10 +1166,18 @@ _clutter_actor_apply_modelview_transform_recursive (ClutterActor *self,
if (self == ancestor)
return;
stage = clutter_actor_get_stage (self);
/* FIXME: if were not yet added to a stage, its probably unsafe to
* return default - idealy the func should fail.
*/
if (stage == NULL)
stage = clutter_stage_get_default ();
if (parent)
_clutter_actor_apply_modelview_transform_recursive (parent, ancestor);
else if (self != clutter_stage_get_default ())
_clutter_actor_apply_modelview_transform (clutter_stage_get_default());
else if (self != stage)
_clutter_actor_apply_modelview_transform (stage);
_clutter_actor_apply_modelview_transform (self);
}
@ -2352,14 +2368,6 @@ clutter_actor_destroy (ClutterActor *self)
g_return_if_fail (CLUTTER_IS_ACTOR (self));
if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL)
{
g_warning ("Calling clutter_actor_destroy() on an actor of type `%s' "
"is not possible. This is usually an application bug.",
g_type_name (G_OBJECT_TYPE (self)));
return;
}
priv = self->priv;
if (priv->parent_actor)
@ -2395,17 +2403,13 @@ clutter_actor_destroy (ClutterActor *self)
void
clutter_actor_queue_redraw (ClutterActor *self)
{
ClutterMainContext *ctx = CLUTTER_CONTEXT();
ClutterActor *stage;
if (!ctx->update_idle)
{
CLUTTER_TIMESTAMP (SCHEDULER, "Adding idle source for actor: %p", self);
g_return_if_fail (CLUTTER_IS_ACTOR (self));
ctx->update_idle =
clutter_threads_add_idle_full (G_PRIORITY_DEFAULT + 10,
redraw_update_idle,
NULL, NULL);
}
/* FIXME: should we check we're visible here? */
if ((stage = clutter_actor_get_stage (self)) != NULL)
clutter_stage_queue_redraw (CLUTTER_STAGE(stage));
}
/**
@ -5728,3 +5732,14 @@ clutter_actor_get_box_from_vertices (ClutterVertex vtx[4],
box->y1 = y_1;
box->y2 = y_2;
}
ClutterActor*
clutter_actor_get_stage (ClutterActor *actor)
{
g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
while (actor && !(CLUTTER_PRIVATE_FLAGS (actor) & CLUTTER_ACTOR_IS_TOPLEVEL))
actor = clutter_actor_get_parent (actor);
return actor;
}

View File

@ -487,6 +487,8 @@ gboolean clutter_actor_is_scaled (ClutterActor *self);
void clutter_actor_box_get_from_vertices (ClutterVertex vtx[4],
ClutterActorBox *box);
ClutterActor* clutter_actor_get_stage (ClutterActor *actor);
G_END_DECLS
#endif /* _HAVE_CLUTTER_ACTOR_H */

View File

@ -95,14 +95,6 @@ clutter_backend_init (ClutterBackend *backend)
priv->resolution = -1.0;
}
ClutterActor *
_clutter_backend_get_stage (ClutterBackend *backend)
{
g_return_val_if_fail (CLUTTER_IS_BACKEND (backend), NULL);
return CLUTTER_BACKEND_GET_CLASS (backend)->get_stage (backend);
}
void
_clutter_backend_add_options (ClutterBackend *backend,
GOptionGroup *group)
@ -146,31 +138,65 @@ _clutter_backend_post_parse (ClutterBackend *backend,
return TRUE;
}
gboolean
_clutter_backend_init_stage (ClutterBackend *backend,
GError **error)
ClutterActor*
_clutter_backend_create_stage (ClutterBackend *backend,
GError **error)
{
ClutterMainContext *context;
ClutterBackendClass *klass;
ClutterActor *stage = NULL;
g_return_val_if_fail (CLUTTER_IS_BACKEND (backend), FALSE);
klass = CLUTTER_BACKEND_GET_CLASS (backend);
if (klass->init_stage)
return klass->init_stage (backend, error);
context = clutter_context_get_default ();
return TRUE;
if (!context->stage_manager)
context->stage_manager = clutter_stage_manager_get_default ();
klass = CLUTTER_BACKEND_GET_CLASS (backend);
if (klass->create_stage)
stage = klass->create_stage (backend, error);
if (!stage)
return NULL;
_clutter_stage_manager_add_stage (context->stage_manager,
CLUTTER_STAGE(stage));
return stage;
}
void
_clutter_backend_redraw (ClutterBackend *backend)
_clutter_backend_redraw (ClutterBackend *backend, ClutterStage *stage)
{
ClutterBackendClass *klass;
klass = CLUTTER_BACKEND_GET_CLASS (backend);
if (G_LIKELY(klass->redraw))
klass->redraw (backend);
klass->redraw (backend, stage);
}
void
_clutter_backend_ensure_context (ClutterBackend *backend, ClutterStage *stage)
{
ClutterBackendClass *klass;
static ClutterStage *current_context_stage = NULL;
g_return_if_fail (CLUTTER_IS_BACKEND (backend));
g_return_if_fail (CLUTTER_IS_STAGE (stage));
if (stage != current_context_stage)
{
klass = CLUTTER_BACKEND_GET_CLASS (backend);
if (G_LIKELY(klass->ensure_context))
klass->ensure_context (backend, stage);
current_context_stage = stage;
CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
}
}
ClutterFeatureFlags
_clutter_backend_get_features (ClutterBackend *backend)
{

View File

@ -28,6 +28,7 @@
#include <glib-object.h>
#include <clutter/clutter-actor.h>
#include <clutter/clutter-stage.h>
#include <clutter/clutter-event.h>
#include <clutter/clutter-feature.h>
@ -60,15 +61,17 @@ struct _ClutterBackendClass
GError **error);
gboolean (* post_parse) (ClutterBackend *backend,
GError **error);
gboolean (* init_stage) (ClutterBackend *backend,
ClutterActor *(* create_stage) (ClutterBackend *backend,
GError **error);
void (* init_events) (ClutterBackend *backend);
void (* init_features) (ClutterBackend *backend);
ClutterActor *(* get_stage) (ClutterBackend *backend);
void (* add_options) (ClutterBackend *backend,
GOptionGroup *group);
ClutterFeatureFlags (* get_features) (ClutterBackend *backend);
void (* redraw) (ClutterBackend *backend);
void (* redraw) (ClutterBackend *backend,
ClutterStage *stage);
void (* ensure_context) (ClutterBackend *backend,
ClutterStage *stage);
};
GType clutter_backend_get_type (void) G_GNUC_CONST;

View File

@ -19,7 +19,8 @@ typedef enum {
CLUTTER_DEBUG_BACKEND = 1 << 9,
CLUTTER_DEBUG_SCHEDULER = 1 << 10,
CLUTTER_DEBUG_SCRIPT = 1 << 11,
CLUTTER_DEBUG_SHADER = 1 << 12
CLUTTER_DEBUG_SHADER = 1 << 12,
CLUTTER_DEBUG_MULTISTAGE = 1 << 13
} ClutterDebugFlag;
#ifdef CLUTTER_ENABLE_DEBUG

View File

@ -180,6 +180,25 @@ clutter_event_get_source (ClutterEvent *event)
return event->any.source;
}
/**
* clutter_event_get_stage:
* @event: a #ClutterEvent
*
* Retrieves the source #ClutterStage the event originated for, or
* NULL if the event has no stage.
*
* Return value: a #ClutterStage
*
* Since: 0.8
*/
ClutterStage*
clutter_event_get_stage (ClutterEvent *event)
{
g_return_val_if_fail (event != NULL, NULL);
return event->any.stage;
}
/**
* clutter_button_event_button:
* @buttev: a #ClutterButtonEvent

View File

@ -200,6 +200,7 @@ struct _ClutterAnyEvent
ClutterEventType type;
guint32 time;
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source;
};
@ -223,6 +224,7 @@ struct _ClutterKeyEvent
ClutterEventType type;
guint32 time;
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source;
ClutterModifierType modifier_state;
guint keyval;
@ -254,6 +256,7 @@ struct _ClutterButtonEvent
ClutterEventType type;
guint32 time;
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source;
gint x;
gint y;
@ -269,6 +272,7 @@ struct _ClutterCrossingEvent
ClutterEventType type;
guint32 time;
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source;
gint x;
gint y;
@ -281,6 +285,7 @@ struct _ClutterMotionEvent
ClutterEventType type;
guint32 time;
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source;
gint x;
gint y;
@ -294,6 +299,7 @@ struct _ClutterScrollEvent
ClutterEventType type;
guint32 time;
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source;
gint x;
gint y;
@ -308,6 +314,7 @@ struct _ClutterStageStateEvent
ClutterEventType type;
guint32 time;
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source; /* unused XXX: should probably be the stage itself */
ClutterStageState changed_mask;
ClutterStageState new_state;
@ -351,6 +358,7 @@ guint32 clutter_button_event_button (ClutterButtonEvent *buttev);
guint32 clutter_keysym_to_unicode (guint keyval);
ClutterStage* clutter_event_get_stage (ClutterEvent *event);
G_END_DECLS

View File

@ -48,6 +48,7 @@ G_BEGIN_DECLS
* @CLUTTER_FEATURE_STAGE_CURSOR: Set if stage has a graphical cursor.
* @CLUTTER_FEATURE_SHADERS_GLSL: Set if the backend supports GLSL shaders.
* @CLUTTER_FEATURE_OFFSCREEN: Set if the backend supports offscreen rendering.
* @CLUTTER_FEATURE_STAGE_MULTIPLE: Set if multiple stages are supported.
*
* Runtime flags indicating specific features available via Clutter window
* sysytem and graphics backend.
@ -64,7 +65,8 @@ typedef enum
CLUTTER_FEATURE_STAGE_USER_RESIZE = (1 << 6),
CLUTTER_FEATURE_STAGE_CURSOR = (1 << 7),
CLUTTER_FEATURE_SHADERS_GLSL = (1 << 8),
CLUTTER_FEATURE_OFFSCREEN = (1 << 9)
CLUTTER_FEATURE_OFFSCREEN = (1 << 9),
CLUTTER_FEATURE_STAGE_MULTIPLE = (1 << 10)
} ClutterFeatureFlags;
gboolean clutter_feature_available (ClutterFeatureFlags feature);

View File

@ -27,6 +27,7 @@
#define __CLUTTER_GROUP_H__
#include <glib-object.h>
#include <clutter/clutter-types.h>
#include <clutter/clutter-actor.h>
G_BEGIN_DECLS

View File

@ -82,6 +82,7 @@ static const GDebugKey clutter_debug_keys[] = {
{ "scheduler", CLUTTER_DEBUG_SCHEDULER },
{ "script", CLUTTER_DEBUG_SCRIPT },
{ "shader", CLUTTER_DEBUG_SHADER },
{ "multistage", CLUTTER_DEBUG_MULTISTAGE },
};
#endif /* CLUTTER_ENABLE_DEBUG */
@ -111,22 +112,21 @@ clutter_get_show_fps (void)
* function, but queue a redraw using clutter_actor_queue_redraw().
*/
void
clutter_redraw (void)
clutter_redraw (ClutterStage *stage)
{
ClutterMainContext *ctx;
ClutterActor *stage;
static GTimer *timer = NULL;
static guint timer_n_frames = 0;
ctx = clutter_context_get_default ();
stage = _clutter_backend_get_stage (ctx->backend);
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_TIMESTAMP (SCHEDULER, "Redraw start");
_clutter_backend_ensure_context (ctx->backend, stage);
CLUTTER_NOTE (PAINT, " Redraw enter");
/* Setup FPS count */
/* Setup FPS count - not currently across *all* stages rather than per */
if (clutter_get_show_fps ())
{
if (!timer)
@ -142,8 +142,8 @@ clutter_redraw (void)
clutter_stage_get_perspectivex (CLUTTER_STAGE (stage), &perspective);
cogl_setup_viewport (clutter_actor_get_width (stage),
clutter_actor_get_height (stage),
cogl_setup_viewport (clutter_actor_get_width (CLUTTER_ACTOR(stage)),
clutter_actor_get_height (CLUTTER_ACTOR(stage)),
perspective.fovy,
perspective.aspect,
perspective.z_near,
@ -156,7 +156,7 @@ clutter_redraw (void)
* the stage. It will likely need to swap buffers, vblank sync etc
* which will be windowing system dependant.
*/
_clutter_backend_redraw (ctx->backend);
_clutter_backend_redraw (ctx->backend, stage);
/* Complete FPS info */
if (clutter_get_show_fps ())
@ -171,9 +171,8 @@ clutter_redraw (void)
}
}
CLUTTER_NOTE (PAINT, " Redraw leave");
CLUTTER_TIMESTAMP (SCHEDULER, "Redraw finish");
CLUTTER_NOTE (PAINT, " Redraw leave for stage:%p", stage);
CLUTTER_TIMESTAMP (SCHEDULER, "Redraw finish for stage:%p", stage);
}
/**
@ -233,6 +232,27 @@ _clutter_do_pick (ClutterStage *stage,
context = clutter_context_get_default ();
_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);
}
cogl_paint_init (&white);
cogl_enable (0);
@ -259,7 +279,7 @@ _clutter_do_pick (ClutterStage *stage,
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);
@ -969,6 +989,7 @@ clutter_init_with_args (int *argc,
GOptionGroup *group;
gboolean res;
GError *stage_error;
ClutterActor *stage;
if (clutter_is_initialized)
return CLUTTER_INIT_SUCCESS;
@ -998,7 +1019,10 @@ clutter_init_with_args (int *argc,
clutter_context = clutter_context_get_default ();
stage_error = NULL;
if (!_clutter_backend_init_stage (clutter_context->backend, &stage_error))
stage = _clutter_backend_create_stage (clutter_context->backend,
&stage_error);
if (!stage)
{
g_propagate_error (error, stage_error);
return CLUTTER_INIT_ERROR_INTERNAL;
@ -1064,6 +1088,7 @@ clutter_init (int *argc,
char ***argv)
{
ClutterMainContext *context;
ClutterActor *stage;
GError *stage_error;
if (clutter_is_initialized)
@ -1091,7 +1116,10 @@ clutter_init (int *argc,
/* Stage will give us a GL Context etc */
stage_error = NULL;
if (!_clutter_backend_init_stage (context->backend, &stage_error))
stage = _clutter_backend_create_stage (context->backend, &stage_error);
if (!stage)
{
CLUTTER_NOTE (MISC, "stage failed to initialise.");
g_critical (stage_error->message);
@ -1165,7 +1193,9 @@ event_click_count_generate (ClutterEvent *event)
previous_button_number = event->button.button;
}
/* store time and position for this click for comparison with next event */
/* store time and position for this click for comparison with
* next event
*/
previous_time = event->button.time;
previous_x = event->button.x;
previous_y = event->button.y;
@ -1301,6 +1331,7 @@ generate_enter_leave_events (ClutterEvent *event)
cev.crossing.x = event->motion.x;
cev.crossing.y = event->motion.y;
cev.crossing.source = context->motion_last_actor;
cev.crossing.stage = event->any.stage;
/* unref in free */
cev.crossing.related = motion_current_actor;
@ -1314,6 +1345,7 @@ generate_enter_leave_events (ClutterEvent *event)
cev.crossing.x = event->motion.x;
cev.crossing.y = event->motion.y;
cev.crossing.source = motion_current_actor;
cev.crossing.stage = event->any.stage;
if (context->motion_last_actor)
cev.crossing.related = context->motion_last_actor;
@ -1371,7 +1403,7 @@ clutter_do_event (ClutterEvent *event)
context = clutter_context_get_default ();
backend = context->backend;
stage = _clutter_backend_get_stage (backend);
stage = CLUTTER_ACTOR(event->any.stage);
if (!stage)
return;
@ -1394,7 +1426,13 @@ clutter_do_event (ClutterEvent *event)
event->any.source = stage;
/* the stage did not handle the event, so we just quit */
if (!clutter_stage_event (CLUTTER_STAGE (stage), event))
clutter_main_quit ();
{
if (stage == clutter_stage_get_default())
clutter_main_quit ();
else
clutter_actor_destroy (stage);
}
break;
case CLUTTER_KEY_PRESS:

View File

@ -72,7 +72,7 @@ void clutter_main (void);
void clutter_main_quit (void);
gint clutter_main_level (void);
void clutter_redraw (void);
void clutter_redraw (ClutterStage *stage);
void clutter_do_event (ClutterEvent *event);

View File

@ -40,6 +40,7 @@
#include <pango/pangoft2.h>
#include "clutter-stage-manager.h"
#include "clutter-event.h"
#include "clutter-backend.h"
#include "clutter-stage.h"
@ -72,28 +73,33 @@ struct _ClutterMainContext
{
ClutterBackend *backend; /* holds a pointer to the windowing
system backend */
ClutterStageManager *stage_manager; /* stages */
GQueue *events_queue; /* the main event queue */
PangoFT2FontMap *font_map;
guint update_idle; /* repaint idler id */
guint is_initialized : 1;
GTimer *timer; /* Used for debugging scheduler */
ClutterPickMode pick_mode; /* Indicates pick render mode */
guint motion_events_per_actor : 1;/* set for enter/leave events */
guint motion_events_per_actor : 1;/* set f
or enter/leave events */
guint motion_frequency; /* Motion events per second */
gint num_reactives; /* Num of reactive actors */
ClutterIDPool *id_pool; /* mapping between reused integer ids and actors */
ClutterIDPool *id_pool; /* mapping between reused integer ids
* and actors
*/
guint frame_rate; /* Default FPS */
ClutterActor *pointer_grab_actor; /* The actor having the pointer grab
(or NULL if there is no pointer grab)
* (or NULL if there is no pointer grab
*/
ClutterActor *keyboard_grab_actor; /* The actor having the pointer grab
(or NULL if there is no pointer grab)
*/
* (or NULL if there is no pointer
* grab)
*/
GSList *shaders; /* stack of overridden shaders */
ClutterActor *motion_last_actor;
@ -115,13 +121,32 @@ ClutterMainContext *clutter_context_get_default (void);
#define I_(str) (g_intern_static_string ((str)))
/* stage manager */
struct _ClutterStageManager
{
GObject parent_instance;
GSList *stages;
};
void _clutter_stage_manager_add_stage (ClutterStageManager *stage_manager,
ClutterStage *stage);
void _clutter_stage_manager_remove_stage (ClutterStageManager *stage_manager,
ClutterStage *stage);
/* vfuncs implemnted by backend */
GType _clutter_backend_impl_get_type (void);
ClutterActor *_clutter_backend_get_stage (ClutterBackend *backend);
void _clutter_backend_redraw (ClutterBackend *backend,
ClutterStage *stage);
void _clutter_backend_redraw (ClutterBackend *backend);
ClutterActor* _clutter_backend_create_stage (ClutterBackend *backend,
GError **error);
void _clutter_backend_redraw (ClutterBackend *backend,
ClutterStage *stage);
void _clutter_backend_add_options (ClutterBackend *backend,
GOptionGroup *group);
@ -129,10 +154,11 @@ gboolean _clutter_backend_pre_parse (ClutterBackend *backend,
GError **error);
gboolean _clutter_backend_post_parse (ClutterBackend *backend,
GError **error);
gboolean _clutter_backend_init_stage (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

@ -0,0 +1,282 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "clutter-marshal.h"
#include "clutter-debug.h"
#include "clutter-private.h"
#include "clutter-version.h"
#include "clutter-stage-manager.h"
enum
{
PROP_0,
PROP_DEFAULT_STAGE
};
enum
{
STAGE_ADDED,
STAGE_REMOVED,
LAST_SIGNAL
};
static guint manager_signals[LAST_SIGNAL] = { 0, };
static ClutterStage *default_stage = NULL;
G_DEFINE_TYPE (ClutterStageManager, clutter_stage_manager, G_TYPE_OBJECT);
static void
clutter_stage_manager_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
switch (prop_id)
{
case PROP_DEFAULT_STAGE:
clutter_stage_manager_set_default_stage (CLUTTER_STAGE_MANAGER (gobject),
g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
clutter_stage_manager_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
switch (prop_id)
{
case PROP_DEFAULT_STAGE:
g_value_set_object (value, default_stage);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
clutter_stage_manager_dispose (GObject *gobject)
{
ClutterStageManager *stage_manager;
GSList *l;
stage_manager = CLUTTER_STAGE_MANAGER (gobject);
for (l = stage_manager->stages; l; l = l->next)
{
ClutterActor *stage = l->data;
if (stage)
clutter_actor_destroy (stage);
}
g_slist_free (stage_manager->stages);
stage_manager->stages = NULL;
G_OBJECT_CLASS (clutter_stage_manager_parent_class)->dispose (gobject);
}
static void
clutter_stage_manager_class_init (ClutterStageManagerClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = clutter_stage_manager_dispose;
gobject_class->set_property = clutter_stage_manager_set_property;
gobject_class->get_property = clutter_stage_manager_get_property;
/**
* ClutterStageManager:default-stage:
*
* The default stage used by Clutter.
*
* Since: 0.8
*/
g_object_class_install_property (gobject_class,
PROP_DEFAULT_STAGE,
g_param_spec_object ("default-stage",
"Default Stage",
"The default stage",
CLUTTER_TYPE_STAGE,
CLUTTER_PARAM_READWRITE));
/**
* ClutterStageManager:stage-added:
* @stage_manager: the object which received the signal
* @stage: the added stage
*
* The ::stage-added signal is emitted each time a new #ClutterStage
* has been added to the stage manager.
*
* Since: 0.8
*/
manager_signals[STAGE_ADDED] =
g_signal_new ("stage-added",
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterStageManagerClass, stage_added),
NULL, NULL,
clutter_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
CLUTTER_TYPE_STAGE);
/**
* ClutterStageManager::stage-removed:
* @stage_manager: the object which received the signal
* @stage: the removed stage
*
* The ::stage-removed signal is emitted each time a #ClutterStage
* has been removed from the stage manager.
*
* Since: 0.8
*/
manager_signals[STAGE_REMOVED] =
g_signal_new ("stage-removed",
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterStageManagerClass, stage_removed),
NULL, NULL,
clutter_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
CLUTTER_TYPE_STAGE);
}
static void
clutter_stage_manager_init (ClutterStageManager *stage_manager)
{
}
/**
* clutter_stage_manager_get_default:
*
* Returns the default #ClutterStageManager.
*
* Return value: the default stage manager instance. The returned object
* is owned by Clutter and you should not reference or unreference it.
*
* Since: 0.8
*/
ClutterStageManager *
clutter_stage_manager_get_default (void)
{
static ClutterStageManager *stage_manager = NULL;
if (G_UNLIKELY (stage_manager == NULL))
stage_manager = g_object_new (CLUTTER_TYPE_STAGE_MANAGER, NULL);
return stage_manager;
}
/**
* clutter_stage_manager_set_default_stage:
* @stage_manager: a #ClutterStageManager
* @stage: a #ClutterStage
*
* Sets @stage as the default stage.
*
* Since: 0.8
*/
void
clutter_stage_manager_set_default_stage (ClutterStageManager *stage_manager,
ClutterStage *stage)
{
g_return_if_fail (CLUTTER_IS_STAGE_MANAGER (stage_manager));
g_return_if_fail (CLUTTER_IS_STAGE (stage));
if (!g_slist_find (stage_manager->stages, stage))
_clutter_stage_manager_add_stage (stage_manager, stage);
default_stage = stage;
g_object_notify (G_OBJECT (stage_manager), "default-stage");
}
/**
* clutter_stage_manager_get_default_stage:
* @stage_manager: a #ClutterStageManager
*
* Returns the default #ClutterStage.
*
* Return value: the default stage. The returned object is owned by
* Clutter and you should never reference or unreference it
*
* Since: 0.8
*/
ClutterStage *
clutter_stage_manager_get_default_stage (ClutterStageManager *stage_manager)
{
return default_stage;
}
/**
* clutter_stage_manager_list_stage:
* @stage_manager: a #ClutterStageManager
*
* Lists all currently used stages.
*
* Return value: a newly allocated list of #ClutterStage objects. Use
* g_slist_free() to deallocate it when done.
*
* Since: 0.8
*/
GSList *
clutter_stage_manager_list_stages (ClutterStageManager *stage_manager)
{
return g_slist_copy (stage_manager->stages);
}
void
_clutter_stage_manager_add_stage (ClutterStageManager *stage_manager,
ClutterStage *stage)
{
if (g_slist_find (stage_manager->stages, stage))
{
g_warning ("Trying to add a stage to the list of managed stages, "
"but it is already in it, aborting.");
return;
}
g_object_ref_sink (stage);
stage_manager->stages = g_slist_append (stage_manager->stages, stage);
if (!default_stage)
{
default_stage = stage;
g_object_notify (G_OBJECT (stage_manager), "default-stage");
}
g_signal_emit (stage_manager, manager_signals[STAGE_ADDED], 0, stage);
}
void
_clutter_stage_manager_remove_stage (ClutterStageManager *stage_manager,
ClutterStage *stage)
{
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);
/* if it's the default stage, get the first available from the list */
if (default_stage == stage)
default_stage = stage_manager->stages ? stage_manager->stages->data
: NULL;
g_signal_emit (stage_manager, manager_signals[STAGE_REMOVED], 0, stage);
g_object_unref (stage);
}

View File

@ -0,0 +1,65 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2008 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __CLUTTER_STAGE_MANAGER_H__
#define __CLUTTER_STAGE_MANAGER_H__
#include <glib.h>
#include <glib-object.h>
#include <clutter/clutter-stage.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_STAGE_MANAGER (clutter_stage_manager_get_type ())
#define CLUTTER_STAGE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE_MANAGER, ClutterStageManager))
#define CLUTTER_IS_STAGE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STAGE_MANAGER))
#define CLUTTER_STAGE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_STAGE_MANAGER, ClutterStageManagerClass))
#define CLUTTER_IS_STAGE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_STAGE_MANAGER))
#define CLUTTER_STAGE_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_STAGE_MANAGER, ClutterStageManagerClass))
typedef struct _ClutterStageManager ClutterStageManager;
typedef struct _ClutterStageManagerClass ClutterStageManagerClass;
struct _ClutterStageManagerClass
{
GObjectClass parent_class;
void (* stage_added) (ClutterStageManager *stage_manager,
ClutterStage *stage);
void (* stage_removed) (ClutterStageManager *stage_manager,
ClutterStage *stage);
};
GType clutter_stage_manager_get_type (void) G_GNUC_CONST;
ClutterStageManager *clutter_stage_manager_get_default (void);
void clutter_stage_manager_set_default_stage (ClutterStageManager *stage_manager,
ClutterStage *stage);
ClutterStage * clutter_stage_manager_get_default_stage (ClutterStageManager *stage_manager);
GSList * clutter_stage_manager_list_stages (ClutterStageManager *stage_manager);
G_END_DECLS
#endif /* __CLUTTER_STAGE_MANAGER_H__ */

View File

@ -44,7 +44,9 @@
#include "clutter-enum-types.h"
#include "clutter-private.h"
#include "clutter-debug.h"
#include "clutter-stage-manager.h"
#include "clutter-version.h" /* For flavour */
#include "clutter-id-pool.h"
#include "cogl.h"
@ -67,6 +69,8 @@ struct _ClutterStagePrivate
gchar *title;
ClutterActor *key_focused_actor;
guint update_idle; /* repaint idler id */
};
enum
@ -469,12 +473,9 @@ clutter_stage_init (ClutterStage *self)
ClutterActor *
clutter_stage_get_default (void)
{
ClutterMainContext *context;
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
context = clutter_context_get_default ();
g_assert (context != NULL);
return _clutter_backend_get_stage (context->backend);
return CLUTTER_ACTOR(clutter_stage_manager_get_default_stage(stage_manager));
}
/**
@ -1349,3 +1350,115 @@ clutter_fog_get_type (void)
return our_type;
}
/**
* clutter_stage_create_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
* exactly like the default stage, but while clutter_stage_get_default()
* will always return the same instance, you will have to keep a pointer
* to any #ClutterStage returned by clutter_stage_create().
*
* The ability to support multiple stages depends on the current
* backend. Use clutter_feature_available() and
* %CLUTTER_FEATURE_STAGE_MULTIPLE to check at runtime whether a
* backend supports multiple stages.
*
* 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.
*
* Since: 0.8
*/
ClutterActor*
clutter_stage_create_new (void)
{
ClutterBackend *backend = clutter_get_default_backend ();
GError *error = NULL;
ClutterActor *retval;
if (!clutter_feature_available (CLUTTER_FEATURE_STAGE_MULTIPLE))
{
g_warning ("Unable to create a new stage: the %s backend does not "
"support multiple stages.",
CLUTTER_FLAVOUR);
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;
}
return retval;
}
/**
* clutter_stage_ensure_current:
* @stage: the #ClutterStage
*
* This function essentially makes sure the right GL context is
* current for the passed stage. It is not intended to
* be used by applications.
*
* Since: 0.8
*/
void
clutter_stage_ensure_current (ClutterStage *stage)
{
ClutterMainContext *ctx;
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)
{
ClutterStage *stage = CLUTTER_STAGE(data);
if (stage->priv->update_idle)
{
g_source_remove (stage->priv->update_idle);
stage->priv->update_idle = 0;
}
CLUTTER_NOTE (MULTISTAGE, "redrawing via idle for stage:%p", stage);
clutter_redraw (stage);
return FALSE;
}
/**
* clutter_stage_queue_redraw:
* @stage: the #ClutterStage
*
* Queues a redraw for the passed stage. Note applications should call
* #clutter_actor_queue_redraw over this.
*
* Since: 0.8
*/
void
clutter_stage_queue_redraw (ClutterStage *stage)
{
g_return_if_fail (CLUTTER_IS_STAGE (stage));
if (!stage->priv->update_idle)
{
CLUTTER_TIMESTAMP (SCHEDULER, "Adding idle source for stage: %p", stage);
/* FIXME: weak_ref self in case we dissapear before paint? */
stage->priv->update_idle =
clutter_threads_add_idle_full (G_PRIORITY_DEFAULT + 10,
redraw_update_idle,
stage,
NULL);
}
}

View File

@ -26,6 +26,7 @@
#ifndef __CLUTTER_STAGE_H__
#define __CLUTTER_STAGE_H__
#include <clutter/clutter-types.h>
#include <clutter/clutter-group.h>
#include <clutter/clutter-color.h>
#include <clutter/clutter-event.h>
@ -80,7 +81,7 @@ G_BEGIN_DECLS
typedef struct _ClutterPerspective ClutterPerspective;
typedef struct _ClutterFog ClutterFog;
typedef struct _ClutterStage ClutterStage;
typedef struct _ClutterStageClass ClutterStageClass;
typedef struct _ClutterStagePrivate ClutterStagePrivate;
@ -237,6 +238,12 @@ void clutter_stage_set_key_focus (ClutterStage *stage,
ClutterActor *actor);
ClutterActor * clutter_stage_get_key_focus (ClutterStage *stage);
ClutterActor* clutter_stage_create_new (void);
void clutter_stage_ensure_current (ClutterStage *stage);
void clutter_stage_queue_redraw (ClutterStage *stage);
/* Commodity macro */
#define clutter_stage_add(stage,actor) G_STMT_START { \
if (CLUTTER_IS_STAGE ((stage)) && CLUTTER_IS_ACTOR ((actor))) \

View File

@ -39,6 +39,7 @@ G_BEGIN_DECLS
/* Forward delarations to avoid header catch 22's */
typedef struct _ClutterActor ClutterActor;
typedef struct _ClutterStage ClutterStage;
/**
* ClutterGravity:

View File

@ -213,7 +213,7 @@ clutter_backend_glx_get_features (ClutterBackend *backend)
{
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
const gchar *glx_extensions = NULL;
ClutterFeatureFlags flags = 0;
ClutterFeatureFlags flags = CLUTTER_FEATURE_STAGE_MULTIPLE;
/* FIXME: we really need to check if gl context is set */
@ -343,14 +343,32 @@ clutter_backend_glx_get_features (ClutterBackend *backend)
}
static void
clutter_backend_glx_redraw (ClutterBackend *backend)
clutter_backend_glx_ensure_context (ClutterBackend *backend,
ClutterStage *stage)
{
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
ClutterBackendGLX *backend_glx;
ClutterStageGLX *stage_glx;
ClutterStageX11 *stage_x11;
stage_x11 = CLUTTER_STAGE_X11(backend_x11->stage);
stage_glx = CLUTTER_STAGE_GLX(backend_x11->stage);
stage_x11 = CLUTTER_STAGE_X11(stage);
stage_glx = CLUTTER_STAGE_GLX(stage);
backend_glx = CLUTTER_BACKEND_GLX(backend);
CLUTTER_NOTE (MULTISTAGE, "setting context for stage:%p", stage );
glXMakeCurrent (stage_x11->xdpy,
stage_x11->xwin,
backend_glx->gl_context);
}
static void
clutter_backend_glx_redraw (ClutterBackend *backend, ClutterStage *stage)
{
ClutterStageGLX *stage_glx;
ClutterStageX11 *stage_x11;
stage_x11 = CLUTTER_STAGE_X11(stage);
stage_glx = CLUTTER_STAGE_GLX(stage);
clutter_actor_paint (CLUTTER_ACTOR (stage_glx));
@ -370,47 +388,42 @@ clutter_backend_glx_redraw (ClutterBackend *backend)
}
}
gboolean
clutter_backend_glx_init_stage (ClutterBackend *backend,
GError **error)
ClutterActor*
clutter_backend_glx_create_stage (ClutterBackend *backend,
GError **error)
{
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
ClutterStageX11 *stage_x11;
ClutterActor *stage;
if (!backend_x11->stage)
{
ClutterStageX11 *stage_x11;
ClutterActor *stage;
stage = g_object_new (CLUTTER_TYPE_STAGE_GLX, NULL);
stage = g_object_new (CLUTTER_TYPE_STAGE_GLX, 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;
/* 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);
CLUTTER_NOTE (MISC, "X11 stage created (display:%p, screen:%d, root:%u)",
stage_x11->xdpy,
stage_x11->xscreen,
(unsigned int) stage_x11->xwin_root);
/* needed ? */
g_object_set_data (G_OBJECT (stage), "clutter-backend", backend);
g_object_set_data (G_OBJECT (stage), "clutter-backend", backend);
clutter_actor_realize (stage);
backend_x11->stage = g_object_ref_sink (stage);
}
clutter_actor_realize (backend_x11->stage);
if (!CLUTTER_ACTOR_IS_REALIZED (backend_x11->stage))
if (!CLUTTER_ACTOR_IS_REALIZED (stage))
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_INTERNAL,
"Unable to realize the main stage");
return FALSE;
return NULL;
}
return TRUE;
return stage;
}
@ -421,15 +434,16 @@ clutter_backend_glx_class_init (ClutterBackendGLXClass *klass)
ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
gobject_class->constructor = clutter_backend_glx_constructor;
gobject_class->dispose = clutter_backend_glx_dispose;
gobject_class->finalize = clutter_backend_glx_finalize;
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->init_stage = clutter_backend_glx_init_stage;
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

View File

@ -72,6 +72,9 @@ struct _ClutterBackendGLX
{
ClutterBackendX11 parent_instance;
/* Single context for all wins */
GLXContext gl_context;
/* Vblank stuff */
GetVideoSyncProc get_video_sync;
WaitVideoSyncProc wait_video_sync;

View File

@ -39,6 +39,7 @@
#include "../clutter-shader.h"
#include "../clutter-group.h"
#include "../clutter-container.h"
#include "../clutter-stage.h"
#include "cogl.h"
@ -98,12 +99,6 @@ clutter_stage_glx_unrealize (ClutterActor *actor)
glXMakeCurrent (stage_x11->xdpy, None, NULL);
if (stage_glx->gl_context != None)
{
glXDestroyContext (stage_x11->xdpy, stage_glx->gl_context);
stage_glx->gl_context = None;
}
XSync (stage_x11->xdpy, False);
clutter_x11_untrap_x_errors ();
@ -116,12 +111,15 @@ clutter_stage_glx_realize (ClutterActor *actor)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (actor);
gboolean is_offscreen;
ClutterBackendGLX *backend_glx;
gboolean is_offscreen;
CLUTTER_NOTE (MISC, "Realizing main stage");
g_object_get (actor, "offscreen", &is_offscreen, NULL);
backend_glx = CLUTTER_BACKEND_GLX(clutter_get_default_backend());
if (G_LIKELY (!is_offscreen))
{
int gl_attributes[] =
@ -142,7 +140,7 @@ clutter_stage_glx_realize (ClutterActor *actor)
/* The following check seems strange */
if (stage_x11->xvisinfo == None)
stage_x11->xvisinfo = glXChooseVisual (stage_x11->xdpy,
stage_x11->xscreen,
stage_x11->xscreen,
gl_attributes);
if (!stage_x11->xvisinfo)
{
@ -195,26 +193,27 @@ clutter_stage_glx_realize (ClutterActor *actor)
clutter_stage_x11_set_wm_protocols (stage_x11);
if (stage_glx->gl_context)
glXDestroyContext (stage_x11->xdpy, stage_glx->gl_context);
CLUTTER_NOTE (GL, "Creating GL Context");
stage_glx->gl_context = glXCreateContext (stage_x11->xdpy,
stage_x11->xvisinfo,
0,
True);
if (stage_glx->gl_context == None)
if (backend_glx->gl_context == None)
{
g_critical ("Unable to create suitable GL context.");
CLUTTER_NOTE (GL, "Creating GL Context");
backend_glx->gl_context = glXCreateContext (stage_x11->xdpy,
stage_x11->xvisinfo,
0,
True);
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
if (backend_glx->gl_context == None)
{
g_critical ("Unable to create suitable GL context.");
return;
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
}
}
CLUTTER_NOTE (GL, "glXMakeCurrent");
glXMakeCurrent (stage_x11->xdpy, stage_x11->xwin, stage_glx->gl_context);
clutter_stage_ensure_current (CLUTTER_STAGE(stage_glx));
}
else
{
@ -244,9 +243,7 @@ clutter_stage_glx_realize (ClutterActor *actor)
goto fail;
}
if (stage_glx->gl_context)
glXDestroyContext (stage_x11->xdpy, stage_glx->gl_context);
stage_x11->xpixmap = XCreatePixmap (stage_x11->xdpy,
stage_x11->xwin_root,
stage_x11->xwin_width,
@ -258,17 +255,34 @@ clutter_stage_glx_realize (ClutterActor *actor)
stage_x11->xvisinfo,
stage_x11->xpixmap);
/* indirect */
stage_glx->gl_context = glXCreateContext (stage_x11->xdpy,
stage_x11->xvisinfo,
0,
False);
if (backend_glx->gl_context == None)
{
CLUTTER_NOTE (GL, "Creating GL Context");
/* FIXME: we probably need a seperate offscreen context here
* - though it likely makes most sense to drop offscreen stages
* and rely on FBO's instead and GLXPixmaps seems mostly broken
* anyway..
*/
backend_glx->gl_context = glXCreateContext (stage_x11->xdpy,
stage_x11->xvisinfo,
0,
False);
if (backend_glx->gl_context == None)
{
g_critical ("Unable to create suitable GL context.");
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
}
}
clutter_x11_trap_x_errors ();
glXMakeCurrent (stage_x11->xdpy,
stage_glx->glxpixmap,
stage_glx->gl_context);
/* below will call glxMakeCurrent */
clutter_stage_ensure_current (CLUTTER_STAGE(stage_glx));
if (clutter_x11_untrap_x_errors ())
{

View File

@ -49,7 +49,6 @@ struct _ClutterStageGLX
ClutterStageX11 parent_instance;
GLXPixmap glxpixmap;
GLXContext gl_context;
};
struct _ClutterStageGLXClass

View File

@ -192,14 +192,6 @@ clutter_backend_x11_init_events (ClutterBackend *backend)
_clutter_backend_x11_events_init (backend);
}
ClutterActor *
clutter_backend_x11_get_stage (ClutterBackend *backend)
{
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
return backend_x11->stage;
}
static const GOptionEntry entries[] =
{
{
@ -247,19 +239,20 @@ clutter_backend_x11_finalize (GObject *gobject)
static void
clutter_backend_x11_dispose (GObject *gobject)
{
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (gobject);
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (gobject);
ClutterMainContext *context;
ClutterStageManager *stage_manager;
GSList *l;
if (backend_x11->stage)
CLUTTER_NOTE (BACKEND, "Disposing the of stages");
context = clutter_context_get_default ();
stage_manager = context->stage_manager;
for (l = stage_manager->stages; l; l = l->next)
{
CLUTTER_NOTE (BACKEND, "Disposing the main stage");
/* we unset the private flag on the stage so we can safely
* destroy it without a warning from clutter_actor_destroy()
*/
CLUTTER_UNSET_PRIVATE_FLAGS (backend_x11->stage,
CLUTTER_ACTOR_IS_TOPLEVEL);
clutter_actor_destroy (backend_x11->stage);
backend_x11->stage = NULL;
ClutterActor *stage = CLUTTER_ACTOR (l->data);
clutter_actor_destroy (stage);
}
CLUTTER_NOTE (BACKEND, "Removing the event source");
@ -314,10 +307,9 @@ clutter_backend_x11_class_init (ClutterBackendX11Class *klass)
gobject_class->dispose = clutter_backend_x11_dispose;
gobject_class->finalize = clutter_backend_x11_finalize;
backend_class->pre_parse = clutter_backend_x11_pre_parse;
backend_class->pre_parse = clutter_backend_x11_pre_parse;
backend_class->post_parse = clutter_backend_x11_post_parse;
backend_class->init_events = clutter_backend_x11_init_events;
backend_class->get_stage = clutter_backend_x11_get_stage;
backend_class->add_options = clutter_backend_x11_add_options;
backend_class->get_features = clutter_backend_x11_get_features;
}

View File

@ -53,9 +53,6 @@ struct _ClutterBackendX11
{
ClutterBackend parent_instance;
/* main stage singleton */
ClutterActor *stage;
Display *xdpy;
Window xwin_root;
Screen *xscreen;

View File

@ -158,7 +158,6 @@ void
_clutter_backend_x11_events_init (ClutterBackend *backend)
{
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
ClutterStage *stage = CLUTTER_STAGE (backend_x11->stage);
GSource *source;
ClutterEventSource *event_source;
int connection_number;
@ -182,9 +181,6 @@ _clutter_backend_x11_events_init (ClutterBackend *backend)
g_source_set_can_recurse (source, TRUE);
g_source_attach (source, NULL);
xembed_set_info (backend_x11,
clutter_x11_get_stage_window (stage),
0);
}
void
@ -243,14 +239,13 @@ translate_key_event (ClutterBackend *backend,
static gboolean
handle_wm_protocols_event (ClutterBackendX11 *backend_x11,
Window window,
XEvent *xevent)
{
Atom atom = (Atom) xevent->xclient.data.l[0];
ClutterStage *stage = CLUTTER_STAGE (backend_x11->stage);
Window stage_xwindow = clutter_x11_get_stage_window (stage);
if (atom == backend_x11->atom_WM_DELETE_WINDOW &&
xevent->xany.window == stage_xwindow)
xevent->xany.window == window)
{
/* the WM_DELETE_WINDOW is a request: we do not destroy
* the window right away, as it might contain vital data;
@ -261,13 +256,13 @@ handle_wm_protocols_event (ClutterBackendX11 *backend_x11,
xevent->xclient.window);
set_user_time (backend_x11,
&stage_xwindow,
&window,
xevent->xclient.data.l[1]);
return TRUE;
}
else if (atom == backend_x11->atom_NET_WM_PING &&
xevent->xany.window == stage_xwindow)
xevent->xany.window == window)
{
XClientMessageEvent xclient = xevent->xclient;
@ -289,7 +284,7 @@ handle_xembed_event (ClutterBackendX11 *backend_x11,
{
ClutterActor *stage;
stage = _clutter_backend_get_stage (CLUTTER_BACKEND (backend_x11));
stage = clutter_stage_get_default ();
switch (xevent->xclient.data.l[1])
{
@ -340,9 +335,6 @@ event_translate (ClutterBackend *backend,
Window xwindow, stage_xwindow;
backend_x11 = CLUTTER_BACKEND_X11 (backend);
stage = CLUTTER_STAGE (_clutter_backend_get_stage (backend));
stage_x11 = CLUTTER_STAGE_X11 (stage);
stage_xwindow = clutter_x11_get_stage_window (stage);
xwindow = xevent->xany.window;
@ -378,9 +370,16 @@ event_translate (ClutterBackend *backend,
* (the x11 filters might be getting events for other windows, so do not
* mess them about.
*/
if (xwindow != stage_xwindow)
stage = clutter_x11_get_stage_from_window (xwindow);
if (stage == NULL)
return FALSE;
stage_x11 = CLUTTER_STAGE_X11 (stage);
stage_xwindow = xwindow; /* clutter_x11_get_stage_window (stage); */
event->any.stage = stage;
res = TRUE;
switch (xevent->type)
@ -514,7 +513,8 @@ event_translate (ClutterBackend *backend,
/* FIXME: need to make stage an 'actor' so can que
* a paint direct from there rather than hack here...
*/
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
CLUTTER_NOTE (MULTISTAGE, "expose for stage:%p, redrawing", stage);
clutter_redraw (stage);
res = FALSE;
}
break;
@ -614,7 +614,7 @@ event_translate (ClutterBackend *backend,
res = handle_xembed_event (backend_x11, xevent);
else if (xevent->xclient.message_type == backend_x11->atom_WM_PROTOCOLS)
{
res = handle_wm_protocols_event (backend_x11, xevent);
res = handle_wm_protocols_event (backend_x11, stage_xwindow, xevent);
event->type = event->any.type = CLUTTER_DELETE;
}
break;

View File

@ -117,7 +117,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_redraw(CLUTTER_STAGE(actor));
XSync (stage_x11->xdpy, FALSE);
XMapWindow (stage_x11->xdpy, stage_x11->xwin);
@ -447,6 +447,39 @@ clutter_x11_get_stage_window (ClutterStage *stage)
return CLUTTER_STAGE_X11 (stage)->xwin;
}
/**
* clutter_x11_get_stage_from_window:
* @win: an X Window ID
*
* Gets the stage for a particular X window.
*
* Return value: The stage or NULL if a stage does not exist for the window.
*
* Since: 0.8
*/
ClutterStage*
clutter_x11_get_stage_from_window (Window win)
{
ClutterMainContext *context;
ClutterStageManager *stage_manager;
GSList *l;
context = clutter_context_get_default ();
stage_manager = context->stage_manager;
/* 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);
if (stage_x11->xwin == win)
return CLUTTER_STAGE(stage_x11);
}
return NULL;
}
/**
* clutter_x11_get_stage_visual:
* @stage: a #ClutterStage

View File

@ -101,6 +101,8 @@ ClutterX11FilterReturn clutter_x11_handle_event (XEvent *xevent);
void clutter_x11_disable_event_retrieval (void);
ClutterStage *clutter_x11_get_stage_from_window (Window win);
G_END_DECLS
#endif /* __CLUTTER_X11_H__ */

View File

@ -7,7 +7,7 @@ noinst_PROGRAMS = test-textures test-events test-offscreen test-scale \
test-threads test-timeline test-score test-script \
test-model test-grab test-effects test-fullscreen \
test-shader test-unproject test-viewport test-fbo \
test-opacity
test-opacity test-multistage
INCLUDES = -I$(top_srcdir)/
LDADD = $(top_builddir)/clutter/libclutter-@CLUTTER_FLAVOUR@-@CLUTTER_MAJORMINOR@.la
@ -43,5 +43,6 @@ test_fullscreen_SOURCES = test-fullscreen.c
test_viewport_SOURCES = test-viewport.c
test_fbo_SOURCES = test-fbo.c
test_opacity_SOURCES = test-opacity.c
test_multistage_SOURCES = test-multistage.c
EXTRA_DIST = redhand.png test-script.json

129
tests/test-multistage.c Normal file
View File

@ -0,0 +1,129 @@
#include <clutter/clutter.h>
static gint n_stages = 1;
static gboolean
tex_button_cb (ClutterActor *actor,
ClutterEvent *event,
gpointer data)
{
clutter_actor_hide (actor);
}
static void
on_button_press (ClutterActor *actor,
ClutterEvent *event,
gpointer data)
{
ClutterActor *new_stage;
ClutterActor *label, *tex;
gint width, height;
gchar *stage_label, *win_title;
ClutterColor color = { 0xdd, 0x33, 0xdd, 0xff };
ClutterColor white = { 0x99, 0x99, 0x99, 0xff };
GdkPixbuf *pixb;
ClutterTimeline *timeline;
ClutterAlpha *alpha;
ClutterBehaviour *r_behave;
new_stage = clutter_stage_create_new ();
/* FIXME: below should really be automatic */
/* clutter_stage_ensure_cogl_context (CLUTTER_STAGE(new_stage)); */
clutter_stage_set_color (CLUTTER_STAGE (new_stage), &color);
clutter_actor_set_size (new_stage, 320, 240);
pixb = gdk_pixbuf_new_from_file ("redhand.png", NULL);
if (!pixb)
g_error("pixbuf load failed");
tex = clutter_texture_new_from_pixbuf (pixb);
clutter_actor_set_reactive (tex, TRUE);
g_signal_connect (tex, "button-press-event",
G_CALLBACK (tex_button_cb), NULL);
clutter_container_add_actor (CLUTTER_CONTAINER (new_stage), tex);
stage_label = g_strdup_printf ("<b>Stage: %d</b>", ++n_stages);
label = clutter_label_new_with_text ("Mono 12", stage_label);
clutter_label_set_color (CLUTTER_LABEL (label), &white);
clutter_label_set_use_markup (CLUTTER_LABEL (label), TRUE);
width = (clutter_actor_get_width (new_stage)
- clutter_actor_get_width (label)) / 2;
height = (clutter_actor_get_height (new_stage)
- clutter_actor_get_height (label)) / 2;
clutter_actor_set_position (label, width, height);
clutter_container_add_actor (CLUTTER_CONTAINER (new_stage), label);
clutter_actor_show (label);
g_free (stage_label);
/*
g_signal_connect (new_stage, "button-press-event",
G_CALLBACK (clutter_actor_destroy),
NULL);
*/
win_title = g_strdup_printf ("Stage:%p", new_stage);
clutter_stage_set_title (CLUTTER_STAGE(new_stage), win_title);
timeline = clutter_timeline_new_for_duration (2000);
g_object_set (timeline, "loop", TRUE, NULL);
alpha = clutter_alpha_new_full (timeline,
CLUTTER_ALPHA_RAMP_INC,
NULL, NULL);
r_behave = clutter_behaviour_rotate_new (alpha,
CLUTTER_Y_AXIS,
CLUTTER_ROTATE_CW,
0.0, 360.0);
clutter_behaviour_rotate_set_center (CLUTTER_BEHAVIOUR_ROTATE (r_behave),
clutter_actor_get_width (label)/2,
0,
0);
clutter_behaviour_apply (r_behave, label);
clutter_timeline_start (timeline);
clutter_actor_show_all (new_stage);
}
int
main (int argc, char *argv[])
{
ClutterActor *stage_default;
ClutterActor *label;
gint width, height;
gchar *win_title;
clutter_init (&argc, &argv);
stage_default = clutter_stage_get_default ();
g_signal_connect (stage_default, "button-press-event",
G_CALLBACK (on_button_press),
NULL);
label = clutter_label_new_with_text ("Mono 16", "Default stage");
width = (clutter_actor_get_width (stage_default)
- clutter_actor_get_width (label))
/ 2;
height = (clutter_actor_get_height (stage_default)
- clutter_actor_get_height (label))
/ 2;
clutter_actor_set_position (label, width, height);
clutter_container_add_actor (CLUTTER_CONTAINER (stage_default), label);
clutter_actor_show (label);
win_title = g_strdup_printf ("Stage:%p", stage_default);
clutter_stage_set_title (CLUTTER_STAGE(stage_default), win_title);
clutter_actor_show (stage_default);
clutter_main ();
return 0;
}