Release Clutter 1.11.4 (snapshot)
[profile/ivi/clutter.git] / clutter / clutter-container.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006 OpenedHand
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
22  *
23  *
24  *
25  * ClutterContainer: Generic actor container interface.
26  * Author: Emmanuele Bassi <ebassi@openedhand.com>
27  */
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include <stdarg.h>
34 #include <glib-object.h>
35 #include <gobject/gvaluecollector.h>
36
37 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
38 #include "deprecated/clutter-container.h"
39
40 #include "clutter-actor-private.h"
41 #include "clutter-child-meta.h"
42 #include "clutter-debug.h"
43 #include "clutter-main.h"
44 #include "clutter-marshal.h"
45 #include "clutter-private.h"
46 #include "clutter-enum-types.h"
47
48 #define CLUTTER_CONTAINER_WARN_NOT_IMPLEMENTED(container,vfunc) \
49         G_STMT_START { \
50           g_warning ("Container of type '%s' does not implement " \
51                      "the required ClutterContainer::%s virtual " \
52                      "function.",                                 \
53                      G_OBJECT_TYPE_NAME ((container)),            \
54                      (vfunc));                                    \
55         } G_STMT_END
56
57 #define CLUTTER_CONTAINER_NOTE_NOT_IMPLEMENTED(container,vfunc) \
58         G_STMT_START { \
59           CLUTTER_NOTE (ACTOR, "Container of type '%s' does not "    \
60                                "implement the ClutterContainer::%s " \
61                                "virtual function.",                  \
62                         G_OBJECT_TYPE_NAME ((container)),            \
63                         (vfunc));                                    \
64         } G_STMT_END
65
66 /**
67  * SECTION:clutter-container
68  * @short_description: An interface for container actors
69  *
70  * #ClutterContainer is an interface implemented by #ClutterActor, and
71  * it provides some common API for notifying when a child actor is added
72  * or removed, as well as the infrastructure for accessing child properties
73  * through #ClutterChildMeta.
74  *
75  * Until Clutter 1.10, the #ClutterContainer interface was also the public
76  * API for implementing container actors; this part of the interface has
77  * been deprecated: #ClutterContainer has a default implementation which
78  * defers to #ClutterActor the child addition and removal, as well as the
79  * iteration. See the documentation of #ClutterContainerIface for the list
80  * of virtual functions that should be overridden.
81  */
82
83 enum
84 {
85   ACTOR_ADDED,
86   ACTOR_REMOVED,
87   CHILD_NOTIFY,
88
89   LAST_SIGNAL
90 };
91
92 static guint container_signals[LAST_SIGNAL] = { 0, };
93 static GQuark quark_child_meta = 0;
94
95 static ClutterChildMeta *get_child_meta     (ClutterContainer *container,
96                                              ClutterActor     *actor);
97 static void              create_child_meta  (ClutterContainer *container,
98                                              ClutterActor     *actor);
99 static void              destroy_child_meta (ClutterContainer *container,
100                                              ClutterActor     *actor);
101 static void              child_notify       (ClutterContainer *container,
102                                              ClutterActor     *child,
103                                              GParamSpec       *pspec);
104
105 typedef ClutterContainerIface   ClutterContainerInterface;
106
107 G_DEFINE_INTERFACE (ClutterContainer, clutter_container, G_TYPE_OBJECT);
108
109 static void
110 container_real_add (ClutterContainer *container,
111                     ClutterActor     *actor)
112 {
113   clutter_actor_add_child (CLUTTER_ACTOR (container), actor);
114 }
115
116 static void
117 container_real_remove (ClutterContainer *container,
118                        ClutterActor     *actor)
119 {
120   clutter_actor_remove_child (CLUTTER_ACTOR (container), actor);
121 }
122
123 typedef struct {
124   ClutterCallback callback;
125   gpointer data;
126 } ForeachClosure;
127
128 static gboolean
129 foreach_cb (ClutterActor *actor,
130             gpointer      data)
131 {
132   ForeachClosure *clos = data;
133
134   clos->callback (actor, clos->data);
135
136   return TRUE;
137 }
138
139 static void
140 container_real_foreach (ClutterContainer *container,
141                         ClutterCallback   callback,
142                         gpointer          user_data)
143 {
144   ForeachClosure clos;
145
146   clos.callback = callback;
147   clos.data = user_data;
148
149   _clutter_actor_foreach_child (CLUTTER_ACTOR (container),
150                                 foreach_cb,
151                                 &clos);
152 }
153
154 static void
155 container_real_raise (ClutterContainer *container,
156                       ClutterActor     *child,
157                       ClutterActor     *sibling)
158 {
159   ClutterActor *self = CLUTTER_ACTOR (container);
160
161   clutter_actor_set_child_above_sibling (self, child, sibling);
162 }
163
164 static void
165 container_real_lower (ClutterContainer *container,
166                       ClutterActor     *child,
167                       ClutterActor     *sibling)
168 {
169   ClutterActor *self = CLUTTER_ACTOR (container);
170
171   clutter_actor_set_child_below_sibling (self, child, sibling);
172 }
173
174 static void
175 container_real_sort_depth_order (ClutterContainer *container)
176 {
177 }
178
179 static void
180 clutter_container_default_init (ClutterContainerInterface *iface)
181 {
182   GType iface_type = G_TYPE_FROM_INTERFACE (iface);
183
184   quark_child_meta =
185     g_quark_from_static_string ("clutter-container-child-data");
186
187   /**
188    * ClutterContainer::actor-added:
189    * @container: the actor which received the signal
190    * @actor: the new child that has been added to @container
191    *
192    * The ::actor-added signal is emitted each time an actor
193    * has been added to @container.
194    *
195    * Since: 0.4
196    */
197   container_signals[ACTOR_ADDED] =
198     g_signal_new (I_("actor-added"),
199                   iface_type,
200                   G_SIGNAL_RUN_FIRST,
201                   G_STRUCT_OFFSET (ClutterContainerIface, actor_added),
202                   NULL, NULL,
203                   _clutter_marshal_VOID__OBJECT,
204                   G_TYPE_NONE, 1,
205                   CLUTTER_TYPE_ACTOR);
206   /**
207    * ClutterContainer::actor-removed:
208    * @container: the actor which received the signal
209    * @actor: the child that has been removed from @container
210    *
211    * The ::actor-removed signal is emitted each time an actor
212    * is removed from @container.
213    *
214    * Since: 0.4
215    */
216   container_signals[ACTOR_REMOVED] =
217     g_signal_new (I_("actor-removed"),
218                   iface_type,
219                   G_SIGNAL_RUN_FIRST,
220                   G_STRUCT_OFFSET (ClutterContainerIface, actor_removed),
221                   NULL, NULL,
222                   _clutter_marshal_VOID__OBJECT,
223                   G_TYPE_NONE, 1,
224                   CLUTTER_TYPE_ACTOR);
225
226   /**
227    * ClutterContainer::child-notify:
228    * @container: the container which received the signal
229    * @actor: the child that has had a property set
230    * @pspec: (type GParamSpec): the #GParamSpec of the property set
231    *
232    * The ::child-notify signal is emitted each time a property is
233    * being set through the clutter_container_child_set() and
234    * clutter_container_child_set_property() calls.
235    *
236    * Since: 0.8
237    */
238   container_signals[CHILD_NOTIFY] =
239     g_signal_new (I_("child-notify"),
240                   iface_type,
241                   G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
242                   G_STRUCT_OFFSET (ClutterContainerIface, child_notify),
243                   NULL, NULL,
244                   _clutter_marshal_VOID__OBJECT_PARAM,
245                   G_TYPE_NONE, 2,
246                   CLUTTER_TYPE_ACTOR, G_TYPE_PARAM);
247
248   iface->add = container_real_add;
249   iface->remove = container_real_remove;
250   iface->foreach = container_real_foreach;
251   iface->raise = container_real_raise;
252   iface->lower = container_real_lower;
253   iface->sort_depth_order = container_real_sort_depth_order;
254
255   iface->child_meta_type = G_TYPE_INVALID;
256   iface->create_child_meta = create_child_meta;
257   iface->destroy_child_meta = destroy_child_meta;
258   iface->get_child_meta = get_child_meta;
259   iface->child_notify = child_notify;
260 }
261
262 static inline void
263 container_add_actor (ClutterContainer *container,
264                      ClutterActor     *actor)
265 {
266   ClutterActor *parent;
267
268   parent = clutter_actor_get_parent (actor);
269   if (G_UNLIKELY (parent != NULL))
270     {
271       g_warning ("Attempting to add actor of type '%s' to a "
272                  "container of type '%s', but the actor has "
273                  "already a parent of type '%s'.",
274                  g_type_name (G_OBJECT_TYPE (actor)),
275                  g_type_name (G_OBJECT_TYPE (container)),
276                  g_type_name (G_OBJECT_TYPE (parent)));
277       return;
278     }
279
280   clutter_container_create_child_meta (container, actor);
281
282 #ifdef CLUTTER_ENABLE_DEBUG
283   if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
284     {
285       ClutterContainerIface *iface = CLUTTER_CONTAINER_GET_IFACE (container);
286
287       if (iface->add != container_real_add)
288         _clutter_diagnostic_message ("The ClutterContainer::add() virtual "
289                                      "function has been deprecated and it "
290                                      "should not be overridden by newly "
291                                      "written code");
292     }
293 #endif /* CLUTTER_ENABLE_DEBUG */
294
295   CLUTTER_CONTAINER_GET_IFACE (container)->add (container, actor);
296 }
297
298 static inline void
299 container_remove_actor (ClutterContainer *container,
300                         ClutterActor     *actor)
301 {
302   ClutterActor *parent;
303
304   parent = clutter_actor_get_parent (actor);
305   if (parent != CLUTTER_ACTOR (container))
306     {
307       g_warning ("Attempting to remove actor of type '%s' from "
308                  "group of class '%s', but the container is not "
309                  "the actor's parent.",
310                  g_type_name (G_OBJECT_TYPE (actor)),
311                  g_type_name (G_OBJECT_TYPE (container)));
312       return;
313     }
314
315   clutter_container_destroy_child_meta (container, actor);
316
317 #ifdef CLUTTER_ENABLE_DEBUG
318   if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
319     {
320       ClutterContainerIface *iface = CLUTTER_CONTAINER_GET_IFACE (container);
321
322       if (iface->remove != container_real_remove)
323         _clutter_diagnostic_message ("The ClutterContainer::remove() virtual "
324                                      "function has been deprecated and it "
325                                      "should not be overridden by newly "
326                                      "written code");
327     }
328 #endif /* CLUTTER_ENABLE_DEBUG */
329
330   CLUTTER_CONTAINER_GET_IFACE (container)->remove (container, actor);
331 }
332
333 static inline void
334 container_add_valist (ClutterContainer *container,
335                       ClutterActor     *first_actor,
336                       va_list           args)
337 {
338   ClutterActor *actor = first_actor;
339
340   while (actor != NULL)
341     {
342       container_add_actor (container, actor);
343       actor = va_arg (args, ClutterActor *);
344     }
345 }
346
347 static inline void
348 container_remove_valist (ClutterContainer *container,
349                          ClutterActor     *first_actor,
350                          va_list           args)
351 {
352   ClutterActor *actor = first_actor;
353
354   while (actor != NULL)
355     {
356       container_remove_actor (container, actor);
357       actor = va_arg (args, ClutterActor *);
358     }
359 }
360
361 /**
362  * clutter_container_add: (skip)
363  * @container: a #ClutterContainer
364  * @first_actor: the first #ClutterActor to add
365  * @...: %NULL terminated list of actors to add
366  *
367  * Adds a list of #ClutterActor<!-- -->s to @container. Each time and
368  * actor is added, the "actor-added" signal is emitted. Each actor should
369  * be parented to @container, which takes a reference on the actor. You
370  * cannot add a #ClutterActor to more than one #ClutterContainer.
371  *
372  * This function will call #ClutterContainerIface.add(), which is a
373  * deprecated virtual function. The default implementation will
374  * call clutter_actor_add_child().
375  *
376  * Since: 0.4
377  *
378  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
379  */
380 void
381 clutter_container_add (ClutterContainer *container,
382                        ClutterActor     *first_actor,
383                        ...)
384 {
385   va_list args;
386
387   g_return_if_fail (CLUTTER_IS_CONTAINER (container));
388   g_return_if_fail (CLUTTER_IS_ACTOR (first_actor));
389
390   va_start (args, first_actor);
391   container_add_valist (container, first_actor, args);
392   va_end (args);
393 }
394
395 /**
396  * clutter_container_add_actor:
397  * @container: a #ClutterContainer
398  * @actor: the first #ClutterActor to add
399  *
400  * Adds a #ClutterActor to @container. This function will emit the
401  * "actor-added" signal. The actor should be parented to
402  * @container. You cannot add a #ClutterActor to more than one
403  * #ClutterContainer.
404  *
405  * This function will call #ClutterContainerIface.add(), which is a
406  * deprecated virtual function. The default implementation will
407  * call clutter_actor_add_child().
408  *
409  * Virtual: add
410  *
411  * Since: 0.4
412  *
413  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
414  */
415 void
416 clutter_container_add_actor (ClutterContainer *container,
417                              ClutterActor     *actor)
418 {
419   g_return_if_fail (CLUTTER_IS_CONTAINER (container));
420   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
421
422   container_add_actor (container, actor);
423 }
424
425 /**
426  * clutter_container_add_valist: (skip)
427  * @container: a #ClutterContainer
428  * @first_actor: the first #ClutterActor to add
429  * @var_args: list of actors to add, followed by %NULL
430  *
431  * Alternative va_list version of clutter_container_add().
432  *
433  * This function will call #ClutterContainerIface.add(), which is a
434  * deprecated virtual function. The default implementation will
435  * call clutter_actor_add_child().
436  *
437  * Since: 0.4
438  *
439  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
440  */
441 void
442 clutter_container_add_valist (ClutterContainer *container,
443                               ClutterActor     *first_actor,
444                               va_list           var_args)
445 {
446   g_return_if_fail (CLUTTER_IS_CONTAINER (container));
447   g_return_if_fail (CLUTTER_IS_ACTOR (first_actor));
448
449   container_add_valist (container, first_actor, var_args);
450 }
451
452 /**
453  * clutter_container_remove: (skip)
454  * @container: a #ClutterContainer
455  * @first_actor: first #ClutterActor to remove
456  * @...: a %NULL-terminated list of actors to remove
457  *
458  * Removes a %NULL terminated list of #ClutterActor<!-- -->s from
459  * @container. Each actor should be unparented, so if you want to keep it
460  * around you must hold a reference to it yourself, using g_object_ref().
461  * Each time an actor is removed, the "actor-removed" signal is
462  * emitted by @container.
463  *
464  * This function will call #ClutterContainerIface.remove(), which is a
465  * deprecated virtual function. The default implementation will call
466  * clutter_actor_remove_child().
467  *
468  * Since: 0.4
469  *
470  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
471  */
472 void
473 clutter_container_remove (ClutterContainer *container,
474                           ClutterActor     *first_actor,
475                           ...)
476 {
477   va_list var_args;
478
479   g_return_if_fail (CLUTTER_IS_CONTAINER (container));
480   g_return_if_fail (CLUTTER_IS_ACTOR (first_actor));
481
482   va_start (var_args, first_actor);
483   container_remove_valist (container, first_actor, var_args);
484   va_end (var_args);
485 }
486
487 /**
488  * clutter_container_remove_actor:
489  * @container: a #ClutterContainer
490  * @actor: a #ClutterActor
491  *
492  * Removes @actor from @container. The actor should be unparented, so
493  * if you want to keep it around you must hold a reference to it
494  * yourself, using g_object_ref(). When the actor has been removed,
495  * the "actor-removed" signal is emitted by @container.
496  *
497  * This function will call #ClutterContainerIface.remove(), which is a
498  * deprecated virtual function. The default implementation will call
499  * clutter_actor_remove_child().
500  *
501  * Virtual: remove
502  *
503  * Since: 0.4
504  *
505  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
506  */
507 void
508 clutter_container_remove_actor (ClutterContainer *container,
509                                 ClutterActor     *actor)
510 {
511   g_return_if_fail (CLUTTER_IS_CONTAINER (container));
512   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
513
514   container_remove_actor (container, actor);
515 }
516
517 /**
518  * clutter_container_remove_valist: (skip)
519  * @container: a #ClutterContainer
520  * @first_actor: the first #ClutterActor to add
521  * @var_args: list of actors to remove, followed by %NULL
522  *
523  * Alternative va_list version of clutter_container_remove().
524  *
525  * This function will call #ClutterContainerIface.remove(), which is a
526  * deprecated virtual function. The default implementation will call
527  * clutter_actor_remove_child().
528  *
529  * Since: 0.4
530  *
531  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
532  */
533 void
534 clutter_container_remove_valist (ClutterContainer *container,
535                                  ClutterActor     *first_actor,
536                                  va_list           var_args)
537 {
538   g_return_if_fail (CLUTTER_IS_CONTAINER (container));
539   g_return_if_fail (CLUTTER_IS_ACTOR (first_actor));
540
541   container_remove_valist (container, first_actor, var_args);
542 }
543
544 static void
545 get_children_cb (ClutterActor *child,
546                  gpointer      data)
547 {
548   GList **children = data;
549
550   *children = g_list_prepend (*children, child);
551 }
552
553 /**
554  * clutter_container_get_children:
555  * @container: a #ClutterContainer
556  *
557  * Retrieves all the children of @container.
558  *
559  * Return value: (element-type Clutter.Actor) (transfer container): a list
560  *   of #ClutterActor<!-- -->s. Use g_list_free() on the returned
561  *   list when done.
562  *
563  * Since: 0.4
564  *
565  * Deprecated: 1.10: Use clutter_actor_get_children() instead.
566  */
567 GList *
568 clutter_container_get_children (ClutterContainer *container)
569 {
570   GList *retval;
571
572   g_return_val_if_fail (CLUTTER_IS_CONTAINER (container), NULL);
573
574   retval = NULL;
575   clutter_container_foreach (container, get_children_cb, &retval);
576
577   return g_list_reverse (retval);
578 }
579
580 /**
581  * clutter_container_foreach:
582  * @container: a #ClutterContainer
583  * @callback: (scope call): a function to be called for each child
584  * @user_data: data to be passed to the function, or %NULL
585  *
586  * Calls @callback for each child of @container that was added
587  * by the application (with clutter_container_add_actor()). Does
588  * not iterate over "internal" children that are part of the
589  * container's own implementation, if any.
590  *
591  * This function calls the #ClutterContainerIface.foreach()
592  * virtual function, which has been deprecated.
593  *
594  * Since: 0.4
595  *
596  * Deprecated: 1.10: Use clutter_actor_get_first_child() or
597  *   clutter_actor_get_last_child() to retrieve the beginning of
598  *   the list of children, and clutter_actor_get_next_sibling()
599  *   and clutter_actor_get_previous_sibling() to iterate over it;
600  *   alternatively, use the #ClutterActorIter API.
601  */
602 void
603 clutter_container_foreach (ClutterContainer *container,
604                            ClutterCallback   callback,
605                            gpointer          user_data)
606 {
607   g_return_if_fail (CLUTTER_IS_CONTAINER (container));
608   g_return_if_fail (callback != NULL);
609
610 #ifdef CLUTTER_ENABLE_DEBUG
611   if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
612     {
613       ClutterContainerIface *iface = CLUTTER_CONTAINER_GET_IFACE (container);
614
615       if (iface->foreach != container_real_foreach)
616         _clutter_diagnostic_message ("The ClutterContainer::foreach() "
617                                      "virtual function has been deprecated "
618                                      "and it should not be overridden by "
619                                      "newly written code");
620     }
621 #endif /* CLUTTER_ENABLE_DEBUG */
622
623   CLUTTER_CONTAINER_GET_IFACE (container)->foreach (container,
624                                                     callback,
625                                                     user_data);
626 }
627
628 /**
629  * clutter_container_foreach_with_internals:
630  * @container: a #ClutterContainer
631  * @callback: (scope call): a function to be called for each child
632  * @user_data: data to be passed to the function, or %NULL
633  *
634  * Calls @callback for each child of @container, including "internal"
635  * children built in to the container itself that were never added
636  * by the application.
637  *
638  * This function calls the #ClutterContainerIface.foreach_with_internals()
639  * virtual function, which has been deprecated.
640  *
641  * Since: 1.0
642  *
643  * Deprecated: 1.10: See clutter_container_foreach().
644  */
645 void
646 clutter_container_foreach_with_internals (ClutterContainer *container,
647                                           ClutterCallback   callback,
648                                           gpointer          user_data)
649 {
650   ClutterContainerIface *iface;
651
652   g_return_if_fail (CLUTTER_IS_CONTAINER (container));
653   g_return_if_fail (callback != NULL);
654
655   iface = CLUTTER_CONTAINER_GET_IFACE (container);
656
657 #ifdef CLUTTER_ENABLE_DEBUG
658   if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
659     {
660       if (iface->foreach_with_internals != NULL)
661         _clutter_diagnostic_message ("The ClutterContainer::foreach_with_internals() "
662                                      "virtual function has been deprecated "
663                                      "and it should not be overridden by "
664                                      "newly written code");
665     }
666 #endif /* CLUTTER_ENABLE_DEBUG */
667
668   if (iface->foreach_with_internals != NULL)
669     iface->foreach_with_internals (container, callback, user_data);
670   else
671     iface->foreach (container, callback, user_data);
672 }
673
674 /**
675  * clutter_container_raise_child:
676  * @container: a #ClutterContainer
677  * @actor: the actor to raise
678  * @sibling: (allow-none): the sibling to raise to, or %NULL to raise
679  *   to the top
680  *
681  * Raises @actor to @sibling level, in the depth ordering.
682  *
683  * This function calls the #ClutterContainerIface.raise() virtual function,
684  * which has been deprecated. The default implementation will call
685  * clutter_actor_set_child_above_sibling().
686  *
687  * Virtual: raise
688  *
689  * Since: 0.6
690  *
691  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
692  */
693 void
694 clutter_container_raise_child (ClutterContainer *container,
695                                ClutterActor     *actor,
696                                ClutterActor     *sibling)
697 {
698   ClutterContainerIface *iface;
699   ClutterActor *self;
700
701   g_return_if_fail (CLUTTER_IS_CONTAINER (container));
702   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
703   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
704
705   if (actor == sibling)
706     return;
707
708   self = CLUTTER_ACTOR (container);
709
710   if (clutter_actor_get_parent (actor) != self)
711     {
712       g_warning ("Actor of type '%s' is not a child of the container "
713                  "of type '%s'",
714                  g_type_name (G_OBJECT_TYPE (actor)),
715                  g_type_name (G_OBJECT_TYPE (container)));
716       return;
717     }
718
719   if (sibling != NULL &&
720       clutter_actor_get_parent (sibling) != self)
721     {
722       g_warning ("Actor of type '%s' is not a child of the container "
723                  "of type '%s'",
724                  g_type_name (G_OBJECT_TYPE (sibling)),
725                  g_type_name (G_OBJECT_TYPE (container)));
726       return;
727     }
728
729   iface = CLUTTER_CONTAINER_GET_IFACE (container);
730
731 #ifdef CLUTTER_ENABLE_DEBUG
732   if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
733     {
734       if (iface->raise != container_real_raise)
735         _clutter_diagnostic_message ("The ClutterContainer::raise() "
736                                      "virtual function has been deprecated "
737                                      "and it should not be overridden by "
738                                      "newly written code");
739     }
740 #endif /* CLUTTER_ENABLE_DEBUG */
741
742   iface->raise (container, actor, sibling);
743 }
744
745 /**
746  * clutter_container_lower_child:
747  * @container: a #ClutterContainer
748  * @actor: the actor to raise
749  * @sibling: (allow-none): the sibling to lower to, or %NULL to lower
750  *   to the bottom
751  *
752  * Lowers @actor to @sibling level, in the depth ordering.
753  *
754  * This function calls the #ClutterContainerIface.lower() virtual function,
755  * which has been deprecated. The default implementation will call
756  * clutter_actor_set_child_below_sibling().
757  *
758  * Virtual: lower
759  *
760  * Since: 0.6
761  *
762  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
763  */
764 void
765 clutter_container_lower_child (ClutterContainer *container,
766                                ClutterActor     *actor,
767                                ClutterActor     *sibling)
768 {
769   ClutterContainerIface *iface;
770   ClutterActor *self;
771
772   g_return_if_fail (CLUTTER_IS_CONTAINER (container));
773   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
774   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
775
776   if (actor == sibling)
777     return;
778
779   self = CLUTTER_ACTOR (container);
780
781   if (clutter_actor_get_parent (actor) != self)
782     {
783       g_warning ("Actor of type '%s' is not a child of the container "
784                  "of type '%s'",
785                  g_type_name (G_OBJECT_TYPE (actor)),
786                  g_type_name (G_OBJECT_TYPE (container)));
787       return;
788     }
789
790   if (sibling != NULL&&
791       clutter_actor_get_parent (sibling) != self)
792     {
793       g_warning ("Actor of type '%s' is not a child of the container "
794                  "of type '%s'",
795                  g_type_name (G_OBJECT_TYPE (sibling)),
796                  g_type_name (G_OBJECT_TYPE (container)));
797       return;
798     }
799
800   iface = CLUTTER_CONTAINER_GET_IFACE (container);
801
802 #ifdef CLUTTER_ENABLE_DEBUG
803   if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
804     {
805       if (iface->lower != container_real_lower)
806         _clutter_diagnostic_message ("The ClutterContainer::lower() "
807                                      "virtual function has been deprecated "
808                                      "and it should not be overridden by "
809                                      "newly written code");
810     }
811 #endif /* CLUTTER_ENABLE_DEBUG */
812
813   iface->lower (container, actor, sibling);
814 }
815
816 /**
817  * clutter_container_sort_depth_order:
818  * @container: a #ClutterContainer
819  *
820  * Sorts a container's children using their depth. This function should not
821  * be normally used by applications.
822  *
823  * Since: 0.6
824  *
825  * Deprecated: 1.10: The #ClutterContainerIface.sort_depth_order() virtual
826  *   function should not be used any more; the default implementation in
827  *   #ClutterContainer does not do anything.
828  */
829 void
830 clutter_container_sort_depth_order (ClutterContainer *container)
831 {
832   ClutterContainerIface *iface;
833
834   g_return_if_fail (CLUTTER_IS_CONTAINER (container));
835
836   iface = CLUTTER_CONTAINER_GET_IFACE (container);
837
838 #ifdef CLUTTER_ENABLE_DEBUG
839   if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
840     {
841       if (iface->sort_depth_order != container_real_sort_depth_order)
842         _clutter_diagnostic_message ("The ClutterContainer::sort_depth_order() "
843                                      "virtual function has been deprecated "
844                                      "and it should not be overridden by "
845                                      "newly written code");
846     }
847 #endif /* CLUTTER_ENABLE_DEBUG */
848
849   iface->sort_depth_order (container);
850 }
851
852 /**
853  * clutter_container_find_child_by_name:
854  * @container: a #ClutterContainer
855  * @child_name: the name of the requested child.
856  *
857  * Finds a child actor of a container by its name. Search recurses
858  * into any child container.
859  *
860  * Return value: (transfer none): The child actor with the requested name,
861  *   or %NULL if no actor with that name was found.
862  *
863  * Since: 0.6
864  */
865 ClutterActor *
866 clutter_container_find_child_by_name (ClutterContainer *container,
867                                       const gchar      *child_name)
868 {
869   GList        *children;
870   GList        *iter;
871   ClutterActor *actor = NULL;
872
873   g_return_val_if_fail (CLUTTER_IS_CONTAINER (container), NULL);
874   g_return_val_if_fail (child_name != NULL, NULL);
875
876   children = clutter_container_get_children (container);
877
878   for (iter = children; iter; iter = g_list_next (iter))
879     {
880       ClutterActor *a;
881       const gchar  *iter_name;
882
883       a = CLUTTER_ACTOR (iter->data);
884       iter_name = clutter_actor_get_name (a);
885
886       if (iter_name && !strcmp (iter_name, child_name))
887         {
888           actor = a;
889           break;
890         }
891
892       if (CLUTTER_IS_CONTAINER (a))
893         {
894           ClutterContainer *c = CLUTTER_CONTAINER (a);
895
896           actor = clutter_container_find_child_by_name (c, child_name);
897           if (actor)
898             break;
899         }
900     }
901
902   g_list_free (children);
903
904   return actor;
905 }
906
907 static ClutterChildMeta *
908 get_child_meta (ClutterContainer *container,
909                 ClutterActor     *actor)
910 {
911   ClutterContainerIface *iface = CLUTTER_CONTAINER_GET_IFACE (container);
912   ClutterChildMeta *meta;
913
914   if (iface->child_meta_type == G_TYPE_INVALID)
915     return NULL;
916
917   meta = g_object_get_qdata (G_OBJECT (actor), quark_child_meta);
918   if (meta != NULL && meta->actor == actor)
919     return meta;
920
921   return NULL;
922 }
923
924 static void
925 create_child_meta (ClutterContainer *container,
926                    ClutterActor     *actor)
927 {
928   ClutterContainerIface *iface = CLUTTER_CONTAINER_GET_IFACE (container);
929   ClutterChildMeta *child_meta = NULL;
930
931   if (iface->child_meta_type == G_TYPE_INVALID)
932     return;
933
934   if (!g_type_is_a (iface->child_meta_type, CLUTTER_TYPE_CHILD_META))
935     {
936       g_warning ("%s: Child data of type '%s' is not a ClutterChildMeta",
937                  G_STRLOC, g_type_name (iface->child_meta_type));
938       return;
939     }
940
941   child_meta = g_object_new (iface->child_meta_type,
942                              "container", container,
943                              "actor", actor,
944                              NULL);
945
946   g_object_set_qdata_full (G_OBJECT (actor), quark_child_meta,
947                            child_meta,
948                            (GDestroyNotify) g_object_unref);
949 }
950
951 static void
952 destroy_child_meta (ClutterContainer *container,
953                     ClutterActor     *actor)
954 {
955   ClutterContainerIface *iface  = CLUTTER_CONTAINER_GET_IFACE (container);
956
957   if (iface->child_meta_type == G_TYPE_INVALID)
958     return;
959
960   g_object_set_qdata (G_OBJECT (actor), quark_child_meta, NULL);
961 }
962
963 /**
964  * clutter_container_get_child_meta:
965  * @container: a #ClutterContainer
966  * @actor: a #ClutterActor that is a child of @container.
967  *
968  * Retrieves the #ClutterChildMeta which contains the data about the
969  * @container specific state for @actor.
970  *
971  * Return value: (transfer none): the #ClutterChildMeta for the @actor child
972  *   of @container or %NULL if the specifiec actor does not exist or the
973  *   container is not configured to provide #ClutterChildMeta<!-- -->s
974  *
975  * Since: 0.8
976  */
977 ClutterChildMeta *
978 clutter_container_get_child_meta (ClutterContainer *container,
979                                   ClutterActor     *actor)
980 {
981   ClutterContainerIface *iface = CLUTTER_CONTAINER_GET_IFACE (container);
982
983   if (iface->child_meta_type == G_TYPE_INVALID)
984     return NULL;
985
986   if (G_LIKELY (iface->get_child_meta))
987     return iface->get_child_meta (container, actor);
988
989   return NULL;
990 }
991
992 /**
993  * clutter_container_create_child_meta:
994  * @container: a #ClutterContainer
995  * @actor: a #ClutterActor
996  *
997  * Creates the #ClutterChildMeta wrapping @actor inside the
998  * @container, if the #ClutterContainerIface::child_meta_type
999  * class member is not set to %G_TYPE_INVALID.
1000  *
1001  * This function is only useful when adding a #ClutterActor to
1002  * a #ClutterContainer implementation outside of the
1003  * #ClutterContainer::add() virtual function implementation.
1004  *
1005  * Applications should not call this function.
1006  *
1007  * Since: 1.2
1008  */
1009 void
1010 clutter_container_create_child_meta (ClutterContainer *container,
1011                                      ClutterActor     *actor)
1012 {
1013   ClutterContainerIface *iface;
1014
1015   g_return_if_fail (CLUTTER_IS_CONTAINER (container));
1016   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
1017
1018   iface = CLUTTER_CONTAINER_GET_IFACE (container);
1019
1020   if (iface->child_meta_type == G_TYPE_INVALID)
1021     return;
1022
1023   g_assert (g_type_is_a (iface->child_meta_type, CLUTTER_TYPE_CHILD_META));
1024
1025   if (G_LIKELY (iface->create_child_meta))
1026     iface->create_child_meta (container, actor);
1027 }
1028
1029 /**
1030  * clutter_container_destroy_child_meta:
1031  * @container: a #ClutterContainer
1032  * @actor: a #ClutterActor
1033  *
1034  * Destroys the #ClutterChildMeta wrapping @actor inside the
1035  * @container, if any.
1036  *
1037  * This function is only useful when removing a #ClutterActor to
1038  * a #ClutterContainer implementation outside of the
1039  * #ClutterContainer::add() virtual function implementation.
1040  *
1041  * Applications should not call this function.
1042  *
1043  * Since: 1.2
1044  */
1045 void
1046 clutter_container_destroy_child_meta (ClutterContainer *container,
1047                                       ClutterActor     *actor)
1048 {
1049   ClutterContainerIface *iface;
1050
1051   g_return_if_fail (CLUTTER_IS_CONTAINER (container));
1052   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
1053
1054   iface = CLUTTER_CONTAINER_GET_IFACE (container);
1055
1056   if (iface->child_meta_type == G_TYPE_INVALID)
1057     return;
1058
1059   if (G_LIKELY (iface->destroy_child_meta))
1060     iface->destroy_child_meta (container, actor);
1061 }
1062
1063 /**
1064  * clutter_container_class_find_child_property:
1065  * @klass: a #GObjectClass implementing the #ClutterContainer interface.
1066  * @property_name: a property name.
1067  *
1068  * Looks up the #GParamSpec for a child property of @klass.
1069  *
1070  * Return value: (transfer none): The #GParamSpec for the property or %NULL
1071  *   if no such property exist.
1072  *
1073  * Since: 0.8
1074  */
1075 GParamSpec *
1076 clutter_container_class_find_child_property (GObjectClass *klass,
1077                                              const gchar  *property_name)
1078 {
1079   ClutterContainerIface *iface;
1080   GObjectClass          *child_class;
1081   GParamSpec            *pspec;
1082
1083   g_return_val_if_fail (G_IS_OBJECT_CLASS (klass), NULL);
1084   g_return_val_if_fail (property_name != NULL, NULL);
1085   g_return_val_if_fail (g_type_is_a (G_TYPE_FROM_CLASS (klass),
1086                                      CLUTTER_TYPE_CONTAINER),
1087                         NULL);
1088
1089   iface = g_type_interface_peek (klass, CLUTTER_TYPE_CONTAINER);
1090   g_return_val_if_fail (iface != NULL, NULL);
1091
1092   if (iface->child_meta_type == G_TYPE_INVALID)
1093     return NULL;
1094
1095   child_class = g_type_class_ref (iface->child_meta_type);
1096   pspec = g_object_class_find_property (child_class, property_name);
1097   g_type_class_unref (child_class);
1098
1099   return pspec;
1100 }
1101
1102 /**
1103  * clutter_container_class_list_child_properties:
1104  * @klass: a #GObjectClass implementing the #ClutterContainer interface.
1105  * @n_properties: return location for length of returned array.
1106  *
1107  * Returns an array of #GParamSpec for all child properties.
1108  *
1109  * Return value: (array length=n_properties) (transfer full): an array
1110  *   of #GParamSpec<!-- -->s which should be freed after use.
1111  *
1112  * Since: 0.8
1113  */
1114 GParamSpec **
1115 clutter_container_class_list_child_properties (GObjectClass *klass,
1116                                                guint        *n_properties)
1117 {
1118   ClutterContainerIface *iface;
1119   GObjectClass          *child_class;
1120   GParamSpec           **retval;
1121
1122   g_return_val_if_fail (G_IS_OBJECT_CLASS (klass), NULL);
1123   g_return_val_if_fail (g_type_is_a (G_TYPE_FROM_CLASS (klass),
1124                                      CLUTTER_TYPE_CONTAINER),
1125                         NULL);
1126
1127   iface = g_type_interface_peek (klass, CLUTTER_TYPE_CONTAINER);
1128   g_return_val_if_fail (iface != NULL, NULL);
1129
1130   if (iface->child_meta_type == G_TYPE_INVALID)
1131     return NULL;
1132
1133   child_class = g_type_class_ref (iface->child_meta_type);
1134   retval = g_object_class_list_properties (child_class, n_properties);
1135   g_type_class_unref (child_class);
1136
1137   return retval;
1138 }
1139
1140 static void
1141 child_notify (ClutterContainer *container,
1142               ClutterActor     *actor,
1143               GParamSpec       *pspec)
1144 {
1145 }
1146
1147 static inline void
1148 container_set_child_property (ClutterContainer *container,
1149                               ClutterActor     *actor,
1150                               const GValue     *value,
1151                               GParamSpec       *pspec)
1152 {
1153   ClutterChildMeta *data;
1154
1155   data = clutter_container_get_child_meta (container, actor);
1156   g_object_set_property (G_OBJECT (data), pspec->name, value);
1157
1158   g_signal_emit (container, container_signals[CHILD_NOTIFY],
1159                  (pspec->flags & G_PARAM_STATIC_NAME)
1160                    ? g_quark_from_static_string (pspec->name)
1161                    : g_quark_from_string (pspec->name),
1162                  actor, pspec);
1163 }
1164
1165 /**
1166  * clutter_container_child_set_property:
1167  * @container: a #ClutterContainer
1168  * @child: a #ClutterActor that is a child of @container.
1169  * @property: the name of the property to set.
1170  * @value: the value.
1171  *
1172  * Sets a container-specific property on a child of @container.
1173  *
1174  * Since: 0.8
1175  */
1176 void
1177 clutter_container_child_set_property (ClutterContainer *container,
1178                                       ClutterActor     *child,
1179                                       const gchar      *property,
1180                                       const GValue     *value)
1181 {
1182   GObjectClass *klass;
1183   GParamSpec   *pspec;
1184
1185   g_return_if_fail (CLUTTER_IS_CONTAINER (container));
1186   g_return_if_fail (CLUTTER_IS_ACTOR (child));
1187   g_return_if_fail (property != NULL);
1188   g_return_if_fail (value != NULL);
1189
1190   klass = G_OBJECT_GET_CLASS (container);
1191
1192   pspec = clutter_container_class_find_child_property (klass, property);
1193   if (!pspec)
1194     {
1195       g_warning ("%s: Containers of type '%s' have no child "
1196                  "property named '%s'",
1197                  G_STRLOC, G_OBJECT_TYPE_NAME (container), property);
1198       return;
1199     }
1200
1201   if (!(pspec->flags & G_PARAM_WRITABLE))
1202     {
1203       g_warning ("%s: Child property '%s' of the container '%s' "
1204                  "is not writable",
1205                  G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (container));
1206       return;
1207     }
1208
1209   container_set_child_property (container, child, value, pspec);
1210 }
1211
1212 /**
1213  * clutter_container_child_set:
1214  * @container: a #ClutterContainer
1215  * @actor: a #ClutterActor that is a child of @container.
1216  * @first_prop: name of the first property to be set.
1217  * @...: value for the first property, followed optionally by more name/value
1218  * pairs terminated with NULL.
1219  *
1220  * Sets container specific properties on the child of a container.
1221  *
1222  * Since: 0.8
1223  */
1224 void
1225 clutter_container_child_set (ClutterContainer *container,
1226                              ClutterActor     *actor,
1227                              const gchar      *first_prop,
1228                              ...)
1229 {
1230   GObjectClass *klass;
1231   const gchar *name;
1232   va_list var_args;
1233   
1234   g_return_if_fail (CLUTTER_IS_CONTAINER (container));
1235   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
1236
1237   klass = G_OBJECT_GET_CLASS (container);
1238
1239   va_start (var_args, first_prop);
1240
1241   name = first_prop;
1242   while (name)
1243     {
1244       GValue value = G_VALUE_INIT;
1245       gchar *error = NULL;
1246       GParamSpec *pspec;
1247     
1248       pspec = clutter_container_class_find_child_property (klass, name);
1249       if (!pspec)
1250         {
1251           g_warning ("%s: Containers of type '%s' have no child "
1252                      "property named '%s'",
1253                      G_STRLOC, G_OBJECT_TYPE_NAME (container), name);
1254           break;
1255         }
1256
1257       if (!(pspec->flags & G_PARAM_WRITABLE))
1258         {
1259           g_warning ("%s: Child property '%s' of the container '%s' "
1260                      "is not writable",
1261                      G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (container));
1262           break;
1263         }
1264
1265       G_VALUE_COLLECT_INIT (&value, G_PARAM_SPEC_VALUE_TYPE (pspec),
1266                             var_args, 0,
1267                             &error);
1268
1269       if (error)
1270         {
1271           /* we intentionally leak the GValue because it might
1272            * be in an undefined state and calling g_value_unset()
1273            * on it might crash
1274            */
1275           g_warning ("%s: %s", G_STRLOC, error);
1276           g_free (error);
1277           break;
1278         }
1279
1280       container_set_child_property (container, actor, &value, pspec);
1281
1282       g_value_unset (&value);
1283
1284       name = va_arg (var_args, gchar*);
1285     }
1286
1287   va_end (var_args);
1288 }
1289
1290 static inline void
1291 container_get_child_property (ClutterContainer *container,
1292                               ClutterActor     *actor,
1293                               GValue           *value,
1294                               GParamSpec       *pspec)
1295 {
1296   ClutterChildMeta *data;
1297
1298   data = clutter_container_get_child_meta (container, actor);
1299   g_object_get_property (G_OBJECT (data), pspec->name, value);
1300 }
1301
1302 /**
1303  * clutter_container_child_get_property:
1304  * @container: a #ClutterContainer
1305  * @child: a #ClutterActor that is a child of @container.
1306  * @property: the name of the property to set.
1307  * @value: the value.
1308  *
1309  * Gets a container specific property of a child of @container, In general,
1310  * a copy is made of the property contents and the caller is responsible for
1311  * freeing the memory by calling g_value_unset().
1312  *
1313  * Note that clutter_container_child_set_property() is really intended for
1314  * language bindings, clutter_container_child_set() is much more convenient
1315  * for C programming.
1316  *
1317  * Since: 0.8
1318  */
1319 void
1320 clutter_container_child_get_property (ClutterContainer *container,
1321                                       ClutterActor     *child,
1322                                       const gchar      *property,
1323                                       GValue           *value)
1324 {
1325   GObjectClass *klass;
1326   GParamSpec   *pspec;
1327
1328   g_return_if_fail (CLUTTER_IS_CONTAINER (container));
1329   g_return_if_fail (CLUTTER_IS_ACTOR (child));
1330   g_return_if_fail (property != NULL);
1331   g_return_if_fail (value != NULL);
1332
1333   klass = G_OBJECT_GET_CLASS (container);
1334
1335   pspec = clutter_container_class_find_child_property (klass, property);
1336   if (!pspec)
1337     {
1338       g_warning ("%s: Containers of type '%s' have no child "
1339                  "property named '%s'",
1340                  G_STRLOC, G_OBJECT_TYPE_NAME (container), property);
1341       return;
1342     }
1343
1344   if (!(pspec->flags & G_PARAM_READABLE))
1345     {
1346       g_warning ("%s: Child property '%s' of the container '%s' "
1347                  "is not writable",
1348                  G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (container));
1349       return;
1350     }
1351
1352   container_get_child_property (container, child, value, pspec);
1353 }
1354
1355
1356 /**
1357  * clutter_container_child_get:
1358  * @container: a #ClutterContainer
1359  * @actor: a #ClutterActor that is a child of @container.
1360  * @first_prop: name of the first property to be set.
1361  * @...: value for the first property, followed optionally by more name/value
1362  * pairs terminated with NULL.
1363  *
1364  * Gets @container specific properties of an actor.
1365  *
1366  * In general, a copy is made of the property contents and the caller is
1367  * responsible for freeing the memory in the appropriate manner for the type, for
1368  * instance by calling g_free() or g_object_unref(). 
1369  *
1370  * Since: 0.8
1371  */
1372 void
1373 clutter_container_child_get (ClutterContainer *container,
1374                              ClutterActor     *actor,
1375                              const gchar      *first_prop,
1376                              ...)
1377 {
1378   GObjectClass *klass;
1379   const gchar *name;
1380   va_list var_args;
1381   
1382   g_return_if_fail (CLUTTER_IS_CONTAINER (container));
1383   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
1384
1385   klass = G_OBJECT_GET_CLASS (container);
1386
1387   va_start (var_args, first_prop);
1388
1389   name = first_prop;
1390   while (name)
1391     {
1392       GValue value = G_VALUE_INIT;
1393       gchar *error = NULL;
1394       GParamSpec *pspec;
1395     
1396       pspec = clutter_container_class_find_child_property (klass, name);
1397       if (!pspec)
1398         {
1399           g_warning ("%s: container '%s' has no child property named '%s'",
1400                      G_STRLOC, G_OBJECT_TYPE_NAME (container), name);
1401           break;
1402         }
1403
1404       if (!(pspec->flags & G_PARAM_READABLE))
1405         {
1406           g_warning ("%s: child property '%s' of container '%s' is not readable",
1407                      G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (container));
1408           break;
1409         }
1410
1411       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1412
1413       container_get_child_property (container, actor, &value, pspec);
1414
1415       G_VALUE_LCOPY (&value, var_args, 0, &error);
1416       if (error)
1417         {
1418           g_warning ("%s: %s", G_STRLOC, error);
1419           g_free (error);
1420           g_value_unset (&value);
1421           break;
1422         }
1423
1424       g_value_unset (&value);
1425
1426       name = va_arg (var_args, gchar*);
1427     }
1428
1429   va_end (var_args);
1430 }
1431
1432 /**
1433  * clutter_container_child_notify:
1434  * @container: a #ClutterContainer
1435  * @child: a #ClutterActor
1436  * @pspec: a #GParamSpec
1437  *
1438  * Calls the #ClutterContainerIface.child_notify() virtual function
1439  * of #ClutterContainer. The default implementation will emit the
1440  * #ClutterContainer::child-notify signal.
1441  *
1442  * Since: 1.6
1443  */
1444 void
1445 clutter_container_child_notify (ClutterContainer *container,
1446                                 ClutterActor     *child,
1447                                 GParamSpec       *pspec)
1448 {
1449   g_return_if_fail (CLUTTER_IS_CONTAINER (container));
1450   g_return_if_fail (CLUTTER_IS_ACTOR (child));
1451   g_return_if_fail (pspec != NULL);
1452
1453   g_return_if_fail (clutter_actor_get_parent (child) == CLUTTER_ACTOR (container));
1454
1455   CLUTTER_CONTAINER_GET_IFACE (container)->child_notify (container,
1456                                                          child,
1457                                                          pspec);
1458 }