mutter/clutter/clutter-stage-manager.c
Neil Roberts b887bddbb1 Applied patch from bug #947
* 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.
2008-06-03 20:15:11 +00:00

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);
}