b887bddbb1
* clutter/clutter-stage.c (clutter_stage_get_default): Don't grab the floating reference when creating the default stage. The stage manager will take a reference to it so it will behave as any other stage. (clutter_stage_new): Don't take the floating reference to the new stage but let the stage manager keep it instead. * clutter/clutter-stage-manager.c (_clutter_stage_manager_add_stage): Take a reference to the stage when it is added to the list. (_clutter_stage_manager_remove_stage): Unref the stage when it is removed from the list. (clutter_stage_manager_dispose): Keep track of the 'next' pointer as a separate variable so we can cope when the stage being destroyed removes itself from the list as the list is being iterated. * clutter/clutter-actor.c (clutter_actor_destroy): Take a reference at the beginning of the function even if there is no parent container so that overall the reference count is not changed when the actor is unref'd again at the bottom of the function. Previously it would have a net effect of leaving the reference count alone unless it is a top level actor in which case it would unref it.
284 lines
7.5 KiB
C
284 lines
7.5 KiB
C
#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, *next;
|
|
|
|
stage_manager = CLUTTER_STAGE_MANAGER (gobject);
|
|
|
|
for (l = stage_manager->stages; l; l = next)
|
|
{
|
|
ClutterActor *stage = l->data;
|
|
next = l->next;
|
|
|
|
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)
|
|
{
|
|
/* 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))
|
|
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);
|
|
}
|