layout-manager: Create LayoutMeta on demand

The ClutterLayoutMeta instances should be created on demand, whenever
the layout manager needs them - if the layout manager supports layout
properties.

This removes the requirement to call add_child_meta() and
remove_child_meta() on add and remove respectively; it also simplifies
the implementation of LayoutManager sub-classes since we can add
fallback code in the base abstract class.

Eventually, this will also lead to an easier to implement ClutterScript
parser for layout properties.

With the new scheme, the ClutterLayoutMeta instance is created whenever
the layout manager tries to access it; if there isn't an instance
already attached to the container's child, one is created -- assuming
that the LayoutManager sub-class has overridden the
get_child_meta_type() virtual function and it's returning a valid GType.

We can also provide a default implementation for create_child_meta(),
by getting the GType and instantiating a ClutterLayoutMeta with all the
fields already set. If the layout manager requires more work then it can
obviously override the default implementation (and even chain up to it).

The ClutterBox actor has been updated, as well as the ClutterBoxLayout
layout manager, to take advantage of the changes of LayoutManager.
This commit is contained in:
Emmanuele Bassi 2009-11-30 19:03:11 +00:00
parent 7d842079ca
commit 15a04a1dd3
5 changed files with 70 additions and 184 deletions

View File

@ -478,18 +478,6 @@ allocate_fill (ClutterActor *child,
*childbox = allocation;
}
static ClutterLayoutMeta *
clutter_box_layout_create_child_meta (ClutterLayoutManager *layout,
ClutterContainer *container,
ClutterActor *actor)
{
return g_object_new (CLUTTER_TYPE_BOX_CHILD,
"manager", layout,
"container", container,
"actor", actor,
NULL);
}
static GType
clutter_box_layout_get_child_meta_type (ClutterLayoutManager *manager)
{
@ -895,7 +883,6 @@ clutter_box_layout_class_init (ClutterBoxLayoutClass *klass)
clutter_box_layout_get_preferred_height;
layout_class->allocate = clutter_box_layout_allocate;
layout_class->set_container = clutter_box_layout_set_container;
layout_class->create_child_meta = clutter_box_layout_create_child_meta;
layout_class->get_child_meta_type =
clutter_box_layout_get_child_meta_type;

View File

@ -118,11 +118,6 @@ clutter_box_real_add (ClutterContainer *container,
clutter_actor_set_parent (actor, CLUTTER_ACTOR (container));
if (priv->manager != NULL)
clutter_layout_manager_add_child_meta (priv->manager,
container,
actor);
clutter_actor_queue_relayout (actor);
g_signal_emit_by_name (container, "actor-added", actor);
@ -141,11 +136,6 @@ clutter_box_real_remove (ClutterContainer *container,
priv->children = g_list_remove (priv->children, actor);
clutter_actor_unparent (actor);
if (priv->manager != NULL)
clutter_layout_manager_remove_child_meta (priv->manager,
container,
actor);
clutter_actor_queue_relayout (CLUTTER_ACTOR (container));
g_signal_emit_by_name (container, "actor-removed", actor);

View File

@ -78,6 +78,34 @@
* policies then it should emit the #ClutterLayoutManager::layout-changed
* signal on itself by using the clutter_layout_manager_layout_changed()
* function.</para>
* <para>If the layout manager has layout properties, that is properties that
* should exist only as the result of the presence of a specific (layout
* manager, container actor, child actor) combination, then it should
* override the <structname>ClutterLayoutManager</structname>::get_child_meta_type()
* virtual function to return the #GType of the #ClutterLayoutMeta sub-class
* used to store the layout properties; optionally, the #ClutterLayoutManager
* sub-class might also override the
* <structname>ClutterLayoutManager</structname>::create_child_meta() virtual
* function to control how the #ClutterLayoutMeta instance is created,
* otherwise the default implementation will be equivalent to:</para>
* <informalexample><programlisting>
* ClutterLayoutManagerClass *klass;
* GType meta_type;
*
* klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager);
* meta_type = klass->get_child_meta_type (manager);
*
* return g_object_new (meta_type,
* "manager", manager,
* "container", container,
* "actor", actor,
* NULL);
* </programlisting></informalexample>
* <para>Where <variablename>manager</variablename> is the
* #ClutterLayoutManager, <variablename>container</variablename> is the
* #ClutterContainer using the #ClutterLayoutManager and
* <variablename>actor</variablename> is the #ClutterActor child of the
* #ClutterContainer.</para>
* </refsect2>
*
* #ClutterLayoutManager is available since Clutter 1.2
@ -163,6 +191,24 @@ layout_manager_real_create_child_meta (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor)
{
ClutterLayoutManagerClass *klass;
GType meta_type;
klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager);
meta_type = klass->get_child_meta_type (manager);
/* provide a default implementation to reduce common code */
if (meta_type != G_TYPE_INVALID)
{
g_assert (g_type_is_a (meta_type, CLUTTER_TYPE_LAYOUT_META));
return g_object_new (meta_type,
"manager", manager,
"container", container,
"actor", actor,
NULL);
}
return NULL;
}
@ -384,29 +430,10 @@ create_child_meta (ClutterLayoutManager *manager,
ClutterLayoutManagerClass *klass;
klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager);
if (klass->get_child_meta_type (manager) != G_TYPE_INVALID)
return klass->create_child_meta (manager, container, actor);
return klass->create_child_meta (manager, container, actor);
}
static gboolean
has_child_meta (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor)
{
ClutterLayoutMeta *layout_meta = NULL;
layout_meta = g_object_get_qdata (G_OBJECT (actor), quark_layout_meta);
if (layout_meta != NULL)
{
ClutterChildMeta *child_meta = CLUTTER_CHILD_META (layout_meta);
if (layout_meta->manager == manager &&
child_meta->container == container &&
child_meta->actor == actor)
return TRUE;
}
return FALSE;
return NULL;
}
static inline ClutterLayoutMeta *
@ -430,15 +457,15 @@ get_child_meta (ClutterLayoutManager *manager,
* layout manager then we simply ask the layout manager
* to replace it with the right one
*/
layout = create_child_meta (manager, container, actor);
if (layout != NULL)
{
g_assert (CLUTTER_IS_LAYOUT_META (layout));
g_object_set_qdata_full (G_OBJECT (actor), quark_layout_meta,
layout,
(GDestroyNotify) g_object_unref);
}
}
layout = create_child_meta (manager, container, actor);
if (layout != NULL)
{
g_assert (CLUTTER_IS_LAYOUT_META (layout));
g_object_set_qdata_full (G_OBJECT (actor), quark_layout_meta,
layout,
(GDestroyNotify) g_object_unref);
return layout;
}
@ -452,9 +479,11 @@ get_child_meta (ClutterLayoutManager *manager,
* @actor: a #ClutterActor child of @container
*
* Retrieves the #ClutterLayoutMeta that the layout @manager associated
* to the @actor child of @container
* to the @actor child of @container, eventually by creating one if the
* #ClutterLayoutManager supports layout properties
*
* Return value: a #ClutterLayoutMeta or %NULL
* Return value: a #ClutterLayoutMeta, or %NULL if the #ClutterLayoutManager
* does not have layout properties
*
* Since: 1.0
*/
@ -470,118 +499,6 @@ clutter_layout_manager_get_child_meta (ClutterLayoutManager *manager,
return get_child_meta (manager, container, actor);
}
/**
* clutter_layout_manager_add_child_meta:
* @manager: a #ClutterLayoutManager
* @container: a #ClutterContainer using @manager
* @actor: a #ClutterActor child of @container
*
* Creates and binds a #ClutterLayoutMeta for @manager to
* a child of @container
*
* This function should only be used when implementing containers
* using #ClutterLayoutManager and not by application code
*
* Typically, containers should bind a #ClutterLayoutMeta created
* by a #ClutterLayoutManager when adding a new child, e.g.:
*
* |[
* static void
* my_container_add (ClutterContainer *container,
* ClutterActor *actor)
* {
* MyContainer *self = MY_CONTAINER (container);
*
* self->children = g_slist_append (self->children, actor);
* clutter_actor_set_parent (actor, CLUTTER_ACTOR (self));
*
* clutter_layout_manager_add_child_meta (self->layout,
* container,
* actor);
*
* clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
*
* g_signal_emit_by_name (container, "actor-added");
* }
* ]|
*
* The #ClutterLayoutMeta should be removed when removing an
* actor; see clutter_layout_manager_remove_child_meta()
*
* Since: 1.2
*/
void
clutter_layout_manager_add_child_meta (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor)
{
ClutterLayoutMeta *meta;
meta = create_child_meta (manager, container, actor);
if (meta == NULL)
return;
g_object_set_qdata_full (G_OBJECT (actor), quark_layout_meta,
meta,
(GDestroyNotify) g_object_unref);
}
/**
* clutter_layout_manager_remove_child_meta:
* @manager: a #ClutterLayoutManager
* @container: a #ClutterContainer using @manager
* @actor: a #ClutterActor child of @container
*
* Unbinds and unrefs a #ClutterLayoutMeta for @manager from
* a child of @container
*
* This function should only be used when implementing containers
* using #ClutterLayoutManager and not by application code
*
* Typically, containers should remove a #ClutterLayoutMeta created
* by a #ClutterLayoutManager when removing a child, e.g.:
*
* |[
* static void
* my_container_remove (ClutterContainer *container,
* ClutterActor *actor)
* {
* MyContainer *self = MY_CONTAINER (container);
*
* g_object_ref (actor);
*
* self->children = g_slist_remove (self->children, actor);
* clutter_actor_unparent (actor);
*
* clutter_layout_manager_remove_child_meta (self->layout,
* container,
* actor);
*
* clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
*
* g_signal_emit_by_name (container, "actor-removed");
*
* g_object_unref (actor);
* }
* ]|
*
* See also clutter_layout_manager_add_child_meta()
*
* Since: 1.2
*/
void
clutter_layout_manager_remove_child_meta (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor)
{
g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager));
g_return_if_fail (CLUTTER_IS_CONTAINER (container));
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
if (has_child_meta (manager, container, actor))
g_object_set_qdata (G_OBJECT (actor), quark_layout_meta, NULL);
}
static inline gboolean
layout_set_property_internal (ClutterLayoutManager *manager,
GObject *gobject,
@ -665,7 +582,7 @@ clutter_layout_manager_child_set (ClutterLayoutManager *manager,
if (meta == NULL)
{
g_warning ("Layout managers of type '%s' do not support "
"child metadata",
"layout metadata",
g_type_name (G_OBJECT_TYPE (manager)));
return;
}
@ -685,7 +602,7 @@ clutter_layout_manager_child_set (ClutterLayoutManager *manager,
pspec = g_object_class_find_property (klass, pname);
if (pspec == NULL)
{
g_warning ("%s: Layout managers of type '%s' have no child "
g_warning ("%s: Layout managers of type '%s' have no layout "
"property named '%s'",
G_STRLOC, G_OBJECT_TYPE_NAME (manager), pname);
break;
@ -749,7 +666,7 @@ clutter_layout_manager_child_set_property (ClutterLayoutManager *manager,
if (meta == NULL)
{
g_warning ("Layout managers of type '%s' do not support "
"child metadata",
"layout metadata",
g_type_name (G_OBJECT_TYPE (manager)));
return;
}
@ -759,7 +676,7 @@ clutter_layout_manager_child_set_property (ClutterLayoutManager *manager,
pspec = g_object_class_find_property (klass, property_name);
if (pspec == NULL)
{
g_warning ("%s: Layout managers of type '%s' have no child "
g_warning ("%s: Layout managers of type '%s' have no layout "
"property named '%s'",
G_STRLOC, G_OBJECT_TYPE_NAME (manager), property_name);
return;
@ -803,7 +720,7 @@ clutter_layout_manager_child_get (ClutterLayoutManager *manager,
if (meta == NULL)
{
g_warning ("Layout managers of type '%s' do not support "
"child metadata",
"layout metadata",
g_type_name (G_OBJECT_TYPE (manager)));
return;
}
@ -823,7 +740,7 @@ clutter_layout_manager_child_get (ClutterLayoutManager *manager,
pspec = g_object_class_find_property (klass, pname);
if (pspec == NULL)
{
g_warning ("%s: Layout managers of type '%s' have no child "
g_warning ("%s: Layout managers of type '%s' have no layout "
"property named '%s'",
G_STRLOC, G_OBJECT_TYPE_NAME (manager), pname);
break;
@ -895,7 +812,7 @@ clutter_layout_manager_child_get_property (ClutterLayoutManager *manager,
if (meta == NULL)
{
g_warning ("Layout managers of type %s do not support "
"child metadata",
"layout metadata",
g_type_name (G_OBJECT_TYPE (manager)));
return;
}
@ -905,7 +822,7 @@ clutter_layout_manager_child_get_property (ClutterLayoutManager *manager,
pspec = g_object_class_find_property (klass, property_name);
if (pspec == NULL)
{
g_warning ("%s: Layout managers of type '%s' have no child "
g_warning ("%s: Layout managers of type '%s' have no layout "
"property named '%s'",
G_STRLOC, G_OBJECT_TYPE_NAME (manager), property_name);
return;

View File

@ -80,7 +80,7 @@ struct _ClutterLayoutManager
* @get_child_meta_type: virtual function; override to return the #GType
* of the #ClutterLayoutMeta sub-class used by the #ClutterLayoutManager
* @create_child_meta: virtual function; override to create a
* #ClutterChildMeta instance associated to a #ClutterContainer and a
* #ClutterLayoutMeta instance associated to a #ClutterContainer and a
* child #ClutterActor, used to maintain layout manager specific properties
* @layout_changed: class handler for the #ClutterLayoutManager::layout-changed
* signal
@ -162,12 +162,6 @@ GParamSpec ** clutter_layout_manager_list_child_properties (ClutterLayoutMa
ClutterLayoutMeta *clutter_layout_manager_get_child_meta (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor);
void clutter_layout_manager_add_child_meta (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor);
void clutter_layout_manager_remove_child_meta (ClutterLayoutManager *manager,
ClutterContainer *container,
ClutterActor *actor);
void clutter_layout_manager_child_set (ClutterLayoutManager *manager,
ClutterContainer *container,

View File

@ -1749,8 +1749,6 @@ clutter_layout_manager_layout_changed
clutter_layout_manager_set_container
<SUBSECTION>
clutter_layout_manager_add_child_meta
clutter_layout_manager_remove_child_meta
clutter_layout_manager_get_child_meta
clutter_layout_manager_child_set
clutter_layout_manager_child_set_property