actor: Add ClutterActorIter.destroy()
[profile/ivi/clutter.git] / clutter / clutter-actor.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, 2007, 2008 OpenedHand Ltd
9  * Copyright (C) 2009, 2010 Intel Corp
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /**
26  * SECTION:clutter-actor
27  * @short_description: Base abstract class for all visual stage actors.
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="bin-layout">
113  *     <title>Actors</title>
114  *     <graphic fileref="test-actor.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-events">
119  *   <title>Handling events on an actor</title>
120  *   <para>A #ClutterActor can receive and handle input device events, for
121  *   instance pointer events and key events, as long as its
122  *   #ClutterActor:reactive property is set to %TRUE.</para>
123  *   <para>Once an actor has been determined to be the source of an event,
124  *   Clutter will traverse the scene graph from the top-level actor towards the
125  *   event source, emitting the #ClutterActor::captured-event signal on each
126  *   ancestor until it reaches the source; this phase is also called
127  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
128  *   stopped, the graph is walked backwards, from the source actor to the
129  *   top-level, and the #ClutterActor::event signal, along with other event
130  *   signals if needed, is emitted; this phase is also called <emphasis>the
131  *   bubble phase</emphasis>. At any point of the signal emission, signal
132  *   handlers can stop the propagation through the scene graph by returning
133  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
134  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
135  * </refsect2>
136  *
137  * <refsect2 id="ClutterActor-subclassing">
138  *   <title>Implementing an actor</title>
139  *   <para>Careful consideration should be given when deciding to implement
140  *   a #ClutterActor sub-class. It is generally recommended to implement a
141  *   sub-class of #ClutterActor only for actors that should be used as leaf
142  *   nodes of a scene graph.</para>
143  *   <para>If your actor should be painted in a custom way, you should
144  *   override the #ClutterActor::paint signal class handler. You can either
145  *   opt to chain up to the parent class implementation or decide to fully
146  *   override the default paint implementation; Clutter will set up the
147  *   transformations and clip regions prior to emitting the #ClutterActor::paint
148  *   signal.</para>
149  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
150  *   #ClutterActorClass.get_preferred_height() virtual functions it is
151  *   possible to change or provide the preferred size of an actor; similarly,
152  *   by overriding the #ClutterActorClass.allocate() virtual function it is
153  *   possible to control the layout of the children of an actor. Make sure to
154  *   always chain up to the parent implementation of the
155  *   #ClutterActorClass.allocate() virtual function.</para>
156  *   <para>In general, it is strongly encouraged to use delegation and
157  *   composition instead of direct subclassing.</para>
158  * </refsect2>
159  *
160  * <refsect2 id="ClutterActor-script">
161  *   <title>ClutterActor custom properties for #ClutterScript</title>
162  *   <para>#ClutterActor defines a custom "rotation" property which
163  *   allows a short-hand description of the rotations to be applied
164  *   to an actor.</para>
165  *   <para>The syntax of the "rotation" property is the following:</para>
166  *   <informalexample>
167  *     <programlisting>
168  * "rotation" : [
169  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
170  * ]
171  *     </programlisting>
172  *   </informalexample>
173  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
174  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
175  *   floating point value representing the rotation angle on the given axis,
176  *   in degrees.</para>
177  *   <para>The <emphasis>center</emphasis> array is optional, and if present
178  *   it must contain the center of rotation as described by two coordinates:
179  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
180  *   "z-axis".</para>
181  *   <para>#ClutterActor will also parse every positional and dimensional
182  *   property defined as a string through clutter_units_from_string(); you
183  *   should read the documentation for the #ClutterUnits parser format for
184  *   the valid units and syntax.</para>
185  * </refsect2>
186  *
187  * <refsect2 id="ClutterActor-animating">
188  *   <title>Custom animatable properties</title>
189  *   <para>#ClutterActor allows accessing properties of #ClutterAction
190  *   and #ClutterConstraint instances associated to an actor instance
191  *   for animation purposes.</para>
192  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
193  *   property it is necessary to set the #ClutterActorMeta:name property on the
194  *   given action or constraint.</para>
195  *   <para>The property can be accessed using the following syntax:</para>
196  *   <informalexample>
197  *     <programlisting>
198  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
199  *     </programlisting>
200  *   </informalexample>
201  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
202  *   <para>The <emphasis>section</emphasis> fragment can be one between
203  *   "actions", "constraints" and "effects".</para>
204  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
205  *   action or constraint, as specified by the #ClutterActorMeta:name
206  *   property.</para>
207  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
208  *   action or constraint property to be animated.</para>
209  *   <para>The example below animates a #ClutterBindConstraint applied to an
210  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
211  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
212  *   its initial state is fully transparent and overlapping the actor to
213  *   which is bound to. </para>
214  *   <informalexample><programlisting>
215  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
216  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
217  * clutter_actor_add_constraint (rect, constraint);
218  *
219  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
220  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
221  * clutter_actor_add_constraint (rect, constraint);
222  *
223  * clutter_actor_set_reactive (rect, TRUE);
224  * clutter_actor_set_opacity (rect, 0);
225  *
226  * g_signal_connect (rect, "button-press-event",
227  *                   G_CALLBACK (on_button_press),
228  *                   NULL);
229  *   </programlisting></informalexample>
230  *   <para>On button press, the rectangle "slides" from behind the actor to
231  *   which is bound to, using the #ClutterBindConstraint:offset property and
232  *   the #ClutterActor:opacity property.</para>
233  *   <informalexample><programlisting>
234  * float new_offset = clutter_actor_get_width (origin) + h_padding;
235  *
236  * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
237  *                        "opacity", 255,
238  *                        "@constraints.bind-x.offset", new_offset,
239  *                        NULL);
240  *   </programlisting></informalexample>
241  * </refsect2>
242  */
243
244 /**
245  * CLUTTER_ACTOR_IS_MAPPED:
246  * @a: a #ClutterActor
247  *
248  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
249  *
250  * The mapped state is set when the actor is visible and all its parents up
251  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
252  *
253  * This check can be used to see if an actor is going to be painted, as only
254  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
255  *
256  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
257  * not be checked directly; instead, the recommended usage is to connect a
258  * handler on the #GObject::notify signal for the #ClutterActor:mapped
259  * property of #ClutterActor, and check the presence of
260  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
261  *
262  * It is also important to note that Clutter may delay the changes of
263  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
264  * limitations, or during the reparenting of an actor, to optimize
265  * unnecessary (and potentially expensive) state changes.
266  *
267  * Since: 0.2
268  */
269
270 /**
271  * CLUTTER_ACTOR_IS_REALIZED:
272  * @a: a #ClutterActor
273  *
274  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
275  *
276  * The realized state has an actor-dependant interpretation. If an
277  * actor wants to delay allocating resources until it is attached to a
278  * stage, it may use the realize state to do so. However it is
279  * perfectly acceptable for an actor to allocate Cogl resources before
280  * being realized because there is only one drawing context used by Clutter
281  * so any resources will work on any stage.  If an actor is mapped it
282  * must also be realized, but an actor can be realized and unmapped
283  * (this is so hiding an actor temporarily doesn't do an expensive
284  * unrealize/realize).
285  *
286  * To be realized an actor must be inside a stage, and all its parents
287  * must be realized.
288  *
289  * Since: 0.2
290  */
291
292 /**
293  * CLUTTER_ACTOR_IS_VISIBLE:
294  * @a: a #ClutterActor
295  *
296  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
297  * Equivalent to the ClutterActor::visible object property.
298  *
299  * Note that an actor is only painted onscreen if it's mapped, which
300  * means it's visible, and all its parents are visible, and one of the
301  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
302  *
303  * Since: 0.2
304  */
305
306 /**
307  * CLUTTER_ACTOR_IS_REACTIVE:
308  * @a: a #ClutterActor
309  *
310  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
311  *
312  * Only reactive actors will receive event-related signals.
313  *
314  * Since: 0.6
315  */
316
317 #ifdef HAVE_CONFIG_H
318 #include "config.h"
319 #endif
320
321 #include <math.h>
322
323 #include "cogl/cogl.h"
324
325 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
326
327 #include "clutter-actor-private.h"
328
329 #include "clutter-action.h"
330 #include "clutter-actor-meta-private.h"
331 #include "clutter-animatable.h"
332 #include "clutter-color-static.h"
333 #include "clutter-color.h"
334 #include "clutter-constraint.h"
335 #include "clutter-container.h"
336 #include "clutter-debug.h"
337 #include "clutter-effect-private.h"
338 #include "clutter-enum-types.h"
339 #include "clutter-fixed-layout.h"
340 #include "clutter-main.h"
341 #include "clutter-marshal.h"
342 #include "clutter-flatten-effect.h"
343 #include "clutter-paint-volume-private.h"
344 #include "clutter-private.h"
345 #include "clutter-profile.h"
346 #include "clutter-scriptable.h"
347 #include "clutter-script-private.h"
348 #include "clutter-stage-private.h"
349 #include "clutter-units.h"
350
351 #include "deprecated/clutter-behaviour.h"
352 #include "deprecated/clutter-container.h"
353
354 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
355 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
356
357 /* Internal enum used to control mapped state update.  This is a hint
358  * which indicates when to do something other than just enforce
359  * invariants.
360  */
361 typedef enum {
362   MAP_STATE_CHECK,           /* just enforce invariants. */
363   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
364                               * used when about to unparent.
365                               */
366   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
367                               * used to set mapped on toplevels.
368                               */
369   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
370                               * used just before unmapping parent.
371                               */
372 } MapStateChange;
373
374 /* 3 entries should be a good compromise, few layout managers
375  * will ask for 3 different preferred size in each allocation cycle */
376 #define N_CACHED_SIZE_REQUESTS 3
377
378 struct _ClutterActorPrivate
379 {
380   /* request mode */
381   ClutterRequestMode request_mode;
382
383   /* our cached size requests for different width / height */
384   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
385   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
386
387   /* An age of 0 means the entry is not set */
388   guint cached_height_age;
389   guint cached_width_age;
390
391   /* the bounding box of the actor, relative to the parent's
392    * allocation
393    */
394   ClutterActorBox allocation;
395   ClutterAllocationFlags allocation_flags;
396
397   /* depth */
398   gfloat z;
399
400   /* clip, in actor coordinates */
401   cairo_rectangle_t clip;
402
403   /* the cached transformation matrix; see apply_transform() */
404   CoglMatrix transform;
405
406   guint8 opacity;
407   gint opacity_override;
408
409   ClutterOffscreenRedirect offscreen_redirect;
410
411   /* This is an internal effect used to implement the
412      offscreen-redirect property */
413   ClutterEffect *flatten_effect;
414
415   /* scene graph */
416   ClutterActor *parent;
417   ClutterActor *prev_sibling;
418   ClutterActor *next_sibling;
419   ClutterActor *first_child;
420   ClutterActor *last_child;
421
422   gint n_children;
423
424   /* tracks whenever the children of an actor are changed; the
425    * age is incremented by 1 whenever an actor is added or
426    * removed. the age is not incremented when the first or the
427    * last child pointers are changed, or when grandchildren of
428    * an actor are changed.
429    */
430   gint age;
431
432   gchar *name; /* a non-unique name, used for debugging */
433   guint32 id; /* unique id, used for backward compatibility */
434
435   gint32 pick_id; /* per-stage unique id, used for picking */
436
437   /* a back-pointer to the Pango context that we can use
438    * to create pre-configured PangoLayout
439    */
440   PangoContext *pango_context;
441
442   /* the text direction configured for this child - either by
443    * application code, or by the actor's parent
444    */
445   ClutterTextDirection text_direction;
446
447   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
448   gint internal_child;
449
450   /* meta classes */
451   ClutterMetaGroup *actions;
452   ClutterMetaGroup *constraints;
453   ClutterMetaGroup *effects;
454
455   /* delegate object used to allocate the children of this actor */
456   ClutterLayoutManager *layout_manager;
457
458   /* used when painting, to update the paint volume */
459   ClutterEffect *current_effect;
460
461   /* This is used to store an effect which needs to be redrawn. A
462      redraw can be queued to start from a particular effect. This is
463      used by parametrised effects that can cache an image of the
464      actor. If a parameter of the effect changes then it only needs to
465      redraw the cached image, not the actual actor. The pointer is
466      only valid if is_dirty == TRUE. If the pointer is NULL then the
467      whole actor is dirty. */
468   ClutterEffect *effect_to_redraw;
469
470   /* This is used when painting effects to implement the
471      clutter_actor_continue_paint() function. It points to the node in
472      the list of effects that is next in the chain */
473   const GList *next_effect_to_paint;
474
475   ClutterPaintVolume paint_volume;
476
477   /* NB: This volume isn't relative to this actor, it is in eye
478    * coordinates so that it can remain valid after the actor changes.
479    */
480   ClutterPaintVolume last_paint_volume;
481
482   ClutterStageQueueRedrawEntry *queue_redraw_entry;
483
484   ClutterColor bg_color;
485
486   /* bitfields */
487
488   /* fixed position and sizes */
489   guint position_set                : 1;
490   guint min_width_set               : 1;
491   guint min_height_set              : 1;
492   guint natural_width_set           : 1;
493   guint natural_height_set          : 1;
494   /* cached request is invalid (implies allocation is too) */
495   guint needs_width_request         : 1;
496   /* cached request is invalid (implies allocation is too) */
497   guint needs_height_request        : 1;
498   /* cached allocation is invalid (request has changed, probably) */
499   guint needs_allocation            : 1;
500   guint show_on_set_parent          : 1;
501   guint has_clip                    : 1;
502   guint clip_to_allocation          : 1;
503   guint enable_model_view_transform : 1;
504   guint enable_paint_unmapped       : 1;
505   guint has_pointer                 : 1;
506   guint propagated_one_redraw       : 1;
507   guint paint_volume_valid          : 1;
508   guint last_paint_volume_valid     : 1;
509   guint in_clone_paint              : 1;
510   guint transform_valid             : 1;
511   /* This is TRUE if anything has queued a redraw since we were last
512      painted. In this case effect_to_redraw will point to an effect
513      the redraw was queued from or it will be NULL if the redraw was
514      queued without an effect. */
515   guint is_dirty                    : 1;
516   guint bg_color_set                : 1;
517 };
518
519 enum
520 {
521   PROP_0,
522
523   PROP_NAME,
524
525   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
526    * when set they force a size request, when gotten they
527    * get the allocation if the allocation is valid, and the
528    * request otherwise
529    */
530   PROP_X,
531   PROP_Y,
532   PROP_WIDTH,
533   PROP_HEIGHT,
534
535   /* Then the rest of these size-related properties are the "actual"
536    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
537    */
538   PROP_FIXED_X,
539   PROP_FIXED_Y,
540
541   PROP_FIXED_POSITION_SET,
542
543   PROP_MIN_WIDTH,
544   PROP_MIN_WIDTH_SET,
545
546   PROP_MIN_HEIGHT,
547   PROP_MIN_HEIGHT_SET,
548
549   PROP_NATURAL_WIDTH,
550   PROP_NATURAL_WIDTH_SET,
551
552   PROP_NATURAL_HEIGHT,
553   PROP_NATURAL_HEIGHT_SET,
554
555   PROP_REQUEST_MODE,
556
557   /* Allocation properties are read-only */
558   PROP_ALLOCATION,
559
560   PROP_DEPTH,
561
562   PROP_CLIP,
563   PROP_HAS_CLIP,
564   PROP_CLIP_TO_ALLOCATION,
565
566   PROP_OPACITY,
567
568   PROP_OFFSCREEN_REDIRECT,
569
570   PROP_VISIBLE,
571   PROP_MAPPED,
572   PROP_REALIZED,
573   PROP_REACTIVE,
574
575   PROP_SCALE_X,
576   PROP_SCALE_Y,
577   PROP_SCALE_CENTER_X,
578   PROP_SCALE_CENTER_Y,
579   PROP_SCALE_GRAVITY,
580
581   PROP_ROTATION_ANGLE_X,
582   PROP_ROTATION_ANGLE_Y,
583   PROP_ROTATION_ANGLE_Z,
584   PROP_ROTATION_CENTER_X,
585   PROP_ROTATION_CENTER_Y,
586   PROP_ROTATION_CENTER_Z,
587   /* This property only makes sense for the z rotation because the
588      others would depend on the actor having a size along the
589      z-axis */
590   PROP_ROTATION_CENTER_Z_GRAVITY,
591
592   PROP_ANCHOR_X,
593   PROP_ANCHOR_Y,
594   PROP_ANCHOR_GRAVITY,
595
596   PROP_SHOW_ON_SET_PARENT,
597
598   PROP_TEXT_DIRECTION,
599   PROP_HAS_POINTER,
600
601   PROP_ACTIONS,
602   PROP_CONSTRAINTS,
603   PROP_EFFECT,
604
605   PROP_LAYOUT_MANAGER,
606
607   PROP_X_ALIGN,
608   PROP_Y_ALIGN,
609   PROP_MARGIN_TOP,
610   PROP_MARGIN_BOTTOM,
611   PROP_MARGIN_LEFT,
612   PROP_MARGIN_RIGHT,
613
614   PROP_BACKGROUND_COLOR,
615   PROP_BACKGROUND_COLOR_SET,
616
617   PROP_FIRST_CHILD,
618   PROP_LAST_CHILD,
619
620   PROP_LAST
621 };
622
623 static GParamSpec *obj_props[PROP_LAST];
624
625 enum
626 {
627   SHOW,
628   HIDE,
629   DESTROY,
630   PARENT_SET,
631   KEY_FOCUS_IN,
632   KEY_FOCUS_OUT,
633   PAINT,
634   PICK,
635   REALIZE,
636   UNREALIZE,
637   QUEUE_REDRAW,
638   QUEUE_RELAYOUT,
639   EVENT,
640   CAPTURED_EVENT,
641   BUTTON_PRESS_EVENT,
642   BUTTON_RELEASE_EVENT,
643   SCROLL_EVENT,
644   KEY_PRESS_EVENT,
645   KEY_RELEASE_EVENT,
646   MOTION_EVENT,
647   ENTER_EVENT,
648   LEAVE_EVENT,
649   ALLOCATION_CHANGED,
650
651   LAST_SIGNAL
652 };
653
654 static guint actor_signals[LAST_SIGNAL] = { 0, };
655
656 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
657 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
658 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
659 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
660
661 /* These setters are all static for now, maybe they should be in the
662  * public API, but they are perhaps obscure enough to leave only as
663  * properties
664  */
665 static void clutter_actor_set_min_width          (ClutterActor *self,
666                                                   gfloat        min_width);
667 static void clutter_actor_set_min_height         (ClutterActor *self,
668                                                   gfloat        min_height);
669 static void clutter_actor_set_natural_width      (ClutterActor *self,
670                                                   gfloat        natural_width);
671 static void clutter_actor_set_natural_height     (ClutterActor *self,
672                                                   gfloat        natural_height);
673 static void clutter_actor_set_min_width_set      (ClutterActor *self,
674                                                   gboolean      use_min_width);
675 static void clutter_actor_set_min_height_set     (ClutterActor *self,
676                                                   gboolean      use_min_height);
677 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
678                                                   gboolean  use_natural_width);
679 static void clutter_actor_set_natural_height_set (ClutterActor *self,
680                                                   gboolean  use_natural_height);
681 static void clutter_actor_update_map_state       (ClutterActor  *self,
682                                                   MapStateChange change);
683 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
684
685 /* Helper routines for managing anchor coords */
686 static void clutter_anchor_coord_get_units (ClutterActor      *self,
687                                             const AnchorCoord *coord,
688                                             gfloat            *x,
689                                             gfloat            *y,
690                                             gfloat            *z);
691 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
692                                             gfloat             x,
693                                             gfloat             y,
694                                             gfloat             z);
695
696 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
697 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
698                                                         ClutterGravity     gravity);
699
700 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
701
702 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
703
704 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
705                                                                ClutterActor *ancestor,
706                                                                CoglMatrix *matrix);
707
708 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
709
710 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
711
712 static void on_layout_manager_changed (ClutterLayoutManager *manager,
713                                        ClutterActor         *self);
714
715 /* Helper macro which translates by the anchor coord, applies the
716    given transformation and then translates back */
717 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
718   gfloat _tx, _ty, _tz;                                                \
719   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
720   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
721   { _transform; }                                                      \
722   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
723
724 static GQuark quark_shader_data = 0;
725 static GQuark quark_actor_layout_info = 0;
726 static GQuark quark_actor_transform_info = 0;
727
728 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
729                          clutter_actor,
730                          G_TYPE_INITIALLY_UNOWNED,
731                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
732                                                 clutter_container_iface_init)
733                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
734                                                 clutter_scriptable_iface_init)
735                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
736                                                 clutter_animatable_iface_init)
737                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
738                                                 atk_implementor_iface_init));
739
740 /*< private >
741  * clutter_actor_get_debug_name:
742  * @actor: a #ClutterActor
743  *
744  * Retrieves a printable name of @actor for debugging messages
745  *
746  * Return value: a string with a printable name
747  */
748 const gchar *
749 _clutter_actor_get_debug_name (ClutterActor *actor)
750 {
751   return actor->priv->name != NULL ? actor->priv->name
752                                    : G_OBJECT_TYPE_NAME (actor);
753 }
754
755 #ifdef CLUTTER_ENABLE_DEBUG
756 /* XXX - this is for debugging only, remove once working (or leave
757  * in only in some debug mode). Should leave it for a little while
758  * until we're confident in the new map/realize/visible handling.
759  */
760 static inline void
761 clutter_actor_verify_map_state (ClutterActor *self)
762 {
763   ClutterActorPrivate *priv = self->priv;
764
765   if (CLUTTER_ACTOR_IS_REALIZED (self))
766     {
767       /* all bets are off during reparent when we're potentially realized,
768        * but should not be according to invariants
769        */
770       if (!CLUTTER_ACTOR_IN_REPARENT (self))
771         {
772           if (priv->parent == NULL)
773             {
774               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
775                 {
776                 }
777               else
778                 g_warning ("Realized non-toplevel actor '%s' should "
779                            "have a parent",
780                            _clutter_actor_get_debug_name (self));
781             }
782           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
783             {
784               g_warning ("Realized actor %s has an unrealized parent %s",
785                          _clutter_actor_get_debug_name (self),
786                          _clutter_actor_get_debug_name (priv->parent));
787             }
788         }
789     }
790
791   if (CLUTTER_ACTOR_IS_MAPPED (self))
792     {
793       if (!CLUTTER_ACTOR_IS_REALIZED (self))
794         g_warning ("Actor '%s' is mapped but not realized",
795                    _clutter_actor_get_debug_name (self));
796
797       /* remaining bets are off during reparent when we're potentially
798        * mapped, but should not be according to invariants
799        */
800       if (!CLUTTER_ACTOR_IN_REPARENT (self))
801         {
802           if (priv->parent == NULL)
803             {
804               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
805                 {
806                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
807                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
808                     {
809                       g_warning ("Toplevel actor '%s' is mapped "
810                                  "but not visible",
811                                  _clutter_actor_get_debug_name (self));
812                     }
813                 }
814               else
815                 {
816                   g_warning ("Mapped actor '%s' should have a parent",
817                              _clutter_actor_get_debug_name (self));
818                 }
819             }
820           else
821             {
822               ClutterActor *iter = self;
823
824               /* check for the enable_paint_unmapped flag on the actor
825                * and parents; if the flag is enabled at any point of this
826                * branch of the scene graph then all the later checks
827                * become pointless
828                */
829               while (iter != NULL)
830                 {
831                   if (iter->priv->enable_paint_unmapped)
832                     return;
833
834                   iter = iter->priv->parent;
835                 }
836
837               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
838                 {
839                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
840                              "is not visible",
841                              _clutter_actor_get_debug_name (self),
842                              _clutter_actor_get_debug_name (priv->parent));
843                 }
844
845               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
846                 {
847                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
848                              "is not realized",
849                              _clutter_actor_get_debug_name (self),
850                              _clutter_actor_get_debug_name (priv->parent));
851                 }
852
853               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
854                 {
855                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
856                     g_warning ("Actor '%s' is mapped but its non-toplevel "
857                                "parent '%s' is not mapped",
858                                _clutter_actor_get_debug_name (self),
859                                _clutter_actor_get_debug_name (priv->parent));
860                 }
861             }
862         }
863     }
864 }
865
866 #endif /* CLUTTER_ENABLE_DEBUG */
867
868 static void
869 clutter_actor_set_mapped (ClutterActor *self,
870                           gboolean      mapped)
871 {
872   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
873     return;
874
875   if (mapped)
876     {
877       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
878       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
879     }
880   else
881     {
882       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
883       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
884     }
885 }
886
887 /* this function updates the mapped and realized states according to
888  * invariants, in the appropriate order.
889  */
890 static void
891 clutter_actor_update_map_state (ClutterActor  *self,
892                                 MapStateChange change)
893 {
894   gboolean was_mapped;
895
896   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
897
898   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
899     {
900       /* the mapped flag on top-level actors must be set by the
901        * per-backend implementation because it might be asynchronous.
902        *
903        * That is, the MAPPED flag on toplevels currently tracks the X
904        * server mapped-ness of the window, while the expected behavior
905        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
906        * This creates some weird complexity by breaking the invariant
907        * that if we're visible and all ancestors shown then we are
908        * also mapped - instead, we are mapped if all ancestors
909        * _possibly excepting_ the stage are mapped. The stage
910        * will map/unmap for example when it is minimized or
911        * moved to another workspace.
912        *
913        * So, the only invariant on the stage is that if visible it
914        * should be realized, and that it has to be visible to be
915        * mapped.
916        */
917       if (CLUTTER_ACTOR_IS_VISIBLE (self))
918         clutter_actor_realize (self);
919
920       switch (change)
921         {
922         case MAP_STATE_CHECK:
923           break;
924
925         case MAP_STATE_MAKE_MAPPED:
926           g_assert (!was_mapped);
927           clutter_actor_set_mapped (self, TRUE);
928           break;
929
930         case MAP_STATE_MAKE_UNMAPPED:
931           g_assert (was_mapped);
932           clutter_actor_set_mapped (self, FALSE);
933           break;
934
935         case MAP_STATE_MAKE_UNREALIZED:
936           /* we only use MAKE_UNREALIZED in unparent,
937            * and unparenting a stage isn't possible.
938            * If someone wants to just unrealize a stage
939            * then clutter_actor_unrealize() doesn't
940            * go through this codepath.
941            */
942           g_warning ("Trying to force unrealize stage is not allowed");
943           break;
944         }
945
946       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
947           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
948           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
949         {
950           g_warning ("Clutter toplevel of type '%s' is not visible, but "
951                      "it is somehow still mapped",
952                      _clutter_actor_get_debug_name (self));
953         }
954     }
955   else
956     {
957       ClutterActorPrivate *priv = self->priv;
958       ClutterActor *parent = priv->parent;
959       gboolean should_be_mapped;
960       gboolean may_be_realized;
961       gboolean must_be_realized;
962
963       should_be_mapped = FALSE;
964       may_be_realized = TRUE;
965       must_be_realized = FALSE;
966
967       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
968         {
969           may_be_realized = FALSE;
970         }
971       else
972         {
973           /* Maintain invariant that if parent is mapped, and we are
974            * visible, then we are mapped ...  unless parent is a
975            * stage, in which case we map regardless of parent's map
976            * state but do require stage to be visible and realized.
977            *
978            * If parent is realized, that does not force us to be
979            * realized; but if parent is unrealized, that does force
980            * us to be unrealized.
981            *
982            * The reason we don't force children to realize with
983            * parents is _clutter_actor_rerealize(); if we require that
984            * a realized parent means children are realized, then to
985            * unrealize an actor we would have to unrealize its
986            * parents, which would end up meaning unrealizing and
987            * hiding the entire stage. So we allow unrealizing a
988            * child (as long as that child is not mapped) while that
989            * child still has a realized parent.
990            *
991            * Also, if we unrealize from leaf nodes to root, and
992            * realize from root to leaf, the invariants are never
993            * violated if we allow children to be unrealized
994            * while parents are realized.
995            *
996            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
997            * to force us to unmap, even though parent is still
998            * mapped. This is because we're unmapping from leaf nodes
999            * up to root nodes.
1000            */
1001           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1002               change != MAP_STATE_MAKE_UNMAPPED)
1003             {
1004               gboolean parent_is_visible_realized_toplevel;
1005
1006               parent_is_visible_realized_toplevel =
1007                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1008                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1009                  CLUTTER_ACTOR_IS_REALIZED (parent));
1010
1011               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1012                   parent_is_visible_realized_toplevel)
1013                 {
1014                   must_be_realized = TRUE;
1015                   should_be_mapped = TRUE;
1016                 }
1017             }
1018
1019           /* if the actor has been set to be painted even if unmapped
1020            * then we should map it and check for realization as well;
1021            * this is an override for the branch of the scene graph
1022            * which begins with this node
1023            */
1024           if (priv->enable_paint_unmapped)
1025             {
1026               if (priv->parent == NULL)
1027                 g_warning ("Attempting to map an unparented actor '%s'",
1028                            _clutter_actor_get_debug_name (self));
1029
1030               should_be_mapped = TRUE;
1031               must_be_realized = TRUE;
1032             }
1033
1034           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1035             may_be_realized = FALSE;
1036         }
1037
1038       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1039         {
1040           if (parent == NULL)
1041             g_warning ("Attempting to map a child that does not "
1042                        "meet the necessary invariants: the actor '%s' "
1043                        "has no parent",
1044                        _clutter_actor_get_debug_name (self));
1045           else
1046             g_warning ("Attempting to map a child that does not "
1047                        "meet the necessary invariants: the actor '%s' "
1048                        "is parented to an unmapped actor '%s'",
1049                        _clutter_actor_get_debug_name (self),
1050                        _clutter_actor_get_debug_name (priv->parent));
1051         }
1052
1053       /* If in reparent, we temporarily suspend unmap and unrealize.
1054        *
1055        * We want to go in the order "realize, map" and "unmap, unrealize"
1056        */
1057
1058       /* Unmap */
1059       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1060         clutter_actor_set_mapped (self, FALSE);
1061
1062       /* Realize */
1063       if (must_be_realized)
1064         clutter_actor_realize (self);
1065
1066       /* if we must be realized then we may be, presumably */
1067       g_assert (!(must_be_realized && !may_be_realized));
1068
1069       /* Unrealize */
1070       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1071         clutter_actor_unrealize_not_hiding (self);
1072
1073       /* Map */
1074       if (should_be_mapped)
1075         {
1076           if (!must_be_realized)
1077             g_warning ("Somehow we think actor '%s' should be mapped but "
1078                        "not realized, which isn't allowed",
1079                        _clutter_actor_get_debug_name (self));
1080
1081           /* realization is allowed to fail (though I don't know what
1082            * an app is supposed to do about that - shouldn't it just
1083            * be a g_error? anyway, we have to avoid mapping if this
1084            * happens)
1085            */
1086           if (CLUTTER_ACTOR_IS_REALIZED (self))
1087             clutter_actor_set_mapped (self, TRUE);
1088         }
1089     }
1090
1091 #ifdef CLUTTER_ENABLE_DEBUG
1092   /* check all invariants were kept */
1093   clutter_actor_verify_map_state (self);
1094 #endif
1095 }
1096
1097 static void
1098 clutter_actor_real_map (ClutterActor *self)
1099 {
1100   ClutterActorPrivate *priv = self->priv;
1101   ClutterActor *stage, *iter;
1102
1103   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1104
1105   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1106                 _clutter_actor_get_debug_name (self));
1107
1108   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1109
1110   stage = _clutter_actor_get_stage_internal (self);
1111   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1112
1113   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1114                 priv->pick_id,
1115                 _clutter_actor_get_debug_name (self));
1116
1117   /* notify on parent mapped before potentially mapping
1118    * children, so apps see a top-down notification.
1119    */
1120   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1121
1122   for (iter = self->priv->first_child;
1123        iter != NULL;
1124        iter = iter->priv->next_sibling)
1125     {
1126       clutter_actor_map (iter);
1127     }
1128 }
1129
1130 /**
1131  * clutter_actor_map:
1132  * @self: A #ClutterActor
1133  *
1134  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1135  * and realizes its children if they are visible. Does nothing if the
1136  * actor is not visible.
1137  *
1138  * Calling this function is strongly disencouraged: the default
1139  * implementation of #ClutterActorClass.map() will map all the children
1140  * of an actor when mapping its parent.
1141  *
1142  * When overriding map, it is mandatory to chain up to the parent
1143  * implementation.
1144  *
1145  * Since: 1.0
1146  */
1147 void
1148 clutter_actor_map (ClutterActor *self)
1149 {
1150   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1151
1152   if (CLUTTER_ACTOR_IS_MAPPED (self))
1153     return;
1154
1155   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1156     return;
1157
1158   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1159 }
1160
1161 static void
1162 clutter_actor_real_unmap (ClutterActor *self)
1163 {
1164   ClutterActorPrivate *priv = self->priv;
1165   ClutterActor *iter;
1166
1167   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1168
1169   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1170                 _clutter_actor_get_debug_name (self));
1171
1172   for (iter = self->priv->first_child;
1173        iter != NULL;
1174        iter = iter->priv->next_sibling)
1175     {
1176       clutter_actor_unmap (iter);
1177     }
1178
1179   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1180
1181   /* clear the contents of the last paint volume, so that hiding + moving +
1182    * showing will not result in the wrong area being repainted
1183    */
1184   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1185   priv->last_paint_volume_valid = TRUE;
1186
1187   /* notify on parent mapped after potentially unmapping
1188    * children, so apps see a bottom-up notification.
1189    */
1190   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1191
1192   /* relinquish keyboard focus if we were unmapped while owning it */
1193   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1194     {
1195       ClutterStage *stage;
1196
1197       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1198
1199       if (stage != NULL)
1200         _clutter_stage_release_pick_id (stage, priv->pick_id);
1201
1202       priv->pick_id = -1;
1203
1204       if (stage != NULL &&
1205           clutter_stage_get_key_focus (stage) == self)
1206         {
1207           clutter_stage_set_key_focus (stage, NULL);
1208         }
1209     }
1210 }
1211
1212 /**
1213  * clutter_actor_unmap:
1214  * @self: A #ClutterActor
1215  *
1216  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1217  * unmaps its children if they were mapped.
1218  *
1219  * Calling this function is not encouraged: the default #ClutterActor
1220  * implementation of #ClutterActorClass.unmap() will also unmap any
1221  * eventual children by default when their parent is unmapped.
1222  *
1223  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1224  * chain up to the parent implementation.
1225  *
1226  * <note>It is important to note that the implementation of the
1227  * #ClutterActorClass.unmap() virtual function may be called after
1228  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1229  * implementation, but it is guaranteed to be called before the
1230  * #GObjectClass.finalize() implementation.</note>
1231  *
1232  * Since: 1.0
1233  */
1234 void
1235 clutter_actor_unmap (ClutterActor *self)
1236 {
1237   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1238
1239   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1240     return;
1241
1242   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1243 }
1244
1245 static void
1246 clutter_actor_real_show (ClutterActor *self)
1247 {
1248   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1249     {
1250       ClutterActorPrivate *priv = self->priv;
1251
1252       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1253
1254       /* we notify on the "visible" flag in the clutter_actor_show()
1255        * wrapper so the entire show signal emission completes first
1256        * (?)
1257        */
1258       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1259
1260       /* we queue a relayout unless the actor is inside a
1261        * container that explicitly told us not to
1262        */
1263       if (priv->parent != NULL &&
1264           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1265         {
1266           /* While an actor is hidden the parent may not have
1267            * allocated/requested so we need to start from scratch
1268            * and avoid the short-circuiting in
1269            * clutter_actor_queue_relayout().
1270            */
1271           priv->needs_width_request  = FALSE;
1272           priv->needs_height_request = FALSE;
1273           priv->needs_allocation     = FALSE;
1274           clutter_actor_queue_relayout (self);
1275         }
1276     }
1277 }
1278
1279 static inline void
1280 set_show_on_set_parent (ClutterActor *self,
1281                         gboolean      set_show)
1282 {
1283   ClutterActorPrivate *priv = self->priv;
1284
1285   set_show = !!set_show;
1286
1287   if (priv->show_on_set_parent == set_show)
1288     return;
1289
1290   if (priv->parent == NULL)
1291     {
1292       priv->show_on_set_parent = set_show;
1293       g_object_notify_by_pspec (G_OBJECT (self),
1294                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1295     }
1296 }
1297
1298 /**
1299  * clutter_actor_show:
1300  * @self: A #ClutterActor
1301  *
1302  * Flags an actor to be displayed. An actor that isn't shown will not
1303  * be rendered on the stage.
1304  *
1305  * Actors are visible by default.
1306  *
1307  * If this function is called on an actor without a parent, the
1308  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1309  * effect.
1310  */
1311 void
1312 clutter_actor_show (ClutterActor *self)
1313 {
1314   ClutterActorPrivate *priv;
1315
1316   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1317
1318   /* simple optimization */
1319   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1320     {
1321       /* we still need to set the :show-on-set-parent property, in
1322        * case show() is called on an unparented actor
1323        */
1324       set_show_on_set_parent (self, TRUE);
1325       return;
1326     }
1327
1328 #ifdef CLUTTER_ENABLE_DEBUG
1329   clutter_actor_verify_map_state (self);
1330 #endif
1331
1332   priv = self->priv;
1333
1334   g_object_freeze_notify (G_OBJECT (self));
1335
1336   set_show_on_set_parent (self, TRUE);
1337
1338   g_signal_emit (self, actor_signals[SHOW], 0);
1339   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1340
1341   if (priv->parent != NULL)
1342     clutter_actor_queue_redraw (priv->parent);
1343
1344   g_object_thaw_notify (G_OBJECT (self));
1345 }
1346
1347 /**
1348  * clutter_actor_show_all:
1349  * @self: a #ClutterActor
1350  *
1351  * Calls clutter_actor_show() on all children of an actor (if any).
1352  *
1353  * Since: 0.2
1354  *
1355  * Deprecated: 1.10: Actors are visible by default
1356  */
1357 void
1358 clutter_actor_show_all (ClutterActor *self)
1359 {
1360   ClutterActorClass *klass;
1361
1362   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1363
1364   klass = CLUTTER_ACTOR_GET_CLASS (self);
1365   if (klass->show_all)
1366     klass->show_all (self);
1367 }
1368
1369 void
1370 clutter_actor_real_hide (ClutterActor *self)
1371 {
1372   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1373     {
1374       ClutterActorPrivate *priv = self->priv;
1375
1376       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1377
1378       /* we notify on the "visible" flag in the clutter_actor_hide()
1379        * wrapper so the entire hide signal emission completes first
1380        * (?)
1381        */
1382       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1383
1384       /* we queue a relayout unless the actor is inside a
1385        * container that explicitly told us not to
1386        */
1387       if (priv->parent != NULL &&
1388           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1389         clutter_actor_queue_relayout (priv->parent);
1390     }
1391 }
1392
1393 /**
1394  * clutter_actor_hide:
1395  * @self: A #ClutterActor
1396  *
1397  * Flags an actor to be hidden. A hidden actor will not be
1398  * rendered on the stage.
1399  *
1400  * Actors are visible by default.
1401  *
1402  * If this function is called on an actor without a parent, the
1403  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1404  * as a side-effect.
1405  */
1406 void
1407 clutter_actor_hide (ClutterActor *self)
1408 {
1409   ClutterActorPrivate *priv;
1410
1411   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1412
1413   /* simple optimization */
1414   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1415     {
1416       /* we still need to set the :show-on-set-parent property, in
1417        * case hide() is called on an unparented actor
1418        */
1419       set_show_on_set_parent (self, FALSE);
1420       return;
1421     }
1422
1423 #ifdef CLUTTER_ENABLE_DEBUG
1424   clutter_actor_verify_map_state (self);
1425 #endif
1426
1427   priv = self->priv;
1428
1429   g_object_freeze_notify (G_OBJECT (self));
1430
1431   set_show_on_set_parent (self, FALSE);
1432
1433   g_signal_emit (self, actor_signals[HIDE], 0);
1434   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1435
1436   if (priv->parent != NULL)
1437     clutter_actor_queue_redraw (priv->parent);
1438
1439   g_object_thaw_notify (G_OBJECT (self));
1440 }
1441
1442 /**
1443  * clutter_actor_hide_all:
1444  * @self: a #ClutterActor
1445  *
1446  * Calls clutter_actor_hide() on all child actors (if any).
1447  *
1448  * Since: 0.2
1449  *
1450  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1451  *   prevent its children from being painted as well.
1452  */
1453 void
1454 clutter_actor_hide_all (ClutterActor *self)
1455 {
1456   ClutterActorClass *klass;
1457
1458   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1459
1460   klass = CLUTTER_ACTOR_GET_CLASS (self);
1461   if (klass->hide_all)
1462     klass->hide_all (self);
1463 }
1464
1465 /**
1466  * clutter_actor_realize:
1467  * @self: A #ClutterActor
1468  *
1469  * Realization informs the actor that it is attached to a stage. It
1470  * can use this to allocate resources if it wanted to delay allocation
1471  * until it would be rendered. However it is perfectly acceptable for
1472  * an actor to create resources before being realized because Clutter
1473  * only ever has a single rendering context so that actor is free to
1474  * be moved from one stage to another.
1475  *
1476  * This function does nothing if the actor is already realized.
1477  *
1478  * Because a realized actor must have realized parent actors, calling
1479  * clutter_actor_realize() will also realize all parents of the actor.
1480  *
1481  * This function does not realize child actors, except in the special
1482  * case that realizing the stage, when the stage is visible, will
1483  * suddenly map (and thus realize) the children of the stage.
1484  **/
1485 void
1486 clutter_actor_realize (ClutterActor *self)
1487 {
1488   ClutterActorPrivate *priv;
1489
1490   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1491
1492   priv = self->priv;
1493
1494 #ifdef CLUTTER_ENABLE_DEBUG
1495   clutter_actor_verify_map_state (self);
1496 #endif
1497
1498   if (CLUTTER_ACTOR_IS_REALIZED (self))
1499     return;
1500
1501   /* To be realized, our parent actors must be realized first.
1502    * This will only succeed if we're inside a toplevel.
1503    */
1504   if (priv->parent != NULL)
1505     clutter_actor_realize (priv->parent);
1506
1507   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1508     {
1509       /* toplevels can be realized at any time */
1510     }
1511   else
1512     {
1513       /* "Fail" the realization if parent is missing or unrealized;
1514        * this should really be a g_warning() not some kind of runtime
1515        * failure; how can an app possibly recover? Instead it's a bug
1516        * in the app and the app should get an explanatory warning so
1517        * someone can fix it. But for now it's too hard to fix this
1518        * because e.g. ClutterTexture needs reworking.
1519        */
1520       if (priv->parent == NULL ||
1521           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1522         return;
1523     }
1524
1525   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1526
1527   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1528   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1529
1530   g_signal_emit (self, actor_signals[REALIZE], 0);
1531
1532   /* Stage actor is allowed to unset the realized flag again in its
1533    * default signal handler, though that is a pathological situation.
1534    */
1535
1536   /* If realization "failed" we'll have to update child state. */
1537   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1538 }
1539
1540 void
1541 clutter_actor_real_unrealize (ClutterActor *self)
1542 {
1543   /* we must be unmapped (implying our children are also unmapped) */
1544   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1545 }
1546
1547 /**
1548  * clutter_actor_unrealize:
1549  * @self: A #ClutterActor
1550  *
1551  * Unrealization informs the actor that it may be being destroyed or
1552  * moved to another stage. The actor may want to destroy any
1553  * underlying graphics resources at this point. However it is
1554  * perfectly acceptable for it to retain the resources until the actor
1555  * is destroyed because Clutter only ever uses a single rendering
1556  * context and all of the graphics resources are valid on any stage.
1557  *
1558  * Because mapped actors must be realized, actors may not be
1559  * unrealized if they are mapped. This function hides the actor to be
1560  * sure it isn't mapped, an application-visible side effect that you
1561  * may not be expecting.
1562  *
1563  * This function should not be called by application code.
1564  */
1565 void
1566 clutter_actor_unrealize (ClutterActor *self)
1567 {
1568   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1569   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1570
1571 /* This function should not really be in the public API, because
1572  * there isn't a good reason to call it. ClutterActor will already
1573  * unrealize things for you when it's important to do so.
1574  *
1575  * If you were using clutter_actor_unrealize() in a dispose
1576  * implementation, then don't, just chain up to ClutterActor's
1577  * dispose.
1578  *
1579  * If you were using clutter_actor_unrealize() to implement
1580  * unrealizing children of your container, then don't, ClutterActor
1581  * will already take care of that.
1582  *
1583  * If you were using clutter_actor_unrealize() to re-realize to
1584  * create your resources in a different way, then use
1585  * _clutter_actor_rerealize() (inside Clutter) or just call your
1586  * code that recreates your resources directly (outside Clutter).
1587  */
1588
1589 #ifdef CLUTTER_ENABLE_DEBUG
1590   clutter_actor_verify_map_state (self);
1591 #endif
1592
1593   clutter_actor_hide (self);
1594
1595   clutter_actor_unrealize_not_hiding (self);
1596 }
1597
1598 static ClutterActorTraverseVisitFlags
1599 unrealize_actor_before_children_cb (ClutterActor *self,
1600                                     int depth,
1601                                     void *user_data)
1602 {
1603   /* If an actor is already unrealized we know its children have also
1604    * already been unrealized... */
1605   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1606     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1607
1608   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1609
1610   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1611 }
1612
1613 static ClutterActorTraverseVisitFlags
1614 unrealize_actor_after_children_cb (ClutterActor *self,
1615                                    int depth,
1616                                    void *user_data)
1617 {
1618   /* We want to unset the realized flag only _after_
1619    * child actors are unrealized, to maintain invariants.
1620    */
1621   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1622   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1623   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1624 }
1625
1626 /*
1627  * clutter_actor_unrealize_not_hiding:
1628  * @self: A #ClutterActor
1629  *
1630  * Unrealization informs the actor that it may be being destroyed or
1631  * moved to another stage. The actor may want to destroy any
1632  * underlying graphics resources at this point. However it is
1633  * perfectly acceptable for it to retain the resources until the actor
1634  * is destroyed because Clutter only ever uses a single rendering
1635  * context and all of the graphics resources are valid on any stage.
1636  *
1637  * Because mapped actors must be realized, actors may not be
1638  * unrealized if they are mapped. You must hide the actor or one of
1639  * its parents before attempting to unrealize.
1640  *
1641  * This function is separate from clutter_actor_unrealize() because it
1642  * does not automatically hide the actor.
1643  * Actors need not be hidden to be unrealized, they just need to
1644  * be unmapped. In fact we don't want to mess up the application's
1645  * setting of the "visible" flag, so hiding is very undesirable.
1646  *
1647  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1648  * backward compatibility.
1649  */
1650 static void
1651 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1652 {
1653   _clutter_actor_traverse (self,
1654                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1655                            unrealize_actor_before_children_cb,
1656                            unrealize_actor_after_children_cb,
1657                            NULL);
1658 }
1659
1660 /*
1661  * _clutter_actor_rerealize:
1662  * @self: A #ClutterActor
1663  * @callback: Function to call while unrealized
1664  * @data: data for callback
1665  *
1666  * If an actor is already unrealized, this just calls the callback.
1667  *
1668  * If it is realized, it unrealizes temporarily, calls the callback,
1669  * and then re-realizes the actor.
1670  *
1671  * As a side effect, leaves all children of the actor unrealized if
1672  * the actor was realized but not showing.  This is because when we
1673  * unrealize the actor temporarily we must unrealize its children
1674  * (e.g. children of a stage can't be realized if stage window is
1675  * gone). And we aren't clever enough to save the realization state of
1676  * all children. In most cases this should not matter, because
1677  * the children will automatically realize when they next become mapped.
1678  */
1679 void
1680 _clutter_actor_rerealize (ClutterActor    *self,
1681                           ClutterCallback  callback,
1682                           void            *data)
1683 {
1684   gboolean was_mapped;
1685   gboolean was_showing;
1686   gboolean was_realized;
1687
1688   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1689
1690 #ifdef CLUTTER_ENABLE_DEBUG
1691   clutter_actor_verify_map_state (self);
1692 #endif
1693
1694   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1695   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1696   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1697
1698   /* Must be unmapped to unrealize. Note we only have to hide this
1699    * actor if it was mapped (if all parents were showing).  If actor
1700    * is merely visible (but not mapped), then that's fine, we can
1701    * leave it visible.
1702    */
1703   if (was_mapped)
1704     clutter_actor_hide (self);
1705
1706   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1707
1708   /* unrealize self and all children */
1709   clutter_actor_unrealize_not_hiding (self);
1710
1711   if (callback != NULL)
1712     {
1713       (* callback) (self, data);
1714     }
1715
1716   if (was_showing)
1717     clutter_actor_show (self); /* will realize only if mapping implies it */
1718   else if (was_realized)
1719     clutter_actor_realize (self); /* realize self and all parents */
1720 }
1721
1722 static void
1723 clutter_actor_real_pick (ClutterActor       *self,
1724                          const ClutterColor *color)
1725 {
1726   /* the default implementation is just to paint a rectangle
1727    * with the same size of the actor using the passed color
1728    */
1729   if (clutter_actor_should_pick_paint (self))
1730     {
1731       ClutterActorBox box = { 0, };
1732       float width, height;
1733
1734       clutter_actor_get_allocation_box (self, &box);
1735
1736       width = box.x2 - box.x1;
1737       height = box.y2 - box.y1;
1738
1739       cogl_set_source_color4ub (color->red,
1740                                 color->green,
1741                                 color->blue,
1742                                 color->alpha);
1743
1744       cogl_rectangle (0, 0, width, height);
1745     }
1746
1747   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1748    * with existing container classes that override the pick() virtual
1749    * and chain up to the default implementation - otherwise we'll end up
1750    * painting our children twice.
1751    *
1752    * this has to go away for 2.0; hopefully along the pick() itself.
1753    */
1754   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1755     {
1756       ClutterActor *iter;
1757
1758       for (iter = self->priv->first_child;
1759            iter != NULL;
1760            iter = iter->priv->next_sibling)
1761         clutter_actor_paint (iter);
1762     }
1763 }
1764
1765 /**
1766  * clutter_actor_should_pick_paint:
1767  * @self: A #ClutterActor
1768  *
1769  * Should be called inside the implementation of the
1770  * #ClutterActor::pick virtual function in order to check whether
1771  * the actor should paint itself in pick mode or not.
1772  *
1773  * This function should never be called directly by applications.
1774  *
1775  * Return value: %TRUE if the actor should paint its silhouette,
1776  *   %FALSE otherwise
1777  */
1778 gboolean
1779 clutter_actor_should_pick_paint (ClutterActor *self)
1780 {
1781   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1782
1783   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1784       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1785        CLUTTER_ACTOR_IS_REACTIVE (self)))
1786     return TRUE;
1787
1788   return FALSE;
1789 }
1790
1791 static void
1792 clutter_actor_real_get_preferred_width (ClutterActor *self,
1793                                         gfloat        for_height,
1794                                         gfloat       *min_width_p,
1795                                         gfloat       *natural_width_p)
1796 {
1797   ClutterActorPrivate *priv = self->priv;
1798
1799   if (priv->n_children != 0 &&
1800       priv->layout_manager != NULL)
1801     {
1802       ClutterContainer *container = CLUTTER_CONTAINER (self);
1803
1804       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1805                     "for the preferred width",
1806                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1807                     priv->layout_manager);
1808
1809       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1810                                                   container,
1811                                                   for_height,
1812                                                   min_width_p,
1813                                                   natural_width_p);
1814
1815       return;
1816     }
1817
1818   /* Default implementation is always 0x0, usually an actor
1819    * using this default is relying on someone to set the
1820    * request manually
1821    */
1822   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1823
1824   if (min_width_p)
1825     *min_width_p = 0;
1826
1827   if (natural_width_p)
1828     *natural_width_p = 0;
1829 }
1830
1831 static void
1832 clutter_actor_real_get_preferred_height (ClutterActor *self,
1833                                          gfloat        for_width,
1834                                          gfloat       *min_height_p,
1835                                          gfloat       *natural_height_p)
1836 {
1837   ClutterActorPrivate *priv = self->priv;
1838
1839   if (priv->n_children != 0 &&
1840       priv->layout_manager != NULL)
1841     {
1842       ClutterContainer *container = CLUTTER_CONTAINER (self);
1843
1844       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1845                     "for the preferred height",
1846                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1847                     priv->layout_manager);
1848
1849       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1850                                                    container,
1851                                                    for_width,
1852                                                    min_height_p,
1853                                                    natural_height_p);
1854
1855       return;
1856     }
1857   /* Default implementation is always 0x0, usually an actor
1858    * using this default is relying on someone to set the
1859    * request manually
1860    */
1861   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1862
1863   if (min_height_p)
1864     *min_height_p = 0;
1865
1866   if (natural_height_p)
1867     *natural_height_p = 0;
1868 }
1869
1870 static void
1871 clutter_actor_store_old_geometry (ClutterActor    *self,
1872                                   ClutterActorBox *box)
1873 {
1874   *box = self->priv->allocation;
1875 }
1876
1877 static inline void
1878 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
1879                                           const ClutterActorBox *old)
1880 {
1881   ClutterActorPrivate *priv = self->priv;
1882   GObject *obj = G_OBJECT (self);
1883
1884   g_object_freeze_notify (obj);
1885
1886   /* to avoid excessive requisition or allocation cycles we
1887    * use the cached values.
1888    *
1889    * - if we don't have an allocation we assume that we need
1890    *   to notify anyway
1891    * - if we don't have a width or a height request we notify
1892    *   width and height
1893    * - if we have a valid allocation then we check the old
1894    *   bounding box with the current allocation and we notify
1895    *   the changes
1896    */
1897   if (priv->needs_allocation)
1898     {
1899       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1900       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1901       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1902       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1903     }
1904   else if (priv->needs_width_request || priv->needs_height_request)
1905     {
1906       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1907       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1908     }
1909   else
1910     {
1911       gfloat xu, yu;
1912       gfloat widthu, heightu;
1913
1914       xu = priv->allocation.x1;
1915       yu = priv->allocation.y1;
1916       widthu = priv->allocation.x2 - priv->allocation.x1;
1917       heightu = priv->allocation.y2 - priv->allocation.y1;
1918
1919       if (xu != old->x1)
1920         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1921
1922       if (yu != old->y1)
1923         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1924
1925       if (widthu != (old->x2 - old->x1))
1926         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1927
1928       if (heightu != (old->y2 - old->y1))
1929         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1930     }
1931
1932   g_object_thaw_notify (obj);
1933 }
1934
1935 /*< private >
1936  * clutter_actor_set_allocation_internal:
1937  * @self: a #ClutterActor
1938  * @box: a #ClutterActorBox
1939  * @flags: allocation flags
1940  *
1941  * Stores the allocation of @self.
1942  *
1943  * This function only performs basic storage and property notification.
1944  *
1945  * This function should be called by clutter_actor_set_allocation()
1946  * and by the default implementation of #ClutterActorClass.allocate().
1947  *
1948  * Return value: %TRUE if the allocation of the #ClutterActor has been
1949  *   changed, and %FALSE otherwise
1950  */
1951 static inline gboolean
1952 clutter_actor_set_allocation_internal (ClutterActor           *self,
1953                                        const ClutterActorBox  *box,
1954                                        ClutterAllocationFlags  flags)
1955 {
1956   ClutterActorPrivate *priv = self->priv;
1957   GObject *obj;
1958   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
1959   gboolean flags_changed;
1960   gboolean retval;
1961   ClutterActorBox old_alloc = { 0, };
1962
1963   obj = G_OBJECT (self);
1964
1965   g_object_freeze_notify (obj);
1966
1967   clutter_actor_store_old_geometry (self, &old_alloc);
1968
1969   x1_changed = priv->allocation.x1 != box->x1;
1970   y1_changed = priv->allocation.y1 != box->y1;
1971   x2_changed = priv->allocation.x2 != box->x2;
1972   y2_changed = priv->allocation.y2 != box->y2;
1973
1974   flags_changed = priv->allocation_flags != flags;
1975
1976   priv->allocation = *box;
1977   priv->allocation_flags = flags;
1978
1979   /* allocation is authoritative */
1980   priv->needs_width_request = FALSE;
1981   priv->needs_height_request = FALSE;
1982   priv->needs_allocation = FALSE;
1983
1984   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
1985     {
1986       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
1987                     _clutter_actor_get_debug_name (self));
1988
1989       priv->transform_valid = FALSE;
1990
1991       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
1992
1993       retval = TRUE;
1994     }
1995   else
1996     retval = FALSE;
1997
1998   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
1999
2000   g_object_thaw_notify (obj);
2001
2002   return retval;
2003 }
2004
2005 static void clutter_actor_real_allocate (ClutterActor           *self,
2006                                          const ClutterActorBox  *box,
2007                                          ClutterAllocationFlags  flags);
2008
2009 static inline void
2010 clutter_actor_maybe_layout_children (ClutterActor           *self,
2011                                      const ClutterActorBox  *allocation,
2012                                      ClutterAllocationFlags  flags)
2013 {
2014   ClutterActorPrivate *priv = self->priv;
2015
2016   /* this is going to be a bit hard to follow, so let's put an explanation
2017    * here.
2018    *
2019    * we want ClutterActor to have a default layout manager if the actor was
2020    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2021    *
2022    * we also want any subclass of ClutterActor that does not override the
2023    * ::allocate() virtual function to delegate to a layout manager.
2024    *
2025    * finally, we want to allow people subclassing ClutterActor and overriding
2026    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2027    *
2028    * on the other hand, we want existing actor subclasses overriding the
2029    * ::allocate() virtual function and chaining up to the parent's
2030    * implementation to continue working without allocating their children
2031    * twice, or without entering an allocation loop.
2032    *
2033    * for the first two points, we check if the class of the actor is
2034    * overridding the ::allocate() virtual function; if it isn't, then we
2035    * follow through with checking whether we have children and a layout
2036    * manager, and eventually calling clutter_layout_manager_allocate().
2037    *
2038    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2039    * allocation flags that we got passed, and if it is present, we continue
2040    * with the check above.
2041    *
2042    * if neither of these two checks yields a positive result, we just
2043    * assume that the ::allocate() virtual function that resulted in this
2044    * function being called will also allocate the children of the actor.
2045    */
2046
2047   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2048     goto check_layout;
2049
2050   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2051     goto check_layout;
2052
2053   return;
2054
2055 check_layout:
2056   if (priv->n_children != 0 &&
2057       priv->layout_manager != NULL)
2058     {
2059       ClutterContainer *container = CLUTTER_CONTAINER (self);
2060       ClutterAllocationFlags children_flags;
2061       ClutterActorBox children_box;
2062
2063       /* normalize the box passed to the layout manager */
2064       children_box.x1 = children_box.y1 = 0.f;
2065       children_box.x2 = (allocation->x2 - allocation->x1);
2066       children_box.y2 = (allocation->y2 - allocation->y1);
2067
2068       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2069        * the actor's children, since it refers only to the current
2070        * actor's allocation.
2071        */
2072       children_flags = flags;
2073       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2074
2075       CLUTTER_NOTE (LAYOUT,
2076                     "Allocating %d children of %s "
2077                     "at { %.2f, %.2f - %.2f x %.2f } "
2078                     "using %s",
2079                     priv->n_children,
2080                     _clutter_actor_get_debug_name (self),
2081                     allocation->x1,
2082                     allocation->y1,
2083                     (allocation->x2 - allocation->x1),
2084                     (allocation->y2 - allocation->y1),
2085                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2086
2087       clutter_layout_manager_allocate (priv->layout_manager,
2088                                        container,
2089                                        &children_box,
2090                                        children_flags);
2091     }
2092 }
2093
2094 static void
2095 clutter_actor_real_allocate (ClutterActor           *self,
2096                              const ClutterActorBox  *box,
2097                              ClutterAllocationFlags  flags)
2098 {
2099   ClutterActorPrivate *priv = self->priv;
2100   gboolean changed;
2101
2102   g_object_freeze_notify (G_OBJECT (self));
2103
2104   changed = clutter_actor_set_allocation_internal (self, box, flags);
2105
2106   /* we allocate our children before we notify changes in our geometry,
2107    * so that people connecting to properties will be able to get valid
2108    * data out of the sub-tree of the scene graph that has this actor at
2109    * the root.
2110    */
2111   clutter_actor_maybe_layout_children (self, box, flags);
2112
2113   if (changed)
2114     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2115                    &priv->allocation,
2116                    priv->allocation_flags);
2117
2118   g_object_thaw_notify (G_OBJECT (self));
2119 }
2120
2121 static void
2122 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2123                                     ClutterActor *origin)
2124 {
2125   /* no point in queuing a redraw on a destroyed actor */
2126   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2127     return;
2128
2129   /* NB: We can't bail out early here if the actor is hidden in case
2130    * the actor bas been cloned. In this case the clone will need to
2131    * receive the signal so it can queue its own redraw.
2132    */
2133
2134   /* calls klass->queue_redraw in default handler */
2135   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2136 }
2137
2138 static void
2139 clutter_actor_real_queue_redraw (ClutterActor *self,
2140                                  ClutterActor *origin)
2141 {
2142   ClutterActor *parent;
2143
2144   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2145                 _clutter_actor_get_debug_name (self),
2146                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2147                                : "same actor");
2148
2149   /* no point in queuing a redraw on a destroyed actor */
2150   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2151     return;
2152
2153   /* If the queue redraw is coming from a child then the actor has
2154      become dirty and any queued effect is no longer valid */
2155   if (self != origin)
2156     {
2157       self->priv->is_dirty = TRUE;
2158       self->priv->effect_to_redraw = NULL;
2159     }
2160
2161   /* If the actor isn't visible, we still had to emit the signal
2162    * to allow for a ClutterClone, but the appearance of the parent
2163    * won't change so we don't have to propagate up the hierarchy.
2164    */
2165   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2166     return;
2167
2168   /* Although we could determine here that a full stage redraw
2169    * has already been queued and immediately bail out, we actually
2170    * guarantee that we will propagate a queue-redraw signal to our
2171    * parent at least once so that it's possible to implement a
2172    * container that tracks which of its children have queued a
2173    * redraw.
2174    */
2175   if (self->priv->propagated_one_redraw)
2176     {
2177       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2178       if (stage != NULL &&
2179           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2180         return;
2181     }
2182
2183   self->priv->propagated_one_redraw = TRUE;
2184
2185   /* notify parents, if they are all visible eventually we'll
2186    * queue redraw on the stage, which queues the redraw idle.
2187    */
2188   parent = clutter_actor_get_parent (self);
2189   if (parent != NULL)
2190     {
2191       /* this will go up recursively */
2192       _clutter_actor_signal_queue_redraw (parent, origin);
2193     }
2194 }
2195
2196 void
2197 clutter_actor_real_queue_relayout (ClutterActor *self)
2198 {
2199   ClutterActorPrivate *priv = self->priv;
2200
2201   /* no point in queueing a redraw on a destroyed actor */
2202   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2203     return;
2204
2205   priv->needs_width_request  = TRUE;
2206   priv->needs_height_request = TRUE;
2207   priv->needs_allocation     = TRUE;
2208
2209   /* reset the cached size requests */
2210   memset (priv->width_requests, 0,
2211           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2212   memset (priv->height_requests, 0,
2213           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2214
2215   /* We need to go all the way up the hierarchy */
2216   if (priv->parent != NULL)
2217     _clutter_actor_queue_only_relayout (priv->parent);
2218 }
2219
2220 /**
2221  * clutter_actor_apply_relative_transform_to_point:
2222  * @self: A #ClutterActor
2223  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2224  *   default #ClutterStage
2225  * @point: A point as #ClutterVertex
2226  * @vertex: (out caller-allocates): The translated #ClutterVertex
2227  *
2228  * Transforms @point in coordinates relative to the actor into
2229  * ancestor-relative coordinates using the relevant transform
2230  * stack (i.e. scale, rotation, etc).
2231  *
2232  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2233  * this case, the coordinates returned will be the coordinates on
2234  * the stage before the projection is applied. This is different from
2235  * the behaviour of clutter_actor_apply_transform_to_point().
2236  *
2237  * Since: 0.6
2238  */
2239 void
2240 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2241                                                  ClutterActor        *ancestor,
2242                                                  const ClutterVertex *point,
2243                                                  ClutterVertex       *vertex)
2244 {
2245   gfloat w;
2246   CoglMatrix matrix;
2247
2248   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2249   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2250   g_return_if_fail (point != NULL);
2251   g_return_if_fail (vertex != NULL);
2252
2253   *vertex = *point;
2254   w = 1.0;
2255
2256   if (ancestor == NULL)
2257     ancestor = _clutter_actor_get_stage_internal (self);
2258
2259   if (ancestor == NULL)
2260     {
2261       *vertex = *point;
2262       return;
2263     }
2264
2265   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2266   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2267 }
2268
2269 static gboolean
2270 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2271                                          const ClutterVertex *vertices_in,
2272                                          ClutterVertex *vertices_out,
2273                                          int n_vertices)
2274 {
2275   ClutterActor *stage;
2276   CoglMatrix modelview;
2277   CoglMatrix projection;
2278   float viewport[4];
2279
2280   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2281
2282   stage = _clutter_actor_get_stage_internal (self);
2283
2284   /* We really can't do anything meaningful in this case so don't try
2285    * to do any transform */
2286   if (stage == NULL)
2287     return FALSE;
2288
2289   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2290    * that gets us to stage coordinates, we want to go all the way to eye
2291    * coordinates */
2292   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2293
2294   /* Fetch the projection and viewport */
2295   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2296   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2297                                &viewport[0],
2298                                &viewport[1],
2299                                &viewport[2],
2300                                &viewport[3]);
2301
2302   _clutter_util_fully_transform_vertices (&modelview,
2303                                           &projection,
2304                                           viewport,
2305                                           vertices_in,
2306                                           vertices_out,
2307                                           n_vertices);
2308
2309   return TRUE;
2310 }
2311
2312 /**
2313  * clutter_actor_apply_transform_to_point:
2314  * @self: A #ClutterActor
2315  * @point: A point as #ClutterVertex
2316  * @vertex: (out caller-allocates): The translated #ClutterVertex
2317  *
2318  * Transforms @point in coordinates relative to the actor
2319  * into screen-relative coordinates with the current actor
2320  * transformation (i.e. scale, rotation, etc)
2321  *
2322  * Since: 0.4
2323  **/
2324 void
2325 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2326                                         const ClutterVertex *point,
2327                                         ClutterVertex       *vertex)
2328 {
2329   g_return_if_fail (point != NULL);
2330   g_return_if_fail (vertex != NULL);
2331   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2332 }
2333
2334 /*
2335  * _clutter_actor_get_relative_transformation_matrix:
2336  * @self: The actor whose coordinate space you want to transform from.
2337  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2338  *            or %NULL if you want to transform all the way to eye coordinates.
2339  * @matrix: A #CoglMatrix to store the transformation
2340  *
2341  * This gets a transformation @matrix that will transform coordinates from the
2342  * coordinate space of @self into the coordinate space of @ancestor.
2343  *
2344  * For example if you need a matrix that can transform the local actor
2345  * coordinates of @self into stage coordinates you would pass the actor's stage
2346  * pointer as the @ancestor.
2347  *
2348  * If you pass %NULL then the transformation will take you all the way through
2349  * to eye coordinates. This can be useful if you want to extract the entire
2350  * modelview transform that Clutter applies before applying the projection
2351  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2352  * using cogl_set_modelview_matrix() for example then you would want a matrix
2353  * that transforms into eye coordinates.
2354  *
2355  * <note><para>This function explicitly initializes the given @matrix. If you just
2356  * want clutter to multiply a relative transformation with an existing matrix
2357  * you can use clutter_actor_apply_relative_transformation_matrix()
2358  * instead.</para></note>
2359  *
2360  */
2361 /* XXX: We should consider caching the stage relative modelview along with
2362  * the actor itself */
2363 static void
2364 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2365                                                    ClutterActor *ancestor,
2366                                                    CoglMatrix *matrix)
2367 {
2368   cogl_matrix_init_identity (matrix);
2369
2370   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2371 }
2372
2373 /* Project the given @box into stage window coordinates, writing the
2374  * transformed vertices to @verts[]. */
2375 static gboolean
2376 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2377                                           const ClutterActorBox *box,
2378                                           ClutterVertex          verts[])
2379 {
2380   ClutterVertex box_vertices[4];
2381
2382   box_vertices[0].x = box->x1;
2383   box_vertices[0].y = box->y1;
2384   box_vertices[0].z = 0;
2385   box_vertices[1].x = box->x2;
2386   box_vertices[1].y = box->y1;
2387   box_vertices[1].z = 0;
2388   box_vertices[2].x = box->x1;
2389   box_vertices[2].y = box->y2;
2390   box_vertices[2].z = 0;
2391   box_vertices[3].x = box->x2;
2392   box_vertices[3].y = box->y2;
2393   box_vertices[3].z = 0;
2394
2395   return
2396     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2397 }
2398
2399 /**
2400  * clutter_actor_get_allocation_vertices:
2401  * @self: A #ClutterActor
2402  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2403  *   against, or %NULL to use the #ClutterStage
2404  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2405  *   location for an array of 4 #ClutterVertex in which to store the result
2406  *
2407  * Calculates the transformed coordinates of the four corners of the
2408  * actor in the plane of @ancestor. The returned vertices relate to
2409  * the #ClutterActorBox coordinates as follows:
2410  * <itemizedlist>
2411  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2412  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2413  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2414  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2415  * </itemizedlist>
2416  *
2417  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2418  * this case, the coordinates returned will be the coordinates on
2419  * the stage before the projection is applied. This is different from
2420  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2421  *
2422  * Since: 0.6
2423  */
2424 void
2425 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2426                                        ClutterActor  *ancestor,
2427                                        ClutterVertex  verts[])
2428 {
2429   ClutterActorPrivate *priv;
2430   ClutterActorBox box;
2431   ClutterVertex vertices[4];
2432   CoglMatrix modelview;
2433
2434   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2435   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2436
2437   if (ancestor == NULL)
2438     ancestor = _clutter_actor_get_stage_internal (self);
2439
2440   /* Fallback to a NOP transform if the actor isn't parented under a
2441    * stage. */
2442   if (ancestor == NULL)
2443     ancestor = self;
2444
2445   priv = self->priv;
2446
2447   /* if the actor needs to be allocated we force a relayout, so that
2448    * we will have valid values to use in the transformations */
2449   if (priv->needs_allocation)
2450     {
2451       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2452       if (stage)
2453         _clutter_stage_maybe_relayout (stage);
2454       else
2455         {
2456           box.x1 = box.y1 = 0;
2457           /* The result isn't really meaningful in this case but at
2458            * least try to do something *vaguely* reasonable... */
2459           clutter_actor_get_size (self, &box.x2, &box.y2);
2460         }
2461     }
2462
2463   clutter_actor_get_allocation_box (self, &box);
2464
2465   vertices[0].x = box.x1;
2466   vertices[0].y = box.y1;
2467   vertices[0].z = 0;
2468   vertices[1].x = box.x2;
2469   vertices[1].y = box.y1;
2470   vertices[1].z = 0;
2471   vertices[2].x = box.x1;
2472   vertices[2].y = box.y2;
2473   vertices[2].z = 0;
2474   vertices[3].x = box.x2;
2475   vertices[3].y = box.y2;
2476   vertices[3].z = 0;
2477
2478   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2479                                                      &modelview);
2480
2481   cogl_matrix_transform_points (&modelview,
2482                                 3,
2483                                 sizeof (ClutterVertex),
2484                                 vertices,
2485                                 sizeof (ClutterVertex),
2486                                 vertices,
2487                                 4);
2488 }
2489
2490 /**
2491  * clutter_actor_get_abs_allocation_vertices:
2492  * @self: A #ClutterActor
2493  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2494  *   of 4 #ClutterVertex where to store the result.
2495  *
2496  * Calculates the transformed screen coordinates of the four corners of
2497  * the actor; the returned vertices relate to the #ClutterActorBox
2498  * coordinates  as follows:
2499  * <itemizedlist>
2500  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2501  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2502  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2503  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2504  * </itemizedlist>
2505  *
2506  * Since: 0.4
2507  */
2508 void
2509 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2510                                            ClutterVertex  verts[])
2511 {
2512   ClutterActorPrivate *priv;
2513   ClutterActorBox actor_space_allocation;
2514
2515   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2516
2517   priv = self->priv;
2518
2519   /* if the actor needs to be allocated we force a relayout, so that
2520    * the actor allocation box will be valid for
2521    * _clutter_actor_transform_and_project_box()
2522    */
2523   if (priv->needs_allocation)
2524     {
2525       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2526       /* There's nothing meaningful we can do now */
2527       if (!stage)
2528         return;
2529
2530       _clutter_stage_maybe_relayout (stage);
2531     }
2532
2533   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2534    * own coordinate space... */
2535   actor_space_allocation.x1 = 0;
2536   actor_space_allocation.y1 = 0;
2537   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2538   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2539   _clutter_actor_transform_and_project_box (self,
2540                                             &actor_space_allocation,
2541                                             verts);
2542 }
2543
2544 static void
2545 clutter_actor_real_apply_transform (ClutterActor *self,
2546                                     CoglMatrix   *matrix)
2547 {
2548   ClutterActorPrivate *priv = self->priv;
2549
2550   if (!priv->transform_valid)
2551     {
2552       CoglMatrix *transform = &priv->transform;
2553       const ClutterTransformInfo *info;
2554
2555       info = _clutter_actor_get_transform_info_or_defaults (self);
2556
2557       cogl_matrix_init_identity (transform);
2558
2559       cogl_matrix_translate (transform,
2560                              priv->allocation.x1,
2561                              priv->allocation.y1,
2562                              0.0);
2563
2564       if (priv->z)
2565         cogl_matrix_translate (transform, 0, 0, priv->z);
2566
2567       /*
2568        * because the rotation involves translations, we must scale
2569        * before applying the rotations (if we apply the scale after
2570        * the rotations, the translations included in the rotation are
2571        * not scaled and so the entire object will move on the screen
2572        * as a result of rotating it).
2573        */
2574       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2575         {
2576           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2577                                         &info->scale_center,
2578                                         cogl_matrix_scale (transform,
2579                                                            info->scale_x,
2580                                                            info->scale_y,
2581                                                            1.0));
2582         }
2583
2584       if (info->rz_angle)
2585         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2586                                       &info->rz_center,
2587                                       cogl_matrix_rotate (transform,
2588                                                           info->rz_angle,
2589                                                           0, 0, 1.0));
2590
2591       if (info->ry_angle)
2592         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2593                                       &info->ry_center,
2594                                       cogl_matrix_rotate (transform,
2595                                                           info->ry_angle,
2596                                                           0, 1.0, 0));
2597
2598       if (info->rx_angle)
2599         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2600                                       &info->rx_center,
2601                                       cogl_matrix_rotate (transform,
2602                                                           info->rx_angle,
2603                                                           1.0, 0, 0));
2604
2605       if (!clutter_anchor_coord_is_zero (&info->anchor))
2606         {
2607           gfloat x, y, z;
2608
2609           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2610           cogl_matrix_translate (transform, -x, -y, -z);
2611         }
2612
2613       priv->transform_valid = TRUE;
2614     }
2615
2616   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2617 }
2618
2619 /* Applies the transforms associated with this actor to the given
2620  * matrix. */
2621 void
2622 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2623                                           CoglMatrix *matrix)
2624 {
2625   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2626 }
2627
2628 /*
2629  * clutter_actor_apply_relative_transformation_matrix:
2630  * @self: The actor whose coordinate space you want to transform from.
2631  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2632  *            or %NULL if you want to transform all the way to eye coordinates.
2633  * @matrix: A #CoglMatrix to apply the transformation too.
2634  *
2635  * This multiplies a transform with @matrix that will transform coordinates
2636  * from the coordinate space of @self into the coordinate space of @ancestor.
2637  *
2638  * For example if you need a matrix that can transform the local actor
2639  * coordinates of @self into stage coordinates you would pass the actor's stage
2640  * pointer as the @ancestor.
2641  *
2642  * If you pass %NULL then the transformation will take you all the way through
2643  * to eye coordinates. This can be useful if you want to extract the entire
2644  * modelview transform that Clutter applies before applying the projection
2645  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2646  * using cogl_set_modelview_matrix() for example then you would want a matrix
2647  * that transforms into eye coordinates.
2648  *
2649  * <note>This function doesn't initialize the given @matrix, it simply
2650  * multiplies the requested transformation matrix with the existing contents of
2651  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2652  * before calling this function, or you can use
2653  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2654  */
2655 void
2656 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2657                                                      ClutterActor *ancestor,
2658                                                      CoglMatrix *matrix)
2659 {
2660   ClutterActor *parent;
2661
2662   /* Note we terminate before ever calling stage->apply_transform()
2663    * since that would conceptually be relative to the underlying
2664    * window OpenGL coordinates so we'd need a special @ancestor
2665    * value to represent the fake parent of the stage. */
2666   if (self == ancestor)
2667     return;
2668
2669   parent = clutter_actor_get_parent (self);
2670
2671   if (parent != NULL)
2672     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2673                                                          matrix);
2674
2675   _clutter_actor_apply_modelview_transform (self, matrix);
2676 }
2677
2678 static void
2679 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2680                                        ClutterPaintVolume *pv,
2681                                        const char *label,
2682                                        const CoglColor *color)
2683 {
2684   static CoglMaterial *outline = NULL;
2685   CoglPrimitive *prim;
2686   ClutterVertex line_ends[12 * 2];
2687   int n_vertices;
2688
2689   if (outline == NULL)
2690     outline = cogl_material_new ();
2691
2692   _clutter_paint_volume_complete (pv);
2693
2694   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2695
2696   /* Front face */
2697   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2698   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2699   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2700   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2701
2702   if (!pv->is_2d)
2703     {
2704       /* Back face */
2705       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2706       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2707       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2708       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2709
2710       /* Lines connecting front face to back face */
2711       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2712       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2713       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2714       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2715     }
2716
2717   prim = cogl_primitive_new_p3 (COGL_VERTICES_MODE_LINES, n_vertices,
2718                                 (CoglVertexP3 *)line_ends);
2719
2720   cogl_material_set_color (outline, color);
2721   cogl_set_source (outline);
2722   cogl_primitive_draw (prim);
2723   cogl_object_unref (prim);
2724
2725   if (label)
2726     {
2727       PangoLayout *layout;
2728       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2729       pango_layout_set_text (layout, label, -1);
2730       cogl_pango_render_layout (layout,
2731                                 pv->vertices[0].x,
2732                                 pv->vertices[0].y,
2733                                 color,
2734                                 0);
2735       g_object_unref (layout);
2736     }
2737 }
2738
2739 static void
2740 _clutter_actor_draw_paint_volume (ClutterActor *self)
2741 {
2742   ClutterPaintVolume *pv;
2743   CoglColor color;
2744
2745   pv = _clutter_actor_get_paint_volume_mutable (self);
2746   if (!pv)
2747     {
2748       gfloat width, height;
2749       ClutterPaintVolume fake_pv;
2750
2751       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2752       _clutter_paint_volume_init_static (&fake_pv, stage);
2753
2754       clutter_actor_get_size (self, &width, &height);
2755       clutter_paint_volume_set_width (&fake_pv, width);
2756       clutter_paint_volume_set_height (&fake_pv, height);
2757
2758       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2759       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2760                                              _clutter_actor_get_debug_name (self),
2761                                              &color);
2762
2763       clutter_paint_volume_free (&fake_pv);
2764     }
2765   else
2766     {
2767       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2768       _clutter_actor_draw_paint_volume_full (self, pv,
2769                                              _clutter_actor_get_debug_name (self),
2770                                              &color);
2771     }
2772 }
2773
2774 static void
2775 _clutter_actor_paint_cull_result (ClutterActor *self,
2776                                   gboolean success,
2777                                   ClutterCullResult result)
2778 {
2779   ClutterPaintVolume *pv;
2780   CoglColor color;
2781
2782   if (success)
2783     {
2784       if (result == CLUTTER_CULL_RESULT_IN)
2785         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2786       else if (result == CLUTTER_CULL_RESULT_OUT)
2787         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2788       else
2789         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2790     }
2791   else
2792     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2793
2794   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2795     _clutter_actor_draw_paint_volume_full (self, pv,
2796                                            _clutter_actor_get_debug_name (self),
2797                                            &color);
2798   else
2799     {
2800       PangoLayout *layout;
2801       char *label =
2802         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2803       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2804       cogl_set_source_color (&color);
2805
2806       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2807       pango_layout_set_text (layout, label, -1);
2808       cogl_pango_render_layout (layout,
2809                                 0,
2810                                 0,
2811                                 &color,
2812                                 0);
2813       g_free (label);
2814       g_object_unref (layout);
2815     }
2816 }
2817
2818 static int clone_paint_level = 0;
2819
2820 void
2821 _clutter_actor_push_clone_paint (void)
2822 {
2823   clone_paint_level++;
2824 }
2825
2826 void
2827 _clutter_actor_pop_clone_paint (void)
2828 {
2829   clone_paint_level--;
2830 }
2831
2832 static gboolean
2833 in_clone_paint (void)
2834 {
2835   return clone_paint_level > 0;
2836 }
2837
2838 /* Returns TRUE if the actor can be ignored */
2839 /* FIXME: we should return a ClutterCullResult, and
2840  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2841  * means there's no point in trying to cull descendants of the current
2842  * node. */
2843 static gboolean
2844 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2845 {
2846   ClutterActorPrivate *priv = self->priv;
2847   ClutterActor *stage;
2848   const ClutterPlane *stage_clip;
2849
2850   if (!priv->last_paint_volume_valid)
2851     {
2852       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2853                     "->last_paint_volume_valid == FALSE",
2854                     _clutter_actor_get_debug_name (self));
2855       return FALSE;
2856     }
2857
2858   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2859     return FALSE;
2860
2861   stage = _clutter_actor_get_stage_internal (self);
2862   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2863   if (G_UNLIKELY (!stage_clip))
2864     {
2865       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2866                     "No stage clip set",
2867                     _clutter_actor_get_debug_name (self));
2868       return FALSE;
2869     }
2870
2871   if (cogl_get_draw_framebuffer () !=
2872       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2873     {
2874       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2875                     "Current framebuffer doesn't correspond to stage",
2876                     _clutter_actor_get_debug_name (self));
2877       return FALSE;
2878     }
2879
2880   *result_out =
2881     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2882   return TRUE;
2883 }
2884
2885 static void
2886 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2887 {
2888   ClutterActorPrivate *priv = self->priv;
2889   const ClutterPaintVolume *pv;
2890
2891   if (priv->last_paint_volume_valid)
2892     {
2893       clutter_paint_volume_free (&priv->last_paint_volume);
2894       priv->last_paint_volume_valid = FALSE;
2895     }
2896
2897   pv = clutter_actor_get_paint_volume (self);
2898   if (!pv)
2899     {
2900       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2901                     "Actor failed to report a paint volume",
2902                     _clutter_actor_get_debug_name (self));
2903       return;
2904     }
2905
2906   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2907
2908   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2909                                             NULL); /* eye coordinates */
2910
2911   priv->last_paint_volume_valid = TRUE;
2912 }
2913
2914 static inline gboolean
2915 actor_has_shader_data (ClutterActor *self)
2916 {
2917   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
2918 }
2919
2920 guint32
2921 _clutter_actor_get_pick_id (ClutterActor *self)
2922 {
2923   if (self->priv->pick_id < 0)
2924     return 0;
2925
2926   return self->priv->pick_id;
2927 }
2928
2929 /* This is the same as clutter_actor_add_effect except that it doesn't
2930    queue a redraw and it doesn't notify on the effect property */
2931 static void
2932 _clutter_actor_add_effect_internal (ClutterActor  *self,
2933                                     ClutterEffect *effect)
2934 {
2935   ClutterActorPrivate *priv = self->priv;
2936
2937   if (priv->effects == NULL)
2938     {
2939       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
2940       priv->effects->actor = self;
2941     }
2942
2943   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2944 }
2945
2946 /* This is the same as clutter_actor_remove_effect except that it doesn't
2947    queue a redraw and it doesn't notify on the effect property */
2948 static void
2949 _clutter_actor_remove_effect_internal (ClutterActor  *self,
2950                                        ClutterEffect *effect)
2951 {
2952   ClutterActorPrivate *priv = self->priv;
2953
2954   if (priv->effects == NULL)
2955     return;
2956
2957   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2958 }
2959
2960 static gboolean
2961 needs_flatten_effect (ClutterActor *self)
2962 {
2963   ClutterActorPrivate *priv = self->priv;
2964
2965   if (G_UNLIKELY (clutter_paint_debug_flags &
2966                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
2967     return FALSE;
2968
2969   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
2970     return TRUE;
2971   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
2972     {
2973       if (clutter_actor_get_paint_opacity (self) < 255 &&
2974           clutter_actor_has_overlaps (self))
2975         return TRUE;
2976     }
2977
2978   return FALSE;
2979 }
2980
2981 static void
2982 add_or_remove_flatten_effect (ClutterActor *self)
2983 {
2984   ClutterActorPrivate *priv = self->priv;
2985
2986   /* Add or remove the flatten effect depending on the
2987      offscreen-redirect property. */
2988   if (needs_flatten_effect (self))
2989     {
2990       if (priv->flatten_effect == NULL)
2991         {
2992           ClutterActorMeta *actor_meta;
2993           gint priority;
2994
2995           priv->flatten_effect = _clutter_flatten_effect_new ();
2996           /* Keep a reference to the effect so that we can queue
2997              redraws from it */
2998           g_object_ref_sink (priv->flatten_effect);
2999
3000           /* Set the priority of the effect to high so that it will
3001              always be applied to the actor first. It uses an internal
3002              priority so that it won't be visible to applications */
3003           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3004           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3005           _clutter_actor_meta_set_priority (actor_meta, priority);
3006
3007           /* This will add the effect without queueing a redraw */
3008           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3009         }
3010     }
3011   else
3012     {
3013       if (priv->flatten_effect != NULL)
3014         {
3015           /* Destroy the effect so that it will lose its fbo cache of
3016              the actor */
3017           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3018           g_object_unref (priv->flatten_effect);
3019           priv->flatten_effect = NULL;
3020         }
3021     }
3022 }
3023
3024 static void
3025 clutter_actor_real_paint (ClutterActor *actor)
3026 {
3027   ClutterActorPrivate *priv = actor->priv;
3028   ClutterActor *iter;
3029
3030   /* paint the background color, if set */
3031   if (priv->bg_color_set)
3032     {
3033       float width, height;
3034       guint8 real_alpha;
3035
3036       clutter_actor_box_get_size (&priv->allocation, &width, &height);
3037
3038       real_alpha = clutter_actor_get_paint_opacity_internal (actor)
3039                  * priv->bg_color.alpha
3040                  / 255;
3041
3042       cogl_set_source_color4ub (priv->bg_color.red,
3043                                 priv->bg_color.green,
3044                                 priv->bg_color.blue,
3045                                 real_alpha);
3046
3047       cogl_rectangle (0, 0, width, height);
3048     }
3049
3050   for (iter = priv->first_child;
3051        iter != NULL;
3052        iter = iter->priv->next_sibling)
3053     {
3054       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3055                     _clutter_actor_get_debug_name (iter),
3056                     _clutter_actor_get_debug_name (actor),
3057                     iter->priv->allocation.x1,
3058                     iter->priv->allocation.y1,
3059                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3060                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3061
3062       clutter_actor_paint (iter);
3063     }
3064 }
3065
3066 /**
3067  * clutter_actor_paint:
3068  * @self: A #ClutterActor
3069  *
3070  * Renders the actor to display.
3071  *
3072  * This function should not be called directly by applications.
3073  * Call clutter_actor_queue_redraw() to queue paints, instead.
3074  *
3075  * This function is context-aware, and will either cause a
3076  * regular paint or a pick paint.
3077  *
3078  * This function will emit the #ClutterActor::paint signal or
3079  * the #ClutterActor::pick signal, depending on the context.
3080  *
3081  * This function does not paint the actor if the actor is set to 0,
3082  * unless it is performing a pick paint.
3083  */
3084 void
3085 clutter_actor_paint (ClutterActor *self)
3086 {
3087   ClutterActorPrivate *priv;
3088   ClutterPickMode pick_mode;
3089   gboolean clip_set = FALSE;
3090   gboolean shader_applied = FALSE;
3091
3092   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3093                           "Actor real-paint counter",
3094                           "Increments each time any actor is painted",
3095                           0 /* no application private data */);
3096   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3097                           "Actor pick-paint counter",
3098                           "Increments each time any actor is painted "
3099                           "for picking",
3100                           0 /* no application private data */);
3101
3102   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3103
3104   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3105     return;
3106
3107   priv = self->priv;
3108
3109   pick_mode = _clutter_context_get_pick_mode ();
3110
3111   if (pick_mode == CLUTTER_PICK_NONE)
3112     priv->propagated_one_redraw = FALSE;
3113
3114   /* It's an important optimization that we consider painting of
3115    * actors with 0 opacity to be a NOP... */
3116   if (pick_mode == CLUTTER_PICK_NONE &&
3117       /* ignore top-levels, since they might be transparent */
3118       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3119       /* Use the override opacity if its been set */
3120       ((priv->opacity_override >= 0) ?
3121        priv->opacity_override : priv->opacity) == 0)
3122     return;
3123
3124   /* if we aren't paintable (not in a toplevel with all
3125    * parents paintable) then do nothing.
3126    */
3127   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3128     return;
3129
3130   /* mark that we are in the paint process */
3131   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3132
3133   cogl_push_matrix();
3134
3135   if (priv->enable_model_view_transform)
3136     {
3137       CoglMatrix matrix;
3138
3139       /* XXX: It could be better to cache the modelview with the actor
3140        * instead of progressively building up the transformations on
3141        * the matrix stack every time we paint. */
3142       cogl_get_modelview_matrix (&matrix);
3143       _clutter_actor_apply_modelview_transform (self, &matrix);
3144
3145 #ifdef CLUTTER_ENABLE_DEBUG
3146       /* Catch when out-of-band transforms have been made by actors not as part
3147        * of an apply_transform vfunc... */
3148       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3149         {
3150           CoglMatrix expected_matrix;
3151
3152           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3153                                                              &expected_matrix);
3154
3155           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3156             {
3157               GString *buf = g_string_sized_new (1024);
3158               ClutterActor *parent;
3159
3160               parent = self;
3161               while (parent != NULL)
3162                 {
3163                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3164
3165                   if (parent->priv->parent != NULL)
3166                     g_string_append (buf, "->");
3167
3168                   parent = parent->priv->parent;
3169                 }
3170
3171               g_warning ("Unexpected transform found when painting actor "
3172                          "\"%s\". This will be caused by one of the actor's "
3173                          "ancestors (%s) using the Cogl API directly to transform "
3174                          "children instead of using ::apply_transform().",
3175                          _clutter_actor_get_debug_name (self),
3176                          buf->str);
3177
3178               g_string_free (buf, TRUE);
3179             }
3180         }
3181 #endif /* CLUTTER_ENABLE_DEBUG */
3182
3183       cogl_set_modelview_matrix (&matrix);
3184     }
3185
3186   if (priv->has_clip)
3187     {
3188       cogl_clip_push_rectangle (priv->clip.x,
3189                                 priv->clip.y,
3190                                 priv->clip.x + priv->clip.width,
3191                                 priv->clip.y + priv->clip.height);
3192       clip_set = TRUE;
3193     }
3194   else if (priv->clip_to_allocation)
3195     {
3196       gfloat width, height;
3197
3198       width  = priv->allocation.x2 - priv->allocation.x1;
3199       height = priv->allocation.y2 - priv->allocation.y1;
3200
3201       cogl_clip_push_rectangle (0, 0, width, height);
3202       clip_set = TRUE;
3203     }
3204
3205   if (pick_mode == CLUTTER_PICK_NONE)
3206     {
3207       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3208
3209       /* We check whether we need to add the flatten effect before
3210          each paint so that we can avoid having a mechanism for
3211          applications to notify when the value of the
3212          has_overlaps virtual changes. */
3213       add_or_remove_flatten_effect (self);
3214     }
3215   else
3216     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3217
3218   /* We save the current paint volume so that the next time the
3219    * actor queues a redraw we can constrain the redraw to just
3220    * cover the union of the new bounding box and the old.
3221    *
3222    * We also fetch the current paint volume to perform culling so
3223    * we can avoid painting actors outside the current clip region.
3224    *
3225    * If we are painting inside a clone, we should neither update
3226    * the paint volume or use it to cull painting, since the paint
3227    * box represents the location of the source actor on the
3228    * screen.
3229    *
3230    * XXX: We are starting to do a lot of vertex transforms on
3231    * the CPU in a typical paint, so at some point we should
3232    * audit these and consider caching some things.
3233    *
3234    * NB: We don't perform culling while picking at this point because
3235    * clutter-stage.c doesn't setup the clipping planes appropriately.
3236    *
3237    * NB: We don't want to update the last-paint-volume during picking
3238    * because the last-paint-volume is used to determine the old screen
3239    * space location of an actor that has moved so we can know the
3240    * minimal region to redraw to clear an old view of the actor. If we
3241    * update this during picking then by the time we come around to
3242    * paint then the last-paint-volume would likely represent the new
3243    * actor position not the old.
3244    */
3245   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3246     {
3247       gboolean success;
3248       /* annoyingly gcc warns if uninitialized even though
3249        * the initialization is redundant :-( */
3250       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3251
3252       if (G_LIKELY ((clutter_paint_debug_flags &
3253                      (CLUTTER_DEBUG_DISABLE_CULLING |
3254                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3255                     (CLUTTER_DEBUG_DISABLE_CULLING |
3256                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3257         _clutter_actor_update_last_paint_volume (self);
3258
3259       success = cull_actor (self, &result);
3260
3261       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3262         _clutter_actor_paint_cull_result (self, success, result);
3263       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3264         goto done;
3265     }
3266
3267   if (priv->effects == NULL)
3268     {
3269       if (pick_mode == CLUTTER_PICK_NONE &&
3270           actor_has_shader_data (self))
3271         {
3272           _clutter_actor_shader_pre_paint (self, FALSE);
3273           shader_applied = TRUE;
3274         }
3275
3276       priv->next_effect_to_paint = NULL;
3277     }
3278   else
3279     priv->next_effect_to_paint =
3280       _clutter_meta_group_peek_metas (priv->effects);
3281
3282   clutter_actor_continue_paint (self);
3283
3284   if (shader_applied)
3285     _clutter_actor_shader_post_paint (self);
3286
3287   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3288                   pick_mode == CLUTTER_PICK_NONE))
3289     _clutter_actor_draw_paint_volume (self);
3290
3291 done:
3292   /* If we make it here then the actor has run through a complete
3293      paint run including all the effects so it's no longer dirty */
3294   if (pick_mode == CLUTTER_PICK_NONE)
3295     priv->is_dirty = FALSE;
3296
3297   if (clip_set)
3298     cogl_clip_pop();
3299
3300   cogl_pop_matrix();
3301
3302   /* paint sequence complete */
3303   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3304 }
3305
3306 /**
3307  * clutter_actor_continue_paint:
3308  * @self: A #ClutterActor
3309  *
3310  * Run the next stage of the paint sequence. This function should only
3311  * be called within the implementation of the ‘run’ virtual of a
3312  * #ClutterEffect. It will cause the run method of the next effect to
3313  * be applied, or it will paint the actual actor if the current effect
3314  * is the last effect in the chain.
3315  *
3316  * Since: 1.8
3317  */
3318 void
3319 clutter_actor_continue_paint (ClutterActor *self)
3320 {
3321   ClutterActorPrivate *priv;
3322
3323   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3324   /* This should only be called from with in the ‘run’ implementation
3325      of a ClutterEffect */
3326   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3327
3328   priv = self->priv;
3329
3330   /* Skip any effects that are disabled */
3331   while (priv->next_effect_to_paint &&
3332          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3333     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3334
3335   /* If this has come from the last effect then we'll just paint the
3336      actual actor */
3337   if (priv->next_effect_to_paint == NULL)
3338     {
3339       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3340         {
3341           g_signal_emit (self, actor_signals[PAINT], 0);
3342         }
3343       else
3344         {
3345           ClutterColor col = { 0, };
3346
3347           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3348
3349           /* Actor will then paint silhouette of itself in supplied
3350            * color.  See clutter_stage_get_actor_at_pos() for where
3351            * picking is enabled.
3352            */
3353           g_signal_emit (self, actor_signals[PICK], 0, &col);
3354         }
3355     }
3356   else
3357     {
3358       ClutterEffect *old_current_effect;
3359       ClutterEffectPaintFlags run_flags = 0;
3360
3361       /* Cache the current effect so that we can put it back before
3362          returning */
3363       old_current_effect = priv->current_effect;
3364
3365       priv->current_effect = priv->next_effect_to_paint->data;
3366       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3367
3368       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3369         {
3370           if (priv->is_dirty)
3371             {
3372               /* If there's an effect queued with this redraw then all
3373                  effects up to that one will be considered dirty. It
3374                  is expected the queued effect will paint the cached
3375                  image and not call clutter_actor_continue_paint again
3376                  (although it should work ok if it does) */
3377               if (priv->effect_to_redraw == NULL ||
3378                   priv->current_effect != priv->effect_to_redraw)
3379                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3380             }
3381
3382           _clutter_effect_paint (priv->current_effect, run_flags);
3383         }
3384       else
3385         {
3386           /* We can't determine when an actor has been modified since
3387              its last pick so lets just assume it has always been
3388              modified */
3389           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3390
3391           _clutter_effect_pick (priv->current_effect, run_flags);
3392         }
3393
3394       priv->current_effect = old_current_effect;
3395     }
3396 }
3397
3398 static ClutterActorTraverseVisitFlags
3399 invalidate_queue_redraw_entry (ClutterActor *self,
3400                                int           depth,
3401                                gpointer      user_data)
3402 {
3403   ClutterActorPrivate *priv = self->priv;
3404
3405   if (priv->queue_redraw_entry != NULL)
3406     {
3407       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3408       priv->queue_redraw_entry = NULL;
3409     }
3410
3411   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3412 }
3413
3414 static inline void
3415 remove_child (ClutterActor *self,
3416               ClutterActor *child)
3417 {
3418   ClutterActor *prev_sibling, *next_sibling;
3419
3420   prev_sibling = child->priv->prev_sibling;
3421   next_sibling = child->priv->next_sibling;
3422
3423   if (prev_sibling != NULL)
3424     prev_sibling->priv->next_sibling = next_sibling;
3425
3426   if (next_sibling != NULL)
3427     next_sibling->priv->prev_sibling = prev_sibling;
3428
3429   if (self->priv->first_child == child)
3430     self->priv->first_child = next_sibling;
3431
3432   if (self->priv->last_child == child)
3433     self->priv->last_child = prev_sibling;
3434
3435   child->priv->parent = NULL;
3436   child->priv->prev_sibling = NULL;
3437   child->priv->next_sibling = NULL;
3438 }
3439
3440 typedef enum {
3441   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3442   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3443   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3444   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3445   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3446   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3447
3448   /* default flags for public API */
3449   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3450                                     REMOVE_CHILD_EMIT_PARENT_SET |
3451                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3452                                     REMOVE_CHILD_CHECK_STATE |
3453                                     REMOVE_CHILD_FLUSH_QUEUE |
3454                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3455
3456   /* flags for legacy/deprecated API */
3457   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3458                                     REMOVE_CHILD_FLUSH_QUEUE |
3459                                     REMOVE_CHILD_EMIT_PARENT_SET |
3460                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3461 } ClutterActorRemoveChildFlags;
3462
3463 /*< private >
3464  * clutter_actor_remove_child_internal:
3465  * @self: a #ClutterActor
3466  * @child: the child of @self that has to be removed
3467  * @flags: control the removal operations
3468  *
3469  * Removes @child from the list of children of @self.
3470  */
3471 static void
3472 clutter_actor_remove_child_internal (ClutterActor                 *self,
3473                                      ClutterActor                 *child,
3474                                      ClutterActorRemoveChildFlags  flags)
3475 {
3476   ClutterActor *old_first, *old_last;
3477   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3478   gboolean flush_queue;
3479   gboolean notify_first_last;
3480   gboolean was_mapped;
3481
3482   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3483   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3484   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3485   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3486   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3487   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3488
3489   if (destroy_meta)
3490     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3491
3492   if (check_state)
3493     {
3494       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3495
3496       /* we need to unrealize *before* we set parent_actor to NULL,
3497        * because in an unrealize method actors are dissociating from the
3498        * stage, which means they need to be able to
3499        * clutter_actor_get_stage().
3500        *
3501        * yhis should unmap and unrealize, unless we're reparenting.
3502        */
3503       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3504     }
3505   else
3506     was_mapped = FALSE;
3507
3508   if (flush_queue)
3509     {
3510       /* We take this opportunity to invalidate any queue redraw entry
3511        * associated with the actor and descendants since we won't be able to
3512        * determine the appropriate stage after this.
3513        *
3514        * we do this after we updated the mapped state because actors might
3515        * end up queueing redraws inside their mapped/unmapped virtual
3516        * functions, and if we invalidate the redraw entry we could end up
3517        * with an inconsistent state and weird memory corruption. see
3518        * bugs:
3519        *
3520        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3521        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3522        */
3523       _clutter_actor_traverse (child,
3524                                0,
3525                                invalidate_queue_redraw_entry,
3526                                NULL,
3527                                NULL);
3528     }
3529
3530   old_first = self->priv->first_child;
3531   old_last = self->priv->last_child;
3532
3533   remove_child (self, child);
3534
3535   self->priv->n_children -= 1;
3536
3537   self->priv->age += 1;
3538
3539   /* clutter_actor_reparent() will emit ::parent-set for us */
3540   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3541     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3542
3543   /* if the child was mapped then we need to relayout ourselves to account
3544    * for the removed child
3545    */
3546   if (was_mapped)
3547     clutter_actor_queue_relayout (self);
3548
3549   /* we need to emit the signal before dropping the reference */
3550   if (emit_actor_removed)
3551     g_signal_emit_by_name (self, "actor-removed", child);
3552
3553   if (notify_first_last)
3554     {
3555       if (old_first != self->priv->first_child)
3556         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3557
3558       if (old_last != self->priv->last_child)
3559         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3560     }
3561
3562   /* remove the reference we acquired in clutter_actor_add_child() */
3563   g_object_unref (child);
3564 }
3565
3566 static const ClutterTransformInfo default_transform_info = {
3567   0.0, { 0, },          /* rotation-x */
3568   0.0, { 0, },          /* rotation-y */
3569   0.0, { 0, },          /* rotation-z */
3570
3571   1.0, 1.0, { 0, },     /* scale */
3572
3573   { 0, },               /* anchor */
3574 };
3575
3576 /*< private >
3577  * _clutter_actor_get_transform_info_or_defaults:
3578  * @self: a #ClutterActor
3579  *
3580  * Retrieves the ClutterTransformInfo structure associated to an actor.
3581  *
3582  * If the actor does not have a ClutterTransformInfo structure associated
3583  * to it, then the default structure will be returned.
3584  *
3585  * This function should only be used for getters.
3586  *
3587  * Return value: a const pointer to the ClutterTransformInfo structure
3588  */
3589 const ClutterTransformInfo *
3590 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3591 {
3592   ClutterTransformInfo *info;
3593
3594   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3595   if (info != NULL)
3596     return info;
3597
3598   return &default_transform_info;
3599 }
3600
3601 static void
3602 clutter_transform_info_free (gpointer data)
3603 {
3604   if (data != NULL)
3605     g_slice_free (ClutterTransformInfo, data);
3606 }
3607
3608 /*< private >
3609  * _clutter_actor_get_transform_info:
3610  * @self: a #ClutterActor
3611  *
3612  * Retrieves a pointer to the ClutterTransformInfo structure.
3613  *
3614  * If the actor does not have a ClutterTransformInfo associated to it, one
3615  * will be created and initialized to the default values.
3616  *
3617  * This function should be used for setters.
3618  *
3619  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3620  * instead.
3621  *
3622  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3623  *   structure
3624  */
3625 ClutterTransformInfo *
3626 _clutter_actor_get_transform_info (ClutterActor *self)
3627 {
3628   ClutterTransformInfo *info;
3629
3630   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3631   if (info == NULL)
3632     {
3633       info = g_slice_new (ClutterTransformInfo);
3634
3635       *info = default_transform_info;
3636
3637       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3638                                info,
3639                                clutter_transform_info_free);
3640     }
3641
3642   return info;
3643 }
3644
3645 /*< private >
3646  * clutter_actor_set_rotation_angle_internal:
3647  * @self: a #ClutterActor
3648  * @axis: the axis of the angle to change
3649  * @angle: the angle of rotation
3650  *
3651  * Sets the rotation angle on the given axis without affecting the
3652  * rotation center point.
3653  */
3654 static inline void
3655 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3656                                            ClutterRotateAxis  axis,
3657                                            gdouble            angle)
3658 {
3659   GObject *obj = G_OBJECT (self);
3660   ClutterTransformInfo *info;
3661
3662   info = _clutter_actor_get_transform_info (self);
3663
3664   g_object_freeze_notify (obj);
3665
3666   switch (axis)
3667     {
3668     case CLUTTER_X_AXIS:
3669       info->rx_angle = angle;
3670       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3671       break;
3672
3673     case CLUTTER_Y_AXIS:
3674       info->ry_angle = angle;
3675       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3676       break;
3677
3678     case CLUTTER_Z_AXIS:
3679       info->rz_angle = angle;
3680       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3681       break;
3682     }
3683
3684   self->priv->transform_valid = FALSE;
3685
3686   g_object_thaw_notify (obj);
3687
3688   clutter_actor_queue_redraw (self);
3689 }
3690
3691 /*< private >
3692  * clutter_actor_set_rotation_center_internal:
3693  * @self: a #ClutterActor
3694  * @axis: the axis of the center to change
3695  * @center: the coordinates of the rotation center
3696  *
3697  * Sets the rotation center on the given axis without affecting the
3698  * rotation angle.
3699  */
3700 static inline void
3701 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3702                                             ClutterRotateAxis    axis,
3703                                             const ClutterVertex *center)
3704 {
3705   GObject *obj = G_OBJECT (self);
3706   ClutterTransformInfo *info;
3707   ClutterVertex v = { 0, 0, 0 };
3708
3709   info = _clutter_actor_get_transform_info (self);
3710
3711   if (center != NULL)
3712     v = *center;
3713
3714   g_object_freeze_notify (obj);
3715
3716   switch (axis)
3717     {
3718     case CLUTTER_X_AXIS:
3719       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3720       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3721       break;
3722
3723     case CLUTTER_Y_AXIS:
3724       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3725       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3726       break;
3727
3728     case CLUTTER_Z_AXIS:
3729       /* if the previously set rotation center was fractional, then
3730        * setting explicit coordinates will have to notify the
3731        * :rotation-center-z-gravity property as well
3732        */
3733       if (info->rz_center.is_fractional)
3734         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3735
3736       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3737       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3738       break;
3739     }
3740
3741   self->priv->transform_valid = FALSE;
3742
3743   g_object_thaw_notify (obj);
3744
3745   clutter_actor_queue_redraw (self);
3746 }
3747
3748 static inline void
3749 clutter_actor_set_scale_factor (ClutterActor      *self,
3750                                 ClutterRotateAxis  axis,
3751                                 gdouble            factor)
3752 {
3753   GObject *obj = G_OBJECT (self);
3754   ClutterTransformInfo *info;
3755
3756   info = _clutter_actor_get_transform_info (self);
3757
3758   g_object_freeze_notify (obj);
3759
3760   switch (axis)
3761     {
3762     case CLUTTER_X_AXIS:
3763       info->scale_x = factor;
3764       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
3765       break;
3766
3767     case CLUTTER_Y_AXIS:
3768       info->scale_y = factor;
3769       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
3770       break;
3771
3772     default:
3773       g_assert_not_reached ();
3774     }
3775
3776   self->priv->transform_valid = FALSE;
3777
3778   clutter_actor_queue_redraw (self);
3779
3780   g_object_thaw_notify (obj);
3781 }
3782
3783 static inline void
3784 clutter_actor_set_scale_center (ClutterActor      *self,
3785                                 ClutterRotateAxis  axis,
3786                                 gfloat             coord)
3787 {
3788   GObject *obj = G_OBJECT (self);
3789   ClutterTransformInfo *info;
3790   gfloat center_x, center_y;
3791
3792   info = _clutter_actor_get_transform_info (self);
3793
3794   g_object_freeze_notify (obj);
3795
3796   /* get the current scale center coordinates */
3797   clutter_anchor_coord_get_units (self, &info->scale_center,
3798                                   &center_x,
3799                                   &center_y,
3800                                   NULL);
3801
3802   /* we need to notify this too, because setting explicit coordinates will
3803    * change the gravity as a side effect
3804    */
3805   if (info->scale_center.is_fractional)
3806     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
3807
3808   switch (axis)
3809     {
3810     case CLUTTER_X_AXIS:
3811       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
3812       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
3813       break;
3814
3815     case CLUTTER_Y_AXIS:
3816       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
3817       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
3818       break;
3819
3820     default:
3821       g_assert_not_reached ();
3822     }
3823
3824   self->priv->transform_valid = FALSE;
3825
3826   clutter_actor_queue_redraw (self);
3827
3828   g_object_thaw_notify (obj);
3829 }
3830
3831 static inline void
3832 clutter_actor_set_anchor_coord (ClutterActor      *self,
3833                                 ClutterRotateAxis  axis,
3834                                 gfloat             coord)
3835 {
3836   GObject *obj = G_OBJECT (self);
3837   ClutterTransformInfo *info;
3838   gfloat anchor_x, anchor_y;
3839
3840   info = _clutter_actor_get_transform_info (self);
3841
3842   g_object_freeze_notify (obj);
3843
3844   clutter_anchor_coord_get_units (self, &info->anchor,
3845                                   &anchor_x,
3846                                   &anchor_y,
3847                                   NULL);
3848
3849   if (info->anchor.is_fractional)
3850     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
3851
3852   switch (axis)
3853     {
3854     case CLUTTER_X_AXIS:
3855       clutter_anchor_coord_set_units (&info->anchor,
3856                                       coord,
3857                                       anchor_y,
3858                                       0.0);
3859       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
3860       break;
3861
3862     case CLUTTER_Y_AXIS:
3863       clutter_anchor_coord_set_units (&info->anchor,
3864                                       anchor_x,
3865                                       coord,
3866                                       0.0);
3867       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
3868       break;
3869
3870     default:
3871       g_assert_not_reached ();
3872     }
3873
3874   self->priv->transform_valid = FALSE;
3875
3876   clutter_actor_queue_redraw (self);
3877
3878   g_object_thaw_notify (obj);
3879 }
3880
3881 static void
3882 clutter_actor_set_property (GObject      *object,
3883                             guint         prop_id,
3884                             const GValue *value,
3885                             GParamSpec   *pspec)
3886 {
3887   ClutterActor *actor = CLUTTER_ACTOR (object);
3888   ClutterActorPrivate *priv = actor->priv;
3889
3890   switch (prop_id)
3891     {
3892     case PROP_X:
3893       clutter_actor_set_x (actor, g_value_get_float (value));
3894       break;
3895
3896     case PROP_Y:
3897       clutter_actor_set_y (actor, g_value_get_float (value));
3898       break;
3899
3900     case PROP_WIDTH:
3901       clutter_actor_set_width (actor, g_value_get_float (value));
3902       break;
3903
3904     case PROP_HEIGHT:
3905       clutter_actor_set_height (actor, g_value_get_float (value));
3906       break;
3907
3908     case PROP_FIXED_X:
3909       clutter_actor_set_x (actor, g_value_get_float (value));
3910       break;
3911
3912     case PROP_FIXED_Y:
3913       clutter_actor_set_y (actor, g_value_get_float (value));
3914       break;
3915
3916     case PROP_FIXED_POSITION_SET:
3917       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
3918       break;
3919
3920     case PROP_MIN_WIDTH:
3921       clutter_actor_set_min_width (actor, g_value_get_float (value));
3922       break;
3923
3924     case PROP_MIN_HEIGHT:
3925       clutter_actor_set_min_height (actor, g_value_get_float (value));
3926       break;
3927
3928     case PROP_NATURAL_WIDTH:
3929       clutter_actor_set_natural_width (actor, g_value_get_float (value));
3930       break;
3931
3932     case PROP_NATURAL_HEIGHT:
3933       clutter_actor_set_natural_height (actor, g_value_get_float (value));
3934       break;
3935
3936     case PROP_MIN_WIDTH_SET:
3937       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
3938       break;
3939
3940     case PROP_MIN_HEIGHT_SET:
3941       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
3942       break;
3943
3944     case PROP_NATURAL_WIDTH_SET:
3945       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
3946       break;
3947
3948     case PROP_NATURAL_HEIGHT_SET:
3949       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
3950       break;
3951
3952     case PROP_REQUEST_MODE:
3953       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
3954       break;
3955
3956     case PROP_DEPTH:
3957       clutter_actor_set_depth (actor, g_value_get_float (value));
3958       break;
3959
3960     case PROP_OPACITY:
3961       clutter_actor_set_opacity (actor, g_value_get_uint (value));
3962       break;
3963
3964     case PROP_OFFSCREEN_REDIRECT:
3965       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
3966       break;
3967
3968     case PROP_NAME:
3969       clutter_actor_set_name (actor, g_value_get_string (value));
3970       break;
3971
3972     case PROP_VISIBLE:
3973       if (g_value_get_boolean (value) == TRUE)
3974         clutter_actor_show (actor);
3975       else
3976         clutter_actor_hide (actor);
3977       break;
3978
3979     case PROP_SCALE_X:
3980       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
3981                                       g_value_get_double (value));
3982       break;
3983
3984     case PROP_SCALE_Y:
3985       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
3986                                       g_value_get_double (value));
3987       break;
3988
3989     case PROP_SCALE_CENTER_X:
3990       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
3991                                       g_value_get_float (value));
3992       break;
3993
3994     case PROP_SCALE_CENTER_Y:
3995       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
3996                                       g_value_get_float (value));
3997       break;
3998
3999     case PROP_SCALE_GRAVITY:
4000       {
4001         const ClutterTransformInfo *info;
4002         ClutterGravity gravity;
4003
4004         info = _clutter_actor_get_transform_info_or_defaults (actor);
4005         gravity = g_value_get_enum (value);
4006
4007         clutter_actor_set_scale_with_gravity (actor,
4008                                               info->scale_x,
4009                                               info->scale_y,
4010                                               gravity);
4011       }
4012       break;
4013
4014     case PROP_CLIP:
4015       {
4016         const ClutterGeometry *geom = g_value_get_boxed (value);
4017
4018         clutter_actor_set_clip (actor,
4019                                 geom->x, geom->y,
4020                                 geom->width, geom->height);
4021       }
4022       break;
4023
4024     case PROP_CLIP_TO_ALLOCATION:
4025       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4026       break;
4027
4028     case PROP_REACTIVE:
4029       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4030       break;
4031
4032     case PROP_ROTATION_ANGLE_X:
4033       clutter_actor_set_rotation_angle_internal (actor,
4034                                                  CLUTTER_X_AXIS,
4035                                                  g_value_get_double (value));
4036       break;
4037
4038     case PROP_ROTATION_ANGLE_Y:
4039       clutter_actor_set_rotation_angle_internal (actor,
4040                                                  CLUTTER_Y_AXIS,
4041                                                  g_value_get_double (value));
4042       break;
4043
4044     case PROP_ROTATION_ANGLE_Z:
4045       clutter_actor_set_rotation_angle_internal (actor,
4046                                                  CLUTTER_Z_AXIS,
4047                                                  g_value_get_double (value));
4048       break;
4049
4050     case PROP_ROTATION_CENTER_X:
4051       clutter_actor_set_rotation_center_internal (actor,
4052                                                   CLUTTER_X_AXIS,
4053                                                   g_value_get_boxed (value));
4054       break;
4055
4056     case PROP_ROTATION_CENTER_Y:
4057       clutter_actor_set_rotation_center_internal (actor,
4058                                                   CLUTTER_Y_AXIS,
4059                                                   g_value_get_boxed (value));
4060       break;
4061
4062     case PROP_ROTATION_CENTER_Z:
4063       clutter_actor_set_rotation_center_internal (actor,
4064                                                   CLUTTER_Z_AXIS,
4065                                                   g_value_get_boxed (value));
4066       break;
4067
4068     case PROP_ROTATION_CENTER_Z_GRAVITY:
4069       {
4070         const ClutterTransformInfo *info;
4071
4072         info = _clutter_actor_get_transform_info_or_defaults (actor);
4073         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4074                                                    g_value_get_enum (value));
4075       }
4076       break;
4077
4078     case PROP_ANCHOR_X:
4079       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4080                                       g_value_get_float (value));
4081       break;
4082
4083     case PROP_ANCHOR_Y:
4084       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4085                                       g_value_get_float (value));
4086       break;
4087
4088     case PROP_ANCHOR_GRAVITY:
4089       clutter_actor_set_anchor_point_from_gravity (actor,
4090                                                    g_value_get_enum (value));
4091       break;
4092
4093     case PROP_SHOW_ON_SET_PARENT:
4094       priv->show_on_set_parent = g_value_get_boolean (value);
4095       break;
4096
4097     case PROP_TEXT_DIRECTION:
4098       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4099       break;
4100
4101     case PROP_ACTIONS:
4102       clutter_actor_add_action (actor, g_value_get_object (value));
4103       break;
4104
4105     case PROP_CONSTRAINTS:
4106       clutter_actor_add_constraint (actor, g_value_get_object (value));
4107       break;
4108
4109     case PROP_EFFECT:
4110       clutter_actor_add_effect (actor, g_value_get_object (value));
4111       break;
4112
4113     case PROP_LAYOUT_MANAGER:
4114       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4115       break;
4116
4117     case PROP_X_ALIGN:
4118       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4119       break;
4120
4121     case PROP_Y_ALIGN:
4122       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4123       break;
4124
4125     case PROP_MARGIN_TOP:
4126       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4127       break;
4128
4129     case PROP_MARGIN_BOTTOM:
4130       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4131       break;
4132
4133     case PROP_MARGIN_LEFT:
4134       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4135       break;
4136
4137     case PROP_MARGIN_RIGHT:
4138       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4139       break;
4140
4141     case PROP_BACKGROUND_COLOR:
4142       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4143       break;
4144
4145     default:
4146       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4147       break;
4148     }
4149 }
4150
4151 static void
4152 clutter_actor_get_property (GObject    *object,
4153                             guint       prop_id,
4154                             GValue     *value,
4155                             GParamSpec *pspec)
4156 {
4157   ClutterActor *actor = CLUTTER_ACTOR (object);
4158   ClutterActorPrivate *priv = actor->priv;
4159
4160   switch (prop_id)
4161     {
4162     case PROP_X:
4163       g_value_set_float (value, clutter_actor_get_x (actor));
4164       break;
4165
4166     case PROP_Y:
4167       g_value_set_float (value, clutter_actor_get_y (actor));
4168       break;
4169
4170     case PROP_WIDTH:
4171       g_value_set_float (value, clutter_actor_get_width (actor));
4172       break;
4173
4174     case PROP_HEIGHT:
4175       g_value_set_float (value, clutter_actor_get_height (actor));
4176       break;
4177
4178     case PROP_FIXED_X:
4179       {
4180         const ClutterLayoutInfo *info;
4181
4182         info = _clutter_actor_get_layout_info_or_defaults (actor);
4183         g_value_set_float (value, info->fixed_x);
4184       }
4185       break;
4186
4187     case PROP_FIXED_Y:
4188       {
4189         const ClutterLayoutInfo *info;
4190
4191         info = _clutter_actor_get_layout_info_or_defaults (actor);
4192         g_value_set_float (value, info->fixed_y);
4193       }
4194       break;
4195
4196     case PROP_FIXED_POSITION_SET:
4197       g_value_set_boolean (value, priv->position_set);
4198       break;
4199
4200     case PROP_MIN_WIDTH:
4201       {
4202         const ClutterLayoutInfo *info;
4203
4204         info = _clutter_actor_get_layout_info_or_defaults (actor);
4205         g_value_set_float (value, info->min_width);
4206       }
4207       break;
4208
4209     case PROP_MIN_HEIGHT:
4210       {
4211         const ClutterLayoutInfo *info;
4212
4213         info = _clutter_actor_get_layout_info_or_defaults (actor);
4214         g_value_set_float (value, info->min_height);
4215       }
4216       break;
4217
4218     case PROP_NATURAL_WIDTH:
4219       {
4220         const ClutterLayoutInfo *info;
4221
4222         info = _clutter_actor_get_layout_info_or_defaults (actor);
4223         g_value_set_float (value, info->natural_width);
4224       }
4225       break;
4226
4227     case PROP_NATURAL_HEIGHT:
4228       {
4229         const ClutterLayoutInfo *info;
4230
4231         info = _clutter_actor_get_layout_info_or_defaults (actor);
4232         g_value_set_float (value, info->natural_height);
4233       }
4234       break;
4235
4236     case PROP_MIN_WIDTH_SET:
4237       g_value_set_boolean (value, priv->min_width_set);
4238       break;
4239
4240     case PROP_MIN_HEIGHT_SET:
4241       g_value_set_boolean (value, priv->min_height_set);
4242       break;
4243
4244     case PROP_NATURAL_WIDTH_SET:
4245       g_value_set_boolean (value, priv->natural_width_set);
4246       break;
4247
4248     case PROP_NATURAL_HEIGHT_SET:
4249       g_value_set_boolean (value, priv->natural_height_set);
4250       break;
4251
4252     case PROP_REQUEST_MODE:
4253       g_value_set_enum (value, priv->request_mode);
4254       break;
4255
4256     case PROP_ALLOCATION:
4257       g_value_set_boxed (value, &priv->allocation);
4258       break;
4259
4260     case PROP_DEPTH:
4261       g_value_set_float (value, clutter_actor_get_depth (actor));
4262       break;
4263
4264     case PROP_OPACITY:
4265       g_value_set_uint (value, priv->opacity);
4266       break;
4267
4268     case PROP_OFFSCREEN_REDIRECT:
4269       g_value_set_enum (value, priv->offscreen_redirect);
4270       break;
4271
4272     case PROP_NAME:
4273       g_value_set_string (value, priv->name);
4274       break;
4275
4276     case PROP_VISIBLE:
4277       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4278       break;
4279
4280     case PROP_MAPPED:
4281       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4282       break;
4283
4284     case PROP_REALIZED:
4285       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4286       break;
4287
4288     case PROP_HAS_CLIP:
4289       g_value_set_boolean (value, priv->has_clip);
4290       break;
4291
4292     case PROP_CLIP:
4293       {
4294         ClutterGeometry clip;
4295
4296         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4297         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4298         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4299         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4300
4301         g_value_set_boxed (value, &clip);
4302       }
4303       break;
4304
4305     case PROP_CLIP_TO_ALLOCATION:
4306       g_value_set_boolean (value, priv->clip_to_allocation);
4307       break;
4308
4309     case PROP_SCALE_X:
4310       {
4311         const ClutterTransformInfo *info;
4312
4313         info = _clutter_actor_get_transform_info_or_defaults (actor);
4314         g_value_set_double (value, info->scale_x);
4315       }
4316       break;
4317
4318     case PROP_SCALE_Y:
4319       {
4320         const ClutterTransformInfo *info;
4321
4322         info = _clutter_actor_get_transform_info_or_defaults (actor);
4323         g_value_set_double (value, info->scale_y);
4324       }
4325       break;
4326
4327     case PROP_SCALE_CENTER_X:
4328       {
4329         gfloat center;
4330
4331         clutter_actor_get_scale_center (actor, &center, NULL);
4332
4333         g_value_set_float (value, center);
4334       }
4335       break;
4336
4337     case PROP_SCALE_CENTER_Y:
4338       {
4339         gfloat center;
4340
4341         clutter_actor_get_scale_center (actor, NULL, &center);
4342
4343         g_value_set_float (value, center);
4344       }
4345       break;
4346
4347     case PROP_SCALE_GRAVITY:
4348       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4349       break;
4350
4351     case PROP_REACTIVE:
4352       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4353       break;
4354
4355     case PROP_ROTATION_ANGLE_X:
4356       {
4357         const ClutterTransformInfo *info;
4358
4359         info = _clutter_actor_get_transform_info_or_defaults (actor);
4360         g_value_set_double (value, info->rx_angle);
4361       }
4362       break;
4363
4364     case PROP_ROTATION_ANGLE_Y:
4365       {
4366         const ClutterTransformInfo *info;
4367
4368         info = _clutter_actor_get_transform_info_or_defaults (actor);
4369         g_value_set_double (value, info->ry_angle);
4370       }
4371       break;
4372
4373     case PROP_ROTATION_ANGLE_Z:
4374       {
4375         const ClutterTransformInfo *info;
4376
4377         info = _clutter_actor_get_transform_info_or_defaults (actor);
4378         g_value_set_double (value, info->rz_angle);
4379       }
4380       break;
4381
4382     case PROP_ROTATION_CENTER_X:
4383       {
4384         ClutterVertex center;
4385
4386         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4387                                     &center.x,
4388                                     &center.y,
4389                                     &center.z);
4390
4391         g_value_set_boxed (value, &center);
4392       }
4393       break;
4394
4395     case PROP_ROTATION_CENTER_Y:
4396       {
4397         ClutterVertex center;
4398
4399         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4400                                     &center.x,
4401                                     &center.y,
4402                                     &center.z);
4403
4404         g_value_set_boxed (value, &center);
4405       }
4406       break;
4407
4408     case PROP_ROTATION_CENTER_Z:
4409       {
4410         ClutterVertex center;
4411
4412         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4413                                     &center.x,
4414                                     &center.y,
4415                                     &center.z);
4416
4417         g_value_set_boxed (value, &center);
4418       }
4419       break;
4420
4421     case PROP_ROTATION_CENTER_Z_GRAVITY:
4422       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4423       break;
4424
4425     case PROP_ANCHOR_X:
4426       {
4427         const ClutterTransformInfo *info;
4428         gfloat anchor_x;
4429
4430         info = _clutter_actor_get_transform_info_or_defaults (actor);
4431         clutter_anchor_coord_get_units (actor, &info->anchor,
4432                                         &anchor_x,
4433                                         NULL,
4434                                         NULL);
4435         g_value_set_float (value, anchor_x);
4436       }
4437       break;
4438
4439     case PROP_ANCHOR_Y:
4440       {
4441         const ClutterTransformInfo *info;
4442         gfloat anchor_y;
4443
4444         info = _clutter_actor_get_transform_info_or_defaults (actor);
4445         clutter_anchor_coord_get_units (actor, &info->anchor,
4446                                         NULL,
4447                                         &anchor_y,
4448                                         NULL);
4449         g_value_set_float (value, anchor_y);
4450       }
4451       break;
4452
4453     case PROP_ANCHOR_GRAVITY:
4454       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4455       break;
4456
4457     case PROP_SHOW_ON_SET_PARENT:
4458       g_value_set_boolean (value, priv->show_on_set_parent);
4459       break;
4460
4461     case PROP_TEXT_DIRECTION:
4462       g_value_set_enum (value, priv->text_direction);
4463       break;
4464
4465     case PROP_HAS_POINTER:
4466       g_value_set_boolean (value, priv->has_pointer);
4467       break;
4468
4469     case PROP_LAYOUT_MANAGER:
4470       g_value_set_object (value, priv->layout_manager);
4471       break;
4472
4473     case PROP_X_ALIGN:
4474       {
4475         const ClutterLayoutInfo *info;
4476
4477         info = _clutter_actor_get_layout_info_or_defaults (actor);
4478         g_value_set_enum (value, info->x_align);
4479       }
4480       break;
4481
4482     case PROP_Y_ALIGN:
4483       {
4484         const ClutterLayoutInfo *info;
4485
4486         info = _clutter_actor_get_layout_info_or_defaults (actor);
4487         g_value_set_enum (value, info->y_align);
4488       }
4489       break;
4490
4491     case PROP_MARGIN_TOP:
4492       {
4493         const ClutterLayoutInfo *info;
4494
4495         info = _clutter_actor_get_layout_info_or_defaults (actor);
4496         g_value_set_float (value, info->margin.top);
4497       }
4498       break;
4499
4500     case PROP_MARGIN_BOTTOM:
4501       {
4502         const ClutterLayoutInfo *info;
4503
4504         info = _clutter_actor_get_layout_info_or_defaults (actor);
4505         g_value_set_float (value, info->margin.bottom);
4506       }
4507       break;
4508
4509     case PROP_MARGIN_LEFT:
4510       {
4511         const ClutterLayoutInfo *info;
4512
4513         info = _clutter_actor_get_layout_info_or_defaults (actor);
4514         g_value_set_float (value, info->margin.left);
4515       }
4516       break;
4517
4518     case PROP_MARGIN_RIGHT:
4519       {
4520         const ClutterLayoutInfo *info;
4521
4522         info = _clutter_actor_get_layout_info_or_defaults (actor);
4523         g_value_set_float (value, info->margin.right);
4524       }
4525       break;
4526
4527     case PROP_BACKGROUND_COLOR_SET:
4528       g_value_set_boolean (value, priv->bg_color_set);
4529       break;
4530
4531     case PROP_BACKGROUND_COLOR:
4532       g_value_set_boxed (value, &priv->bg_color);
4533       break;
4534
4535     case PROP_FIRST_CHILD:
4536       g_value_set_object (value, priv->first_child);
4537       break;
4538
4539     case PROP_LAST_CHILD:
4540       g_value_set_object (value, priv->last_child);
4541       break;
4542
4543     default:
4544       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4545       break;
4546     }
4547 }
4548
4549 static void
4550 clutter_actor_dispose (GObject *object)
4551 {
4552   ClutterActor *self = CLUTTER_ACTOR (object);
4553   ClutterActorPrivate *priv = self->priv;
4554
4555   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4556                 priv->id,
4557                 g_type_name (G_OBJECT_TYPE (self)),
4558                 object->ref_count);
4559
4560   g_signal_emit (self, actor_signals[DESTROY], 0);
4561
4562   /* avoid recursing when called from clutter_actor_destroy() */
4563   if (priv->parent != NULL)
4564     {
4565       ClutterActor *parent = priv->parent;
4566
4567       /* go through the Container implementation unless this
4568        * is an internal child and has been marked as such.
4569        *
4570        * removing the actor from its parent will reset the
4571        * realized and mapped states.
4572        */
4573       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4574         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4575       else
4576         clutter_actor_remove_child_internal (parent, self,
4577                                              REMOVE_CHILD_LEGACY_FLAGS);
4578     }
4579
4580   /* parent must be gone at this point */
4581   g_assert (priv->parent == NULL);
4582
4583   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4584     {
4585       /* can't be mapped or realized with no parent */
4586       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4587       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4588     }
4589
4590   g_clear_object (&priv->pango_context);
4591   g_clear_object (&priv->actions);
4592   g_clear_object (&priv->constraints);
4593   g_clear_object (&priv->effects);
4594   g_clear_object (&priv->flatten_effect);
4595
4596   if (priv->layout_manager != NULL)
4597     {
4598       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4599       g_object_unref (priv->layout_manager);
4600       priv->layout_manager = NULL;
4601     }
4602
4603   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4604 }
4605
4606 static void
4607 clutter_actor_finalize (GObject *object)
4608 {
4609   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4610
4611   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4612                 priv->name != NULL ? priv->name : "<none>",
4613                 priv->id,
4614                 g_type_name (G_OBJECT_TYPE (object)));
4615
4616   _clutter_context_release_id (priv->id);
4617
4618   g_free (priv->name);
4619
4620   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4621 }
4622
4623
4624 /**
4625  * clutter_actor_get_accessible:
4626  * @self: a #ClutterActor
4627  *
4628  * Returns the accessible object that describes the actor to an
4629  * assistive technology.
4630  *
4631  * If no class-specific #AtkObject implementation is available for the
4632  * actor instance in question, it will inherit an #AtkObject
4633  * implementation from the first ancestor class for which such an
4634  * implementation is defined.
4635  *
4636  * The documentation of the <ulink
4637  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4638  * library contains more information about accessible objects and
4639  * their uses.
4640  *
4641  * Returns: (transfer none): the #AtkObject associated with @actor
4642  */
4643 AtkObject *
4644 clutter_actor_get_accessible (ClutterActor *self)
4645 {
4646   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4647
4648   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4649 }
4650
4651 static AtkObject *
4652 clutter_actor_real_get_accessible (ClutterActor *actor)
4653 {
4654   return atk_gobject_accessible_for_object (G_OBJECT (actor));
4655 }
4656
4657 static AtkObject *
4658 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4659 {
4660   AtkObject *accessible;
4661
4662   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4663   if (accessible != NULL)
4664     g_object_ref (accessible);
4665
4666   return accessible;
4667 }
4668
4669 static void
4670 atk_implementor_iface_init (AtkImplementorIface *iface)
4671 {
4672   iface->ref_accessible = _clutter_actor_ref_accessible;
4673 }
4674
4675 static gboolean
4676 clutter_actor_real_get_paint_volume (ClutterActor       *self,
4677                                      ClutterPaintVolume *volume)
4678 {
4679   ClutterActorPrivate *priv = self->priv;
4680   ClutterActor *child;
4681   gboolean res;
4682
4683   /* this is the default return value: we cannot know if a class
4684    * is going to paint outside its allocation, so we take the
4685    * conservative approach.
4686    */
4687   res = FALSE;
4688
4689   /* we start from the allocation */
4690   clutter_paint_volume_set_from_allocation (volume, self);
4691
4692   /* if the actor has a clip set then we have a pretty definite
4693    * size for the paint volume: the actor cannot possibly paint
4694    * outside the clip region.
4695    */
4696   if (priv->clip_to_allocation)
4697     {
4698       /* the allocation has already been set, so we just flip the
4699        * return value
4700        */
4701       res = TRUE;
4702     }
4703   else if (priv->has_clip &&
4704            priv->clip.width >= 0 &&
4705            priv->clip.height >= 0)
4706     {
4707       ClutterVertex origin;
4708
4709       origin.x = priv->clip.x;
4710       origin.y = priv->clip.y;
4711       origin.z = 0;
4712
4713       clutter_paint_volume_set_origin (volume, &origin);
4714       clutter_paint_volume_set_width (volume, priv->clip.width);
4715       clutter_paint_volume_set_height (volume, priv->clip.height);
4716
4717       res = TRUE;
4718     }
4719
4720   /* if we don't have children we just bail out here... */
4721   if (priv->n_children == 0)
4722     return res;
4723
4724   /* ...but if we have children then we ask for their paint volume in
4725    * our coordinates. if any of our children replies that it doesn't
4726    * have a paint volume, we bail out
4727    */
4728   for (child = priv->first_child;
4729        child != NULL;
4730        child = child->priv->next_sibling)
4731     {
4732       const ClutterPaintVolume *child_volume;
4733
4734       child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4735       if (child_volume == NULL)
4736         {
4737           res = FALSE;
4738           break;
4739         }
4740
4741       clutter_paint_volume_union (volume, child_volume);
4742       res = TRUE;
4743     }
4744
4745   return res;
4746 }
4747
4748 static gboolean
4749 clutter_actor_real_has_overlaps (ClutterActor *self)
4750 {
4751   /* By default we'll assume that all actors need an offscreen redirect to get
4752    * the correct opacity. Actors such as ClutterTexture that would never need
4753    * an offscreen redirect can override this to return FALSE. */
4754   return TRUE;
4755 }
4756
4757 static void
4758 clutter_actor_real_destroy (ClutterActor *actor)
4759 {
4760   ClutterActorIter iter;
4761
4762   clutter_actor_iter_init (&iter, actor);
4763   while (clutter_actor_iter_next (&iter, NULL))
4764     clutter_actor_iter_destroy (&iter);
4765 }
4766
4767 static GObject *
4768 clutter_actor_constructor (GType gtype,
4769                            guint n_props,
4770                            GObjectConstructParam *props)
4771 {
4772   GObjectClass *gobject_class;
4773   ClutterActor *self;
4774   GObject *retval;
4775
4776   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
4777   retval = gobject_class->constructor (gtype, n_props, props);
4778   self = CLUTTER_ACTOR (retval);
4779
4780   if (self->priv->layout_manager == NULL)
4781     {
4782       ClutterLayoutManager *default_layout;
4783
4784       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
4785
4786       default_layout = clutter_fixed_layout_new ();
4787       clutter_actor_set_layout_manager (self, default_layout);
4788     }
4789
4790   return retval;
4791 }
4792
4793 static void
4794 clutter_actor_class_init (ClutterActorClass *klass)
4795 {
4796   GObjectClass *object_class = G_OBJECT_CLASS (klass);
4797
4798   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
4799   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
4800   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
4801
4802   object_class->constructor = clutter_actor_constructor;
4803   object_class->set_property = clutter_actor_set_property;
4804   object_class->get_property = clutter_actor_get_property;
4805   object_class->dispose = clutter_actor_dispose;
4806   object_class->finalize = clutter_actor_finalize;
4807
4808   klass->show = clutter_actor_real_show;
4809   klass->show_all = clutter_actor_show;
4810   klass->hide = clutter_actor_real_hide;
4811   klass->hide_all = clutter_actor_hide;
4812   klass->map = clutter_actor_real_map;
4813   klass->unmap = clutter_actor_real_unmap;
4814   klass->unrealize = clutter_actor_real_unrealize;
4815   klass->pick = clutter_actor_real_pick;
4816   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
4817   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
4818   klass->allocate = clutter_actor_real_allocate;
4819   klass->queue_redraw = clutter_actor_real_queue_redraw;
4820   klass->queue_relayout = clutter_actor_real_queue_relayout;
4821   klass->apply_transform = clutter_actor_real_apply_transform;
4822   klass->get_accessible = clutter_actor_real_get_accessible;
4823   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
4824   klass->has_overlaps = clutter_actor_real_has_overlaps;
4825   klass->paint = clutter_actor_real_paint;
4826   klass->destroy = clutter_actor_real_destroy;
4827
4828   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
4829
4830   /**
4831    * ClutterActor:x:
4832    *
4833    * X coordinate of the actor in pixels. If written, forces a fixed
4834    * position for the actor. If read, returns the fixed position if any,
4835    * otherwise the allocation if available, otherwise 0.
4836    */
4837   obj_props[PROP_X] =
4838     g_param_spec_float ("x",
4839                         P_("X coordinate"),
4840                         P_("X coordinate of the actor"),
4841                         -G_MAXFLOAT, G_MAXFLOAT,
4842                         0.0,
4843                         CLUTTER_PARAM_READWRITE);
4844
4845   /**
4846    * ClutterActor:y:
4847    *
4848    * Y coordinate of the actor in pixels. If written, forces a fixed
4849    * position for the actor.  If read, returns the fixed position if
4850    * any, otherwise the allocation if available, otherwise 0.
4851    */
4852   obj_props[PROP_Y] =
4853     g_param_spec_float ("y",
4854                         P_("Y coordinate"),
4855                         P_("Y coordinate of the actor"),
4856                         -G_MAXFLOAT, G_MAXFLOAT,
4857                         0.0,
4858                         CLUTTER_PARAM_READWRITE);
4859
4860   /**
4861    * ClutterActor:width:
4862    *
4863    * Width of the actor (in pixels). If written, forces the minimum and
4864    * natural size request of the actor to the given width. If read, returns
4865    * the allocated width if available, otherwise the width request.
4866    */
4867   obj_props[PROP_WIDTH] =
4868     g_param_spec_float ("width",
4869                         P_("Width"),
4870                         P_("Width of the actor"),
4871                         0.0, G_MAXFLOAT,
4872                         0.0,
4873                         CLUTTER_PARAM_READWRITE);
4874
4875   /**
4876    * ClutterActor:height:
4877    *
4878    * Height of the actor (in pixels).  If written, forces the minimum and
4879    * natural size request of the actor to the given height. If read, returns
4880    * the allocated height if available, otherwise the height request.
4881    */
4882   obj_props[PROP_HEIGHT] =
4883     g_param_spec_float ("height",
4884                         P_("Height"),
4885                         P_("Height of the actor"),
4886                         0.0, G_MAXFLOAT,
4887                         0.0,
4888                         CLUTTER_PARAM_READWRITE);
4889
4890   /**
4891    * ClutterActor:fixed-x:
4892    *
4893    * The fixed X position of the actor in pixels.
4894    *
4895    * Writing this property sets #ClutterActor:fixed-position-set
4896    * property as well, as a side effect
4897    *
4898    * Since: 0.8
4899    */
4900   obj_props[PROP_FIXED_X] =
4901     g_param_spec_float ("fixed-x",
4902                         P_("Fixed X"),
4903                         P_("Forced X position of the actor"),
4904                         -G_MAXFLOAT, G_MAXFLOAT,
4905                         0.0,
4906                         CLUTTER_PARAM_READWRITE);
4907
4908   /**
4909    * ClutterActor:fixed-y:
4910    *
4911    * The fixed Y position of the actor in pixels.
4912    *
4913    * Writing this property sets the #ClutterActor:fixed-position-set
4914    * property as well, as a side effect
4915    *
4916    * Since: 0.8
4917    */
4918   obj_props[PROP_FIXED_Y] =
4919     g_param_spec_float ("fixed-y",
4920                         P_("Fixed Y"),
4921                         P_("Forced Y position of the actor"),
4922                         -G_MAXFLOAT, G_MAXFLOAT,
4923                         0,
4924                         CLUTTER_PARAM_READWRITE);
4925
4926   /**
4927    * ClutterActor:fixed-position-set:
4928    *
4929    * This flag controls whether the #ClutterActor:fixed-x and
4930    * #ClutterActor:fixed-y properties are used
4931    *
4932    * Since: 0.8
4933    */
4934   obj_props[PROP_FIXED_POSITION_SET] =
4935     g_param_spec_boolean ("fixed-position-set",
4936                           P_("Fixed position set"),
4937                           P_("Whether to use fixed positioning for the actor"),
4938                           FALSE,
4939                           CLUTTER_PARAM_READWRITE);
4940
4941   /**
4942    * ClutterActor:min-width:
4943    *
4944    * A forced minimum width request for the actor, in pixels
4945    *
4946    * Writing this property sets the #ClutterActor:min-width-set property
4947    * as well, as a side effect.
4948    *
4949    *This property overrides the usual width request of the actor.
4950    *
4951    * Since: 0.8
4952    */
4953   obj_props[PROP_MIN_WIDTH] =
4954     g_param_spec_float ("min-width",
4955                         P_("Min Width"),
4956                         P_("Forced minimum width request for the actor"),
4957                         0.0, G_MAXFLOAT,
4958                         0.0,
4959                         CLUTTER_PARAM_READWRITE);
4960
4961   /**
4962    * ClutterActor:min-height:
4963    *
4964    * A forced minimum height request for the actor, in pixels
4965    *
4966    * Writing this property sets the #ClutterActor:min-height-set property
4967    * as well, as a side effect. This property overrides the usual height
4968    * request of the actor.
4969    *
4970    * Since: 0.8
4971    */
4972   obj_props[PROP_MIN_HEIGHT] =
4973     g_param_spec_float ("min-height",
4974                         P_("Min Height"),
4975                         P_("Forced minimum height request for the actor"),
4976                         0.0, G_MAXFLOAT,
4977                         0.0,
4978                         CLUTTER_PARAM_READWRITE);
4979
4980   /**
4981    * ClutterActor:natural-width:
4982    *
4983    * A forced natural width request for the actor, in pixels
4984    *
4985    * Writing this property sets the #ClutterActor:natural-width-set
4986    * property as well, as a side effect. This property overrides the
4987    * usual width request of the actor
4988    *
4989    * Since: 0.8
4990    */
4991   obj_props[PROP_NATURAL_WIDTH] =
4992     g_param_spec_float ("natural-width",
4993                         P_("Natural Width"),
4994                         P_("Forced natural width request for the actor"),
4995                         0.0, G_MAXFLOAT,
4996                         0.0,
4997                         CLUTTER_PARAM_READWRITE);
4998
4999   /**
5000    * ClutterActor:natural-height:
5001    *
5002    * A forced natural height request for the actor, in pixels
5003    *
5004    * Writing this property sets the #ClutterActor:natural-height-set
5005    * property as well, as a side effect. This property overrides the
5006    * usual height request of the actor
5007    *
5008    * Since: 0.8
5009    */
5010   obj_props[PROP_NATURAL_HEIGHT] =
5011     g_param_spec_float ("natural-height",
5012                         P_("Natural Height"),
5013                         P_("Forced natural height request for the actor"),
5014                         0.0, G_MAXFLOAT,
5015                         0.0,
5016                         CLUTTER_PARAM_READWRITE);
5017
5018   /**
5019    * ClutterActor:min-width-set:
5020    *
5021    * This flag controls whether the #ClutterActor:min-width property
5022    * is used
5023    *
5024    * Since: 0.8
5025    */
5026   obj_props[PROP_MIN_WIDTH_SET] =
5027     g_param_spec_boolean ("min-width-set",
5028                           P_("Minimum width set"),
5029                           P_("Whether to use the min-width property"),
5030                           FALSE,
5031                           CLUTTER_PARAM_READWRITE);
5032
5033   /**
5034    * ClutterActor:min-height-set:
5035    *
5036    * This flag controls whether the #ClutterActor:min-height property
5037    * is used
5038    *
5039    * Since: 0.8
5040    */
5041   obj_props[PROP_MIN_HEIGHT_SET] =
5042     g_param_spec_boolean ("min-height-set",
5043                           P_("Minimum height set"),
5044                           P_("Whether to use the min-height property"),
5045                           FALSE,
5046                           CLUTTER_PARAM_READWRITE);
5047
5048   /**
5049    * ClutterActor:natural-width-set:
5050    *
5051    * This flag controls whether the #ClutterActor:natural-width property
5052    * is used
5053    *
5054    * Since: 0.8
5055    */
5056   obj_props[PROP_NATURAL_WIDTH_SET] =
5057     g_param_spec_boolean ("natural-width-set",
5058                           P_("Natural width set"),
5059                           P_("Whether to use the natural-width property"),
5060                           FALSE,
5061                           CLUTTER_PARAM_READWRITE);
5062
5063   /**
5064    * ClutterActor:natural-height-set:
5065    *
5066    * This flag controls whether the #ClutterActor:natural-height property
5067    * is used
5068    *
5069    * Since: 0.8
5070    */
5071   obj_props[PROP_NATURAL_HEIGHT_SET] =
5072     g_param_spec_boolean ("natural-height-set",
5073                           P_("Natural height set"),
5074                           P_("Whether to use the natural-height property"),
5075                           FALSE,
5076                           CLUTTER_PARAM_READWRITE);
5077
5078   /**
5079    * ClutterActor:allocation:
5080    *
5081    * The allocation for the actor, in pixels
5082    *
5083    * This is property is read-only, but you might monitor it to know when an
5084    * actor moves or resizes
5085    *
5086    * Since: 0.8
5087    */
5088   obj_props[PROP_ALLOCATION] =
5089     g_param_spec_boxed ("allocation",
5090                         P_("Allocation"),
5091                         P_("The actor's allocation"),
5092                         CLUTTER_TYPE_ACTOR_BOX,
5093                         CLUTTER_PARAM_READABLE);
5094
5095   /**
5096    * ClutterActor:request-mode:
5097    *
5098    * Request mode for the #ClutterActor. The request mode determines the
5099    * type of geometry management used by the actor, either height for width
5100    * (the default) or width for height.
5101    *
5102    * For actors implementing height for width, the parent container should get
5103    * the preferred width first, and then the preferred height for that width.
5104    *
5105    * For actors implementing width for height, the parent container should get
5106    * the preferred height first, and then the preferred width for that height.
5107    *
5108    * For instance:
5109    *
5110    * |[
5111    *   ClutterRequestMode mode;
5112    *   gfloat natural_width, min_width;
5113    *   gfloat natural_height, min_height;
5114    *
5115    *   mode = clutter_actor_get_request_mode (child);
5116    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5117    *     {
5118    *       clutter_actor_get_preferred_width (child, -1,
5119    *                                          &amp;min_width,
5120    *                                          &amp;natural_width);
5121    *       clutter_actor_get_preferred_height (child, natural_width,
5122    *                                           &amp;min_height,
5123    *                                           &amp;natural_height);
5124    *     }
5125    *   else
5126    *     {
5127    *       clutter_actor_get_preferred_height (child, -1,
5128    *                                           &amp;min_height,
5129    *                                           &amp;natural_height);
5130    *       clutter_actor_get_preferred_width (child, natural_height,
5131    *                                          &amp;min_width,
5132    *                                          &amp;natural_width);
5133    *     }
5134    * ]|
5135    *
5136    * will retrieve the minimum and natural width and height depending on the
5137    * preferred request mode of the #ClutterActor "child".
5138    *
5139    * The clutter_actor_get_preferred_size() function will implement this
5140    * check for you.
5141    *
5142    * Since: 0.8
5143    */
5144   obj_props[PROP_REQUEST_MODE] =
5145     g_param_spec_enum ("request-mode",
5146                        P_("Request Mode"),
5147                        P_("The actor's request mode"),
5148                        CLUTTER_TYPE_REQUEST_MODE,
5149                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5150                        CLUTTER_PARAM_READWRITE);
5151
5152   /**
5153    * ClutterActor:depth:
5154    *
5155    * The position of the actor on the Z axis
5156    *
5157    * Since: 0.6
5158    */
5159   obj_props[PROP_DEPTH] =
5160     g_param_spec_float ("depth",
5161                         P_("Depth"),
5162                         P_("Position on the Z axis"),
5163                         -G_MAXFLOAT, G_MAXFLOAT,
5164                         0.0,
5165                         CLUTTER_PARAM_READWRITE);
5166
5167   /**
5168    * ClutterActor:opacity:
5169    *
5170    * Opacity of an actor, between 0 (fully transparent) and
5171    * 255 (fully opaque)
5172    */
5173   obj_props[PROP_OPACITY] =
5174     g_param_spec_uint ("opacity",
5175                        P_("Opacity"),
5176                        P_("Opacity of an actor"),
5177                        0, 255,
5178                        255,
5179                        CLUTTER_PARAM_READWRITE);
5180
5181   /**
5182    * ClutterActor:offscreen-redirect:
5183    *
5184    * Determines the conditions in which the actor will be redirected
5185    * to an offscreen framebuffer while being painted. For example this
5186    * can be used to cache an actor in a framebuffer or for improved
5187    * handling of transparent actors. See
5188    * clutter_actor_set_offscreen_redirect() for details.
5189    *
5190    * Since: 1.8
5191    */
5192   obj_props[PROP_OFFSCREEN_REDIRECT] =
5193     g_param_spec_flags ("offscreen-redirect",
5194                         P_("Offscreen redirect"),
5195                         P_("Flags controlling when to flatten the actor into a single image"),
5196                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5197                         0,
5198                         CLUTTER_PARAM_READWRITE);
5199
5200   /**
5201    * ClutterActor:visible:
5202    *
5203    * Whether the actor is set to be visible or not
5204    *
5205    * See also #ClutterActor:mapped
5206    */
5207   obj_props[PROP_VISIBLE] =
5208     g_param_spec_boolean ("visible",
5209                           P_("Visible"),
5210                           P_("Whether the actor is visible or not"),
5211                           FALSE,
5212                           CLUTTER_PARAM_READWRITE);
5213
5214   /**
5215    * ClutterActor:mapped:
5216    *
5217    * Whether the actor is mapped (will be painted when the stage
5218    * to which it belongs is mapped)
5219    *
5220    * Since: 1.0
5221    */
5222   obj_props[PROP_MAPPED] =
5223     g_param_spec_boolean ("mapped",
5224                           P_("Mapped"),
5225                           P_("Whether the actor will be painted"),
5226                           FALSE,
5227                           CLUTTER_PARAM_READABLE);
5228
5229   /**
5230    * ClutterActor:realized:
5231    *
5232    * Whether the actor has been realized
5233    *
5234    * Since: 1.0
5235    */
5236   obj_props[PROP_REALIZED] =
5237     g_param_spec_boolean ("realized",
5238                           P_("Realized"),
5239                           P_("Whether the actor has been realized"),
5240                           FALSE,
5241                           CLUTTER_PARAM_READABLE);
5242
5243   /**
5244    * ClutterActor:reactive:
5245    *
5246    * Whether the actor is reactive to events or not
5247    *
5248    * Only reactive actors will emit event-related signals
5249    *
5250    * Since: 0.6
5251    */
5252   obj_props[PROP_REACTIVE] =
5253     g_param_spec_boolean ("reactive",
5254                           P_("Reactive"),
5255                           P_("Whether the actor is reactive to events"),
5256                           FALSE,
5257                           CLUTTER_PARAM_READWRITE);
5258
5259   /**
5260    * ClutterActor:has-clip:
5261    *
5262    * Whether the actor has the #ClutterActor:clip property set or not
5263    */
5264   obj_props[PROP_HAS_CLIP] =
5265     g_param_spec_boolean ("has-clip",
5266                           P_("Has Clip"),
5267                           P_("Whether the actor has a clip set"),
5268                           FALSE,
5269                           CLUTTER_PARAM_READABLE);
5270
5271   /**
5272    * ClutterActor:clip:
5273    *
5274    * The clip region for the actor, in actor-relative coordinates
5275    *
5276    * Every part of the actor outside the clip region will not be
5277    * painted
5278    */
5279   obj_props[PROP_CLIP] =
5280     g_param_spec_boxed ("clip",
5281                         P_("Clip"),
5282                         P_("The clip region for the actor"),
5283                         CLUTTER_TYPE_GEOMETRY,
5284                         CLUTTER_PARAM_READWRITE);
5285
5286   /**
5287    * ClutterActor:name:
5288    *
5289    * The name of the actor
5290    *
5291    * Since: 0.2
5292    */
5293   obj_props[PROP_NAME] =
5294     g_param_spec_string ("name",
5295                          P_("Name"),
5296                          P_("Name of the actor"),
5297                          NULL,
5298                          CLUTTER_PARAM_READWRITE);
5299
5300   /**
5301    * ClutterActor:scale-x:
5302    *
5303    * The horizontal scale of the actor
5304    *
5305    * Since: 0.6
5306    */
5307   obj_props[PROP_SCALE_X] =
5308     g_param_spec_double ("scale-x",
5309                          P_("Scale X"),
5310                          P_("Scale factor on the X axis"),
5311                          0.0, G_MAXDOUBLE,
5312                          1.0,
5313                          CLUTTER_PARAM_READWRITE);
5314
5315   /**
5316    * ClutterActor:scale-y:
5317    *
5318    * The vertical scale of the actor
5319    *
5320    * Since: 0.6
5321    */
5322   obj_props[PROP_SCALE_Y] =
5323     g_param_spec_double ("scale-y",
5324                          P_("Scale Y"),
5325                          P_("Scale factor on the Y axis"),
5326                          0.0, G_MAXDOUBLE,
5327                          1.0,
5328                          CLUTTER_PARAM_READWRITE);
5329
5330   /**
5331    * ClutterActor:scale-center-x:
5332    *
5333    * The horizontal center point for scaling
5334    *
5335    * Since: 1.0
5336    */
5337   obj_props[PROP_SCALE_CENTER_X] =
5338     g_param_spec_float ("scale-center-x",
5339                         P_("Scale Center X"),
5340                         P_("Horizontal scale center"),
5341                         -G_MAXFLOAT, G_MAXFLOAT,
5342                         0.0,
5343                         CLUTTER_PARAM_READWRITE);
5344
5345   /**
5346    * ClutterActor:scale-center-y:
5347    *
5348    * The vertical center point for scaling
5349    *
5350    * Since: 1.0
5351    */
5352   obj_props[PROP_SCALE_CENTER_Y] =
5353     g_param_spec_float ("scale-center-y",
5354                         P_("Scale Center Y"),
5355                         P_("Vertical scale center"),
5356                         -G_MAXFLOAT, G_MAXFLOAT,
5357                         0.0,
5358                         CLUTTER_PARAM_READWRITE);
5359
5360   /**
5361    * ClutterActor:scale-gravity:
5362    *
5363    * The center point for scaling expressed as a #ClutterGravity
5364    *
5365    * Since: 1.0
5366    */
5367   obj_props[PROP_SCALE_GRAVITY] =
5368     g_param_spec_enum ("scale-gravity",
5369                        P_("Scale Gravity"),
5370                        P_("The center of scaling"),
5371                        CLUTTER_TYPE_GRAVITY,
5372                        CLUTTER_GRAVITY_NONE,
5373                        CLUTTER_PARAM_READWRITE);
5374
5375   /**
5376    * ClutterActor:rotation-angle-x:
5377    *
5378    * The rotation angle on the X axis
5379    *
5380    * Since: 0.6
5381    */
5382   obj_props[PROP_ROTATION_ANGLE_X] =
5383     g_param_spec_double ("rotation-angle-x",
5384                          P_("Rotation Angle X"),
5385                          P_("The rotation angle on the X axis"),
5386                          -G_MAXDOUBLE, G_MAXDOUBLE,
5387                          0.0,
5388                          CLUTTER_PARAM_READWRITE);
5389
5390   /**
5391    * ClutterActor:rotation-angle-y:
5392    *
5393    * The rotation angle on the Y axis
5394    *
5395    * Since: 0.6
5396    */
5397   obj_props[PROP_ROTATION_ANGLE_Y] =
5398     g_param_spec_double ("rotation-angle-y",
5399                          P_("Rotation Angle Y"),
5400                          P_("The rotation angle on the Y axis"),
5401                          -G_MAXDOUBLE, G_MAXDOUBLE,
5402                          0.0,
5403                          CLUTTER_PARAM_READWRITE);
5404
5405   /**
5406    * ClutterActor:rotation-angle-z:
5407    *
5408    * The rotation angle on the Z axis
5409    *
5410    * Since: 0.6
5411    */
5412   obj_props[PROP_ROTATION_ANGLE_Z] =
5413     g_param_spec_double ("rotation-angle-z",
5414                          P_("Rotation Angle Z"),
5415                          P_("The rotation angle on the Z axis"),
5416                          -G_MAXDOUBLE, G_MAXDOUBLE,
5417                          0.0,
5418                          CLUTTER_PARAM_READWRITE);
5419
5420   /**
5421    * ClutterActor:rotation-center-x:
5422    *
5423    * The rotation center on the X axis.
5424    *
5425    * Since: 0.6
5426    */
5427   obj_props[PROP_ROTATION_CENTER_X] =
5428     g_param_spec_boxed ("rotation-center-x",
5429                         P_("Rotation Center X"),
5430                         P_("The rotation center on the X axis"),
5431                         CLUTTER_TYPE_VERTEX,
5432                         CLUTTER_PARAM_READWRITE);
5433
5434   /**
5435    * ClutterActor:rotation-center-y:
5436    *
5437    * The rotation center on the Y axis.
5438    *
5439    * Since: 0.6
5440    */
5441   obj_props[PROP_ROTATION_CENTER_Y] =
5442     g_param_spec_boxed ("rotation-center-y",
5443                         P_("Rotation Center Y"),
5444                         P_("The rotation center on the Y axis"),
5445                         CLUTTER_TYPE_VERTEX,
5446                         CLUTTER_PARAM_READWRITE);
5447
5448   /**
5449    * ClutterActor:rotation-center-z:
5450    *
5451    * The rotation center on the Z axis.
5452    *
5453    * Since: 0.6
5454    */
5455   obj_props[PROP_ROTATION_CENTER_Z] =
5456     g_param_spec_boxed ("rotation-center-z",
5457                         P_("Rotation Center Z"),
5458                         P_("The rotation center on the Z axis"),
5459                         CLUTTER_TYPE_VERTEX,
5460                         CLUTTER_PARAM_READWRITE);
5461
5462   /**
5463    * ClutterActor:rotation-center-z-gravity:
5464    *
5465    * The rotation center on the Z axis expressed as a #ClutterGravity.
5466    *
5467    * Since: 1.0
5468    */
5469   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5470     g_param_spec_enum ("rotation-center-z-gravity",
5471                        P_("Rotation Center Z Gravity"),
5472                        P_("Center point for rotation around the Z axis"),
5473                        CLUTTER_TYPE_GRAVITY,
5474                        CLUTTER_GRAVITY_NONE,
5475                        CLUTTER_PARAM_READWRITE);
5476
5477   /**
5478    * ClutterActor:anchor-x:
5479    *
5480    * The X coordinate of an actor's anchor point, relative to
5481    * the actor coordinate space, in pixels
5482    *
5483    * Since: 0.8
5484    */
5485   obj_props[PROP_ANCHOR_X] =
5486     g_param_spec_float ("anchor-x",
5487                         P_("Anchor X"),
5488                         P_("X coordinate of the anchor point"),
5489                         -G_MAXFLOAT, G_MAXFLOAT,
5490                         0,
5491                         CLUTTER_PARAM_READWRITE);
5492
5493   /**
5494    * ClutterActor:anchor-y:
5495    *
5496    * The Y coordinate of an actor's anchor point, relative to
5497    * the actor coordinate space, in pixels
5498    *
5499    * Since: 0.8
5500    */
5501   obj_props[PROP_ANCHOR_Y] =
5502     g_param_spec_float ("anchor-y",
5503                         P_("Anchor Y"),
5504                         P_("Y coordinate of the anchor point"),
5505                         -G_MAXFLOAT, G_MAXFLOAT,
5506                         0,
5507                         CLUTTER_PARAM_READWRITE);
5508
5509   /**
5510    * ClutterActor:anchor-gravity:
5511    *
5512    * The anchor point expressed as a #ClutterGravity
5513    *
5514    * Since: 1.0
5515    */
5516   obj_props[PROP_ANCHOR_GRAVITY] =
5517     g_param_spec_enum ("anchor-gravity",
5518                        P_("Anchor Gravity"),
5519                        P_("The anchor point as a ClutterGravity"),
5520                        CLUTTER_TYPE_GRAVITY,
5521                        CLUTTER_GRAVITY_NONE,
5522                        CLUTTER_PARAM_READWRITE);
5523
5524   /**
5525    * ClutterActor:show-on-set-parent:
5526    *
5527    * If %TRUE, the actor is automatically shown when parented.
5528    *
5529    * Calling clutter_actor_hide() on an actor which has not been
5530    * parented will set this property to %FALSE as a side effect.
5531    *
5532    * Since: 0.8
5533    */
5534   obj_props[PROP_SHOW_ON_SET_PARENT] =
5535     g_param_spec_boolean ("show-on-set-parent",
5536                           P_("Show on set parent"),
5537                           P_("Whether the actor is shown when parented"),
5538                           TRUE,
5539                           CLUTTER_PARAM_READWRITE);
5540
5541   /**
5542    * ClutterActor:clip-to-allocation:
5543    *
5544    * Whether the clip region should track the allocated area
5545    * of the actor.
5546    *
5547    * This property is ignored if a clip area has been explicitly
5548    * set using clutter_actor_set_clip().
5549    *
5550    * Since: 1.0
5551    */
5552   obj_props[PROP_CLIP_TO_ALLOCATION] =
5553     g_param_spec_boolean ("clip-to-allocation",
5554                           P_("Clip to Allocation"),
5555                           P_("Sets the clip region to track the actor's allocation"),
5556                           FALSE,
5557                           CLUTTER_PARAM_READWRITE);
5558
5559   /**
5560    * ClutterActor:text-direction:
5561    *
5562    * The direction of the text inside a #ClutterActor.
5563    *
5564    * Since: 1.0
5565    */
5566   obj_props[PROP_TEXT_DIRECTION] =
5567     g_param_spec_enum ("text-direction",
5568                        P_("Text Direction"),
5569                        P_("Direction of the text"),
5570                        CLUTTER_TYPE_TEXT_DIRECTION,
5571                        CLUTTER_TEXT_DIRECTION_LTR,
5572                        CLUTTER_PARAM_READWRITE);
5573
5574   /**
5575    * ClutterActor:has-pointer:
5576    *
5577    * Whether the actor contains the pointer of a #ClutterInputDevice
5578    * or not.
5579    *
5580    * Since: 1.2
5581    */
5582   obj_props[PROP_HAS_POINTER] =
5583     g_param_spec_boolean ("has-pointer",
5584                           P_("Has Pointer"),
5585                           P_("Whether the actor contains the pointer of an input device"),
5586                           FALSE,
5587                           CLUTTER_PARAM_READABLE);
5588
5589   /**
5590    * ClutterActor:actions:
5591    *
5592    * Adds a #ClutterAction to the actor
5593    *
5594    * Since: 1.4
5595    */
5596   obj_props[PROP_ACTIONS] =
5597     g_param_spec_object ("actions",
5598                          P_("Actions"),
5599                          P_("Adds an action to the actor"),
5600                          CLUTTER_TYPE_ACTION,
5601                          CLUTTER_PARAM_WRITABLE);
5602
5603   /**
5604    * ClutterActor:constraints:
5605    *
5606    * Adds a #ClutterConstraint to the actor
5607    *
5608    * Since: 1.4
5609    */
5610   obj_props[PROP_CONSTRAINTS] =
5611     g_param_spec_object ("constraints",
5612                          P_("Constraints"),
5613                          P_("Adds a constraint to the actor"),
5614                          CLUTTER_TYPE_CONSTRAINT,
5615                          CLUTTER_PARAM_WRITABLE);
5616
5617   /**
5618    * ClutterActor:effect:
5619    *
5620    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
5621    *
5622    * Since: 1.4
5623    */
5624   obj_props[PROP_EFFECT] =
5625     g_param_spec_object ("effect",
5626                          P_("Effect"),
5627                          P_("Add an effect to be applied on the actor"),
5628                          CLUTTER_TYPE_EFFECT,
5629                          CLUTTER_PARAM_WRITABLE);
5630
5631   /**
5632    * ClutterActor:layout-manager:
5633    *
5634    * A delegate object for controlling the layout of the children of
5635    * an actor.
5636    *
5637    * Since: 1.10
5638    */
5639   obj_props[PROP_LAYOUT_MANAGER] =
5640     g_param_spec_object ("layout-manager",
5641                          P_("Layout Manager"),
5642                          P_("The object controlling the layout of an actor's children"),
5643                          CLUTTER_TYPE_LAYOUT_MANAGER,
5644                          CLUTTER_PARAM_READWRITE);
5645
5646
5647   /**
5648    * ClutterActor:x-align:
5649    *
5650    * The alignment of an actor on the X axis, if the actor has been given
5651    * extra space for its allocation.
5652    *
5653    * Since: 1.10
5654    */
5655   obj_props[PROP_X_ALIGN] =
5656     g_param_spec_enum ("x-align",
5657                        P_("X Alignment"),
5658                        P_("The alignment of the actor on the X axis within its allocation"),
5659                        CLUTTER_TYPE_ACTOR_ALIGN,
5660                        CLUTTER_ACTOR_ALIGN_FILL,
5661                        CLUTTER_PARAM_READWRITE);
5662
5663   /**
5664    * ClutterActor:y-align:
5665    *
5666    * The alignment of an actor on the Y axis, if the actor has been given
5667    * extra space for its allocation.
5668    *
5669    * Since: 1.10
5670    */
5671   obj_props[PROP_Y_ALIGN] =
5672     g_param_spec_enum ("y-align",
5673                        P_("Y Alignment"),
5674                        P_("The alignment of the actor on the Y axis within its allocation"),
5675                        CLUTTER_TYPE_ACTOR_ALIGN,
5676                        CLUTTER_ACTOR_ALIGN_FILL,
5677                        CLUTTER_PARAM_READWRITE);
5678
5679   /**
5680    * ClutterActor:margin-top:
5681    *
5682    * The margin (in pixels) from the top of the actor.
5683    *
5684    * This property adds a margin to the actor's preferred size; the margin
5685    * will be automatically taken into account when allocating the actor.
5686    *
5687    * Since: 1.10
5688    */
5689   obj_props[PROP_MARGIN_TOP] =
5690     g_param_spec_float ("margin-top",
5691                         P_("Margin Top"),
5692                         P_("Extra space at the top"),
5693                         0.0, G_MAXFLOAT,
5694                         0.0,
5695                         CLUTTER_PARAM_READWRITE);
5696
5697   /**
5698    * ClutterActor:margin-bottom:
5699    *
5700    * The margin (in pixels) from the bottom of the actor.
5701    *
5702    * This property adds a margin to the actor's preferred size; the margin
5703    * will be automatically taken into account when allocating the actor.
5704    *
5705    * Since: 1.10
5706    */
5707   obj_props[PROP_MARGIN_BOTTOM] =
5708     g_param_spec_float ("margin-bottom",
5709                         P_("Margin Bottom"),
5710                         P_("Extra space at the bottom"),
5711                         0.0, G_MAXFLOAT,
5712                         0.0,
5713                         CLUTTER_PARAM_READWRITE);
5714
5715   /**
5716    * ClutterActor:margin-left:
5717    *
5718    * The margin (in pixels) from the left of the actor.
5719    *
5720    * This property adds a margin to the actor's preferred size; the margin
5721    * will be automatically taken into account when allocating the actor.
5722    *
5723    * Since: 1.10
5724    */
5725   obj_props[PROP_MARGIN_LEFT] =
5726     g_param_spec_float ("margin-left",
5727                         P_("Margin Left"),
5728                         P_("Extra space at the left"),
5729                         0.0, G_MAXFLOAT,
5730                         0.0,
5731                         CLUTTER_PARAM_READWRITE);
5732
5733   /**
5734    * ClutterActor:margin-right:
5735    *
5736    * The margin (in pixels) from the right of the actor.
5737    *
5738    * This property adds a margin to the actor's preferred size; the margin
5739    * will be automatically taken into account when allocating the actor.
5740    *
5741    * Since: 1.10
5742    */
5743   obj_props[PROP_MARGIN_RIGHT] =
5744     g_param_spec_float ("margin-right",
5745                         P_("Margin Right"),
5746                         P_("Extra space at the right"),
5747                         0.0, G_MAXFLOAT,
5748                         0.0,
5749                         CLUTTER_PARAM_READWRITE);
5750
5751   /**
5752    * ClutterActor:background-color-set:
5753    *
5754    * Whether the #ClutterActor:background-color property has been set.
5755    *
5756    * Since: 1.10
5757    */
5758   obj_props[PROP_BACKGROUND_COLOR_SET] =
5759     g_param_spec_boolean ("background-color-set",
5760                           P_("Background Color Set"),
5761                           P_("Whether the background color is set"),
5762                           FALSE,
5763                           CLUTTER_PARAM_READABLE);
5764
5765   /**
5766    * ClutterActor:background-color:
5767    *
5768    * Paints a solid fill of the actor's allocation using the specified
5769    * color.
5770    *
5771    * Since: 1.10
5772    */
5773   obj_props[PROP_BACKGROUND_COLOR] =
5774     clutter_param_spec_color ("background-color",
5775                               P_("Background color"),
5776                               P_("The actor's background color"),
5777                               CLUTTER_COLOR_Transparent,
5778                               CLUTTER_PARAM_READWRITE);
5779
5780   /**
5781    * ClutterActor:first-child:
5782    *
5783    * The actor's first child.
5784    *
5785    * Since: 1.10
5786    */
5787   obj_props[PROP_FIRST_CHILD] =
5788     g_param_spec_object ("first-child",
5789                          P_("First Child"),
5790                          P_("The actor's first child"),
5791                          CLUTTER_TYPE_ACTOR,
5792                          CLUTTER_PARAM_READABLE);
5793
5794   /**
5795    * ClutterActor:last-child:
5796    *
5797    * The actor's last child.
5798    *
5799    * Since: 1.10
5800    */
5801   obj_props[PROP_LAST_CHILD] =
5802     g_param_spec_object ("last-child",
5803                          P_("Last Child"),
5804                          P_("The actor's last child"),
5805                          CLUTTER_TYPE_ACTOR,
5806                          CLUTTER_PARAM_READABLE);
5807
5808   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
5809
5810   /**
5811    * ClutterActor::destroy:
5812    * @actor: the #ClutterActor which emitted the signal
5813    *
5814    * The ::destroy signal notifies that all references held on the
5815    * actor which emitted it should be released.
5816    *
5817    * The ::destroy signal should be used by all holders of a reference
5818    * on @actor.
5819    *
5820    * This signal might result in the finalization of the #ClutterActor
5821    * if all references are released.
5822    *
5823    * Composite actors and actors implementing the #ClutterContainer
5824    * interface should override the default implementation of the
5825    * class handler of this signal and call clutter_actor_destroy() on
5826    * their children. When overriding the default class handler, it is
5827    * required to chain up to the parent's implementation.
5828    *
5829    * Since: 0.2
5830    */
5831   actor_signals[DESTROY] =
5832     g_signal_new (I_("destroy"),
5833                   G_TYPE_FROM_CLASS (object_class),
5834                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
5835                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
5836                   NULL, NULL,
5837                   _clutter_marshal_VOID__VOID,
5838                   G_TYPE_NONE, 0);
5839   /**
5840    * ClutterActor::show:
5841    * @actor: the object which received the signal
5842    *
5843    * The ::show signal is emitted when an actor is visible and
5844    * rendered on the stage.
5845    *
5846    * Since: 0.2
5847    */
5848   actor_signals[SHOW] =
5849     g_signal_new (I_("show"),
5850                   G_TYPE_FROM_CLASS (object_class),
5851                   G_SIGNAL_RUN_FIRST,
5852                   G_STRUCT_OFFSET (ClutterActorClass, show),
5853                   NULL, NULL,
5854                   _clutter_marshal_VOID__VOID,
5855                   G_TYPE_NONE, 0);
5856   /**
5857    * ClutterActor::hide:
5858    * @actor: the object which received the signal
5859    *
5860    * The ::hide signal is emitted when an actor is no longer rendered
5861    * on the stage.
5862    *
5863    * Since: 0.2
5864    */
5865   actor_signals[HIDE] =
5866     g_signal_new (I_("hide"),
5867                   G_TYPE_FROM_CLASS (object_class),
5868                   G_SIGNAL_RUN_FIRST,
5869                   G_STRUCT_OFFSET (ClutterActorClass, hide),
5870                   NULL, NULL,
5871                   _clutter_marshal_VOID__VOID,
5872                   G_TYPE_NONE, 0);
5873   /**
5874    * ClutterActor::parent-set:
5875    * @actor: the object which received the signal
5876    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
5877    *
5878    * This signal is emitted when the parent of the actor changes.
5879    *
5880    * Since: 0.2
5881    */
5882   actor_signals[PARENT_SET] =
5883     g_signal_new (I_("parent-set"),
5884                   G_TYPE_FROM_CLASS (object_class),
5885                   G_SIGNAL_RUN_LAST,
5886                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
5887                   NULL, NULL,
5888                   _clutter_marshal_VOID__OBJECT,
5889                   G_TYPE_NONE, 1,
5890                   CLUTTER_TYPE_ACTOR);
5891
5892   /**
5893    * ClutterActor::queue-redraw:
5894    * @actor: the actor we're bubbling the redraw request through
5895    * @origin: the actor which initiated the redraw request
5896    *
5897    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
5898    * is called on @origin.
5899    *
5900    * The default implementation for #ClutterActor chains up to the
5901    * parent actor and queues a redraw on the parent, thus "bubbling"
5902    * the redraw queue up through the actor graph. The default
5903    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
5904    * in a main loop idle handler.
5905    *
5906    * Note that the @origin actor may be the stage, or a container; it
5907    * does not have to be a leaf node in the actor graph.
5908    *
5909    * Toolkits embedding a #ClutterStage which require a redraw and
5910    * relayout cycle can stop the emission of this signal using the
5911    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
5912    * themselves, like:
5913    *
5914    * |[
5915    *   static void
5916    *   on_redraw_complete (gpointer data)
5917    *   {
5918    *     ClutterStage *stage = data;
5919    *
5920    *     /&ast; execute the Clutter drawing pipeline &ast;/
5921    *     clutter_stage_ensure_redraw (stage);
5922    *   }
5923    *
5924    *   static void
5925    *   on_stage_queue_redraw (ClutterStage *stage)
5926    *   {
5927    *     /&ast; this prevents the default handler to run &ast;/
5928    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
5929    *
5930    *     /&ast; queue a redraw with the host toolkit and call
5931    *      &ast; a function when the redraw has been completed
5932    *      &ast;/
5933    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
5934    *   }
5935    * ]|
5936    *
5937    * <note><para>This signal is emitted before the Clutter paint
5938    * pipeline is executed. If you want to know when the pipeline has
5939    * been completed you should connect to the ::paint signal on the
5940    * Stage with g_signal_connect_after().</para></note>
5941    *
5942    * Since: 1.0
5943    */
5944   actor_signals[QUEUE_REDRAW] =
5945     g_signal_new (I_("queue-redraw"),
5946                   G_TYPE_FROM_CLASS (object_class),
5947                   G_SIGNAL_RUN_LAST,
5948                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
5949                   NULL, NULL,
5950                   _clutter_marshal_VOID__OBJECT,
5951                   G_TYPE_NONE, 1,
5952                   CLUTTER_TYPE_ACTOR);
5953
5954   /**
5955    * ClutterActor::queue-relayout
5956    * @actor: the actor being queued for relayout
5957    *
5958    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
5959    * is called on an actor.
5960    *
5961    * The default implementation for #ClutterActor chains up to the
5962    * parent actor and queues a relayout on the parent, thus "bubbling"
5963    * the relayout queue up through the actor graph.
5964    *
5965    * The main purpose of this signal is to allow relayout to be propagated
5966    * properly in the procense of #ClutterClone actors. Applications will
5967    * not normally need to connect to this signal.
5968    *
5969    * Since: 1.2
5970    */
5971   actor_signals[QUEUE_RELAYOUT] =
5972     g_signal_new (I_("queue-relayout"),
5973                   G_TYPE_FROM_CLASS (object_class),
5974                   G_SIGNAL_RUN_LAST,
5975                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
5976                   NULL, NULL,
5977                   _clutter_marshal_VOID__VOID,
5978                   G_TYPE_NONE, 0);
5979
5980   /**
5981    * ClutterActor::event:
5982    * @actor: the actor which received the event
5983    * @event: a #ClutterEvent
5984    *
5985    * The ::event signal is emitted each time an event is received
5986    * by the @actor. This signal will be emitted on every actor,
5987    * following the hierarchy chain, until it reaches the top-level
5988    * container (the #ClutterStage).
5989    *
5990    * Return value: %TRUE if the event has been handled by the actor,
5991    *   or %FALSE to continue the emission.
5992    *
5993    * Since: 0.6
5994    */
5995   actor_signals[EVENT] =
5996     g_signal_new (I_("event"),
5997                   G_TYPE_FROM_CLASS (object_class),
5998                   G_SIGNAL_RUN_LAST,
5999                   G_STRUCT_OFFSET (ClutterActorClass, event),
6000                   _clutter_boolean_handled_accumulator, NULL,
6001                   _clutter_marshal_BOOLEAN__BOXED,
6002                   G_TYPE_BOOLEAN, 1,
6003                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6004   /**
6005    * ClutterActor::button-press-event:
6006    * @actor: the actor which received the event
6007    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6008    *
6009    * The ::button-press-event signal is emitted each time a mouse button
6010    * is pressed on @actor.
6011    *
6012    * Return value: %TRUE if the event has been handled by the actor,
6013    *   or %FALSE to continue the emission.
6014    *
6015    * Since: 0.6
6016    */
6017   actor_signals[BUTTON_PRESS_EVENT] =
6018     g_signal_new (I_("button-press-event"),
6019                   G_TYPE_FROM_CLASS (object_class),
6020                   G_SIGNAL_RUN_LAST,
6021                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6022                   _clutter_boolean_handled_accumulator, NULL,
6023                   _clutter_marshal_BOOLEAN__BOXED,
6024                   G_TYPE_BOOLEAN, 1,
6025                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6026   /**
6027    * ClutterActor::button-release-event:
6028    * @actor: the actor which received the event
6029    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6030    *
6031    * The ::button-release-event signal is emitted each time a mouse button
6032    * is released on @actor.
6033    *
6034    * Return value: %TRUE if the event has been handled by the actor,
6035    *   or %FALSE to continue the emission.
6036    *
6037    * Since: 0.6
6038    */
6039   actor_signals[BUTTON_RELEASE_EVENT] =
6040     g_signal_new (I_("button-release-event"),
6041                   G_TYPE_FROM_CLASS (object_class),
6042                   G_SIGNAL_RUN_LAST,
6043                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6044                   _clutter_boolean_handled_accumulator, NULL,
6045                   _clutter_marshal_BOOLEAN__BOXED,
6046                   G_TYPE_BOOLEAN, 1,
6047                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6048   /**
6049    * ClutterActor::scroll-event:
6050    * @actor: the actor which received the event
6051    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6052    *
6053    * The ::scroll-event signal is emitted each time the mouse is
6054    * scrolled on @actor
6055    *
6056    * Return value: %TRUE if the event has been handled by the actor,
6057    *   or %FALSE to continue the emission.
6058    *
6059    * Since: 0.6
6060    */
6061   actor_signals[SCROLL_EVENT] =
6062     g_signal_new (I_("scroll-event"),
6063                   G_TYPE_FROM_CLASS (object_class),
6064                   G_SIGNAL_RUN_LAST,
6065                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6066                   _clutter_boolean_handled_accumulator, NULL,
6067                   _clutter_marshal_BOOLEAN__BOXED,
6068                   G_TYPE_BOOLEAN, 1,
6069                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6070   /**
6071    * ClutterActor::key-press-event:
6072    * @actor: the actor which received the event
6073    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6074    *
6075    * The ::key-press-event signal is emitted each time a keyboard button
6076    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6077    *
6078    * Return value: %TRUE if the event has been handled by the actor,
6079    *   or %FALSE to continue the emission.
6080    *
6081    * Since: 0.6
6082    */
6083   actor_signals[KEY_PRESS_EVENT] =
6084     g_signal_new (I_("key-press-event"),
6085                   G_TYPE_FROM_CLASS (object_class),
6086                   G_SIGNAL_RUN_LAST,
6087                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6088                   _clutter_boolean_handled_accumulator, NULL,
6089                   _clutter_marshal_BOOLEAN__BOXED,
6090                   G_TYPE_BOOLEAN, 1,
6091                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6092   /**
6093    * ClutterActor::key-release-event:
6094    * @actor: the actor which received the event
6095    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6096    *
6097    * The ::key-release-event signal is emitted each time a keyboard button
6098    * is released while @actor has key focus (see
6099    * clutter_stage_set_key_focus()).
6100    *
6101    * Return value: %TRUE if the event has been handled by the actor,
6102    *   or %FALSE to continue the emission.
6103    *
6104    * Since: 0.6
6105    */
6106   actor_signals[KEY_RELEASE_EVENT] =
6107     g_signal_new (I_("key-release-event"),
6108                   G_TYPE_FROM_CLASS (object_class),
6109                   G_SIGNAL_RUN_LAST,
6110                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6111                   _clutter_boolean_handled_accumulator, NULL,
6112                   _clutter_marshal_BOOLEAN__BOXED,
6113                   G_TYPE_BOOLEAN, 1,
6114                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6115   /**
6116    * ClutterActor::motion-event:
6117    * @actor: the actor which received the event
6118    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6119    *
6120    * The ::motion-event signal is emitted each time the mouse pointer is
6121    * moved over @actor.
6122    *
6123    * Return value: %TRUE if the event has been handled by the actor,
6124    *   or %FALSE to continue the emission.
6125    *
6126    * Since: 0.6
6127    */
6128   actor_signals[MOTION_EVENT] =
6129     g_signal_new (I_("motion-event"),
6130                   G_TYPE_FROM_CLASS (object_class),
6131                   G_SIGNAL_RUN_LAST,
6132                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6133                   _clutter_boolean_handled_accumulator, NULL,
6134                   _clutter_marshal_BOOLEAN__BOXED,
6135                   G_TYPE_BOOLEAN, 1,
6136                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6137
6138   /**
6139    * ClutterActor::key-focus-in:
6140    * @actor: the actor which now has key focus
6141    *
6142    * The ::key-focus-in signal is emitted when @actor receives key focus.
6143    *
6144    * Since: 0.6
6145    */
6146   actor_signals[KEY_FOCUS_IN] =
6147     g_signal_new (I_("key-focus-in"),
6148                   G_TYPE_FROM_CLASS (object_class),
6149                   G_SIGNAL_RUN_LAST,
6150                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6151                   NULL, NULL,
6152                   _clutter_marshal_VOID__VOID,
6153                   G_TYPE_NONE, 0);
6154
6155   /**
6156    * ClutterActor::key-focus-out:
6157    * @actor: the actor which now has key focus
6158    *
6159    * The ::key-focus-out signal is emitted when @actor loses key focus.
6160    *
6161    * Since: 0.6
6162    */
6163   actor_signals[KEY_FOCUS_OUT] =
6164     g_signal_new (I_("key-focus-out"),
6165                   G_TYPE_FROM_CLASS (object_class),
6166                   G_SIGNAL_RUN_LAST,
6167                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6168                   NULL, NULL,
6169                   _clutter_marshal_VOID__VOID,
6170                   G_TYPE_NONE, 0);
6171
6172   /**
6173    * ClutterActor::enter-event:
6174    * @actor: the actor which the pointer has entered.
6175    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6176    *
6177    * The ::enter-event signal is emitted when the pointer enters the @actor
6178    *
6179    * Return value: %TRUE if the event has been handled by the actor,
6180    *   or %FALSE to continue the emission.
6181    *
6182    * Since: 0.6
6183    */
6184   actor_signals[ENTER_EVENT] =
6185     g_signal_new (I_("enter-event"),
6186                   G_TYPE_FROM_CLASS (object_class),
6187                   G_SIGNAL_RUN_LAST,
6188                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6189                   _clutter_boolean_handled_accumulator, NULL,
6190                   _clutter_marshal_BOOLEAN__BOXED,
6191                   G_TYPE_BOOLEAN, 1,
6192                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6193
6194   /**
6195    * ClutterActor::leave-event:
6196    * @actor: the actor which the pointer has left
6197    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6198    *
6199    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6200    *
6201    * Return value: %TRUE if the event has been handled by the actor,
6202    *   or %FALSE to continue the emission.
6203    *
6204    * Since: 0.6
6205    */
6206   actor_signals[LEAVE_EVENT] =
6207     g_signal_new (I_("leave-event"),
6208                   G_TYPE_FROM_CLASS (object_class),
6209                   G_SIGNAL_RUN_LAST,
6210                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6211                   _clutter_boolean_handled_accumulator, NULL,
6212                   _clutter_marshal_BOOLEAN__BOXED,
6213                   G_TYPE_BOOLEAN, 1,
6214                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6215
6216   /**
6217    * ClutterActor::captured-event:
6218    * @actor: the actor which received the signal
6219    * @event: a #ClutterEvent
6220    *
6221    * The ::captured-event signal is emitted when an event is captured
6222    * by Clutter. This signal will be emitted starting from the top-level
6223    * container (the #ClutterStage) to the actor which received the event
6224    * going down the hierarchy. This signal can be used to intercept every
6225    * event before the specialized events (like
6226    * ClutterActor::button-press-event or ::key-released-event) are
6227    * emitted.
6228    *
6229    * Return value: %TRUE if the event has been handled by the actor,
6230    *   or %FALSE to continue the emission.
6231    *
6232    * Since: 0.6
6233    */
6234   actor_signals[CAPTURED_EVENT] =
6235     g_signal_new (I_("captured-event"),
6236                   G_TYPE_FROM_CLASS (object_class),
6237                   G_SIGNAL_RUN_LAST,
6238                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6239                   _clutter_boolean_handled_accumulator, NULL,
6240                   _clutter_marshal_BOOLEAN__BOXED,
6241                   G_TYPE_BOOLEAN, 1,
6242                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6243
6244   /**
6245    * ClutterActor::paint:
6246    * @actor: the #ClutterActor that received the signal
6247    *
6248    * The ::paint signal is emitted each time an actor is being painted.
6249    *
6250    * Subclasses of #ClutterActor should override the class signal handler
6251    * and paint themselves in that function.
6252    *
6253    * It is possible to connect a handler to the ::paint signal in order
6254    * to set up some custom aspect of a paint.
6255    *
6256    * Since: 0.8
6257    */
6258   actor_signals[PAINT] =
6259     g_signal_new (I_("paint"),
6260                   G_TYPE_FROM_CLASS (object_class),
6261                   G_SIGNAL_RUN_LAST,
6262                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6263                   NULL, NULL,
6264                   _clutter_marshal_VOID__VOID,
6265                   G_TYPE_NONE, 0);
6266   /**
6267    * ClutterActor::realize:
6268    * @actor: the #ClutterActor that received the signal
6269    *
6270    * The ::realize signal is emitted each time an actor is being
6271    * realized.
6272    *
6273    * Since: 0.8
6274    */
6275   actor_signals[REALIZE] =
6276     g_signal_new (I_("realize"),
6277                   G_TYPE_FROM_CLASS (object_class),
6278                   G_SIGNAL_RUN_LAST,
6279                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6280                   NULL, NULL,
6281                   _clutter_marshal_VOID__VOID,
6282                   G_TYPE_NONE, 0);
6283   /**
6284    * ClutterActor::unrealize:
6285    * @actor: the #ClutterActor that received the signal
6286    *
6287    * The ::unrealize signal is emitted each time an actor is being
6288    * unrealized.
6289    *
6290    * Since: 0.8
6291    */
6292   actor_signals[UNREALIZE] =
6293     g_signal_new (I_("unrealize"),
6294                   G_TYPE_FROM_CLASS (object_class),
6295                   G_SIGNAL_RUN_LAST,
6296                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6297                   NULL, NULL,
6298                   _clutter_marshal_VOID__VOID,
6299                   G_TYPE_NONE, 0);
6300
6301   /**
6302    * ClutterActor::pick:
6303    * @actor: the #ClutterActor that received the signal
6304    * @color: the #ClutterColor to be used when picking
6305    *
6306    * The ::pick signal is emitted each time an actor is being painted
6307    * in "pick mode". The pick mode is used to identify the actor during
6308    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6309    * The actor should paint its shape using the passed @pick_color.
6310    *
6311    * Subclasses of #ClutterActor should override the class signal handler
6312    * and paint themselves in that function.
6313    *
6314    * It is possible to connect a handler to the ::pick signal in order
6315    * to set up some custom aspect of a paint in pick mode.
6316    *
6317    * Since: 1.0
6318    */
6319   actor_signals[PICK] =
6320     g_signal_new (I_("pick"),
6321                   G_TYPE_FROM_CLASS (object_class),
6322                   G_SIGNAL_RUN_LAST,
6323                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6324                   NULL, NULL,
6325                   _clutter_marshal_VOID__BOXED,
6326                   G_TYPE_NONE, 1,
6327                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6328
6329   /**
6330    * ClutterActor::allocation-changed:
6331    * @actor: the #ClutterActor that emitted the signal
6332    * @box: a #ClutterActorBox with the new allocation
6333    * @flags: #ClutterAllocationFlags for the allocation
6334    *
6335    * The ::allocation-changed signal is emitted when the
6336    * #ClutterActor:allocation property changes. Usually, application
6337    * code should just use the notifications for the :allocation property
6338    * but if you want to track the allocation flags as well, for instance
6339    * to know whether the absolute origin of @actor changed, then you might
6340    * want use this signal instead.
6341    *
6342    * Since: 1.0
6343    */
6344   actor_signals[ALLOCATION_CHANGED] =
6345     g_signal_new (I_("allocation-changed"),
6346                   G_TYPE_FROM_CLASS (object_class),
6347                   G_SIGNAL_RUN_LAST,
6348                   0,
6349                   NULL, NULL,
6350                   _clutter_marshal_VOID__BOXED_FLAGS,
6351                   G_TYPE_NONE, 2,
6352                   CLUTTER_TYPE_ACTOR_BOX,
6353                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6354 }
6355
6356 static void
6357 clutter_actor_init (ClutterActor *self)
6358 {
6359   ClutterActorPrivate *priv;
6360
6361   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6362
6363   priv->id = _clutter_context_acquire_id (self);
6364   priv->pick_id = -1;
6365
6366   priv->opacity = 0xff;
6367   priv->show_on_set_parent = TRUE;
6368
6369   priv->needs_width_request = TRUE;
6370   priv->needs_height_request = TRUE;
6371   priv->needs_allocation = TRUE;
6372
6373   priv->cached_width_age = 1;
6374   priv->cached_height_age = 1;
6375
6376   priv->opacity_override = -1;
6377   priv->enable_model_view_transform = TRUE;
6378
6379   /* Initialize an empty paint volume to start with */
6380   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6381   priv->last_paint_volume_valid = TRUE;
6382
6383   priv->transform_valid = FALSE;
6384 }
6385
6386 /**
6387  * clutter_actor_new:
6388  *
6389  * Creates a new #ClutterActor.
6390  *
6391  * A newly created actor has a floating reference, which will be sunk
6392  * when it is added to another actor.
6393  *
6394  * Return value: (transfer full): the newly created #ClutterActor
6395  *
6396  * Since: 1.10
6397  */
6398 ClutterActor *
6399 clutter_actor_new (void)
6400 {
6401   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6402 }
6403
6404 /**
6405  * clutter_actor_destroy:
6406  * @self: a #ClutterActor
6407  *
6408  * Destroys an actor.  When an actor is destroyed, it will break any
6409  * references it holds to other objects.  If the actor is inside a
6410  * container, the actor will be removed.
6411  *
6412  * When you destroy a container, its children will be destroyed as well.
6413  *
6414  * Note: you cannot destroy the #ClutterStage returned by
6415  * clutter_stage_get_default().
6416  */
6417 void
6418 clutter_actor_destroy (ClutterActor *self)
6419 {
6420   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6421
6422   g_object_ref (self);
6423
6424   /* avoid recursion while destroying */
6425   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6426     {
6427       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6428
6429       g_object_run_dispose (G_OBJECT (self));
6430
6431       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6432     }
6433
6434   g_object_unref (self);
6435 }
6436
6437 void
6438 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6439                                     ClutterPaintVolume *clip)
6440 {
6441   ClutterActorPrivate *priv = self->priv;
6442   ClutterPaintVolume *pv;
6443   gboolean clipped;
6444
6445   /* If we've been explicitly passed a clip volume then there's
6446    * nothing more to calculate, but otherwise the only thing we know
6447    * is that the change is constrained to the given actor.
6448    *
6449    * The idea is that if we know the paint volume for where the actor
6450    * was last drawn (in eye coordinates) and we also have the paint
6451    * volume for where it will be drawn next (in actor coordinates)
6452    * then if we queue a redraw for both these volumes that will cover
6453    * everything that needs to be redrawn to clear the old view and
6454    * show the latest view of the actor.
6455    *
6456    * Don't clip this redraw if we don't know what position we had for
6457    * the previous redraw since we don't know where to set the clip so
6458    * it will clear the actor as it is currently.
6459    */
6460   if (clip)
6461     {
6462       _clutter_actor_set_queue_redraw_clip (self, clip);
6463       clipped = TRUE;
6464     }
6465   else if (G_LIKELY (priv->last_paint_volume_valid))
6466     {
6467       pv = _clutter_actor_get_paint_volume_mutable (self);
6468       if (pv)
6469         {
6470           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6471
6472           /* make sure we redraw the actors old position... */
6473           _clutter_actor_set_queue_redraw_clip (stage,
6474                                                 &priv->last_paint_volume);
6475           _clutter_actor_signal_queue_redraw (stage, stage);
6476           _clutter_actor_set_queue_redraw_clip (stage, NULL);
6477
6478           /* XXX: Ideally the redraw signal would take a clip volume
6479            * argument, but that would be an ABI break. Until we can
6480            * break the ABI we pass the argument out-of-band
6481            */
6482
6483           /* setup the clip for the actors new position... */
6484           _clutter_actor_set_queue_redraw_clip (self, pv);
6485           clipped = TRUE;
6486         }
6487       else
6488         clipped = FALSE;
6489     }
6490   else
6491     clipped = FALSE;
6492
6493   _clutter_actor_signal_queue_redraw (self, self);
6494
6495   /* Just in case anyone is manually firing redraw signals without
6496    * using the public queue_redraw() API we are careful to ensure that
6497    * our out-of-band clip member is cleared before returning...
6498    *
6499    * Note: A NULL clip denotes a full-stage, un-clipped redraw
6500    */
6501   if (G_LIKELY (clipped))
6502     _clutter_actor_set_queue_redraw_clip (self, NULL);
6503
6504   priv->queue_redraw_entry = NULL;
6505 }
6506
6507 static void
6508 _clutter_actor_get_allocation_clip (ClutterActor *self,
6509                                     ClutterActorBox *clip)
6510 {
6511   ClutterActorBox allocation;
6512
6513   /* XXX: we don't care if we get an out of date allocation here
6514    * because clutter_actor_queue_redraw_with_clip knows to ignore
6515    * the clip if the actor's allocation is invalid.
6516    *
6517    * This is noted because clutter_actor_get_allocation_box does some
6518    * unnecessary work to support buggy code with a comment suggesting
6519    * that it could be changed later which would be good for this use
6520    * case!
6521    */
6522   clutter_actor_get_allocation_box (self, &allocation);
6523
6524   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6525    * actor's own coordinate space but the allocation is in parent
6526    * coordinates */
6527   clip->x1 = 0;
6528   clip->y1 = 0;
6529   clip->x2 = allocation.x2 - allocation.x1;
6530   clip->y2 = allocation.y2 - allocation.y1;
6531 }
6532
6533 void
6534 _clutter_actor_queue_redraw_full (ClutterActor       *self,
6535                                   ClutterRedrawFlags  flags,
6536                                   ClutterPaintVolume *volume,
6537                                   ClutterEffect      *effect)
6538 {
6539   ClutterActorPrivate *priv = self->priv;
6540   ClutterPaintVolume allocation_pv;
6541   ClutterPaintVolume *pv;
6542   gboolean should_free_pv;
6543   ClutterActor *stage;
6544
6545   /* Here's an outline of the actor queue redraw mechanism:
6546    *
6547    * The process starts in one of the following two functions which
6548    * are wrappers for this function:
6549    * clutter_actor_queue_redraw
6550    * _clutter_actor_queue_redraw_with_clip
6551    *
6552    * additionally, an effect can queue a redraw by wrapping this
6553    * function in clutter_effect_queue_rerun
6554    *
6555    * This functions queues an entry in a list associated with the
6556    * stage which is a list of actors that queued a redraw while
6557    * updating the timelines, performing layouting and processing other
6558    * mainloop sources before the next paint starts.
6559    *
6560    * We aim to minimize the processing done at this point because
6561    * there is a good chance other events will happen while updating
6562    * the scenegraph that would invalidate any expensive work we might
6563    * otherwise try to do here. For example we don't try and resolve
6564    * the screen space bounding box of an actor at this stage so as to
6565    * minimize how much of the screen redraw because it's possible
6566    * something else will happen which will force a full redraw anyway.
6567    *
6568    * When all updates are complete and we come to paint the stage then
6569    * we iterate this list and actually emit the "queue-redraw" signals
6570    * for each of the listed actors which will bubble up to the stage
6571    * for each actor and at that point we will transform the actors
6572    * paint volume into screen coordinates to determine the clip region
6573    * for what needs to be redrawn in the next paint.
6574    *
6575    * Besides minimizing redundant work another reason for this
6576    * deferred design is that it's more likely we will be able to
6577    * determine the paint volume of an actor once we've finished
6578    * updating the scenegraph because its allocation should be up to
6579    * date. NB: If we can't determine an actors paint volume then we
6580    * can't automatically queue a clipped redraw which can make a big
6581    * difference to performance.
6582    *
6583    * So the control flow goes like this:
6584    * One of clutter_actor_queue_redraw,
6585    *        _clutter_actor_queue_redraw_with_clip
6586    *     or clutter_effect_queue_rerun
6587    *
6588    * then control moves to:
6589    *   _clutter_stage_queue_actor_redraw
6590    *
6591    * later during _clutter_stage_do_update, once relayouting is done
6592    * and the scenegraph has been updated we will call:
6593    * _clutter_stage_finish_queue_redraws
6594    *
6595    * _clutter_stage_finish_queue_redraws will call
6596    * _clutter_actor_finish_queue_redraw for each listed actor.
6597    * Note: actors *are* allowed to queue further redraws during this
6598    * process (considering clone actors or texture_new_from_actor which
6599    * respond to their source queueing a redraw by queuing a redraw
6600    * themselves). We repeat the process until the list is empty.
6601    *
6602    * This will result in the "queue-redraw" signal being fired for
6603    * each actor which will pass control to the default signal handler:
6604    * clutter_actor_real_queue_redraw
6605    *
6606    * This will bubble up to the stages handler:
6607    * clutter_stage_real_queue_redraw
6608    *
6609    * clutter_stage_real_queue_redraw will transform the actors paint
6610    * volume into screen space and add it as a clip region for the next
6611    * paint.
6612    */
6613
6614   /* ignore queueing a redraw for actors being destroyed */
6615   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6616     return;
6617
6618   stage = _clutter_actor_get_stage_internal (self);
6619
6620   /* Ignore queueing a redraw for actors not descended from a stage */
6621   if (stage == NULL)
6622     return;
6623
6624   /* ignore queueing a redraw on stages that are being destroyed */
6625   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
6626     return;
6627
6628   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
6629     {
6630       ClutterActorBox allocation_clip;
6631       ClutterVertex origin;
6632
6633       /* If the actor doesn't have a valid allocation then we will
6634        * queue a full stage redraw. */
6635       if (priv->needs_allocation)
6636         {
6637           /* NB: NULL denotes an undefined clip which will result in a
6638            * full redraw... */
6639           _clutter_actor_set_queue_redraw_clip (self, NULL);
6640           _clutter_actor_signal_queue_redraw (self, self);
6641           return;
6642         }
6643
6644       _clutter_paint_volume_init_static (&allocation_pv, self);
6645       pv = &allocation_pv;
6646
6647       _clutter_actor_get_allocation_clip (self, &allocation_clip);
6648
6649       origin.x = allocation_clip.x1;
6650       origin.y = allocation_clip.y1;
6651       origin.z = 0;
6652       clutter_paint_volume_set_origin (pv, &origin);
6653       clutter_paint_volume_set_width (pv,
6654                                       allocation_clip.x2 - allocation_clip.x1);
6655       clutter_paint_volume_set_height (pv,
6656                                        allocation_clip.y2 -
6657                                        allocation_clip.y1);
6658       should_free_pv = TRUE;
6659     }
6660   else
6661     {
6662       pv = volume;
6663       should_free_pv = FALSE;
6664     }
6665
6666   self->priv->queue_redraw_entry =
6667     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
6668                                        priv->queue_redraw_entry,
6669                                        self,
6670                                        pv);
6671
6672   if (should_free_pv)
6673     clutter_paint_volume_free (pv);
6674
6675   /* If this is the first redraw queued then we can directly use the
6676      effect parameter */
6677   if (!priv->is_dirty)
6678     priv->effect_to_redraw = effect;
6679   /* Otherwise we need to merge it with the existing effect parameter */
6680   else if (effect != NULL)
6681     {
6682       /* If there's already an effect then we need to use whichever is
6683          later in the chain of actors. Otherwise a full redraw has
6684          already been queued on the actor so we need to ignore the
6685          effect parameter */
6686       if (priv->effect_to_redraw != NULL)
6687         {
6688           if (priv->effects == NULL)
6689             g_warning ("Redraw queued with an effect that is "
6690                        "not applied to the actor");
6691           else
6692             {
6693               const GList *l;
6694
6695               for (l = _clutter_meta_group_peek_metas (priv->effects);
6696                    l != NULL;
6697                    l = l->next)
6698                 {
6699                   if (l->data == priv->effect_to_redraw ||
6700                       l->data == effect)
6701                     priv->effect_to_redraw = l->data;
6702                 }
6703             }
6704         }
6705     }
6706   else
6707     {
6708       /* If no effect is specified then we need to redraw the whole
6709          actor */
6710       priv->effect_to_redraw = NULL;
6711     }
6712
6713   priv->is_dirty = TRUE;
6714 }
6715
6716 /**
6717  * clutter_actor_queue_redraw:
6718  * @self: A #ClutterActor
6719  *
6720  * Queues up a redraw of an actor and any children. The redraw occurs
6721  * once the main loop becomes idle (after the current batch of events
6722  * has been processed, roughly).
6723  *
6724  * Applications rarely need to call this, as redraws are handled
6725  * automatically by modification functions.
6726  *
6727  * This function will not do anything if @self is not visible, or
6728  * if the actor is inside an invisible part of the scenegraph.
6729  *
6730  * Also be aware that painting is a NOP for actors with an opacity of
6731  * 0
6732  *
6733  * When you are implementing a custom actor you must queue a redraw
6734  * whenever some private state changes that will affect painting or
6735  * picking of your actor.
6736  */
6737 void
6738 clutter_actor_queue_redraw (ClutterActor *self)
6739 {
6740   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6741
6742   _clutter_actor_queue_redraw_full (self,
6743                                     0, /* flags */
6744                                     NULL, /* clip volume */
6745                                     NULL /* effect */);
6746 }
6747
6748 /*< private >
6749  * _clutter_actor_queue_redraw_with_clip:
6750  * @self: A #ClutterActor
6751  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
6752  *   this queue redraw.
6753  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
6754  *   redrawn or %NULL if you are just using a @flag to state your
6755  *   desired clipping.
6756  *
6757  * Queues up a clipped redraw of an actor and any children. The redraw
6758  * occurs once the main loop becomes idle (after the current batch of
6759  * events has been processed, roughly).
6760  *
6761  * If no flags are given the clip volume is defined by @volume
6762  * specified in actor coordinates and tells Clutter that only content
6763  * within this volume has been changed so Clutter can optionally
6764  * optimize the redraw.
6765  *
6766  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
6767  * should be %NULL and this tells Clutter to use the actor's current
6768  * allocation as a clip box. This flag can only be used for 2D actors,
6769  * because any actor with depth may be projected outside its
6770  * allocation.
6771  *
6772  * Applications rarely need to call this, as redraws are handled
6773  * automatically by modification functions.
6774  *
6775  * This function will not do anything if @self is not visible, or if
6776  * the actor is inside an invisible part of the scenegraph.
6777  *
6778  * Also be aware that painting is a NOP for actors with an opacity of
6779  * 0
6780  *
6781  * When you are implementing a custom actor you must queue a redraw
6782  * whenever some private state changes that will affect painting or
6783  * picking of your actor.
6784  */
6785 void
6786 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
6787                                        ClutterRedrawFlags  flags,
6788                                        ClutterPaintVolume *volume)
6789 {
6790   _clutter_actor_queue_redraw_full (self,
6791                                     flags, /* flags */
6792                                     volume, /* clip volume */
6793                                     NULL /* effect */);
6794 }
6795
6796 static void
6797 _clutter_actor_queue_only_relayout (ClutterActor *self)
6798 {
6799   ClutterActorPrivate *priv = self->priv;
6800
6801   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6802     return;
6803
6804   if (priv->needs_width_request &&
6805       priv->needs_height_request &&
6806       priv->needs_allocation)
6807     return; /* save some cpu cycles */
6808
6809 #if CLUTTER_ENABLE_DEBUG
6810   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
6811     {
6812       g_warning ("The actor '%s' is currently inside an allocation "
6813                  "cycle; calling clutter_actor_queue_relayout() is "
6814                  "not recommended",
6815                  _clutter_actor_get_debug_name (self));
6816     }
6817 #endif /* CLUTTER_ENABLE_DEBUG */
6818
6819   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
6820 }
6821
6822 /**
6823  * clutter_actor_queue_redraw_with_clip:
6824  * @self: a #ClutterActor
6825  * @clip: (allow-none): a rectangular clip region, or %NULL
6826  *
6827  * Queues a redraw on @self limited to a specific, actor-relative
6828  * rectangular area.
6829  *
6830  * If @clip is %NULL this function is equivalent to
6831  * clutter_actor_queue_redraw().
6832  *
6833  * Since: 1.10
6834  */
6835 void
6836 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
6837                                       const cairo_rectangle_int_t *clip)
6838 {
6839   ClutterPaintVolume volume;
6840   ClutterVertex origin;
6841
6842   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6843
6844   if (clip == NULL)
6845     {
6846       clutter_actor_queue_redraw (self);
6847       return;
6848     }
6849
6850   _clutter_paint_volume_init_static (&volume, self);
6851
6852   origin.x = clip->x;
6853   origin.y = clip->y;
6854   origin.z = 0.0f;
6855
6856   clutter_paint_volume_set_origin (&volume, &origin);
6857   clutter_paint_volume_set_width (&volume, clip->width);
6858   clutter_paint_volume_set_height (&volume, clip->height);
6859
6860   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
6861
6862   clutter_paint_volume_free (&volume);
6863 }
6864
6865 /**
6866  * clutter_actor_queue_relayout:
6867  * @self: A #ClutterActor
6868  *
6869  * Indicates that the actor's size request or other layout-affecting
6870  * properties may have changed. This function is used inside #ClutterActor
6871  * subclass implementations, not by applications directly.
6872  *
6873  * Queueing a new layout automatically queues a redraw as well.
6874  *
6875  * Since: 0.8
6876  */
6877 void
6878 clutter_actor_queue_relayout (ClutterActor *self)
6879 {
6880   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6881
6882   _clutter_actor_queue_only_relayout (self);
6883   clutter_actor_queue_redraw (self);
6884 }
6885
6886 /**
6887  * clutter_actor_get_preferred_size:
6888  * @self: a #ClutterActor
6889  * @min_width_p: (out) (allow-none): return location for the minimum
6890  *   width, or %NULL
6891  * @min_height_p: (out) (allow-none): return location for the minimum
6892  *   height, or %NULL
6893  * @natural_width_p: (out) (allow-none): return location for the natural
6894  *   width, or %NULL
6895  * @natural_height_p: (out) (allow-none): return location for the natural
6896  *   height, or %NULL
6897  *
6898  * Computes the preferred minimum and natural size of an actor, taking into
6899  * account the actor's geometry management (either height-for-width
6900  * or width-for-height).
6901  *
6902  * The width and height used to compute the preferred height and preferred
6903  * width are the actor's natural ones.
6904  *
6905  * If you need to control the height for the preferred width, or the width for
6906  * the preferred height, you should use clutter_actor_get_preferred_width()
6907  * and clutter_actor_get_preferred_height(), and check the actor's preferred
6908  * geometry management using the #ClutterActor:request-mode property.
6909  *
6910  * Since: 0.8
6911  */
6912 void
6913 clutter_actor_get_preferred_size (ClutterActor *self,
6914                                   gfloat       *min_width_p,
6915                                   gfloat       *min_height_p,
6916                                   gfloat       *natural_width_p,
6917                                   gfloat       *natural_height_p)
6918 {
6919   ClutterActorPrivate *priv;
6920   gfloat min_width, min_height;
6921   gfloat natural_width, natural_height;
6922
6923   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6924
6925   priv = self->priv;
6926
6927   min_width = min_height = 0;
6928   natural_width = natural_height = 0;
6929
6930   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
6931     {
6932       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
6933       clutter_actor_get_preferred_width (self, -1,
6934                                          &min_width,
6935                                          &natural_width);
6936       clutter_actor_get_preferred_height (self, natural_width,
6937                                           &min_height,
6938                                           &natural_height);
6939     }
6940   else
6941     {
6942       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
6943       clutter_actor_get_preferred_height (self, -1,
6944                                           &min_height,
6945                                           &natural_height);
6946       clutter_actor_get_preferred_width (self, natural_height,
6947                                          &min_width,
6948                                          &natural_width);
6949     }
6950
6951   if (min_width_p)
6952     *min_width_p = min_width;
6953
6954   if (min_height_p)
6955     *min_height_p = min_height;
6956
6957   if (natural_width_p)
6958     *natural_width_p = natural_width;
6959
6960   if (natural_height_p)
6961     *natural_height_p = natural_height;
6962 }
6963
6964 /*< private >
6965  * effective_align:
6966  * @align: a #ClutterActorAlign
6967  * @direction: a #ClutterTextDirection
6968  *
6969  * Retrieves the correct alignment depending on the text direction
6970  *
6971  * Return value: the effective alignment
6972  */
6973 static ClutterActorAlign
6974 effective_align (ClutterActorAlign    align,
6975                  ClutterTextDirection direction)
6976 {
6977   ClutterActorAlign res;
6978
6979   switch (align)
6980     {
6981     case CLUTTER_ACTOR_ALIGN_START:
6982       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
6983           ? CLUTTER_ACTOR_ALIGN_END
6984           : CLUTTER_ACTOR_ALIGN_START;
6985       break;
6986
6987     case CLUTTER_ACTOR_ALIGN_END:
6988       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
6989           ? CLUTTER_ACTOR_ALIGN_START
6990           : CLUTTER_ACTOR_ALIGN_END;
6991       break;
6992
6993     default:
6994       res = align;
6995       break;
6996     }
6997
6998   return res;
6999 }
7000
7001 static inline void
7002 adjust_for_margin (float  margin_start,
7003                    float  margin_end,
7004                    float *minimum_size,
7005                    float *natural_size,
7006                    float *allocated_start,
7007                    float *allocated_end)
7008 {
7009   *minimum_size -= (margin_start + margin_end);
7010   *natural_size -= (margin_start + margin_end);
7011   *allocated_start += margin_start;
7012   *allocated_end -= margin_end;
7013 }
7014
7015 static inline void
7016 adjust_for_alignment (ClutterActorAlign  alignment,
7017                       float              natural_size,
7018                       float             *allocated_start,
7019                       float             *allocated_end)
7020 {
7021   float allocated_size = *allocated_end - *allocated_start;
7022
7023   switch (alignment)
7024     {
7025     case CLUTTER_ACTOR_ALIGN_FILL:
7026       /* do nothing */
7027       break;
7028
7029     case CLUTTER_ACTOR_ALIGN_START:
7030       /* keep start */
7031       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7032       break;
7033
7034     case CLUTTER_ACTOR_ALIGN_END:
7035       if (allocated_size > natural_size)
7036         {
7037           *allocated_start += (allocated_size - natural_size);
7038           *allocated_end = *allocated_start + natural_size;
7039         }
7040       break;
7041
7042     case CLUTTER_ACTOR_ALIGN_CENTER:
7043       if (allocated_size > natural_size)
7044         {
7045           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7046           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7047         }
7048       break;
7049     }
7050 }
7051
7052 /*< private >
7053  * clutter_actor_adjust_width:
7054  * @self: a #ClutterActor
7055  * @minimum_width: (inout): the actor's preferred minimum width, which
7056  *   will be adjusted depending on the margin
7057  * @natural_width: (inout): the actor's preferred natural width, which
7058  *   will be adjusted depending on the margin
7059  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7060  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7061  *
7062  * Adjusts the preferred and allocated position and size of an actor,
7063  * depending on the margin and alignment properties.
7064  */
7065 static void
7066 clutter_actor_adjust_width (ClutterActor *self,
7067                             gfloat       *minimum_width,
7068                             gfloat       *natural_width,
7069                             gfloat       *adjusted_x1,
7070                             gfloat       *adjusted_x2)
7071 {
7072   ClutterTextDirection text_dir;
7073   const ClutterLayoutInfo *info;
7074
7075   info = _clutter_actor_get_layout_info_or_defaults (self);
7076   text_dir = clutter_actor_get_text_direction (self);
7077
7078   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7079
7080   /* this will tweak natural_width to remove the margin, so that
7081    * adjust_for_alignment() will use the correct size
7082    */
7083   adjust_for_margin (info->margin.left, info->margin.right,
7084                      minimum_width, natural_width,
7085                      adjusted_x1, adjusted_x2);
7086
7087   adjust_for_alignment (effective_align (info->x_align, text_dir),
7088                         *natural_width,
7089                         adjusted_x1, adjusted_x2);
7090 }
7091
7092 /*< private >
7093  * clutter_actor_adjust_height:
7094  * @self: a #ClutterActor
7095  * @minimum_height: (inout): the actor's preferred minimum height, which
7096  *   will be adjusted depending on the margin
7097  * @natural_height: (inout): the actor's preferred natural height, which
7098  *   will be adjusted depending on the margin
7099  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7100  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7101  *
7102  * Adjusts the preferred and allocated position and size of an actor,
7103  * depending on the margin and alignment properties.
7104  */
7105 static void
7106 clutter_actor_adjust_height (ClutterActor *self,
7107                              gfloat       *minimum_height,
7108                              gfloat       *natural_height,
7109                              gfloat       *adjusted_y1,
7110                              gfloat       *adjusted_y2)
7111 {
7112   const ClutterLayoutInfo *info;
7113
7114   info = _clutter_actor_get_layout_info_or_defaults (self);
7115
7116   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7117
7118   /* this will tweak natural_height to remove the margin, so that
7119    * adjust_for_alignment() will use the correct size
7120    */
7121   adjust_for_margin (info->margin.top, info->margin.bottom,
7122                      minimum_height, natural_height,
7123                      adjusted_y1,
7124                      adjusted_y2);
7125
7126   /* we don't use effective_align() here, because text direction
7127    * only affects the horizontal axis
7128    */
7129   adjust_for_alignment (info->y_align,
7130                         *natural_height,
7131                         adjusted_y1,
7132                         adjusted_y2);
7133
7134 }
7135
7136 /* looks for a cached size request for this for_size. If not
7137  * found, returns the oldest entry so it can be overwritten */
7138 static gboolean
7139 _clutter_actor_get_cached_size_request (gfloat         for_size,
7140                                         SizeRequest   *cached_size_requests,
7141                                         SizeRequest  **result)
7142 {
7143   guint i;
7144
7145   *result = &cached_size_requests[0];
7146
7147   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7148     {
7149       SizeRequest *sr;
7150
7151       sr = &cached_size_requests[i];
7152
7153       if (sr->age > 0 &&
7154           sr->for_size == for_size)
7155         {
7156           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7157           *result = sr;
7158           return TRUE;
7159         }
7160       else if (sr->age < (*result)->age)
7161         {
7162           *result = sr;
7163         }
7164     }
7165
7166   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7167
7168   return FALSE;
7169 }
7170
7171 /**
7172  * clutter_actor_get_preferred_width:
7173  * @self: A #ClutterActor
7174  * @for_height: available height when computing the preferred width,
7175  *   or a negative value to indicate that no height is defined
7176  * @min_width_p: (out) (allow-none): return location for minimum width,
7177  *   or %NULL
7178  * @natural_width_p: (out) (allow-none): return location for the natural
7179  *   width, or %NULL
7180  *
7181  * Computes the requested minimum and natural widths for an actor,
7182  * optionally depending on the specified height, or if they are
7183  * already computed, returns the cached values.
7184  *
7185  * An actor may not get its request - depending on the layout
7186  * manager that's in effect.
7187  *
7188  * A request should not incorporate the actor's scale or anchor point;
7189  * those transformations do not affect layout, only rendering.
7190  *
7191  * Since: 0.8
7192  */
7193 void
7194 clutter_actor_get_preferred_width (ClutterActor *self,
7195                                    gfloat        for_height,
7196                                    gfloat       *min_width_p,
7197                                    gfloat       *natural_width_p)
7198 {
7199   float request_min_width, request_natural_width;
7200   SizeRequest *cached_size_request;
7201   const ClutterLayoutInfo *info;
7202   ClutterActorPrivate *priv;
7203   gboolean found_in_cache;
7204
7205   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7206
7207   priv = self->priv;
7208
7209   info = _clutter_actor_get_layout_info_or_defaults (self);
7210
7211   /* we shortcircuit the case of a fixed size set using set_width() */
7212   if (priv->min_width_set && priv->natural_width_set)
7213     {
7214       if (min_width_p != NULL)
7215         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7216
7217       if (natural_width_p != NULL)
7218         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7219
7220       return;
7221     }
7222
7223   /* the remaining cases are:
7224    *
7225    *   - either min_width or natural_width have been set
7226    *   - neither min_width or natural_width have been set
7227    *
7228    * in both cases, we go through the cache (and through the actor in case
7229    * of cache misses) and determine the authoritative value depending on
7230    * the *_set flags.
7231    */
7232
7233   if (!priv->needs_width_request)
7234     {
7235       found_in_cache =
7236         _clutter_actor_get_cached_size_request (for_height,
7237                                                 priv->width_requests,
7238                                                 &cached_size_request);
7239     }
7240   else
7241     {
7242       /* if the actor needs a width request we use the first slot */
7243       found_in_cache = FALSE;
7244       cached_size_request = &priv->width_requests[0];
7245     }
7246
7247   if (!found_in_cache)
7248     {
7249       gfloat minimum_width, natural_width;
7250       ClutterActorClass *klass;
7251
7252       minimum_width = natural_width = 0;
7253
7254       /* adjust for the margin */
7255       if (for_height >= 0)
7256         {
7257           for_height -= (info->margin.top + info->margin.bottom);
7258           if (for_height < 0)
7259             for_height = 0;
7260         }
7261
7262       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7263
7264       klass = CLUTTER_ACTOR_GET_CLASS (self);
7265       klass->get_preferred_width (self, for_height,
7266                                   &minimum_width,
7267                                   &natural_width);
7268
7269       /* adjust for the margin */
7270       minimum_width += (info->margin.left + info->margin.right);
7271       natural_width += (info->margin.left + info->margin.right);
7272
7273       /* Due to accumulated float errors, it's better not to warn
7274        * on this, but just fix it.
7275        */
7276       if (natural_width < minimum_width)
7277         natural_width = minimum_width;
7278
7279       cached_size_request->min_size = minimum_width;
7280       cached_size_request->natural_size = natural_width;
7281       cached_size_request->for_size = for_height;
7282       cached_size_request->age = priv->cached_width_age;
7283
7284       priv->cached_width_age += 1;
7285       priv->needs_width_request = FALSE;
7286     }
7287
7288   if (!priv->min_width_set)
7289     request_min_width = cached_size_request->min_size;
7290   else
7291     request_min_width = info->min_width;
7292
7293   if (!priv->natural_width_set)
7294     request_natural_width = cached_size_request->natural_size;
7295   else
7296     request_natural_width = info->natural_width;
7297
7298   if (min_width_p)
7299     *min_width_p = request_min_width;
7300
7301   if (natural_width_p)
7302     *natural_width_p = request_natural_width;
7303 }
7304
7305 /**
7306  * clutter_actor_get_preferred_height:
7307  * @self: A #ClutterActor
7308  * @for_width: available width to assume in computing desired height,
7309  *   or a negative value to indicate that no width is defined
7310  * @min_height_p: (out) (allow-none): return location for minimum height,
7311  *   or %NULL
7312  * @natural_height_p: (out) (allow-none): return location for natural
7313  *   height, or %NULL
7314  *
7315  * Computes the requested minimum and natural heights for an actor,
7316  * or if they are already computed, returns the cached values.
7317  *
7318  * An actor may not get its request - depending on the layout
7319  * manager that's in effect.
7320  *
7321  * A request should not incorporate the actor's scale or anchor point;
7322  * those transformations do not affect layout, only rendering.
7323  *
7324  * Since: 0.8
7325  */
7326 void
7327 clutter_actor_get_preferred_height (ClutterActor *self,
7328                                     gfloat        for_width,
7329                                     gfloat       *min_height_p,
7330                                     gfloat       *natural_height_p)
7331 {
7332   float request_min_height, request_natural_height;
7333   SizeRequest *cached_size_request;
7334   const ClutterLayoutInfo *info;
7335   ClutterActorPrivate *priv;
7336   gboolean found_in_cache;
7337
7338   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7339
7340   priv = self->priv;
7341
7342   info = _clutter_actor_get_layout_info_or_defaults (self);
7343
7344   /* we shortcircuit the case of a fixed size set using set_height() */
7345   if (priv->min_height_set && priv->natural_height_set)
7346     {
7347       if (min_height_p != NULL)
7348         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7349
7350       if (natural_height_p != NULL)
7351         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7352
7353       return;
7354     }
7355
7356   /* the remaining cases are:
7357    *
7358    *   - either min_height or natural_height have been set
7359    *   - neither min_height or natural_height have been set
7360    *
7361    * in both cases, we go through the cache (and through the actor in case
7362    * of cache misses) and determine the authoritative value depending on
7363    * the *_set flags.
7364    */
7365
7366   if (!priv->needs_height_request)
7367     {
7368       found_in_cache =
7369         _clutter_actor_get_cached_size_request (for_width,
7370                                                 priv->height_requests,
7371                                                 &cached_size_request);
7372     }
7373   else
7374     {
7375       found_in_cache = FALSE;
7376       cached_size_request = &priv->height_requests[0];
7377     }
7378
7379   if (!found_in_cache)
7380     {
7381       gfloat minimum_height, natural_height;
7382       ClutterActorClass *klass;
7383
7384       minimum_height = natural_height = 0;
7385
7386       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7387
7388       /* adjust for margin */
7389       if (for_width >= 0)
7390         {
7391           for_width -= (info->margin.left + info->margin.right);
7392           if (for_width < 0)
7393             for_width = 0;
7394         }
7395
7396       klass = CLUTTER_ACTOR_GET_CLASS (self);
7397       klass->get_preferred_height (self, for_width,
7398                                    &minimum_height,
7399                                    &natural_height);
7400
7401       /* adjust for margin */
7402       minimum_height += (info->margin.top + info->margin.bottom);
7403       natural_height += (info->margin.top + info->margin.bottom);
7404
7405       /* Due to accumulated float errors, it's better not to warn
7406        * on this, but just fix it.
7407        */
7408       if (natural_height < minimum_height)
7409         natural_height = minimum_height;
7410
7411       cached_size_request->min_size = minimum_height;
7412       cached_size_request->natural_size = natural_height;
7413       cached_size_request->for_size = for_width;
7414       cached_size_request->age = priv->cached_height_age;
7415
7416       priv->cached_height_age += 1;
7417       priv->needs_height_request = FALSE;
7418     }
7419
7420   if (!priv->min_height_set)
7421     request_min_height = cached_size_request->min_size;
7422   else
7423     request_min_height = info->min_height;
7424
7425   if (!priv->natural_height_set)
7426     request_natural_height = cached_size_request->natural_size;
7427   else
7428     request_natural_height = info->natural_height;
7429
7430   if (min_height_p)
7431     *min_height_p = request_min_height;
7432
7433   if (natural_height_p)
7434     *natural_height_p = request_natural_height;
7435 }
7436
7437 /**
7438  * clutter_actor_get_allocation_box:
7439  * @self: A #ClutterActor
7440  * @box: (out): the function fills this in with the actor's allocation
7441  *
7442  * Gets the layout box an actor has been assigned. The allocation can
7443  * only be assumed valid inside a paint() method; anywhere else, it
7444  * may be out-of-date.
7445  *
7446  * An allocation does not incorporate the actor's scale or anchor point;
7447  * those transformations do not affect layout, only rendering.
7448  *
7449  * <note>Do not call any of the clutter_actor_get_allocation_*() family
7450  * of functions inside the implementation of the get_preferred_width()
7451  * or get_preferred_height() virtual functions.</note>
7452  *
7453  * Since: 0.8
7454  */
7455 void
7456 clutter_actor_get_allocation_box (ClutterActor    *self,
7457                                   ClutterActorBox *box)
7458 {
7459   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7460
7461   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7462    * which limits calling get_allocation to inside paint() basically; or
7463    * we can 2) force a layout, which could be expensive if someone calls
7464    * get_allocation somewhere silly; or we can 3) just return the latest
7465    * value, allowing it to be out-of-date, and assume people know what
7466    * they are doing.
7467    *
7468    * The least-surprises approach that keeps existing code working is
7469    * likely to be 2). People can end up doing some inefficient things,
7470    * though, and in general code that requires 2) is probably broken.
7471    */
7472
7473   /* this implements 2) */
7474   if (G_UNLIKELY (self->priv->needs_allocation))
7475     {
7476       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7477
7478       /* do not queue a relayout on an unparented actor */
7479       if (stage)
7480         _clutter_stage_maybe_relayout (stage);
7481     }
7482
7483   /* commenting out the code above and just keeping this assigment
7484    * implements 3)
7485    */
7486   *box = self->priv->allocation;
7487 }
7488
7489 /**
7490  * clutter_actor_get_allocation_geometry:
7491  * @self: A #ClutterActor
7492  * @geom: (out): allocation geometry in pixels
7493  *
7494  * Gets the layout box an actor has been assigned.  The allocation can
7495  * only be assumed valid inside a paint() method; anywhere else, it
7496  * may be out-of-date.
7497  *
7498  * An allocation does not incorporate the actor's scale or anchor point;
7499  * those transformations do not affect layout, only rendering.
7500  *
7501  * The returned rectangle is in pixels.
7502  *
7503  * Since: 0.8
7504  */
7505 void
7506 clutter_actor_get_allocation_geometry (ClutterActor    *self,
7507                                        ClutterGeometry *geom)
7508 {
7509   ClutterActorBox box;
7510
7511   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7512   g_return_if_fail (geom != NULL);
7513
7514   clutter_actor_get_allocation_box (self, &box);
7515
7516   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7517   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7518   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7519   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7520 }
7521
7522 static void
7523 clutter_actor_update_constraints (ClutterActor    *self,
7524                                   ClutterActorBox *allocation)
7525 {
7526   ClutterActorPrivate *priv = self->priv;
7527   const GList *constraints, *l;
7528
7529   if (priv->constraints == NULL)
7530     return;
7531
7532   constraints = _clutter_meta_group_peek_metas (priv->constraints);
7533   for (l = constraints; l != NULL; l = l->next)
7534     {
7535       ClutterConstraint *constraint = l->data;
7536       ClutterActorMeta *meta = l->data;
7537
7538       if (clutter_actor_meta_get_enabled (meta))
7539         {
7540           _clutter_constraint_update_allocation (constraint,
7541                                                  self,
7542                                                  allocation);
7543         }
7544     }
7545 }
7546
7547 /*< private >
7548  * clutter_actor_adjust_allocation:
7549  * @self: a #ClutterActor
7550  * @allocation: (inout): the allocation to adjust
7551  *
7552  * Adjusts the passed allocation box taking into account the actor's
7553  * layout information, like alignment, expansion, and margin.
7554  */
7555 static void
7556 clutter_actor_adjust_allocation (ClutterActor    *self,
7557                                  ClutterActorBox *allocation)
7558 {
7559   ClutterActorBox adj_allocation;
7560   float alloc_width, alloc_height;
7561   float min_width, min_height;
7562   float nat_width, nat_height;
7563   ClutterRequestMode req_mode;
7564
7565   adj_allocation = *allocation;
7566
7567   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
7568
7569   /* we want to hit the cache, so we use the public API */
7570   req_mode = clutter_actor_get_request_mode (self);
7571
7572   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7573     {
7574       clutter_actor_get_preferred_width (self, -1,
7575                                          &min_width,
7576                                          &nat_width);
7577       clutter_actor_get_preferred_height (self, alloc_width,
7578                                           &min_height,
7579                                           &nat_height);
7580     }
7581   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
7582     {
7583       clutter_actor_get_preferred_height (self, -1,
7584                                           &min_height,
7585                                           &nat_height);
7586       clutter_actor_get_preferred_height (self, alloc_height,
7587                                           &min_width,
7588                                           &nat_width);
7589     }
7590
7591 #ifdef CLUTTER_ENABLE_DEBUG
7592   /* warn about underallocations */
7593   if (_clutter_diagnostic_enabled () &&
7594       (floorf (min_width - alloc_width) > 0 ||
7595        floorf (min_height - alloc_height) > 0))
7596     {
7597       ClutterActor *parent = clutter_actor_get_parent (self);
7598
7599       /* the only actors that are allowed to be underallocated are the Stage,
7600        * as it doesn't have an implicit size, and Actors that specifically
7601        * told us that they want to opt-out from layout control mechanisms
7602        * through the NO_LAYOUT escape hatch.
7603        */
7604       if (parent != NULL &&
7605           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
7606         {
7607           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
7608                      "of %.2f x %.2f from its parent actor '%s', but its "
7609                      "requested minimum size is of %.2f x %.2f",
7610                      _clutter_actor_get_debug_name (self),
7611                      alloc_width, alloc_height,
7612                      _clutter_actor_get_debug_name (parent),
7613                      min_width, min_height);
7614         }
7615     }
7616 #endif
7617
7618   clutter_actor_adjust_width (self,
7619                               &min_width,
7620                               &nat_width,
7621                               &adj_allocation.x1,
7622                               &adj_allocation.x2);
7623
7624   clutter_actor_adjust_height (self,
7625                                &min_height,
7626                                &nat_height,
7627                                &adj_allocation.y1,
7628                                &adj_allocation.y2);
7629
7630   /* we maintain the invariant that an allocation cannot be adjusted
7631    * to be outside the parent-given box
7632    */
7633   if (adj_allocation.x1 < allocation->x1 ||
7634       adj_allocation.y1 < allocation->y1 ||
7635       adj_allocation.x2 > allocation->x2 ||
7636       adj_allocation.y2 > allocation->y2)
7637     {
7638       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
7639                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
7640                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
7641                  _clutter_actor_get_debug_name (self),
7642                  adj_allocation.x1, adj_allocation.y1,
7643                  adj_allocation.x2 - adj_allocation.x1,
7644                  adj_allocation.y2 - adj_allocation.y1,
7645                  allocation->x1, allocation->y1,
7646                  allocation->x2 - allocation->x1,
7647                  allocation->y2 - allocation->y1);
7648       return;
7649     }
7650
7651   *allocation = adj_allocation;
7652 }
7653
7654 /**
7655  * clutter_actor_allocate:
7656  * @self: A #ClutterActor
7657  * @box: new allocation of the actor, in parent-relative coordinates
7658  * @flags: flags that control the allocation
7659  *
7660  * Called by the parent of an actor to assign the actor its size.
7661  * Should never be called by applications (except when implementing
7662  * a container or layout manager).
7663  *
7664  * Actors can know from their allocation box whether they have moved
7665  * with respect to their parent actor. The @flags parameter describes
7666  * additional information about the allocation, for instance whether
7667  * the parent has moved with respect to the stage, for example because
7668  * a grandparent's origin has moved.
7669  *
7670  * Since: 0.8
7671  */
7672 void
7673 clutter_actor_allocate (ClutterActor           *self,
7674                         const ClutterActorBox  *box,
7675                         ClutterAllocationFlags  flags)
7676 {
7677   ClutterActorPrivate *priv;
7678   ClutterActorClass *klass;
7679   ClutterActorBox old_allocation, real_allocation;
7680   gboolean origin_changed, child_moved, size_changed;
7681   gboolean stage_allocation_changed;
7682
7683   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7684   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
7685     {
7686       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
7687                  "which isn't a descendent of the stage!\n",
7688                  self, _clutter_actor_get_debug_name (self));
7689       return;
7690     }
7691
7692   priv = self->priv;
7693
7694   old_allocation = priv->allocation;
7695   real_allocation = *box;
7696
7697   /* constraints are allowed to modify the allocation only here; we do
7698    * this prior to all the other checks so that we can bail out if the
7699    * allocation did not change
7700    */
7701   clutter_actor_update_constraints (self, &real_allocation);
7702
7703   /* adjust the allocation depending on the align/margin properties */
7704   clutter_actor_adjust_allocation (self, &real_allocation);
7705
7706   if (real_allocation.x2 < real_allocation.x1 ||
7707       real_allocation.y2 < real_allocation.y1)
7708     {
7709       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
7710                  _clutter_actor_get_debug_name (self),
7711                  real_allocation.x2 - real_allocation.x1,
7712                  real_allocation.y2 - real_allocation.y1);
7713     }
7714
7715   /* we allow 0-sized actors, but not negative-sized ones */
7716   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
7717   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
7718
7719   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
7720
7721   child_moved = (real_allocation.x1 != old_allocation.x1 ||
7722                  real_allocation.y1 != old_allocation.y1);
7723
7724   size_changed = (real_allocation.x2 != old_allocation.x2 ||
7725                   real_allocation.y2 != old_allocation.y2);
7726
7727   if (origin_changed || child_moved || size_changed)
7728     stage_allocation_changed = TRUE;
7729   else
7730     stage_allocation_changed = FALSE;
7731
7732   /* If we get an allocation "out of the blue"
7733    * (we did not queue relayout), then we want to
7734    * ignore it. But if we have needs_allocation set,
7735    * we want to guarantee that allocate() virtual
7736    * method is always called, i.e. that queue_relayout()
7737    * always results in an allocate() invocation on
7738    * an actor.
7739    *
7740    * The optimization here is to avoid re-allocating
7741    * actors that did not queue relayout and were
7742    * not moved.
7743    */
7744   if (!priv->needs_allocation && !stage_allocation_changed)
7745     {
7746       CLUTTER_NOTE (LAYOUT, "No allocation needed");
7747       return;
7748     }
7749
7750   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
7751    * clutter_actor_allocate(), it indicates whether the parent has its
7752    * absolute origin moved; when passed in to ClutterActor::allocate()
7753    * virtual method though, it indicates whether the child has its
7754    * absolute origin moved.  So we set it when child_moved is TRUE
7755    */
7756   if (child_moved)
7757     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
7758
7759   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7760
7761   klass = CLUTTER_ACTOR_GET_CLASS (self);
7762   klass->allocate (self, &real_allocation, flags);
7763
7764   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7765
7766   if (stage_allocation_changed)
7767     clutter_actor_queue_redraw (self);
7768 }
7769
7770 /**
7771  * clutter_actor_set_allocation:
7772  * @self: a #ClutterActor
7773  * @box: a #ClutterActorBox
7774  * @flags: allocation flags
7775  *
7776  * Stores the allocation of @self as defined by @box.
7777  *
7778  * This function can only be called from within the implementation of
7779  * the #ClutterActorClass.allocate() virtual function.
7780  *
7781  * The allocation should have been adjusted to take into account constraints,
7782  * alignment, and margin properties. If you are implementing a #ClutterActor
7783  * subclass that provides its own layout management policy for its children
7784  * instead of using a #ClutterLayoutManager delegate, you should not call
7785  * this function on the children of @self; instead, you should call
7786  * clutter_actor_allocate(), which will adjust the allocation box for
7787  * you.
7788  *
7789  * This function should only be used by subclasses of #ClutterActor
7790  * that wish to store their allocation but cannot chain up to the
7791  * parent's implementation; the default implementation of the
7792  * #ClutterActorClass.allocate() virtual function will call this
7793  * function.
7794  *
7795  * It is important to note that, while chaining up was the recommended
7796  * behaviour for #ClutterActor subclasses prior to the introduction of
7797  * this function, it is recommended to call clutter_actor_set_allocation()
7798  * instead.
7799  *
7800  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
7801  * to handle the allocation of its children, this function will call
7802  * the clutter_layout_manager_allocate() function only if the
7803  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
7804  * expected that the subclass will call clutter_layout_manager_allocate()
7805  * by itself. For instance, the following code:
7806  *
7807  * |[
7808  * static void
7809  * my_actor_allocate (ClutterActor *actor,
7810  *                    const ClutterActorBox *allocation,
7811  *                    ClutterAllocationFlags flags)
7812  * {
7813  *   ClutterActorBox new_alloc;
7814  *   ClutterAllocationFlags new_flags;
7815  *
7816  *   adjust_allocation (allocation, &amp;new_alloc);
7817  *
7818  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
7819  *
7820  *   /&ast; this will use the layout manager set on the actor &ast;/
7821  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
7822  * }
7823  * ]|
7824  *
7825  * is equivalent to this:
7826  *
7827  * |[
7828  * static void
7829  * my_actor_allocate (ClutterActor *actor,
7830  *                    const ClutterActorBox *allocation,
7831  *                    ClutterAllocationFlags flags)
7832  * {
7833  *   ClutterLayoutManager *layout;
7834  *   ClutterActorBox new_alloc;
7835  *
7836  *   adjust_allocation (allocation, &amp;new_alloc);
7837  *
7838  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
7839  *
7840  *   layout = clutter_actor_get_layout_manager (actor);
7841  *   clutter_layout_manager_allocate (layout,
7842  *                                    CLUTTER_CONTAINER (actor),
7843  *                                    &amp;new_alloc,
7844  *                                    flags);
7845  * }
7846  * ]|
7847  *
7848  * Since: 1.10
7849  */
7850 void
7851 clutter_actor_set_allocation (ClutterActor           *self,
7852                               const ClutterActorBox  *box,
7853                               ClutterAllocationFlags  flags)
7854 {
7855   ClutterActorPrivate *priv;
7856   gboolean changed;
7857
7858   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7859   g_return_if_fail (box != NULL);
7860
7861   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
7862     {
7863       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
7864                   "can only be called from within the implementation of "
7865                   "the ClutterActor::allocate() virtual function.");
7866       return;
7867     }
7868
7869   priv = self->priv;
7870
7871   g_object_freeze_notify (G_OBJECT (self));
7872
7873   changed = clutter_actor_set_allocation_internal (self, box, flags);
7874
7875   /* we allocate our children before we notify changes in our geometry,
7876    * so that people connecting to properties will be able to get valid
7877    * data out of the sub-tree of the scene graph that has this actor at
7878    * the root.
7879    */
7880   clutter_actor_maybe_layout_children (self, box, flags);
7881
7882   if (changed)
7883     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
7884                    &priv->allocation,
7885                    priv->allocation_flags);
7886
7887   g_object_thaw_notify (G_OBJECT (self));
7888 }
7889
7890 /**
7891  * clutter_actor_set_geometry:
7892  * @self: A #ClutterActor
7893  * @geometry: A #ClutterGeometry
7894  *
7895  * Sets the actor's fixed position and forces its minimum and natural
7896  * size, in pixels. This means the untransformed actor will have the
7897  * given geometry. This is the same as calling clutter_actor_set_position()
7898  * and clutter_actor_set_size().
7899  *
7900  * Deprecated: 1.10: Use clutter_actor_set_position() and
7901  *   clutter_actor_set_size() instead.
7902  */
7903 void
7904 clutter_actor_set_geometry (ClutterActor          *self,
7905                             const ClutterGeometry *geometry)
7906 {
7907   g_object_freeze_notify (G_OBJECT (self));
7908
7909   clutter_actor_set_position (self, geometry->x, geometry->y);
7910   clutter_actor_set_size (self, geometry->width, geometry->height);
7911
7912   g_object_thaw_notify (G_OBJECT (self));
7913 }
7914
7915 /**
7916  * clutter_actor_get_geometry:
7917  * @self: A #ClutterActor
7918  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
7919  *
7920  * Gets the size and position of an actor relative to its parent
7921  * actor. This is the same as calling clutter_actor_get_position() and
7922  * clutter_actor_get_size(). It tries to "do what you mean" and get the
7923  * requested size and position if the actor's allocation is invalid.
7924  *
7925  * Deprecated: 1.10: Use clutter_actor_get_position() and
7926  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
7927  *   instead.
7928  */
7929 void
7930 clutter_actor_get_geometry (ClutterActor    *self,
7931                             ClutterGeometry *geometry)
7932 {
7933   gfloat x, y, width, height;
7934
7935   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7936   g_return_if_fail (geometry != NULL);
7937
7938   clutter_actor_get_position (self, &x, &y);
7939   clutter_actor_get_size (self, &width, &height);
7940
7941   geometry->x = (int) x;
7942   geometry->y = (int) y;
7943   geometry->width = (int) width;
7944   geometry->height = (int) height;
7945 }
7946
7947 /**
7948  * clutter_actor_set_position
7949  * @self: A #ClutterActor
7950  * @x: New left position of actor in pixels.
7951  * @y: New top position of actor in pixels.
7952  *
7953  * Sets the actor's fixed position in pixels relative to any parent
7954  * actor.
7955  *
7956  * If a layout manager is in use, this position will override the
7957  * layout manager and force a fixed position.
7958  */
7959 void
7960 clutter_actor_set_position (ClutterActor *self,
7961                             gfloat        x,
7962                             gfloat        y)
7963 {
7964   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7965
7966   g_object_freeze_notify (G_OBJECT (self));
7967
7968   clutter_actor_set_x (self, x);
7969   clutter_actor_set_y (self, y);
7970
7971   g_object_thaw_notify (G_OBJECT (self));
7972 }
7973
7974 /**
7975  * clutter_actor_get_fixed_position_set:
7976  * @self: A #ClutterActor
7977  *
7978  * Checks whether an actor has a fixed position set (and will thus be
7979  * unaffected by any layout manager).
7980  *
7981  * Return value: %TRUE if the fixed position is set on the actor
7982  *
7983  * Since: 0.8
7984  */
7985 gboolean
7986 clutter_actor_get_fixed_position_set (ClutterActor *self)
7987 {
7988   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
7989
7990   return self->priv->position_set;
7991 }
7992
7993 /**
7994  * clutter_actor_set_fixed_position_set:
7995  * @self: A #ClutterActor
7996  * @is_set: whether to use fixed position
7997  *
7998  * Sets whether an actor has a fixed position set (and will thus be
7999  * unaffected by any layout manager).
8000  *
8001  * Since: 0.8
8002  */
8003 void
8004 clutter_actor_set_fixed_position_set (ClutterActor *self,
8005                                       gboolean      is_set)
8006 {
8007   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8008
8009   if (self->priv->position_set == (is_set != FALSE))
8010     return;
8011
8012   self->priv->position_set = is_set != FALSE;
8013   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8014
8015   clutter_actor_queue_relayout (self);
8016 }
8017
8018 /**
8019  * clutter_actor_move_by:
8020  * @self: A #ClutterActor
8021  * @dx: Distance to move Actor on X axis.
8022  * @dy: Distance to move Actor on Y axis.
8023  *
8024  * Moves an actor by the specified distance relative to its current
8025  * position in pixels.
8026  *
8027  * This function modifies the fixed position of an actor and thus removes
8028  * it from any layout management. Another way to move an actor is with an
8029  * anchor point, see clutter_actor_set_anchor_point().
8030  *
8031  * Since: 0.2
8032  */
8033 void
8034 clutter_actor_move_by (ClutterActor *self,
8035                        gfloat        dx,
8036                        gfloat        dy)
8037 {
8038   const ClutterLayoutInfo *info;
8039   gfloat x, y;
8040
8041   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8042
8043   info = _clutter_actor_get_layout_info_or_defaults (self);
8044   x = info->fixed_x;
8045   y = info->fixed_y;
8046
8047   clutter_actor_set_position (self, x + dx, y + dy);
8048 }
8049
8050 static void
8051 clutter_actor_set_min_width (ClutterActor *self,
8052                              gfloat        min_width)
8053 {
8054   ClutterActorPrivate *priv = self->priv;
8055   ClutterActorBox old = { 0, };
8056   ClutterLayoutInfo *info;
8057
8058   /* if we are setting the size on a top-level actor and the
8059    * backend only supports static top-levels (e.g. framebuffers)
8060    * then we ignore the passed value and we override it with
8061    * the stage implementation's preferred size.
8062    */
8063   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8064       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8065     return;
8066
8067   info = _clutter_actor_get_layout_info (self);
8068
8069   if (priv->min_width_set && min_width == info->min_width)
8070     return;
8071
8072   g_object_freeze_notify (G_OBJECT (self));
8073
8074   clutter_actor_store_old_geometry (self, &old);
8075
8076   info->min_width = min_width;
8077   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8078   clutter_actor_set_min_width_set (self, TRUE);
8079
8080   clutter_actor_notify_if_geometry_changed (self, &old);
8081
8082   g_object_thaw_notify (G_OBJECT (self));
8083
8084   clutter_actor_queue_relayout (self);
8085 }
8086
8087 static void
8088 clutter_actor_set_min_height (ClutterActor *self,
8089                               gfloat        min_height)
8090
8091 {
8092   ClutterActorPrivate *priv = self->priv;
8093   ClutterActorBox old = { 0, };
8094   ClutterLayoutInfo *info;
8095
8096   /* if we are setting the size on a top-level actor and the
8097    * backend only supports static top-levels (e.g. framebuffers)
8098    * then we ignore the passed value and we override it with
8099    * the stage implementation's preferred size.
8100    */
8101   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8102       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8103     return;
8104
8105   info = _clutter_actor_get_layout_info (self);
8106
8107   if (priv->min_height_set && min_height == info->min_height)
8108     return;
8109
8110   g_object_freeze_notify (G_OBJECT (self));
8111
8112   clutter_actor_store_old_geometry (self, &old);
8113
8114   info->min_height = min_height;
8115   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8116   clutter_actor_set_min_height_set (self, TRUE);
8117
8118   clutter_actor_notify_if_geometry_changed (self, &old);
8119
8120   g_object_thaw_notify (G_OBJECT (self));
8121
8122   clutter_actor_queue_relayout (self);
8123 }
8124
8125 static void
8126 clutter_actor_set_natural_width (ClutterActor *self,
8127                                  gfloat        natural_width)
8128 {
8129   ClutterActorPrivate *priv = self->priv;
8130   ClutterActorBox old = { 0, };
8131   ClutterLayoutInfo *info;
8132
8133   /* if we are setting the size on a top-level actor and the
8134    * backend only supports static top-levels (e.g. framebuffers)
8135    * then we ignore the passed value and we override it with
8136    * the stage implementation's preferred size.
8137    */
8138   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8139       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8140     return;
8141
8142   info = _clutter_actor_get_layout_info (self);
8143
8144   if (priv->natural_width_set && natural_width == info->natural_width)
8145     return;
8146
8147   g_object_freeze_notify (G_OBJECT (self));
8148
8149   clutter_actor_store_old_geometry (self, &old);
8150
8151   info->natural_width = natural_width;
8152   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8153   clutter_actor_set_natural_width_set (self, TRUE);
8154
8155   clutter_actor_notify_if_geometry_changed (self, &old);
8156
8157   g_object_thaw_notify (G_OBJECT (self));
8158
8159   clutter_actor_queue_relayout (self);
8160 }
8161
8162 static void
8163 clutter_actor_set_natural_height (ClutterActor *self,
8164                                   gfloat        natural_height)
8165 {
8166   ClutterActorPrivate *priv = self->priv;
8167   ClutterActorBox old = { 0, };
8168   ClutterLayoutInfo *info;
8169
8170   /* if we are setting the size on a top-level actor and the
8171    * backend only supports static top-levels (e.g. framebuffers)
8172    * then we ignore the passed value and we override it with
8173    * the stage implementation's preferred size.
8174    */
8175   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8176       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8177     return;
8178
8179   info = _clutter_actor_get_layout_info (self);
8180
8181   if (priv->natural_height_set && natural_height == info->natural_height)
8182     return;
8183
8184   g_object_freeze_notify (G_OBJECT (self));
8185
8186   clutter_actor_store_old_geometry (self, &old);
8187
8188   info->natural_height = natural_height;
8189   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8190   clutter_actor_set_natural_height_set (self, TRUE);
8191
8192   clutter_actor_notify_if_geometry_changed (self, &old);
8193
8194   g_object_thaw_notify (G_OBJECT (self));
8195
8196   clutter_actor_queue_relayout (self);
8197 }
8198
8199 static void
8200 clutter_actor_set_min_width_set (ClutterActor *self,
8201                                  gboolean      use_min_width)
8202 {
8203   ClutterActorPrivate *priv = self->priv;
8204   ClutterActorBox old = { 0, };
8205
8206   if (priv->min_width_set == (use_min_width != FALSE))
8207     return;
8208
8209   clutter_actor_store_old_geometry (self, &old);
8210
8211   priv->min_width_set = use_min_width != FALSE;
8212   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8213
8214   clutter_actor_notify_if_geometry_changed (self, &old);
8215
8216   clutter_actor_queue_relayout (self);
8217 }
8218
8219 static void
8220 clutter_actor_set_min_height_set (ClutterActor *self,
8221                                   gboolean      use_min_height)
8222 {
8223   ClutterActorPrivate *priv = self->priv;
8224   ClutterActorBox old = { 0, };
8225
8226   if (priv->min_height_set == (use_min_height != FALSE))
8227     return;
8228
8229   clutter_actor_store_old_geometry (self, &old);
8230
8231   priv->min_height_set = use_min_height != FALSE;
8232   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8233
8234   clutter_actor_notify_if_geometry_changed (self, &old);
8235
8236   clutter_actor_queue_relayout (self);
8237 }
8238
8239 static void
8240 clutter_actor_set_natural_width_set (ClutterActor *self,
8241                                      gboolean      use_natural_width)
8242 {
8243   ClutterActorPrivate *priv = self->priv;
8244   ClutterActorBox old = { 0, };
8245
8246   if (priv->natural_width_set == (use_natural_width != FALSE))
8247     return;
8248
8249   clutter_actor_store_old_geometry (self, &old);
8250
8251   priv->natural_width_set = use_natural_width != FALSE;
8252   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8253
8254   clutter_actor_notify_if_geometry_changed (self, &old);
8255
8256   clutter_actor_queue_relayout (self);
8257 }
8258
8259 static void
8260 clutter_actor_set_natural_height_set (ClutterActor *self,
8261                                       gboolean      use_natural_height)
8262 {
8263   ClutterActorPrivate *priv = self->priv;
8264   ClutterActorBox old = { 0, };
8265
8266   if (priv->natural_height_set == (use_natural_height != FALSE))
8267     return;
8268
8269   clutter_actor_store_old_geometry (self, &old);
8270
8271   priv->natural_height_set = use_natural_height != FALSE;
8272   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8273
8274   clutter_actor_notify_if_geometry_changed (self, &old);
8275
8276   clutter_actor_queue_relayout (self);
8277 }
8278
8279 /**
8280  * clutter_actor_set_request_mode:
8281  * @self: a #ClutterActor
8282  * @mode: the request mode
8283  *
8284  * Sets the geometry request mode of @self.
8285  *
8286  * The @mode determines the order for invoking
8287  * clutter_actor_get_preferred_width() and
8288  * clutter_actor_get_preferred_height()
8289  *
8290  * Since: 1.2
8291  */
8292 void
8293 clutter_actor_set_request_mode (ClutterActor       *self,
8294                                 ClutterRequestMode  mode)
8295 {
8296   ClutterActorPrivate *priv;
8297
8298   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8299
8300   priv = self->priv;
8301
8302   if (priv->request_mode == mode)
8303     return;
8304
8305   priv->request_mode = mode;
8306
8307   priv->needs_width_request = TRUE;
8308   priv->needs_height_request = TRUE;
8309
8310   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8311
8312   clutter_actor_queue_relayout (self);
8313 }
8314
8315 /**
8316  * clutter_actor_get_request_mode:
8317  * @self: a #ClutterActor
8318  *
8319  * Retrieves the geometry request mode of @self
8320  *
8321  * Return value: the request mode for the actor
8322  *
8323  * Since: 1.2
8324  */
8325 ClutterRequestMode
8326 clutter_actor_get_request_mode (ClutterActor *self)
8327 {
8328   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8329                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8330
8331   return self->priv->request_mode;
8332 }
8333
8334 /* variant of set_width() without checks and without notification
8335  * freeze+thaw, for internal usage only
8336  */
8337 static inline void
8338 clutter_actor_set_width_internal (ClutterActor *self,
8339                                   gfloat        width)
8340 {
8341   if (width >= 0)
8342     {
8343       /* the Stage will use the :min-width to control the minimum
8344        * width to be resized to, so we should not be setting it
8345        * along with the :natural-width
8346        */
8347       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8348         clutter_actor_set_min_width (self, width);
8349
8350       clutter_actor_set_natural_width (self, width);
8351     }
8352   else
8353     {
8354       /* we only unset the :natural-width for the Stage */
8355       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8356         clutter_actor_set_min_width_set (self, FALSE);
8357
8358       clutter_actor_set_natural_width_set (self, FALSE);
8359     }
8360 }
8361
8362 /* variant of set_height() without checks and without notification
8363  * freeze+thaw, for internal usage only
8364  */
8365 static inline void
8366 clutter_actor_set_height_internal (ClutterActor *self,
8367                                    gfloat        height)
8368 {
8369   if (height >= 0)
8370     {
8371       /* see the comment above in set_width_internal() */
8372       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8373         clutter_actor_set_min_height (self, height);
8374
8375       clutter_actor_set_natural_height (self, height);
8376     }
8377   else
8378     {
8379       /* see the comment above in set_width_internal() */
8380       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8381         clutter_actor_set_min_height_set (self, FALSE);
8382
8383       clutter_actor_set_natural_height_set (self, FALSE);
8384     }
8385 }
8386
8387 /**
8388  * clutter_actor_set_size
8389  * @self: A #ClutterActor
8390  * @width: New width of actor in pixels, or -1
8391  * @height: New height of actor in pixels, or -1
8392  *
8393  * Sets the actor's size request in pixels. This overrides any
8394  * "normal" size request the actor would have. For example
8395  * a text actor might normally request the size of the text;
8396  * this function would force a specific size instead.
8397  *
8398  * If @width and/or @height are -1 the actor will use its
8399  * "normal" size request instead of overriding it, i.e.
8400  * you can "unset" the size with -1.
8401  *
8402  * This function sets or unsets both the minimum and natural size.
8403  */
8404 void
8405 clutter_actor_set_size (ClutterActor *self,
8406                         gfloat        width,
8407                         gfloat        height)
8408 {
8409   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8410
8411   g_object_freeze_notify (G_OBJECT (self));
8412
8413   clutter_actor_set_width_internal (self, width);
8414   clutter_actor_set_height_internal (self, height);
8415
8416   g_object_thaw_notify (G_OBJECT (self));
8417 }
8418
8419 /**
8420  * clutter_actor_get_size:
8421  * @self: A #ClutterActor
8422  * @width: (out) (allow-none): return location for the width, or %NULL.
8423  * @height: (out) (allow-none): return location for the height, or %NULL.
8424  *
8425  * This function tries to "do what you mean" and return
8426  * the size an actor will have. If the actor has a valid
8427  * allocation, the allocation will be returned; otherwise,
8428  * the actors natural size request will be returned.
8429  *
8430  * If you care whether you get the request vs. the allocation, you
8431  * should probably call a different function like
8432  * clutter_actor_get_allocation_box() or
8433  * clutter_actor_get_preferred_width().
8434  *
8435  * Since: 0.2
8436  */
8437 void
8438 clutter_actor_get_size (ClutterActor *self,
8439                         gfloat       *width,
8440                         gfloat       *height)
8441 {
8442   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8443
8444   if (width)
8445     *width = clutter_actor_get_width (self);
8446
8447   if (height)
8448     *height = clutter_actor_get_height (self);
8449 }
8450
8451 /**
8452  * clutter_actor_get_position:
8453  * @self: a #ClutterActor
8454  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8455  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8456  *
8457  * This function tries to "do what you mean" and tell you where the
8458  * actor is, prior to any transformations. Retrieves the fixed
8459  * position of an actor in pixels, if one has been set; otherwise, if
8460  * the allocation is valid, returns the actor's allocated position;
8461  * otherwise, returns 0,0.
8462  *
8463  * The returned position is in pixels.
8464  *
8465  * Since: 0.6
8466  */
8467 void
8468 clutter_actor_get_position (ClutterActor *self,
8469                             gfloat       *x,
8470                             gfloat       *y)
8471 {
8472   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8473
8474   if (x)
8475     *x = clutter_actor_get_x (self);
8476
8477   if (y)
8478     *y = clutter_actor_get_y (self);
8479 }
8480
8481 /**
8482  * clutter_actor_get_transformed_position:
8483  * @self: A #ClutterActor
8484  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8485  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8486  *
8487  * Gets the absolute position of an actor, in pixels relative to the stage.
8488  *
8489  * Since: 0.8
8490  */
8491 void
8492 clutter_actor_get_transformed_position (ClutterActor *self,
8493                                         gfloat       *x,
8494                                         gfloat       *y)
8495 {
8496   ClutterVertex v1;
8497   ClutterVertex v2;
8498
8499   v1.x = v1.y = v1.z = 0;
8500   clutter_actor_apply_transform_to_point (self, &v1, &v2);
8501
8502   if (x)
8503     *x = v2.x;
8504
8505   if (y)
8506     *y = v2.y;
8507 }
8508
8509 /**
8510  * clutter_actor_get_transformed_size:
8511  * @self: A #ClutterActor
8512  * @width: (out) (allow-none): return location for the width, or %NULL
8513  * @height: (out) (allow-none): return location for the height, or %NULL
8514  *
8515  * Gets the absolute size of an actor in pixels, taking into account the
8516  * scaling factors.
8517  *
8518  * If the actor has a valid allocation, the allocated size will be used.
8519  * If the actor has not a valid allocation then the preferred size will
8520  * be transformed and returned.
8521  *
8522  * If you want the transformed allocation, see
8523  * clutter_actor_get_abs_allocation_vertices() instead.
8524  *
8525  * <note>When the actor (or one of its ancestors) is rotated around the
8526  * X or Y axis, it no longer appears as on the stage as a rectangle, but
8527  * as a generic quadrangle; in that case this function returns the size
8528  * of the smallest rectangle that encapsulates the entire quad. Please
8529  * note that in this case no assumptions can be made about the relative
8530  * position of this envelope to the absolute position of the actor, as
8531  * returned by clutter_actor_get_transformed_position(); if you need this
8532  * information, you need to use clutter_actor_get_abs_allocation_vertices()
8533  * to get the coords of the actual quadrangle.</note>
8534  *
8535  * Since: 0.8
8536  */
8537 void
8538 clutter_actor_get_transformed_size (ClutterActor *self,
8539                                     gfloat       *width,
8540                                     gfloat       *height)
8541 {
8542   ClutterActorPrivate *priv;
8543   ClutterVertex v[4];
8544   gfloat x_min, x_max, y_min, y_max;
8545   gint i;
8546
8547   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8548
8549   priv = self->priv;
8550
8551   /* if the actor hasn't been allocated yet, get the preferred
8552    * size and transform that
8553    */
8554   if (priv->needs_allocation)
8555     {
8556       gfloat natural_width, natural_height;
8557       ClutterActorBox box;
8558
8559       /* Make a fake allocation to transform.
8560        *
8561        * NB: _clutter_actor_transform_and_project_box expects a box in
8562        * the actor's coordinate space... */
8563
8564       box.x1 = 0;
8565       box.y1 = 0;
8566
8567       natural_width = natural_height = 0;
8568       clutter_actor_get_preferred_size (self, NULL, NULL,
8569                                         &natural_width,
8570                                         &natural_height);
8571
8572       box.x2 = natural_width;
8573       box.y2 = natural_height;
8574
8575       _clutter_actor_transform_and_project_box (self, &box, v);
8576     }
8577   else
8578     clutter_actor_get_abs_allocation_vertices (self, v);
8579
8580   x_min = x_max = v[0].x;
8581   y_min = y_max = v[0].y;
8582
8583   for (i = 1; i < G_N_ELEMENTS (v); ++i)
8584     {
8585       if (v[i].x < x_min)
8586         x_min = v[i].x;
8587
8588       if (v[i].x > x_max)
8589         x_max = v[i].x;
8590
8591       if (v[i].y < y_min)
8592         y_min = v[i].y;
8593
8594       if (v[i].y > y_max)
8595         y_max = v[i].y;
8596     }
8597
8598   if (width)
8599     *width  = x_max - x_min;
8600
8601   if (height)
8602     *height = y_max - y_min;
8603 }
8604
8605 /**
8606  * clutter_actor_get_width:
8607  * @self: A #ClutterActor
8608  *
8609  * Retrieves the width of a #ClutterActor.
8610  *
8611  * If the actor has a valid allocation, this function will return the
8612  * width of the allocated area given to the actor.
8613  *
8614  * If the actor does not have a valid allocation, this function will
8615  * return the actor's natural width, that is the preferred width of
8616  * the actor.
8617  *
8618  * If you care whether you get the preferred width or the width that
8619  * has been assigned to the actor, you should probably call a different
8620  * function like clutter_actor_get_allocation_box() to retrieve the
8621  * allocated size or clutter_actor_get_preferred_width() to retrieve the
8622  * preferred width.
8623  *
8624  * If an actor has a fixed width, for instance a width that has been
8625  * assigned using clutter_actor_set_width(), the width returned will
8626  * be the same value.
8627  *
8628  * Return value: the width of the actor, in pixels
8629  */
8630 gfloat
8631 clutter_actor_get_width (ClutterActor *self)
8632 {
8633   ClutterActorPrivate *priv;
8634
8635   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8636
8637   priv = self->priv;
8638
8639   if (priv->needs_allocation)
8640     {
8641       gfloat natural_width = 0;
8642
8643       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8644         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8645       else
8646         {
8647           gfloat natural_height = 0;
8648
8649           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8650           clutter_actor_get_preferred_width (self, natural_height,
8651                                              NULL,
8652                                              &natural_width);
8653         }
8654
8655       return natural_width;
8656     }
8657   else
8658     return priv->allocation.x2 - priv->allocation.x1;
8659 }
8660
8661 /**
8662  * clutter_actor_get_height:
8663  * @self: A #ClutterActor
8664  *
8665  * Retrieves the height of a #ClutterActor.
8666  *
8667  * If the actor has a valid allocation, this function will return the
8668  * height of the allocated area given to the actor.
8669  *
8670  * If the actor does not have a valid allocation, this function will
8671  * return the actor's natural height, that is the preferred height of
8672  * the actor.
8673  *
8674  * If you care whether you get the preferred height or the height that
8675  * has been assigned to the actor, you should probably call a different
8676  * function like clutter_actor_get_allocation_box() to retrieve the
8677  * allocated size or clutter_actor_get_preferred_height() to retrieve the
8678  * preferred height.
8679  *
8680  * If an actor has a fixed height, for instance a height that has been
8681  * assigned using clutter_actor_set_height(), the height returned will
8682  * be the same value.
8683  *
8684  * Return value: the height of the actor, in pixels
8685  */
8686 gfloat
8687 clutter_actor_get_height (ClutterActor *self)
8688 {
8689   ClutterActorPrivate *priv;
8690
8691   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8692
8693   priv = self->priv;
8694
8695   if (priv->needs_allocation)
8696     {
8697       gfloat natural_height = 0;
8698
8699       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8700         {
8701           gfloat natural_width = 0;
8702
8703           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8704           clutter_actor_get_preferred_height (self, natural_width,
8705                                               NULL, &natural_height);
8706         }
8707       else
8708         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8709
8710       return natural_height;
8711     }
8712   else
8713     return priv->allocation.y2 - priv->allocation.y1;
8714 }
8715
8716 /**
8717  * clutter_actor_set_width
8718  * @self: A #ClutterActor
8719  * @width: Requested new width for the actor, in pixels, or -1
8720  *
8721  * Forces a width on an actor, causing the actor's preferred width
8722  * and height (if any) to be ignored.
8723  *
8724  * If @width is -1 the actor will use its preferred width request
8725  * instead of overriding it, i.e. you can "unset" the width with -1.
8726  *
8727  * This function sets both the minimum and natural size of the actor.
8728  *
8729  * since: 0.2
8730  */
8731 void
8732 clutter_actor_set_width (ClutterActor *self,
8733                          gfloat        width)
8734 {
8735   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8736
8737   g_object_freeze_notify (G_OBJECT (self));
8738
8739   clutter_actor_set_width_internal (self, width);
8740
8741   g_object_thaw_notify (G_OBJECT (self));
8742 }
8743
8744 /**
8745  * clutter_actor_set_height
8746  * @self: A #ClutterActor
8747  * @height: Requested new height for the actor, in pixels, or -1
8748  *
8749  * Forces a height on an actor, causing the actor's preferred width
8750  * and height (if any) to be ignored.
8751  *
8752  * If @height is -1 the actor will use its preferred height instead of
8753  * overriding it, i.e. you can "unset" the height with -1.
8754  *
8755  * This function sets both the minimum and natural size of the actor.
8756  *
8757  * since: 0.2
8758  */
8759 void
8760 clutter_actor_set_height (ClutterActor *self,
8761                           gfloat        height)
8762 {
8763   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8764
8765   g_object_freeze_notify (G_OBJECT (self));
8766
8767   clutter_actor_set_height_internal (self, height);
8768
8769   g_object_thaw_notify (G_OBJECT (self));
8770 }
8771
8772 /**
8773  * clutter_actor_set_x:
8774  * @self: a #ClutterActor
8775  * @x: the actor's position on the X axis
8776  *
8777  * Sets the actor's X coordinate, relative to its parent, in pixels.
8778  *
8779  * Overrides any layout manager and forces a fixed position for
8780  * the actor.
8781  *
8782  * Since: 0.6
8783  */
8784 void
8785 clutter_actor_set_x (ClutterActor *self,
8786                      gfloat        x)
8787 {
8788   ClutterActorBox old = { 0, };
8789   ClutterActorPrivate *priv;
8790   ClutterLayoutInfo *info;
8791
8792   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8793
8794   priv = self->priv;
8795
8796   info = _clutter_actor_get_layout_info (self);
8797
8798   if (priv->position_set && info->fixed_x == x)
8799     return;
8800
8801   clutter_actor_store_old_geometry (self, &old);
8802
8803   info->fixed_x = x;
8804   clutter_actor_set_fixed_position_set (self, TRUE);
8805
8806   clutter_actor_notify_if_geometry_changed (self, &old);
8807
8808   clutter_actor_queue_relayout (self);
8809 }
8810
8811 /**
8812  * clutter_actor_set_y:
8813  * @self: a #ClutterActor
8814  * @y: the actor's position on the Y axis
8815  *
8816  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
8817  *
8818  * Overrides any layout manager and forces a fixed position for
8819  * the actor.
8820  *
8821  * Since: 0.6
8822  */
8823 void
8824 clutter_actor_set_y (ClutterActor *self,
8825                      gfloat        y)
8826 {
8827   ClutterActorBox old = { 0, };
8828   ClutterActorPrivate *priv;
8829   ClutterLayoutInfo *info;
8830
8831   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8832
8833   priv = self->priv;
8834
8835   info = _clutter_actor_get_layout_info (self);
8836
8837   if (priv->position_set && info->fixed_y == y)
8838     return;
8839
8840   clutter_actor_store_old_geometry (self, &old);
8841
8842   info->fixed_y = y;
8843   clutter_actor_set_fixed_position_set (self, TRUE);
8844
8845   clutter_actor_notify_if_geometry_changed (self, &old);
8846
8847   clutter_actor_queue_relayout (self);
8848 }
8849
8850 /**
8851  * clutter_actor_get_x
8852  * @self: A #ClutterActor
8853  *
8854  * Retrieves the X coordinate of a #ClutterActor.
8855  *
8856  * This function tries to "do what you mean", by returning the
8857  * correct value depending on the actor's state.
8858  *
8859  * If the actor has a valid allocation, this function will return
8860  * the X coordinate of the origin of the allocation box.
8861  *
8862  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
8863  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8864  * function will return that coordinate.
8865  *
8866  * If both the allocation and a fixed position are missing, this function
8867  * will return 0.
8868  *
8869  * Return value: the X coordinate, in pixels, ignoring any
8870  *   transformation (i.e. scaling, rotation)
8871  */
8872 gfloat
8873 clutter_actor_get_x (ClutterActor *self)
8874 {
8875   ClutterActorPrivate *priv;
8876
8877   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8878
8879   priv = self->priv;
8880
8881   if (priv->needs_allocation)
8882     {
8883       if (priv->position_set)
8884         {
8885           const ClutterLayoutInfo *info;
8886
8887           info = _clutter_actor_get_layout_info_or_defaults (self);
8888
8889           return info->fixed_x;
8890         }
8891       else
8892         return 0;
8893     }
8894   else
8895     return priv->allocation.x1;
8896 }
8897
8898 /**
8899  * clutter_actor_get_y
8900  * @self: A #ClutterActor
8901  *
8902  * Retrieves the Y coordinate of a #ClutterActor.
8903  *
8904  * This function tries to "do what you mean", by returning the
8905  * correct value depending on the actor's state.
8906  *
8907  * If the actor has a valid allocation, this function will return
8908  * the Y coordinate of the origin of the allocation box.
8909  *
8910  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
8911  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8912  * function will return that coordinate.
8913  *
8914  * If both the allocation and a fixed position are missing, this function
8915  * will return 0.
8916  *
8917  * Return value: the Y coordinate, in pixels, ignoring any
8918  *   transformation (i.e. scaling, rotation)
8919  */
8920 gfloat
8921 clutter_actor_get_y (ClutterActor *self)
8922 {
8923   ClutterActorPrivate *priv;
8924
8925   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8926
8927   priv = self->priv;
8928
8929   if (priv->needs_allocation)
8930     {
8931       if (priv->position_set)
8932         {
8933           const ClutterLayoutInfo *info;
8934
8935           info = _clutter_actor_get_layout_info_or_defaults (self);
8936
8937           return info->fixed_y;
8938         }
8939       else
8940         return 0;
8941     }
8942   else
8943     return priv->allocation.y1;
8944 }
8945
8946 /**
8947  * clutter_actor_set_scale:
8948  * @self: A #ClutterActor
8949  * @scale_x: double factor to scale actor by horizontally.
8950  * @scale_y: double factor to scale actor by vertically.
8951  *
8952  * Scales an actor with the given factors. The scaling is relative to
8953  * the scale center and the anchor point. The scale center is
8954  * unchanged by this function and defaults to 0,0.
8955  *
8956  * Since: 0.2
8957  */
8958 void
8959 clutter_actor_set_scale (ClutterActor *self,
8960                          gdouble       scale_x,
8961                          gdouble       scale_y)
8962 {
8963   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8964
8965   g_object_freeze_notify (G_OBJECT (self));
8966
8967   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
8968   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
8969
8970   g_object_thaw_notify (G_OBJECT (self));
8971 }
8972
8973 /**
8974  * clutter_actor_set_scale_full:
8975  * @self: A #ClutterActor
8976  * @scale_x: double factor to scale actor by horizontally.
8977  * @scale_y: double factor to scale actor by vertically.
8978  * @center_x: X coordinate of the center of the scale.
8979  * @center_y: Y coordinate of the center of the scale
8980  *
8981  * Scales an actor with the given factors around the given center
8982  * point. The center point is specified in pixels relative to the
8983  * anchor point (usually the top left corner of the actor).
8984  *
8985  * Since: 1.0
8986  */
8987 void
8988 clutter_actor_set_scale_full (ClutterActor *self,
8989                               gdouble       scale_x,
8990                               gdouble       scale_y,
8991                               gfloat        center_x,
8992                               gfloat        center_y)
8993 {
8994   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8995
8996   g_object_freeze_notify (G_OBJECT (self));
8997
8998   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
8999   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9000   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9001   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9002
9003   g_object_thaw_notify (G_OBJECT (self));
9004 }
9005
9006 /**
9007  * clutter_actor_set_scale_with_gravity:
9008  * @self: A #ClutterActor
9009  * @scale_x: double factor to scale actor by horizontally.
9010  * @scale_y: double factor to scale actor by vertically.
9011  * @gravity: the location of the scale center expressed as a compass
9012  * direction.
9013  *
9014  * Scales an actor with the given factors around the given
9015  * center point. The center point is specified as one of the compass
9016  * directions in #ClutterGravity. For example, setting it to north
9017  * will cause the top of the actor to remain unchanged and the rest of
9018  * the actor to expand left, right and downwards.
9019  *
9020  * Since: 1.0
9021  */
9022 void
9023 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9024                                       gdouble         scale_x,
9025                                       gdouble         scale_y,
9026                                       ClutterGravity  gravity)
9027 {
9028   ClutterTransformInfo *info;
9029   GObject *obj;
9030
9031   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9032
9033   obj = G_OBJECT (self);
9034
9035   g_object_freeze_notify (obj);
9036
9037   info = _clutter_actor_get_transform_info (self);
9038   info->scale_x = scale_x;
9039   info->scale_y = scale_y;
9040
9041   if (gravity == CLUTTER_GRAVITY_NONE)
9042     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9043   else
9044     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9045
9046   self->priv->transform_valid = FALSE;
9047
9048   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9049   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9050   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9051   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9052   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9053
9054   clutter_actor_queue_redraw (self);
9055
9056   g_object_thaw_notify (obj);
9057 }
9058
9059 /**
9060  * clutter_actor_get_scale:
9061  * @self: A #ClutterActor
9062  * @scale_x: (out) (allow-none): Location to store horizonal
9063  *   scale factor, or %NULL.
9064  * @scale_y: (out) (allow-none): Location to store vertical
9065  *   scale factor, or %NULL.
9066  *
9067  * Retrieves an actors scale factors.
9068  *
9069  * Since: 0.2
9070  */
9071 void
9072 clutter_actor_get_scale (ClutterActor *self,
9073                          gdouble      *scale_x,
9074                          gdouble      *scale_y)
9075 {
9076   const ClutterTransformInfo *info;
9077
9078   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9079
9080   info = _clutter_actor_get_transform_info_or_defaults (self);
9081
9082   if (scale_x)
9083     *scale_x = info->scale_x;
9084
9085   if (scale_y)
9086     *scale_y = info->scale_y;
9087 }
9088
9089 /**
9090  * clutter_actor_get_scale_center:
9091  * @self: A #ClutterActor
9092  * @center_x: (out) (allow-none): Location to store the X position
9093  *   of the scale center, or %NULL.
9094  * @center_y: (out) (allow-none): Location to store the Y position
9095  *   of the scale center, or %NULL.
9096  *
9097  * Retrieves the scale center coordinate in pixels relative to the top
9098  * left corner of the actor. If the scale center was specified using a
9099  * #ClutterGravity this will calculate the pixel offset using the
9100  * current size of the actor.
9101  *
9102  * Since: 1.0
9103  */
9104 void
9105 clutter_actor_get_scale_center (ClutterActor *self,
9106                                 gfloat       *center_x,
9107                                 gfloat       *center_y)
9108 {
9109   const ClutterTransformInfo *info;
9110
9111   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9112
9113   info = _clutter_actor_get_transform_info_or_defaults (self);
9114
9115   clutter_anchor_coord_get_units (self, &info->scale_center,
9116                                   center_x,
9117                                   center_y,
9118                                   NULL);
9119 }
9120
9121 /**
9122  * clutter_actor_get_scale_gravity:
9123  * @self: A #ClutterActor
9124  *
9125  * Retrieves the scale center as a compass direction. If the scale
9126  * center was specified in pixels or units this will return
9127  * %CLUTTER_GRAVITY_NONE.
9128  *
9129  * Return value: the scale gravity
9130  *
9131  * Since: 1.0
9132  */
9133 ClutterGravity
9134 clutter_actor_get_scale_gravity (ClutterActor *self)
9135 {
9136   const ClutterTransformInfo *info;
9137
9138   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9139
9140   info = _clutter_actor_get_transform_info_or_defaults (self);
9141
9142   return clutter_anchor_coord_get_gravity (&info->scale_center);
9143 }
9144
9145 /**
9146  * clutter_actor_set_opacity:
9147  * @self: A #ClutterActor
9148  * @opacity: New opacity value for the actor.
9149  *
9150  * Sets the actor's opacity, with zero being completely transparent and
9151  * 255 (0xff) being fully opaque.
9152  */
9153 void
9154 clutter_actor_set_opacity (ClutterActor *self,
9155                            guint8        opacity)
9156 {
9157   ClutterActorPrivate *priv;
9158
9159   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9160
9161   priv = self->priv;
9162
9163   if (priv->opacity != opacity)
9164     {
9165       priv->opacity = opacity;
9166
9167       /* Queue a redraw from the flatten effect so that it can use
9168          its cached image if available instead of having to redraw the
9169          actual actor. If it doesn't end up using the FBO then the
9170          effect is still able to continue the paint anyway. If there
9171          is no flatten effect yet then this is equivalent to queueing
9172          a full redraw */
9173       _clutter_actor_queue_redraw_full (self,
9174                                         0, /* flags */
9175                                         NULL, /* clip */
9176                                         priv->flatten_effect);
9177
9178       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9179     }
9180 }
9181
9182 /*
9183  * clutter_actor_get_paint_opacity_internal:
9184  * @self: a #ClutterActor
9185  *
9186  * Retrieves the absolute opacity of the actor, as it appears on the stage
9187  *
9188  * This function does not do type checks
9189  *
9190  * Return value: the absolute opacity of the actor
9191  */
9192 static guint8
9193 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9194 {
9195   ClutterActorPrivate *priv = self->priv;
9196   ClutterActor *parent;
9197
9198   /* override the top-level opacity to always be 255; even in
9199    * case of ClutterStage:use-alpha being TRUE we want the rest
9200    * of the scene to be painted
9201    */
9202   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9203     return 255;
9204
9205   if (priv->opacity_override >= 0)
9206     return priv->opacity_override;
9207
9208   parent = priv->parent;
9209
9210   /* Factor in the actual actors opacity with parents */
9211   if (parent != NULL)
9212     {
9213       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9214
9215       if (opacity != 0xff)
9216         return (opacity * priv->opacity) / 0xff;
9217     }
9218
9219   return priv->opacity;
9220
9221 }
9222
9223 /**
9224  * clutter_actor_get_paint_opacity:
9225  * @self: A #ClutterActor
9226  *
9227  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9228  *
9229  * This function traverses the hierarchy chain and composites the opacity of
9230  * the actor with that of its parents.
9231  *
9232  * This function is intended for subclasses to use in the paint virtual
9233  * function, to paint themselves with the correct opacity.
9234  *
9235  * Return value: The actor opacity value.
9236  *
9237  * Since: 0.8
9238  */
9239 guint8
9240 clutter_actor_get_paint_opacity (ClutterActor *self)
9241 {
9242   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9243
9244   return clutter_actor_get_paint_opacity_internal (self);
9245 }
9246
9247 /**
9248  * clutter_actor_get_opacity:
9249  * @self: a #ClutterActor
9250  *
9251  * Retrieves the opacity value of an actor, as set by
9252  * clutter_actor_set_opacity().
9253  *
9254  * For retrieving the absolute opacity of the actor inside a paint
9255  * virtual function, see clutter_actor_get_paint_opacity().
9256  *
9257  * Return value: the opacity of the actor
9258  */
9259 guint8
9260 clutter_actor_get_opacity (ClutterActor *self)
9261 {
9262   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9263
9264   return self->priv->opacity;
9265 }
9266
9267 /**
9268  * clutter_actor_set_offscreen_redirect:
9269  * @self: A #ClutterActor
9270  * @redirect: New offscreen redirect flags for the actor.
9271  *
9272  * Defines the circumstances where the actor should be redirected into
9273  * an offscreen image. The offscreen image is used to flatten the
9274  * actor into a single image while painting for two main reasons.
9275  * Firstly, when the actor is painted a second time without any of its
9276  * contents changing it can simply repaint the cached image without
9277  * descending further down the actor hierarchy. Secondly, it will make
9278  * the opacity look correct even if there are overlapping primitives
9279  * in the actor.
9280  *
9281  * Caching the actor could in some cases be a performance win and in
9282  * some cases be a performance lose so it is important to determine
9283  * which value is right for an actor before modifying this value. For
9284  * example, there is never any reason to flatten an actor that is just
9285  * a single texture (such as a #ClutterTexture) because it is
9286  * effectively already cached in an image so the offscreen would be
9287  * redundant. Also if the actor contains primitives that are far apart
9288  * with a large transparent area in the middle (such as a large
9289  * CluterGroup with a small actor in the top left and a small actor in
9290  * the bottom right) then the cached image will contain the entire
9291  * image of the large area and the paint will waste time blending all
9292  * of the transparent pixels in the middle.
9293  *
9294  * The default method of implementing opacity on a container simply
9295  * forwards on the opacity to all of the children. If the children are
9296  * overlapping then it will appear as if they are two separate glassy
9297  * objects and there will be a break in the color where they
9298  * overlap. By redirecting to an offscreen buffer it will be as if the
9299  * two opaque objects are combined into one and then made transparent
9300  * which is usually what is expected.
9301  *
9302  * The image below demonstrates the difference between redirecting and
9303  * not. The image shows two Clutter groups, each containing a red and
9304  * a green rectangle which overlap. The opacity on the group is set to
9305  * 128 (which is 50%). When the offscreen redirect is not used, the
9306  * red rectangle can be seen through the blue rectangle as if the two
9307  * rectangles were separately transparent. When the redirect is used
9308  * the group as a whole is transparent instead so the red rectangle is
9309  * not visible where they overlap.
9310  *
9311  * <figure id="offscreen-redirect">
9312  *   <title>Sample of using an offscreen redirect for transparency</title>
9313  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
9314  * </figure>
9315  *
9316  * The default value for this property is 0, so we effectively will
9317  * never redirect an actor offscreen by default. This means that there
9318  * are times that transparent actors may look glassy as described
9319  * above. The reason this is the default is because there is a
9320  * performance trade off between quality and performance here. In many
9321  * cases the default form of glassy opacity looks good enough, but if
9322  * it's not you will need to set the
9323  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9324  * redirection for opacity.
9325  *
9326  * Custom actors that don't contain any overlapping primitives are
9327  * recommended to override the has_overlaps() virtual to return %FALSE
9328  * for maximum efficiency.
9329  *
9330  * Since: 1.8
9331  */
9332 void
9333 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9334                                       ClutterOffscreenRedirect redirect)
9335 {
9336   ClutterActorPrivate *priv;
9337
9338   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9339
9340   priv = self->priv;
9341
9342   if (priv->offscreen_redirect != redirect)
9343     {
9344       priv->offscreen_redirect = redirect;
9345
9346       /* Queue a redraw from the effect so that it can use its cached
9347          image if available instead of having to redraw the actual
9348          actor. If it doesn't end up using the FBO then the effect is
9349          still able to continue the paint anyway. If there is no
9350          effect then this is equivalent to queuing a full redraw */
9351       _clutter_actor_queue_redraw_full (self,
9352                                         0, /* flags */
9353                                         NULL, /* clip */
9354                                         priv->flatten_effect);
9355
9356       g_object_notify_by_pspec (G_OBJECT (self),
9357                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
9358     }
9359 }
9360
9361 /**
9362  * clutter_actor_get_offscreen_redirect:
9363  * @self: a #ClutterActor
9364  *
9365  * Retrieves whether to redirect the actor to an offscreen buffer, as
9366  * set by clutter_actor_set_offscreen_redirect().
9367  *
9368  * Return value: the value of the offscreen-redirect property of the actor
9369  *
9370  * Since: 1.8
9371  */
9372 ClutterOffscreenRedirect
9373 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9374 {
9375   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9376
9377   return self->priv->offscreen_redirect;
9378 }
9379
9380 /**
9381  * clutter_actor_set_name:
9382  * @self: A #ClutterActor
9383  * @name: Textual tag to apply to actor
9384  *
9385  * Sets the given name to @self. The name can be used to identify
9386  * a #ClutterActor.
9387  */
9388 void
9389 clutter_actor_set_name (ClutterActor *self,
9390                         const gchar  *name)
9391 {
9392   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9393
9394   g_free (self->priv->name);
9395   self->priv->name = g_strdup (name);
9396
9397   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
9398 }
9399
9400 /**
9401  * clutter_actor_get_name:
9402  * @self: A #ClutterActor
9403  *
9404  * Retrieves the name of @self.
9405  *
9406  * Return value: the name of the actor, or %NULL. The returned string is
9407  *   owned by the actor and should not be modified or freed.
9408  */
9409 const gchar *
9410 clutter_actor_get_name (ClutterActor *self)
9411 {
9412   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9413
9414   return self->priv->name;
9415 }
9416
9417 /**
9418  * clutter_actor_get_gid:
9419  * @self: A #ClutterActor
9420  *
9421  * Retrieves the unique id for @self.
9422  *
9423  * Return value: Globally unique value for this object instance.
9424  *
9425  * Since: 0.6
9426  *
9427  * Deprecated: 1.8: The id is not used any longer.
9428  */
9429 guint32
9430 clutter_actor_get_gid (ClutterActor *self)
9431 {
9432   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9433
9434   return self->priv->id;
9435 }
9436
9437 /**
9438  * clutter_actor_set_depth:
9439  * @self: a #ClutterActor
9440  * @depth: Z co-ord
9441  *
9442  * Sets the Z coordinate of @self to @depth.
9443  *
9444  * The unit used by @depth is dependant on the perspective setup. See
9445  * also clutter_stage_set_perspective().
9446  */
9447 void
9448 clutter_actor_set_depth (ClutterActor *self,
9449                          gfloat        depth)
9450 {
9451   ClutterActorPrivate *priv;
9452
9453   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9454
9455   priv = self->priv;
9456
9457   if (priv->z != depth)
9458     {
9459       /* Sets Z value - XXX 2.0: should we invert? */
9460       priv->z = depth;
9461
9462       priv->transform_valid = FALSE;
9463
9464       /* FIXME - remove this crap; sadly, there are still containers
9465        * in Clutter that depend on this utter brain damage
9466        */
9467       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
9468
9469       clutter_actor_queue_redraw (self);
9470
9471       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
9472     }
9473 }
9474
9475 /**
9476  * clutter_actor_get_depth:
9477  * @self: a #ClutterActor
9478  *
9479  * Retrieves the depth of @self.
9480  *
9481  * Return value: the depth of the actor
9482  */
9483 gfloat
9484 clutter_actor_get_depth (ClutterActor *self)
9485 {
9486   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
9487
9488   return self->priv->z;
9489 }
9490
9491 /**
9492  * clutter_actor_set_rotation:
9493  * @self: a #ClutterActor
9494  * @axis: the axis of rotation
9495  * @angle: the angle of rotation
9496  * @x: X coordinate of the rotation center
9497  * @y: Y coordinate of the rotation center
9498  * @z: Z coordinate of the rotation center
9499  *
9500  * Sets the rotation angle of @self around the given axis.
9501  *
9502  * The rotation center coordinates used depend on the value of @axis:
9503  * <itemizedlist>
9504  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
9505  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
9506  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
9507  * </itemizedlist>
9508  *
9509  * The rotation coordinates are relative to the anchor point of the
9510  * actor, set using clutter_actor_set_anchor_point(). If no anchor
9511  * point is set, the upper left corner is assumed as the origin.
9512  *
9513  * Since: 0.8
9514  */
9515 void
9516 clutter_actor_set_rotation (ClutterActor      *self,
9517                             ClutterRotateAxis  axis,
9518                             gdouble            angle,
9519                             gfloat             x,
9520                             gfloat             y,
9521                             gfloat             z)
9522 {
9523   ClutterVertex v;
9524
9525   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9526
9527   v.x = x;
9528   v.y = y;
9529   v.z = z;
9530
9531   g_object_freeze_notify (G_OBJECT (self));
9532
9533   clutter_actor_set_rotation_angle_internal (self, axis, angle);
9534   clutter_actor_set_rotation_center_internal (self, axis, &v);
9535
9536   g_object_thaw_notify (G_OBJECT (self));
9537 }
9538
9539 /**
9540  * clutter_actor_set_z_rotation_from_gravity:
9541  * @self: a #ClutterActor
9542  * @angle: the angle of rotation
9543  * @gravity: the center point of the rotation
9544  *
9545  * Sets the rotation angle of @self around the Z axis using the center
9546  * point specified as a compass point. For example to rotate such that
9547  * the center of the actor remains static you can use
9548  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
9549  * will move accordingly.
9550  *
9551  * Since: 1.0
9552  */
9553 void
9554 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
9555                                            gdouble         angle,
9556                                            ClutterGravity  gravity)
9557 {
9558   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9559
9560   if (gravity == CLUTTER_GRAVITY_NONE)
9561     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
9562   else
9563     {
9564       GObject *obj = G_OBJECT (self);
9565       ClutterTransformInfo *info;
9566
9567       info = _clutter_actor_get_transform_info (self);
9568
9569       g_object_freeze_notify (obj);
9570
9571       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
9572
9573       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
9574       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
9575       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
9576
9577       g_object_thaw_notify (obj);
9578     }
9579 }
9580
9581 /**
9582  * clutter_actor_get_rotation:
9583  * @self: a #ClutterActor
9584  * @axis: the axis of rotation
9585  * @x: (out): return value for the X coordinate of the center of rotation
9586  * @y: (out): return value for the Y coordinate of the center of rotation
9587  * @z: (out): return value for the Z coordinate of the center of rotation
9588  *
9589  * Retrieves the angle and center of rotation on the given axis,
9590  * set using clutter_actor_set_rotation().
9591  *
9592  * Return value: the angle of rotation
9593  *
9594  * Since: 0.8
9595  */
9596 gdouble
9597 clutter_actor_get_rotation (ClutterActor      *self,
9598                             ClutterRotateAxis  axis,
9599                             gfloat            *x,
9600                             gfloat            *y,
9601                             gfloat            *z)
9602 {
9603   const ClutterTransformInfo *info;
9604   const AnchorCoord *anchor_coord;
9605   gdouble retval = 0;
9606
9607   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9608
9609   info = _clutter_actor_get_transform_info_or_defaults (self);
9610
9611   switch (axis)
9612     {
9613     case CLUTTER_X_AXIS:
9614       anchor_coord = &info->rx_center;
9615       retval = info->rx_angle;
9616       break;
9617
9618     case CLUTTER_Y_AXIS:
9619       anchor_coord = &info->ry_center;
9620       retval = info->ry_angle;
9621       break;
9622
9623     case CLUTTER_Z_AXIS:
9624       anchor_coord = &info->rz_center;
9625       retval = info->rz_angle;
9626       break;
9627
9628     default:
9629       anchor_coord = NULL;
9630       retval = 0.0;
9631       break;
9632     }
9633
9634   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
9635
9636   return retval;
9637 }
9638
9639 /**
9640  * clutter_actor_get_z_rotation_gravity:
9641  * @self: A #ClutterActor
9642  *
9643  * Retrieves the center for the rotation around the Z axis as a
9644  * compass direction. If the center was specified in pixels or units
9645  * this will return %CLUTTER_GRAVITY_NONE.
9646  *
9647  * Return value: the Z rotation center
9648  *
9649  * Since: 1.0
9650  */
9651 ClutterGravity
9652 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
9653 {
9654   const ClutterTransformInfo *info;
9655
9656   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
9657
9658   info = _clutter_actor_get_transform_info_or_defaults (self);
9659
9660   return clutter_anchor_coord_get_gravity (&info->rz_center);
9661 }
9662
9663 /**
9664  * clutter_actor_set_clip:
9665  * @self: A #ClutterActor
9666  * @xoff: X offset of the clip rectangle
9667  * @yoff: Y offset of the clip rectangle
9668  * @width: Width of the clip rectangle
9669  * @height: Height of the clip rectangle
9670  *
9671  * Sets clip area for @self. The clip area is always computed from the
9672  * upper left corner of the actor, even if the anchor point is set
9673  * otherwise.
9674  *
9675  * Since: 0.6
9676  */
9677 void
9678 clutter_actor_set_clip (ClutterActor *self,
9679                         gfloat        xoff,
9680                         gfloat        yoff,
9681                         gfloat        width,
9682                         gfloat        height)
9683 {
9684   ClutterActorPrivate *priv;
9685
9686   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9687
9688   priv = self->priv;
9689
9690   if (priv->has_clip &&
9691       priv->clip.x == xoff &&
9692       priv->clip.y == yoff &&
9693       priv->clip.width == width &&
9694       priv->clip.height == height)
9695     return;
9696
9697   priv->clip.x = xoff;
9698   priv->clip.y = yoff;
9699   priv->clip.width = width;
9700   priv->clip.height = height;
9701
9702   priv->has_clip = TRUE;
9703
9704   clutter_actor_queue_redraw (self);
9705
9706   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9707   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
9708 }
9709
9710 /**
9711  * clutter_actor_remove_clip
9712  * @self: A #ClutterActor
9713  *
9714  * Removes clip area from @self.
9715  */
9716 void
9717 clutter_actor_remove_clip (ClutterActor *self)
9718 {
9719   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9720
9721   if (!self->priv->has_clip)
9722     return;
9723
9724   self->priv->has_clip = FALSE;
9725
9726   clutter_actor_queue_redraw (self);
9727
9728   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9729 }
9730
9731 /**
9732  * clutter_actor_has_clip:
9733  * @self: a #ClutterActor
9734  *
9735  * Determines whether the actor has a clip area set or not.
9736  *
9737  * Return value: %TRUE if the actor has a clip area set.
9738  *
9739  * Since: 0.1.1
9740  */
9741 gboolean
9742 clutter_actor_has_clip (ClutterActor *self)
9743 {
9744   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9745
9746   return self->priv->has_clip;
9747 }
9748
9749 /**
9750  * clutter_actor_get_clip:
9751  * @self: a #ClutterActor
9752  * @xoff: (out) (allow-none): return location for the X offset of
9753  *   the clip rectangle, or %NULL
9754  * @yoff: (out) (allow-none): return location for the Y offset of
9755  *   the clip rectangle, or %NULL
9756  * @width: (out) (allow-none): return location for the width of
9757  *   the clip rectangle, or %NULL
9758  * @height: (out) (allow-none): return location for the height of
9759  *   the clip rectangle, or %NULL
9760  *
9761  * Gets the clip area for @self, if any is set
9762  *
9763  * Since: 0.6
9764  */
9765 void
9766 clutter_actor_get_clip (ClutterActor *self,
9767                         gfloat       *xoff,
9768                         gfloat       *yoff,
9769                         gfloat       *width,
9770                         gfloat       *height)
9771 {
9772   ClutterActorPrivate *priv;
9773
9774   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9775
9776   priv = self->priv;
9777
9778   if (!priv->has_clip)
9779     return;
9780
9781   if (xoff != NULL)
9782     *xoff = priv->clip.x;
9783
9784   if (yoff != NULL)
9785     *yoff = priv->clip.y;
9786
9787   if (width != NULL)
9788     *width = priv->clip.width;
9789
9790   if (height != NULL)
9791     *height = priv->clip.height;
9792 }
9793
9794 /**
9795  * clutter_actor_get_children:
9796  * @self: a #ClutterActor
9797  *
9798  * Retrieves the list of children of @self.
9799  *
9800  * Return value: (transfer container) (element-type ClutterActor): A newly
9801  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
9802  *   done.
9803  *
9804  * Since: 1.10
9805  */
9806 GList *
9807 clutter_actor_get_children (ClutterActor *self)
9808 {
9809   ClutterActor *iter;
9810   GList *res;
9811
9812   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9813
9814   /* we walk the list backward so that we can use prepend(),
9815    * which is O(1)
9816    */
9817   for (iter = self->priv->last_child, res = NULL;
9818        iter != NULL;
9819        iter = iter->priv->prev_sibling)
9820     {
9821       res = g_list_prepend (res, iter);
9822     }
9823
9824   return res;
9825 }
9826
9827 /*< private >
9828  * insert_child_at_depth:
9829  * @self: a #ClutterActor
9830  * @child: a #ClutterActor
9831  *
9832  * Inserts @child inside the list of children held by @self, using
9833  * the depth as the insertion criteria.
9834  *
9835  * This sadly makes the insertion not O(1), but we can keep the
9836  * list sorted so that the painters algorithm we use for painting
9837  * the children will work correctly.
9838  */
9839 static void
9840 insert_child_at_depth (ClutterActor *self,
9841                        ClutterActor *child,
9842                        gpointer      dummy G_GNUC_UNUSED)
9843 {
9844   ClutterActor *iter;
9845
9846   child->priv->parent = self;
9847
9848   /* special-case the first child */
9849   if (self->priv->n_children == 0)
9850     {
9851       self->priv->first_child = child;
9852       self->priv->last_child = child;
9853
9854       child->priv->next_sibling = NULL;
9855       child->priv->prev_sibling = NULL;
9856
9857       return;
9858     }
9859
9860   /* Find the right place to insert the child so that it will still be
9861      sorted and the child will be after all of the actors at the same
9862      dept */
9863   for (iter = self->priv->first_child;
9864        iter != NULL;
9865        iter = iter->priv->next_sibling)
9866     {
9867       if (iter->priv->z > child->priv->z)
9868         break;
9869     }
9870
9871   if (iter != NULL)
9872     {
9873       ClutterActor *tmp = iter->priv->prev_sibling;
9874
9875       if (tmp != NULL)
9876         tmp->priv->next_sibling = child;
9877
9878       /* Insert the node before the found one */
9879       child->priv->prev_sibling = iter->priv->prev_sibling;
9880       child->priv->next_sibling = iter;
9881       iter->priv->prev_sibling = child;
9882     }
9883   else
9884     {
9885       ClutterActor *tmp = self->priv->last_child;
9886
9887       if (tmp != NULL)
9888         tmp->priv->next_sibling = child;
9889
9890       /* insert the node at the end of the list */
9891       child->priv->prev_sibling = self->priv->last_child;
9892       child->priv->next_sibling = NULL;
9893     }
9894
9895   if (child->priv->prev_sibling == NULL)
9896     self->priv->first_child = child;
9897
9898   if (child->priv->next_sibling == NULL)
9899     self->priv->last_child = child;
9900 }
9901
9902 static void
9903 insert_child_at_index (ClutterActor *self,
9904                        ClutterActor *child,
9905                        gpointer      data_)
9906 {
9907   gint index_ = GPOINTER_TO_INT (data_);
9908
9909   child->priv->parent = self;
9910
9911   if (index_ == 0)
9912     {
9913       ClutterActor *tmp = self->priv->first_child;
9914
9915       if (tmp != NULL)
9916         tmp->priv->prev_sibling = child;
9917
9918       child->priv->prev_sibling = NULL;
9919       child->priv->next_sibling = tmp;
9920     }
9921   else if (index_ < 0)
9922     {
9923       ClutterActor *tmp = self->priv->last_child;
9924
9925       if (tmp != NULL)
9926         tmp->priv->next_sibling = child;
9927
9928       child->priv->prev_sibling = tmp;
9929       child->priv->next_sibling = NULL;
9930     }
9931   else
9932     {
9933       ClutterActor *iter;
9934       int i;
9935
9936       for (iter = self->priv->first_child, i = 0;
9937            iter != NULL;
9938            iter = iter->priv->next_sibling, i += 1)
9939         {
9940           if (index_ == i)
9941             {
9942               ClutterActor *tmp = iter->priv->prev_sibling;
9943
9944               child->priv->prev_sibling = tmp;
9945               child->priv->next_sibling = iter;
9946
9947               iter->priv->prev_sibling = child;
9948
9949               if (tmp != NULL)
9950                 tmp->priv->next_sibling = child;
9951
9952               break;
9953             }
9954         }
9955     }
9956
9957   if (child->priv->prev_sibling == NULL)
9958     self->priv->first_child = child;
9959
9960   if (child->priv->next_sibling == NULL)
9961     self->priv->last_child = child;
9962 }
9963
9964 static void
9965 insert_child_above (ClutterActor *self,
9966                     ClutterActor *child,
9967                     gpointer      data)
9968 {
9969   ClutterActor *sibling = data;
9970
9971   child->priv->parent = self;
9972
9973   if (sibling == NULL)
9974     sibling = self->priv->last_child;
9975
9976   child->priv->prev_sibling = sibling;
9977
9978   if (sibling != NULL)
9979     {
9980       ClutterActor *tmp = sibling->priv->next_sibling;
9981
9982       child->priv->next_sibling = tmp;
9983
9984       if (tmp != NULL)
9985         tmp->priv->prev_sibling = child;
9986
9987       sibling->priv->next_sibling = child;
9988     }
9989   else
9990     child->priv->next_sibling = NULL;
9991
9992   if (child->priv->prev_sibling == NULL)
9993     self->priv->first_child = child;
9994
9995   if (child->priv->next_sibling == NULL)
9996     self->priv->last_child = child;
9997 }
9998
9999 static void
10000 insert_child_below (ClutterActor *self,
10001                     ClutterActor *child,
10002                     gpointer      data)
10003 {
10004   ClutterActor *sibling = data;
10005
10006   child->priv->parent = self;
10007
10008   if (sibling == NULL)
10009     sibling = self->priv->first_child;
10010
10011   child->priv->next_sibling = sibling;
10012
10013   if (sibling != NULL)
10014     {
10015       ClutterActor *tmp = sibling->priv->prev_sibling;
10016
10017       child->priv->prev_sibling = tmp;
10018
10019       if (tmp != NULL)
10020         tmp->priv->next_sibling = child;
10021
10022       sibling->priv->prev_sibling = child;
10023     }
10024   else
10025     child->priv->prev_sibling = NULL;
10026
10027   if (child->priv->prev_sibling == NULL)
10028     self->priv->first_child = child;
10029
10030   if (child->priv->next_sibling == NULL)
10031     self->priv->last_child = child;
10032 }
10033
10034 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10035                                            ClutterActor *child,
10036                                            gpointer      data);
10037
10038 typedef enum {
10039   ADD_CHILD_CREATE_META       = 1 << 0,
10040   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10041   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10042   ADD_CHILD_CHECK_STATE       = 1 << 3,
10043   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10044
10045   /* default flags for public API */
10046   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10047                                ADD_CHILD_EMIT_PARENT_SET |
10048                                ADD_CHILD_EMIT_ACTOR_ADDED |
10049                                ADD_CHILD_CHECK_STATE |
10050                                ADD_CHILD_NOTIFY_FIRST_LAST,
10051
10052   /* flags for legacy/deprecated API */
10053   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10054                                ADD_CHILD_CHECK_STATE |
10055                                ADD_CHILD_NOTIFY_FIRST_LAST
10056 } ClutterActorAddChildFlags;
10057
10058 /*< private >
10059  * clutter_actor_add_child_internal:
10060  * @self: a #ClutterActor
10061  * @child: a #ClutterActor
10062  * @flags: control flags for actions
10063  * @add_func: delegate function
10064  * @data: (closure): data to pass to @add_func
10065  *
10066  * Adds @child to the list of children of @self.
10067  *
10068  * The actual insertion inside the list is delegated to @add_func: this
10069  * function will just set up the state, perform basic checks, and emit
10070  * signals.
10071  *
10072  * The @flags argument is used to perform additional operations.
10073  */
10074 static inline void
10075 clutter_actor_add_child_internal (ClutterActor              *self,
10076                                   ClutterActor              *child,
10077                                   ClutterActorAddChildFlags  flags,
10078                                   ClutterActorAddChildFunc   add_func,
10079                                   gpointer                   data)
10080 {
10081   ClutterTextDirection text_dir;
10082   gboolean create_meta;
10083   gboolean emit_parent_set, emit_actor_added;
10084   gboolean check_state;
10085   gboolean notify_first_last;
10086   ClutterActor *old_first_child, *old_last_child;
10087
10088   if (child->priv->parent != NULL)
10089     {
10090       g_warning ("Cannot set a parent on an actor which has a parent. "
10091                  "You must use clutter_actor_remove_child() first.");
10092       return;
10093     }
10094
10095   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10096     {
10097       g_warning ("Cannot set a parent on a toplevel actor\n");
10098       return;
10099     }
10100
10101   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10102     {
10103       g_warning ("Cannot set a parent currently being destroyed");
10104       return;
10105     }
10106
10107   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10108   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10109   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10110   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10111   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10112
10113   old_first_child = self->priv->first_child;
10114   old_last_child = self->priv->last_child;
10115
10116   if (create_meta)
10117     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10118
10119   g_object_ref_sink (child);
10120   child->priv->parent = NULL;
10121   child->priv->next_sibling = NULL;
10122   child->priv->prev_sibling = NULL;
10123
10124   /* delegate the actual insertion */
10125   add_func (self, child, data);
10126
10127   g_assert (child->priv->parent == self);
10128
10129   self->priv->n_children += 1;
10130
10131   self->priv->age += 1;
10132
10133   /* if push_internal() has been called then we automatically set
10134    * the flag on the actor
10135    */
10136   if (self->priv->internal_child)
10137     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10138
10139   /* clutter_actor_reparent() will emit ::parent-set for us */
10140   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10141     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10142
10143   if (check_state)
10144     {
10145       /* If parent is mapped or realized, we need to also be mapped or
10146        * realized once we're inside the parent.
10147        */
10148       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10149
10150       /* propagate the parent's text direction to the child */
10151       text_dir = clutter_actor_get_text_direction (self);
10152       clutter_actor_set_text_direction (child, text_dir);
10153     }
10154
10155   if (child->priv->show_on_set_parent)
10156     clutter_actor_show (child);
10157
10158   if (CLUTTER_ACTOR_IS_MAPPED (child))
10159     clutter_actor_queue_redraw (child);
10160
10161   /* maintain the invariant that if an actor needs layout,
10162    * its parents do as well
10163    */
10164   if (child->priv->needs_width_request ||
10165       child->priv->needs_height_request ||
10166       child->priv->needs_allocation)
10167     {
10168       /* we work around the short-circuiting we do
10169        * in clutter_actor_queue_relayout() since we
10170        * want to force a relayout
10171        */
10172       child->priv->needs_width_request = TRUE;
10173       child->priv->needs_height_request = TRUE;
10174       child->priv->needs_allocation = TRUE;
10175
10176       clutter_actor_queue_relayout (child->priv->parent);
10177     }
10178
10179   if (emit_actor_added)
10180     g_signal_emit_by_name (self, "actor-added", child);
10181
10182   if (notify_first_last)
10183     {
10184       if (old_first_child != self->priv->first_child)
10185         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10186
10187       if (old_last_child != self->priv->last_child)
10188         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10189     }
10190 }
10191
10192 /**
10193  * clutter_actor_add_child:
10194  * @self: a #ClutterActor
10195  * @child: a #ClutterActor
10196  *
10197  * Adds @child to the children of @self.
10198  *
10199  * This function will acquire a reference on @child that will only
10200  * be released when calling clutter_actor_remove_child().
10201  *
10202  * This function will take into consideration the #ClutterActor:depth
10203  * of @child, and will keep the list of children sorted.
10204  *
10205  * This function will emit the #ClutterContainer::actor-added signal
10206  * on @self.
10207  *
10208  * Since: 1.10
10209  */
10210 void
10211 clutter_actor_add_child (ClutterActor *self,
10212                          ClutterActor *child)
10213 {
10214   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10215   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10216   g_return_if_fail (self != child);
10217   g_return_if_fail (child->priv->parent == NULL);
10218
10219   clutter_actor_add_child_internal (self, child,
10220                                     ADD_CHILD_DEFAULT_FLAGS,
10221                                     insert_child_at_depth,
10222                                     NULL);
10223 }
10224
10225 /**
10226  * clutter_actor_insert_child_at_index:
10227  * @self: a #ClutterActor
10228  * @child: a #ClutterActor
10229  * @index_: the index
10230  *
10231  * Inserts @child into the list of children of @self, using the
10232  * given @index_.
10233  *
10234  * This function will acquire a reference on @child that will only
10235  * be released when calling clutter_actor_remove_child().
10236  *
10237  * This function will not take into consideration the #ClutterActor:depth
10238  * of @child.
10239  *
10240  * This function will emit the #ClutterContainer::actor-added signal
10241  * on @self.
10242  *
10243  * Since: 1.10
10244  */
10245 void
10246 clutter_actor_insert_child_at_index (ClutterActor *self,
10247                                      ClutterActor *child,
10248                                      gint          index_)
10249 {
10250   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10251   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10252   g_return_if_fail (self != child);
10253   g_return_if_fail (child->priv->parent == NULL);
10254
10255   clutter_actor_add_child_internal (self, child,
10256                                     ADD_CHILD_DEFAULT_FLAGS,
10257                                     insert_child_at_index,
10258                                     GINT_TO_POINTER (index_));
10259 }
10260
10261 /**
10262  * clutter_actor_insert_child_above:
10263  * @self: a #ClutterActor
10264  * @child: a #ClutterActor
10265  * @sibling: (allow-none): a child of @self, or %NULL
10266  *
10267  * Inserts @child into the list of children of @self, above another
10268  * child of @self or, if @sibling is %NULL, above all the children
10269  * of @self.
10270  *
10271  * This function will acquire a reference on @child that will only
10272  * be released when calling clutter_actor_remove_child().
10273  *
10274  * This function will not take into consideration the #ClutterActor:depth
10275  * of @child.
10276  *
10277  * This function will emit the #ClutterContainer::actor-added signal
10278  * on @self.
10279  *
10280  * Since: 1.10
10281  */
10282 void
10283 clutter_actor_insert_child_above (ClutterActor *self,
10284                                   ClutterActor *child,
10285                                   ClutterActor *sibling)
10286 {
10287   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10288   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10289   g_return_if_fail (self != child);
10290   g_return_if_fail (child != sibling);
10291   g_return_if_fail (child->priv->parent == NULL);
10292   g_return_if_fail (sibling == NULL ||
10293                     (CLUTTER_IS_ACTOR (sibling) &&
10294                      sibling->priv->parent == self));
10295
10296   clutter_actor_add_child_internal (self, child,
10297                                     ADD_CHILD_DEFAULT_FLAGS,
10298                                     insert_child_above,
10299                                     sibling);
10300 }
10301
10302 /**
10303  * clutter_actor_insert_child_below:
10304  * @self: a #ClutterActor
10305  * @child: a #ClutterActor
10306  * @sibling: (allow-none): a child of @self, or %NULL
10307  *
10308  * Inserts @child into the list of children of @self, below another
10309  * child of @self or, if @sibling is %NULL, below all the children
10310  * of @self.
10311  *
10312  * This function will acquire a reference on @child that will only
10313  * be released when calling clutter_actor_remove_child().
10314  *
10315  * This function will not take into consideration the #ClutterActor:depth
10316  * of @child.
10317  *
10318  * This function will emit the #ClutterContainer::actor-added signal
10319  * on @self.
10320  *
10321  * Since: 1.10
10322  */
10323 void
10324 clutter_actor_insert_child_below (ClutterActor *self,
10325                                   ClutterActor *child,
10326                                   ClutterActor *sibling)
10327 {
10328   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10329   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10330   g_return_if_fail (self != child);
10331   g_return_if_fail (child != sibling);
10332   g_return_if_fail (child->priv->parent == NULL);
10333   g_return_if_fail (sibling == NULL ||
10334                     (CLUTTER_IS_ACTOR (sibling) &&
10335                      sibling->priv->parent == self));
10336
10337   clutter_actor_add_child_internal (self, child,
10338                                     ADD_CHILD_DEFAULT_FLAGS,
10339                                     insert_child_below,
10340                                     sibling);
10341 }
10342
10343 /**
10344  * clutter_actor_set_parent:
10345  * @self: A #ClutterActor
10346  * @parent: A new #ClutterActor parent
10347  *
10348  * Sets the parent of @self to @parent.
10349  *
10350  * This function will result in @parent acquiring a reference on @self,
10351  * eventually by sinking its floating reference first. The reference
10352  * will be released by clutter_actor_unparent().
10353  *
10354  * This function should only be called by legacy #ClutterActor<!-- -->s
10355  * implementing the #ClutterContainer interface.
10356  *
10357  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
10358  */
10359 void
10360 clutter_actor_set_parent (ClutterActor *self,
10361                           ClutterActor *parent)
10362 {
10363   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10364   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
10365   g_return_if_fail (self != parent);
10366   g_return_if_fail (self->priv->parent == NULL);
10367
10368   /* as this function will be called inside ClutterContainer::add
10369    * implementations or when building up a composite actor, we have
10370    * to preserve the old behaviour, and not create child meta or
10371    * emit the ::actor-added signal, to avoid recursion or double
10372    * emissions
10373    */
10374   clutter_actor_add_child_internal (parent, self,
10375                                     ADD_CHILD_LEGACY_FLAGS,
10376                                     insert_child_at_depth,
10377                                     NULL);
10378 }
10379
10380 /**
10381  * clutter_actor_get_parent:
10382  * @self: A #ClutterActor
10383  *
10384  * Retrieves the parent of @self.
10385  *
10386  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
10387  *  if no parent is set
10388  */
10389 ClutterActor *
10390 clutter_actor_get_parent (ClutterActor *self)
10391 {
10392   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10393
10394   return self->priv->parent;
10395 }
10396
10397 /**
10398  * clutter_actor_get_paint_visibility:
10399  * @self: A #ClutterActor
10400  *
10401  * Retrieves the 'paint' visibility of an actor recursively checking for non
10402  * visible parents.
10403  *
10404  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
10405  *
10406  * Return Value: %TRUE if the actor is visibile and will be painted.
10407  *
10408  * Since: 0.8.4
10409  */
10410 gboolean
10411 clutter_actor_get_paint_visibility (ClutterActor *actor)
10412 {
10413   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
10414
10415   return CLUTTER_ACTOR_IS_MAPPED (actor);
10416 }
10417
10418 /**
10419  * clutter_actor_remove_child:
10420  * @self: a #ClutterActor
10421  * @child: a #ClutterActor
10422  *
10423  * Removes @child from the children of @self.
10424  *
10425  * This function will release the reference added by
10426  * clutter_actor_add_child(), so if you want to keep using @child
10427  * you will have to acquire a referenced on it before calling this
10428  * function.
10429  *
10430  * This function will emit the #ClutterContainer::actor-removed
10431  * signal on @self.
10432  *
10433  * Since: 1.10
10434  */
10435 void
10436 clutter_actor_remove_child (ClutterActor *self,
10437                             ClutterActor *child)
10438 {
10439   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10440   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10441   g_return_if_fail (self != child);
10442   g_return_if_fail (child->priv->parent != NULL);
10443   g_return_if_fail (child->priv->parent == self);
10444
10445   clutter_actor_remove_child_internal (self, child,
10446                                        REMOVE_CHILD_DEFAULT_FLAGS);
10447 }
10448
10449 /**
10450  * clutter_actor_remove_all_children:
10451  * @self: a #ClutterActor
10452  *
10453  * Removes all children of @self.
10454  *
10455  * This function releases the reference added by inserting a child actor
10456  * in the list of children of @self.
10457  *
10458  * Since: 1.10
10459  */
10460 void
10461 clutter_actor_remove_all_children (ClutterActor *self)
10462 {
10463   ClutterActor *iter;
10464
10465   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10466
10467   if (self->priv->n_children == 0)
10468     return;
10469
10470   iter = self->priv->first_child;
10471   while (iter != NULL)
10472     {
10473       ClutterActor *next = iter->priv->next_sibling;
10474
10475       clutter_actor_remove_child_internal (self, iter,
10476                                            REMOVE_CHILD_DEFAULT_FLAGS);
10477
10478       iter = next;
10479     }
10480
10481   g_assert (self->priv->first_child == NULL);
10482   g_assert (self->priv->last_child == NULL);
10483   g_assert (self->priv->n_children == 0);
10484 }
10485
10486 typedef struct _InsertBetweenData {
10487   ClutterActor *prev_sibling;
10488   ClutterActor *next_sibling;
10489 } InsertBetweenData;
10490
10491 static void
10492 insert_child_between (ClutterActor *self,
10493                       ClutterActor *child,
10494                       gpointer      data_)
10495 {
10496   InsertBetweenData *data = data_;
10497   ClutterActor *prev_sibling = data->prev_sibling;
10498   ClutterActor *next_sibling = data->next_sibling;
10499
10500   child->priv->parent = self;
10501   child->priv->prev_sibling = prev_sibling;
10502   child->priv->next_sibling = next_sibling;
10503
10504   if (prev_sibling != NULL)
10505     prev_sibling->priv->next_sibling = child;
10506
10507   if (next_sibling != NULL)
10508     next_sibling->priv->prev_sibling = child;
10509
10510   if (child->priv->prev_sibling == NULL)
10511     self->priv->first_child = child;
10512
10513   if (child->priv->next_sibling == NULL)
10514     self->priv->last_child = child;
10515 }
10516
10517 /**
10518  * clutter_actor_replace_child:
10519  * @self: a #ClutterActor
10520  * @old_child: the child of @self to replace
10521  * @new_child: the #ClutterActor to replace @old_child
10522  *
10523  * Replaces @old_child with @new_child in the list of children of @self.
10524  *
10525  * Since: 1.10
10526  */
10527 void
10528 clutter_actor_replace_child (ClutterActor *self,
10529                              ClutterActor *old_child,
10530                              ClutterActor *new_child)
10531 {
10532   ClutterActor *prev_sibling, *next_sibling;
10533   InsertBetweenData clos;
10534
10535   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10536   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
10537   g_return_if_fail (old_child->priv->parent == self);
10538   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
10539   g_return_if_fail (old_child != new_child);
10540   g_return_if_fail (new_child != self);
10541   g_return_if_fail (new_child->priv->parent == NULL);
10542
10543   prev_sibling = old_child->priv->prev_sibling;
10544   next_sibling = old_child->priv->next_sibling;
10545   clutter_actor_remove_child_internal (self, old_child,
10546                                        REMOVE_CHILD_DEFAULT_FLAGS);
10547
10548   clos.prev_sibling = prev_sibling;
10549   clos.next_sibling = next_sibling;
10550   clutter_actor_add_child_internal (self, new_child,
10551                                     ADD_CHILD_DEFAULT_FLAGS,
10552                                     insert_child_between,
10553                                     &clos);
10554 }
10555
10556 /**
10557  * clutter_actor_unparent:
10558  * @self: a #ClutterActor
10559  *
10560  * Removes the parent of @self.
10561  *
10562  * This will cause the parent of @self to release the reference
10563  * acquired when calling clutter_actor_set_parent(), so if you
10564  * want to keep @self you will have to acquire a reference of
10565  * your own, through g_object_ref().
10566  *
10567  * This function should only be called by legacy #ClutterActor<!-- -->s
10568  * implementing the #ClutterContainer interface.
10569  *
10570  * Since: 0.1.1
10571  *
10572  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
10573  */
10574 void
10575 clutter_actor_unparent (ClutterActor *self)
10576 {
10577   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10578
10579   if (self->priv->parent == NULL)
10580     return;
10581
10582   clutter_actor_remove_child_internal (self->priv->parent, self,
10583                                        REMOVE_CHILD_LEGACY_FLAGS);
10584 }
10585
10586 /**
10587  * clutter_actor_reparent:
10588  * @self: a #ClutterActor
10589  * @new_parent: the new #ClutterActor parent
10590  *
10591  * Resets the parent actor of @self.
10592  *
10593  * This function is logically equivalent to calling clutter_actor_unparent()
10594  * and clutter_actor_set_parent(), but more efficiently implemented, as it
10595  * ensures the child is not finalized when unparented, and emits the
10596  * #ClutterActor::parent-set signal only once.
10597  *
10598  * In reality, calling this function is less useful than it sounds, as some
10599  * application code may rely on changes in the intermediate state between
10600  * removal and addition of the actor from its old parent to the @new_parent.
10601  * Thus, it is strongly encouraged to avoid using this function in application
10602  * code.
10603  *
10604  * Since: 0.2
10605  *
10606  * Deprecated: 1.10: Use clutter_actor_remove_child() and
10607  *   clutter_actor_add_child() instead; remember to take a reference on
10608  *   the actor being removed before calling clutter_actor_remove_child()
10609  *   to avoid the reference count dropping to zero and the actor being
10610  *   destroyed.
10611  */
10612 void
10613 clutter_actor_reparent (ClutterActor *self,
10614                         ClutterActor *new_parent)
10615 {
10616   ClutterActorPrivate *priv;
10617
10618   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10619   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
10620   g_return_if_fail (self != new_parent);
10621
10622   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10623     {
10624       g_warning ("Cannot set a parent on a toplevel actor");
10625       return;
10626     }
10627
10628   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
10629     {
10630       g_warning ("Cannot set a parent currently being destroyed");
10631       return;
10632     }
10633
10634   priv = self->priv;
10635
10636   if (priv->parent != new_parent)
10637     {
10638       ClutterActor *old_parent;
10639
10640       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10641
10642       old_parent = priv->parent;
10643
10644       g_object_ref (self);
10645
10646       if (old_parent != NULL)
10647         {
10648          /* go through the Container implementation if this is a regular
10649           * child and not an internal one
10650           */
10651          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10652            {
10653              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
10654
10655              /* this will have to call unparent() */
10656              clutter_container_remove_actor (parent, self);
10657            }
10658          else
10659            clutter_actor_remove_child_internal (old_parent, self,
10660                                                 REMOVE_CHILD_LEGACY_FLAGS);
10661         }
10662
10663       /* Note, will call set_parent() */
10664       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10665         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
10666       else
10667         clutter_actor_add_child_internal (new_parent, self,
10668                                           ADD_CHILD_LEGACY_FLAGS,
10669                                           insert_child_at_depth,
10670                                           NULL);
10671
10672       /* we emit the ::parent-set signal once */
10673       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
10674
10675       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10676
10677       /* the IN_REPARENT flag suspends state updates */
10678       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
10679
10680       g_object_unref (self);
10681    }
10682 }
10683
10684 /**
10685  * clutter_actor_contains:
10686  * @self: A #ClutterActor
10687  * @descendant: A #ClutterActor, possibly contained in @self
10688  *
10689  * Determines if @descendant is contained inside @self (either as an
10690  * immediate child, or as a deeper descendant). If @self and
10691  * @descendant point to the same actor then it will also return %TRUE.
10692  *
10693  * Return value: whether @descendent is contained within @self
10694  *
10695  * Since: 1.4
10696  */
10697 gboolean
10698 clutter_actor_contains (ClutterActor *self,
10699                         ClutterActor *descendant)
10700 {
10701   ClutterActor *actor;
10702
10703   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10704   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
10705
10706   for (actor = descendant; actor; actor = actor->priv->parent)
10707     if (actor == self)
10708       return TRUE;
10709
10710   return FALSE;
10711 }
10712
10713 /**
10714  * clutter_actor_set_child_above_sibling:
10715  * @self: a #ClutterActor
10716  * @child: a #ClutterActor child of @self
10717  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10718  *
10719  * Sets @child to be above @sibling in the list of children of @self.
10720  *
10721  * If @sibling is %NULL, @child will be the new last child of @self.
10722  *
10723  * This function is logically equivalent to removing @child and using
10724  * clutter_actor_insert_child_above(), but it will not emit signals
10725  * or change state on @child.
10726  *
10727  * Since: 1.10
10728  */
10729 void
10730 clutter_actor_set_child_above_sibling (ClutterActor *self,
10731                                        ClutterActor *child,
10732                                        ClutterActor *sibling)
10733 {
10734   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10735   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10736   g_return_if_fail (child->priv->parent == self);
10737   g_return_if_fail (child != sibling);
10738   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10739
10740   if (sibling != NULL)
10741     g_return_if_fail (sibling->priv->parent == self);
10742
10743   /* we don't want to change the state of child, or emit signals, or
10744    * regenerate ChildMeta instances here, but we still want to follow
10745    * the correct sequence of steps encoded in remove_child() and
10746    * add_child(), so that correctness is ensured, and we only go
10747    * through one known code path.
10748    */
10749   g_object_ref (child);
10750   clutter_actor_remove_child_internal (self, child, 0);
10751   clutter_actor_add_child_internal (self, child,
10752                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10753                                     insert_child_above,
10754                                     sibling);
10755
10756   clutter_actor_queue_relayout (self);
10757 }
10758
10759 /**
10760  * clutter_actor_set_child_below_sibling:
10761  * @self: a #ClutterActor
10762  * @child: a #ClutterActor child of @self
10763  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10764  *
10765  * Sets @child to be below @sibling in the list of children of @self.
10766  *
10767  * If @sibling is %NULL, @child will be the new first child of @self.
10768  *
10769  * This function is logically equivalent to removing @self and using
10770  * clutter_actor_insert_child_below(), but it will not emit signals
10771  * or change state on @child.
10772  *
10773  * Since: 1.10
10774  */
10775 void
10776 clutter_actor_set_child_below_sibling (ClutterActor *self,
10777                                        ClutterActor *child,
10778                                        ClutterActor *sibling)
10779 {
10780   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10781   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10782   g_return_if_fail (child->priv->parent == self);
10783   g_return_if_fail (child != sibling);
10784   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10785
10786   if (sibling != NULL)
10787     g_return_if_fail (sibling->priv->parent == self);
10788
10789   /* see the comment in set_child_above_sibling() */
10790   g_object_ref (child);
10791   clutter_actor_remove_child_internal (self, child, 0);
10792   clutter_actor_add_child_internal (self, child,
10793                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10794                                     insert_child_below,
10795                                     sibling);
10796
10797   clutter_actor_queue_relayout (self);
10798 }
10799
10800 /**
10801  * clutter_actor_set_child_at_index:
10802  * @self: a #ClutterActor
10803  * @child: a #ClutterActor child of @self
10804  * @index_: the new index for @child
10805  *
10806  * Changes the index of @child in the list of children of @self.
10807  *
10808  * This function is logically equivalent to removing @child and
10809  * calling clutter_actor_insert_child_at_index(), but it will not
10810  * emit signals or change state on @child.
10811  *
10812  * Since: 1.10
10813  */
10814 void
10815 clutter_actor_set_child_at_index (ClutterActor *self,
10816                                   ClutterActor *child,
10817                                   gint          index_)
10818 {
10819   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10820   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10821   g_return_if_fail (child->priv->parent == self);
10822   g_return_if_fail (index_ <= self->priv->n_children);
10823
10824   g_object_ref (child);
10825   clutter_actor_remove_child_internal (self, child, 0);
10826   clutter_actor_add_child_internal (self, child,
10827                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10828                                     insert_child_at_index,
10829                                     GINT_TO_POINTER (index_));
10830
10831   clutter_actor_queue_relayout (self);
10832 }
10833
10834 /**
10835  * clutter_actor_raise:
10836  * @self: A #ClutterActor
10837  * @below: (allow-none): A #ClutterActor to raise above.
10838  *
10839  * Puts @self above @below.
10840  *
10841  * Both actors must have the same parent, and the parent must implement
10842  * the #ClutterContainer interface
10843  *
10844  * This function calls clutter_container_raise_child() internally.
10845  *
10846  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
10847  */
10848 void
10849 clutter_actor_raise (ClutterActor *self,
10850                      ClutterActor *below)
10851 {
10852   ClutterActor *parent;
10853
10854   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10855
10856   parent = clutter_actor_get_parent (self);
10857   if (parent == NULL)
10858     {
10859       g_warning ("%s: Actor '%s' is not inside a container",
10860                  G_STRFUNC,
10861                  _clutter_actor_get_debug_name (self));
10862       return;
10863     }
10864
10865   if (below != NULL)
10866     {
10867       if (parent != clutter_actor_get_parent (below))
10868         {
10869           g_warning ("%s Actor '%s' is not in the same container as "
10870                      "actor '%s'",
10871                      G_STRFUNC,
10872                      _clutter_actor_get_debug_name (self),
10873                      _clutter_actor_get_debug_name (below));
10874           return;
10875         }
10876     }
10877
10878   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
10879 }
10880
10881 /**
10882  * clutter_actor_lower:
10883  * @self: A #ClutterActor
10884  * @above: (allow-none): A #ClutterActor to lower below
10885  *
10886  * Puts @self below @above.
10887  *
10888  * Both actors must have the same parent, and the parent must implement
10889  * the #ClutterContainer interface.
10890  *
10891  * This function calls clutter_container_lower_child() internally.
10892  *
10893  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
10894  */
10895 void
10896 clutter_actor_lower (ClutterActor *self,
10897                      ClutterActor *above)
10898 {
10899   ClutterActor *parent;
10900
10901   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10902
10903   parent = clutter_actor_get_parent (self);
10904   if (parent == NULL)
10905     {
10906       g_warning ("%s: Actor of type %s is not inside a container",
10907                  G_STRFUNC,
10908                  _clutter_actor_get_debug_name (self));
10909       return;
10910     }
10911
10912   if (above)
10913     {
10914       if (parent != clutter_actor_get_parent (above))
10915         {
10916           g_warning ("%s: Actor '%s' is not in the same container as "
10917                      "actor '%s'",
10918                      G_STRFUNC,
10919                      _clutter_actor_get_debug_name (self),
10920                      _clutter_actor_get_debug_name (above));
10921           return;
10922         }
10923     }
10924
10925   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
10926 }
10927
10928 /**
10929  * clutter_actor_raise_top:
10930  * @self: A #ClutterActor
10931  *
10932  * Raises @self to the top.
10933  *
10934  * This function calls clutter_actor_raise() internally.
10935  *
10936  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
10937  *   a %NULL sibling, instead.
10938  */
10939 void
10940 clutter_actor_raise_top (ClutterActor *self)
10941 {
10942   clutter_actor_raise (self, NULL);
10943 }
10944
10945 /**
10946  * clutter_actor_lower_bottom:
10947  * @self: A #ClutterActor
10948  *
10949  * Lowers @self to the bottom.
10950  *
10951  * This function calls clutter_actor_lower() internally.
10952  *
10953  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
10954  *   a %NULL sibling, instead.
10955  */
10956 void
10957 clutter_actor_lower_bottom (ClutterActor *self)
10958 {
10959   clutter_actor_lower (self, NULL);
10960 }
10961
10962 /*
10963  * Event handling
10964  */
10965
10966 /**
10967  * clutter_actor_event:
10968  * @actor: a #ClutterActor
10969  * @event: a #ClutterEvent
10970  * @capture: TRUE if event in in capture phase, FALSE otherwise.
10971  *
10972  * This function is used to emit an event on the main stage.
10973  * You should rarely need to use this function, except for
10974  * synthetising events.
10975  *
10976  * Return value: the return value from the signal emission: %TRUE
10977  *   if the actor handled the event, or %FALSE if the event was
10978  *   not handled
10979  *
10980  * Since: 0.6
10981  */
10982 gboolean
10983 clutter_actor_event (ClutterActor *actor,
10984                      ClutterEvent *event,
10985                      gboolean      capture)
10986 {
10987   gboolean retval = FALSE;
10988   gint signal_num = -1;
10989
10990   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
10991   g_return_val_if_fail (event != NULL, FALSE);
10992
10993   g_object_ref (actor);
10994
10995   if (capture)
10996     {
10997       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
10998                      event,
10999                      &retval);
11000       goto out;
11001     }
11002
11003   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11004
11005   if (!retval)
11006     {
11007       switch (event->type)
11008         {
11009         case CLUTTER_NOTHING:
11010           break;
11011         case CLUTTER_BUTTON_PRESS:
11012           signal_num = BUTTON_PRESS_EVENT;
11013           break;
11014         case CLUTTER_BUTTON_RELEASE:
11015           signal_num = BUTTON_RELEASE_EVENT;
11016           break;
11017         case CLUTTER_SCROLL:
11018           signal_num = SCROLL_EVENT;
11019           break;
11020         case CLUTTER_KEY_PRESS:
11021           signal_num = KEY_PRESS_EVENT;
11022           break;
11023         case CLUTTER_KEY_RELEASE:
11024           signal_num = KEY_RELEASE_EVENT;
11025           break;
11026         case CLUTTER_MOTION:
11027           signal_num = MOTION_EVENT;
11028           break;
11029         case CLUTTER_ENTER:
11030           signal_num = ENTER_EVENT;
11031           break;
11032         case CLUTTER_LEAVE:
11033           signal_num = LEAVE_EVENT;
11034           break;
11035         case CLUTTER_DELETE:
11036         case CLUTTER_DESTROY_NOTIFY:
11037         case CLUTTER_CLIENT_MESSAGE:
11038         default:
11039           signal_num = -1;
11040           break;
11041         }
11042
11043       if (signal_num != -1)
11044         g_signal_emit (actor, actor_signals[signal_num], 0,
11045                        event, &retval);
11046     }
11047
11048 out:
11049   g_object_unref (actor);
11050
11051   return retval;
11052 }
11053
11054 /**
11055  * clutter_actor_set_reactive:
11056  * @actor: a #ClutterActor
11057  * @reactive: whether the actor should be reactive to events
11058  *
11059  * Sets @actor as reactive. Reactive actors will receive events.
11060  *
11061  * Since: 0.6
11062  */
11063 void
11064 clutter_actor_set_reactive (ClutterActor *actor,
11065                             gboolean      reactive)
11066 {
11067   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11068
11069   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11070     return;
11071
11072   if (reactive)
11073     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11074   else
11075     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11076
11077   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11078 }
11079
11080 /**
11081  * clutter_actor_get_reactive:
11082  * @actor: a #ClutterActor
11083  *
11084  * Checks whether @actor is marked as reactive.
11085  *
11086  * Return value: %TRUE if the actor is reactive
11087  *
11088  * Since: 0.6
11089  */
11090 gboolean
11091 clutter_actor_get_reactive (ClutterActor *actor)
11092 {
11093   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11094
11095   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11096 }
11097
11098 /**
11099  * clutter_actor_get_anchor_point:
11100  * @self: a #ClutterActor
11101  * @anchor_x: (out): return location for the X coordinate of the anchor point
11102  * @anchor_y: (out): return location for the Y coordinate of the anchor point
11103  *
11104  * Gets the current anchor point of the @actor in pixels.
11105  *
11106  * Since: 0.6
11107  */
11108 void
11109 clutter_actor_get_anchor_point (ClutterActor *self,
11110                                 gfloat       *anchor_x,
11111                                 gfloat       *anchor_y)
11112 {
11113   const ClutterTransformInfo *info;
11114
11115   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11116
11117   info = _clutter_actor_get_transform_info_or_defaults (self);
11118   clutter_anchor_coord_get_units (self, &info->anchor,
11119                                   anchor_x,
11120                                   anchor_y,
11121                                   NULL);
11122 }
11123
11124 /**
11125  * clutter_actor_set_anchor_point:
11126  * @self: a #ClutterActor
11127  * @anchor_x: X coordinate of the anchor point
11128  * @anchor_y: Y coordinate of the anchor point
11129  *
11130  * Sets an anchor point for @self. The anchor point is a point in the
11131  * coordinate space of an actor to which the actor position within its
11132  * parent is relative; the default is (0, 0), i.e. the top-left corner
11133  * of the actor.
11134  *
11135  * Since: 0.6
11136  */
11137 void
11138 clutter_actor_set_anchor_point (ClutterActor *self,
11139                                 gfloat        anchor_x,
11140                                 gfloat        anchor_y)
11141 {
11142   ClutterTransformInfo *info;
11143   ClutterActorPrivate *priv;
11144   gboolean changed = FALSE;
11145   gfloat old_anchor_x, old_anchor_y;
11146   GObject *obj;
11147
11148   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11149
11150   obj = G_OBJECT (self);
11151   priv = self->priv;
11152   info = _clutter_actor_get_transform_info (self);
11153
11154   g_object_freeze_notify (obj);
11155
11156   clutter_anchor_coord_get_units (self, &info->anchor,
11157                                   &old_anchor_x,
11158                                   &old_anchor_y,
11159                                   NULL);
11160
11161   if (info->anchor.is_fractional)
11162     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11163
11164   if (old_anchor_x != anchor_x)
11165     {
11166       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11167       changed = TRUE;
11168     }
11169
11170   if (old_anchor_y != anchor_y)
11171     {
11172       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11173       changed = TRUE;
11174     }
11175
11176   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11177
11178   if (changed)
11179     {
11180       priv->transform_valid = FALSE;
11181       clutter_actor_queue_redraw (self);
11182     }
11183
11184   g_object_thaw_notify (obj);
11185 }
11186
11187 /**
11188  * clutter_actor_get_anchor_point_gravity:
11189  * @self: a #ClutterActor
11190  *
11191  * Retrieves the anchor position expressed as a #ClutterGravity. If
11192  * the anchor point was specified using pixels or units this will
11193  * return %CLUTTER_GRAVITY_NONE.
11194  *
11195  * Return value: the #ClutterGravity used by the anchor point
11196  *
11197  * Since: 1.0
11198  */
11199 ClutterGravity
11200 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11201 {
11202   const ClutterTransformInfo *info;
11203
11204   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11205
11206   info = _clutter_actor_get_transform_info_or_defaults (self);
11207
11208   return clutter_anchor_coord_get_gravity (&info->anchor);
11209 }
11210
11211 /**
11212  * clutter_actor_move_anchor_point:
11213  * @self: a #ClutterActor
11214  * @anchor_x: X coordinate of the anchor point
11215  * @anchor_y: Y coordinate of the anchor point
11216  *
11217  * Sets an anchor point for the actor, and adjusts the actor postion so that
11218  * the relative position of the actor toward its parent remains the same.
11219  *
11220  * Since: 0.6
11221  */
11222 void
11223 clutter_actor_move_anchor_point (ClutterActor *self,
11224                                  gfloat        anchor_x,
11225                                  gfloat        anchor_y)
11226 {
11227   gfloat old_anchor_x, old_anchor_y;
11228   const ClutterTransformInfo *info;
11229
11230   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11231
11232   info = _clutter_actor_get_transform_info (self);
11233   clutter_anchor_coord_get_units (self, &info->anchor,
11234                                   &old_anchor_x,
11235                                   &old_anchor_y,
11236                                   NULL);
11237
11238   g_object_freeze_notify (G_OBJECT (self));
11239
11240   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
11241
11242   if (self->priv->position_set)
11243     clutter_actor_move_by (self,
11244                            anchor_x - old_anchor_x,
11245                            anchor_y - old_anchor_y);
11246
11247   g_object_thaw_notify (G_OBJECT (self));
11248 }
11249
11250 /**
11251  * clutter_actor_move_anchor_point_from_gravity:
11252  * @self: a #ClutterActor
11253  * @gravity: #ClutterGravity.
11254  *
11255  * Sets an anchor point on the actor based on the given gravity, adjusting the
11256  * actor postion so that its relative position within its parent remains
11257  * unchanged.
11258  *
11259  * Since version 1.0 the anchor point will be stored as a gravity so
11260  * that if the actor changes size then the anchor point will move. For
11261  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11262  * and later double the size of the actor, the anchor point will move
11263  * to the bottom right.
11264  *
11265  * Since: 0.6
11266  */
11267 void
11268 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
11269                                               ClutterGravity  gravity)
11270 {
11271   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
11272   const ClutterTransformInfo *info;
11273   ClutterActorPrivate *priv;
11274
11275   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11276
11277   priv = self->priv;
11278   info = _clutter_actor_get_transform_info (self);
11279
11280   g_object_freeze_notify (G_OBJECT (self));
11281
11282   clutter_anchor_coord_get_units (self, &info->anchor,
11283                                   &old_anchor_x,
11284                                   &old_anchor_y,
11285                                   NULL);
11286   clutter_actor_set_anchor_point_from_gravity (self, gravity);
11287   clutter_anchor_coord_get_units (self, &info->anchor,
11288                                   &new_anchor_x,
11289                                   &new_anchor_y,
11290                                   NULL);
11291
11292   if (priv->position_set)
11293     clutter_actor_move_by (self,
11294                            new_anchor_x - old_anchor_x,
11295                            new_anchor_y - old_anchor_y);
11296
11297   g_object_thaw_notify (G_OBJECT (self));
11298 }
11299
11300 /**
11301  * clutter_actor_set_anchor_point_from_gravity:
11302  * @self: a #ClutterActor
11303  * @gravity: #ClutterGravity.
11304  *
11305  * Sets an anchor point on the actor, based on the given gravity (this is a
11306  * convenience function wrapping clutter_actor_set_anchor_point()).
11307  *
11308  * Since version 1.0 the anchor point will be stored as a gravity so
11309  * that if the actor changes size then the anchor point will move. For
11310  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11311  * and later double the size of the actor, the anchor point will move
11312  * to the bottom right.
11313  *
11314  * Since: 0.6
11315  */
11316 void
11317 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
11318                                              ClutterGravity  gravity)
11319 {
11320   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11321
11322   if (gravity == CLUTTER_GRAVITY_NONE)
11323     clutter_actor_set_anchor_point (self, 0, 0);
11324   else
11325     {
11326       GObject *obj = G_OBJECT (self);
11327       ClutterTransformInfo *info;
11328
11329       g_object_freeze_notify (obj);
11330
11331       info = _clutter_actor_get_transform_info (self);
11332       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
11333
11334       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11335       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11336       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11337
11338       self->priv->transform_valid = FALSE;
11339
11340       clutter_actor_queue_redraw (self);
11341
11342       g_object_thaw_notify (obj);
11343     }
11344 }
11345
11346 static void
11347 clutter_container_iface_init (ClutterContainerIface *iface)
11348 {
11349   /* we don't override anything, as ClutterContainer already has a default
11350    * implementation that we can use, and which calls into our own API.
11351    */
11352 }
11353
11354 typedef enum
11355 {
11356   PARSE_X,
11357   PARSE_Y,
11358   PARSE_WIDTH,
11359   PARSE_HEIGHT,
11360   PARSE_ANCHOR_X,
11361   PARSE_ANCHOR_Y
11362 } ParseDimension;
11363
11364 static gfloat
11365 parse_units (ClutterActor   *self,
11366              ParseDimension  dimension,
11367              JsonNode       *node)
11368 {
11369   GValue value = { 0, };
11370   gfloat retval = 0;
11371
11372   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
11373     return 0;
11374
11375   json_node_get_value (node, &value);
11376
11377   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
11378     {
11379       retval = (gfloat) g_value_get_int64 (&value);
11380     }
11381   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
11382     {
11383       retval = g_value_get_double (&value);
11384     }
11385   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
11386     {
11387       ClutterUnits units;
11388       gboolean res;
11389
11390       res = clutter_units_from_string (&units, g_value_get_string (&value));
11391       if (res)
11392         retval = clutter_units_to_pixels (&units);
11393       else
11394         {
11395           g_warning ("Invalid value '%s': integers, strings or floating point "
11396                      "values can be used for the x, y, width and height "
11397                      "properties. Valid modifiers for strings are 'px', 'mm', "
11398                      "'pt' and 'em'.",
11399                      g_value_get_string (&value));
11400           retval = 0;
11401         }
11402     }
11403   else
11404     {
11405       g_warning ("Invalid value of type '%s': integers, strings of floating "
11406                  "point values can be used for the x, y, width, height "
11407                  "anchor-x and anchor-y properties.",
11408                  g_type_name (G_VALUE_TYPE (&value)));
11409     }
11410
11411   g_value_unset (&value);
11412
11413   return retval;
11414 }
11415
11416 typedef struct {
11417   ClutterRotateAxis axis;
11418
11419   gdouble angle;
11420
11421   gfloat center_x;
11422   gfloat center_y;
11423   gfloat center_z;
11424 } RotationInfo;
11425
11426 static inline gboolean
11427 parse_rotation_array (ClutterActor *actor,
11428                       JsonArray    *array,
11429                       RotationInfo *info)
11430 {
11431   JsonNode *element;
11432
11433   if (json_array_get_length (array) != 2)
11434     return FALSE;
11435
11436   /* angle */
11437   element = json_array_get_element (array, 0);
11438   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
11439     info->angle = json_node_get_double (element);
11440   else
11441     return FALSE;
11442
11443   /* center */
11444   element = json_array_get_element (array, 1);
11445   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
11446     {
11447       JsonArray *center = json_node_get_array (element);
11448
11449       if (json_array_get_length (center) != 2)
11450         return FALSE;
11451
11452       switch (info->axis)
11453         {
11454         case CLUTTER_X_AXIS:
11455           info->center_y = parse_units (actor, PARSE_Y,
11456                                         json_array_get_element (center, 0));
11457           info->center_z = parse_units (actor, PARSE_Y,
11458                                         json_array_get_element (center, 1));
11459           return TRUE;
11460
11461         case CLUTTER_Y_AXIS:
11462           info->center_x = parse_units (actor, PARSE_X,
11463                                         json_array_get_element (center, 0));
11464           info->center_z = parse_units (actor, PARSE_X,
11465                                         json_array_get_element (center, 1));
11466           return TRUE;
11467
11468         case CLUTTER_Z_AXIS:
11469           info->center_x = parse_units (actor, PARSE_X,
11470                                         json_array_get_element (center, 0));
11471           info->center_y = parse_units (actor, PARSE_Y,
11472                                         json_array_get_element (center, 1));
11473           return TRUE;
11474         }
11475     }
11476
11477   return FALSE;
11478 }
11479
11480 static gboolean
11481 parse_rotation (ClutterActor *actor,
11482                 JsonNode     *node,
11483                 RotationInfo *info)
11484 {
11485   JsonArray *array;
11486   guint len, i;
11487   gboolean retval = FALSE;
11488
11489   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
11490     {
11491       g_warning ("Invalid node of type '%s' found, expecting an array",
11492                  json_node_type_name (node));
11493       return FALSE;
11494     }
11495
11496   array = json_node_get_array (node);
11497   len = json_array_get_length (array);
11498
11499   for (i = 0; i < len; i++)
11500     {
11501       JsonNode *element = json_array_get_element (array, i);
11502       JsonObject *object;
11503       JsonNode *member;
11504
11505       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
11506         {
11507           g_warning ("Invalid node of type '%s' found, expecting an object",
11508                      json_node_type_name (element));
11509           return FALSE;
11510         }
11511
11512       object = json_node_get_object (element);
11513
11514       if (json_object_has_member (object, "x-axis"))
11515         {
11516           member = json_object_get_member (object, "x-axis");
11517
11518           info->axis = CLUTTER_X_AXIS;
11519
11520           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11521             {
11522               info->angle = json_node_get_double (member);
11523               retval = TRUE;
11524             }
11525           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11526             retval = parse_rotation_array (actor,
11527                                            json_node_get_array (member),
11528                                            info);
11529           else
11530             retval = FALSE;
11531         }
11532       else if (json_object_has_member (object, "y-axis"))
11533         {
11534           member = json_object_get_member (object, "y-axis");
11535
11536           info->axis = CLUTTER_Y_AXIS;
11537
11538           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11539             {
11540               info->angle = json_node_get_double (member);
11541               retval = TRUE;
11542             }
11543           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11544             retval = parse_rotation_array (actor,
11545                                            json_node_get_array (member),
11546                                            info);
11547           else
11548             retval = FALSE;
11549         }
11550       else if (json_object_has_member (object, "z-axis"))
11551         {
11552           member = json_object_get_member (object, "z-axis");
11553
11554           info->axis = CLUTTER_Z_AXIS;
11555
11556           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11557             {
11558               info->angle = json_node_get_double (member);
11559               retval = TRUE;
11560             }
11561           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11562             retval = parse_rotation_array (actor,
11563                                            json_node_get_array (member),
11564                                            info);
11565           else
11566             retval = FALSE;
11567         }
11568     }
11569
11570   return retval;
11571 }
11572
11573 static GSList *
11574 parse_actor_metas (ClutterScript *script,
11575                    ClutterActor  *actor,
11576                    JsonNode      *node)
11577 {
11578   GList *elements, *l;
11579   GSList *retval = NULL;
11580
11581   if (!JSON_NODE_HOLDS_ARRAY (node))
11582     return NULL;
11583
11584   elements = json_array_get_elements (json_node_get_array (node));
11585
11586   for (l = elements; l != NULL; l = l->next)
11587     {
11588       JsonNode *element = l->data;
11589       const gchar *id_ = _clutter_script_get_id_from_node (element);
11590       GObject *meta;
11591
11592       if (id_ == NULL || *id_ == '\0')
11593         continue;
11594
11595       meta = clutter_script_get_object (script, id_);
11596       if (meta == NULL)
11597         continue;
11598
11599       retval = g_slist_prepend (retval, meta);
11600     }
11601
11602   g_list_free (elements);
11603
11604   return g_slist_reverse (retval);
11605 }
11606
11607 static GSList *
11608 parse_behaviours (ClutterScript *script,
11609                   ClutterActor  *actor,
11610                   JsonNode      *node)
11611 {
11612   GList *elements, *l;
11613   GSList *retval = NULL;
11614
11615   if (!JSON_NODE_HOLDS_ARRAY (node))
11616     return NULL;
11617
11618   elements = json_array_get_elements (json_node_get_array (node));
11619
11620   for (l = elements; l != NULL; l = l->next)
11621     {
11622       JsonNode *element = l->data;
11623       const gchar *id_ = _clutter_script_get_id_from_node (element);
11624       GObject *behaviour;
11625
11626       if (id_ == NULL || *id_ == '\0')
11627         continue;
11628
11629       behaviour = clutter_script_get_object (script, id_);
11630       if (behaviour == NULL)
11631         continue;
11632
11633       retval = g_slist_prepend (retval, behaviour);
11634     }
11635
11636   g_list_free (elements);
11637
11638   return g_slist_reverse (retval);
11639 }
11640
11641 static gboolean
11642 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
11643                                  ClutterScript     *script,
11644                                  GValue            *value,
11645                                  const gchar       *name,
11646                                  JsonNode          *node)
11647 {
11648   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11649   gboolean retval = FALSE;
11650
11651   if ((name[0] == 'x' && name[1] == '\0') ||
11652       (name[0] == 'y' && name[1] == '\0') ||
11653       (strcmp (name, "width") == 0) ||
11654       (strcmp (name, "height") == 0) ||
11655       (strcmp (name, "anchor_x") == 0) ||
11656       (strcmp (name, "anchor_y") == 0))
11657     {
11658       ParseDimension dimension;
11659       gfloat units;
11660
11661       if (name[0] == 'x')
11662         dimension = PARSE_X;
11663       else if (name[0] == 'y')
11664         dimension = PARSE_Y;
11665       else if (name[0] == 'w')
11666         dimension = PARSE_WIDTH;
11667       else if (name[0] == 'h')
11668         dimension = PARSE_HEIGHT;
11669       else if (name[0] == 'a' && name[7] == 'x')
11670         dimension = PARSE_ANCHOR_X;
11671       else if (name[0] == 'a' && name[7] == 'y')
11672         dimension = PARSE_ANCHOR_Y;
11673       else
11674         return FALSE;
11675
11676       units = parse_units (actor, dimension, node);
11677
11678       /* convert back to pixels: all properties are pixel-based */
11679       g_value_init (value, G_TYPE_FLOAT);
11680       g_value_set_float (value, units);
11681
11682       retval = TRUE;
11683     }
11684   else if (strcmp (name, "rotation") == 0)
11685     {
11686       RotationInfo *info;
11687
11688       info = g_slice_new0 (RotationInfo);
11689       retval = parse_rotation (actor, node, info);
11690
11691       if (retval)
11692         {
11693           g_value_init (value, G_TYPE_POINTER);
11694           g_value_set_pointer (value, info);
11695         }
11696       else
11697         g_slice_free (RotationInfo, info);
11698     }
11699   else if (strcmp (name, "behaviours") == 0)
11700     {
11701       GSList *l;
11702
11703 #ifdef CLUTTER_ENABLE_DEBUG
11704       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
11705         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
11706                                      "and it should not be used in newly "
11707                                      "written ClutterScript definitions.");
11708 #endif
11709
11710       l = parse_behaviours (script, actor, node);
11711
11712       g_value_init (value, G_TYPE_POINTER);
11713       g_value_set_pointer (value, l);
11714
11715       retval = TRUE;
11716     }
11717   else if (strcmp (name, "actions") == 0 ||
11718            strcmp (name, "constraints") == 0 ||
11719            strcmp (name, "effects") == 0)
11720     {
11721       GSList *l;
11722
11723       l = parse_actor_metas (script, actor, node);
11724
11725       g_value_init (value, G_TYPE_POINTER);
11726       g_value_set_pointer (value, l);
11727
11728       retval = TRUE;
11729     }
11730
11731   return retval;
11732 }
11733
11734 static void
11735 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
11736                                    ClutterScript     *script,
11737                                    const gchar       *name,
11738                                    const GValue      *value)
11739 {
11740   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11741
11742 #ifdef CLUTTER_ENABLE_DEBUG
11743   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
11744     {
11745       gchar *tmp = g_strdup_value_contents (value);
11746
11747       CLUTTER_NOTE (SCRIPT,
11748                     "in ClutterActor::set_custom_property('%s') = %s",
11749                     name,
11750                     tmp);
11751
11752       g_free (tmp);
11753     }
11754 #endif /* CLUTTER_ENABLE_DEBUG */
11755
11756   if (strcmp (name, "rotation") == 0)
11757     {
11758       RotationInfo *info;
11759
11760       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11761         return;
11762
11763       info = g_value_get_pointer (value);
11764
11765       clutter_actor_set_rotation (actor,
11766                                   info->axis, info->angle,
11767                                   info->center_x,
11768                                   info->center_y,
11769                                   info->center_z);
11770
11771       g_slice_free (RotationInfo, info);
11772
11773       return;
11774     }
11775
11776   if (strcmp (name, "behaviours") == 0)
11777     {
11778       GSList *behaviours, *l;
11779
11780       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11781         return;
11782
11783       behaviours = g_value_get_pointer (value);
11784       for (l = behaviours; l != NULL; l = l->next)
11785         {
11786           ClutterBehaviour *behaviour = l->data;
11787
11788           clutter_behaviour_apply (behaviour, actor);
11789         }
11790
11791       g_slist_free (behaviours);
11792
11793       return;
11794     }
11795
11796   if (strcmp (name, "actions") == 0 ||
11797       strcmp (name, "constraints") == 0 ||
11798       strcmp (name, "effects") == 0)
11799     {
11800       GSList *metas, *l;
11801
11802       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11803         return;
11804
11805       metas = g_value_get_pointer (value);
11806       for (l = metas; l != NULL; l = l->next)
11807         {
11808           if (name[0] == 'a')
11809             clutter_actor_add_action (actor, l->data);
11810
11811           if (name[0] == 'c')
11812             clutter_actor_add_constraint (actor, l->data);
11813
11814           if (name[0] == 'e')
11815             clutter_actor_add_effect (actor, l->data);
11816         }
11817
11818       g_slist_free (metas);
11819
11820       return;
11821     }
11822
11823   g_object_set_property (G_OBJECT (scriptable), name, value);
11824 }
11825
11826 static void
11827 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
11828 {
11829   iface->parse_custom_node = clutter_actor_parse_custom_node;
11830   iface->set_custom_property = clutter_actor_set_custom_property;
11831 }
11832
11833 static ClutterActorMeta *
11834 get_meta_from_animation_property (ClutterActor  *actor,
11835                                   const gchar   *name,
11836                                   gchar        **name_p)
11837 {
11838   ClutterActorPrivate *priv = actor->priv;
11839   ClutterActorMeta *meta = NULL;
11840   gchar **tokens;
11841
11842   /* if this is not a special property, fall through */
11843   if (name[0] != '@')
11844     return NULL;
11845
11846   /* detect the properties named using the following spec:
11847    *
11848    *   @<section>.<meta-name>.<property-name>
11849    *
11850    * where <section> can be one of the following:
11851    *
11852    *   - actions
11853    *   - constraints
11854    *   - effects
11855    *
11856    * and <meta-name> is the name set on a specific ActorMeta
11857    */
11858
11859   tokens = g_strsplit (name + 1, ".", -1);
11860   if (tokens == NULL || g_strv_length (tokens) != 3)
11861     {
11862       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
11863                     name + 1);
11864       g_strfreev (tokens);
11865       return NULL;
11866     }
11867
11868   if (strcmp (tokens[0], "actions") == 0)
11869     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
11870
11871   if (strcmp (tokens[0], "constraints") == 0)
11872     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
11873
11874   if (strcmp (tokens[0], "effects") == 0)
11875     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
11876
11877   if (name_p != NULL)
11878     *name_p = g_strdup (tokens[2]);
11879
11880   CLUTTER_NOTE (ANIMATION,
11881                 "Looking for property '%s' of object '%s' in section '%s'",
11882                 tokens[2],
11883                 tokens[1],
11884                 tokens[0]);
11885
11886   g_strfreev (tokens);
11887
11888   return meta;
11889 }
11890
11891 static GParamSpec *
11892 clutter_actor_find_property (ClutterAnimatable *animatable,
11893                              const gchar       *property_name)
11894 {
11895   ClutterActorMeta *meta = NULL;
11896   GObjectClass *klass = NULL;
11897   GParamSpec *pspec = NULL;
11898   gchar *p_name = NULL;
11899
11900   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
11901                                            property_name,
11902                                            &p_name);
11903
11904   if (meta != NULL)
11905     {
11906       klass = G_OBJECT_GET_CLASS (meta);
11907
11908       pspec = g_object_class_find_property (klass, p_name);
11909     }
11910   else
11911     {
11912       klass = G_OBJECT_GET_CLASS (animatable);
11913
11914       pspec = g_object_class_find_property (klass, property_name);
11915     }
11916
11917   g_free (p_name);
11918
11919   return pspec;
11920 }
11921
11922 static void
11923 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
11924                                  const gchar       *property_name,
11925                                  GValue            *initial)
11926 {
11927   ClutterActorMeta *meta = NULL;
11928   gchar *p_name = NULL;
11929
11930   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
11931                                            property_name,
11932                                            &p_name);
11933
11934   if (meta != NULL)
11935     g_object_get_property (G_OBJECT (meta), p_name, initial);
11936   else
11937     g_object_get_property (G_OBJECT (animatable), property_name, initial);
11938
11939   g_free (p_name);
11940 }
11941
11942 static void
11943 clutter_actor_set_final_state (ClutterAnimatable *animatable,
11944                                const gchar       *property_name,
11945                                const GValue      *final)
11946 {
11947   ClutterActorMeta *meta = NULL;
11948   gchar *p_name = NULL;
11949
11950   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
11951                                            property_name,
11952                                            &p_name);
11953   if (meta != NULL)
11954     g_object_set_property (G_OBJECT (meta), p_name, final);
11955   else
11956     g_object_set_property (G_OBJECT (animatable), property_name, final);
11957
11958   g_free (p_name);
11959 }
11960
11961 static void
11962 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
11963 {
11964   iface->find_property = clutter_actor_find_property;
11965   iface->get_initial_state = clutter_actor_get_initial_state;
11966   iface->set_final_state = clutter_actor_set_final_state;
11967 }
11968
11969 /**
11970  * clutter_actor_transform_stage_point:
11971  * @self: A #ClutterActor
11972  * @x: (in): x screen coordinate of the point to unproject
11973  * @y: (in): y screen coordinate of the point to unproject
11974  * @x_out: (out): return location for the unprojected x coordinance
11975  * @y_out: (out): return location for the unprojected y coordinance
11976  *
11977  * This function translates screen coordinates (@x, @y) to
11978  * coordinates relative to the actor. For example, it can be used to translate
11979  * screen events from global screen coordinates into actor-local coordinates.
11980  *
11981  * The conversion can fail, notably if the transform stack results in the
11982  * actor being projected on the screen as a mere line.
11983  *
11984  * The conversion should not be expected to be pixel-perfect due to the
11985  * nature of the operation. In general the error grows when the skewing
11986  * of the actor rectangle on screen increases.
11987  *
11988  * <note><para>This function can be computationally intensive.</para></note>
11989  *
11990  * <note><para>This function only works when the allocation is up-to-date,
11991  * i.e. inside of paint().</para></note>
11992  *
11993  * Return value: %TRUE if conversion was successful.
11994  *
11995  * Since: 0.6
11996  */
11997 gboolean
11998 clutter_actor_transform_stage_point (ClutterActor *self,
11999                                      gfloat        x,
12000                                      gfloat        y,
12001                                      gfloat       *x_out,
12002                                      gfloat       *y_out)
12003 {
12004   ClutterVertex v[4];
12005   float ST[3][3];
12006   float RQ[3][3];
12007   int du, dv, xi, yi;
12008   float px, py;
12009   float xf, yf, wf, det;
12010   ClutterActorPrivate *priv;
12011
12012   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12013
12014   priv = self->priv;
12015
12016   /* This implementation is based on the quad -> quad projection algorithm
12017    * described by Paul Heckbert in:
12018    *
12019    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12020    *
12021    * and the sample implementation at:
12022    *
12023    *   http://www.cs.cmu.edu/~ph/src/texfund/
12024    *
12025    * Our texture is a rectangle with origin [0, 0], so we are mapping from
12026    * quad to rectangle only, which significantly simplifies things; the
12027    * function calls have been unrolled, and most of the math is done in fixed
12028    * point.
12029    */
12030
12031   clutter_actor_get_abs_allocation_vertices (self, v);
12032
12033   /* Keeping these as ints simplifies the multiplication (no significant
12034    * loss of precision here).
12035    */
12036   du = (int) (priv->allocation.x2 - priv->allocation.x1);
12037   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12038
12039   if (!du || !dv)
12040     return FALSE;
12041
12042 #define UX2FP(x)        (x)
12043 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12044
12045   /* First, find mapping from unit uv square to xy quadrilateral; this
12046    * equivalent to the pmap_square_quad() functions in the sample
12047    * implementation, which we can simplify, since our target is always
12048    * a rectangle.
12049    */
12050   px = v[0].x - v[1].x + v[3].x - v[2].x;
12051   py = v[0].y - v[1].y + v[3].y - v[2].y;
12052
12053   if (!px && !py)
12054     {
12055       /* affine transform */
12056       RQ[0][0] = UX2FP (v[1].x - v[0].x);
12057       RQ[1][0] = UX2FP (v[3].x - v[1].x);
12058       RQ[2][0] = UX2FP (v[0].x);
12059       RQ[0][1] = UX2FP (v[1].y - v[0].y);
12060       RQ[1][1] = UX2FP (v[3].y - v[1].y);
12061       RQ[2][1] = UX2FP (v[0].y);
12062       RQ[0][2] = 0;
12063       RQ[1][2] = 0;
12064       RQ[2][2] = 1.0;
12065     }
12066   else
12067     {
12068       /* projective transform */
12069       double dx1, dx2, dy1, dy2, del;
12070
12071       dx1 = UX2FP (v[1].x - v[3].x);
12072       dx2 = UX2FP (v[2].x - v[3].x);
12073       dy1 = UX2FP (v[1].y - v[3].y);
12074       dy2 = UX2FP (v[2].y - v[3].y);
12075
12076       del = DET2FP (dx1, dx2, dy1, dy2);
12077       if (!del)
12078         return FALSE;
12079
12080       /*
12081        * The division here needs to be done in floating point for
12082        * precisions reasons.
12083        */
12084       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12085       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12086       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12087       RQ[2][2] = 1.0;
12088       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12089       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12090       RQ[2][0] = UX2FP (v[0].x);
12091       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12092       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12093       RQ[2][1] = UX2FP (v[0].y);
12094     }
12095
12096   /*
12097    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12098    * square. Since our rectangle is based at 0,0 we only need to scale.
12099    */
12100   RQ[0][0] /= du;
12101   RQ[1][0] /= dv;
12102   RQ[0][1] /= du;
12103   RQ[1][1] /= dv;
12104   RQ[0][2] /= du;
12105   RQ[1][2] /= dv;
12106
12107   /*
12108    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12109    * inverse of that.
12110    */
12111   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12112   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12113   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12114   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12115   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12116   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12117   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12118   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12119   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12120
12121   /*
12122    * Check the resulting matrix is OK.
12123    */
12124   det = (RQ[0][0] * ST[0][0])
12125       + (RQ[0][1] * ST[0][1])
12126       + (RQ[0][2] * ST[0][2]);
12127   if (!det)
12128     return FALSE;
12129
12130   /*
12131    * Now transform our point with the ST matrix; the notional w
12132    * coordinate is 1, hence the last part is simply added.
12133    */
12134   xi = (int) x;
12135   yi = (int) y;
12136
12137   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
12138   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
12139   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
12140
12141   if (x_out)
12142     *x_out = xf / wf;
12143
12144   if (y_out)
12145     *y_out = yf / wf;
12146
12147 #undef UX2FP
12148 #undef DET2FP
12149
12150   return TRUE;
12151 }
12152
12153 /*
12154  * ClutterGeometry
12155  */
12156
12157 static ClutterGeometry*
12158 clutter_geometry_copy (const ClutterGeometry *geometry)
12159 {
12160   return g_slice_dup (ClutterGeometry, geometry);
12161 }
12162
12163 static void
12164 clutter_geometry_free (ClutterGeometry *geometry)
12165 {
12166   if (G_LIKELY (geometry != NULL))
12167     g_slice_free (ClutterGeometry, geometry);
12168 }
12169
12170 /**
12171  * clutter_geometry_union:
12172  * @geometry_a: a #ClutterGeometry
12173  * @geometry_b: another #ClutterGeometry
12174  * @result: (out): location to store the result
12175  *
12176  * Find the union of two rectangles represented as #ClutterGeometry.
12177  *
12178  * Since: 1.4
12179  */
12180 void
12181 clutter_geometry_union (const ClutterGeometry *geometry_a,
12182                         const ClutterGeometry *geometry_b,
12183                         ClutterGeometry       *result)
12184 {
12185   /* We don't try to handle rectangles that can't be represented
12186    * as a signed integer box */
12187   gint x_1 = MIN (geometry_a->x, geometry_b->x);
12188   gint y_1 = MIN (geometry_a->y, geometry_b->y);
12189   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
12190                   geometry_b->x + (gint)geometry_b->width);
12191   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
12192                   geometry_b->y + (gint)geometry_b->height);
12193   result->x = x_1;
12194   result->y = y_1;
12195   result->width = x_2 - x_1;
12196   result->height = y_2 - y_1;
12197 }
12198
12199 /**
12200  * clutter_geometry_intersects:
12201  * @geometry0: The first geometry to test
12202  * @geometry1: The second geometry to test
12203  *
12204  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
12205  * they do else %FALSE.
12206  *
12207  * Return value: %TRUE of @geometry0 and geometry1 intersect else
12208  * %FALSE.
12209  *
12210  * Since: 1.4
12211  */
12212 gboolean
12213 clutter_geometry_intersects (const ClutterGeometry *geometry0,
12214                              const ClutterGeometry *geometry1)
12215 {
12216   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
12217       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
12218       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
12219       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
12220     return FALSE;
12221   else
12222     return TRUE;
12223 }
12224
12225 static gboolean
12226 clutter_geometry_progress (const GValue *a,
12227                            const GValue *b,
12228                            gdouble       progress,
12229                            GValue       *retval)
12230 {
12231   const ClutterGeometry *a_geom = g_value_get_boxed (a);
12232   const ClutterGeometry *b_geom = g_value_get_boxed (b);
12233   ClutterGeometry res = { 0, };
12234   gint a_width = a_geom->width;
12235   gint b_width = b_geom->width;
12236   gint a_height = a_geom->height;
12237   gint b_height = b_geom->height;
12238
12239   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
12240   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
12241
12242   res.width = a_width + (b_width - a_width) * progress;
12243   res.height = a_height + (b_height - a_height) * progress;
12244
12245   g_value_set_boxed (retval, &res);
12246
12247   return TRUE;
12248 }
12249
12250 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
12251                                clutter_geometry_copy,
12252                                clutter_geometry_free,
12253                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
12254
12255 /*
12256  * ClutterVertices
12257  */
12258
12259 /**
12260  * clutter_vertex_new:
12261  * @x: X coordinate
12262  * @y: Y coordinate
12263  * @z: Z coordinate
12264  *
12265  * Creates a new #ClutterVertex for the point in 3D space
12266  * identified by the 3 coordinates @x, @y, @z
12267  *
12268  * Return value: the newly allocate #ClutterVertex. Use
12269  *   clutter_vertex_free() to free the resources
12270  *
12271  * Since: 1.0
12272  */
12273 ClutterVertex *
12274 clutter_vertex_new (gfloat x,
12275                     gfloat y,
12276                     gfloat z)
12277 {
12278   ClutterVertex *vertex;
12279
12280   vertex = g_slice_new (ClutterVertex);
12281   vertex->x = x;
12282   vertex->y = y;
12283   vertex->z = z;
12284
12285   return vertex;
12286 }
12287
12288 /**
12289  * clutter_vertex_copy:
12290  * @vertex: a #ClutterVertex
12291  *
12292  * Copies @vertex
12293  *
12294  * Return value: a newly allocated copy of #ClutterVertex. Use
12295  *   clutter_vertex_free() to free the allocated resources
12296  *
12297  * Since: 1.0
12298  */
12299 ClutterVertex *
12300 clutter_vertex_copy (const ClutterVertex *vertex)
12301 {
12302   if (G_LIKELY (vertex != NULL))
12303     return g_slice_dup (ClutterVertex, vertex);
12304
12305   return NULL;
12306 }
12307
12308 /**
12309  * clutter_vertex_free:
12310  * @vertex: a #ClutterVertex
12311  *
12312  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
12313  *
12314  * Since: 1.0
12315  */
12316 void
12317 clutter_vertex_free (ClutterVertex *vertex)
12318 {
12319   if (G_UNLIKELY (vertex != NULL))
12320     g_slice_free (ClutterVertex, vertex);
12321 }
12322
12323 /**
12324  * clutter_vertex_equal:
12325  * @vertex_a: a #ClutterVertex
12326  * @vertex_b: a #ClutterVertex
12327  *
12328  * Compares @vertex_a and @vertex_b for equality
12329  *
12330  * Return value: %TRUE if the passed #ClutterVertex are equal
12331  *
12332  * Since: 1.0
12333  */
12334 gboolean
12335 clutter_vertex_equal (const ClutterVertex *vertex_a,
12336                       const ClutterVertex *vertex_b)
12337 {
12338   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
12339
12340   if (vertex_a == vertex_b)
12341     return TRUE;
12342
12343   return vertex_a->x == vertex_b->x &&
12344          vertex_a->y == vertex_b->y &&
12345          vertex_a->z == vertex_b->z;
12346 }
12347
12348 static gboolean
12349 clutter_vertex_progress (const GValue *a,
12350                          const GValue *b,
12351                          gdouble       progress,
12352                          GValue       *retval)
12353 {
12354   const ClutterVertex *av = g_value_get_boxed (a);
12355   const ClutterVertex *bv = g_value_get_boxed (b);
12356   ClutterVertex res = { 0, };
12357
12358   res.x = av->x + (bv->x - av->x) * progress;
12359   res.y = av->y + (bv->y - av->y) * progress;
12360   res.z = av->z + (bv->z - av->z) * progress;
12361
12362   g_value_set_boxed (retval, &res);
12363
12364   return TRUE;
12365 }
12366
12367 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
12368                                clutter_vertex_copy,
12369                                clutter_vertex_free,
12370                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
12371
12372 /**
12373  * clutter_actor_is_rotated:
12374  * @self: a #ClutterActor
12375  *
12376  * Checks whether any rotation is applied to the actor.
12377  *
12378  * Return value: %TRUE if the actor is rotated.
12379  *
12380  * Since: 0.6
12381  */
12382 gboolean
12383 clutter_actor_is_rotated (ClutterActor *self)
12384 {
12385   const ClutterTransformInfo *info;
12386
12387   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12388
12389   info = _clutter_actor_get_transform_info_or_defaults (self);
12390
12391   if (info->rx_angle || info->ry_angle || info->rz_angle)
12392     return TRUE;
12393
12394   return FALSE;
12395 }
12396
12397 /**
12398  * clutter_actor_is_scaled:
12399  * @self: a #ClutterActor
12400  *
12401  * Checks whether the actor is scaled in either dimension.
12402  *
12403  * Return value: %TRUE if the actor is scaled.
12404  *
12405  * Since: 0.6
12406  */
12407 gboolean
12408 clutter_actor_is_scaled (ClutterActor *self)
12409 {
12410   const ClutterTransformInfo *info;
12411
12412   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12413
12414   info = _clutter_actor_get_transform_info_or_defaults (self);
12415
12416   if (info->scale_x != 1.0 || info->scale_y != 1.0)
12417     return TRUE;
12418
12419   return FALSE;
12420 }
12421
12422 ClutterActor *
12423 _clutter_actor_get_stage_internal (ClutterActor *actor)
12424 {
12425   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
12426     actor = actor->priv->parent;
12427
12428   return actor;
12429 }
12430
12431 /**
12432  * clutter_actor_get_stage:
12433  * @actor: a #ClutterActor
12434  *
12435  * Retrieves the #ClutterStage where @actor is contained.
12436  *
12437  * Return value: (transfer none) (type Clutter.Stage): the stage
12438  *   containing the actor, or %NULL
12439  *
12440  * Since: 0.8
12441  */
12442 ClutterActor *
12443 clutter_actor_get_stage (ClutterActor *actor)
12444 {
12445   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
12446
12447   return _clutter_actor_get_stage_internal (actor);
12448 }
12449
12450 /**
12451  * clutter_actor_allocate_available_size:
12452  * @self: a #ClutterActor
12453  * @x: the actor's X coordinate
12454  * @y: the actor's Y coordinate
12455  * @available_width: the maximum available width, or -1 to use the
12456  *   actor's natural width
12457  * @available_height: the maximum available height, or -1 to use the
12458  *   actor's natural height
12459  * @flags: flags controlling the allocation
12460  *
12461  * Allocates @self taking into account the #ClutterActor<!-- -->'s
12462  * preferred size, but limiting it to the maximum available width
12463  * and height provided.
12464  *
12465  * This function will do the right thing when dealing with the
12466  * actor's request mode.
12467  *
12468  * The implementation of this function is equivalent to:
12469  *
12470  * |[
12471  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12472  *     {
12473  *       clutter_actor_get_preferred_width (self, available_height,
12474  *                                          &amp;min_width,
12475  *                                          &amp;natural_width);
12476  *       width = CLAMP (natural_width, min_width, available_width);
12477  *
12478  *       clutter_actor_get_preferred_height (self, width,
12479  *                                           &amp;min_height,
12480  *                                           &amp;natural_height);
12481  *       height = CLAMP (natural_height, min_height, available_height);
12482  *     }
12483  *   else
12484  *     {
12485  *       clutter_actor_get_preferred_height (self, available_width,
12486  *                                           &amp;min_height,
12487  *                                           &amp;natural_height);
12488  *       height = CLAMP (natural_height, min_height, available_height);
12489  *
12490  *       clutter_actor_get_preferred_width (self, height,
12491  *                                          &amp;min_width,
12492  *                                          &amp;natural_width);
12493  *       width = CLAMP (natural_width, min_width, available_width);
12494  *     }
12495  *
12496  *   box.x1 = x; box.y1 = y;
12497  *   box.x2 = box.x1 + available_width;
12498  *   box.y2 = box.y1 + available_height;
12499  *   clutter_actor_allocate (self, &amp;box, flags);
12500  * ]|
12501  *
12502  * This function can be used by fluid layout managers to allocate
12503  * an actor's preferred size without making it bigger than the area
12504  * available for the container.
12505  *
12506  * Since: 1.0
12507  */
12508 void
12509 clutter_actor_allocate_available_size (ClutterActor           *self,
12510                                        gfloat                  x,
12511                                        gfloat                  y,
12512                                        gfloat                  available_width,
12513                                        gfloat                  available_height,
12514                                        ClutterAllocationFlags  flags)
12515 {
12516   ClutterActorPrivate *priv;
12517   gfloat width, height;
12518   gfloat min_width, min_height;
12519   gfloat natural_width, natural_height;
12520   ClutterActorBox box;
12521
12522   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12523
12524   priv = self->priv;
12525
12526   width = height = 0.0;
12527
12528   switch (priv->request_mode)
12529     {
12530     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
12531       clutter_actor_get_preferred_width (self, available_height,
12532                                          &min_width,
12533                                          &natural_width);
12534       width  = CLAMP (natural_width, min_width, available_width);
12535
12536       clutter_actor_get_preferred_height (self, width,
12537                                           &min_height,
12538                                           &natural_height);
12539       height = CLAMP (natural_height, min_height, available_height);
12540       break;
12541
12542     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
12543       clutter_actor_get_preferred_height (self, available_width,
12544                                           &min_height,
12545                                           &natural_height);
12546       height = CLAMP (natural_height, min_height, available_height);
12547
12548       clutter_actor_get_preferred_width (self, height,
12549                                          &min_width,
12550                                          &natural_width);
12551       width  = CLAMP (natural_width, min_width, available_width);
12552       break;
12553     }
12554
12555
12556   box.x1 = x;
12557   box.y1 = y;
12558   box.x2 = box.x1 + width;
12559   box.y2 = box.y1 + height;
12560   clutter_actor_allocate (self, &box, flags);
12561 }
12562
12563 /**
12564  * clutter_actor_allocate_preferred_size:
12565  * @self: a #ClutterActor
12566  * @flags: flags controlling the allocation
12567  *
12568  * Allocates the natural size of @self.
12569  *
12570  * This function is a utility call for #ClutterActor implementations
12571  * that allocates the actor's preferred natural size. It can be used
12572  * by fixed layout managers (like #ClutterGroup or so called
12573  * 'composite actors') inside the ClutterActor::allocate
12574  * implementation to give each child exactly how much space it
12575  * requires.
12576  *
12577  * This function is not meant to be used by applications. It is also
12578  * not meant to be used outside the implementation of the
12579  * ClutterActor::allocate virtual function.
12580  *
12581  * Since: 0.8
12582  */
12583 void
12584 clutter_actor_allocate_preferred_size (ClutterActor           *self,
12585                                        ClutterAllocationFlags  flags)
12586 {
12587   gfloat actor_x, actor_y;
12588   gfloat natural_width, natural_height;
12589   ClutterActorBox actor_box;
12590
12591   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12592
12593   actor_x = clutter_actor_get_x (self);
12594   actor_y = clutter_actor_get_y (self);
12595
12596   clutter_actor_get_preferred_size (self,
12597                                     NULL, NULL,
12598                                     &natural_width,
12599                                     &natural_height);
12600
12601   actor_box.x1 = actor_x;
12602   actor_box.y1 = actor_y;
12603   actor_box.x2 = actor_box.x1 + natural_width;
12604   actor_box.y2 = actor_box.y1 + natural_height;
12605
12606   clutter_actor_allocate (self, &actor_box, flags);
12607 }
12608
12609 /**
12610  * clutter_actor_allocate_align_fill:
12611  * @self: a #ClutterActor
12612  * @box: a #ClutterActorBox, containing the available width and height
12613  * @x_align: the horizontal alignment, between 0 and 1
12614  * @y_align: the vertical alignment, between 0 and 1
12615  * @x_fill: whether the actor should fill horizontally
12616  * @y_fill: whether the actor should fill vertically
12617  * @flags: allocation flags to be passed to clutter_actor_allocate()
12618  *
12619  * Allocates @self by taking into consideration the available allocation
12620  * area; an alignment factor on either axis; and whether the actor should
12621  * fill the allocation on either axis.
12622  *
12623  * The @box should contain the available allocation width and height;
12624  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
12625  * allocation will be offset by their value.
12626  *
12627  * This function takes into consideration the geometry request specified by
12628  * the #ClutterActor:request-mode property, and the text direction.
12629  *
12630  * This function is useful for fluid layout managers, like #ClutterBinLayout
12631  * or #ClutterTableLayout
12632  *
12633  * Since: 1.4
12634  */
12635 void
12636 clutter_actor_allocate_align_fill (ClutterActor           *self,
12637                                    const ClutterActorBox  *box,
12638                                    gdouble                 x_align,
12639                                    gdouble                 y_align,
12640                                    gboolean                x_fill,
12641                                    gboolean                y_fill,
12642                                    ClutterAllocationFlags  flags)
12643 {
12644   ClutterActorPrivate *priv;
12645   ClutterActorBox allocation = { 0, };
12646   gfloat x_offset, y_offset;
12647   gfloat available_width, available_height;
12648   gfloat child_width, child_height;
12649
12650   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12651   g_return_if_fail (box != NULL);
12652   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
12653   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
12654
12655   priv = self->priv;
12656
12657   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
12658   clutter_actor_box_get_size (box, &available_width, &available_height);
12659
12660   if (available_width < 0)
12661     available_width = 0;
12662
12663   if (available_height < 0)
12664     available_height = 0;
12665
12666   if (x_fill)
12667     {
12668       allocation.x1 = x_offset;
12669       allocation.x2 = allocation.x1 + available_width;
12670     }
12671
12672   if (y_fill)
12673     {
12674       allocation.y1 = y_offset;
12675       allocation.y2 = allocation.y1 + available_height;
12676     }
12677
12678   /* if we are filling horizontally and vertically then we're done */
12679   if (x_fill && y_fill)
12680     goto out;
12681
12682   child_width = child_height = 0.0f;
12683
12684   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12685     {
12686       gfloat min_width, natural_width;
12687       gfloat min_height, natural_height;
12688
12689       clutter_actor_get_preferred_width (self, available_height,
12690                                          &min_width,
12691                                          &natural_width);
12692
12693       child_width = CLAMP (natural_width, min_width, available_width);
12694
12695       if (!y_fill)
12696         {
12697           clutter_actor_get_preferred_height (self, child_width,
12698                                               &min_height,
12699                                               &natural_height);
12700
12701           child_height = CLAMP (natural_height, min_height, available_height);
12702         }
12703     }
12704   else
12705     {
12706       gfloat min_width, natural_width;
12707       gfloat min_height, natural_height;
12708
12709       clutter_actor_get_preferred_height (self, available_width,
12710                                           &min_height,
12711                                           &natural_height);
12712
12713       child_height = CLAMP (natural_height, min_height, available_height);
12714
12715       if (!x_fill)
12716         {
12717           clutter_actor_get_preferred_width (self, child_height,
12718                                              &min_width,
12719                                              &natural_width);
12720
12721           child_width = CLAMP (natural_width, min_width, available_width);
12722         }
12723     }
12724
12725   /* invert the horizontal alignment for RTL languages */
12726   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
12727     x_align = 1.0 - x_align;
12728
12729   if (!x_fill)
12730     {
12731       allocation.x1 = x_offset
12732                     + ((available_width - child_width) * x_align);
12733       allocation.x2 = allocation.x1 + child_width;
12734     }
12735
12736   if (!y_fill)
12737     {
12738       allocation.y1 = y_offset
12739                     + ((available_height - child_height) * y_align);
12740       allocation.y2 = allocation.y1 + child_height;
12741     }
12742
12743 out:
12744   clutter_actor_box_clamp_to_pixel (&allocation);
12745   clutter_actor_allocate (self, &allocation, flags);
12746 }
12747
12748 /**
12749  * clutter_actor_grab_key_focus:
12750  * @self: a #ClutterActor
12751  *
12752  * Sets the key focus of the #ClutterStage including @self
12753  * to this #ClutterActor.
12754  *
12755  * Since: 1.0
12756  */
12757 void
12758 clutter_actor_grab_key_focus (ClutterActor *self)
12759 {
12760   ClutterActor *stage;
12761
12762   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12763
12764   stage = _clutter_actor_get_stage_internal (self);
12765   if (stage != NULL)
12766     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
12767 }
12768
12769 /**
12770  * clutter_actor_get_pango_context:
12771  * @self: a #ClutterActor
12772  *
12773  * Retrieves the #PangoContext for @self. The actor's #PangoContext
12774  * is already configured using the appropriate font map, resolution
12775  * and font options.
12776  *
12777  * Unlike clutter_actor_create_pango_context(), this context is owend
12778  * by the #ClutterActor and it will be updated each time the options
12779  * stored by the #ClutterBackend change.
12780  *
12781  * You can use the returned #PangoContext to create a #PangoLayout
12782  * and render text using cogl_pango_render_layout() to reuse the
12783  * glyphs cache also used by Clutter.
12784  *
12785  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
12786  *   The returned #PangoContext is owned by the actor and should not be
12787  *   unreferenced by the application code
12788  *
12789  * Since: 1.0
12790  */
12791 PangoContext *
12792 clutter_actor_get_pango_context (ClutterActor *self)
12793 {
12794   ClutterActorPrivate *priv;
12795
12796   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12797
12798   priv = self->priv;
12799
12800   if (priv->pango_context != NULL)
12801     return priv->pango_context;
12802
12803   priv->pango_context = _clutter_context_get_pango_context ();
12804   g_object_ref (priv->pango_context);
12805
12806   return priv->pango_context;
12807 }
12808
12809 /**
12810  * clutter_actor_create_pango_context:
12811  * @self: a #ClutterActor
12812  *
12813  * Creates a #PangoContext for the given actor. The #PangoContext
12814  * is already configured using the appropriate font map, resolution
12815  * and font options.
12816  *
12817  * See also clutter_actor_get_pango_context().
12818  *
12819  * Return value: (transfer full): the newly created #PangoContext.
12820  *   Use g_object_unref() on the returned value to deallocate its
12821  *   resources
12822  *
12823  * Since: 1.0
12824  */
12825 PangoContext *
12826 clutter_actor_create_pango_context (ClutterActor *self)
12827 {
12828   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12829
12830   return _clutter_context_create_pango_context ();
12831 }
12832
12833 /**
12834  * clutter_actor_create_pango_layout:
12835  * @self: a #ClutterActor
12836  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
12837  *
12838  * Creates a new #PangoLayout from the same #PangoContext used
12839  * by the #ClutterActor. The #PangoLayout is already configured
12840  * with the font map, resolution and font options, and the
12841  * given @text.
12842  *
12843  * If you want to keep around a #PangoLayout created by this
12844  * function you will have to connect to the #ClutterBackend::font-changed
12845  * and #ClutterBackend::resolution-changed signals, and call
12846  * pango_layout_context_changed() in response to them.
12847  *
12848  * Return value: (transfer full): the newly created #PangoLayout.
12849  *   Use g_object_unref() when done
12850  *
12851  * Since: 1.0
12852  */
12853 PangoLayout *
12854 clutter_actor_create_pango_layout (ClutterActor *self,
12855                                    const gchar  *text)
12856 {
12857   PangoContext *context;
12858   PangoLayout *layout;
12859
12860   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12861
12862   context = clutter_actor_get_pango_context (self);
12863   layout = pango_layout_new (context);
12864
12865   if (text)
12866     pango_layout_set_text (layout, text, -1);
12867
12868   return layout;
12869 }
12870
12871 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
12872  * ClutterOffscreenEffect.
12873  */
12874 void
12875 _clutter_actor_set_opacity_override (ClutterActor *self,
12876                                      gint          opacity)
12877 {
12878   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12879
12880   self->priv->opacity_override = opacity;
12881 }
12882
12883 gint
12884 _clutter_actor_get_opacity_override (ClutterActor *self)
12885 {
12886   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
12887
12888   return self->priv->opacity_override;
12889 }
12890
12891 /* Allows you to disable applying the actors model view transform during
12892  * a paint. Used by ClutterClone. */
12893 void
12894 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
12895                                                 gboolean      enable)
12896 {
12897   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12898
12899   self->priv->enable_model_view_transform = enable;
12900 }
12901
12902 void
12903 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
12904                                           gboolean      enable)
12905 {
12906   ClutterActorPrivate *priv;
12907
12908   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12909
12910   priv = self->priv;
12911
12912   priv->enable_paint_unmapped = enable;
12913
12914   if (priv->enable_paint_unmapped)
12915     {
12916       /* Make sure that the parents of the widget are realized first;
12917        * otherwise checks in clutter_actor_update_map_state() will
12918        * fail.
12919        */
12920       clutter_actor_realize (self);
12921
12922       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
12923     }
12924   else
12925     {
12926       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
12927     }
12928 }
12929
12930 static void
12931 clutter_anchor_coord_get_units (ClutterActor      *self,
12932                                 const AnchorCoord *coord,
12933                                 gfloat            *x,
12934                                 gfloat            *y,
12935                                 gfloat            *z)
12936 {
12937   if (coord->is_fractional)
12938     {
12939       gfloat actor_width, actor_height;
12940
12941       clutter_actor_get_size (self, &actor_width, &actor_height);
12942
12943       if (x)
12944         *x = actor_width * coord->v.fraction.x;
12945
12946       if (y)
12947         *y = actor_height * coord->v.fraction.y;
12948
12949       if (z)
12950         *z = 0;
12951     }
12952   else
12953     {
12954       if (x)
12955         *x = coord->v.units.x;
12956
12957       if (y)
12958         *y = coord->v.units.y;
12959
12960       if (z)
12961         *z = coord->v.units.z;
12962     }
12963 }
12964
12965 static void
12966 clutter_anchor_coord_set_units (AnchorCoord *coord,
12967                                 gfloat       x,
12968                                 gfloat       y,
12969                                 gfloat       z)
12970 {
12971   coord->is_fractional = FALSE;
12972   coord->v.units.x = x;
12973   coord->v.units.y = y;
12974   coord->v.units.z = z;
12975 }
12976
12977 static ClutterGravity
12978 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
12979 {
12980   if (coord->is_fractional)
12981     {
12982       if (coord->v.fraction.x == 0.0)
12983         {
12984           if (coord->v.fraction.y == 0.0)
12985             return CLUTTER_GRAVITY_NORTH_WEST;
12986           else if (coord->v.fraction.y == 0.5)
12987             return CLUTTER_GRAVITY_WEST;
12988           else if (coord->v.fraction.y == 1.0)
12989             return CLUTTER_GRAVITY_SOUTH_WEST;
12990           else
12991             return CLUTTER_GRAVITY_NONE;
12992         }
12993       else if (coord->v.fraction.x == 0.5)
12994         {
12995           if (coord->v.fraction.y == 0.0)
12996             return CLUTTER_GRAVITY_NORTH;
12997           else if (coord->v.fraction.y == 0.5)
12998             return CLUTTER_GRAVITY_CENTER;
12999           else if (coord->v.fraction.y == 1.0)
13000             return CLUTTER_GRAVITY_SOUTH;
13001           else
13002             return CLUTTER_GRAVITY_NONE;
13003         }
13004       else if (coord->v.fraction.x == 1.0)
13005         {
13006           if (coord->v.fraction.y == 0.0)
13007             return CLUTTER_GRAVITY_NORTH_EAST;
13008           else if (coord->v.fraction.y == 0.5)
13009             return CLUTTER_GRAVITY_EAST;
13010           else if (coord->v.fraction.y == 1.0)
13011             return CLUTTER_GRAVITY_SOUTH_EAST;
13012           else
13013             return CLUTTER_GRAVITY_NONE;
13014         }
13015       else
13016         return CLUTTER_GRAVITY_NONE;
13017     }
13018   else
13019     return CLUTTER_GRAVITY_NONE;
13020 }
13021
13022 static void
13023 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
13024                                   ClutterGravity  gravity)
13025 {
13026   switch (gravity)
13027     {
13028     case CLUTTER_GRAVITY_NORTH:
13029       coord->v.fraction.x = 0.5;
13030       coord->v.fraction.y = 0.0;
13031       break;
13032
13033     case CLUTTER_GRAVITY_NORTH_EAST:
13034       coord->v.fraction.x = 1.0;
13035       coord->v.fraction.y = 0.0;
13036       break;
13037
13038     case CLUTTER_GRAVITY_EAST:
13039       coord->v.fraction.x = 1.0;
13040       coord->v.fraction.y = 0.5;
13041       break;
13042
13043     case CLUTTER_GRAVITY_SOUTH_EAST:
13044       coord->v.fraction.x = 1.0;
13045       coord->v.fraction.y = 1.0;
13046       break;
13047
13048     case CLUTTER_GRAVITY_SOUTH:
13049       coord->v.fraction.x = 0.5;
13050       coord->v.fraction.y = 1.0;
13051       break;
13052
13053     case CLUTTER_GRAVITY_SOUTH_WEST:
13054       coord->v.fraction.x = 0.0;
13055       coord->v.fraction.y = 1.0;
13056       break;
13057
13058     case CLUTTER_GRAVITY_WEST:
13059       coord->v.fraction.x = 0.0;
13060       coord->v.fraction.y = 0.5;
13061       break;
13062
13063     case CLUTTER_GRAVITY_NORTH_WEST:
13064       coord->v.fraction.x = 0.0;
13065       coord->v.fraction.y = 0.0;
13066       break;
13067
13068     case CLUTTER_GRAVITY_CENTER:
13069       coord->v.fraction.x = 0.5;
13070       coord->v.fraction.y = 0.5;
13071       break;
13072
13073     default:
13074       coord->v.fraction.x = 0.0;
13075       coord->v.fraction.y = 0.0;
13076       break;
13077     }
13078
13079   coord->is_fractional = TRUE;
13080 }
13081
13082 static gboolean
13083 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13084 {
13085   if (coord->is_fractional)
13086     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13087   else
13088     return (coord->v.units.x == 0.0
13089             && coord->v.units.y == 0.0
13090             && coord->v.units.z == 0.0);
13091 }
13092
13093 /**
13094  * clutter_actor_get_flags:
13095  * @self: a #ClutterActor
13096  *
13097  * Retrieves the flags set on @self
13098  *
13099  * Return value: a bitwise or of #ClutterActorFlags or 0
13100  *
13101  * Since: 1.0
13102  */
13103 ClutterActorFlags
13104 clutter_actor_get_flags (ClutterActor *self)
13105 {
13106   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13107
13108   return self->flags;
13109 }
13110
13111 /**
13112  * clutter_actor_set_flags:
13113  * @self: a #ClutterActor
13114  * @flags: the flags to set
13115  *
13116  * Sets @flags on @self
13117  *
13118  * This function will emit notifications for the changed properties
13119  *
13120  * Since: 1.0
13121  */
13122 void
13123 clutter_actor_set_flags (ClutterActor      *self,
13124                          ClutterActorFlags  flags)
13125 {
13126   ClutterActorFlags old_flags;
13127   GObject *obj;
13128   gboolean was_reactive_set, reactive_set;
13129   gboolean was_realized_set, realized_set;
13130   gboolean was_mapped_set, mapped_set;
13131   gboolean was_visible_set, visible_set;
13132
13133   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13134
13135   if (self->flags == flags)
13136     return;
13137
13138   obj = G_OBJECT (self);
13139   g_object_ref (obj);
13140   g_object_freeze_notify (obj);
13141
13142   old_flags = self->flags;
13143
13144   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13145   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13146   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13147   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13148
13149   self->flags |= flags;
13150
13151   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13152   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13153   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13154   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13155
13156   if (reactive_set != was_reactive_set)
13157     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13158
13159   if (realized_set != was_realized_set)
13160     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13161
13162   if (mapped_set != was_mapped_set)
13163     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13164
13165   if (visible_set != was_visible_set)
13166     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13167
13168   g_object_thaw_notify (obj);
13169   g_object_unref (obj);
13170 }
13171
13172 /**
13173  * clutter_actor_unset_flags:
13174  * @self: a #ClutterActor
13175  * @flags: the flags to unset
13176  *
13177  * Unsets @flags on @self
13178  *
13179  * This function will emit notifications for the changed properties
13180  *
13181  * Since: 1.0
13182  */
13183 void
13184 clutter_actor_unset_flags (ClutterActor      *self,
13185                            ClutterActorFlags  flags)
13186 {
13187   ClutterActorFlags old_flags;
13188   GObject *obj;
13189   gboolean was_reactive_set, reactive_set;
13190   gboolean was_realized_set, realized_set;
13191   gboolean was_mapped_set, mapped_set;
13192   gboolean was_visible_set, visible_set;
13193
13194   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13195
13196   obj = G_OBJECT (self);
13197   g_object_freeze_notify (obj);
13198
13199   old_flags = self->flags;
13200
13201   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13202   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13203   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13204   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13205
13206   self->flags &= ~flags;
13207
13208   if (self->flags == old_flags)
13209     return;
13210
13211   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13212   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13213   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13214   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13215
13216   if (reactive_set != was_reactive_set)
13217     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13218
13219   if (realized_set != was_realized_set)
13220     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13221
13222   if (mapped_set != was_mapped_set)
13223     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13224
13225   if (visible_set != was_visible_set)
13226     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13227
13228   g_object_thaw_notify (obj);
13229 }
13230
13231 /**
13232  * clutter_actor_get_transformation_matrix:
13233  * @self: a #ClutterActor
13234  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
13235  *
13236  * Retrieves the transformations applied to @self relative to its
13237  * parent.
13238  *
13239  * Since: 1.0
13240  */
13241 void
13242 clutter_actor_get_transformation_matrix (ClutterActor *self,
13243                                          CoglMatrix   *matrix)
13244 {
13245   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13246
13247   cogl_matrix_init_identity (matrix);
13248
13249   _clutter_actor_apply_modelview_transform (self, matrix);
13250 }
13251
13252 void
13253 _clutter_actor_set_in_clone_paint (ClutterActor *self,
13254                                    gboolean      is_in_clone_paint)
13255 {
13256   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13257   self->priv->in_clone_paint = is_in_clone_paint;
13258 }
13259
13260 /**
13261  * clutter_actor_is_in_clone_paint:
13262  * @self: a #ClutterActor
13263  *
13264  * Checks whether @self is being currently painted by a #ClutterClone
13265  *
13266  * This function is useful only inside the ::paint virtual function
13267  * implementations or within handlers for the #ClutterActor::paint
13268  * signal
13269  *
13270  * This function should not be used by applications
13271  *
13272  * Return value: %TRUE if the #ClutterActor is currently being painted
13273  *   by a #ClutterClone, and %FALSE otherwise
13274  *
13275  * Since: 1.0
13276  */
13277 gboolean
13278 clutter_actor_is_in_clone_paint (ClutterActor *self)
13279 {
13280   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13281
13282   return self->priv->in_clone_paint;
13283 }
13284
13285 static gboolean
13286 set_direction_recursive (ClutterActor *actor,
13287                          gpointer      user_data)
13288 {
13289   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
13290
13291   clutter_actor_set_text_direction (actor, text_dir);
13292
13293   return TRUE;
13294 }
13295
13296 /**
13297  * clutter_actor_set_text_direction:
13298  * @self: a #ClutterActor
13299  * @text_dir: the text direction for @self
13300  *
13301  * Sets the #ClutterTextDirection for an actor
13302  *
13303  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
13304  *
13305  * If @self implements #ClutterContainer then this function will recurse
13306  * inside all the children of @self (including the internal ones).
13307  *
13308  * Composite actors not implementing #ClutterContainer, or actors requiring
13309  * special handling when the text direction changes, should connect to
13310  * the #GObject::notify signal for the #ClutterActor:text-direction property
13311  *
13312  * Since: 1.2
13313  */
13314 void
13315 clutter_actor_set_text_direction (ClutterActor         *self,
13316                                   ClutterTextDirection  text_dir)
13317 {
13318   ClutterActorPrivate *priv;
13319
13320   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13321   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
13322
13323   priv = self->priv;
13324
13325   if (priv->text_direction != text_dir)
13326     {
13327       priv->text_direction = text_dir;
13328
13329       /* we need to emit the notify::text-direction first, so that
13330        * the sub-classes can catch that and do specific handling of
13331        * the text direction; see clutter_text_direction_changed_cb()
13332        * inside clutter-text.c
13333        */
13334       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
13335
13336       _clutter_actor_foreach_child (self, set_direction_recursive,
13337                                     GINT_TO_POINTER (text_dir));
13338
13339       clutter_actor_queue_relayout (self);
13340     }
13341 }
13342
13343 void
13344 _clutter_actor_set_has_pointer (ClutterActor *self,
13345                                 gboolean      has_pointer)
13346 {
13347   ClutterActorPrivate *priv = self->priv;
13348
13349   if (priv->has_pointer != has_pointer)
13350     {
13351       priv->has_pointer = has_pointer;
13352
13353       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
13354     }
13355 }
13356
13357 /**
13358  * clutter_actor_get_text_direction:
13359  * @self: a #ClutterActor
13360  *
13361  * Retrieves the value set using clutter_actor_set_text_direction()
13362  *
13363  * If no text direction has been previously set, the default text
13364  * direction, as returned by clutter_get_default_text_direction(), will
13365  * be returned instead
13366  *
13367  * Return value: the #ClutterTextDirection for the actor
13368  *
13369  * Since: 1.2
13370  */
13371 ClutterTextDirection
13372 clutter_actor_get_text_direction (ClutterActor *self)
13373 {
13374   ClutterActorPrivate *priv;
13375
13376   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
13377                         CLUTTER_TEXT_DIRECTION_LTR);
13378
13379   priv = self->priv;
13380
13381   /* if no direction has been set yet use the default */
13382   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
13383     priv->text_direction = clutter_get_default_text_direction ();
13384
13385   return priv->text_direction;
13386 }
13387
13388 /**
13389  * clutter_actor_push_internal:
13390  * @self: a #ClutterActor
13391  *
13392  * Should be used by actors implementing the #ClutterContainer and with
13393  * internal children added through clutter_actor_set_parent(), for instance:
13394  *
13395  * |[
13396  *   static void
13397  *   my_actor_init (MyActor *self)
13398  *   {
13399  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
13400  *
13401  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
13402  *
13403  *     /&ast; calling clutter_actor_set_parent() now will result in
13404  *      &ast; the internal flag being set on a child of MyActor
13405  *      &ast;/
13406  *
13407  *     /&ast; internal child - a background texture &ast;/
13408  *     self->priv->background_tex = clutter_texture_new ();
13409  *     clutter_actor_set_parent (self->priv->background_tex,
13410  *                               CLUTTER_ACTOR (self));
13411  *
13412  *     /&ast; internal child - a label &ast;/
13413  *     self->priv->label = clutter_text_new ();
13414  *     clutter_actor_set_parent (self->priv->label,
13415  *                               CLUTTER_ACTOR (self));
13416  *
13417  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
13418  *
13419  *     /&ast; calling clutter_actor_set_parent() now will not result in
13420  *      &ast; the internal flag being set on a child of MyActor
13421  *      &ast;/
13422  *   }
13423  * ]|
13424  *
13425  * This function will be used by Clutter to toggle an "internal child"
13426  * flag whenever clutter_actor_set_parent() is called; internal children
13427  * are handled differently by Clutter, specifically when destroying their
13428  * parent.
13429  *
13430  * Call clutter_actor_pop_internal() when you finished adding internal
13431  * children.
13432  *
13433  * Nested calls to clutter_actor_push_internal() are allowed, but each
13434  * one must by followed by a clutter_actor_pop_internal() call.
13435  *
13436  * Since: 1.2
13437  *
13438  * Deprecated: 1.10: All children of an actor are accessible through
13439  *   the #ClutterActor API, and #ClutterActor implements the
13440  *   #ClutterContainer interface, so this function is only useful
13441  *   for legacy containers overriding the default implementation.
13442  */
13443 void
13444 clutter_actor_push_internal (ClutterActor *self)
13445 {
13446   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13447
13448   self->priv->internal_child += 1;
13449 }
13450
13451 /**
13452  * clutter_actor_pop_internal:
13453  * @self: a #ClutterActor
13454  *
13455  * Disables the effects of clutter_actor_push_internal().
13456  *
13457  * Since: 1.2
13458  *
13459  * Deprecated: 1.10: All children of an actor are accessible through
13460  *   the #ClutterActor API. This function is only useful for legacy
13461  *   containers overriding the default implementation of the
13462  *   #ClutterContainer interface.
13463  */
13464 void
13465 clutter_actor_pop_internal (ClutterActor *self)
13466 {
13467   ClutterActorPrivate *priv;
13468
13469   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13470
13471   priv = self->priv;
13472
13473   if (priv->internal_child == 0)
13474     {
13475       g_warning ("Mismatched %s: you need to call "
13476                  "clutter_actor_push_composite() at least once before "
13477                  "calling this function", G_STRFUNC);
13478       return;
13479     }
13480
13481   priv->internal_child -= 1;
13482 }
13483
13484 /**
13485  * clutter_actor_has_pointer:
13486  * @self: a #ClutterActor
13487  *
13488  * Checks whether an actor contains the pointer of a
13489  * #ClutterInputDevice
13490  *
13491  * Return value: %TRUE if the actor contains the pointer, and
13492  *   %FALSE otherwise
13493  *
13494  * Since: 1.2
13495  */
13496 gboolean
13497 clutter_actor_has_pointer (ClutterActor *self)
13498 {
13499   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13500
13501   return self->priv->has_pointer;
13502 }
13503
13504 /* XXX: This is a workaround for not being able to break the ABI of
13505  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
13506  * clutter_actor_queue_clipped_redraw() for details.
13507  */
13508 ClutterPaintVolume *
13509 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
13510 {
13511   return g_object_get_data (G_OBJECT (self),
13512                             "-clutter-actor-queue-redraw-clip");
13513 }
13514
13515 void
13516 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
13517                                       ClutterPaintVolume *clip)
13518 {
13519   g_object_set_data (G_OBJECT (self),
13520                      "-clutter-actor-queue-redraw-clip",
13521                      clip);
13522 }
13523
13524 /**
13525  * clutter_actor_has_allocation:
13526  * @self: a #ClutterActor
13527  *
13528  * Checks if the actor has an up-to-date allocation assigned to
13529  * it. This means that the actor should have an allocation: it's
13530  * visible and has a parent. It also means that there is no
13531  * outstanding relayout request in progress for the actor or its
13532  * children (There might be other outstanding layout requests in
13533  * progress that will cause the actor to get a new allocation
13534  * when the stage is laid out, however).
13535  *
13536  * If this function returns %FALSE, then the actor will normally
13537  * be allocated before it is next drawn on the screen.
13538  *
13539  * Return value: %TRUE if the actor has an up-to-date allocation
13540  *
13541  * Since: 1.4
13542  */
13543 gboolean
13544 clutter_actor_has_allocation (ClutterActor *self)
13545 {
13546   ClutterActorPrivate *priv;
13547
13548   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13549
13550   priv = self->priv;
13551
13552   return priv->parent != NULL &&
13553          CLUTTER_ACTOR_IS_VISIBLE (self) &&
13554          !priv->needs_allocation;
13555 }
13556
13557 /**
13558  * clutter_actor_add_action:
13559  * @self: a #ClutterActor
13560  * @action: a #ClutterAction
13561  *
13562  * Adds @action to the list of actions applied to @self
13563  *
13564  * A #ClutterAction can only belong to one actor at a time
13565  *
13566  * The #ClutterActor will hold a reference on @action until either
13567  * clutter_actor_remove_action() or clutter_actor_clear_actions()
13568  * is called
13569  *
13570  * Since: 1.4
13571  */
13572 void
13573 clutter_actor_add_action (ClutterActor  *self,
13574                           ClutterAction *action)
13575 {
13576   ClutterActorPrivate *priv;
13577
13578   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13579   g_return_if_fail (CLUTTER_IS_ACTION (action));
13580
13581   priv = self->priv;
13582
13583   if (priv->actions == NULL)
13584     {
13585       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13586       priv->actions->actor = self;
13587     }
13588
13589   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
13590
13591   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13592 }
13593
13594 /**
13595  * clutter_actor_add_action_with_name:
13596  * @self: a #ClutterActor
13597  * @name: the name to set on the action
13598  * @action: a #ClutterAction
13599  *
13600  * A convenience function for setting the name of a #ClutterAction
13601  * while adding it to the list of actions applied to @self
13602  *
13603  * This function is the logical equivalent of:
13604  *
13605  * |[
13606  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13607  *   clutter_actor_add_action (self, action);
13608  * ]|
13609  *
13610  * Since: 1.4
13611  */
13612 void
13613 clutter_actor_add_action_with_name (ClutterActor  *self,
13614                                     const gchar   *name,
13615                                     ClutterAction *action)
13616 {
13617   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13618   g_return_if_fail (name != NULL);
13619   g_return_if_fail (CLUTTER_IS_ACTION (action));
13620
13621   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13622   clutter_actor_add_action (self, action);
13623 }
13624
13625 /**
13626  * clutter_actor_remove_action:
13627  * @self: a #ClutterActor
13628  * @action: a #ClutterAction
13629  *
13630  * Removes @action from the list of actions applied to @self
13631  *
13632  * The reference held by @self on the #ClutterAction will be released
13633  *
13634  * Since: 1.4
13635  */
13636 void
13637 clutter_actor_remove_action (ClutterActor  *self,
13638                              ClutterAction *action)
13639 {
13640   ClutterActorPrivate *priv;
13641
13642   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13643   g_return_if_fail (CLUTTER_IS_ACTION (action));
13644
13645   priv = self->priv;
13646
13647   if (priv->actions == NULL)
13648     return;
13649
13650   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
13651
13652   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13653 }
13654
13655 /**
13656  * clutter_actor_remove_action_by_name:
13657  * @self: a #ClutterActor
13658  * @name: the name of the action to remove
13659  *
13660  * Removes the #ClutterAction with the given name from the list
13661  * of actions applied to @self
13662  *
13663  * Since: 1.4
13664  */
13665 void
13666 clutter_actor_remove_action_by_name (ClutterActor *self,
13667                                      const gchar  *name)
13668 {
13669   ClutterActorPrivate *priv;
13670   ClutterActorMeta *meta;
13671
13672   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13673   g_return_if_fail (name != NULL);
13674
13675   priv = self->priv;
13676
13677   if (priv->actions == NULL)
13678     return;
13679
13680   meta = _clutter_meta_group_get_meta (priv->actions, name);
13681   if (meta == NULL)
13682     return;
13683
13684   _clutter_meta_group_remove_meta (priv->actions, meta);
13685
13686   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13687 }
13688
13689 /**
13690  * clutter_actor_get_actions:
13691  * @self: a #ClutterActor
13692  *
13693  * Retrieves the list of actions applied to @self
13694  *
13695  * Return value: (transfer container) (element-type Clutter.Action): a copy
13696  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
13697  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13698  *   allocated by the returned #GList
13699  *
13700  * Since: 1.4
13701  */
13702 GList *
13703 clutter_actor_get_actions (ClutterActor *self)
13704 {
13705   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13706
13707   if (self->priv->actions == NULL)
13708     return NULL;
13709
13710   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
13711 }
13712
13713 /**
13714  * clutter_actor_get_action:
13715  * @self: a #ClutterActor
13716  * @name: the name of the action to retrieve
13717  *
13718  * Retrieves the #ClutterAction with the given name in the list
13719  * of actions applied to @self
13720  *
13721  * Return value: (transfer none): a #ClutterAction for the given
13722  *   name, or %NULL. The returned #ClutterAction is owned by the
13723  *   actor and it should not be unreferenced directly
13724  *
13725  * Since: 1.4
13726  */
13727 ClutterAction *
13728 clutter_actor_get_action (ClutterActor *self,
13729                           const gchar  *name)
13730 {
13731   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13732   g_return_val_if_fail (name != NULL, NULL);
13733
13734   if (self->priv->actions == NULL)
13735     return NULL;
13736
13737   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
13738 }
13739
13740 /**
13741  * clutter_actor_clear_actions:
13742  * @self: a #ClutterActor
13743  *
13744  * Clears the list of actions applied to @self
13745  *
13746  * Since: 1.4
13747  */
13748 void
13749 clutter_actor_clear_actions (ClutterActor *self)
13750 {
13751   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13752
13753   if (self->priv->actions == NULL)
13754     return;
13755
13756   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
13757 }
13758
13759 /**
13760  * clutter_actor_add_constraint:
13761  * @self: a #ClutterActor
13762  * @constraint: a #ClutterConstraint
13763  *
13764  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
13765  * to @self
13766  *
13767  * The #ClutterActor will hold a reference on the @constraint until
13768  * either clutter_actor_remove_constraint() or
13769  * clutter_actor_clear_constraints() is called.
13770  *
13771  * Since: 1.4
13772  */
13773 void
13774 clutter_actor_add_constraint (ClutterActor      *self,
13775                               ClutterConstraint *constraint)
13776 {
13777   ClutterActorPrivate *priv;
13778
13779   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13780   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13781
13782   priv = self->priv;
13783
13784   if (priv->constraints == NULL)
13785     {
13786       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13787       priv->constraints->actor = self;
13788     }
13789
13790   _clutter_meta_group_add_meta (priv->constraints,
13791                                 CLUTTER_ACTOR_META (constraint));
13792   clutter_actor_queue_relayout (self);
13793
13794   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
13795 }
13796
13797 /**
13798  * clutter_actor_add_constraint_with_name:
13799  * @self: a #ClutterActor
13800  * @name: the name to set on the constraint
13801  * @constraint: a #ClutterConstraint
13802  *
13803  * A convenience function for setting the name of a #ClutterConstraint
13804  * while adding it to the list of constraints applied to @self
13805  *
13806  * This function is the logical equivalent of:
13807  *
13808  * |[
13809  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
13810  *   clutter_actor_add_constraint (self, constraint);
13811  * ]|
13812  *
13813  * Since: 1.4
13814  */
13815 void
13816 clutter_actor_add_constraint_with_name (ClutterActor      *self,
13817                                         const gchar       *name,
13818                                         ClutterConstraint *constraint)
13819 {
13820   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13821   g_return_if_fail (name != NULL);
13822   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13823
13824   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
13825   clutter_actor_add_constraint (self, constraint);
13826 }
13827
13828 /**
13829  * clutter_actor_remove_constraint:
13830  * @self: a #ClutterActor
13831  * @constraint: a #ClutterConstraint
13832  *
13833  * Removes @constraint from the list of constraints applied to @self
13834  *
13835  * The reference held by @self on the #ClutterConstraint will be released
13836  *
13837  * Since: 1.4
13838  */
13839 void
13840 clutter_actor_remove_constraint (ClutterActor      *self,
13841                                  ClutterConstraint *constraint)
13842 {
13843   ClutterActorPrivate *priv;
13844
13845   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13846   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13847
13848   priv = self->priv;
13849
13850   if (priv->constraints == NULL)
13851     return;
13852
13853   _clutter_meta_group_remove_meta (priv->constraints,
13854                                    CLUTTER_ACTOR_META (constraint));
13855   clutter_actor_queue_relayout (self);
13856
13857   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
13858 }
13859
13860 /**
13861  * clutter_actor_remove_constraint_by_name:
13862  * @self: a #ClutterActor
13863  * @name: the name of the constraint to remove
13864  *
13865  * Removes the #ClutterConstraint with the given name from the list
13866  * of constraints applied to @self
13867  *
13868  * Since: 1.4
13869  */
13870 void
13871 clutter_actor_remove_constraint_by_name (ClutterActor *self,
13872                                          const gchar  *name)
13873 {
13874   ClutterActorPrivate *priv;
13875   ClutterActorMeta *meta;
13876
13877   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13878   g_return_if_fail (name != NULL);
13879
13880   priv = self->priv;
13881
13882   if (priv->constraints == NULL)
13883     return;
13884
13885   meta = _clutter_meta_group_get_meta (priv->constraints, name);
13886   if (meta == NULL)
13887     return;
13888
13889   _clutter_meta_group_remove_meta (priv->constraints, meta);
13890   clutter_actor_queue_relayout (self);
13891 }
13892
13893 /**
13894  * clutter_actor_get_constraints:
13895  * @self: a #ClutterActor
13896  *
13897  * Retrieves the list of constraints applied to @self
13898  *
13899  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
13900  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
13901  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13902  *   allocated by the returned #GList
13903  *
13904  * Since: 1.4
13905  */
13906 GList *
13907 clutter_actor_get_constraints (ClutterActor *self)
13908 {
13909   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13910
13911   if (self->priv->constraints == NULL)
13912     return NULL;
13913
13914   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
13915 }
13916
13917 /**
13918  * clutter_actor_get_constraint:
13919  * @self: a #ClutterActor
13920  * @name: the name of the constraint to retrieve
13921  *
13922  * Retrieves the #ClutterConstraint with the given name in the list
13923  * of constraints applied to @self
13924  *
13925  * Return value: (transfer none): a #ClutterConstraint for the given
13926  *   name, or %NULL. The returned #ClutterConstraint is owned by the
13927  *   actor and it should not be unreferenced directly
13928  *
13929  * Since: 1.4
13930  */
13931 ClutterConstraint *
13932 clutter_actor_get_constraint (ClutterActor *self,
13933                               const gchar  *name)
13934 {
13935   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13936   g_return_val_if_fail (name != NULL, NULL);
13937
13938   if (self->priv->constraints == NULL)
13939     return NULL;
13940
13941   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
13942 }
13943
13944 /**
13945  * clutter_actor_clear_constraints:
13946  * @self: a #ClutterActor
13947  *
13948  * Clears the list of constraints applied to @self
13949  *
13950  * Since: 1.4
13951  */
13952 void
13953 clutter_actor_clear_constraints (ClutterActor *self)
13954 {
13955   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13956
13957   if (self->priv->constraints == NULL)
13958     return;
13959
13960   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
13961
13962   clutter_actor_queue_relayout (self);
13963 }
13964
13965 /**
13966  * clutter_actor_set_clip_to_allocation:
13967  * @self: a #ClutterActor
13968  * @clip_set: %TRUE to apply a clip tracking the allocation
13969  *
13970  * Sets whether @self should be clipped to the same size as its
13971  * allocation
13972  *
13973  * Since: 1.4
13974  */
13975 void
13976 clutter_actor_set_clip_to_allocation (ClutterActor *self,
13977                                       gboolean      clip_set)
13978 {
13979   ClutterActorPrivate *priv;
13980
13981   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13982
13983   clip_set = !!clip_set;
13984
13985   priv = self->priv;
13986
13987   if (priv->clip_to_allocation != clip_set)
13988     {
13989       priv->clip_to_allocation = clip_set;
13990
13991       clutter_actor_queue_redraw (self);
13992
13993       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
13994     }
13995 }
13996
13997 /**
13998  * clutter_actor_get_clip_to_allocation:
13999  * @self: a #ClutterActor
14000  *
14001  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14002  *
14003  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14004  *
14005  * Since: 1.4
14006  */
14007 gboolean
14008 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14009 {
14010   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14011
14012   return self->priv->clip_to_allocation;
14013 }
14014
14015 /**
14016  * clutter_actor_add_effect:
14017  * @self: a #ClutterActor
14018  * @effect: a #ClutterEffect
14019  *
14020  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14021  *
14022  * The #ClutterActor will hold a reference on the @effect until either
14023  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14024  * called.
14025  *
14026  * Since: 1.4
14027  */
14028 void
14029 clutter_actor_add_effect (ClutterActor  *self,
14030                           ClutterEffect *effect)
14031 {
14032   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14033   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14034
14035   _clutter_actor_add_effect_internal (self, effect);
14036
14037   clutter_actor_queue_redraw (self);
14038
14039   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14040 }
14041
14042 /**
14043  * clutter_actor_add_effect_with_name:
14044  * @self: a #ClutterActor
14045  * @name: the name to set on the effect
14046  * @effect: a #ClutterEffect
14047  *
14048  * A convenience function for setting the name of a #ClutterEffect
14049  * while adding it to the list of effectss applied to @self
14050  *
14051  * This function is the logical equivalent of:
14052  *
14053  * |[
14054  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14055  *   clutter_actor_add_effect (self, effect);
14056  * ]|
14057  *
14058  * Since: 1.4
14059  */
14060 void
14061 clutter_actor_add_effect_with_name (ClutterActor  *self,
14062                                     const gchar   *name,
14063                                     ClutterEffect *effect)
14064 {
14065   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14066   g_return_if_fail (name != NULL);
14067   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14068
14069   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14070   clutter_actor_add_effect (self, effect);
14071 }
14072
14073 /**
14074  * clutter_actor_remove_effect:
14075  * @self: a #ClutterActor
14076  * @effect: a #ClutterEffect
14077  *
14078  * Removes @effect from the list of effects applied to @self
14079  *
14080  * The reference held by @self on the #ClutterEffect will be released
14081  *
14082  * Since: 1.4
14083  */
14084 void
14085 clutter_actor_remove_effect (ClutterActor  *self,
14086                              ClutterEffect *effect)
14087 {
14088   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14089   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14090
14091   _clutter_actor_remove_effect_internal (self, effect);
14092
14093   clutter_actor_queue_redraw (self);
14094
14095   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14096 }
14097
14098 /**
14099  * clutter_actor_remove_effect_by_name:
14100  * @self: a #ClutterActor
14101  * @name: the name of the effect to remove
14102  *
14103  * Removes the #ClutterEffect with the given name from the list
14104  * of effects applied to @self
14105  *
14106  * Since: 1.4
14107  */
14108 void
14109 clutter_actor_remove_effect_by_name (ClutterActor *self,
14110                                      const gchar  *name)
14111 {
14112   ClutterActorPrivate *priv;
14113   ClutterActorMeta *meta;
14114
14115   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14116   g_return_if_fail (name != NULL);
14117
14118   priv = self->priv;
14119
14120   if (priv->effects == NULL)
14121     return;
14122
14123   meta = _clutter_meta_group_get_meta (priv->effects, name);
14124   if (meta == NULL)
14125     return;
14126
14127   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
14128 }
14129
14130 /**
14131  * clutter_actor_get_effects:
14132  * @self: a #ClutterActor
14133  *
14134  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
14135  *
14136  * Return value: (transfer container) (element-type Clutter.Effect): a list
14137  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
14138  *   list are owned by Clutter and they should not be freed. You should
14139  *   free the returned list using g_list_free() when done
14140  *
14141  * Since: 1.4
14142  */
14143 GList *
14144 clutter_actor_get_effects (ClutterActor *self)
14145 {
14146   ClutterActorPrivate *priv;
14147
14148   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14149
14150   priv = self->priv;
14151
14152   if (priv->effects == NULL)
14153     return NULL;
14154
14155   return _clutter_meta_group_get_metas_no_internal (priv->effects);
14156 }
14157
14158 /**
14159  * clutter_actor_get_effect:
14160  * @self: a #ClutterActor
14161  * @name: the name of the effect to retrieve
14162  *
14163  * Retrieves the #ClutterEffect with the given name in the list
14164  * of effects applied to @self
14165  *
14166  * Return value: (transfer none): a #ClutterEffect for the given
14167  *   name, or %NULL. The returned #ClutterEffect is owned by the
14168  *   actor and it should not be unreferenced directly
14169  *
14170  * Since: 1.4
14171  */
14172 ClutterEffect *
14173 clutter_actor_get_effect (ClutterActor *self,
14174                           const gchar  *name)
14175 {
14176   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14177   g_return_val_if_fail (name != NULL, NULL);
14178
14179   if (self->priv->effects == NULL)
14180     return NULL;
14181
14182   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
14183 }
14184
14185 /**
14186  * clutter_actor_clear_effects:
14187  * @self: a #ClutterActor
14188  *
14189  * Clears the list of effects applied to @self
14190  *
14191  * Since: 1.4
14192  */
14193 void
14194 clutter_actor_clear_effects (ClutterActor *self)
14195 {
14196   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14197
14198   if (self->priv->effects == NULL)
14199     return;
14200
14201   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
14202
14203   clutter_actor_queue_redraw (self);
14204 }
14205
14206 /**
14207  * clutter_actor_has_key_focus:
14208  * @self: a #ClutterActor
14209  *
14210  * Checks whether @self is the #ClutterActor that has key focus
14211  *
14212  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
14213  *
14214  * Since: 1.4
14215  */
14216 gboolean
14217 clutter_actor_has_key_focus (ClutterActor *self)
14218 {
14219   ClutterActor *stage;
14220
14221   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14222
14223   stage = _clutter_actor_get_stage_internal (self);
14224   if (stage == NULL)
14225     return FALSE;
14226
14227   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
14228 }
14229
14230 static gboolean
14231 _clutter_actor_get_paint_volume_real (ClutterActor *self,
14232                                       ClutterPaintVolume *pv)
14233 {
14234   ClutterActorPrivate *priv = self->priv;
14235
14236   /* Actors are only expected to report a valid paint volume
14237    * while they have a valid allocation. */
14238   if (G_UNLIKELY (priv->needs_allocation))
14239     {
14240       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14241                     "Actor needs allocation",
14242                     _clutter_actor_get_debug_name (self));
14243       return FALSE;
14244     }
14245
14246   /* Check if there are any handlers connected to the paint
14247    * signal. If there are then all bets are off for what the paint
14248    * volume for this actor might possibly be!
14249    *
14250    * XXX: It's expected that this is going to end up being quite a
14251    * costly check to have to do here, but we haven't come up with
14252    * another solution that can reliably catch paint signal handlers at
14253    * the right time to either avoid artefacts due to invalid stage
14254    * clipping or due to incorrect culling.
14255    *
14256    * Previously we checked in clutter_actor_paint(), but at that time
14257    * we may already be using a stage clip that could be derived from
14258    * an invalid paint-volume. We used to try and handle that by
14259    * queuing a follow up, unclipped, redraw but still the previous
14260    * checking wasn't enough to catch invalid volumes involved in
14261    * culling (considering that containers may derive their volume from
14262    * children that haven't yet been painted)
14263    *
14264    * Longer term, improved solutions could be:
14265    * - Disallow painting in the paint signal, only allow using it
14266    *   for tracking when paints happen. We can add another API that
14267    *   allows monkey patching the paint of arbitrary actors but in a
14268    *   more controlled way and that also supports modifying the
14269    *   paint-volume.
14270    * - If we could be notified somehow when signal handlers are
14271    *   connected we wouldn't have to poll for handlers like this.
14272    */
14273   if (g_signal_has_handler_pending (self,
14274                                     actor_signals[PAINT],
14275                                     0,
14276                                     TRUE))
14277     {
14278       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14279                     "Actor has \"paint\" signal handlers",
14280                     _clutter_actor_get_debug_name (self));
14281       return FALSE;
14282     }
14283
14284   _clutter_paint_volume_init_static (pv, self);
14285
14286   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
14287     {
14288       clutter_paint_volume_free (pv);
14289       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14290                     "Actor failed to report a volume",
14291                     _clutter_actor_get_debug_name (self));
14292       return FALSE;
14293     }
14294
14295   /* since effects can modify the paint volume, we allow them to actually
14296    * do this by making get_paint_volume() "context sensitive"
14297    */
14298   if (priv->effects != NULL)
14299     {
14300       if (priv->current_effect != NULL)
14301         {
14302           const GList *effects, *l;
14303
14304           /* if we are being called from within the paint sequence of
14305            * an actor, get the paint volume up to the current effect
14306            */
14307           effects = _clutter_meta_group_peek_metas (priv->effects);
14308           for (l = effects;
14309                l != NULL || (l != NULL && l->data != priv->current_effect);
14310                l = l->next)
14311             {
14312               if (!_clutter_effect_get_paint_volume (l->data, pv))
14313                 {
14314                   clutter_paint_volume_free (pv);
14315                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14316                                 "Effect (%s) failed to report a volume",
14317                                 _clutter_actor_get_debug_name (self),
14318                                 _clutter_actor_meta_get_debug_name (l->data));
14319                   return FALSE;
14320                 }
14321             }
14322         }
14323       else
14324         {
14325           const GList *effects, *l;
14326
14327           /* otherwise, get the cumulative volume */
14328           effects = _clutter_meta_group_peek_metas (priv->effects);
14329           for (l = effects; l != NULL; l = l->next)
14330             if (!_clutter_effect_get_paint_volume (l->data, pv))
14331               {
14332                 clutter_paint_volume_free (pv);
14333                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14334                               "Effect (%s) failed to report a volume",
14335                               _clutter_actor_get_debug_name (self),
14336                               _clutter_actor_meta_get_debug_name (l->data));
14337                 return FALSE;
14338               }
14339         }
14340     }
14341
14342   return TRUE;
14343 }
14344
14345 /* The public clutter_actor_get_paint_volume API returns a const
14346  * pointer since we return a pointer directly to the cached
14347  * PaintVolume associated with the actor and don't want the user to
14348  * inadvertently modify it, but for internal uses we sometimes need
14349  * access to the same PaintVolume but need to apply some book-keeping
14350  * modifications to it so we don't want a const pointer.
14351  */
14352 static ClutterPaintVolume *
14353 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
14354 {
14355   ClutterActorPrivate *priv;
14356
14357   priv = self->priv;
14358
14359   if (priv->paint_volume_valid)
14360     clutter_paint_volume_free (&priv->paint_volume);
14361
14362   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
14363     {
14364       priv->paint_volume_valid = TRUE;
14365       return &priv->paint_volume;
14366     }
14367   else
14368     {
14369       priv->paint_volume_valid = FALSE;
14370       return NULL;
14371     }
14372 }
14373
14374 /**
14375  * clutter_actor_get_paint_volume:
14376  * @self: a #ClutterActor
14377  *
14378  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
14379  * when a paint volume can't be determined.
14380  *
14381  * The paint volume is defined as the 3D space occupied by an actor
14382  * when being painted.
14383  *
14384  * This function will call the <function>get_paint_volume()</function>
14385  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
14386  * should not usually care about overriding the default implementation,
14387  * unless they are, for instance: painting outside their allocation, or
14388  * actors with a depth factor (not in terms of #ClutterActor:depth but real
14389  * 3D depth).
14390  *
14391  * <note>2D actors overriding <function>get_paint_volume()</function>
14392  * ensure their volume has a depth of 0. (This will be true so long as
14393  * you don't call clutter_paint_volume_set_depth().)</note>
14394  *
14395  * Return value: (transfer none): a pointer to a #ClutterPaintVolume
14396  *   or %NULL if no volume could be determined.
14397  *
14398  * Since: 1.6
14399  */
14400 const ClutterPaintVolume *
14401 clutter_actor_get_paint_volume (ClutterActor *self)
14402 {
14403   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14404
14405   return _clutter_actor_get_paint_volume_mutable (self);
14406 }
14407
14408 /**
14409  * clutter_actor_get_transformed_paint_volume:
14410  * @self: a #ClutterActor
14411  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
14412  *    (or %NULL for the stage)
14413  *
14414  * Retrieves the 3D paint volume of an actor like
14415  * clutter_actor_get_paint_volume() does (Please refer to the
14416  * documentation of clutter_actor_get_paint_volume() for more
14417  * details.) and it additionally transforms the paint volume into the
14418  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
14419  * is passed for @relative_to_ancestor)
14420  *
14421  * This can be used by containers that base their paint volume on
14422  * the volume of their children. Such containers can query the
14423  * transformed paint volume of all of its children and union them
14424  * together using clutter_paint_volume_union().
14425  *
14426  * Return value: (transfer none): a pointer to a #ClutterPaintVolume
14427  *   or %NULL if no volume could be determined.
14428  *
14429  * Since: 1.6
14430  */
14431 const ClutterPaintVolume *
14432 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
14433                                             ClutterActor *relative_to_ancestor)
14434 {
14435   const ClutterPaintVolume *volume;
14436   ClutterActor *stage;
14437   ClutterPaintVolume *transformed_volume;
14438
14439   stage = _clutter_actor_get_stage_internal (self);
14440   if (G_UNLIKELY (stage == NULL))
14441     return NULL;
14442
14443   if (relative_to_ancestor == NULL)
14444     relative_to_ancestor = stage;
14445
14446   volume = clutter_actor_get_paint_volume (self);
14447   if (volume == NULL)
14448     return NULL;
14449
14450   transformed_volume =
14451     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
14452
14453   _clutter_paint_volume_copy_static (volume, transformed_volume);
14454
14455   _clutter_paint_volume_transform_relative (transformed_volume,
14456                                             relative_to_ancestor);
14457
14458   return transformed_volume;
14459 }
14460
14461 /**
14462  * clutter_actor_get_paint_box:
14463  * @self: a #ClutterActor
14464  * @box: (out): return location for a #ClutterActorBox
14465  *
14466  * Retrieves the paint volume of the passed #ClutterActor, and
14467  * transforms it into a 2D bounding box in stage coordinates.
14468  *
14469  * This function is useful to determine the on screen area occupied by
14470  * the actor. The box is only an approximation and may often be
14471  * considerably larger due to the optimizations used to calculate the
14472  * box. The box is never smaller though, so it can reliably be used
14473  * for culling.
14474  *
14475  * There are times when a 2D paint box can't be determined, e.g.
14476  * because the actor isn't yet parented under a stage or because
14477  * the actor is unable to determine a paint volume.
14478  *
14479  * Return value: %TRUE if a 2D paint box could be determined, else
14480  * %FALSE.
14481  *
14482  * Since: 1.6
14483  */
14484 gboolean
14485 clutter_actor_get_paint_box (ClutterActor    *self,
14486                              ClutterActorBox *box)
14487 {
14488   ClutterActor *stage;
14489   ClutterPaintVolume *pv;
14490
14491   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14492   g_return_val_if_fail (box != NULL, FALSE);
14493
14494   stage = _clutter_actor_get_stage_internal (self);
14495   if (G_UNLIKELY (!stage))
14496     return FALSE;
14497
14498   pv = _clutter_actor_get_paint_volume_mutable (self);
14499   if (G_UNLIKELY (!pv))
14500     return FALSE;
14501
14502   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
14503
14504   return TRUE;
14505 }
14506
14507 /**
14508  * clutter_actor_has_overlaps:
14509  * @self: A #ClutterActor
14510  *
14511  * Asks the actor's implementation whether it may contain overlapping
14512  * primitives.
14513  *
14514  * For example; Clutter may use this to determine whether the painting
14515  * should be redirected to an offscreen buffer to correctly implement
14516  * the opacity property.
14517  *
14518  * Custom actors can override the default response by implementing the
14519  * #ClutterActor <function>has_overlaps</function> virtual function. See
14520  * clutter_actor_set_offscreen_redirect() for more information.
14521  *
14522  * Return value: %TRUE if the actor may have overlapping primitives, and
14523  *   %FALSE otherwise
14524  *
14525  * Since: 1.8
14526  */
14527 gboolean
14528 clutter_actor_has_overlaps (ClutterActor *self)
14529 {
14530   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14531
14532   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
14533 }
14534
14535 /**
14536  * clutter_actor_has_effects:
14537  * @self: A #ClutterActor
14538  *
14539  * Returns whether the actor has any effects applied.
14540  *
14541  * Return value: %TRUE if the actor has any effects,
14542  *   %FALSE otherwise
14543  *
14544  * Since: 1.10
14545  */
14546 gboolean
14547 clutter_actor_has_effects (ClutterActor *self)
14548 {
14549   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14550
14551   if (self->priv->effects == NULL)
14552     return FALSE;
14553
14554   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
14555 }
14556
14557 /**
14558  * clutter_actor_has_constraints:
14559  * @self: A #ClutterActor
14560  *
14561  * Returns whether the actor has any constraints applied.
14562  *
14563  * Return value: %TRUE if the actor has any constraints,
14564  *   %FALSE otherwise
14565  *
14566  * Since: 1.10
14567  */
14568 gboolean
14569 clutter_actor_has_constraints (ClutterActor *self)
14570 {
14571   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14572
14573   return self->priv->constraints != NULL;
14574 }
14575
14576 /**
14577  * clutter_actor_has_actions:
14578  * @self: A #ClutterActor
14579  *
14580  * Returns whether the actor has any actions applied.
14581  *
14582  * Return value: %TRUE if the actor has any actions,
14583  *   %FALSE otherwise
14584  *
14585  * Since: 1.10
14586  */
14587 gboolean
14588 clutter_actor_has_actions (ClutterActor *self)
14589 {
14590   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14591
14592   return self->priv->actions != NULL;
14593 }
14594
14595 /**
14596  * clutter_actor_get_n_children:
14597  * @self: a #ClutterActor
14598  *
14599  * Retrieves the number of children of @self.
14600  *
14601  * Return value: the number of children of an actor
14602  *
14603  * Since: 1.10
14604  */
14605 gint
14606 clutter_actor_get_n_children (ClutterActor *self)
14607 {
14608   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14609
14610   return self->priv->n_children;
14611 }
14612
14613 /**
14614  * clutter_actor_get_child_at_index:
14615  * @self: a #ClutterActor
14616  * @index_: the position in the list of children
14617  *
14618  * Retrieves the actor at the given @index_ inside the list of
14619  * children of @self.
14620  *
14621  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
14622  *
14623  * Since: 1.10
14624  */
14625 ClutterActor *
14626 clutter_actor_get_child_at_index (ClutterActor *self,
14627                                   gint          index_)
14628 {
14629   ClutterActor *iter;
14630   int i;
14631
14632   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14633   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
14634
14635   for (iter = self->priv->first_child, i = 0;
14636        iter != NULL && i < index_;
14637        iter = iter->priv->next_sibling, i += 1)
14638     ;
14639
14640   return iter;
14641 }
14642
14643 /*< private >
14644  * _clutter_actor_foreach_child:
14645  * @actor: The actor whos children you want to iterate
14646  * @callback: The function to call for each child
14647  * @user_data: Private data to pass to @callback
14648  *
14649  * Calls a given @callback once for each child of the specified @actor and
14650  * passing the @user_data pointer each time.
14651  *
14652  * Return value: returns %TRUE if all children were iterated, else
14653  *    %FALSE if a callback broke out of iteration early.
14654  */
14655 gboolean
14656 _clutter_actor_foreach_child (ClutterActor           *self,
14657                               ClutterForeachCallback  callback,
14658                               gpointer                user_data)
14659 {
14660   ClutterActorPrivate *priv = self->priv;
14661   ClutterActor *iter;
14662   gboolean cont;
14663
14664   for (cont = TRUE, iter = priv->first_child;
14665        cont && iter != NULL;
14666        iter = iter->priv->next_sibling)
14667     {
14668       cont = callback (iter, user_data);
14669     }
14670
14671   return cont;
14672 }
14673
14674 /* For debugging purposes this gives us a simple way to print out
14675  * the scenegraph e.g in gdb using:
14676  * [|
14677  *   _clutter_actor_traverse (stage,
14678  *                            0,
14679  *                            _clutter_debug_print_actor_cb,
14680  *                            NULL,
14681  *                            NULL);
14682  * |]
14683  */
14684 ClutterActorTraverseVisitFlags
14685 _clutter_debug_print_actor_cb (ClutterActor *actor,
14686                                int depth,
14687                                void *user_data)
14688 {
14689   g_print ("%*s%s:%p\n",
14690            depth * 2, "",
14691            _clutter_actor_get_debug_name (actor),
14692            actor);
14693
14694   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14695 }
14696
14697 static void
14698 _clutter_actor_traverse_breadth (ClutterActor           *actor,
14699                                  ClutterTraverseCallback callback,
14700                                  gpointer                user_data)
14701 {
14702   GQueue *queue = g_queue_new ();
14703   ClutterActor dummy;
14704   int current_depth = 0;
14705
14706   g_queue_push_tail (queue, actor);
14707   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
14708
14709   while ((actor = g_queue_pop_head (queue)))
14710     {
14711       ClutterActorTraverseVisitFlags flags;
14712
14713       if (actor == &dummy)
14714         {
14715           current_depth++;
14716           g_queue_push_tail (queue, &dummy);
14717           continue;
14718         }
14719
14720       flags = callback (actor, current_depth, user_data);
14721       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14722         break;
14723       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14724         {
14725           ClutterActor *iter;
14726
14727           for (iter = actor->priv->first_child;
14728                iter != NULL;
14729                iter = iter->priv->next_sibling)
14730             {
14731               g_queue_push_tail (queue, iter);
14732             }
14733         }
14734     }
14735
14736   g_queue_free (queue);
14737 }
14738
14739 static ClutterActorTraverseVisitFlags
14740 _clutter_actor_traverse_depth (ClutterActor           *actor,
14741                                ClutterTraverseCallback before_children_callback,
14742                                ClutterTraverseCallback after_children_callback,
14743                                int                     current_depth,
14744                                gpointer                user_data)
14745 {
14746   ClutterActorTraverseVisitFlags flags;
14747
14748   flags = before_children_callback (actor, current_depth, user_data);
14749   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14750     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14751
14752   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14753     {
14754       ClutterActor *iter;
14755
14756       for (iter = actor->priv->first_child;
14757            iter != NULL;
14758            iter = iter->priv->next_sibling)
14759         {
14760           flags = _clutter_actor_traverse_depth (iter,
14761                                                  before_children_callback,
14762                                                  after_children_callback,
14763                                                  current_depth + 1,
14764                                                  user_data);
14765
14766           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14767             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14768         }
14769     }
14770
14771   if (after_children_callback)
14772     return after_children_callback (actor, current_depth, user_data);
14773   else
14774     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14775 }
14776
14777 /* _clutter_actor_traverse:
14778  * @actor: The actor to start traversing the graph from
14779  * @flags: These flags may affect how the traversal is done
14780  * @before_children_callback: A function to call before visiting the
14781  *   children of the current actor.
14782  * @after_children_callback: A function to call after visiting the
14783  *   children of the current actor. (Ignored if
14784  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
14785  * @user_data: The private data to pass to the callbacks
14786  *
14787  * Traverses the scenegraph starting at the specified @actor and
14788  * descending through all its children and its children's children.
14789  * For each actor traversed @before_children_callback and
14790  * @after_children_callback are called with the specified
14791  * @user_data, before and after visiting that actor's children.
14792  *
14793  * The callbacks can return flags that affect the ongoing traversal
14794  * such as by skipping over an actors children or bailing out of
14795  * any further traversing.
14796  */
14797 void
14798 _clutter_actor_traverse (ClutterActor              *actor,
14799                          ClutterActorTraverseFlags  flags,
14800                          ClutterTraverseCallback    before_children_callback,
14801                          ClutterTraverseCallback    after_children_callback,
14802                          gpointer                   user_data)
14803 {
14804   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
14805     _clutter_actor_traverse_breadth (actor,
14806                                      before_children_callback,
14807                                      user_data);
14808   else /* DEPTH_FIRST */
14809     _clutter_actor_traverse_depth (actor,
14810                                    before_children_callback,
14811                                    after_children_callback,
14812                                    0, /* start depth */
14813                                    user_data);
14814 }
14815
14816 static void
14817 on_layout_manager_changed (ClutterLayoutManager *manager,
14818                            ClutterActor         *self)
14819 {
14820   clutter_actor_queue_relayout (self);
14821 }
14822
14823 /**
14824  * clutter_actor_set_layout_manager:
14825  * @self: a #ClutterActor
14826  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
14827  *
14828  * Sets the #ClutterLayoutManager delegate object that will be used to
14829  * lay out the children of @self.
14830  *
14831  * The #ClutterActor will take a reference on the passed @manager which
14832  * will be released either when the layout manager is removed, or when
14833  * the actor is destroyed.
14834  *
14835  * Since: 1.10
14836  */
14837 void
14838 clutter_actor_set_layout_manager (ClutterActor         *self,
14839                                   ClutterLayoutManager *manager)
14840 {
14841   ClutterActorPrivate *priv;
14842
14843   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14844   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
14845
14846   priv = self->priv;
14847
14848   if (priv->layout_manager != NULL)
14849     {
14850       g_signal_handlers_disconnect_by_func (priv->layout_manager,
14851                                             G_CALLBACK (on_layout_manager_changed),
14852                                             self);
14853       clutter_layout_manager_set_container (priv->layout_manager, NULL);
14854       g_object_unref (priv->layout_manager);
14855     }
14856
14857   priv->layout_manager = manager;
14858
14859   if (priv->layout_manager != NULL)
14860     {
14861       g_object_ref_sink (priv->layout_manager);
14862       clutter_layout_manager_set_container (priv->layout_manager,
14863                                             CLUTTER_CONTAINER (self));
14864       g_signal_connect (priv->layout_manager, "layout-changed",
14865                         G_CALLBACK (on_layout_manager_changed),
14866                         self);
14867     }
14868
14869   clutter_actor_queue_relayout (self);
14870
14871   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
14872 }
14873
14874 /**
14875  * clutter_actor_get_layout_manager:
14876  * @self: a #ClutterActor
14877  *
14878  * Retrieves the #ClutterLayoutManager used by @self.
14879  *
14880  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
14881  *   or %NULL
14882  *
14883  * Since: 1.10
14884  */
14885 ClutterLayoutManager *
14886 clutter_actor_get_layout_manager (ClutterActor *self)
14887 {
14888   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14889
14890   return self->priv->layout_manager;
14891 }
14892
14893 static const ClutterLayoutInfo default_layout_info = {
14894   0.f,                          /* fixed-x */
14895   0.f,                          /* fixed-y */
14896   { 0, 0, 0, 0 },               /* margin */
14897   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
14898   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
14899   0.f, 0.f,                     /* min_width, natural_width */
14900   0.f, 0.f,                     /* natual_width, natural_height */
14901 };
14902
14903 static void
14904 layout_info_free (gpointer data)
14905 {
14906   if (G_LIKELY (data != NULL))
14907     g_slice_free (ClutterLayoutInfo, data);
14908 }
14909
14910 /*< private >
14911  * _clutter_actor_get_layout_info:
14912  * @self: a #ClutterActor
14913  *
14914  * Retrieves a pointer to the ClutterLayoutInfo structure.
14915  *
14916  * If the actor does not have a ClutterLayoutInfo associated to it, one
14917  * will be created and initialized to the default values.
14918  *
14919  * This function should be used for setters.
14920  *
14921  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
14922  * instead.
14923  *
14924  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
14925  */
14926 ClutterLayoutInfo *
14927 _clutter_actor_get_layout_info (ClutterActor *self)
14928 {
14929   ClutterLayoutInfo *retval;
14930
14931   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
14932   if (retval == NULL)
14933     {
14934       retval = g_slice_new (ClutterLayoutInfo);
14935
14936       *retval = default_layout_info;
14937
14938       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
14939                                retval,
14940                                layout_info_free);
14941     }
14942
14943   return retval;
14944 }
14945
14946 /*< private >
14947  * _clutter_actor_get_layout_info_or_defaults:
14948  * @self: a #ClutterActor
14949  *
14950  * Retrieves the ClutterLayoutInfo structure associated to an actor.
14951  *
14952  * If the actor does not have a ClutterLayoutInfo structure associated to it,
14953  * then the default structure will be returned.
14954  *
14955  * This function should only be used for getters.
14956  *
14957  * Return value: a const pointer to the ClutterLayoutInfo structure
14958  */
14959 const ClutterLayoutInfo *
14960 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
14961 {
14962   const ClutterLayoutInfo *info;
14963
14964   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
14965   if (info == NULL)
14966     return &default_layout_info;
14967
14968   return info;
14969 }
14970
14971 /**
14972  * clutter_actor_set_x_align:
14973  * @self: a #ClutterActor
14974  * @x_align: the horizontal alignment policy
14975  *
14976  * Sets the horizontal alignment policy of a #ClutterActor, in case the
14977  * actor received extra horizontal space.
14978  *
14979  * See also the #ClutterActor:x-align property.
14980  *
14981  * Since: 1.10
14982  */
14983 void
14984 clutter_actor_set_x_align (ClutterActor      *self,
14985                            ClutterActorAlign  x_align)
14986 {
14987   ClutterLayoutInfo *info;
14988
14989   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14990
14991   info = _clutter_actor_get_layout_info (self);
14992
14993   if (info->x_align != x_align)
14994     {
14995       info->x_align = x_align;
14996
14997       clutter_actor_queue_relayout (self);
14998
14999       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15000     }
15001 }
15002
15003 /**
15004  * clutter_actor_get_x_align:
15005  * @self: a #ClutterActor
15006  *
15007  * Retrieves the horizontal alignment policy set using
15008  * clutter_actor_set_x_align().
15009  *
15010  * Return value: the horizontal alignment policy.
15011  *
15012  * Since: 1.10
15013  */
15014 ClutterActorAlign
15015 clutter_actor_get_x_align (ClutterActor *self)
15016 {
15017   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15018
15019   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15020 }
15021
15022 /**
15023  * clutter_actor_set_y_align:
15024  * @self: a #ClutterActor
15025  * @y_align: the vertical alignment policy
15026  *
15027  * Sets the vertical alignment policy of a #ClutterActor, in case the
15028  * actor received extra vertical space.
15029  *
15030  * See also the #ClutterActor:y-align property.
15031  *
15032  * Since: 1.10
15033  */
15034 void
15035 clutter_actor_set_y_align (ClutterActor      *self,
15036                            ClutterActorAlign  y_align)
15037 {
15038   ClutterLayoutInfo *info;
15039
15040   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15041
15042   info = _clutter_actor_get_layout_info (self);
15043
15044   if (info->y_align != y_align)
15045     {
15046       info->y_align = y_align;
15047
15048       clutter_actor_queue_relayout (self);
15049
15050       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15051     }
15052 }
15053
15054 /**
15055  * clutter_actor_get_y_align:
15056  * @self: a #ClutterActor
15057  *
15058  * Retrieves the vertical alignment policy set using
15059  * clutter_actor_set_y_align().
15060  *
15061  * Return value: the vertical alignment policy.
15062  *
15063  * Since: 1.10
15064  */
15065 ClutterActorAlign
15066 clutter_actor_get_y_align (ClutterActor *self)
15067 {
15068   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15069
15070   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15071 }
15072
15073
15074 /**
15075  * clutter_margin_new:
15076  *
15077  * Creates a new #ClutterMargin.
15078  *
15079  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15080  *   clutter_margin_free() to free the resources associated with it when
15081  *   done.
15082  *
15083  * Since: 1.10
15084  */
15085 ClutterMargin *
15086 clutter_margin_new (void)
15087 {
15088   return g_slice_new0 (ClutterMargin);
15089 }
15090
15091 /**
15092  * clutter_margin_copy:
15093  * @margin_: a #ClutterMargin
15094  *
15095  * Creates a new #ClutterMargin and copies the contents of @margin_ into
15096  * the newly created structure.
15097  *
15098  * Return value: (transfer full): a copy of the #ClutterMargin.
15099  *
15100  * Since: 1.10
15101  */
15102 ClutterMargin *
15103 clutter_margin_copy (const ClutterMargin *margin_)
15104 {
15105   if (G_LIKELY (margin_ != NULL))
15106     return g_slice_dup (ClutterMargin, margin_);
15107
15108   return NULL;
15109 }
15110
15111 /**
15112  * clutter_margin_free:
15113  * @margin_: a #ClutterMargin
15114  *
15115  * Frees the resources allocated by clutter_margin_new() and
15116  * clutter_margin_copy().
15117  *
15118  * Since: 1.10
15119  */
15120 void
15121 clutter_margin_free (ClutterMargin *margin_)
15122 {
15123   if (G_LIKELY (margin_ != NULL))
15124     g_slice_free (ClutterMargin, margin_);
15125 }
15126
15127 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
15128                      clutter_margin_copy,
15129                      clutter_margin_free)
15130
15131 /**
15132  * clutter_actor_set_margin:
15133  * @self: a #ClutterActor
15134  * @margin: a #ClutterMargin
15135  *
15136  * Sets all the components of the margin of a #ClutterActor.
15137  *
15138  * Since: 1.10
15139  */
15140 void
15141 clutter_actor_set_margin (ClutterActor        *self,
15142                           const ClutterMargin *margin)
15143 {
15144   ClutterLayoutInfo *info;
15145   gboolean changed;
15146   GObject *obj;
15147
15148   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15149   g_return_if_fail (margin != NULL);
15150
15151   obj = G_OBJECT (self);
15152   changed = FALSE;
15153
15154   g_object_freeze_notify (obj);
15155
15156   info = _clutter_actor_get_layout_info (self);
15157
15158   if (info->margin.top != margin->top)
15159     {
15160       info->margin.top = margin->top;
15161       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
15162       changed = TRUE;
15163     }
15164
15165   if (info->margin.right != margin->right)
15166     {
15167       info->margin.right = margin->right;
15168       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
15169       changed = TRUE;
15170     }
15171
15172   if (info->margin.bottom != margin->bottom)
15173     {
15174       info->margin.bottom = margin->bottom;
15175       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
15176       changed = TRUE;
15177     }
15178
15179   if (info->margin.left != margin->left)
15180     {
15181       info->margin.left = margin->left;
15182       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
15183       changed = TRUE;
15184     }
15185
15186   if (changed)
15187     clutter_actor_queue_relayout (self);
15188
15189   g_object_thaw_notify (obj);
15190 }
15191
15192 /**
15193  * clutter_actor_get_margin:
15194  * @self: a #ClutterActor
15195  * @margin: (out caller-allocates): return location for a #ClutterMargin
15196  *
15197  * Retrieves all the components of the margin of a #ClutterActor.
15198  *
15199  * Since: 1.10
15200  */
15201 void
15202 clutter_actor_get_margin (ClutterActor  *self,
15203                           ClutterMargin *margin)
15204 {
15205   const ClutterLayoutInfo *info;
15206
15207   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15208   g_return_if_fail (margin != NULL);
15209
15210   info = _clutter_actor_get_layout_info_or_defaults (self);
15211
15212   *margin = info->margin;
15213 }
15214
15215 /**
15216  * clutter_actor_set_margin_top:
15217  * @self: a #ClutterActor
15218  * @margin: the top margin
15219  *
15220  * Sets the margin from the top of a #ClutterActor.
15221  *
15222  * Since: 1.10
15223  */
15224 void
15225 clutter_actor_set_margin_top (ClutterActor *self,
15226                               gfloat        margin)
15227 {
15228   ClutterLayoutInfo *info;
15229
15230   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15231   g_return_if_fail (margin >= 0.f);
15232
15233   info = _clutter_actor_get_layout_info (self);
15234
15235   if (info->margin.top == margin)
15236     return;
15237
15238   info->margin.top = margin;
15239
15240   clutter_actor_queue_relayout (self);
15241
15242   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
15243 }
15244
15245 /**
15246  * clutter_actor_get_margin_top:
15247  * @self: a #ClutterActor
15248  *
15249  * Retrieves the top margin of a #ClutterActor.
15250  *
15251  * Return value: the top margin
15252  *
15253  * Since: 1.10
15254  */
15255 gfloat
15256 clutter_actor_get_margin_top (ClutterActor *self)
15257 {
15258   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15259
15260   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
15261 }
15262
15263 /**
15264  * clutter_actor_set_margin_bottom:
15265  * @self: a #ClutterActor
15266  * @margin: the bottom margin
15267  *
15268  * Sets the margin from the bottom of a #ClutterActor.
15269  *
15270  * Since: 1.10
15271  */
15272 void
15273 clutter_actor_set_margin_bottom (ClutterActor *self,
15274                                  gfloat        margin)
15275 {
15276   ClutterLayoutInfo *info;
15277
15278   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15279   g_return_if_fail (margin >= 0.f);
15280
15281   info = _clutter_actor_get_layout_info (self);
15282
15283   if (info->margin.bottom == margin)
15284     return;
15285
15286   info->margin.bottom = margin;
15287
15288   clutter_actor_queue_relayout (self);
15289
15290   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
15291 }
15292
15293 /**
15294  * clutter_actor_get_margin_bottom:
15295  * @self: a #ClutterActor
15296  *
15297  * Retrieves the bottom margin of a #ClutterActor.
15298  *
15299  * Return value: the bottom margin
15300  *
15301  * Since: 1.10
15302  */
15303 gfloat
15304 clutter_actor_get_margin_bottom (ClutterActor *self)
15305 {
15306   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15307
15308   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
15309 }
15310
15311 /**
15312  * clutter_actor_set_margin_left:
15313  * @self: a #ClutterActor
15314  * @margin: the left margin
15315  *
15316  * Sets the margin from the left of a #ClutterActor.
15317  *
15318  * Since: 1.10
15319  */
15320 void
15321 clutter_actor_set_margin_left (ClutterActor *self,
15322                                gfloat        margin)
15323 {
15324   ClutterLayoutInfo *info;
15325
15326   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15327   g_return_if_fail (margin >= 0.f);
15328
15329   info = _clutter_actor_get_layout_info (self);
15330
15331   if (info->margin.left == margin)
15332     return;
15333
15334   info->margin.left = margin;
15335
15336   clutter_actor_queue_relayout (self);
15337
15338   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
15339 }
15340
15341 /**
15342  * clutter_actor_get_margin_left:
15343  * @self: a #ClutterActor
15344  *
15345  * Retrieves the left margin of a #ClutterActor.
15346  *
15347  * Return value: the left margin
15348  *
15349  * Since: 1.10
15350  */
15351 gfloat
15352 clutter_actor_get_margin_left (ClutterActor *self)
15353 {
15354   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15355
15356   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
15357 }
15358
15359 /**
15360  * clutter_actor_set_margin_right:
15361  * @self: a #ClutterActor
15362  * @margin: the right margin
15363  *
15364  * Sets the margin from the right of a #ClutterActor.
15365  *
15366  * Since: 1.10
15367  */
15368 void
15369 clutter_actor_set_margin_right (ClutterActor *self,
15370                                 gfloat        margin)
15371 {
15372   ClutterLayoutInfo *info;
15373
15374   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15375   g_return_if_fail (margin >= 0.f);
15376
15377   info = _clutter_actor_get_layout_info (self);
15378
15379   if (info->margin.right == margin)
15380     return;
15381
15382   info->margin.right = margin;
15383
15384   clutter_actor_queue_relayout (self);
15385
15386   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
15387 }
15388
15389 /**
15390  * clutter_actor_get_margin_right:
15391  * @self: a #ClutterActor
15392  *
15393  * Retrieves the right margin of a #ClutterActor.
15394  *
15395  * Return value: the right margin
15396  *
15397  * Since: 1.10
15398  */
15399 gfloat
15400 clutter_actor_get_margin_right (ClutterActor *self)
15401 {
15402   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15403
15404   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
15405 }
15406
15407 /**
15408  * clutter_actor_set_background_color:
15409  * @self: a #ClutterActor
15410  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
15411  *  set color
15412  *
15413  * Sets the background color of a #ClutterActor.
15414  *
15415  * The background color will be used to cover the whole allocation of the
15416  * actor. The default background color of an actor is transparent.
15417  *
15418  * To check whether an actor has a background color, you can use the
15419  * #ClutterActor:background-color-set actor property.
15420  *
15421  * Since: 1.10
15422  */
15423 void
15424 clutter_actor_set_background_color (ClutterActor       *self,
15425                                     const ClutterColor *color)
15426 {
15427   ClutterActorPrivate *priv;
15428
15429   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15430
15431   priv = self->priv;
15432
15433   if (color == NULL)
15434     {
15435       priv->bg_color_set = FALSE;
15436       g_object_notify_by_pspec (G_OBJECT (self),
15437                                 obj_props[PROP_BACKGROUND_COLOR_SET]);
15438       return;
15439     }
15440
15441   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
15442     return;
15443
15444   priv->bg_color = *color;
15445   priv->bg_color_set = TRUE;
15446
15447   clutter_actor_queue_redraw (self);
15448
15449   g_object_notify_by_pspec (G_OBJECT (self),
15450                             obj_props[PROP_BACKGROUND_COLOR_SET]);
15451   g_object_notify_by_pspec (G_OBJECT (self),
15452                             obj_props[PROP_BACKGROUND_COLOR]);
15453 }
15454
15455 /**
15456  * clutter_actor_get_background_color:
15457  * @self: a #ClutterActor
15458  * @color: (out caller-allocates): return location for a #ClutterColor
15459  *
15460  * Retrieves the color set using clutter_actor_set_background_color().
15461  *
15462  * Since: 1.10
15463  */
15464 void
15465 clutter_actor_get_background_color (ClutterActor *self,
15466                                     ClutterColor *color)
15467 {
15468   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15469   g_return_if_fail (color != NULL);
15470
15471   *color = self->priv->bg_color;
15472 }
15473
15474 /**
15475  * clutter_actor_get_previous_sibling:
15476  * @self: a #ClutterActor
15477  *
15478  * Retrieves the sibling of @self that comes before it in the list
15479  * of children of @self's parent.
15480  *
15481  * The returned pointer is only valid until the scene graph changes; it
15482  * is not safe to modify the list of children of @self while iterating
15483  * it.
15484  *
15485  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15486  *
15487  * Since: 1.10
15488  */
15489 ClutterActor *
15490 clutter_actor_get_previous_sibling (ClutterActor *self)
15491 {
15492   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15493
15494   return self->priv->prev_sibling;
15495 }
15496
15497 /**
15498  * clutter_actor_get_next_sibling:
15499  * @self: a #ClutterActor
15500  *
15501  * Retrieves the sibling of @self that comes after it in the list
15502  * of children of @self's parent.
15503  *
15504  * The returned pointer is only valid until the scene graph changes; it
15505  * is not safe to modify the list of children of @self while iterating
15506  * it.
15507  *
15508  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15509  *
15510  * Since: 1.10
15511  */
15512 ClutterActor *
15513 clutter_actor_get_next_sibling (ClutterActor *self)
15514 {
15515   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15516
15517   return self->priv->next_sibling;
15518 }
15519
15520 /**
15521  * clutter_actor_get_first_child:
15522  * @self: a #ClutterActor
15523  *
15524  * Retrieves the first child of @self.
15525  *
15526  * The returned pointer is only valid until the scene graph changes; it
15527  * is not safe to modify the list of children of @self while iterating
15528  * it.
15529  *
15530  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15531  *
15532  * Since: 1.10
15533  */
15534 ClutterActor *
15535 clutter_actor_get_first_child (ClutterActor *self)
15536 {
15537   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15538
15539   return self->priv->first_child;
15540 }
15541
15542 /**
15543  * clutter_actor_get_last_child:
15544  * @self: a #ClutterActor
15545  *
15546  * Retrieves the last child of @self.
15547  *
15548  * The returned pointer is only valid until the scene graph changes; it
15549  * is not safe to modify the list of children of @self while iterating
15550  * it.
15551  *
15552  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15553  *
15554  * Since: 1.10
15555  */
15556 ClutterActor *
15557 clutter_actor_get_last_child (ClutterActor *self)
15558 {
15559   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15560
15561   return self->priv->last_child;
15562 }
15563
15564 /* easy way to have properly named fields instead of the dummy ones
15565  * we use in the public structure
15566  */
15567 typedef struct _RealActorIter
15568 {
15569   ClutterActor *root;           /* dummy1 */
15570   ClutterActor *current;        /* dummy2 */
15571   gpointer padding_1;           /* dummy3 */
15572   gint age;                     /* dummy4 */
15573   gpointer padding_2;           /* dummy5 */
15574 } RealActorIter;
15575
15576 /**
15577  * clutter_actor_iter_init:
15578  * @iter: a #ClutterActorIter
15579  * @root: a #ClutterActor
15580  *
15581  * Initializes a #ClutterActorIter, which can then be used to iterate
15582  * efficiently over a section of the scene graph, and associates it
15583  * with @root.
15584  *
15585  * Modifying the scene graph section that contains @root will invalidate
15586  * the iterator.
15587  *
15588  * |[
15589  *   ClutterActorIter iter;
15590  *   ClutterActor *child;
15591  *
15592  *   clutter_actor_iter_init (&iter, container);
15593  *   while (clutter_actor_iter_next (&iter, &child))
15594  *     {
15595  *       /&ast; do something with child &ast;/
15596  *     }
15597  * ]|
15598  *
15599  * Since: 1.10
15600  */
15601 void
15602 clutter_actor_iter_init (ClutterActorIter *iter,
15603                          ClutterActor     *root)
15604 {
15605   RealActorIter *ri = (RealActorIter *) iter;
15606
15607   g_return_if_fail (iter != NULL);
15608   g_return_if_fail (CLUTTER_IS_ACTOR (root));
15609
15610   ri->root = root;
15611   ri->current = NULL;
15612   ri->age = root->priv->age;
15613 }
15614
15615 /**
15616  * clutter_actor_iter_next:
15617  * @iter: a #ClutterActorIter
15618  * @child: (out): return location for a #ClutterActor
15619  *
15620  * Advances the @iter and retrieves the next child of the root #ClutterActor
15621  * that was used to initialize the #ClutterActorIterator.
15622  *
15623  * If the iterator can advance, this function returns %TRUE and sets the
15624  * @child argument.
15625  *
15626  * If the iterator cannot advance, this function returns %FALSE, and
15627  * the contents of @child are undefined.
15628  *
15629  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15630  *
15631  * Since: 1.10
15632  */
15633 gboolean
15634 clutter_actor_iter_next (ClutterActorIter  *iter,
15635                          ClutterActor     **child)
15636 {
15637   RealActorIter *ri = (RealActorIter *) iter;
15638
15639   g_return_val_if_fail (iter != NULL, FALSE);
15640   g_return_val_if_fail (ri->root != NULL, FALSE);
15641 #ifndef G_DISABLE_ASSERT
15642   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15643 #endif
15644
15645   if (ri->current == NULL)
15646     ri->current = ri->root->priv->first_child;
15647   else
15648     ri->current = ri->current->priv->next_sibling;
15649
15650   if (child != NULL)
15651     *child = ri->current;
15652
15653   return ri->current != NULL;
15654 }
15655
15656 /**
15657  * clutter_actor_iter_next:
15658  * @iter: a #ClutterActorIter
15659  * @child: (out): return location for a #ClutterActor
15660  *
15661  * Advances the @iter and retrieves the previous child of the root
15662  * #ClutterActor that was used to initialize the #ClutterActorIterator.
15663  *
15664  * If the iterator can advance, this function returns %TRUE and sets the
15665  * @child argument.
15666  *
15667  * If the iterator cannot advance, this function returns %FALSE, and
15668  * the contents of @child are undefined.
15669  *
15670  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15671  *
15672  * Since: 1.10
15673  */
15674 gboolean
15675 clutter_actor_iter_prev (ClutterActorIter  *iter,
15676                          ClutterActor     **child)
15677 {
15678   RealActorIter *ri = (RealActorIter *) iter;
15679
15680   g_return_val_if_fail (iter != NULL, FALSE);
15681   g_return_val_if_fail (ri->root != NULL, FALSE);
15682 #ifndef G_DISABLE_ASSERT
15683   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15684 #endif
15685
15686   if (ri->current == NULL)
15687     ri->current = ri->root->priv->last_child;
15688   else
15689     ri->current = ri->current->priv->prev_sibling;
15690
15691   if (child != NULL)
15692     *child = ri->current;
15693
15694   return ri->current != NULL;
15695 }
15696
15697 /**
15698  * clutter_actor_iter_remove:
15699  * @iter: a #ClutterActorIter
15700  *
15701  * Safely removes the #ClutterActor currently pointer to by the iterator
15702  * from its parent.
15703  *
15704  * This function can only be called after clutter_actor_iter_next() or
15705  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15706  * than once for the same actor.
15707  *
15708  * This function will call clutter_actor_remove_child() internally.
15709  *
15710  * Since: 1.10
15711  */
15712 void
15713 clutter_actor_iter_remove (ClutterActorIter *iter)
15714 {
15715   RealActorIter *ri = (RealActorIter *) iter;
15716   ClutterActor *cur;
15717
15718   g_return_if_fail (iter != NULL);
15719   g_return_if_fail (ri->root != NULL);
15720 #ifndef G_DISABLE_ASSERT
15721   g_return_if_fail (ri->age == ri->root->priv->age);
15722 #endif
15723   g_return_if_fail (ri->current != NULL);
15724
15725   cur = ri->current;
15726
15727   if (cur != NULL)
15728     {
15729       ri->current = cur->priv->prev_sibling;
15730
15731       clutter_actor_remove_child_internal (ri->root, cur,
15732                                            REMOVE_CHILD_DEFAULT_FLAGS);
15733
15734       ri->age += 1;
15735     }
15736 }
15737
15738 /**
15739  * clutter_actor_iter_destroy:
15740  * @iter: a #ClutterActorIter
15741  *
15742  * Safely destroys the #ClutterActor currently pointer to by the iterator
15743  * from its parent.
15744  *
15745  * This function can only be called after clutter_actor_iter_next() or
15746  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15747  * than once for the same actor.
15748  *
15749  * This function will call clutter_actor_destroy() internally.
15750  *
15751  * Since: 1.10
15752  */
15753 void
15754 clutter_actor_iter_destroy (ClutterActorIter *iter)
15755 {
15756   RealActorIter *ri = (RealActorIter *) iter;
15757   ClutterActor *cur;
15758
15759   g_return_if_fail (iter != NULL);
15760   g_return_if_fail (ri->root != NULL);
15761 #ifndef G_DISABLE_ASSERT
15762   g_return_if_fail (ri->age == ri->root->priv->age);
15763 #endif
15764   g_return_if_fail (ri->current != NULL);
15765
15766   cur = ri->current;
15767
15768   if (cur != NULL)
15769     {
15770       ri->current = cur->priv->prev_sibling;
15771
15772       clutter_actor_destroy (cur);
15773
15774       ri->age += 1;
15775     }
15776 }