property-transition: Remove animatable from the ctor
[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, 2011, 2012 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: The basic element of the scene graph 
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="actor-example-image">
113  *     <title>Actors</title>
114  *     <graphic fileref="actor-example.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-painting">
119  *   <title>Painting an actor</title>
120  *   <para>There are three ways to paint an actor:</para>
121  *   <itemizedlist>
122  *     <listitem><para>set a delegate #ClutterContent as the value for the
123  *     #ClutterActor:content property of the actor;</para></listitem>
124  *     <listitem><para>subclass #ClutterActor and override the
125  *     #ClutterActorClass.paint_node() virtual function;</para></listitem>
126  *     <listitem><para>subclass #ClutterActor and override the
127  *     #ClutterActorClass.paint() virtual function.</para></listitem>
128  *   </itemizedlist>
129  *   <formalpara>
130  *     <title>Setting the Content property</title>
131  *     <para>A #ClutterContent is a delegate object that takes over the
132  *     painting operation of one, or more actors. The #ClutterContent
133  *     painting will be performed on top of the #ClutterActor:background-color
134  *     of the actor, and before calling the #ClutterActorClass.paint_node()
135  *     virtual function.</para>
136  *     <informalexample><programlisting>
137  * ClutterActor *actor = clutter_actor_new ();
138  *
139  * /&ast; set the bounding box &ast;/
140  * clutter_actor_set_position (actor, 50, 50);
141  * clutter_actor_set_size (actor, 100, 100);
142  *
143  * /&ast; set the content; the image_content variable is set elsewhere &ast;/
144  * clutter_actor_set_content (actor, image_content);
145  *     </programlisting></informalexample>
146  *   </formalpara>
147  *   <formalpara>
148  *     <title>Overriding the paint_node virtual function</title>
149  *     <para>The #ClutterActorClass.paint_node() virtual function is invoked
150  *     whenever an actor needs to be painted. The implementation of the
151  *     virtual function must only paint the contents of the actor itself,
152  *     and not the contents of its children, if the actor has any.</para>
153  *     <para>The #ClutterPaintNode passed to the virtual function is the
154  *     local root of the render tree; any node added to it will be
155  *     rendered at the correct position, as defined by the actor's
156  *     #ClutterActor:allocation.</para>
157  *     <informalexample><programlisting>
158  * static void
159  * my_actor_paint_node (ClutterActor     *actor,
160  *                      ClutterPaintNode *root)
161  * {
162  *   ClutterPaintNode *node;
163  *   ClutterActorBox box;
164  *
165  *   /&ast; where the content of the actor should be painted &ast;/
166  *   clutter_actor_get_allocation_box (actor, &box);
167  *
168  *   /&ast; the cogl_texture variable is set elsewhere &ast;/
169  *   node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White,
170  *                                    CLUTTER_SCALING_FILTER_TRILINEAR,
171  *                                    CLUTTER_SCALING_FILTER_LINEAR);
172  *
173  *   /&ast; paint the content of the node using the allocation &ast;/
174  *   clutter_paint_node_add_rectangle (node, &box);
175  *
176  *   /&ast; add the node, and transfer ownership &ast;/
177  *   clutter_paint_node_add_child (root, node);
178  *   clutter_paint_node_unref (node);
179  * }
180  *     </programlisting></informalexample>
181  *   </formalpara>
182  *   <formalpara>
183  *     <title>Overriding the paint virtual function</title>
184  *     <para>The #ClutterActorClass.paint() virtual function is invoked
185  *     when the #ClutterActor::paint signal is emitted, and after the other
186  *     signal handlers have been invoked. Overriding the paint virtual
187  *     function gives total control to the paint sequence of the actor
188  *     itself, including the children of the actor, if any.</para>
189  *     <warning><para>It is strongly discouraged to override the
190  *     #ClutterActorClass.paint() virtual function, as well as connecting
191  *     to the #ClutterActor::paint signal. These hooks into the paint
192  *     sequence are considered legacy, and will be removed when the Clutter
193  *     API changes.</para></warning>
194  *   </formalpara>
195  * </refsect2>
196  *
197  * <refsect2 id="ClutterActor-events">
198  *   <title>Handling events on an actor</title>
199  *   <para>A #ClutterActor can receive and handle input device events, for
200  *   instance pointer events and key events, as long as its
201  *   #ClutterActor:reactive property is set to %TRUE.</para>
202  *   <para>Once an actor has been determined to be the source of an event,
203  *   Clutter will traverse the scene graph from the top-level actor towards the
204  *   event source, emitting the #ClutterActor::captured-event signal on each
205  *   ancestor until it reaches the source; this phase is also called
206  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
207  *   stopped, the graph is walked backwards, from the source actor to the
208  *   top-level, and the #ClutterActor::event signal, along with other event
209  *   signals if needed, is emitted; this phase is also called <emphasis>the
210  *   bubble phase</emphasis>. At any point of the signal emission, signal
211  *   handlers can stop the propagation through the scene graph by returning
212  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
213  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
214  * </refsect2>
215  *
216  * <refsect2 id="ClutterActor-subclassing">
217  *   <title>Implementing an actor</title>
218  *   <para>Careful consideration should be given when deciding to implement
219  *   a #ClutterActor sub-class. It is generally recommended to implement a
220  *   sub-class of #ClutterActor only for actors that should be used as leaf
221  *   nodes of a scene graph.</para>
222  *   <para>If your actor should be painted in a custom way, you should
223  *   override the #ClutterActor::paint signal class handler. You can either
224  *   opt to chain up to the parent class implementation or decide to fully
225  *   override the default paint implementation; Clutter will set up the
226  *   transformations and clip regions prior to emitting the #ClutterActor::paint
227  *   signal.</para>
228  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
229  *   #ClutterActorClass.get_preferred_height() virtual functions it is
230  *   possible to change or provide the preferred size of an actor; similarly,
231  *   by overriding the #ClutterActorClass.allocate() virtual function it is
232  *   possible to control the layout of the children of an actor. Make sure to
233  *   always chain up to the parent implementation of the
234  *   #ClutterActorClass.allocate() virtual function.</para>
235  *   <para>In general, it is strongly encouraged to use delegation and
236  *   composition instead of direct subclassing.</para>
237  * </refsect2>
238  *
239  * <refsect2 id="ClutterActor-script">
240  *   <title>ClutterActor custom properties for #ClutterScript</title>
241  *   <para>#ClutterActor defines a custom "rotation" property which
242  *   allows a short-hand description of the rotations to be applied
243  *   to an actor.</para>
244  *   <para>The syntax of the "rotation" property is the following:</para>
245  *   <informalexample>
246  *     <programlisting>
247  * "rotation" : [
248  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
249  * ]
250  *     </programlisting>
251  *   </informalexample>
252  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
253  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
254  *   floating point value representing the rotation angle on the given axis,
255  *   in degrees.</para>
256  *   <para>The <emphasis>center</emphasis> array is optional, and if present
257  *   it must contain the center of rotation as described by two coordinates:
258  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
259  *   "z-axis".</para>
260  *   <para>#ClutterActor will also parse every positional and dimensional
261  *   property defined as a string through clutter_units_from_string(); you
262  *   should read the documentation for the #ClutterUnits parser format for
263  *   the valid units and syntax.</para>
264  * </refsect2>
265  *
266  * <refsect2 id="ClutterActor-animating">
267  *   <title>Custom animatable properties</title>
268  *   <para>#ClutterActor allows accessing properties of #ClutterAction
269  *   and #ClutterConstraint instances associated to an actor instance
270  *   for animation purposes.</para>
271  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
272  *   property it is necessary to set the #ClutterActorMeta:name property on the
273  *   given action or constraint.</para>
274  *   <para>The property can be accessed using the following syntax:</para>
275  *   <informalexample>
276  *     <programlisting>
277  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
278  *     </programlisting>
279  *   </informalexample>
280  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
281  *   <para>The <emphasis>section</emphasis> fragment can be one between
282  *   "actions", "constraints" and "effects".</para>
283  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
284  *   action or constraint, as specified by the #ClutterActorMeta:name
285  *   property.</para>
286  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
287  *   action or constraint property to be animated.</para>
288  *   <para>The example below animates a #ClutterBindConstraint applied to an
289  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
290  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
291  *   its initial state is fully transparent and overlapping the actor to
292  *   which is bound to. </para>
293  *   <informalexample><programlisting>
294  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
295  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
296  * clutter_actor_add_constraint (rect, constraint);
297  *
298  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
299  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
300  * clutter_actor_add_constraint (rect, constraint);
301  *
302  * clutter_actor_set_reactive (rect, TRUE);
303  * clutter_actor_set_opacity (rect, 0);
304  *
305  * g_signal_connect (rect, "button-press-event",
306  *                   G_CALLBACK (on_button_press),
307  *                   NULL);
308  *   </programlisting></informalexample>
309  *   <para>On button press, the rectangle "slides" from behind the actor to
310  *   which is bound to, using the #ClutterBindConstraint:offset property and
311  *   the #ClutterActor:opacity property.</para>
312  *   <informalexample><programlisting>
313  * float new_offset = clutter_actor_get_width (origin) + h_padding;
314  *
315  * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
316  *                        "opacity", 255,
317  *                        "@constraints.bind-x.offset", new_offset,
318  *                        NULL);
319  *   </programlisting></informalexample>
320  * </refsect2>
321  *
322  * <refsect2 id="ClutterActor-animatable-properties">
323  *   <title>Animatable properties</title>
324  *   <para>Certain properties on #ClutterActor are marked as "animatable";
325  *   these properties will be automatically tweened between the current
326  *   value and the new value when one is set.</para>
327  *   <para>For backward compatibility, animatable properties will only be
328  *   tweened if the easing duration is greater than 0, or if a new easing
329  *   state is set, for instance the following example:</para>
330  *   <informalexample><programlisting>
331  * clutter_actor_save_easing_state (actor);
332  * clutter_actor_set_position (actor, 200, 200);
333  * clutter_actor_restore_easing_state (actor);
334  *   </programlisting></informalexample>
335  *   <para>will tween the actor to the (200, 200) coordinates using the default
336  *   easing mode and duration of a new easing state. The example above is
337  *   equivalent to the following code:</para>
338  *   <informalexample><programlisting>
339  * clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC);
340  * clutter_actor_set_easing_duration (actor, 250);
341  * clutter_actor_set_position (actor, 200, 200);
342  * clutter_actor_restore_easing_state (actor);
343  *   </programlisting></informalexample>
344  *   <para>It is possible to nest easing states to tween animatable
345  *   properties using different modes and durations, for instance:</para>
346  *   <informalexample><programlisting>
347  * clutter_actor_save_easing_state (actor); /&ast; outer state &ast;/
348  *
349  * /&ast; set the duration of the animation to 2 seconds and change position &ast;/
350  * clutter_actor_set_easing_duration (actor, 2000);
351  * clutter_actor_set_position (actor, 0, 0);
352  *
353  * clutter_actor_save_easing_state (actor); /&ast; inner state &ast;/
354  *
355  * /&ast; set the duration of the animation to 5 seconds and change depth and opacity &ast;/
356  * clutter_actor_set_easing_duration (actor, 5000);
357  * clutter_actor_set_depth (actor, 200);
358  * clutter_actor_set_opacity (actor, 0);
359  *
360  * clutter_actor_restore_easing_state (actor);
361  *
362  * clutter_actor_restore_easing_state (actor);
363  *   </programlisting></informalexample>
364  * </refsect2>
365  */
366
367 /**
368  * CLUTTER_ACTOR_IS_MAPPED:
369  * @a: a #ClutterActor
370  *
371  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
372  *
373  * The mapped state is set when the actor is visible and all its parents up
374  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
375  *
376  * This check can be used to see if an actor is going to be painted, as only
377  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
378  *
379  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
380  * not be checked directly; instead, the recommended usage is to connect a
381  * handler on the #GObject::notify signal for the #ClutterActor:mapped
382  * property of #ClutterActor, and check the presence of
383  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
384  *
385  * It is also important to note that Clutter may delay the changes of
386  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
387  * limitations, or during the reparenting of an actor, to optimize
388  * unnecessary (and potentially expensive) state changes.
389  *
390  * Since: 0.2
391  */
392
393 /**
394  * CLUTTER_ACTOR_IS_REALIZED:
395  * @a: a #ClutterActor
396  *
397  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
398  *
399  * The realized state has an actor-dependant interpretation. If an
400  * actor wants to delay allocating resources until it is attached to a
401  * stage, it may use the realize state to do so. However it is
402  * perfectly acceptable for an actor to allocate Cogl resources before
403  * being realized because there is only one drawing context used by Clutter
404  * so any resources will work on any stage.  If an actor is mapped it
405  * must also be realized, but an actor can be realized and unmapped
406  * (this is so hiding an actor temporarily doesn't do an expensive
407  * unrealize/realize).
408  *
409  * To be realized an actor must be inside a stage, and all its parents
410  * must be realized.
411  *
412  * Since: 0.2
413  */
414
415 /**
416  * CLUTTER_ACTOR_IS_VISIBLE:
417  * @a: a #ClutterActor
418  *
419  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
420  * Equivalent to the ClutterActor::visible object property.
421  *
422  * Note that an actor is only painted onscreen if it's mapped, which
423  * means it's visible, and all its parents are visible, and one of the
424  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
425  *
426  * Since: 0.2
427  */
428
429 /**
430  * CLUTTER_ACTOR_IS_REACTIVE:
431  * @a: a #ClutterActor
432  *
433  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
434  *
435  * Only reactive actors will receive event-related signals.
436  *
437  * Since: 0.6
438  */
439
440 #ifdef HAVE_CONFIG_H
441 #include "config.h"
442 #endif
443
444 #include <math.h>
445
446 #include <gobject/gvaluecollector.h>
447
448 #include <cogl/cogl.h>
449
450 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
451 #define CLUTTER_ENABLE_EXPERIMENTAL_API
452
453 #include "clutter-actor-private.h"
454
455 #include "clutter-action.h"
456 #include "clutter-actor-meta-private.h"
457 #include "clutter-animatable.h"
458 #include "clutter-color-static.h"
459 #include "clutter-color.h"
460 #include "clutter-constraint.h"
461 #include "clutter-container.h"
462 #include "clutter-content-private.h"
463 #include "clutter-debug.h"
464 #include "clutter-effect-private.h"
465 #include "clutter-enum-types.h"
466 #include "clutter-fixed-layout.h"
467 #include "clutter-flatten-effect.h"
468 #include "clutter-interval.h"
469 #include "clutter-main.h"
470 #include "clutter-marshal.h"
471 #include "clutter-paint-nodes.h"
472 #include "clutter-paint-node-private.h"
473 #include "clutter-paint-volume-private.h"
474 #include "clutter-private.h"
475 #include "clutter-profile.h"
476 #include "clutter-property-transition.h"
477 #include "clutter-scriptable.h"
478 #include "clutter-script-private.h"
479 #include "clutter-stage-private.h"
480 #include "clutter-timeline.h"
481 #include "clutter-transition.h"
482 #include "clutter-units.h"
483
484 #include "deprecated/clutter-actor.h"
485 #include "deprecated/clutter-behaviour.h"
486 #include "deprecated/clutter-container.h"
487
488 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
489 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
490
491 /* Internal enum used to control mapped state update.  This is a hint
492  * which indicates when to do something other than just enforce
493  * invariants.
494  */
495 typedef enum {
496   MAP_STATE_CHECK,           /* just enforce invariants. */
497   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
498                               * used when about to unparent.
499                               */
500   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
501                               * used to set mapped on toplevels.
502                               */
503   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
504                               * used just before unmapping parent.
505                               */
506 } MapStateChange;
507
508 /* 3 entries should be a good compromise, few layout managers
509  * will ask for 3 different preferred size in each allocation cycle */
510 #define N_CACHED_SIZE_REQUESTS 3
511
512 struct _ClutterActorPrivate
513 {
514   /* request mode */
515   ClutterRequestMode request_mode;
516
517   /* our cached size requests for different width / height */
518   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
519   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
520
521   /* An age of 0 means the entry is not set */
522   guint cached_height_age;
523   guint cached_width_age;
524
525   /* the bounding box of the actor, relative to the parent's
526    * allocation
527    */
528   ClutterActorBox allocation;
529   ClutterAllocationFlags allocation_flags;
530
531   /* clip, in actor coordinates */
532   cairo_rectangle_t clip;
533
534   /* the cached transformation matrix; see apply_transform() */
535   CoglMatrix transform;
536
537   guint8 opacity;
538   gint opacity_override;
539
540   ClutterOffscreenRedirect offscreen_redirect;
541
542   /* This is an internal effect used to implement the
543      offscreen-redirect property */
544   ClutterEffect *flatten_effect;
545
546   /* scene graph */
547   ClutterActor *parent;
548   ClutterActor *prev_sibling;
549   ClutterActor *next_sibling;
550   ClutterActor *first_child;
551   ClutterActor *last_child;
552
553   gint n_children;
554
555   /* tracks whenever the children of an actor are changed; the
556    * age is incremented by 1 whenever an actor is added or
557    * removed. the age is not incremented when the first or the
558    * last child pointers are changed, or when grandchildren of
559    * an actor are changed.
560    */
561   gint age;
562
563   gchar *name; /* a non-unique name, used for debugging */
564   guint32 id; /* unique id, used for backward compatibility */
565
566   gint32 pick_id; /* per-stage unique id, used for picking */
567
568   /* a back-pointer to the Pango context that we can use
569    * to create pre-configured PangoLayout
570    */
571   PangoContext *pango_context;
572
573   /* the text direction configured for this child - either by
574    * application code, or by the actor's parent
575    */
576   ClutterTextDirection text_direction;
577
578   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
579   gint internal_child;
580
581   /* meta classes */
582   ClutterMetaGroup *actions;
583   ClutterMetaGroup *constraints;
584   ClutterMetaGroup *effects;
585
586   /* delegate object used to allocate the children of this actor */
587   ClutterLayoutManager *layout_manager;
588
589   /* delegate object used to paint the contents of this actor */
590   ClutterContent *content;
591
592   ClutterContentGravity content_gravity;
593   ClutterScalingFilter min_filter;
594   ClutterScalingFilter mag_filter;
595
596   /* used when painting, to update the paint volume */
597   ClutterEffect *current_effect;
598
599   /* This is used to store an effect which needs to be redrawn. A
600      redraw can be queued to start from a particular effect. This is
601      used by parametrised effects that can cache an image of the
602      actor. If a parameter of the effect changes then it only needs to
603      redraw the cached image, not the actual actor. The pointer is
604      only valid if is_dirty == TRUE. If the pointer is NULL then the
605      whole actor is dirty. */
606   ClutterEffect *effect_to_redraw;
607
608   /* This is used when painting effects to implement the
609      clutter_actor_continue_paint() function. It points to the node in
610      the list of effects that is next in the chain */
611   const GList *next_effect_to_paint;
612
613   ClutterPaintVolume paint_volume;
614
615   /* NB: This volume isn't relative to this actor, it is in eye
616    * coordinates so that it can remain valid after the actor changes.
617    */
618   ClutterPaintVolume last_paint_volume;
619
620   ClutterStageQueueRedrawEntry *queue_redraw_entry;
621
622   ClutterColor bg_color;
623
624   /* bitfields */
625
626   /* fixed position and sizes */
627   guint position_set                : 1;
628   guint min_width_set               : 1;
629   guint min_height_set              : 1;
630   guint natural_width_set           : 1;
631   guint natural_height_set          : 1;
632   /* cached request is invalid (implies allocation is too) */
633   guint needs_width_request         : 1;
634   /* cached request is invalid (implies allocation is too) */
635   guint needs_height_request        : 1;
636   /* cached allocation is invalid (request has changed, probably) */
637   guint needs_allocation            : 1;
638   guint show_on_set_parent          : 1;
639   guint has_clip                    : 1;
640   guint clip_to_allocation          : 1;
641   guint enable_model_view_transform : 1;
642   guint enable_paint_unmapped       : 1;
643   guint has_pointer                 : 1;
644   guint propagated_one_redraw       : 1;
645   guint paint_volume_valid          : 1;
646   guint last_paint_volume_valid     : 1;
647   guint in_clone_paint              : 1;
648   guint transform_valid             : 1;
649   /* This is TRUE if anything has queued a redraw since we were last
650      painted. In this case effect_to_redraw will point to an effect
651      the redraw was queued from or it will be NULL if the redraw was
652      queued without an effect. */
653   guint is_dirty                    : 1;
654   guint bg_color_set                : 1;
655 };
656
657 enum
658 {
659   PROP_0,
660
661   PROP_NAME,
662
663   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
664    * when set they force a size request, when gotten they
665    * get the allocation if the allocation is valid, and the
666    * request otherwise
667    */
668   PROP_X,
669   PROP_Y,
670   PROP_WIDTH,
671   PROP_HEIGHT,
672
673   /* Then the rest of these size-related properties are the "actual"
674    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
675    */
676   PROP_FIXED_X,
677   PROP_FIXED_Y,
678
679   PROP_FIXED_POSITION_SET,
680
681   PROP_MIN_WIDTH,
682   PROP_MIN_WIDTH_SET,
683
684   PROP_MIN_HEIGHT,
685   PROP_MIN_HEIGHT_SET,
686
687   PROP_NATURAL_WIDTH,
688   PROP_NATURAL_WIDTH_SET,
689
690   PROP_NATURAL_HEIGHT,
691   PROP_NATURAL_HEIGHT_SET,
692
693   PROP_REQUEST_MODE,
694
695   /* Allocation properties are read-only */
696   PROP_ALLOCATION,
697
698   PROP_DEPTH,
699
700   PROP_CLIP,
701   PROP_HAS_CLIP,
702   PROP_CLIP_TO_ALLOCATION,
703
704   PROP_OPACITY,
705
706   PROP_OFFSCREEN_REDIRECT,
707
708   PROP_VISIBLE,
709   PROP_MAPPED,
710   PROP_REALIZED,
711   PROP_REACTIVE,
712
713   PROP_SCALE_X,
714   PROP_SCALE_Y,
715   PROP_SCALE_CENTER_X,
716   PROP_SCALE_CENTER_Y,
717   PROP_SCALE_GRAVITY,
718
719   PROP_ROTATION_ANGLE_X,
720   PROP_ROTATION_ANGLE_Y,
721   PROP_ROTATION_ANGLE_Z,
722   PROP_ROTATION_CENTER_X,
723   PROP_ROTATION_CENTER_Y,
724   PROP_ROTATION_CENTER_Z,
725   /* This property only makes sense for the z rotation because the
726      others would depend on the actor having a size along the
727      z-axis */
728   PROP_ROTATION_CENTER_Z_GRAVITY,
729
730   PROP_ANCHOR_X,
731   PROP_ANCHOR_Y,
732   PROP_ANCHOR_GRAVITY,
733
734   PROP_SHOW_ON_SET_PARENT,
735
736   PROP_TEXT_DIRECTION,
737   PROP_HAS_POINTER,
738
739   PROP_ACTIONS,
740   PROP_CONSTRAINTS,
741   PROP_EFFECT,
742
743   PROP_LAYOUT_MANAGER,
744
745   PROP_X_ALIGN,
746   PROP_Y_ALIGN,
747   PROP_MARGIN_TOP,
748   PROP_MARGIN_BOTTOM,
749   PROP_MARGIN_LEFT,
750   PROP_MARGIN_RIGHT,
751
752   PROP_BACKGROUND_COLOR,
753   PROP_BACKGROUND_COLOR_SET,
754
755   PROP_FIRST_CHILD,
756   PROP_LAST_CHILD,
757
758   PROP_CONTENT,
759   PROP_CONTENT_GRAVITY,
760   PROP_CONTENT_BOX,
761   PROP_MINIFICATION_FILTER,
762   PROP_MAGNIFICATION_FILTER,
763
764   PROP_LAST
765 };
766
767 static GParamSpec *obj_props[PROP_LAST];
768
769 enum
770 {
771   SHOW,
772   HIDE,
773   DESTROY,
774   PARENT_SET,
775   KEY_FOCUS_IN,
776   KEY_FOCUS_OUT,
777   PAINT,
778   PICK,
779   REALIZE,
780   UNREALIZE,
781   QUEUE_REDRAW,
782   QUEUE_RELAYOUT,
783   EVENT,
784   CAPTURED_EVENT,
785   BUTTON_PRESS_EVENT,
786   BUTTON_RELEASE_EVENT,
787   SCROLL_EVENT,
788   KEY_PRESS_EVENT,
789   KEY_RELEASE_EVENT,
790   MOTION_EVENT,
791   ENTER_EVENT,
792   LEAVE_EVENT,
793   ALLOCATION_CHANGED,
794   TRANSITIONS_COMPLETED,
795
796   LAST_SIGNAL
797 };
798
799 static guint actor_signals[LAST_SIGNAL] = { 0, };
800
801 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
802 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
803 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
804 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
805
806 /* These setters are all static for now, maybe they should be in the
807  * public API, but they are perhaps obscure enough to leave only as
808  * properties
809  */
810 static void clutter_actor_set_min_width          (ClutterActor *self,
811                                                   gfloat        min_width);
812 static void clutter_actor_set_min_height         (ClutterActor *self,
813                                                   gfloat        min_height);
814 static void clutter_actor_set_natural_width      (ClutterActor *self,
815                                                   gfloat        natural_width);
816 static void clutter_actor_set_natural_height     (ClutterActor *self,
817                                                   gfloat        natural_height);
818 static void clutter_actor_set_min_width_set      (ClutterActor *self,
819                                                   gboolean      use_min_width);
820 static void clutter_actor_set_min_height_set     (ClutterActor *self,
821                                                   gboolean      use_min_height);
822 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
823                                                   gboolean  use_natural_width);
824 static void clutter_actor_set_natural_height_set (ClutterActor *self,
825                                                   gboolean  use_natural_height);
826 static void clutter_actor_update_map_state       (ClutterActor  *self,
827                                                   MapStateChange change);
828 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
829
830 /* Helper routines for managing anchor coords */
831 static void clutter_anchor_coord_get_units (ClutterActor      *self,
832                                             const AnchorCoord *coord,
833                                             gfloat            *x,
834                                             gfloat            *y,
835                                             gfloat            *z);
836 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
837                                             gfloat             x,
838                                             gfloat             y,
839                                             gfloat             z);
840
841 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
842 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
843                                                         ClutterGravity     gravity);
844
845 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
846
847 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
848
849 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
850                                                                ClutterActor *ancestor,
851                                                                CoglMatrix *matrix);
852
853 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
854
855 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
856
857 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
858                                                                 const ClutterColor *color);
859
860 static void on_layout_manager_changed (ClutterLayoutManager *manager,
861                                        ClutterActor         *self);
862
863 /* Helper macro which translates by the anchor coord, applies the
864    given transformation and then translates back */
865 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
866   gfloat _tx, _ty, _tz;                                                \
867   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
868   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
869   { _transform; }                                                      \
870   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
871
872 static GQuark quark_shader_data = 0;
873 static GQuark quark_actor_layout_info = 0;
874 static GQuark quark_actor_transform_info = 0;
875 static GQuark quark_actor_animation_info = 0;
876
877 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
878                          clutter_actor,
879                          G_TYPE_INITIALLY_UNOWNED,
880                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
881                                                 clutter_container_iface_init)
882                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
883                                                 clutter_scriptable_iface_init)
884                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
885                                                 clutter_animatable_iface_init)
886                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
887                                                 atk_implementor_iface_init));
888
889 /*< private >
890  * clutter_actor_get_debug_name:
891  * @actor: a #ClutterActor
892  *
893  * Retrieves a printable name of @actor for debugging messages
894  *
895  * Return value: a string with a printable name
896  */
897 const gchar *
898 _clutter_actor_get_debug_name (ClutterActor *actor)
899 {
900   return actor->priv->name != NULL ? actor->priv->name
901                                    : G_OBJECT_TYPE_NAME (actor);
902 }
903
904 #ifdef CLUTTER_ENABLE_DEBUG
905 /* XXX - this is for debugging only, remove once working (or leave
906  * in only in some debug mode). Should leave it for a little while
907  * until we're confident in the new map/realize/visible handling.
908  */
909 static inline void
910 clutter_actor_verify_map_state (ClutterActor *self)
911 {
912   ClutterActorPrivate *priv = self->priv;
913
914   if (CLUTTER_ACTOR_IS_REALIZED (self))
915     {
916       /* all bets are off during reparent when we're potentially realized,
917        * but should not be according to invariants
918        */
919       if (!CLUTTER_ACTOR_IN_REPARENT (self))
920         {
921           if (priv->parent == NULL)
922             {
923               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
924                 {
925                 }
926               else
927                 g_warning ("Realized non-toplevel actor '%s' should "
928                            "have a parent",
929                            _clutter_actor_get_debug_name (self));
930             }
931           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
932             {
933               g_warning ("Realized actor %s has an unrealized parent %s",
934                          _clutter_actor_get_debug_name (self),
935                          _clutter_actor_get_debug_name (priv->parent));
936             }
937         }
938     }
939
940   if (CLUTTER_ACTOR_IS_MAPPED (self))
941     {
942       if (!CLUTTER_ACTOR_IS_REALIZED (self))
943         g_warning ("Actor '%s' is mapped but not realized",
944                    _clutter_actor_get_debug_name (self));
945
946       /* remaining bets are off during reparent when we're potentially
947        * mapped, but should not be according to invariants
948        */
949       if (!CLUTTER_ACTOR_IN_REPARENT (self))
950         {
951           if (priv->parent == NULL)
952             {
953               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
954                 {
955                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
956                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
957                     {
958                       g_warning ("Toplevel actor '%s' is mapped "
959                                  "but not visible",
960                                  _clutter_actor_get_debug_name (self));
961                     }
962                 }
963               else
964                 {
965                   g_warning ("Mapped actor '%s' should have a parent",
966                              _clutter_actor_get_debug_name (self));
967                 }
968             }
969           else
970             {
971               ClutterActor *iter = self;
972
973               /* check for the enable_paint_unmapped flag on the actor
974                * and parents; if the flag is enabled at any point of this
975                * branch of the scene graph then all the later checks
976                * become pointless
977                */
978               while (iter != NULL)
979                 {
980                   if (iter->priv->enable_paint_unmapped)
981                     return;
982
983                   iter = iter->priv->parent;
984                 }
985
986               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
987                 {
988                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
989                              "is not visible",
990                              _clutter_actor_get_debug_name (self),
991                              _clutter_actor_get_debug_name (priv->parent));
992                 }
993
994               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
995                 {
996                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
997                              "is not realized",
998                              _clutter_actor_get_debug_name (self),
999                              _clutter_actor_get_debug_name (priv->parent));
1000                 }
1001
1002               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1003                 {
1004                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1005                     g_warning ("Actor '%s' is mapped but its non-toplevel "
1006                                "parent '%s' is not mapped",
1007                                _clutter_actor_get_debug_name (self),
1008                                _clutter_actor_get_debug_name (priv->parent));
1009                 }
1010             }
1011         }
1012     }
1013 }
1014
1015 #endif /* CLUTTER_ENABLE_DEBUG */
1016
1017 static void
1018 clutter_actor_set_mapped (ClutterActor *self,
1019                           gboolean      mapped)
1020 {
1021   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1022     return;
1023
1024   if (mapped)
1025     {
1026       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1027       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1028     }
1029   else
1030     {
1031       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1032       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1033     }
1034 }
1035
1036 /* this function updates the mapped and realized states according to
1037  * invariants, in the appropriate order.
1038  */
1039 static void
1040 clutter_actor_update_map_state (ClutterActor  *self,
1041                                 MapStateChange change)
1042 {
1043   gboolean was_mapped;
1044
1045   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1046
1047   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1048     {
1049       /* the mapped flag on top-level actors must be set by the
1050        * per-backend implementation because it might be asynchronous.
1051        *
1052        * That is, the MAPPED flag on toplevels currently tracks the X
1053        * server mapped-ness of the window, while the expected behavior
1054        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1055        * This creates some weird complexity by breaking the invariant
1056        * that if we're visible and all ancestors shown then we are
1057        * also mapped - instead, we are mapped if all ancestors
1058        * _possibly excepting_ the stage are mapped. The stage
1059        * will map/unmap for example when it is minimized or
1060        * moved to another workspace.
1061        *
1062        * So, the only invariant on the stage is that if visible it
1063        * should be realized, and that it has to be visible to be
1064        * mapped.
1065        */
1066       if (CLUTTER_ACTOR_IS_VISIBLE (self))
1067         clutter_actor_realize (self);
1068
1069       switch (change)
1070         {
1071         case MAP_STATE_CHECK:
1072           break;
1073
1074         case MAP_STATE_MAKE_MAPPED:
1075           g_assert (!was_mapped);
1076           clutter_actor_set_mapped (self, TRUE);
1077           break;
1078
1079         case MAP_STATE_MAKE_UNMAPPED:
1080           g_assert (was_mapped);
1081           clutter_actor_set_mapped (self, FALSE);
1082           break;
1083
1084         case MAP_STATE_MAKE_UNREALIZED:
1085           /* we only use MAKE_UNREALIZED in unparent,
1086            * and unparenting a stage isn't possible.
1087            * If someone wants to just unrealize a stage
1088            * then clutter_actor_unrealize() doesn't
1089            * go through this codepath.
1090            */
1091           g_warning ("Trying to force unrealize stage is not allowed");
1092           break;
1093         }
1094
1095       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1096           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1097           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1098         {
1099           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1100                      "it is somehow still mapped",
1101                      _clutter_actor_get_debug_name (self));
1102         }
1103     }
1104   else
1105     {
1106       ClutterActorPrivate *priv = self->priv;
1107       ClutterActor *parent = priv->parent;
1108       gboolean should_be_mapped;
1109       gboolean may_be_realized;
1110       gboolean must_be_realized;
1111
1112       should_be_mapped = FALSE;
1113       may_be_realized = TRUE;
1114       must_be_realized = FALSE;
1115
1116       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1117         {
1118           may_be_realized = FALSE;
1119         }
1120       else
1121         {
1122           /* Maintain invariant that if parent is mapped, and we are
1123            * visible, then we are mapped ...  unless parent is a
1124            * stage, in which case we map regardless of parent's map
1125            * state but do require stage to be visible and realized.
1126            *
1127            * If parent is realized, that does not force us to be
1128            * realized; but if parent is unrealized, that does force
1129            * us to be unrealized.
1130            *
1131            * The reason we don't force children to realize with
1132            * parents is _clutter_actor_rerealize(); if we require that
1133            * a realized parent means children are realized, then to
1134            * unrealize an actor we would have to unrealize its
1135            * parents, which would end up meaning unrealizing and
1136            * hiding the entire stage. So we allow unrealizing a
1137            * child (as long as that child is not mapped) while that
1138            * child still has a realized parent.
1139            *
1140            * Also, if we unrealize from leaf nodes to root, and
1141            * realize from root to leaf, the invariants are never
1142            * violated if we allow children to be unrealized
1143            * while parents are realized.
1144            *
1145            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1146            * to force us to unmap, even though parent is still
1147            * mapped. This is because we're unmapping from leaf nodes
1148            * up to root nodes.
1149            */
1150           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1151               change != MAP_STATE_MAKE_UNMAPPED)
1152             {
1153               gboolean parent_is_visible_realized_toplevel;
1154
1155               parent_is_visible_realized_toplevel =
1156                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1157                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1158                  CLUTTER_ACTOR_IS_REALIZED (parent));
1159
1160               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1161                   parent_is_visible_realized_toplevel)
1162                 {
1163                   must_be_realized = TRUE;
1164                   should_be_mapped = TRUE;
1165                 }
1166             }
1167
1168           /* if the actor has been set to be painted even if unmapped
1169            * then we should map it and check for realization as well;
1170            * this is an override for the branch of the scene graph
1171            * which begins with this node
1172            */
1173           if (priv->enable_paint_unmapped)
1174             {
1175               if (priv->parent == NULL)
1176                 g_warning ("Attempting to map an unparented actor '%s'",
1177                            _clutter_actor_get_debug_name (self));
1178
1179               should_be_mapped = TRUE;
1180               must_be_realized = TRUE;
1181             }
1182
1183           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1184             may_be_realized = FALSE;
1185         }
1186
1187       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1188         {
1189           if (parent == NULL)
1190             g_warning ("Attempting to map a child that does not "
1191                        "meet the necessary invariants: the actor '%s' "
1192                        "has no parent",
1193                        _clutter_actor_get_debug_name (self));
1194           else
1195             g_warning ("Attempting to map a child that does not "
1196                        "meet the necessary invariants: the actor '%s' "
1197                        "is parented to an unmapped actor '%s'",
1198                        _clutter_actor_get_debug_name (self),
1199                        _clutter_actor_get_debug_name (priv->parent));
1200         }
1201
1202       /* If in reparent, we temporarily suspend unmap and unrealize.
1203        *
1204        * We want to go in the order "realize, map" and "unmap, unrealize"
1205        */
1206
1207       /* Unmap */
1208       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1209         clutter_actor_set_mapped (self, FALSE);
1210
1211       /* Realize */
1212       if (must_be_realized)
1213         clutter_actor_realize (self);
1214
1215       /* if we must be realized then we may be, presumably */
1216       g_assert (!(must_be_realized && !may_be_realized));
1217
1218       /* Unrealize */
1219       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1220         clutter_actor_unrealize_not_hiding (self);
1221
1222       /* Map */
1223       if (should_be_mapped)
1224         {
1225           if (!must_be_realized)
1226             g_warning ("Somehow we think actor '%s' should be mapped but "
1227                        "not realized, which isn't allowed",
1228                        _clutter_actor_get_debug_name (self));
1229
1230           /* realization is allowed to fail (though I don't know what
1231            * an app is supposed to do about that - shouldn't it just
1232            * be a g_error? anyway, we have to avoid mapping if this
1233            * happens)
1234            */
1235           if (CLUTTER_ACTOR_IS_REALIZED (self))
1236             clutter_actor_set_mapped (self, TRUE);
1237         }
1238     }
1239
1240 #ifdef CLUTTER_ENABLE_DEBUG
1241   /* check all invariants were kept */
1242   clutter_actor_verify_map_state (self);
1243 #endif
1244 }
1245
1246 static void
1247 clutter_actor_real_map (ClutterActor *self)
1248 {
1249   ClutterActorPrivate *priv = self->priv;
1250   ClutterActor *stage, *iter;
1251
1252   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1253
1254   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1255                 _clutter_actor_get_debug_name (self));
1256
1257   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1258
1259   stage = _clutter_actor_get_stage_internal (self);
1260   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1261
1262   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1263                 priv->pick_id,
1264                 _clutter_actor_get_debug_name (self));
1265
1266   /* notify on parent mapped before potentially mapping
1267    * children, so apps see a top-down notification.
1268    */
1269   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1270
1271   for (iter = self->priv->first_child;
1272        iter != NULL;
1273        iter = iter->priv->next_sibling)
1274     {
1275       clutter_actor_map (iter);
1276     }
1277 }
1278
1279 /**
1280  * clutter_actor_map:
1281  * @self: A #ClutterActor
1282  *
1283  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1284  * and realizes its children if they are visible. Does nothing if the
1285  * actor is not visible.
1286  *
1287  * Calling this function is strongly disencouraged: the default
1288  * implementation of #ClutterActorClass.map() will map all the children
1289  * of an actor when mapping its parent.
1290  *
1291  * When overriding map, it is mandatory to chain up to the parent
1292  * implementation.
1293  *
1294  * Since: 1.0
1295  */
1296 void
1297 clutter_actor_map (ClutterActor *self)
1298 {
1299   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1300
1301   if (CLUTTER_ACTOR_IS_MAPPED (self))
1302     return;
1303
1304   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1305     return;
1306
1307   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1308 }
1309
1310 static void
1311 clutter_actor_real_unmap (ClutterActor *self)
1312 {
1313   ClutterActorPrivate *priv = self->priv;
1314   ClutterActor *iter;
1315
1316   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1317
1318   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1319                 _clutter_actor_get_debug_name (self));
1320
1321   for (iter = self->priv->first_child;
1322        iter != NULL;
1323        iter = iter->priv->next_sibling)
1324     {
1325       clutter_actor_unmap (iter);
1326     }
1327
1328   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1329
1330   /* clear the contents of the last paint volume, so that hiding + moving +
1331    * showing will not result in the wrong area being repainted
1332    */
1333   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1334   priv->last_paint_volume_valid = TRUE;
1335
1336   /* notify on parent mapped after potentially unmapping
1337    * children, so apps see a bottom-up notification.
1338    */
1339   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1340
1341   /* relinquish keyboard focus if we were unmapped while owning it */
1342   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1343     {
1344       ClutterStage *stage;
1345
1346       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1347
1348       if (stage != NULL)
1349         _clutter_stage_release_pick_id (stage, priv->pick_id);
1350
1351       priv->pick_id = -1;
1352
1353       if (stage != NULL &&
1354           clutter_stage_get_key_focus (stage) == self)
1355         {
1356           clutter_stage_set_key_focus (stage, NULL);
1357         }
1358     }
1359 }
1360
1361 /**
1362  * clutter_actor_unmap:
1363  * @self: A #ClutterActor
1364  *
1365  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1366  * unmaps its children if they were mapped.
1367  *
1368  * Calling this function is not encouraged: the default #ClutterActor
1369  * implementation of #ClutterActorClass.unmap() will also unmap any
1370  * eventual children by default when their parent is unmapped.
1371  *
1372  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1373  * chain up to the parent implementation.
1374  *
1375  * <note>It is important to note that the implementation of the
1376  * #ClutterActorClass.unmap() virtual function may be called after
1377  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1378  * implementation, but it is guaranteed to be called before the
1379  * #GObjectClass.finalize() implementation.</note>
1380  *
1381  * Since: 1.0
1382  */
1383 void
1384 clutter_actor_unmap (ClutterActor *self)
1385 {
1386   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1387
1388   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1389     return;
1390
1391   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1392 }
1393
1394 static void
1395 clutter_actor_real_show (ClutterActor *self)
1396 {
1397   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1398     {
1399       ClutterActorPrivate *priv = self->priv;
1400
1401       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1402
1403       /* we notify on the "visible" flag in the clutter_actor_show()
1404        * wrapper so the entire show signal emission completes first
1405        * (?)
1406        */
1407       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1408
1409       /* we queue a relayout unless the actor is inside a
1410        * container that explicitly told us not to
1411        */
1412       if (priv->parent != NULL &&
1413           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1414         {
1415           /* While an actor is hidden the parent may not have
1416            * allocated/requested so we need to start from scratch
1417            * and avoid the short-circuiting in
1418            * clutter_actor_queue_relayout().
1419            */
1420           priv->needs_width_request  = FALSE;
1421           priv->needs_height_request = FALSE;
1422           priv->needs_allocation     = FALSE;
1423           clutter_actor_queue_relayout (self);
1424         }
1425     }
1426 }
1427
1428 static inline void
1429 set_show_on_set_parent (ClutterActor *self,
1430                         gboolean      set_show)
1431 {
1432   ClutterActorPrivate *priv = self->priv;
1433
1434   set_show = !!set_show;
1435
1436   if (priv->show_on_set_parent == set_show)
1437     return;
1438
1439   if (priv->parent == NULL)
1440     {
1441       priv->show_on_set_parent = set_show;
1442       g_object_notify_by_pspec (G_OBJECT (self),
1443                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1444     }
1445 }
1446
1447 /**
1448  * clutter_actor_show:
1449  * @self: A #ClutterActor
1450  *
1451  * Flags an actor to be displayed. An actor that isn't shown will not
1452  * be rendered on the stage.
1453  *
1454  * Actors are visible by default.
1455  *
1456  * If this function is called on an actor without a parent, the
1457  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1458  * effect.
1459  */
1460 void
1461 clutter_actor_show (ClutterActor *self)
1462 {
1463   ClutterActorPrivate *priv;
1464
1465   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1466
1467   /* simple optimization */
1468   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1469     {
1470       /* we still need to set the :show-on-set-parent property, in
1471        * case show() is called on an unparented actor
1472        */
1473       set_show_on_set_parent (self, TRUE);
1474       return;
1475     }
1476
1477 #ifdef CLUTTER_ENABLE_DEBUG
1478   clutter_actor_verify_map_state (self);
1479 #endif
1480
1481   priv = self->priv;
1482
1483   g_object_freeze_notify (G_OBJECT (self));
1484
1485   set_show_on_set_parent (self, TRUE);
1486
1487   g_signal_emit (self, actor_signals[SHOW], 0);
1488   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1489
1490   if (priv->parent != NULL)
1491     clutter_actor_queue_redraw (priv->parent);
1492
1493   g_object_thaw_notify (G_OBJECT (self));
1494 }
1495
1496 /**
1497  * clutter_actor_show_all:
1498  * @self: a #ClutterActor
1499  *
1500  * Calls clutter_actor_show() on all children of an actor (if any).
1501  *
1502  * Since: 0.2
1503  *
1504  * Deprecated: 1.10: Actors are visible by default
1505  */
1506 void
1507 clutter_actor_show_all (ClutterActor *self)
1508 {
1509   ClutterActorClass *klass;
1510
1511   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1512
1513   klass = CLUTTER_ACTOR_GET_CLASS (self);
1514   if (klass->show_all)
1515     klass->show_all (self);
1516 }
1517
1518 static void
1519 clutter_actor_real_hide (ClutterActor *self)
1520 {
1521   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1522     {
1523       ClutterActorPrivate *priv = self->priv;
1524
1525       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1526
1527       /* we notify on the "visible" flag in the clutter_actor_hide()
1528        * wrapper so the entire hide signal emission completes first
1529        * (?)
1530        */
1531       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1532
1533       /* we queue a relayout unless the actor is inside a
1534        * container that explicitly told us not to
1535        */
1536       if (priv->parent != NULL &&
1537           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1538         clutter_actor_queue_relayout (priv->parent);
1539     }
1540 }
1541
1542 /**
1543  * clutter_actor_hide:
1544  * @self: A #ClutterActor
1545  *
1546  * Flags an actor to be hidden. A hidden actor will not be
1547  * rendered on the stage.
1548  *
1549  * Actors are visible by default.
1550  *
1551  * If this function is called on an actor without a parent, the
1552  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1553  * as a side-effect.
1554  */
1555 void
1556 clutter_actor_hide (ClutterActor *self)
1557 {
1558   ClutterActorPrivate *priv;
1559
1560   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1561
1562   /* simple optimization */
1563   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1564     {
1565       /* we still need to set the :show-on-set-parent property, in
1566        * case hide() is called on an unparented actor
1567        */
1568       set_show_on_set_parent (self, FALSE);
1569       return;
1570     }
1571
1572 #ifdef CLUTTER_ENABLE_DEBUG
1573   clutter_actor_verify_map_state (self);
1574 #endif
1575
1576   priv = self->priv;
1577
1578   g_object_freeze_notify (G_OBJECT (self));
1579
1580   set_show_on_set_parent (self, FALSE);
1581
1582   g_signal_emit (self, actor_signals[HIDE], 0);
1583   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1584
1585   if (priv->parent != NULL)
1586     clutter_actor_queue_redraw (priv->parent);
1587
1588   g_object_thaw_notify (G_OBJECT (self));
1589 }
1590
1591 /**
1592  * clutter_actor_hide_all:
1593  * @self: a #ClutterActor
1594  *
1595  * Calls clutter_actor_hide() on all child actors (if any).
1596  *
1597  * Since: 0.2
1598  *
1599  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1600  *   prevent its children from being painted as well.
1601  */
1602 void
1603 clutter_actor_hide_all (ClutterActor *self)
1604 {
1605   ClutterActorClass *klass;
1606
1607   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1608
1609   klass = CLUTTER_ACTOR_GET_CLASS (self);
1610   if (klass->hide_all)
1611     klass->hide_all (self);
1612 }
1613
1614 /**
1615  * clutter_actor_realize:
1616  * @self: A #ClutterActor
1617  *
1618  * Realization informs the actor that it is attached to a stage. It
1619  * can use this to allocate resources if it wanted to delay allocation
1620  * until it would be rendered. However it is perfectly acceptable for
1621  * an actor to create resources before being realized because Clutter
1622  * only ever has a single rendering context so that actor is free to
1623  * be moved from one stage to another.
1624  *
1625  * This function does nothing if the actor is already realized.
1626  *
1627  * Because a realized actor must have realized parent actors, calling
1628  * clutter_actor_realize() will also realize all parents of the actor.
1629  *
1630  * This function does not realize child actors, except in the special
1631  * case that realizing the stage, when the stage is visible, will
1632  * suddenly map (and thus realize) the children of the stage.
1633  **/
1634 void
1635 clutter_actor_realize (ClutterActor *self)
1636 {
1637   ClutterActorPrivate *priv;
1638
1639   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1640
1641   priv = self->priv;
1642
1643 #ifdef CLUTTER_ENABLE_DEBUG
1644   clutter_actor_verify_map_state (self);
1645 #endif
1646
1647   if (CLUTTER_ACTOR_IS_REALIZED (self))
1648     return;
1649
1650   /* To be realized, our parent actors must be realized first.
1651    * This will only succeed if we're inside a toplevel.
1652    */
1653   if (priv->parent != NULL)
1654     clutter_actor_realize (priv->parent);
1655
1656   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1657     {
1658       /* toplevels can be realized at any time */
1659     }
1660   else
1661     {
1662       /* "Fail" the realization if parent is missing or unrealized;
1663        * this should really be a g_warning() not some kind of runtime
1664        * failure; how can an app possibly recover? Instead it's a bug
1665        * in the app and the app should get an explanatory warning so
1666        * someone can fix it. But for now it's too hard to fix this
1667        * because e.g. ClutterTexture needs reworking.
1668        */
1669       if (priv->parent == NULL ||
1670           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1671         return;
1672     }
1673
1674   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1675
1676   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1677   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1678
1679   g_signal_emit (self, actor_signals[REALIZE], 0);
1680
1681   /* Stage actor is allowed to unset the realized flag again in its
1682    * default signal handler, though that is a pathological situation.
1683    */
1684
1685   /* If realization "failed" we'll have to update child state. */
1686   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1687 }
1688
1689 static void
1690 clutter_actor_real_unrealize (ClutterActor *self)
1691 {
1692   /* we must be unmapped (implying our children are also unmapped) */
1693   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1694 }
1695
1696 /**
1697  * clutter_actor_unrealize:
1698  * @self: A #ClutterActor
1699  *
1700  * Unrealization informs the actor that it may be being destroyed or
1701  * moved to another stage. The actor may want to destroy any
1702  * underlying graphics resources at this point. However it is
1703  * perfectly acceptable for it to retain the resources until the actor
1704  * is destroyed because Clutter only ever uses a single rendering
1705  * context and all of the graphics resources are valid on any stage.
1706  *
1707  * Because mapped actors must be realized, actors may not be
1708  * unrealized if they are mapped. This function hides the actor to be
1709  * sure it isn't mapped, an application-visible side effect that you
1710  * may not be expecting.
1711  *
1712  * This function should not be called by application code.
1713  */
1714 void
1715 clutter_actor_unrealize (ClutterActor *self)
1716 {
1717   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1718   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1719
1720 /* This function should not really be in the public API, because
1721  * there isn't a good reason to call it. ClutterActor will already
1722  * unrealize things for you when it's important to do so.
1723  *
1724  * If you were using clutter_actor_unrealize() in a dispose
1725  * implementation, then don't, just chain up to ClutterActor's
1726  * dispose.
1727  *
1728  * If you were using clutter_actor_unrealize() to implement
1729  * unrealizing children of your container, then don't, ClutterActor
1730  * will already take care of that.
1731  *
1732  * If you were using clutter_actor_unrealize() to re-realize to
1733  * create your resources in a different way, then use
1734  * _clutter_actor_rerealize() (inside Clutter) or just call your
1735  * code that recreates your resources directly (outside Clutter).
1736  */
1737
1738 #ifdef CLUTTER_ENABLE_DEBUG
1739   clutter_actor_verify_map_state (self);
1740 #endif
1741
1742   clutter_actor_hide (self);
1743
1744   clutter_actor_unrealize_not_hiding (self);
1745 }
1746
1747 static ClutterActorTraverseVisitFlags
1748 unrealize_actor_before_children_cb (ClutterActor *self,
1749                                     int depth,
1750                                     void *user_data)
1751 {
1752   /* If an actor is already unrealized we know its children have also
1753    * already been unrealized... */
1754   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1755     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1756
1757   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1758
1759   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1760 }
1761
1762 static ClutterActorTraverseVisitFlags
1763 unrealize_actor_after_children_cb (ClutterActor *self,
1764                                    int depth,
1765                                    void *user_data)
1766 {
1767   /* We want to unset the realized flag only _after_
1768    * child actors are unrealized, to maintain invariants.
1769    */
1770   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1771   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1772   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1773 }
1774
1775 /*
1776  * clutter_actor_unrealize_not_hiding:
1777  * @self: A #ClutterActor
1778  *
1779  * Unrealization informs the actor that it may be being destroyed or
1780  * moved to another stage. The actor may want to destroy any
1781  * underlying graphics resources at this point. However it is
1782  * perfectly acceptable for it to retain the resources until the actor
1783  * is destroyed because Clutter only ever uses a single rendering
1784  * context and all of the graphics resources are valid on any stage.
1785  *
1786  * Because mapped actors must be realized, actors may not be
1787  * unrealized if they are mapped. You must hide the actor or one of
1788  * its parents before attempting to unrealize.
1789  *
1790  * This function is separate from clutter_actor_unrealize() because it
1791  * does not automatically hide the actor.
1792  * Actors need not be hidden to be unrealized, they just need to
1793  * be unmapped. In fact we don't want to mess up the application's
1794  * setting of the "visible" flag, so hiding is very undesirable.
1795  *
1796  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1797  * backward compatibility.
1798  */
1799 static void
1800 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1801 {
1802   _clutter_actor_traverse (self,
1803                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1804                            unrealize_actor_before_children_cb,
1805                            unrealize_actor_after_children_cb,
1806                            NULL);
1807 }
1808
1809 /*
1810  * _clutter_actor_rerealize:
1811  * @self: A #ClutterActor
1812  * @callback: Function to call while unrealized
1813  * @data: data for callback
1814  *
1815  * If an actor is already unrealized, this just calls the callback.
1816  *
1817  * If it is realized, it unrealizes temporarily, calls the callback,
1818  * and then re-realizes the actor.
1819  *
1820  * As a side effect, leaves all children of the actor unrealized if
1821  * the actor was realized but not showing.  This is because when we
1822  * unrealize the actor temporarily we must unrealize its children
1823  * (e.g. children of a stage can't be realized if stage window is
1824  * gone). And we aren't clever enough to save the realization state of
1825  * all children. In most cases this should not matter, because
1826  * the children will automatically realize when they next become mapped.
1827  */
1828 void
1829 _clutter_actor_rerealize (ClutterActor    *self,
1830                           ClutterCallback  callback,
1831                           void            *data)
1832 {
1833   gboolean was_mapped;
1834   gboolean was_showing;
1835   gboolean was_realized;
1836
1837   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1838
1839 #ifdef CLUTTER_ENABLE_DEBUG
1840   clutter_actor_verify_map_state (self);
1841 #endif
1842
1843   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1844   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1845   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1846
1847   /* Must be unmapped to unrealize. Note we only have to hide this
1848    * actor if it was mapped (if all parents were showing).  If actor
1849    * is merely visible (but not mapped), then that's fine, we can
1850    * leave it visible.
1851    */
1852   if (was_mapped)
1853     clutter_actor_hide (self);
1854
1855   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1856
1857   /* unrealize self and all children */
1858   clutter_actor_unrealize_not_hiding (self);
1859
1860   if (callback != NULL)
1861     {
1862       (* callback) (self, data);
1863     }
1864
1865   if (was_showing)
1866     clutter_actor_show (self); /* will realize only if mapping implies it */
1867   else if (was_realized)
1868     clutter_actor_realize (self); /* realize self and all parents */
1869 }
1870
1871 static void
1872 clutter_actor_real_pick (ClutterActor       *self,
1873                          const ClutterColor *color)
1874 {
1875   /* the default implementation is just to paint a rectangle
1876    * with the same size of the actor using the passed color
1877    */
1878   if (clutter_actor_should_pick_paint (self))
1879     {
1880       ClutterActorBox box = { 0, };
1881       float width, height;
1882
1883       clutter_actor_get_allocation_box (self, &box);
1884
1885       width = box.x2 - box.x1;
1886       height = box.y2 - box.y1;
1887
1888       cogl_set_source_color4ub (color->red,
1889                                 color->green,
1890                                 color->blue,
1891                                 color->alpha);
1892
1893       cogl_rectangle (0, 0, width, height);
1894     }
1895
1896   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1897    * with existing container classes that override the pick() virtual
1898    * and chain up to the default implementation - otherwise we'll end up
1899    * painting our children twice.
1900    *
1901    * this has to go away for 2.0; hopefully along the pick() itself.
1902    */
1903   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1904     {
1905       ClutterActor *iter;
1906
1907       for (iter = self->priv->first_child;
1908            iter != NULL;
1909            iter = iter->priv->next_sibling)
1910         clutter_actor_paint (iter);
1911     }
1912 }
1913
1914 /**
1915  * clutter_actor_should_pick_paint:
1916  * @self: A #ClutterActor
1917  *
1918  * Should be called inside the implementation of the
1919  * #ClutterActor::pick virtual function in order to check whether
1920  * the actor should paint itself in pick mode or not.
1921  *
1922  * This function should never be called directly by applications.
1923  *
1924  * Return value: %TRUE if the actor should paint its silhouette,
1925  *   %FALSE otherwise
1926  */
1927 gboolean
1928 clutter_actor_should_pick_paint (ClutterActor *self)
1929 {
1930   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1931
1932   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1933       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1934        CLUTTER_ACTOR_IS_REACTIVE (self)))
1935     return TRUE;
1936
1937   return FALSE;
1938 }
1939
1940 static void
1941 clutter_actor_real_get_preferred_width (ClutterActor *self,
1942                                         gfloat        for_height,
1943                                         gfloat       *min_width_p,
1944                                         gfloat       *natural_width_p)
1945 {
1946   ClutterActorPrivate *priv = self->priv;
1947
1948   if (priv->n_children != 0 &&
1949       priv->layout_manager != NULL)
1950     {
1951       ClutterContainer *container = CLUTTER_CONTAINER (self);
1952
1953       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1954                     "for the preferred width",
1955                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1956                     priv->layout_manager);
1957
1958       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1959                                                   container,
1960                                                   for_height,
1961                                                   min_width_p,
1962                                                   natural_width_p);
1963
1964       return;
1965     }
1966
1967   /* Default implementation is always 0x0, usually an actor
1968    * using this default is relying on someone to set the
1969    * request manually
1970    */
1971   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1972
1973   if (min_width_p)
1974     *min_width_p = 0;
1975
1976   if (natural_width_p)
1977     *natural_width_p = 0;
1978 }
1979
1980 static void
1981 clutter_actor_real_get_preferred_height (ClutterActor *self,
1982                                          gfloat        for_width,
1983                                          gfloat       *min_height_p,
1984                                          gfloat       *natural_height_p)
1985 {
1986   ClutterActorPrivate *priv = self->priv;
1987
1988   if (priv->n_children != 0 &&
1989       priv->layout_manager != NULL)
1990     {
1991       ClutterContainer *container = CLUTTER_CONTAINER (self);
1992
1993       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1994                     "for the preferred height",
1995                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1996                     priv->layout_manager);
1997
1998       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1999                                                    container,
2000                                                    for_width,
2001                                                    min_height_p,
2002                                                    natural_height_p);
2003
2004       return;
2005     }
2006   /* Default implementation is always 0x0, usually an actor
2007    * using this default is relying on someone to set the
2008    * request manually
2009    */
2010   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2011
2012   if (min_height_p)
2013     *min_height_p = 0;
2014
2015   if (natural_height_p)
2016     *natural_height_p = 0;
2017 }
2018
2019 static void
2020 clutter_actor_store_old_geometry (ClutterActor    *self,
2021                                   ClutterActorBox *box)
2022 {
2023   *box = self->priv->allocation;
2024 }
2025
2026 static inline void
2027 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2028                                           const ClutterActorBox *old)
2029 {
2030   ClutterActorPrivate *priv = self->priv;
2031   GObject *obj = G_OBJECT (self);
2032
2033   g_object_freeze_notify (obj);
2034
2035   /* to avoid excessive requisition or allocation cycles we
2036    * use the cached values.
2037    *
2038    * - if we don't have an allocation we assume that we need
2039    *   to notify anyway
2040    * - if we don't have a width or a height request we notify
2041    *   width and height
2042    * - if we have a valid allocation then we check the old
2043    *   bounding box with the current allocation and we notify
2044    *   the changes
2045    */
2046   if (priv->needs_allocation)
2047     {
2048       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2049       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2050       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2051       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2052     }
2053   else if (priv->needs_width_request || priv->needs_height_request)
2054     {
2055       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2056       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2057     }
2058   else
2059     {
2060       gfloat x, y;
2061       gfloat width, height;
2062
2063       x = priv->allocation.x1;
2064       y = priv->allocation.y1;
2065       width = priv->allocation.x2 - priv->allocation.x1;
2066       height = priv->allocation.y2 - priv->allocation.y1;
2067
2068       if (x != old->x1)
2069         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2070
2071       if (y != old->y1)
2072         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2073
2074       if (width != (old->x2 - old->x1))
2075         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2076
2077       if (height != (old->y2 - old->y1))
2078         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2079     }
2080
2081   g_object_thaw_notify (obj);
2082 }
2083
2084 /*< private >
2085  * clutter_actor_set_allocation_internal:
2086  * @self: a #ClutterActor
2087  * @box: a #ClutterActorBox
2088  * @flags: allocation flags
2089  *
2090  * Stores the allocation of @self.
2091  *
2092  * This function only performs basic storage and property notification.
2093  *
2094  * This function should be called by clutter_actor_set_allocation()
2095  * and by the default implementation of #ClutterActorClass.allocate().
2096  *
2097  * Return value: %TRUE if the allocation of the #ClutterActor has been
2098  *   changed, and %FALSE otherwise
2099  */
2100 static inline gboolean
2101 clutter_actor_set_allocation_internal (ClutterActor           *self,
2102                                        const ClutterActorBox  *box,
2103                                        ClutterAllocationFlags  flags)
2104 {
2105   ClutterActorPrivate *priv = self->priv;
2106   GObject *obj;
2107   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2108   gboolean flags_changed;
2109   gboolean retval;
2110   ClutterActorBox old_alloc = { 0, };
2111
2112   obj = G_OBJECT (self);
2113
2114   g_object_freeze_notify (obj);
2115
2116   clutter_actor_store_old_geometry (self, &old_alloc);
2117
2118   x1_changed = priv->allocation.x1 != box->x1;
2119   y1_changed = priv->allocation.y1 != box->y1;
2120   x2_changed = priv->allocation.x2 != box->x2;
2121   y2_changed = priv->allocation.y2 != box->y2;
2122
2123   flags_changed = priv->allocation_flags != flags;
2124
2125   priv->allocation = *box;
2126   priv->allocation_flags = flags;
2127
2128   /* allocation is authoritative */
2129   priv->needs_width_request = FALSE;
2130   priv->needs_height_request = FALSE;
2131   priv->needs_allocation = FALSE;
2132
2133   if (x1_changed || y1_changed ||
2134       x2_changed || y2_changed ||
2135       flags_changed)
2136     {
2137       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2138                     _clutter_actor_get_debug_name (self));
2139
2140       priv->transform_valid = FALSE;
2141
2142       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2143
2144       /* if the allocation changes, so does the content box */
2145       if (priv->content != NULL)
2146         g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2147
2148       retval = TRUE;
2149     }
2150   else
2151     retval = FALSE;
2152
2153   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2154
2155   g_object_thaw_notify (obj);
2156
2157   return retval;
2158 }
2159
2160 static void clutter_actor_real_allocate (ClutterActor           *self,
2161                                          const ClutterActorBox  *box,
2162                                          ClutterAllocationFlags  flags);
2163
2164 static inline void
2165 clutter_actor_maybe_layout_children (ClutterActor           *self,
2166                                      const ClutterActorBox  *allocation,
2167                                      ClutterAllocationFlags  flags)
2168 {
2169   ClutterActorPrivate *priv = self->priv;
2170
2171   /* this is going to be a bit hard to follow, so let's put an explanation
2172    * here.
2173    *
2174    * we want ClutterActor to have a default layout manager if the actor was
2175    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2176    *
2177    * we also want any subclass of ClutterActor that does not override the
2178    * ::allocate() virtual function to delegate to a layout manager.
2179    *
2180    * finally, we want to allow people subclassing ClutterActor and overriding
2181    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2182    *
2183    * on the other hand, we want existing actor subclasses overriding the
2184    * ::allocate() virtual function and chaining up to the parent's
2185    * implementation to continue working without allocating their children
2186    * twice, or without entering an allocation loop.
2187    *
2188    * for the first two points, we check if the class of the actor is
2189    * overridding the ::allocate() virtual function; if it isn't, then we
2190    * follow through with checking whether we have children and a layout
2191    * manager, and eventually calling clutter_layout_manager_allocate().
2192    *
2193    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2194    * allocation flags that we got passed, and if it is present, we continue
2195    * with the check above.
2196    *
2197    * if neither of these two checks yields a positive result, we just
2198    * assume that the ::allocate() virtual function that resulted in this
2199    * function being called will also allocate the children of the actor.
2200    */
2201
2202   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2203     goto check_layout;
2204
2205   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2206     goto check_layout;
2207
2208   return;
2209
2210 check_layout:
2211   if (priv->n_children != 0 &&
2212       priv->layout_manager != NULL)
2213     {
2214       ClutterContainer *container = CLUTTER_CONTAINER (self);
2215       ClutterAllocationFlags children_flags;
2216       ClutterActorBox children_box;
2217
2218       /* normalize the box passed to the layout manager */
2219       children_box.x1 = children_box.y1 = 0.f;
2220       children_box.x2 = (allocation->x2 - allocation->x1);
2221       children_box.y2 = (allocation->y2 - allocation->y1);
2222
2223       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2224        * the actor's children, since it refers only to the current
2225        * actor's allocation.
2226        */
2227       children_flags = flags;
2228       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2229
2230       CLUTTER_NOTE (LAYOUT,
2231                     "Allocating %d children of %s "
2232                     "at { %.2f, %.2f - %.2f x %.2f } "
2233                     "using %s",
2234                     priv->n_children,
2235                     _clutter_actor_get_debug_name (self),
2236                     allocation->x1,
2237                     allocation->y1,
2238                     (allocation->x2 - allocation->x1),
2239                     (allocation->y2 - allocation->y1),
2240                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2241
2242       clutter_layout_manager_allocate (priv->layout_manager,
2243                                        container,
2244                                        &children_box,
2245                                        children_flags);
2246     }
2247 }
2248
2249 static void
2250 clutter_actor_real_allocate (ClutterActor           *self,
2251                              const ClutterActorBox  *box,
2252                              ClutterAllocationFlags  flags)
2253 {
2254   ClutterActorPrivate *priv = self->priv;
2255   gboolean changed;
2256
2257   g_object_freeze_notify (G_OBJECT (self));
2258
2259   changed = clutter_actor_set_allocation_internal (self, box, flags);
2260
2261   /* we allocate our children before we notify changes in our geometry,
2262    * so that people connecting to properties will be able to get valid
2263    * data out of the sub-tree of the scene graph that has this actor at
2264    * the root.
2265    */
2266   clutter_actor_maybe_layout_children (self, box, flags);
2267
2268   if (changed)
2269     {
2270       ClutterActorBox signal_box = priv->allocation;
2271       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2272
2273       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2274                      &signal_box,
2275                      signal_flags);
2276     }
2277
2278   g_object_thaw_notify (G_OBJECT (self));
2279 }
2280
2281 static void
2282 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2283                                     ClutterActor *origin)
2284 {
2285   /* no point in queuing a redraw on a destroyed actor */
2286   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2287     return;
2288
2289   /* NB: We can't bail out early here if the actor is hidden in case
2290    * the actor bas been cloned. In this case the clone will need to
2291    * receive the signal so it can queue its own redraw.
2292    */
2293
2294   /* calls klass->queue_redraw in default handler */
2295   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2296 }
2297
2298 static void
2299 clutter_actor_real_queue_redraw (ClutterActor *self,
2300                                  ClutterActor *origin)
2301 {
2302   ClutterActor *parent;
2303
2304   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2305                 _clutter_actor_get_debug_name (self),
2306                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2307                                : "same actor");
2308
2309   /* no point in queuing a redraw on a destroyed actor */
2310   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2311     return;
2312
2313   /* If the queue redraw is coming from a child then the actor has
2314      become dirty and any queued effect is no longer valid */
2315   if (self != origin)
2316     {
2317       self->priv->is_dirty = TRUE;
2318       self->priv->effect_to_redraw = NULL;
2319     }
2320
2321   /* If the actor isn't visible, we still had to emit the signal
2322    * to allow for a ClutterClone, but the appearance of the parent
2323    * won't change so we don't have to propagate up the hierarchy.
2324    */
2325   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2326     return;
2327
2328   /* Although we could determine here that a full stage redraw
2329    * has already been queued and immediately bail out, we actually
2330    * guarantee that we will propagate a queue-redraw signal to our
2331    * parent at least once so that it's possible to implement a
2332    * container that tracks which of its children have queued a
2333    * redraw.
2334    */
2335   if (self->priv->propagated_one_redraw)
2336     {
2337       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2338       if (stage != NULL &&
2339           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2340         return;
2341     }
2342
2343   self->priv->propagated_one_redraw = TRUE;
2344
2345   /* notify parents, if they are all visible eventually we'll
2346    * queue redraw on the stage, which queues the redraw idle.
2347    */
2348   parent = clutter_actor_get_parent (self);
2349   if (parent != NULL)
2350     {
2351       /* this will go up recursively */
2352       _clutter_actor_signal_queue_redraw (parent, origin);
2353     }
2354 }
2355
2356 static void
2357 clutter_actor_real_queue_relayout (ClutterActor *self)
2358 {
2359   ClutterActorPrivate *priv = self->priv;
2360
2361   /* no point in queueing a redraw on a destroyed actor */
2362   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2363     return;
2364
2365   priv->needs_width_request  = TRUE;
2366   priv->needs_height_request = TRUE;
2367   priv->needs_allocation     = TRUE;
2368
2369   /* reset the cached size requests */
2370   memset (priv->width_requests, 0,
2371           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2372   memset (priv->height_requests, 0,
2373           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2374
2375   /* We need to go all the way up the hierarchy */
2376   if (priv->parent != NULL)
2377     _clutter_actor_queue_only_relayout (priv->parent);
2378 }
2379
2380 /**
2381  * clutter_actor_apply_relative_transform_to_point:
2382  * @self: A #ClutterActor
2383  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2384  *   default #ClutterStage
2385  * @point: A point as #ClutterVertex
2386  * @vertex: (out caller-allocates): The translated #ClutterVertex
2387  *
2388  * Transforms @point in coordinates relative to the actor into
2389  * ancestor-relative coordinates using the relevant transform
2390  * stack (i.e. scale, rotation, etc).
2391  *
2392  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2393  * this case, the coordinates returned will be the coordinates on
2394  * the stage before the projection is applied. This is different from
2395  * the behaviour of clutter_actor_apply_transform_to_point().
2396  *
2397  * Since: 0.6
2398  */
2399 void
2400 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2401                                                  ClutterActor        *ancestor,
2402                                                  const ClutterVertex *point,
2403                                                  ClutterVertex       *vertex)
2404 {
2405   gfloat w;
2406   CoglMatrix matrix;
2407
2408   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2409   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2410   g_return_if_fail (point != NULL);
2411   g_return_if_fail (vertex != NULL);
2412
2413   *vertex = *point;
2414   w = 1.0;
2415
2416   if (ancestor == NULL)
2417     ancestor = _clutter_actor_get_stage_internal (self);
2418
2419   if (ancestor == NULL)
2420     {
2421       *vertex = *point;
2422       return;
2423     }
2424
2425   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2426   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2427 }
2428
2429 static gboolean
2430 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2431                                          const ClutterVertex *vertices_in,
2432                                          ClutterVertex *vertices_out,
2433                                          int n_vertices)
2434 {
2435   ClutterActor *stage;
2436   CoglMatrix modelview;
2437   CoglMatrix projection;
2438   float viewport[4];
2439
2440   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2441
2442   stage = _clutter_actor_get_stage_internal (self);
2443
2444   /* We really can't do anything meaningful in this case so don't try
2445    * to do any transform */
2446   if (stage == NULL)
2447     return FALSE;
2448
2449   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2450    * that gets us to stage coordinates, we want to go all the way to eye
2451    * coordinates */
2452   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2453
2454   /* Fetch the projection and viewport */
2455   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2456   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2457                                &viewport[0],
2458                                &viewport[1],
2459                                &viewport[2],
2460                                &viewport[3]);
2461
2462   _clutter_util_fully_transform_vertices (&modelview,
2463                                           &projection,
2464                                           viewport,
2465                                           vertices_in,
2466                                           vertices_out,
2467                                           n_vertices);
2468
2469   return TRUE;
2470 }
2471
2472 /**
2473  * clutter_actor_apply_transform_to_point:
2474  * @self: A #ClutterActor
2475  * @point: A point as #ClutterVertex
2476  * @vertex: (out caller-allocates): The translated #ClutterVertex
2477  *
2478  * Transforms @point in coordinates relative to the actor
2479  * into screen-relative coordinates with the current actor
2480  * transformation (i.e. scale, rotation, etc)
2481  *
2482  * Since: 0.4
2483  **/
2484 void
2485 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2486                                         const ClutterVertex *point,
2487                                         ClutterVertex       *vertex)
2488 {
2489   g_return_if_fail (point != NULL);
2490   g_return_if_fail (vertex != NULL);
2491   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2492 }
2493
2494 /*
2495  * _clutter_actor_get_relative_transformation_matrix:
2496  * @self: The actor whose coordinate space you want to transform from.
2497  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2498  *            or %NULL if you want to transform all the way to eye coordinates.
2499  * @matrix: A #CoglMatrix to store the transformation
2500  *
2501  * This gets a transformation @matrix that will transform coordinates from the
2502  * coordinate space of @self into the coordinate space of @ancestor.
2503  *
2504  * For example if you need a matrix that can transform the local actor
2505  * coordinates of @self into stage coordinates you would pass the actor's stage
2506  * pointer as the @ancestor.
2507  *
2508  * If you pass %NULL then the transformation will take you all the way through
2509  * to eye coordinates. This can be useful if you want to extract the entire
2510  * modelview transform that Clutter applies before applying the projection
2511  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2512  * using cogl_set_modelview_matrix() for example then you would want a matrix
2513  * that transforms into eye coordinates.
2514  *
2515  * <note><para>This function explicitly initializes the given @matrix. If you just
2516  * want clutter to multiply a relative transformation with an existing matrix
2517  * you can use clutter_actor_apply_relative_transformation_matrix()
2518  * instead.</para></note>
2519  *
2520  */
2521 /* XXX: We should consider caching the stage relative modelview along with
2522  * the actor itself */
2523 static void
2524 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2525                                                    ClutterActor *ancestor,
2526                                                    CoglMatrix *matrix)
2527 {
2528   cogl_matrix_init_identity (matrix);
2529
2530   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2531 }
2532
2533 /* Project the given @box into stage window coordinates, writing the
2534  * transformed vertices to @verts[]. */
2535 static gboolean
2536 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2537                                           const ClutterActorBox *box,
2538                                           ClutterVertex          verts[])
2539 {
2540   ClutterVertex box_vertices[4];
2541
2542   box_vertices[0].x = box->x1;
2543   box_vertices[0].y = box->y1;
2544   box_vertices[0].z = 0;
2545   box_vertices[1].x = box->x2;
2546   box_vertices[1].y = box->y1;
2547   box_vertices[1].z = 0;
2548   box_vertices[2].x = box->x1;
2549   box_vertices[2].y = box->y2;
2550   box_vertices[2].z = 0;
2551   box_vertices[3].x = box->x2;
2552   box_vertices[3].y = box->y2;
2553   box_vertices[3].z = 0;
2554
2555   return
2556     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2557 }
2558
2559 /**
2560  * clutter_actor_get_allocation_vertices:
2561  * @self: A #ClutterActor
2562  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2563  *   against, or %NULL to use the #ClutterStage
2564  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2565  *   location for an array of 4 #ClutterVertex in which to store the result
2566  *
2567  * Calculates the transformed coordinates of the four corners of the
2568  * actor in the plane of @ancestor. The returned vertices relate to
2569  * the #ClutterActorBox coordinates as follows:
2570  * <itemizedlist>
2571  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2572  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2573  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2574  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2575  * </itemizedlist>
2576  *
2577  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2578  * this case, the coordinates returned will be the coordinates on
2579  * the stage before the projection is applied. This is different from
2580  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2581  *
2582  * Since: 0.6
2583  */
2584 void
2585 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2586                                        ClutterActor  *ancestor,
2587                                        ClutterVertex  verts[])
2588 {
2589   ClutterActorPrivate *priv;
2590   ClutterActorBox box;
2591   ClutterVertex vertices[4];
2592   CoglMatrix modelview;
2593
2594   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2595   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2596
2597   if (ancestor == NULL)
2598     ancestor = _clutter_actor_get_stage_internal (self);
2599
2600   /* Fallback to a NOP transform if the actor isn't parented under a
2601    * stage. */
2602   if (ancestor == NULL)
2603     ancestor = self;
2604
2605   priv = self->priv;
2606
2607   /* if the actor needs to be allocated we force a relayout, so that
2608    * we will have valid values to use in the transformations */
2609   if (priv->needs_allocation)
2610     {
2611       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2612       if (stage)
2613         _clutter_stage_maybe_relayout (stage);
2614       else
2615         {
2616           box.x1 = box.y1 = 0;
2617           /* The result isn't really meaningful in this case but at
2618            * least try to do something *vaguely* reasonable... */
2619           clutter_actor_get_size (self, &box.x2, &box.y2);
2620         }
2621     }
2622
2623   clutter_actor_get_allocation_box (self, &box);
2624
2625   vertices[0].x = box.x1;
2626   vertices[0].y = box.y1;
2627   vertices[0].z = 0;
2628   vertices[1].x = box.x2;
2629   vertices[1].y = box.y1;
2630   vertices[1].z = 0;
2631   vertices[2].x = box.x1;
2632   vertices[2].y = box.y2;
2633   vertices[2].z = 0;
2634   vertices[3].x = box.x2;
2635   vertices[3].y = box.y2;
2636   vertices[3].z = 0;
2637
2638   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2639                                                      &modelview);
2640
2641   cogl_matrix_transform_points (&modelview,
2642                                 3,
2643                                 sizeof (ClutterVertex),
2644                                 vertices,
2645                                 sizeof (ClutterVertex),
2646                                 vertices,
2647                                 4);
2648 }
2649
2650 /**
2651  * clutter_actor_get_abs_allocation_vertices:
2652  * @self: A #ClutterActor
2653  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2654  *   of 4 #ClutterVertex where to store the result.
2655  *
2656  * Calculates the transformed screen coordinates of the four corners of
2657  * the actor; the returned vertices relate to the #ClutterActorBox
2658  * coordinates  as follows:
2659  * <itemizedlist>
2660  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2661  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2662  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2663  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2664  * </itemizedlist>
2665  *
2666  * Since: 0.4
2667  */
2668 void
2669 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2670                                            ClutterVertex  verts[])
2671 {
2672   ClutterActorPrivate *priv;
2673   ClutterActorBox actor_space_allocation;
2674
2675   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2676
2677   priv = self->priv;
2678
2679   /* if the actor needs to be allocated we force a relayout, so that
2680    * the actor allocation box will be valid for
2681    * _clutter_actor_transform_and_project_box()
2682    */
2683   if (priv->needs_allocation)
2684     {
2685       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2686       /* There's nothing meaningful we can do now */
2687       if (!stage)
2688         return;
2689
2690       _clutter_stage_maybe_relayout (stage);
2691     }
2692
2693   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2694    * own coordinate space... */
2695   actor_space_allocation.x1 = 0;
2696   actor_space_allocation.y1 = 0;
2697   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2698   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2699   _clutter_actor_transform_and_project_box (self,
2700                                             &actor_space_allocation,
2701                                             verts);
2702 }
2703
2704 static void
2705 clutter_actor_real_apply_transform (ClutterActor *self,
2706                                     CoglMatrix   *matrix)
2707 {
2708   ClutterActorPrivate *priv = self->priv;
2709
2710   if (!priv->transform_valid)
2711     {
2712       CoglMatrix *transform = &priv->transform;
2713       const ClutterTransformInfo *info;
2714
2715       info = _clutter_actor_get_transform_info_or_defaults (self);
2716
2717       cogl_matrix_init_identity (transform);
2718
2719       cogl_matrix_translate (transform,
2720                              priv->allocation.x1,
2721                              priv->allocation.y1,
2722                              0.0);
2723
2724       if (info->depth)
2725         cogl_matrix_translate (transform, 0, 0, info->depth);
2726
2727       /*
2728        * because the rotation involves translations, we must scale
2729        * before applying the rotations (if we apply the scale after
2730        * the rotations, the translations included in the rotation are
2731        * not scaled and so the entire object will move on the screen
2732        * as a result of rotating it).
2733        */
2734       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2735         {
2736           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2737                                         &info->scale_center,
2738                                         cogl_matrix_scale (transform,
2739                                                            info->scale_x,
2740                                                            info->scale_y,
2741                                                            1.0));
2742         }
2743
2744       if (info->rz_angle)
2745         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2746                                       &info->rz_center,
2747                                       cogl_matrix_rotate (transform,
2748                                                           info->rz_angle,
2749                                                           0, 0, 1.0));
2750
2751       if (info->ry_angle)
2752         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2753                                       &info->ry_center,
2754                                       cogl_matrix_rotate (transform,
2755                                                           info->ry_angle,
2756                                                           0, 1.0, 0));
2757
2758       if (info->rx_angle)
2759         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2760                                       &info->rx_center,
2761                                       cogl_matrix_rotate (transform,
2762                                                           info->rx_angle,
2763                                                           1.0, 0, 0));
2764
2765       if (!clutter_anchor_coord_is_zero (&info->anchor))
2766         {
2767           gfloat x, y, z;
2768
2769           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2770           cogl_matrix_translate (transform, -x, -y, -z);
2771         }
2772
2773       priv->transform_valid = TRUE;
2774     }
2775
2776   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2777 }
2778
2779 /* Applies the transforms associated with this actor to the given
2780  * matrix. */
2781 void
2782 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2783                                           CoglMatrix *matrix)
2784 {
2785   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2786 }
2787
2788 /*
2789  * clutter_actor_apply_relative_transformation_matrix:
2790  * @self: The actor whose coordinate space you want to transform from.
2791  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2792  *            or %NULL if you want to transform all the way to eye coordinates.
2793  * @matrix: A #CoglMatrix to apply the transformation too.
2794  *
2795  * This multiplies a transform with @matrix that will transform coordinates
2796  * from the coordinate space of @self into the coordinate space of @ancestor.
2797  *
2798  * For example if you need a matrix that can transform the local actor
2799  * coordinates of @self into stage coordinates you would pass the actor's stage
2800  * pointer as the @ancestor.
2801  *
2802  * If you pass %NULL then the transformation will take you all the way through
2803  * to eye coordinates. This can be useful if you want to extract the entire
2804  * modelview transform that Clutter applies before applying the projection
2805  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2806  * using cogl_set_modelview_matrix() for example then you would want a matrix
2807  * that transforms into eye coordinates.
2808  *
2809  * <note>This function doesn't initialize the given @matrix, it simply
2810  * multiplies the requested transformation matrix with the existing contents of
2811  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2812  * before calling this function, or you can use
2813  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2814  */
2815 void
2816 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2817                                                      ClutterActor *ancestor,
2818                                                      CoglMatrix *matrix)
2819 {
2820   ClutterActor *parent;
2821
2822   /* Note we terminate before ever calling stage->apply_transform()
2823    * since that would conceptually be relative to the underlying
2824    * window OpenGL coordinates so we'd need a special @ancestor
2825    * value to represent the fake parent of the stage. */
2826   if (self == ancestor)
2827     return;
2828
2829   parent = clutter_actor_get_parent (self);
2830
2831   if (parent != NULL)
2832     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2833                                                          matrix);
2834
2835   _clutter_actor_apply_modelview_transform (self, matrix);
2836 }
2837
2838 static void
2839 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2840                                        ClutterPaintVolume *pv,
2841                                        const char *label,
2842                                        const CoglColor *color)
2843 {
2844   static CoglPipeline *outline = NULL;
2845   CoglPrimitive *prim;
2846   ClutterVertex line_ends[12 * 2];
2847   int n_vertices;
2848   CoglContext *ctx =
2849     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2850   /* XXX: at some point we'll query this from the stage but we can't
2851    * do that until the osx backend uses Cogl natively. */
2852   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2853
2854   if (outline == NULL)
2855     outline = cogl_pipeline_new (ctx);
2856
2857   _clutter_paint_volume_complete (pv);
2858
2859   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2860
2861   /* Front face */
2862   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2863   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2864   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2865   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2866
2867   if (!pv->is_2d)
2868     {
2869       /* Back face */
2870       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2871       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2872       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2873       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2874
2875       /* Lines connecting front face to back face */
2876       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2877       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2878       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2879       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2880     }
2881
2882   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2883                                 n_vertices,
2884                                 (CoglVertexP3 *)line_ends);
2885
2886   cogl_pipeline_set_color (outline, color);
2887   cogl_framebuffer_draw_primitive (fb, outline, prim);
2888   cogl_object_unref (prim);
2889
2890   if (label)
2891     {
2892       PangoLayout *layout;
2893       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2894       pango_layout_set_text (layout, label, -1);
2895       cogl_pango_render_layout (layout,
2896                                 pv->vertices[0].x,
2897                                 pv->vertices[0].y,
2898                                 color,
2899                                 0);
2900       g_object_unref (layout);
2901     }
2902 }
2903
2904 static void
2905 _clutter_actor_draw_paint_volume (ClutterActor *self)
2906 {
2907   ClutterPaintVolume *pv;
2908   CoglColor color;
2909
2910   pv = _clutter_actor_get_paint_volume_mutable (self);
2911   if (!pv)
2912     {
2913       gfloat width, height;
2914       ClutterPaintVolume fake_pv;
2915
2916       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2917       _clutter_paint_volume_init_static (&fake_pv, stage);
2918
2919       clutter_actor_get_size (self, &width, &height);
2920       clutter_paint_volume_set_width (&fake_pv, width);
2921       clutter_paint_volume_set_height (&fake_pv, height);
2922
2923       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2924       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2925                                              _clutter_actor_get_debug_name (self),
2926                                              &color);
2927
2928       clutter_paint_volume_free (&fake_pv);
2929     }
2930   else
2931     {
2932       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2933       _clutter_actor_draw_paint_volume_full (self, pv,
2934                                              _clutter_actor_get_debug_name (self),
2935                                              &color);
2936     }
2937 }
2938
2939 static void
2940 _clutter_actor_paint_cull_result (ClutterActor *self,
2941                                   gboolean success,
2942                                   ClutterCullResult result)
2943 {
2944   ClutterPaintVolume *pv;
2945   CoglColor color;
2946
2947   if (success)
2948     {
2949       if (result == CLUTTER_CULL_RESULT_IN)
2950         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2951       else if (result == CLUTTER_CULL_RESULT_OUT)
2952         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2953       else
2954         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2955     }
2956   else
2957     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2958
2959   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2960     _clutter_actor_draw_paint_volume_full (self, pv,
2961                                            _clutter_actor_get_debug_name (self),
2962                                            &color);
2963   else
2964     {
2965       PangoLayout *layout;
2966       char *label =
2967         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2968       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2969       cogl_set_source_color (&color);
2970
2971       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2972       pango_layout_set_text (layout, label, -1);
2973       cogl_pango_render_layout (layout,
2974                                 0,
2975                                 0,
2976                                 &color,
2977                                 0);
2978       g_free (label);
2979       g_object_unref (layout);
2980     }
2981 }
2982
2983 static int clone_paint_level = 0;
2984
2985 void
2986 _clutter_actor_push_clone_paint (void)
2987 {
2988   clone_paint_level++;
2989 }
2990
2991 void
2992 _clutter_actor_pop_clone_paint (void)
2993 {
2994   clone_paint_level--;
2995 }
2996
2997 static gboolean
2998 in_clone_paint (void)
2999 {
3000   return clone_paint_level > 0;
3001 }
3002
3003 /* Returns TRUE if the actor can be ignored */
3004 /* FIXME: we should return a ClutterCullResult, and
3005  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3006  * means there's no point in trying to cull descendants of the current
3007  * node. */
3008 static gboolean
3009 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3010 {
3011   ClutterActorPrivate *priv = self->priv;
3012   ClutterActor *stage;
3013   const ClutterPlane *stage_clip;
3014
3015   if (!priv->last_paint_volume_valid)
3016     {
3017       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3018                     "->last_paint_volume_valid == FALSE",
3019                     _clutter_actor_get_debug_name (self));
3020       return FALSE;
3021     }
3022
3023   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3024     return FALSE;
3025
3026   stage = _clutter_actor_get_stage_internal (self);
3027   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3028   if (G_UNLIKELY (!stage_clip))
3029     {
3030       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3031                     "No stage clip set",
3032                     _clutter_actor_get_debug_name (self));
3033       return FALSE;
3034     }
3035
3036   if (cogl_get_draw_framebuffer () !=
3037       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3038     {
3039       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3040                     "Current framebuffer doesn't correspond to stage",
3041                     _clutter_actor_get_debug_name (self));
3042       return FALSE;
3043     }
3044
3045   *result_out =
3046     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3047   return TRUE;
3048 }
3049
3050 static void
3051 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3052 {
3053   ClutterActorPrivate *priv = self->priv;
3054   const ClutterPaintVolume *pv;
3055
3056   if (priv->last_paint_volume_valid)
3057     {
3058       clutter_paint_volume_free (&priv->last_paint_volume);
3059       priv->last_paint_volume_valid = FALSE;
3060     }
3061
3062   pv = clutter_actor_get_paint_volume (self);
3063   if (!pv)
3064     {
3065       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3066                     "Actor failed to report a paint volume",
3067                     _clutter_actor_get_debug_name (self));
3068       return;
3069     }
3070
3071   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3072
3073   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3074                                             NULL); /* eye coordinates */
3075
3076   priv->last_paint_volume_valid = TRUE;
3077 }
3078
3079 static inline gboolean
3080 actor_has_shader_data (ClutterActor *self)
3081 {
3082   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3083 }
3084
3085 guint32
3086 _clutter_actor_get_pick_id (ClutterActor *self)
3087 {
3088   if (self->priv->pick_id < 0)
3089     return 0;
3090
3091   return self->priv->pick_id;
3092 }
3093
3094 /* This is the same as clutter_actor_add_effect except that it doesn't
3095    queue a redraw and it doesn't notify on the effect property */
3096 static void
3097 _clutter_actor_add_effect_internal (ClutterActor  *self,
3098                                     ClutterEffect *effect)
3099 {
3100   ClutterActorPrivate *priv = self->priv;
3101
3102   if (priv->effects == NULL)
3103     {
3104       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3105       priv->effects->actor = self;
3106     }
3107
3108   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3109 }
3110
3111 /* This is the same as clutter_actor_remove_effect except that it doesn't
3112    queue a redraw and it doesn't notify on the effect property */
3113 static void
3114 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3115                                        ClutterEffect *effect)
3116 {
3117   ClutterActorPrivate *priv = self->priv;
3118
3119   if (priv->effects == NULL)
3120     return;
3121
3122   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3123 }
3124
3125 static gboolean
3126 needs_flatten_effect (ClutterActor *self)
3127 {
3128   ClutterActorPrivate *priv = self->priv;
3129
3130   if (G_UNLIKELY (clutter_paint_debug_flags &
3131                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3132     return FALSE;
3133
3134   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3135     return TRUE;
3136   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3137     {
3138       if (clutter_actor_get_paint_opacity (self) < 255 &&
3139           clutter_actor_has_overlaps (self))
3140         return TRUE;
3141     }
3142
3143   return FALSE;
3144 }
3145
3146 static void
3147 add_or_remove_flatten_effect (ClutterActor *self)
3148 {
3149   ClutterActorPrivate *priv = self->priv;
3150
3151   /* Add or remove the flatten effect depending on the
3152      offscreen-redirect property. */
3153   if (needs_flatten_effect (self))
3154     {
3155       if (priv->flatten_effect == NULL)
3156         {
3157           ClutterActorMeta *actor_meta;
3158           gint priority;
3159
3160           priv->flatten_effect = _clutter_flatten_effect_new ();
3161           /* Keep a reference to the effect so that we can queue
3162              redraws from it */
3163           g_object_ref_sink (priv->flatten_effect);
3164
3165           /* Set the priority of the effect to high so that it will
3166              always be applied to the actor first. It uses an internal
3167              priority so that it won't be visible to applications */
3168           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3169           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3170           _clutter_actor_meta_set_priority (actor_meta, priority);
3171
3172           /* This will add the effect without queueing a redraw */
3173           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3174         }
3175     }
3176   else
3177     {
3178       if (priv->flatten_effect != NULL)
3179         {
3180           /* Destroy the effect so that it will lose its fbo cache of
3181              the actor */
3182           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3183           g_clear_object (&priv->flatten_effect);
3184         }
3185     }
3186 }
3187
3188 static void
3189 clutter_actor_real_paint (ClutterActor *actor)
3190 {
3191   ClutterActorPrivate *priv = actor->priv;
3192   ClutterActor *iter;
3193
3194   for (iter = priv->first_child;
3195        iter != NULL;
3196        iter = iter->priv->next_sibling)
3197     {
3198       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3199                     _clutter_actor_get_debug_name (iter),
3200                     _clutter_actor_get_debug_name (actor),
3201                     iter->priv->allocation.x1,
3202                     iter->priv->allocation.y1,
3203                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3204                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3205
3206       clutter_actor_paint (iter);
3207     }
3208 }
3209
3210 static gboolean
3211 clutter_actor_paint_node (ClutterActor     *actor,
3212                           ClutterPaintNode *root)
3213 {
3214   ClutterActorPrivate *priv = actor->priv;
3215
3216   if (root == NULL)
3217     return FALSE;
3218
3219   if (priv->bg_color_set &&
3220       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3221     {
3222       ClutterPaintNode *node;
3223       ClutterColor bg_color;
3224       ClutterActorBox box;
3225
3226       box.x1 = 0.f;
3227       box.y1 = 0.f;
3228       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3229       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3230
3231       bg_color = priv->bg_color;
3232       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3233                      * priv->bg_color.alpha
3234                      / 255;
3235
3236       node = clutter_color_node_new (&bg_color);
3237       clutter_paint_node_set_name (node, "backgroundColor");
3238       clutter_paint_node_add_rectangle (node, &box);
3239       clutter_paint_node_add_child (root, node);
3240       clutter_paint_node_unref (node);
3241     }
3242
3243   if (priv->content != NULL)
3244     _clutter_content_paint_content (priv->content, actor, root);
3245
3246   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3247     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3248
3249   if (clutter_paint_node_get_n_children (root) == 0)
3250     return FALSE;
3251
3252 #ifdef CLUTTER_ENABLE_DEBUG
3253   if (CLUTTER_HAS_DEBUG (PAINT))
3254     {
3255       /* dump the tree only if we have one */
3256       _clutter_paint_node_dump_tree (root);
3257     }
3258 #endif /* CLUTTER_ENABLE_DEBUG */
3259
3260   _clutter_paint_node_paint (root);
3261
3262 #if 0
3263   /* XXX: Uncomment this when we disable emitting the paint signal */
3264   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3265 #endif
3266
3267   return TRUE;
3268 }
3269
3270 /**
3271  * clutter_actor_paint:
3272  * @self: A #ClutterActor
3273  *
3274  * Renders the actor to display.
3275  *
3276  * This function should not be called directly by applications.
3277  * Call clutter_actor_queue_redraw() to queue paints, instead.
3278  *
3279  * This function is context-aware, and will either cause a
3280  * regular paint or a pick paint.
3281  *
3282  * This function will emit the #ClutterActor::paint signal or
3283  * the #ClutterActor::pick signal, depending on the context.
3284  *
3285  * This function does not paint the actor if the actor is set to 0,
3286  * unless it is performing a pick paint.
3287  */
3288 void
3289 clutter_actor_paint (ClutterActor *self)
3290 {
3291   ClutterActorPrivate *priv;
3292   ClutterPickMode pick_mode;
3293   gboolean clip_set = FALSE;
3294   gboolean shader_applied = FALSE;
3295
3296   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3297                           "Actor real-paint counter",
3298                           "Increments each time any actor is painted",
3299                           0 /* no application private data */);
3300   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3301                           "Actor pick-paint counter",
3302                           "Increments each time any actor is painted "
3303                           "for picking",
3304                           0 /* no application private data */);
3305
3306   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3307
3308   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3309     return;
3310
3311   priv = self->priv;
3312
3313   pick_mode = _clutter_context_get_pick_mode ();
3314
3315   if (pick_mode == CLUTTER_PICK_NONE)
3316     priv->propagated_one_redraw = FALSE;
3317
3318   /* It's an important optimization that we consider painting of
3319    * actors with 0 opacity to be a NOP... */
3320   if (pick_mode == CLUTTER_PICK_NONE &&
3321       /* ignore top-levels, since they might be transparent */
3322       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3323       /* Use the override opacity if its been set */
3324       ((priv->opacity_override >= 0) ?
3325        priv->opacity_override : priv->opacity) == 0)
3326     return;
3327
3328   /* if we aren't paintable (not in a toplevel with all
3329    * parents paintable) then do nothing.
3330    */
3331   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3332     return;
3333
3334   /* mark that we are in the paint process */
3335   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3336
3337   cogl_push_matrix();
3338
3339   if (priv->enable_model_view_transform)
3340     {
3341       CoglMatrix matrix;
3342
3343       /* XXX: It could be better to cache the modelview with the actor
3344        * instead of progressively building up the transformations on
3345        * the matrix stack every time we paint. */
3346       cogl_get_modelview_matrix (&matrix);
3347       _clutter_actor_apply_modelview_transform (self, &matrix);
3348
3349 #ifdef CLUTTER_ENABLE_DEBUG
3350       /* Catch when out-of-band transforms have been made by actors not as part
3351        * of an apply_transform vfunc... */
3352       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3353         {
3354           CoglMatrix expected_matrix;
3355
3356           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3357                                                              &expected_matrix);
3358
3359           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3360             {
3361               GString *buf = g_string_sized_new (1024);
3362               ClutterActor *parent;
3363
3364               parent = self;
3365               while (parent != NULL)
3366                 {
3367                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3368
3369                   if (parent->priv->parent != NULL)
3370                     g_string_append (buf, "->");
3371
3372                   parent = parent->priv->parent;
3373                 }
3374
3375               g_warning ("Unexpected transform found when painting actor "
3376                          "\"%s\". This will be caused by one of the actor's "
3377                          "ancestors (%s) using the Cogl API directly to transform "
3378                          "children instead of using ::apply_transform().",
3379                          _clutter_actor_get_debug_name (self),
3380                          buf->str);
3381
3382               g_string_free (buf, TRUE);
3383             }
3384         }
3385 #endif /* CLUTTER_ENABLE_DEBUG */
3386
3387       cogl_set_modelview_matrix (&matrix);
3388     }
3389
3390   if (priv->has_clip)
3391     {
3392       cogl_clip_push_rectangle (priv->clip.x,
3393                                 priv->clip.y,
3394                                 priv->clip.x + priv->clip.width,
3395                                 priv->clip.y + priv->clip.height);
3396       clip_set = TRUE;
3397     }
3398   else if (priv->clip_to_allocation)
3399     {
3400       gfloat width, height;
3401
3402       width  = priv->allocation.x2 - priv->allocation.x1;
3403       height = priv->allocation.y2 - priv->allocation.y1;
3404
3405       cogl_clip_push_rectangle (0, 0, width, height);
3406       clip_set = TRUE;
3407     }
3408
3409   if (pick_mode == CLUTTER_PICK_NONE)
3410     {
3411       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3412
3413       /* We check whether we need to add the flatten effect before
3414          each paint so that we can avoid having a mechanism for
3415          applications to notify when the value of the
3416          has_overlaps virtual changes. */
3417       add_or_remove_flatten_effect (self);
3418     }
3419   else
3420     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3421
3422   /* We save the current paint volume so that the next time the
3423    * actor queues a redraw we can constrain the redraw to just
3424    * cover the union of the new bounding box and the old.
3425    *
3426    * We also fetch the current paint volume to perform culling so
3427    * we can avoid painting actors outside the current clip region.
3428    *
3429    * If we are painting inside a clone, we should neither update
3430    * the paint volume or use it to cull painting, since the paint
3431    * box represents the location of the source actor on the
3432    * screen.
3433    *
3434    * XXX: We are starting to do a lot of vertex transforms on
3435    * the CPU in a typical paint, so at some point we should
3436    * audit these and consider caching some things.
3437    *
3438    * NB: We don't perform culling while picking at this point because
3439    * clutter-stage.c doesn't setup the clipping planes appropriately.
3440    *
3441    * NB: We don't want to update the last-paint-volume during picking
3442    * because the last-paint-volume is used to determine the old screen
3443    * space location of an actor that has moved so we can know the
3444    * minimal region to redraw to clear an old view of the actor. If we
3445    * update this during picking then by the time we come around to
3446    * paint then the last-paint-volume would likely represent the new
3447    * actor position not the old.
3448    */
3449   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3450     {
3451       gboolean success;
3452       /* annoyingly gcc warns if uninitialized even though
3453        * the initialization is redundant :-( */
3454       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3455
3456       if (G_LIKELY ((clutter_paint_debug_flags &
3457                      (CLUTTER_DEBUG_DISABLE_CULLING |
3458                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3459                     (CLUTTER_DEBUG_DISABLE_CULLING |
3460                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3461         _clutter_actor_update_last_paint_volume (self);
3462
3463       success = cull_actor (self, &result);
3464
3465       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3466         _clutter_actor_paint_cull_result (self, success, result);
3467       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3468         goto done;
3469     }
3470
3471   if (priv->effects == NULL)
3472     {
3473       if (pick_mode == CLUTTER_PICK_NONE &&
3474           actor_has_shader_data (self))
3475         {
3476           _clutter_actor_shader_pre_paint (self, FALSE);
3477           shader_applied = TRUE;
3478         }
3479
3480       priv->next_effect_to_paint = NULL;
3481     }
3482   else
3483     priv->next_effect_to_paint =
3484       _clutter_meta_group_peek_metas (priv->effects);
3485
3486   clutter_actor_continue_paint (self);
3487
3488   if (shader_applied)
3489     _clutter_actor_shader_post_paint (self);
3490
3491   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3492                   pick_mode == CLUTTER_PICK_NONE))
3493     _clutter_actor_draw_paint_volume (self);
3494
3495 done:
3496   /* If we make it here then the actor has run through a complete
3497      paint run including all the effects so it's no longer dirty */
3498   if (pick_mode == CLUTTER_PICK_NONE)
3499     priv->is_dirty = FALSE;
3500
3501   if (clip_set)
3502     cogl_clip_pop();
3503
3504   cogl_pop_matrix();
3505
3506   /* paint sequence complete */
3507   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3508 }
3509
3510 /**
3511  * clutter_actor_continue_paint:
3512  * @self: A #ClutterActor
3513  *
3514  * Run the next stage of the paint sequence. This function should only
3515  * be called within the implementation of the ‘run’ virtual of a
3516  * #ClutterEffect. It will cause the run method of the next effect to
3517  * be applied, or it will paint the actual actor if the current effect
3518  * is the last effect in the chain.
3519  *
3520  * Since: 1.8
3521  */
3522 void
3523 clutter_actor_continue_paint (ClutterActor *self)
3524 {
3525   ClutterActorPrivate *priv;
3526
3527   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3528   /* This should only be called from with in the ‘run’ implementation
3529      of a ClutterEffect */
3530   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3531
3532   priv = self->priv;
3533
3534   /* Skip any effects that are disabled */
3535   while (priv->next_effect_to_paint &&
3536          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3537     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3538
3539   /* If this has come from the last effect then we'll just paint the
3540      actual actor */
3541   if (priv->next_effect_to_paint == NULL)
3542     {
3543       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3544         {
3545           ClutterPaintNode *dummy;
3546
3547           /* XXX - this will go away in 2.0, when we can get rid of this
3548            * stuff and switch to a pure retained render tree of PaintNodes
3549            * for the entire frame, starting from the Stage; the paint()
3550            * virtual function can then be called directly.
3551            */
3552           dummy = _clutter_dummy_node_new (self);
3553           clutter_paint_node_set_name (dummy, "Root");
3554
3555           /* XXX - for 1.12, we use the return value of paint_node() to
3556            * decide whether we should emit the ::paint signal.
3557            */
3558           clutter_actor_paint_node (self, dummy);
3559           clutter_paint_node_unref (dummy);
3560
3561           g_signal_emit (self, actor_signals[PAINT], 0);
3562         }
3563       else
3564         {
3565           ClutterColor col = { 0, };
3566
3567           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3568
3569           /* Actor will then paint silhouette of itself in supplied
3570            * color.  See clutter_stage_get_actor_at_pos() for where
3571            * picking is enabled.
3572            */
3573           g_signal_emit (self, actor_signals[PICK], 0, &col);
3574         }
3575     }
3576   else
3577     {
3578       ClutterEffect *old_current_effect;
3579       ClutterEffectPaintFlags run_flags = 0;
3580
3581       /* Cache the current effect so that we can put it back before
3582          returning */
3583       old_current_effect = priv->current_effect;
3584
3585       priv->current_effect = priv->next_effect_to_paint->data;
3586       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3587
3588       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3589         {
3590           if (priv->is_dirty)
3591             {
3592               /* If there's an effect queued with this redraw then all
3593                  effects up to that one will be considered dirty. It
3594                  is expected the queued effect will paint the cached
3595                  image and not call clutter_actor_continue_paint again
3596                  (although it should work ok if it does) */
3597               if (priv->effect_to_redraw == NULL ||
3598                   priv->current_effect != priv->effect_to_redraw)
3599                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3600             }
3601
3602           _clutter_effect_paint (priv->current_effect, run_flags);
3603         }
3604       else
3605         {
3606           /* We can't determine when an actor has been modified since
3607              its last pick so lets just assume it has always been
3608              modified */
3609           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3610
3611           _clutter_effect_pick (priv->current_effect, run_flags);
3612         }
3613
3614       priv->current_effect = old_current_effect;
3615     }
3616 }
3617
3618 static ClutterActorTraverseVisitFlags
3619 invalidate_queue_redraw_entry (ClutterActor *self,
3620                                int           depth,
3621                                gpointer      user_data)
3622 {
3623   ClutterActorPrivate *priv = self->priv;
3624
3625   if (priv->queue_redraw_entry != NULL)
3626     {
3627       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3628       priv->queue_redraw_entry = NULL;
3629     }
3630
3631   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3632 }
3633
3634 static inline void
3635 remove_child (ClutterActor *self,
3636               ClutterActor *child)
3637 {
3638   ClutterActor *prev_sibling, *next_sibling;
3639
3640   prev_sibling = child->priv->prev_sibling;
3641   next_sibling = child->priv->next_sibling;
3642
3643   if (prev_sibling != NULL)
3644     prev_sibling->priv->next_sibling = next_sibling;
3645
3646   if (next_sibling != NULL)
3647     next_sibling->priv->prev_sibling = prev_sibling;
3648
3649   if (self->priv->first_child == child)
3650     self->priv->first_child = next_sibling;
3651
3652   if (self->priv->last_child == child)
3653     self->priv->last_child = prev_sibling;
3654
3655   child->priv->parent = NULL;
3656   child->priv->prev_sibling = NULL;
3657   child->priv->next_sibling = NULL;
3658 }
3659
3660 typedef enum {
3661   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3662   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3663   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3664   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3665   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3666   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3667
3668   /* default flags for public API */
3669   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3670                                     REMOVE_CHILD_EMIT_PARENT_SET |
3671                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3672                                     REMOVE_CHILD_CHECK_STATE |
3673                                     REMOVE_CHILD_FLUSH_QUEUE |
3674                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3675
3676   /* flags for legacy/deprecated API */
3677   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3678                                     REMOVE_CHILD_FLUSH_QUEUE |
3679                                     REMOVE_CHILD_EMIT_PARENT_SET |
3680                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3681 } ClutterActorRemoveChildFlags;
3682
3683 /*< private >
3684  * clutter_actor_remove_child_internal:
3685  * @self: a #ClutterActor
3686  * @child: the child of @self that has to be removed
3687  * @flags: control the removal operations
3688  *
3689  * Removes @child from the list of children of @self.
3690  */
3691 static void
3692 clutter_actor_remove_child_internal (ClutterActor                 *self,
3693                                      ClutterActor                 *child,
3694                                      ClutterActorRemoveChildFlags  flags)
3695 {
3696   ClutterActor *old_first, *old_last;
3697   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3698   gboolean flush_queue;
3699   gboolean notify_first_last;
3700   gboolean was_mapped;
3701
3702   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3703   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3704   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3705   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3706   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3707   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3708
3709   g_object_freeze_notify (G_OBJECT (self));
3710
3711   if (destroy_meta)
3712     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3713
3714   if (check_state)
3715     {
3716       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3717
3718       /* we need to unrealize *before* we set parent_actor to NULL,
3719        * because in an unrealize method actors are dissociating from the
3720        * stage, which means they need to be able to
3721        * clutter_actor_get_stage().
3722        *
3723        * yhis should unmap and unrealize, unless we're reparenting.
3724        */
3725       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3726     }
3727   else
3728     was_mapped = FALSE;
3729
3730   if (flush_queue)
3731     {
3732       /* We take this opportunity to invalidate any queue redraw entry
3733        * associated with the actor and descendants since we won't be able to
3734        * determine the appropriate stage after this.
3735        *
3736        * we do this after we updated the mapped state because actors might
3737        * end up queueing redraws inside their mapped/unmapped virtual
3738        * functions, and if we invalidate the redraw entry we could end up
3739        * with an inconsistent state and weird memory corruption. see
3740        * bugs:
3741        *
3742        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3743        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3744        */
3745       _clutter_actor_traverse (child,
3746                                0,
3747                                invalidate_queue_redraw_entry,
3748                                NULL,
3749                                NULL);
3750     }
3751
3752   old_first = self->priv->first_child;
3753   old_last = self->priv->last_child;
3754
3755   remove_child (self, child);
3756
3757   self->priv->n_children -= 1;
3758
3759   self->priv->age += 1;
3760
3761   /* clutter_actor_reparent() will emit ::parent-set for us */
3762   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3763     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3764
3765   /* if the child was mapped then we need to relayout ourselves to account
3766    * for the removed child
3767    */
3768   if (was_mapped)
3769     clutter_actor_queue_relayout (self);
3770
3771   /* we need to emit the signal before dropping the reference */
3772   if (emit_actor_removed)
3773     g_signal_emit_by_name (self, "actor-removed", child);
3774
3775   if (notify_first_last)
3776     {
3777       if (old_first != self->priv->first_child)
3778         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3779
3780       if (old_last != self->priv->last_child)
3781         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3782     }
3783
3784   g_object_thaw_notify (G_OBJECT (self));
3785
3786   /* remove the reference we acquired in clutter_actor_add_child() */
3787   g_object_unref (child);
3788 }
3789
3790 static const ClutterTransformInfo default_transform_info = {
3791   0.0, { 0, },          /* rotation-x */
3792   0.0, { 0, },          /* rotation-y */
3793   0.0, { 0, },          /* rotation-z */
3794
3795   1.0, 1.0, { 0, },     /* scale */
3796
3797   { 0, },               /* anchor */
3798
3799   0.0,                  /* depth */
3800 };
3801
3802 /*< private >
3803  * _clutter_actor_get_transform_info_or_defaults:
3804  * @self: a #ClutterActor
3805  *
3806  * Retrieves the ClutterTransformInfo structure associated to an actor.
3807  *
3808  * If the actor does not have a ClutterTransformInfo structure associated
3809  * to it, then the default structure will be returned.
3810  *
3811  * This function should only be used for getters.
3812  *
3813  * Return value: a const pointer to the ClutterTransformInfo structure
3814  */
3815 const ClutterTransformInfo *
3816 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3817 {
3818   ClutterTransformInfo *info;
3819
3820   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3821   if (info != NULL)
3822     return info;
3823
3824   return &default_transform_info;
3825 }
3826
3827 static void
3828 clutter_transform_info_free (gpointer data)
3829 {
3830   if (data != NULL)
3831     g_slice_free (ClutterTransformInfo, data);
3832 }
3833
3834 /*< private >
3835  * _clutter_actor_get_transform_info:
3836  * @self: a #ClutterActor
3837  *
3838  * Retrieves a pointer to the ClutterTransformInfo structure.
3839  *
3840  * If the actor does not have a ClutterTransformInfo associated to it, one
3841  * will be created and initialized to the default values.
3842  *
3843  * This function should be used for setters.
3844  *
3845  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3846  * instead.
3847  *
3848  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3849  *   structure
3850  */
3851 ClutterTransformInfo *
3852 _clutter_actor_get_transform_info (ClutterActor *self)
3853 {
3854   ClutterTransformInfo *info;
3855
3856   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3857   if (info == NULL)
3858     {
3859       info = g_slice_new (ClutterTransformInfo);
3860
3861       *info = default_transform_info;
3862
3863       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3864                                info,
3865                                clutter_transform_info_free);
3866     }
3867
3868   return info;
3869 }
3870
3871 /*< private >
3872  * clutter_actor_set_rotation_angle_internal:
3873  * @self: a #ClutterActor
3874  * @axis: the axis of the angle to change
3875  * @angle: the angle of rotation
3876  *
3877  * Sets the rotation angle on the given axis without affecting the
3878  * rotation center point.
3879  */
3880 static inline void
3881 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3882                                            ClutterRotateAxis  axis,
3883                                            gdouble            angle)
3884 {
3885   GObject *obj = G_OBJECT (self);
3886   ClutterTransformInfo *info;
3887
3888   info = _clutter_actor_get_transform_info (self);
3889
3890   g_object_freeze_notify (obj);
3891
3892   switch (axis)
3893     {
3894     case CLUTTER_X_AXIS:
3895       info->rx_angle = angle;
3896       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3897       break;
3898
3899     case CLUTTER_Y_AXIS:
3900       info->ry_angle = angle;
3901       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3902       break;
3903
3904     case CLUTTER_Z_AXIS:
3905       info->rz_angle = angle;
3906       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3907       break;
3908     }
3909
3910   self->priv->transform_valid = FALSE;
3911
3912   g_object_thaw_notify (obj);
3913
3914   clutter_actor_queue_redraw (self);
3915 }
3916
3917 static inline void
3918 clutter_actor_set_rotation_angle (ClutterActor      *self,
3919                                   ClutterRotateAxis  axis,
3920                                   gdouble            angle)
3921 {
3922   ClutterTransformInfo *info;
3923
3924   info = _clutter_actor_get_transform_info (self);
3925
3926   if (clutter_actor_get_easing_duration (self) != 0)
3927     {
3928       ClutterTransition *transition;
3929       GParamSpec *pspec = NULL;
3930       double *cur_angle_p = NULL;
3931
3932       switch (axis)
3933         {
3934         case CLUTTER_X_AXIS:
3935           cur_angle_p = &info->rx_angle;
3936           pspec = obj_props[PROP_ROTATION_ANGLE_X];
3937           break;
3938
3939         case CLUTTER_Y_AXIS:
3940           cur_angle_p = &info->ry_angle;
3941           pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3942           break;
3943
3944         case CLUTTER_Z_AXIS:
3945           cur_angle_p = &info->rz_angle;
3946           pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3947           break;
3948         }
3949
3950       g_assert (pspec != NULL);
3951       g_assert (cur_angle_p != NULL);
3952
3953       transition = _clutter_actor_get_transition (self, pspec);
3954       if (transition == NULL)
3955         {
3956           transition = _clutter_actor_create_transition (self, pspec,
3957                                                          *cur_angle_p,
3958                                                          angle);
3959         }
3960       else
3961         _clutter_actor_update_transition (self, pspec, angle);
3962
3963       self->priv->transform_valid = FALSE;
3964       clutter_actor_queue_redraw (self);
3965     }
3966   else
3967     clutter_actor_set_rotation_angle_internal (self, axis, angle);
3968 }
3969
3970 /*< private >
3971  * clutter_actor_set_rotation_center_internal:
3972  * @self: a #ClutterActor
3973  * @axis: the axis of the center to change
3974  * @center: the coordinates of the rotation center
3975  *
3976  * Sets the rotation center on the given axis without affecting the
3977  * rotation angle.
3978  */
3979 static inline void
3980 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3981                                             ClutterRotateAxis    axis,
3982                                             const ClutterVertex *center)
3983 {
3984   GObject *obj = G_OBJECT (self);
3985   ClutterTransformInfo *info;
3986   ClutterVertex v = { 0, 0, 0 };
3987
3988   info = _clutter_actor_get_transform_info (self);
3989
3990   if (center != NULL)
3991     v = *center;
3992
3993   g_object_freeze_notify (obj);
3994
3995   switch (axis)
3996     {
3997     case CLUTTER_X_AXIS:
3998       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3999       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4000       break;
4001
4002     case CLUTTER_Y_AXIS:
4003       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4004       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4005       break;
4006
4007     case CLUTTER_Z_AXIS:
4008       /* if the previously set rotation center was fractional, then
4009        * setting explicit coordinates will have to notify the
4010        * :rotation-center-z-gravity property as well
4011        */
4012       if (info->rz_center.is_fractional)
4013         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4014
4015       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4016       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4017       break;
4018     }
4019
4020   self->priv->transform_valid = FALSE;
4021
4022   g_object_thaw_notify (obj);
4023
4024   clutter_actor_queue_redraw (self);
4025 }
4026
4027 static void
4028 clutter_actor_animate_scale_factor (ClutterActor *self,
4029                                     double        old_factor,
4030                                     double        new_factor,
4031                                     GParamSpec   *pspec)
4032 {
4033   ClutterTransition *transition;
4034
4035   transition = _clutter_actor_get_transition (self, pspec);
4036   if (transition == NULL)
4037     {
4038       transition = _clutter_actor_create_transition (self, pspec,
4039                                                      old_factor,
4040                                                      new_factor);
4041     }
4042   else
4043     _clutter_actor_update_transition (self, pspec, new_factor);
4044
4045
4046   self->priv->transform_valid = FALSE;
4047   clutter_actor_queue_redraw (self);
4048 }
4049
4050 static void
4051 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4052                                          double factor,
4053                                          GParamSpec *pspec)
4054 {
4055   GObject *obj = G_OBJECT (self);
4056   ClutterTransformInfo *info;
4057
4058   info = _clutter_actor_get_transform_info (self);
4059
4060   if (pspec == obj_props[PROP_SCALE_X])
4061     info->scale_x = factor;
4062   else
4063     info->scale_y = factor;
4064
4065   self->priv->transform_valid = FALSE;
4066   clutter_actor_queue_redraw (self);
4067   g_object_notify_by_pspec (obj, pspec);
4068 }
4069
4070 static inline void
4071 clutter_actor_set_scale_factor (ClutterActor      *self,
4072                                 ClutterRotateAxis  axis,
4073                                 gdouble            factor)
4074 {
4075   GObject *obj = G_OBJECT (self);
4076   ClutterTransformInfo *info;
4077   GParamSpec *pspec;
4078
4079   info = _clutter_actor_get_transform_info (self);
4080
4081   g_object_freeze_notify (obj);
4082
4083   switch (axis)
4084     {
4085     case CLUTTER_X_AXIS:
4086       pspec = obj_props[PROP_SCALE_X];
4087
4088       if (clutter_actor_get_easing_duration (self) != 0)
4089         clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
4090       else
4091         clutter_actor_set_scale_factor_internal (self, factor, pspec);
4092       break;
4093
4094     case CLUTTER_Y_AXIS:
4095       pspec = obj_props[PROP_SCALE_Y];
4096
4097       if (clutter_actor_get_easing_duration (self) != 0)
4098         clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4099       else
4100         clutter_actor_set_scale_factor_internal (self, factor, pspec);
4101       break;
4102
4103     default:
4104       g_assert_not_reached ();
4105     }
4106
4107   g_object_thaw_notify (obj);
4108 }
4109
4110 static inline void
4111 clutter_actor_set_scale_center (ClutterActor      *self,
4112                                 ClutterRotateAxis  axis,
4113                                 gfloat             coord)
4114 {
4115   GObject *obj = G_OBJECT (self);
4116   ClutterTransformInfo *info;
4117   gfloat center_x, center_y;
4118
4119   info = _clutter_actor_get_transform_info (self);
4120
4121   g_object_freeze_notify (obj);
4122
4123   /* get the current scale center coordinates */
4124   clutter_anchor_coord_get_units (self, &info->scale_center,
4125                                   &center_x,
4126                                   &center_y,
4127                                   NULL);
4128
4129   /* we need to notify this too, because setting explicit coordinates will
4130    * change the gravity as a side effect
4131    */
4132   if (info->scale_center.is_fractional)
4133     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4134
4135   switch (axis)
4136     {
4137     case CLUTTER_X_AXIS:
4138       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4139       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4140       break;
4141
4142     case CLUTTER_Y_AXIS:
4143       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4144       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4145       break;
4146
4147     default:
4148       g_assert_not_reached ();
4149     }
4150
4151   self->priv->transform_valid = FALSE;
4152
4153   clutter_actor_queue_redraw (self);
4154
4155   g_object_thaw_notify (obj);
4156 }
4157
4158 static inline void
4159 clutter_actor_set_scale_gravity (ClutterActor   *self,
4160                                  ClutterGravity  gravity)
4161 {
4162   ClutterTransformInfo *info;
4163   GObject *obj;
4164
4165   info = _clutter_actor_get_transform_info (self);
4166   obj = G_OBJECT (self);
4167
4168   if (gravity == CLUTTER_GRAVITY_NONE)
4169     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4170   else
4171     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4172
4173   self->priv->transform_valid = FALSE;
4174
4175   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4176   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4177   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4178
4179   clutter_actor_queue_redraw (self);
4180 }
4181
4182 static inline void
4183 clutter_actor_set_anchor_coord (ClutterActor      *self,
4184                                 ClutterRotateAxis  axis,
4185                                 gfloat             coord)
4186 {
4187   GObject *obj = G_OBJECT (self);
4188   ClutterTransformInfo *info;
4189   gfloat anchor_x, anchor_y;
4190
4191   info = _clutter_actor_get_transform_info (self);
4192
4193   g_object_freeze_notify (obj);
4194
4195   clutter_anchor_coord_get_units (self, &info->anchor,
4196                                   &anchor_x,
4197                                   &anchor_y,
4198                                   NULL);
4199
4200   if (info->anchor.is_fractional)
4201     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4202
4203   switch (axis)
4204     {
4205     case CLUTTER_X_AXIS:
4206       clutter_anchor_coord_set_units (&info->anchor,
4207                                       coord,
4208                                       anchor_y,
4209                                       0.0);
4210       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4211       break;
4212
4213     case CLUTTER_Y_AXIS:
4214       clutter_anchor_coord_set_units (&info->anchor,
4215                                       anchor_x,
4216                                       coord,
4217                                       0.0);
4218       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4219       break;
4220
4221     default:
4222       g_assert_not_reached ();
4223     }
4224
4225   self->priv->transform_valid = FALSE;
4226
4227   clutter_actor_queue_redraw (self);
4228
4229   g_object_thaw_notify (obj);
4230 }
4231
4232 static void
4233 clutter_actor_set_property (GObject      *object,
4234                             guint         prop_id,
4235                             const GValue *value,
4236                             GParamSpec   *pspec)
4237 {
4238   ClutterActor *actor = CLUTTER_ACTOR (object);
4239   ClutterActorPrivate *priv = actor->priv;
4240
4241   switch (prop_id)
4242     {
4243     case PROP_X:
4244       clutter_actor_set_x (actor, g_value_get_float (value));
4245       break;
4246
4247     case PROP_Y:
4248       clutter_actor_set_y (actor, g_value_get_float (value));
4249       break;
4250
4251     case PROP_WIDTH:
4252       clutter_actor_set_width (actor, g_value_get_float (value));
4253       break;
4254
4255     case PROP_HEIGHT:
4256       clutter_actor_set_height (actor, g_value_get_float (value));
4257       break;
4258
4259     case PROP_FIXED_X:
4260       clutter_actor_set_x (actor, g_value_get_float (value));
4261       break;
4262
4263     case PROP_FIXED_Y:
4264       clutter_actor_set_y (actor, g_value_get_float (value));
4265       break;
4266
4267     case PROP_FIXED_POSITION_SET:
4268       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4269       break;
4270
4271     case PROP_MIN_WIDTH:
4272       clutter_actor_set_min_width (actor, g_value_get_float (value));
4273       break;
4274
4275     case PROP_MIN_HEIGHT:
4276       clutter_actor_set_min_height (actor, g_value_get_float (value));
4277       break;
4278
4279     case PROP_NATURAL_WIDTH:
4280       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4281       break;
4282
4283     case PROP_NATURAL_HEIGHT:
4284       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4285       break;
4286
4287     case PROP_MIN_WIDTH_SET:
4288       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4289       break;
4290
4291     case PROP_MIN_HEIGHT_SET:
4292       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4293       break;
4294
4295     case PROP_NATURAL_WIDTH_SET:
4296       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4297       break;
4298
4299     case PROP_NATURAL_HEIGHT_SET:
4300       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4301       break;
4302
4303     case PROP_REQUEST_MODE:
4304       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4305       break;
4306
4307     case PROP_DEPTH:
4308       clutter_actor_set_depth (actor, g_value_get_float (value));
4309       break;
4310
4311     case PROP_OPACITY:
4312       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4313       break;
4314
4315     case PROP_OFFSCREEN_REDIRECT:
4316       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4317       break;
4318
4319     case PROP_NAME:
4320       clutter_actor_set_name (actor, g_value_get_string (value));
4321       break;
4322
4323     case PROP_VISIBLE:
4324       if (g_value_get_boolean (value) == TRUE)
4325         clutter_actor_show (actor);
4326       else
4327         clutter_actor_hide (actor);
4328       break;
4329
4330     case PROP_SCALE_X:
4331       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4332                                       g_value_get_double (value));
4333       break;
4334
4335     case PROP_SCALE_Y:
4336       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4337                                       g_value_get_double (value));
4338       break;
4339
4340     case PROP_SCALE_CENTER_X:
4341       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4342                                       g_value_get_float (value));
4343       break;
4344
4345     case PROP_SCALE_CENTER_Y:
4346       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4347                                       g_value_get_float (value));
4348       break;
4349
4350     case PROP_SCALE_GRAVITY:
4351       clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4352       break;
4353
4354     case PROP_CLIP:
4355       {
4356         const ClutterGeometry *geom = g_value_get_boxed (value);
4357
4358         clutter_actor_set_clip (actor,
4359                                 geom->x, geom->y,
4360                                 geom->width, geom->height);
4361       }
4362       break;
4363
4364     case PROP_CLIP_TO_ALLOCATION:
4365       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4366       break;
4367
4368     case PROP_REACTIVE:
4369       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4370       break;
4371
4372     case PROP_ROTATION_ANGLE_X:
4373       clutter_actor_set_rotation_angle (actor,
4374                                         CLUTTER_X_AXIS,
4375                                         g_value_get_double (value));
4376       break;
4377
4378     case PROP_ROTATION_ANGLE_Y:
4379       clutter_actor_set_rotation_angle (actor,
4380                                         CLUTTER_Y_AXIS,
4381                                         g_value_get_double (value));
4382       break;
4383
4384     case PROP_ROTATION_ANGLE_Z:
4385       clutter_actor_set_rotation_angle (actor,
4386                                         CLUTTER_Z_AXIS,
4387                                         g_value_get_double (value));
4388       break;
4389
4390     case PROP_ROTATION_CENTER_X:
4391       clutter_actor_set_rotation_center_internal (actor,
4392                                                   CLUTTER_X_AXIS,
4393                                                   g_value_get_boxed (value));
4394       break;
4395
4396     case PROP_ROTATION_CENTER_Y:
4397       clutter_actor_set_rotation_center_internal (actor,
4398                                                   CLUTTER_Y_AXIS,
4399                                                   g_value_get_boxed (value));
4400       break;
4401
4402     case PROP_ROTATION_CENTER_Z:
4403       clutter_actor_set_rotation_center_internal (actor,
4404                                                   CLUTTER_Z_AXIS,
4405                                                   g_value_get_boxed (value));
4406       break;
4407
4408     case PROP_ROTATION_CENTER_Z_GRAVITY:
4409       {
4410         const ClutterTransformInfo *info;
4411
4412         info = _clutter_actor_get_transform_info_or_defaults (actor);
4413         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4414                                                    g_value_get_enum (value));
4415       }
4416       break;
4417
4418     case PROP_ANCHOR_X:
4419       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4420                                       g_value_get_float (value));
4421       break;
4422
4423     case PROP_ANCHOR_Y:
4424       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4425                                       g_value_get_float (value));
4426       break;
4427
4428     case PROP_ANCHOR_GRAVITY:
4429       clutter_actor_set_anchor_point_from_gravity (actor,
4430                                                    g_value_get_enum (value));
4431       break;
4432
4433     case PROP_SHOW_ON_SET_PARENT:
4434       priv->show_on_set_parent = g_value_get_boolean (value);
4435       break;
4436
4437     case PROP_TEXT_DIRECTION:
4438       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4439       break;
4440
4441     case PROP_ACTIONS:
4442       clutter_actor_add_action (actor, g_value_get_object (value));
4443       break;
4444
4445     case PROP_CONSTRAINTS:
4446       clutter_actor_add_constraint (actor, g_value_get_object (value));
4447       break;
4448
4449     case PROP_EFFECT:
4450       clutter_actor_add_effect (actor, g_value_get_object (value));
4451       break;
4452
4453     case PROP_LAYOUT_MANAGER:
4454       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4455       break;
4456
4457     case PROP_X_ALIGN:
4458       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4459       break;
4460
4461     case PROP_Y_ALIGN:
4462       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4463       break;
4464
4465     case PROP_MARGIN_TOP:
4466       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4467       break;
4468
4469     case PROP_MARGIN_BOTTOM:
4470       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4471       break;
4472
4473     case PROP_MARGIN_LEFT:
4474       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4475       break;
4476
4477     case PROP_MARGIN_RIGHT:
4478       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4479       break;
4480
4481     case PROP_BACKGROUND_COLOR:
4482       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4483       break;
4484
4485     case PROP_CONTENT:
4486       clutter_actor_set_content (actor, g_value_get_object (value));
4487       break;
4488
4489     case PROP_CONTENT_GRAVITY:
4490       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4491       break;
4492
4493     case PROP_MINIFICATION_FILTER:
4494       clutter_actor_set_content_scaling_filters (actor,
4495                                                  g_value_get_enum (value),
4496                                                  actor->priv->mag_filter);
4497       break;
4498
4499     case PROP_MAGNIFICATION_FILTER:
4500       clutter_actor_set_content_scaling_filters (actor,
4501                                                  actor->priv->min_filter,
4502                                                  g_value_get_enum (value));
4503       break;
4504
4505     default:
4506       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4507       break;
4508     }
4509 }
4510
4511 static void
4512 clutter_actor_get_property (GObject    *object,
4513                             guint       prop_id,
4514                             GValue     *value,
4515                             GParamSpec *pspec)
4516 {
4517   ClutterActor *actor = CLUTTER_ACTOR (object);
4518   ClutterActorPrivate *priv = actor->priv;
4519
4520   switch (prop_id)
4521     {
4522     case PROP_X:
4523       g_value_set_float (value, clutter_actor_get_x (actor));
4524       break;
4525
4526     case PROP_Y:
4527       g_value_set_float (value, clutter_actor_get_y (actor));
4528       break;
4529
4530     case PROP_WIDTH:
4531       g_value_set_float (value, clutter_actor_get_width (actor));
4532       break;
4533
4534     case PROP_HEIGHT:
4535       g_value_set_float (value, clutter_actor_get_height (actor));
4536       break;
4537
4538     case PROP_FIXED_X:
4539       {
4540         const ClutterLayoutInfo *info;
4541
4542         info = _clutter_actor_get_layout_info_or_defaults (actor);
4543         g_value_set_float (value, info->fixed_x);
4544       }
4545       break;
4546
4547     case PROP_FIXED_Y:
4548       {
4549         const ClutterLayoutInfo *info;
4550
4551         info = _clutter_actor_get_layout_info_or_defaults (actor);
4552         g_value_set_float (value, info->fixed_y);
4553       }
4554       break;
4555
4556     case PROP_FIXED_POSITION_SET:
4557       g_value_set_boolean (value, priv->position_set);
4558       break;
4559
4560     case PROP_MIN_WIDTH:
4561       {
4562         const ClutterLayoutInfo *info;
4563
4564         info = _clutter_actor_get_layout_info_or_defaults (actor);
4565         g_value_set_float (value, info->min_width);
4566       }
4567       break;
4568
4569     case PROP_MIN_HEIGHT:
4570       {
4571         const ClutterLayoutInfo *info;
4572
4573         info = _clutter_actor_get_layout_info_or_defaults (actor);
4574         g_value_set_float (value, info->min_height);
4575       }
4576       break;
4577
4578     case PROP_NATURAL_WIDTH:
4579       {
4580         const ClutterLayoutInfo *info;
4581
4582         info = _clutter_actor_get_layout_info_or_defaults (actor);
4583         g_value_set_float (value, info->natural_width);
4584       }
4585       break;
4586
4587     case PROP_NATURAL_HEIGHT:
4588       {
4589         const ClutterLayoutInfo *info;
4590
4591         info = _clutter_actor_get_layout_info_or_defaults (actor);
4592         g_value_set_float (value, info->natural_height);
4593       }
4594       break;
4595
4596     case PROP_MIN_WIDTH_SET:
4597       g_value_set_boolean (value, priv->min_width_set);
4598       break;
4599
4600     case PROP_MIN_HEIGHT_SET:
4601       g_value_set_boolean (value, priv->min_height_set);
4602       break;
4603
4604     case PROP_NATURAL_WIDTH_SET:
4605       g_value_set_boolean (value, priv->natural_width_set);
4606       break;
4607
4608     case PROP_NATURAL_HEIGHT_SET:
4609       g_value_set_boolean (value, priv->natural_height_set);
4610       break;
4611
4612     case PROP_REQUEST_MODE:
4613       g_value_set_enum (value, priv->request_mode);
4614       break;
4615
4616     case PROP_ALLOCATION:
4617       g_value_set_boxed (value, &priv->allocation);
4618       break;
4619
4620     case PROP_DEPTH:
4621       g_value_set_float (value, clutter_actor_get_depth (actor));
4622       break;
4623
4624     case PROP_OPACITY:
4625       g_value_set_uint (value, priv->opacity);
4626       break;
4627
4628     case PROP_OFFSCREEN_REDIRECT:
4629       g_value_set_enum (value, priv->offscreen_redirect);
4630       break;
4631
4632     case PROP_NAME:
4633       g_value_set_string (value, priv->name);
4634       break;
4635
4636     case PROP_VISIBLE:
4637       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4638       break;
4639
4640     case PROP_MAPPED:
4641       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4642       break;
4643
4644     case PROP_REALIZED:
4645       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4646       break;
4647
4648     case PROP_HAS_CLIP:
4649       g_value_set_boolean (value, priv->has_clip);
4650       break;
4651
4652     case PROP_CLIP:
4653       {
4654         ClutterGeometry clip;
4655
4656         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4657         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4658         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4659         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4660
4661         g_value_set_boxed (value, &clip);
4662       }
4663       break;
4664
4665     case PROP_CLIP_TO_ALLOCATION:
4666       g_value_set_boolean (value, priv->clip_to_allocation);
4667       break;
4668
4669     case PROP_SCALE_X:
4670       {
4671         const ClutterTransformInfo *info;
4672
4673         info = _clutter_actor_get_transform_info_or_defaults (actor);
4674         g_value_set_double (value, info->scale_x);
4675       }
4676       break;
4677
4678     case PROP_SCALE_Y:
4679       {
4680         const ClutterTransformInfo *info;
4681
4682         info = _clutter_actor_get_transform_info_or_defaults (actor);
4683         g_value_set_double (value, info->scale_y);
4684       }
4685       break;
4686
4687     case PROP_SCALE_CENTER_X:
4688       {
4689         gfloat center;
4690
4691         clutter_actor_get_scale_center (actor, &center, NULL);
4692
4693         g_value_set_float (value, center);
4694       }
4695       break;
4696
4697     case PROP_SCALE_CENTER_Y:
4698       {
4699         gfloat center;
4700
4701         clutter_actor_get_scale_center (actor, NULL, &center);
4702
4703         g_value_set_float (value, center);
4704       }
4705       break;
4706
4707     case PROP_SCALE_GRAVITY:
4708       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4709       break;
4710
4711     case PROP_REACTIVE:
4712       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4713       break;
4714
4715     case PROP_ROTATION_ANGLE_X:
4716       {
4717         const ClutterTransformInfo *info;
4718
4719         info = _clutter_actor_get_transform_info_or_defaults (actor);
4720         g_value_set_double (value, info->rx_angle);
4721       }
4722       break;
4723
4724     case PROP_ROTATION_ANGLE_Y:
4725       {
4726         const ClutterTransformInfo *info;
4727
4728         info = _clutter_actor_get_transform_info_or_defaults (actor);
4729         g_value_set_double (value, info->ry_angle);
4730       }
4731       break;
4732
4733     case PROP_ROTATION_ANGLE_Z:
4734       {
4735         const ClutterTransformInfo *info;
4736
4737         info = _clutter_actor_get_transform_info_or_defaults (actor);
4738         g_value_set_double (value, info->rz_angle);
4739       }
4740       break;
4741
4742     case PROP_ROTATION_CENTER_X:
4743       {
4744         ClutterVertex center;
4745
4746         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4747                                     &center.x,
4748                                     &center.y,
4749                                     &center.z);
4750
4751         g_value_set_boxed (value, &center);
4752       }
4753       break;
4754
4755     case PROP_ROTATION_CENTER_Y:
4756       {
4757         ClutterVertex center;
4758
4759         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4760                                     &center.x,
4761                                     &center.y,
4762                                     &center.z);
4763
4764         g_value_set_boxed (value, &center);
4765       }
4766       break;
4767
4768     case PROP_ROTATION_CENTER_Z:
4769       {
4770         ClutterVertex center;
4771
4772         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4773                                     &center.x,
4774                                     &center.y,
4775                                     &center.z);
4776
4777         g_value_set_boxed (value, &center);
4778       }
4779       break;
4780
4781     case PROP_ROTATION_CENTER_Z_GRAVITY:
4782       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4783       break;
4784
4785     case PROP_ANCHOR_X:
4786       {
4787         const ClutterTransformInfo *info;
4788         gfloat anchor_x;
4789
4790         info = _clutter_actor_get_transform_info_or_defaults (actor);
4791         clutter_anchor_coord_get_units (actor, &info->anchor,
4792                                         &anchor_x,
4793                                         NULL,
4794                                         NULL);
4795         g_value_set_float (value, anchor_x);
4796       }
4797       break;
4798
4799     case PROP_ANCHOR_Y:
4800       {
4801         const ClutterTransformInfo *info;
4802         gfloat anchor_y;
4803
4804         info = _clutter_actor_get_transform_info_or_defaults (actor);
4805         clutter_anchor_coord_get_units (actor, &info->anchor,
4806                                         NULL,
4807                                         &anchor_y,
4808                                         NULL);
4809         g_value_set_float (value, anchor_y);
4810       }
4811       break;
4812
4813     case PROP_ANCHOR_GRAVITY:
4814       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4815       break;
4816
4817     case PROP_SHOW_ON_SET_PARENT:
4818       g_value_set_boolean (value, priv->show_on_set_parent);
4819       break;
4820
4821     case PROP_TEXT_DIRECTION:
4822       g_value_set_enum (value, priv->text_direction);
4823       break;
4824
4825     case PROP_HAS_POINTER:
4826       g_value_set_boolean (value, priv->has_pointer);
4827       break;
4828
4829     case PROP_LAYOUT_MANAGER:
4830       g_value_set_object (value, priv->layout_manager);
4831       break;
4832
4833     case PROP_X_ALIGN:
4834       {
4835         const ClutterLayoutInfo *info;
4836
4837         info = _clutter_actor_get_layout_info_or_defaults (actor);
4838         g_value_set_enum (value, info->x_align);
4839       }
4840       break;
4841
4842     case PROP_Y_ALIGN:
4843       {
4844         const ClutterLayoutInfo *info;
4845
4846         info = _clutter_actor_get_layout_info_or_defaults (actor);
4847         g_value_set_enum (value, info->y_align);
4848       }
4849       break;
4850
4851     case PROP_MARGIN_TOP:
4852       {
4853         const ClutterLayoutInfo *info;
4854
4855         info = _clutter_actor_get_layout_info_or_defaults (actor);
4856         g_value_set_float (value, info->margin.top);
4857       }
4858       break;
4859
4860     case PROP_MARGIN_BOTTOM:
4861       {
4862         const ClutterLayoutInfo *info;
4863
4864         info = _clutter_actor_get_layout_info_or_defaults (actor);
4865         g_value_set_float (value, info->margin.bottom);
4866       }
4867       break;
4868
4869     case PROP_MARGIN_LEFT:
4870       {
4871         const ClutterLayoutInfo *info;
4872
4873         info = _clutter_actor_get_layout_info_or_defaults (actor);
4874         g_value_set_float (value, info->margin.left);
4875       }
4876       break;
4877
4878     case PROP_MARGIN_RIGHT:
4879       {
4880         const ClutterLayoutInfo *info;
4881
4882         info = _clutter_actor_get_layout_info_or_defaults (actor);
4883         g_value_set_float (value, info->margin.right);
4884       }
4885       break;
4886
4887     case PROP_BACKGROUND_COLOR_SET:
4888       g_value_set_boolean (value, priv->bg_color_set);
4889       break;
4890
4891     case PROP_BACKGROUND_COLOR:
4892       g_value_set_boxed (value, &priv->bg_color);
4893       break;
4894
4895     case PROP_FIRST_CHILD:
4896       g_value_set_object (value, priv->first_child);
4897       break;
4898
4899     case PROP_LAST_CHILD:
4900       g_value_set_object (value, priv->last_child);
4901       break;
4902
4903     case PROP_CONTENT:
4904       g_value_set_object (value, priv->content);
4905       break;
4906
4907     case PROP_CONTENT_GRAVITY:
4908       g_value_set_enum (value, priv->content_gravity);
4909       break;
4910
4911     case PROP_CONTENT_BOX:
4912       {
4913         ClutterActorBox box = { 0, };
4914
4915         clutter_actor_get_content_box (actor, &box);
4916         g_value_set_boxed (value, &box);
4917       }
4918       break;
4919
4920     case PROP_MINIFICATION_FILTER:
4921       g_value_set_enum (value, priv->min_filter);
4922       break;
4923
4924     case PROP_MAGNIFICATION_FILTER:
4925       g_value_set_enum (value, priv->mag_filter);
4926       break;
4927
4928     default:
4929       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4930       break;
4931     }
4932 }
4933
4934 static void
4935 clutter_actor_dispose (GObject *object)
4936 {
4937   ClutterActor *self = CLUTTER_ACTOR (object);
4938   ClutterActorPrivate *priv = self->priv;
4939
4940   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4941                 priv->id,
4942                 g_type_name (G_OBJECT_TYPE (self)),
4943                 object->ref_count);
4944
4945   g_signal_emit (self, actor_signals[DESTROY], 0);
4946
4947   /* avoid recursing when called from clutter_actor_destroy() */
4948   if (priv->parent != NULL)
4949     {
4950       ClutterActor *parent = priv->parent;
4951
4952       /* go through the Container implementation unless this
4953        * is an internal child and has been marked as such.
4954        *
4955        * removing the actor from its parent will reset the
4956        * realized and mapped states.
4957        */
4958       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4959         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4960       else
4961         clutter_actor_remove_child_internal (parent, self,
4962                                              REMOVE_CHILD_LEGACY_FLAGS);
4963     }
4964
4965   /* parent must be gone at this point */
4966   g_assert (priv->parent == NULL);
4967
4968   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4969     {
4970       /* can't be mapped or realized with no parent */
4971       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4972       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4973     }
4974
4975   g_clear_object (&priv->pango_context);
4976   g_clear_object (&priv->actions);
4977   g_clear_object (&priv->constraints);
4978   g_clear_object (&priv->effects);
4979   g_clear_object (&priv->flatten_effect);
4980
4981   if (priv->layout_manager != NULL)
4982     {
4983       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4984       g_clear_object (&priv->layout_manager);
4985     }
4986
4987   if (priv->content != NULL)
4988     {
4989       _clutter_content_detached (priv->content, self);
4990       g_clear_object (&priv->content);
4991     }
4992
4993   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4994 }
4995
4996 static void
4997 clutter_actor_finalize (GObject *object)
4998 {
4999   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5000
5001   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5002                 priv->name != NULL ? priv->name : "<none>",
5003                 priv->id,
5004                 g_type_name (G_OBJECT_TYPE (object)));
5005
5006   _clutter_context_release_id (priv->id);
5007
5008   g_free (priv->name);
5009
5010   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5011 }
5012
5013
5014 /**
5015  * clutter_actor_get_accessible:
5016  * @self: a #ClutterActor
5017  *
5018  * Returns the accessible object that describes the actor to an
5019  * assistive technology.
5020  *
5021  * If no class-specific #AtkObject implementation is available for the
5022  * actor instance in question, it will inherit an #AtkObject
5023  * implementation from the first ancestor class for which such an
5024  * implementation is defined.
5025  *
5026  * The documentation of the <ulink
5027  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5028  * library contains more information about accessible objects and
5029  * their uses.
5030  *
5031  * Returns: (transfer none): the #AtkObject associated with @actor
5032  */
5033 AtkObject *
5034 clutter_actor_get_accessible (ClutterActor *self)
5035 {
5036   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5037
5038   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5039 }
5040
5041 static AtkObject *
5042 clutter_actor_real_get_accessible (ClutterActor *actor)
5043 {
5044   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5045 }
5046
5047 static AtkObject *
5048 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5049 {
5050   AtkObject *accessible;
5051
5052   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5053   if (accessible != NULL)
5054     g_object_ref (accessible);
5055
5056   return accessible;
5057 }
5058
5059 static void
5060 atk_implementor_iface_init (AtkImplementorIface *iface)
5061 {
5062   iface->ref_accessible = _clutter_actor_ref_accessible;
5063 }
5064
5065 static gboolean
5066 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5067                                            ClutterPaintVolume *volume)
5068 {
5069   ClutterActorPrivate *priv = self->priv;
5070   gboolean res = FALSE;
5071
5072   /* we start from the allocation */
5073   clutter_paint_volume_set_width (volume,
5074                                   priv->allocation.x2 - priv->allocation.x1);
5075   clutter_paint_volume_set_height (volume,
5076                                    priv->allocation.y2 - priv->allocation.y1);
5077
5078   /* if the actor has a clip set then we have a pretty definite
5079    * size for the paint volume: the actor cannot possibly paint
5080    * outside the clip region.
5081    */
5082   if (priv->clip_to_allocation)
5083     {
5084       /* the allocation has already been set, so we just flip the
5085        * return value
5086        */
5087       res = TRUE;
5088     }
5089   else
5090     {
5091       ClutterActor *child;
5092
5093       if (priv->has_clip &&
5094           priv->clip.width >= 0 &&
5095           priv->clip.height >= 0)
5096         {
5097           ClutterVertex origin;
5098
5099           origin.x = priv->clip.x;
5100           origin.y = priv->clip.y;
5101           origin.z = 0;
5102
5103           clutter_paint_volume_set_origin (volume, &origin);
5104           clutter_paint_volume_set_width (volume, priv->clip.width);
5105           clutter_paint_volume_set_height (volume, priv->clip.height);
5106
5107           res = TRUE;
5108         }
5109
5110       /* if we don't have children we just bail out here... */
5111       if (priv->n_children == 0)
5112         return res;
5113
5114       /* ...but if we have children then we ask for their paint volume in
5115        * our coordinates. if any of our children replies that it doesn't
5116        * have a paint volume, we bail out
5117        */
5118       for (child = priv->first_child;
5119            child != NULL;
5120            child = child->priv->next_sibling)
5121         {
5122           const ClutterPaintVolume *child_volume;
5123
5124           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5125           if (child_volume == NULL)
5126             {
5127               res = FALSE;
5128               break;
5129             }
5130
5131           clutter_paint_volume_union (volume, child_volume);
5132           res = TRUE;
5133         }
5134     }
5135
5136   return res;
5137
5138 }
5139
5140 static gboolean
5141 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5142                                      ClutterPaintVolume *volume)
5143 {
5144   ClutterActorClass *klass;
5145   gboolean res;
5146
5147   klass = CLUTTER_ACTOR_GET_CLASS (self);
5148
5149   /* XXX - this thoroughly sucks, but we don't want to penalize users
5150    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5151    * redraw. This should go away in 2.0.
5152    */
5153   if (klass->paint == clutter_actor_real_paint &&
5154       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5155     {
5156       res = TRUE;
5157     }
5158   else
5159     {
5160       /* this is the default return value: we cannot know if a class
5161        * is going to paint outside its allocation, so we take the
5162        * conservative approach.
5163        */
5164       res = FALSE;
5165     }
5166
5167   if (clutter_actor_update_default_paint_volume (self, volume))
5168     return res;
5169
5170   return FALSE;
5171 }
5172
5173 /**
5174  * clutter_actor_get_default_paint_volume:
5175  * @self: a #ClutterActor
5176  *
5177  * Retrieves the default paint volume for @self.
5178  *
5179  * This function provides the same #ClutterPaintVolume that would be
5180  * computed by the default implementation inside #ClutterActor of the
5181  * #ClutterActorClass.get_paint_volume() virtual function.
5182  *
5183  * This function should only be used by #ClutterActor subclasses that
5184  * cannot chain up to the parent implementation when computing their
5185  * paint volume.
5186  *
5187  * Return value: (transfer none): a pointer to the default
5188  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5189  *   the actor could not compute a valid paint volume. The returned value
5190  *   is not guaranteed to be stable across multiple frames, so if you
5191  *   want to retain it, you will need to copy it using
5192  *   clutter_paint_volume_copy().
5193  *
5194  * Since: 1.10
5195  */
5196 const ClutterPaintVolume *
5197 clutter_actor_get_default_paint_volume (ClutterActor *self)
5198 {
5199   ClutterPaintVolume volume;
5200   ClutterPaintVolume *res;
5201
5202   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5203
5204   res = NULL;
5205   _clutter_paint_volume_init_static (&volume, self);
5206   if (clutter_actor_update_default_paint_volume (self, &volume))
5207     {
5208       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5209
5210       if (stage != NULL)
5211         {
5212           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5213           _clutter_paint_volume_copy_static (&volume, res);
5214         }
5215     }
5216
5217   clutter_paint_volume_free (&volume);
5218
5219   return res;
5220 }
5221
5222 static gboolean
5223 clutter_actor_real_has_overlaps (ClutterActor *self)
5224 {
5225   /* By default we'll assume that all actors need an offscreen redirect to get
5226    * the correct opacity. Actors such as ClutterTexture that would never need
5227    * an offscreen redirect can override this to return FALSE. */
5228   return TRUE;
5229 }
5230
5231 static void
5232 clutter_actor_real_destroy (ClutterActor *actor)
5233 {
5234   ClutterActorIter iter;
5235
5236   clutter_actor_iter_init (&iter, actor);
5237   while (clutter_actor_iter_next (&iter, NULL))
5238     clutter_actor_iter_destroy (&iter);
5239 }
5240
5241 static GObject *
5242 clutter_actor_constructor (GType gtype,
5243                            guint n_props,
5244                            GObjectConstructParam *props)
5245 {
5246   GObjectClass *gobject_class;
5247   ClutterActor *self;
5248   GObject *retval;
5249
5250   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5251   retval = gobject_class->constructor (gtype, n_props, props);
5252   self = CLUTTER_ACTOR (retval);
5253
5254   if (self->priv->layout_manager == NULL)
5255     {
5256       ClutterLayoutManager *default_layout;
5257
5258       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5259
5260       default_layout = clutter_fixed_layout_new ();
5261       clutter_actor_set_layout_manager (self, default_layout);
5262     }
5263
5264   return retval;
5265 }
5266
5267 static void
5268 clutter_actor_class_init (ClutterActorClass *klass)
5269 {
5270   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5271
5272   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5273   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5274   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5275   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5276
5277   object_class->constructor = clutter_actor_constructor;
5278   object_class->set_property = clutter_actor_set_property;
5279   object_class->get_property = clutter_actor_get_property;
5280   object_class->dispose = clutter_actor_dispose;
5281   object_class->finalize = clutter_actor_finalize;
5282
5283   klass->show = clutter_actor_real_show;
5284   klass->show_all = clutter_actor_show;
5285   klass->hide = clutter_actor_real_hide;
5286   klass->hide_all = clutter_actor_hide;
5287   klass->map = clutter_actor_real_map;
5288   klass->unmap = clutter_actor_real_unmap;
5289   klass->unrealize = clutter_actor_real_unrealize;
5290   klass->pick = clutter_actor_real_pick;
5291   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5292   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5293   klass->allocate = clutter_actor_real_allocate;
5294   klass->queue_redraw = clutter_actor_real_queue_redraw;
5295   klass->queue_relayout = clutter_actor_real_queue_relayout;
5296   klass->apply_transform = clutter_actor_real_apply_transform;
5297   klass->get_accessible = clutter_actor_real_get_accessible;
5298   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5299   klass->has_overlaps = clutter_actor_real_has_overlaps;
5300   klass->paint = clutter_actor_real_paint;
5301   klass->destroy = clutter_actor_real_destroy;
5302
5303   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5304
5305   /**
5306    * ClutterActor:x:
5307    *
5308    * X coordinate of the actor in pixels. If written, forces a fixed
5309    * position for the actor. If read, returns the fixed position if any,
5310    * otherwise the allocation if available, otherwise 0.
5311    *
5312    * The #ClutterActor:x property is animatable.
5313    */
5314   obj_props[PROP_X] =
5315     g_param_spec_float ("x",
5316                         P_("X coordinate"),
5317                         P_("X coordinate of the actor"),
5318                         -G_MAXFLOAT, G_MAXFLOAT,
5319                         0.0,
5320                         G_PARAM_READWRITE |
5321                         G_PARAM_STATIC_STRINGS |
5322                         CLUTTER_PARAM_ANIMATABLE);
5323
5324   /**
5325    * ClutterActor:y:
5326    *
5327    * Y coordinate of the actor in pixels. If written, forces a fixed
5328    * position for the actor.  If read, returns the fixed position if
5329    * any, otherwise the allocation if available, otherwise 0.
5330    *
5331    * The #ClutterActor:y property is animatable.
5332    */
5333   obj_props[PROP_Y] =
5334     g_param_spec_float ("y",
5335                         P_("Y coordinate"),
5336                         P_("Y coordinate of the actor"),
5337                         -G_MAXFLOAT, G_MAXFLOAT,
5338                         0.0,
5339                         G_PARAM_READWRITE |
5340                         G_PARAM_STATIC_STRINGS |
5341                         CLUTTER_PARAM_ANIMATABLE);
5342
5343   /**
5344    * ClutterActor:width:
5345    *
5346    * Width of the actor (in pixels). If written, forces the minimum and
5347    * natural size request of the actor to the given width. If read, returns
5348    * the allocated width if available, otherwise the width request.
5349    *
5350    * The #ClutterActor:width property is animatable.
5351    */
5352   obj_props[PROP_WIDTH] =
5353     g_param_spec_float ("width",
5354                         P_("Width"),
5355                         P_("Width of the actor"),
5356                         0.0, G_MAXFLOAT,
5357                         0.0,
5358                         G_PARAM_READWRITE |
5359                         G_PARAM_STATIC_STRINGS |
5360                         CLUTTER_PARAM_ANIMATABLE);
5361
5362   /**
5363    * ClutterActor:height:
5364    *
5365    * Height of the actor (in pixels).  If written, forces the minimum and
5366    * natural size request of the actor to the given height. If read, returns
5367    * the allocated height if available, otherwise the height request.
5368    *
5369    * The #ClutterActor:height property is animatable.
5370    */
5371   obj_props[PROP_HEIGHT] =
5372     g_param_spec_float ("height",
5373                         P_("Height"),
5374                         P_("Height of the actor"),
5375                         0.0, G_MAXFLOAT,
5376                         0.0,
5377                         G_PARAM_READWRITE |
5378                         G_PARAM_STATIC_STRINGS |
5379                         CLUTTER_PARAM_ANIMATABLE);
5380
5381   /**
5382    * ClutterActor:fixed-x:
5383    *
5384    * The fixed X position of the actor in pixels.
5385    *
5386    * Writing this property sets #ClutterActor:fixed-position-set
5387    * property as well, as a side effect
5388    *
5389    * Since: 0.8
5390    */
5391   obj_props[PROP_FIXED_X] =
5392     g_param_spec_float ("fixed-x",
5393                         P_("Fixed X"),
5394                         P_("Forced X position of the actor"),
5395                         -G_MAXFLOAT, G_MAXFLOAT,
5396                         0.0,
5397                         CLUTTER_PARAM_READWRITE);
5398
5399   /**
5400    * ClutterActor:fixed-y:
5401    *
5402    * The fixed Y position of the actor in pixels.
5403    *
5404    * Writing this property sets the #ClutterActor:fixed-position-set
5405    * property as well, as a side effect
5406    *
5407    * Since: 0.8
5408    */
5409   obj_props[PROP_FIXED_Y] =
5410     g_param_spec_float ("fixed-y",
5411                         P_("Fixed Y"),
5412                         P_("Forced Y position of the actor"),
5413                         -G_MAXFLOAT, G_MAXFLOAT,
5414                         0,
5415                         CLUTTER_PARAM_READWRITE);
5416
5417   /**
5418    * ClutterActor:fixed-position-set:
5419    *
5420    * This flag controls whether the #ClutterActor:fixed-x and
5421    * #ClutterActor:fixed-y properties are used
5422    *
5423    * Since: 0.8
5424    */
5425   obj_props[PROP_FIXED_POSITION_SET] =
5426     g_param_spec_boolean ("fixed-position-set",
5427                           P_("Fixed position set"),
5428                           P_("Whether to use fixed positioning for the actor"),
5429                           FALSE,
5430                           CLUTTER_PARAM_READWRITE);
5431
5432   /**
5433    * ClutterActor:min-width:
5434    *
5435    * A forced minimum width request for the actor, in pixels
5436    *
5437    * Writing this property sets the #ClutterActor:min-width-set property
5438    * as well, as a side effect.
5439    *
5440    *This property overrides the usual width request of the actor.
5441    *
5442    * Since: 0.8
5443    */
5444   obj_props[PROP_MIN_WIDTH] =
5445     g_param_spec_float ("min-width",
5446                         P_("Min Width"),
5447                         P_("Forced minimum width request for the actor"),
5448                         0.0, G_MAXFLOAT,
5449                         0.0,
5450                         CLUTTER_PARAM_READWRITE);
5451
5452   /**
5453    * ClutterActor:min-height:
5454    *
5455    * A forced minimum height request for the actor, in pixels
5456    *
5457    * Writing this property sets the #ClutterActor:min-height-set property
5458    * as well, as a side effect. This property overrides the usual height
5459    * request of the actor.
5460    *
5461    * Since: 0.8
5462    */
5463   obj_props[PROP_MIN_HEIGHT] =
5464     g_param_spec_float ("min-height",
5465                         P_("Min Height"),
5466                         P_("Forced minimum height request for the actor"),
5467                         0.0, G_MAXFLOAT,
5468                         0.0,
5469                         CLUTTER_PARAM_READWRITE);
5470
5471   /**
5472    * ClutterActor:natural-width:
5473    *
5474    * A forced natural width request for the actor, in pixels
5475    *
5476    * Writing this property sets the #ClutterActor:natural-width-set
5477    * property as well, as a side effect. This property overrides the
5478    * usual width request of the actor
5479    *
5480    * Since: 0.8
5481    */
5482   obj_props[PROP_NATURAL_WIDTH] =
5483     g_param_spec_float ("natural-width",
5484                         P_("Natural Width"),
5485                         P_("Forced natural width request for the actor"),
5486                         0.0, G_MAXFLOAT,
5487                         0.0,
5488                         CLUTTER_PARAM_READWRITE);
5489
5490   /**
5491    * ClutterActor:natural-height:
5492    *
5493    * A forced natural height request for the actor, in pixels
5494    *
5495    * Writing this property sets the #ClutterActor:natural-height-set
5496    * property as well, as a side effect. This property overrides the
5497    * usual height request of the actor
5498    *
5499    * Since: 0.8
5500    */
5501   obj_props[PROP_NATURAL_HEIGHT] =
5502     g_param_spec_float ("natural-height",
5503                         P_("Natural Height"),
5504                         P_("Forced natural height request for the actor"),
5505                         0.0, G_MAXFLOAT,
5506                         0.0,
5507                         CLUTTER_PARAM_READWRITE);
5508
5509   /**
5510    * ClutterActor:min-width-set:
5511    *
5512    * This flag controls whether the #ClutterActor:min-width property
5513    * is used
5514    *
5515    * Since: 0.8
5516    */
5517   obj_props[PROP_MIN_WIDTH_SET] =
5518     g_param_spec_boolean ("min-width-set",
5519                           P_("Minimum width set"),
5520                           P_("Whether to use the min-width property"),
5521                           FALSE,
5522                           CLUTTER_PARAM_READWRITE);
5523
5524   /**
5525    * ClutterActor:min-height-set:
5526    *
5527    * This flag controls whether the #ClutterActor:min-height property
5528    * is used
5529    *
5530    * Since: 0.8
5531    */
5532   obj_props[PROP_MIN_HEIGHT_SET] =
5533     g_param_spec_boolean ("min-height-set",
5534                           P_("Minimum height set"),
5535                           P_("Whether to use the min-height property"),
5536                           FALSE,
5537                           CLUTTER_PARAM_READWRITE);
5538
5539   /**
5540    * ClutterActor:natural-width-set:
5541    *
5542    * This flag controls whether the #ClutterActor:natural-width property
5543    * is used
5544    *
5545    * Since: 0.8
5546    */
5547   obj_props[PROP_NATURAL_WIDTH_SET] =
5548     g_param_spec_boolean ("natural-width-set",
5549                           P_("Natural width set"),
5550                           P_("Whether to use the natural-width property"),
5551                           FALSE,
5552                           CLUTTER_PARAM_READWRITE);
5553
5554   /**
5555    * ClutterActor:natural-height-set:
5556    *
5557    * This flag controls whether the #ClutterActor:natural-height property
5558    * is used
5559    *
5560    * Since: 0.8
5561    */
5562   obj_props[PROP_NATURAL_HEIGHT_SET] =
5563     g_param_spec_boolean ("natural-height-set",
5564                           P_("Natural height set"),
5565                           P_("Whether to use the natural-height property"),
5566                           FALSE,
5567                           CLUTTER_PARAM_READWRITE);
5568
5569   /**
5570    * ClutterActor:allocation:
5571    *
5572    * The allocation for the actor, in pixels
5573    *
5574    * This is property is read-only, but you might monitor it to know when an
5575    * actor moves or resizes
5576    *
5577    * Since: 0.8
5578    */
5579   obj_props[PROP_ALLOCATION] =
5580     g_param_spec_boxed ("allocation",
5581                         P_("Allocation"),
5582                         P_("The actor's allocation"),
5583                         CLUTTER_TYPE_ACTOR_BOX,
5584                         CLUTTER_PARAM_READABLE);
5585
5586   /**
5587    * ClutterActor:request-mode:
5588    *
5589    * Request mode for the #ClutterActor. The request mode determines the
5590    * type of geometry management used by the actor, either height for width
5591    * (the default) or width for height.
5592    *
5593    * For actors implementing height for width, the parent container should get
5594    * the preferred width first, and then the preferred height for that width.
5595    *
5596    * For actors implementing width for height, the parent container should get
5597    * the preferred height first, and then the preferred width for that height.
5598    *
5599    * For instance:
5600    *
5601    * |[
5602    *   ClutterRequestMode mode;
5603    *   gfloat natural_width, min_width;
5604    *   gfloat natural_height, min_height;
5605    *
5606    *   mode = clutter_actor_get_request_mode (child);
5607    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5608    *     {
5609    *       clutter_actor_get_preferred_width (child, -1,
5610    *                                          &amp;min_width,
5611    *                                          &amp;natural_width);
5612    *       clutter_actor_get_preferred_height (child, natural_width,
5613    *                                           &amp;min_height,
5614    *                                           &amp;natural_height);
5615    *     }
5616    *   else
5617    *     {
5618    *       clutter_actor_get_preferred_height (child, -1,
5619    *                                           &amp;min_height,
5620    *                                           &amp;natural_height);
5621    *       clutter_actor_get_preferred_width (child, natural_height,
5622    *                                          &amp;min_width,
5623    *                                          &amp;natural_width);
5624    *     }
5625    * ]|
5626    *
5627    * will retrieve the minimum and natural width and height depending on the
5628    * preferred request mode of the #ClutterActor "child".
5629    *
5630    * The clutter_actor_get_preferred_size() function will implement this
5631    * check for you.
5632    *
5633    * Since: 0.8
5634    */
5635   obj_props[PROP_REQUEST_MODE] =
5636     g_param_spec_enum ("request-mode",
5637                        P_("Request Mode"),
5638                        P_("The actor's request mode"),
5639                        CLUTTER_TYPE_REQUEST_MODE,
5640                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5641                        CLUTTER_PARAM_READWRITE);
5642
5643   /**
5644    * ClutterActor:depth:
5645    *
5646    * The position of the actor on the Z axis.
5647    *
5648    * The #ClutterActor:depth property is relative to the parent's
5649    * modelview matrix.
5650    *
5651    * The #ClutterActor:depth property is animatable.
5652    *
5653    * Since: 0.6
5654    */
5655   obj_props[PROP_DEPTH] =
5656     g_param_spec_float ("depth",
5657                         P_("Depth"),
5658                         P_("Position on the Z axis"),
5659                         -G_MAXFLOAT, G_MAXFLOAT,
5660                         0.0,
5661                         G_PARAM_READWRITE |
5662                         G_PARAM_STATIC_STRINGS |
5663                         CLUTTER_PARAM_ANIMATABLE);
5664
5665   /**
5666    * ClutterActor:opacity:
5667    *
5668    * Opacity of an actor, between 0 (fully transparent) and
5669    * 255 (fully opaque)
5670    *
5671    * The #ClutterActor:opacity property is animatable.
5672    */
5673   obj_props[PROP_OPACITY] =
5674     g_param_spec_uint ("opacity",
5675                        P_("Opacity"),
5676                        P_("Opacity of an actor"),
5677                        0, 255,
5678                        255,
5679                        G_PARAM_READWRITE |
5680                        G_PARAM_STATIC_STRINGS |
5681                        CLUTTER_PARAM_ANIMATABLE);
5682
5683   /**
5684    * ClutterActor:offscreen-redirect:
5685    *
5686    * Determines the conditions in which the actor will be redirected
5687    * to an offscreen framebuffer while being painted. For example this
5688    * can be used to cache an actor in a framebuffer or for improved
5689    * handling of transparent actors. See
5690    * clutter_actor_set_offscreen_redirect() for details.
5691    *
5692    * Since: 1.8
5693    */
5694   obj_props[PROP_OFFSCREEN_REDIRECT] =
5695     g_param_spec_flags ("offscreen-redirect",
5696                         P_("Offscreen redirect"),
5697                         P_("Flags controlling when to flatten the actor into a single image"),
5698                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5699                         0,
5700                         CLUTTER_PARAM_READWRITE);
5701
5702   /**
5703    * ClutterActor:visible:
5704    *
5705    * Whether the actor is set to be visible or not
5706    *
5707    * See also #ClutterActor:mapped
5708    */
5709   obj_props[PROP_VISIBLE] =
5710     g_param_spec_boolean ("visible",
5711                           P_("Visible"),
5712                           P_("Whether the actor is visible or not"),
5713                           FALSE,
5714                           CLUTTER_PARAM_READWRITE);
5715
5716   /**
5717    * ClutterActor:mapped:
5718    *
5719    * Whether the actor is mapped (will be painted when the stage
5720    * to which it belongs is mapped)
5721    *
5722    * Since: 1.0
5723    */
5724   obj_props[PROP_MAPPED] =
5725     g_param_spec_boolean ("mapped",
5726                           P_("Mapped"),
5727                           P_("Whether the actor will be painted"),
5728                           FALSE,
5729                           CLUTTER_PARAM_READABLE);
5730
5731   /**
5732    * ClutterActor:realized:
5733    *
5734    * Whether the actor has been realized
5735    *
5736    * Since: 1.0
5737    */
5738   obj_props[PROP_REALIZED] =
5739     g_param_spec_boolean ("realized",
5740                           P_("Realized"),
5741                           P_("Whether the actor has been realized"),
5742                           FALSE,
5743                           CLUTTER_PARAM_READABLE);
5744
5745   /**
5746    * ClutterActor:reactive:
5747    *
5748    * Whether the actor is reactive to events or not
5749    *
5750    * Only reactive actors will emit event-related signals
5751    *
5752    * Since: 0.6
5753    */
5754   obj_props[PROP_REACTIVE] =
5755     g_param_spec_boolean ("reactive",
5756                           P_("Reactive"),
5757                           P_("Whether the actor is reactive to events"),
5758                           FALSE,
5759                           CLUTTER_PARAM_READWRITE);
5760
5761   /**
5762    * ClutterActor:has-clip:
5763    *
5764    * Whether the actor has the #ClutterActor:clip property set or not
5765    */
5766   obj_props[PROP_HAS_CLIP] =
5767     g_param_spec_boolean ("has-clip",
5768                           P_("Has Clip"),
5769                           P_("Whether the actor has a clip set"),
5770                           FALSE,
5771                           CLUTTER_PARAM_READABLE);
5772
5773   /**
5774    * ClutterActor:clip:
5775    *
5776    * The clip region for the actor, in actor-relative coordinates
5777    *
5778    * Every part of the actor outside the clip region will not be
5779    * painted
5780    */
5781   obj_props[PROP_CLIP] =
5782     g_param_spec_boxed ("clip",
5783                         P_("Clip"),
5784                         P_("The clip region for the actor"),
5785                         CLUTTER_TYPE_GEOMETRY,
5786                         CLUTTER_PARAM_READWRITE);
5787
5788   /**
5789    * ClutterActor:name:
5790    *
5791    * The name of the actor
5792    *
5793    * Since: 0.2
5794    */
5795   obj_props[PROP_NAME] =
5796     g_param_spec_string ("name",
5797                          P_("Name"),
5798                          P_("Name of the actor"),
5799                          NULL,
5800                          CLUTTER_PARAM_READWRITE);
5801
5802   /**
5803    * ClutterActor:scale-x:
5804    *
5805    * The horizontal scale of the actor.
5806    *
5807    * The #ClutterActor:scale-x property is animatable.
5808    *
5809    * Since: 0.6
5810    */
5811   obj_props[PROP_SCALE_X] =
5812     g_param_spec_double ("scale-x",
5813                          P_("Scale X"),
5814                          P_("Scale factor on the X axis"),
5815                          0.0, G_MAXDOUBLE,
5816                          1.0,
5817                          G_PARAM_READWRITE |
5818                          G_PARAM_STATIC_STRINGS |
5819                          CLUTTER_PARAM_ANIMATABLE);
5820
5821   /**
5822    * ClutterActor:scale-y:
5823    *
5824    * The vertical scale of the actor.
5825    *
5826    * The #ClutterActor:scale-y property is animatable.
5827    *
5828    * Since: 0.6
5829    */
5830   obj_props[PROP_SCALE_Y] =
5831     g_param_spec_double ("scale-y",
5832                          P_("Scale Y"),
5833                          P_("Scale factor on the Y axis"),
5834                          0.0, G_MAXDOUBLE,
5835                          1.0,
5836                          G_PARAM_READWRITE |
5837                          G_PARAM_STATIC_STRINGS |
5838                          CLUTTER_PARAM_ANIMATABLE);
5839
5840   /**
5841    * ClutterActor:scale-center-x:
5842    *
5843    * The horizontal center point for scaling
5844    *
5845    * Since: 1.0
5846    */
5847   obj_props[PROP_SCALE_CENTER_X] =
5848     g_param_spec_float ("scale-center-x",
5849                         P_("Scale Center X"),
5850                         P_("Horizontal scale center"),
5851                         -G_MAXFLOAT, G_MAXFLOAT,
5852                         0.0,
5853                         CLUTTER_PARAM_READWRITE);
5854
5855   /**
5856    * ClutterActor:scale-center-y:
5857    *
5858    * The vertical center point for scaling
5859    *
5860    * Since: 1.0
5861    */
5862   obj_props[PROP_SCALE_CENTER_Y] =
5863     g_param_spec_float ("scale-center-y",
5864                         P_("Scale Center Y"),
5865                         P_("Vertical scale center"),
5866                         -G_MAXFLOAT, G_MAXFLOAT,
5867                         0.0,
5868                         CLUTTER_PARAM_READWRITE);
5869
5870   /**
5871    * ClutterActor:scale-gravity:
5872    *
5873    * The center point for scaling expressed as a #ClutterGravity
5874    *
5875    * Since: 1.0
5876    */
5877   obj_props[PROP_SCALE_GRAVITY] =
5878     g_param_spec_enum ("scale-gravity",
5879                        P_("Scale Gravity"),
5880                        P_("The center of scaling"),
5881                        CLUTTER_TYPE_GRAVITY,
5882                        CLUTTER_GRAVITY_NONE,
5883                        CLUTTER_PARAM_READWRITE);
5884
5885   /**
5886    * ClutterActor:rotation-angle-x:
5887    *
5888    * The rotation angle on the X axis.
5889    *
5890    * The #ClutterActor:rotation-angle-x property is animatable.
5891    *
5892    * Since: 0.6
5893    */
5894   obj_props[PROP_ROTATION_ANGLE_X] =
5895     g_param_spec_double ("rotation-angle-x",
5896                          P_("Rotation Angle X"),
5897                          P_("The rotation angle on the X axis"),
5898                          -G_MAXDOUBLE, G_MAXDOUBLE,
5899                          0.0,
5900                          G_PARAM_READWRITE |
5901                          G_PARAM_STATIC_STRINGS |
5902                          CLUTTER_PARAM_ANIMATABLE);
5903
5904   /**
5905    * ClutterActor:rotation-angle-y:
5906    *
5907    * The rotation angle on the Y axis
5908    *
5909    * The #ClutterActor:rotation-angle-y property is animatable.
5910    *
5911    * Since: 0.6
5912    */
5913   obj_props[PROP_ROTATION_ANGLE_Y] =
5914     g_param_spec_double ("rotation-angle-y",
5915                          P_("Rotation Angle Y"),
5916                          P_("The rotation angle on the Y axis"),
5917                          -G_MAXDOUBLE, G_MAXDOUBLE,
5918                          0.0,
5919                          G_PARAM_READWRITE |
5920                          G_PARAM_STATIC_STRINGS |
5921                          CLUTTER_PARAM_ANIMATABLE);
5922
5923   /**
5924    * ClutterActor:rotation-angle-z:
5925    *
5926    * The rotation angle on the Z axis
5927    *
5928    * The #ClutterActor:rotation-angle-z property is animatable.
5929    *
5930    * Since: 0.6
5931    */
5932   obj_props[PROP_ROTATION_ANGLE_Z] =
5933     g_param_spec_double ("rotation-angle-z",
5934                          P_("Rotation Angle Z"),
5935                          P_("The rotation angle on the Z axis"),
5936                          -G_MAXDOUBLE, G_MAXDOUBLE,
5937                          0.0,
5938                          G_PARAM_READWRITE |
5939                          G_PARAM_STATIC_STRINGS |
5940                          CLUTTER_PARAM_ANIMATABLE);
5941
5942   /**
5943    * ClutterActor:rotation-center-x:
5944    *
5945    * The rotation center on the X axis.
5946    *
5947    * Since: 0.6
5948    */
5949   obj_props[PROP_ROTATION_CENTER_X] =
5950     g_param_spec_boxed ("rotation-center-x",
5951                         P_("Rotation Center X"),
5952                         P_("The rotation center on the X axis"),
5953                         CLUTTER_TYPE_VERTEX,
5954                         CLUTTER_PARAM_READWRITE);
5955
5956   /**
5957    * ClutterActor:rotation-center-y:
5958    *
5959    * The rotation center on the Y axis.
5960    *
5961    * Since: 0.6
5962    */
5963   obj_props[PROP_ROTATION_CENTER_Y] =
5964     g_param_spec_boxed ("rotation-center-y",
5965                         P_("Rotation Center Y"),
5966                         P_("The rotation center on the Y axis"),
5967                         CLUTTER_TYPE_VERTEX,
5968                         CLUTTER_PARAM_READWRITE);
5969
5970   /**
5971    * ClutterActor:rotation-center-z:
5972    *
5973    * The rotation center on the Z axis.
5974    *
5975    * Since: 0.6
5976    */
5977   obj_props[PROP_ROTATION_CENTER_Z] =
5978     g_param_spec_boxed ("rotation-center-z",
5979                         P_("Rotation Center Z"),
5980                         P_("The rotation center on the Z axis"),
5981                         CLUTTER_TYPE_VERTEX,
5982                         CLUTTER_PARAM_READWRITE);
5983
5984   /**
5985    * ClutterActor:rotation-center-z-gravity:
5986    *
5987    * The rotation center on the Z axis expressed as a #ClutterGravity.
5988    *
5989    * Since: 1.0
5990    */
5991   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5992     g_param_spec_enum ("rotation-center-z-gravity",
5993                        P_("Rotation Center Z Gravity"),
5994                        P_("Center point for rotation around the Z axis"),
5995                        CLUTTER_TYPE_GRAVITY,
5996                        CLUTTER_GRAVITY_NONE,
5997                        CLUTTER_PARAM_READWRITE);
5998
5999   /**
6000    * ClutterActor:anchor-x:
6001    *
6002    * The X coordinate of an actor's anchor point, relative to
6003    * the actor coordinate space, in pixels
6004    *
6005    * Since: 0.8
6006    */
6007   obj_props[PROP_ANCHOR_X] =
6008     g_param_spec_float ("anchor-x",
6009                         P_("Anchor X"),
6010                         P_("X coordinate of the anchor point"),
6011                         -G_MAXFLOAT, G_MAXFLOAT,
6012                         0,
6013                         CLUTTER_PARAM_READWRITE);
6014
6015   /**
6016    * ClutterActor:anchor-y:
6017    *
6018    * The Y coordinate of an actor's anchor point, relative to
6019    * the actor coordinate space, in pixels
6020    *
6021    * Since: 0.8
6022    */
6023   obj_props[PROP_ANCHOR_Y] =
6024     g_param_spec_float ("anchor-y",
6025                         P_("Anchor Y"),
6026                         P_("Y coordinate of the anchor point"),
6027                         -G_MAXFLOAT, G_MAXFLOAT,
6028                         0,
6029                         CLUTTER_PARAM_READWRITE);
6030
6031   /**
6032    * ClutterActor:anchor-gravity:
6033    *
6034    * The anchor point expressed as a #ClutterGravity
6035    *
6036    * Since: 1.0
6037    */
6038   obj_props[PROP_ANCHOR_GRAVITY] =
6039     g_param_spec_enum ("anchor-gravity",
6040                        P_("Anchor Gravity"),
6041                        P_("The anchor point as a ClutterGravity"),
6042                        CLUTTER_TYPE_GRAVITY,
6043                        CLUTTER_GRAVITY_NONE,
6044                        CLUTTER_PARAM_READWRITE);
6045
6046   /**
6047    * ClutterActor:show-on-set-parent:
6048    *
6049    * If %TRUE, the actor is automatically shown when parented.
6050    *
6051    * Calling clutter_actor_hide() on an actor which has not been
6052    * parented will set this property to %FALSE as a side effect.
6053    *
6054    * Since: 0.8
6055    */
6056   obj_props[PROP_SHOW_ON_SET_PARENT] =
6057     g_param_spec_boolean ("show-on-set-parent",
6058                           P_("Show on set parent"),
6059                           P_("Whether the actor is shown when parented"),
6060                           TRUE,
6061                           CLUTTER_PARAM_READWRITE);
6062
6063   /**
6064    * ClutterActor:clip-to-allocation:
6065    *
6066    * Whether the clip region should track the allocated area
6067    * of the actor.
6068    *
6069    * This property is ignored if a clip area has been explicitly
6070    * set using clutter_actor_set_clip().
6071    *
6072    * Since: 1.0
6073    */
6074   obj_props[PROP_CLIP_TO_ALLOCATION] =
6075     g_param_spec_boolean ("clip-to-allocation",
6076                           P_("Clip to Allocation"),
6077                           P_("Sets the clip region to track the actor's allocation"),
6078                           FALSE,
6079                           CLUTTER_PARAM_READWRITE);
6080
6081   /**
6082    * ClutterActor:text-direction:
6083    *
6084    * The direction of the text inside a #ClutterActor.
6085    *
6086    * Since: 1.0
6087    */
6088   obj_props[PROP_TEXT_DIRECTION] =
6089     g_param_spec_enum ("text-direction",
6090                        P_("Text Direction"),
6091                        P_("Direction of the text"),
6092                        CLUTTER_TYPE_TEXT_DIRECTION,
6093                        CLUTTER_TEXT_DIRECTION_LTR,
6094                        CLUTTER_PARAM_READWRITE);
6095
6096   /**
6097    * ClutterActor:has-pointer:
6098    *
6099    * Whether the actor contains the pointer of a #ClutterInputDevice
6100    * or not.
6101    *
6102    * Since: 1.2
6103    */
6104   obj_props[PROP_HAS_POINTER] =
6105     g_param_spec_boolean ("has-pointer",
6106                           P_("Has Pointer"),
6107                           P_("Whether the actor contains the pointer of an input device"),
6108                           FALSE,
6109                           CLUTTER_PARAM_READABLE);
6110
6111   /**
6112    * ClutterActor:actions:
6113    *
6114    * Adds a #ClutterAction to the actor
6115    *
6116    * Since: 1.4
6117    */
6118   obj_props[PROP_ACTIONS] =
6119     g_param_spec_object ("actions",
6120                          P_("Actions"),
6121                          P_("Adds an action to the actor"),
6122                          CLUTTER_TYPE_ACTION,
6123                          CLUTTER_PARAM_WRITABLE);
6124
6125   /**
6126    * ClutterActor:constraints:
6127    *
6128    * Adds a #ClutterConstraint to the actor
6129    *
6130    * Since: 1.4
6131    */
6132   obj_props[PROP_CONSTRAINTS] =
6133     g_param_spec_object ("constraints",
6134                          P_("Constraints"),
6135                          P_("Adds a constraint to the actor"),
6136                          CLUTTER_TYPE_CONSTRAINT,
6137                          CLUTTER_PARAM_WRITABLE);
6138
6139   /**
6140    * ClutterActor:effect:
6141    *
6142    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6143    *
6144    * Since: 1.4
6145    */
6146   obj_props[PROP_EFFECT] =
6147     g_param_spec_object ("effect",
6148                          P_("Effect"),
6149                          P_("Add an effect to be applied on the actor"),
6150                          CLUTTER_TYPE_EFFECT,
6151                          CLUTTER_PARAM_WRITABLE);
6152
6153   /**
6154    * ClutterActor:layout-manager:
6155    *
6156    * A delegate object for controlling the layout of the children of
6157    * an actor.
6158    *
6159    * Since: 1.10
6160    */
6161   obj_props[PROP_LAYOUT_MANAGER] =
6162     g_param_spec_object ("layout-manager",
6163                          P_("Layout Manager"),
6164                          P_("The object controlling the layout of an actor's children"),
6165                          CLUTTER_TYPE_LAYOUT_MANAGER,
6166                          CLUTTER_PARAM_READWRITE);
6167
6168
6169   /**
6170    * ClutterActor:x-align:
6171    *
6172    * The alignment of an actor on the X axis, if the actor has been given
6173    * extra space for its allocation.
6174    *
6175    * Since: 1.10
6176    */
6177   obj_props[PROP_X_ALIGN] =
6178     g_param_spec_enum ("x-align",
6179                        P_("X Alignment"),
6180                        P_("The alignment of the actor on the X axis within its allocation"),
6181                        CLUTTER_TYPE_ACTOR_ALIGN,
6182                        CLUTTER_ACTOR_ALIGN_FILL,
6183                        CLUTTER_PARAM_READWRITE);
6184
6185   /**
6186    * ClutterActor:y-align:
6187    *
6188    * The alignment of an actor on the Y axis, if the actor has been given
6189    * extra space for its allocation.
6190    *
6191    * Since: 1.10
6192    */
6193   obj_props[PROP_Y_ALIGN] =
6194     g_param_spec_enum ("y-align",
6195                        P_("Y Alignment"),
6196                        P_("The alignment of the actor on the Y axis within its allocation"),
6197                        CLUTTER_TYPE_ACTOR_ALIGN,
6198                        CLUTTER_ACTOR_ALIGN_FILL,
6199                        CLUTTER_PARAM_READWRITE);
6200
6201   /**
6202    * ClutterActor:margin-top:
6203    *
6204    * The margin (in pixels) from the top of the actor.
6205    *
6206    * This property adds a margin to the actor's preferred size; the margin
6207    * will be automatically taken into account when allocating the actor.
6208    *
6209    * Since: 1.10
6210    */
6211   obj_props[PROP_MARGIN_TOP] =
6212     g_param_spec_float ("margin-top",
6213                         P_("Margin Top"),
6214                         P_("Extra space at the top"),
6215                         0.0, G_MAXFLOAT,
6216                         0.0,
6217                         CLUTTER_PARAM_READWRITE);
6218
6219   /**
6220    * ClutterActor:margin-bottom:
6221    *
6222    * The margin (in pixels) from the bottom of the actor.
6223    *
6224    * This property adds a margin to the actor's preferred size; the margin
6225    * will be automatically taken into account when allocating the actor.
6226    *
6227    * Since: 1.10
6228    */
6229   obj_props[PROP_MARGIN_BOTTOM] =
6230     g_param_spec_float ("margin-bottom",
6231                         P_("Margin Bottom"),
6232                         P_("Extra space at the bottom"),
6233                         0.0, G_MAXFLOAT,
6234                         0.0,
6235                         CLUTTER_PARAM_READWRITE);
6236
6237   /**
6238    * ClutterActor:margin-left:
6239    *
6240    * The margin (in pixels) from the left of the actor.
6241    *
6242    * This property adds a margin to the actor's preferred size; the margin
6243    * will be automatically taken into account when allocating the actor.
6244    *
6245    * Since: 1.10
6246    */
6247   obj_props[PROP_MARGIN_LEFT] =
6248     g_param_spec_float ("margin-left",
6249                         P_("Margin Left"),
6250                         P_("Extra space at the left"),
6251                         0.0, G_MAXFLOAT,
6252                         0.0,
6253                         CLUTTER_PARAM_READWRITE);
6254
6255   /**
6256    * ClutterActor:margin-right:
6257    *
6258    * The margin (in pixels) from the right of the actor.
6259    *
6260    * This property adds a margin to the actor's preferred size; the margin
6261    * will be automatically taken into account when allocating the actor.
6262    *
6263    * Since: 1.10
6264    */
6265   obj_props[PROP_MARGIN_RIGHT] =
6266     g_param_spec_float ("margin-right",
6267                         P_("Margin Right"),
6268                         P_("Extra space at the right"),
6269                         0.0, G_MAXFLOAT,
6270                         0.0,
6271                         CLUTTER_PARAM_READWRITE);
6272
6273   /**
6274    * ClutterActor:background-color-set:
6275    *
6276    * Whether the #ClutterActor:background-color property has been set.
6277    *
6278    * Since: 1.10
6279    */
6280   obj_props[PROP_BACKGROUND_COLOR_SET] =
6281     g_param_spec_boolean ("background-color-set",
6282                           P_("Background Color Set"),
6283                           P_("Whether the background color is set"),
6284                           FALSE,
6285                           CLUTTER_PARAM_READABLE);
6286
6287   /**
6288    * ClutterActor:background-color:
6289    *
6290    * Paints a solid fill of the actor's allocation using the specified
6291    * color.
6292    *
6293    * The #ClutterActor:background-color property is animatable.
6294    *
6295    * Since: 1.10
6296    */
6297   obj_props[PROP_BACKGROUND_COLOR] =
6298     clutter_param_spec_color ("background-color",
6299                               P_("Background color"),
6300                               P_("The actor's background color"),
6301                               CLUTTER_COLOR_Transparent,
6302                               G_PARAM_READWRITE |
6303                               G_PARAM_STATIC_STRINGS |
6304                               CLUTTER_PARAM_ANIMATABLE);
6305
6306   /**
6307    * ClutterActor:first-child:
6308    *
6309    * The actor's first child.
6310    *
6311    * Since: 1.10
6312    */
6313   obj_props[PROP_FIRST_CHILD] =
6314     g_param_spec_object ("first-child",
6315                          P_("First Child"),
6316                          P_("The actor's first child"),
6317                          CLUTTER_TYPE_ACTOR,
6318                          CLUTTER_PARAM_READABLE);
6319
6320   /**
6321    * ClutterActor:last-child:
6322    *
6323    * The actor's last child.
6324    *
6325    * Since: 1.10
6326    */
6327   obj_props[PROP_LAST_CHILD] =
6328     g_param_spec_object ("last-child",
6329                          P_("Last Child"),
6330                          P_("The actor's last child"),
6331                          CLUTTER_TYPE_ACTOR,
6332                          CLUTTER_PARAM_READABLE);
6333
6334   /**
6335    * ClutterActor:content:
6336    *
6337    * The #ClutterContent implementation that controls the content
6338    * of the actor.
6339    *
6340    * Since: 1.10
6341    */
6342   obj_props[PROP_CONTENT] =
6343     g_param_spec_object ("content",
6344                          P_("Content"),
6345                          P_("Delegate object for painting the actor's content"),
6346                          CLUTTER_TYPE_CONTENT,
6347                          CLUTTER_PARAM_READWRITE);
6348
6349   /**
6350    * ClutterActor:content-gravity:
6351    *
6352    * The alignment that should be honoured by the #ClutterContent
6353    * set with the #ClutterActor:content property.
6354    *
6355    * Changing the value of this property will change the bounding box of
6356    * the content; you can use the #ClutterActor:content-box property to
6357    * get the position and size of the content within the actor's
6358    * allocation.
6359    *
6360    * This property is meaningful only for #ClutterContent implementations
6361    * that have a preferred size, and if the preferred size is smaller than
6362    * the actor's allocation.
6363    *
6364    * Since: 1.10
6365    */
6366   obj_props[PROP_CONTENT_GRAVITY] =
6367     g_param_spec_enum ("content-gravity",
6368                        P_("Content Gravity"),
6369                        P_("Alignment of the actor's content"),
6370                        CLUTTER_TYPE_CONTENT_GRAVITY,
6371                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6372                        CLUTTER_PARAM_READWRITE);
6373
6374   /**
6375    * ClutterActor:content-box:
6376    *
6377    * The bounding box for the #ClutterContent used by the actor.
6378    *
6379    * The value of this property is controlled by the #ClutterActor:allocation
6380    * and #ClutterActor:content-gravity properties of #ClutterActor.
6381    *
6382    * The bounding box for the content is guaranteed to never exceed the
6383    * allocation's of the actor.
6384    *
6385    * Since: 1.10
6386    */
6387   obj_props[PROP_CONTENT_BOX] =
6388     g_param_spec_boxed ("content-box",
6389                         P_("Content Box"),
6390                         P_("The bounding box of the actor's content"),
6391                         CLUTTER_TYPE_ACTOR_BOX,
6392                         CLUTTER_PARAM_READABLE);
6393
6394   obj_props[PROP_MINIFICATION_FILTER] =
6395     g_param_spec_enum ("minification-filter",
6396                        P_("Minification Filter"),
6397                        P_("The filter used when reducing the size of the content"),
6398                        CLUTTER_TYPE_SCALING_FILTER,
6399                        CLUTTER_SCALING_FILTER_LINEAR,
6400                        CLUTTER_PARAM_READWRITE);
6401
6402   obj_props[PROP_MAGNIFICATION_FILTER] =
6403     g_param_spec_enum ("magnification-filter",
6404                        P_("Magnification Filter"),
6405                        P_("The filter used when increasing the size of the content"),
6406                        CLUTTER_TYPE_SCALING_FILTER,
6407                        CLUTTER_SCALING_FILTER_LINEAR,
6408                        CLUTTER_PARAM_READWRITE);
6409
6410   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6411
6412   /**
6413    * ClutterActor::destroy:
6414    * @actor: the #ClutterActor which emitted the signal
6415    *
6416    * The ::destroy signal notifies that all references held on the
6417    * actor which emitted it should be released.
6418    *
6419    * The ::destroy signal should be used by all holders of a reference
6420    * on @actor.
6421    *
6422    * This signal might result in the finalization of the #ClutterActor
6423    * if all references are released.
6424    *
6425    * Composite actors and actors implementing the #ClutterContainer
6426    * interface should override the default implementation of the
6427    * class handler of this signal and call clutter_actor_destroy() on
6428    * their children. When overriding the default class handler, it is
6429    * required to chain up to the parent's implementation.
6430    *
6431    * Since: 0.2
6432    */
6433   actor_signals[DESTROY] =
6434     g_signal_new (I_("destroy"),
6435                   G_TYPE_FROM_CLASS (object_class),
6436                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6437                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6438                   NULL, NULL,
6439                   _clutter_marshal_VOID__VOID,
6440                   G_TYPE_NONE, 0);
6441   /**
6442    * ClutterActor::show:
6443    * @actor: the object which received the signal
6444    *
6445    * The ::show signal is emitted when an actor is visible and
6446    * rendered on the stage.
6447    *
6448    * Since: 0.2
6449    */
6450   actor_signals[SHOW] =
6451     g_signal_new (I_("show"),
6452                   G_TYPE_FROM_CLASS (object_class),
6453                   G_SIGNAL_RUN_FIRST,
6454                   G_STRUCT_OFFSET (ClutterActorClass, show),
6455                   NULL, NULL,
6456                   _clutter_marshal_VOID__VOID,
6457                   G_TYPE_NONE, 0);
6458   /**
6459    * ClutterActor::hide:
6460    * @actor: the object which received the signal
6461    *
6462    * The ::hide signal is emitted when an actor is no longer rendered
6463    * on the stage.
6464    *
6465    * Since: 0.2
6466    */
6467   actor_signals[HIDE] =
6468     g_signal_new (I_("hide"),
6469                   G_TYPE_FROM_CLASS (object_class),
6470                   G_SIGNAL_RUN_FIRST,
6471                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6472                   NULL, NULL,
6473                   _clutter_marshal_VOID__VOID,
6474                   G_TYPE_NONE, 0);
6475   /**
6476    * ClutterActor::parent-set:
6477    * @actor: the object which received the signal
6478    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6479    *
6480    * This signal is emitted when the parent of the actor changes.
6481    *
6482    * Since: 0.2
6483    */
6484   actor_signals[PARENT_SET] =
6485     g_signal_new (I_("parent-set"),
6486                   G_TYPE_FROM_CLASS (object_class),
6487                   G_SIGNAL_RUN_LAST,
6488                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6489                   NULL, NULL,
6490                   _clutter_marshal_VOID__OBJECT,
6491                   G_TYPE_NONE, 1,
6492                   CLUTTER_TYPE_ACTOR);
6493
6494   /**
6495    * ClutterActor::queue-redraw:
6496    * @actor: the actor we're bubbling the redraw request through
6497    * @origin: the actor which initiated the redraw request
6498    *
6499    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6500    * is called on @origin.
6501    *
6502    * The default implementation for #ClutterActor chains up to the
6503    * parent actor and queues a redraw on the parent, thus "bubbling"
6504    * the redraw queue up through the actor graph. The default
6505    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6506    * in a main loop idle handler.
6507    *
6508    * Note that the @origin actor may be the stage, or a container; it
6509    * does not have to be a leaf node in the actor graph.
6510    *
6511    * Toolkits embedding a #ClutterStage which require a redraw and
6512    * relayout cycle can stop the emission of this signal using the
6513    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6514    * themselves, like:
6515    *
6516    * |[
6517    *   static void
6518    *   on_redraw_complete (gpointer data)
6519    *   {
6520    *     ClutterStage *stage = data;
6521    *
6522    *     /&ast; execute the Clutter drawing pipeline &ast;/
6523    *     clutter_stage_ensure_redraw (stage);
6524    *   }
6525    *
6526    *   static void
6527    *   on_stage_queue_redraw (ClutterStage *stage)
6528    *   {
6529    *     /&ast; this prevents the default handler to run &ast;/
6530    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6531    *
6532    *     /&ast; queue a redraw with the host toolkit and call
6533    *      &ast; a function when the redraw has been completed
6534    *      &ast;/
6535    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6536    *   }
6537    * ]|
6538    *
6539    * <note><para>This signal is emitted before the Clutter paint
6540    * pipeline is executed. If you want to know when the pipeline has
6541    * been completed you should connect to the ::paint signal on the
6542    * Stage with g_signal_connect_after().</para></note>
6543    *
6544    * Since: 1.0
6545    */
6546   actor_signals[QUEUE_REDRAW] =
6547     g_signal_new (I_("queue-redraw"),
6548                   G_TYPE_FROM_CLASS (object_class),
6549                   G_SIGNAL_RUN_LAST |
6550                   G_SIGNAL_NO_HOOKS,
6551                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6552                   NULL, NULL,
6553                   _clutter_marshal_VOID__OBJECT,
6554                   G_TYPE_NONE, 1,
6555                   CLUTTER_TYPE_ACTOR);
6556
6557   /**
6558    * ClutterActor::queue-relayout
6559    * @actor: the actor being queued for relayout
6560    *
6561    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6562    * is called on an actor.
6563    *
6564    * The default implementation for #ClutterActor chains up to the
6565    * parent actor and queues a relayout on the parent, thus "bubbling"
6566    * the relayout queue up through the actor graph.
6567    *
6568    * The main purpose of this signal is to allow relayout to be propagated
6569    * properly in the procense of #ClutterClone actors. Applications will
6570    * not normally need to connect to this signal.
6571    *
6572    * Since: 1.2
6573    */
6574   actor_signals[QUEUE_RELAYOUT] =
6575     g_signal_new (I_("queue-relayout"),
6576                   G_TYPE_FROM_CLASS (object_class),
6577                   G_SIGNAL_RUN_LAST |
6578                   G_SIGNAL_NO_HOOKS,
6579                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6580                   NULL, NULL,
6581                   _clutter_marshal_VOID__VOID,
6582                   G_TYPE_NONE, 0);
6583
6584   /**
6585    * ClutterActor::event:
6586    * @actor: the actor which received the event
6587    * @event: a #ClutterEvent
6588    *
6589    * The ::event signal is emitted each time an event is received
6590    * by the @actor. This signal will be emitted on every actor,
6591    * following the hierarchy chain, until it reaches the top-level
6592    * container (the #ClutterStage).
6593    *
6594    * Return value: %TRUE if the event has been handled by the actor,
6595    *   or %FALSE to continue the emission.
6596    *
6597    * Since: 0.6
6598    */
6599   actor_signals[EVENT] =
6600     g_signal_new (I_("event"),
6601                   G_TYPE_FROM_CLASS (object_class),
6602                   G_SIGNAL_RUN_LAST,
6603                   G_STRUCT_OFFSET (ClutterActorClass, event),
6604                   _clutter_boolean_handled_accumulator, NULL,
6605                   _clutter_marshal_BOOLEAN__BOXED,
6606                   G_TYPE_BOOLEAN, 1,
6607                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6608   /**
6609    * ClutterActor::button-press-event:
6610    * @actor: the actor which received the event
6611    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6612    *
6613    * The ::button-press-event signal is emitted each time a mouse button
6614    * is pressed on @actor.
6615    *
6616    * Return value: %TRUE if the event has been handled by the actor,
6617    *   or %FALSE to continue the emission.
6618    *
6619    * Since: 0.6
6620    */
6621   actor_signals[BUTTON_PRESS_EVENT] =
6622     g_signal_new (I_("button-press-event"),
6623                   G_TYPE_FROM_CLASS (object_class),
6624                   G_SIGNAL_RUN_LAST,
6625                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6626                   _clutter_boolean_handled_accumulator, NULL,
6627                   _clutter_marshal_BOOLEAN__BOXED,
6628                   G_TYPE_BOOLEAN, 1,
6629                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6630   /**
6631    * ClutterActor::button-release-event:
6632    * @actor: the actor which received the event
6633    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6634    *
6635    * The ::button-release-event signal is emitted each time a mouse button
6636    * is released on @actor.
6637    *
6638    * Return value: %TRUE if the event has been handled by the actor,
6639    *   or %FALSE to continue the emission.
6640    *
6641    * Since: 0.6
6642    */
6643   actor_signals[BUTTON_RELEASE_EVENT] =
6644     g_signal_new (I_("button-release-event"),
6645                   G_TYPE_FROM_CLASS (object_class),
6646                   G_SIGNAL_RUN_LAST,
6647                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6648                   _clutter_boolean_handled_accumulator, NULL,
6649                   _clutter_marshal_BOOLEAN__BOXED,
6650                   G_TYPE_BOOLEAN, 1,
6651                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6652   /**
6653    * ClutterActor::scroll-event:
6654    * @actor: the actor which received the event
6655    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6656    *
6657    * The ::scroll-event signal is emitted each time the mouse is
6658    * scrolled on @actor
6659    *
6660    * Return value: %TRUE if the event has been handled by the actor,
6661    *   or %FALSE to continue the emission.
6662    *
6663    * Since: 0.6
6664    */
6665   actor_signals[SCROLL_EVENT] =
6666     g_signal_new (I_("scroll-event"),
6667                   G_TYPE_FROM_CLASS (object_class),
6668                   G_SIGNAL_RUN_LAST,
6669                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6670                   _clutter_boolean_handled_accumulator, NULL,
6671                   _clutter_marshal_BOOLEAN__BOXED,
6672                   G_TYPE_BOOLEAN, 1,
6673                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6674   /**
6675    * ClutterActor::key-press-event:
6676    * @actor: the actor which received the event
6677    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6678    *
6679    * The ::key-press-event signal is emitted each time a keyboard button
6680    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6681    *
6682    * Return value: %TRUE if the event has been handled by the actor,
6683    *   or %FALSE to continue the emission.
6684    *
6685    * Since: 0.6
6686    */
6687   actor_signals[KEY_PRESS_EVENT] =
6688     g_signal_new (I_("key-press-event"),
6689                   G_TYPE_FROM_CLASS (object_class),
6690                   G_SIGNAL_RUN_LAST,
6691                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6692                   _clutter_boolean_handled_accumulator, NULL,
6693                   _clutter_marshal_BOOLEAN__BOXED,
6694                   G_TYPE_BOOLEAN, 1,
6695                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6696   /**
6697    * ClutterActor::key-release-event:
6698    * @actor: the actor which received the event
6699    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6700    *
6701    * The ::key-release-event signal is emitted each time a keyboard button
6702    * is released while @actor has key focus (see
6703    * clutter_stage_set_key_focus()).
6704    *
6705    * Return value: %TRUE if the event has been handled by the actor,
6706    *   or %FALSE to continue the emission.
6707    *
6708    * Since: 0.6
6709    */
6710   actor_signals[KEY_RELEASE_EVENT] =
6711     g_signal_new (I_("key-release-event"),
6712                   G_TYPE_FROM_CLASS (object_class),
6713                   G_SIGNAL_RUN_LAST,
6714                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6715                   _clutter_boolean_handled_accumulator, NULL,
6716                   _clutter_marshal_BOOLEAN__BOXED,
6717                   G_TYPE_BOOLEAN, 1,
6718                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6719   /**
6720    * ClutterActor::motion-event:
6721    * @actor: the actor which received the event
6722    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6723    *
6724    * The ::motion-event signal is emitted each time the mouse pointer is
6725    * moved over @actor.
6726    *
6727    * Return value: %TRUE if the event has been handled by the actor,
6728    *   or %FALSE to continue the emission.
6729    *
6730    * Since: 0.6
6731    */
6732   actor_signals[MOTION_EVENT] =
6733     g_signal_new (I_("motion-event"),
6734                   G_TYPE_FROM_CLASS (object_class),
6735                   G_SIGNAL_RUN_LAST,
6736                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6737                   _clutter_boolean_handled_accumulator, NULL,
6738                   _clutter_marshal_BOOLEAN__BOXED,
6739                   G_TYPE_BOOLEAN, 1,
6740                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6741
6742   /**
6743    * ClutterActor::key-focus-in:
6744    * @actor: the actor which now has key focus
6745    *
6746    * The ::key-focus-in signal is emitted when @actor receives key focus.
6747    *
6748    * Since: 0.6
6749    */
6750   actor_signals[KEY_FOCUS_IN] =
6751     g_signal_new (I_("key-focus-in"),
6752                   G_TYPE_FROM_CLASS (object_class),
6753                   G_SIGNAL_RUN_LAST,
6754                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6755                   NULL, NULL,
6756                   _clutter_marshal_VOID__VOID,
6757                   G_TYPE_NONE, 0);
6758
6759   /**
6760    * ClutterActor::key-focus-out:
6761    * @actor: the actor which now has key focus
6762    *
6763    * The ::key-focus-out signal is emitted when @actor loses key focus.
6764    *
6765    * Since: 0.6
6766    */
6767   actor_signals[KEY_FOCUS_OUT] =
6768     g_signal_new (I_("key-focus-out"),
6769                   G_TYPE_FROM_CLASS (object_class),
6770                   G_SIGNAL_RUN_LAST,
6771                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6772                   NULL, NULL,
6773                   _clutter_marshal_VOID__VOID,
6774                   G_TYPE_NONE, 0);
6775
6776   /**
6777    * ClutterActor::enter-event:
6778    * @actor: the actor which the pointer has entered.
6779    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6780    *
6781    * The ::enter-event signal is emitted when the pointer enters the @actor
6782    *
6783    * Return value: %TRUE if the event has been handled by the actor,
6784    *   or %FALSE to continue the emission.
6785    *
6786    * Since: 0.6
6787    */
6788   actor_signals[ENTER_EVENT] =
6789     g_signal_new (I_("enter-event"),
6790                   G_TYPE_FROM_CLASS (object_class),
6791                   G_SIGNAL_RUN_LAST,
6792                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6793                   _clutter_boolean_handled_accumulator, NULL,
6794                   _clutter_marshal_BOOLEAN__BOXED,
6795                   G_TYPE_BOOLEAN, 1,
6796                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6797
6798   /**
6799    * ClutterActor::leave-event:
6800    * @actor: the actor which the pointer has left
6801    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6802    *
6803    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6804    *
6805    * Return value: %TRUE if the event has been handled by the actor,
6806    *   or %FALSE to continue the emission.
6807    *
6808    * Since: 0.6
6809    */
6810   actor_signals[LEAVE_EVENT] =
6811     g_signal_new (I_("leave-event"),
6812                   G_TYPE_FROM_CLASS (object_class),
6813                   G_SIGNAL_RUN_LAST,
6814                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6815                   _clutter_boolean_handled_accumulator, NULL,
6816                   _clutter_marshal_BOOLEAN__BOXED,
6817                   G_TYPE_BOOLEAN, 1,
6818                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6819
6820   /**
6821    * ClutterActor::captured-event:
6822    * @actor: the actor which received the signal
6823    * @event: a #ClutterEvent
6824    *
6825    * The ::captured-event signal is emitted when an event is captured
6826    * by Clutter. This signal will be emitted starting from the top-level
6827    * container (the #ClutterStage) to the actor which received the event
6828    * going down the hierarchy. This signal can be used to intercept every
6829    * event before the specialized events (like
6830    * ClutterActor::button-press-event or ::key-released-event) are
6831    * emitted.
6832    *
6833    * Return value: %TRUE if the event has been handled by the actor,
6834    *   or %FALSE to continue the emission.
6835    *
6836    * Since: 0.6
6837    */
6838   actor_signals[CAPTURED_EVENT] =
6839     g_signal_new (I_("captured-event"),
6840                   G_TYPE_FROM_CLASS (object_class),
6841                   G_SIGNAL_RUN_LAST,
6842                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6843                   _clutter_boolean_handled_accumulator, NULL,
6844                   _clutter_marshal_BOOLEAN__BOXED,
6845                   G_TYPE_BOOLEAN, 1,
6846                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6847
6848   /**
6849    * ClutterActor::paint:
6850    * @actor: the #ClutterActor that received the signal
6851    *
6852    * The ::paint signal is emitted each time an actor is being painted.
6853    *
6854    * Subclasses of #ClutterActor should override the class signal handler
6855    * and paint themselves in that function.
6856    *
6857    * It is possible to connect a handler to the ::paint signal in order
6858    * to set up some custom aspect of a paint.
6859    *
6860    * Since: 0.8
6861    */
6862   actor_signals[PAINT] =
6863     g_signal_new (I_("paint"),
6864                   G_TYPE_FROM_CLASS (object_class),
6865                   G_SIGNAL_RUN_LAST |
6866                   G_SIGNAL_NO_HOOKS,
6867                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6868                   NULL, NULL,
6869                   _clutter_marshal_VOID__VOID,
6870                   G_TYPE_NONE, 0);
6871   /**
6872    * ClutterActor::realize:
6873    * @actor: the #ClutterActor that received the signal
6874    *
6875    * The ::realize signal is emitted each time an actor is being
6876    * realized.
6877    *
6878    * Since: 0.8
6879    */
6880   actor_signals[REALIZE] =
6881     g_signal_new (I_("realize"),
6882                   G_TYPE_FROM_CLASS (object_class),
6883                   G_SIGNAL_RUN_LAST,
6884                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6885                   NULL, NULL,
6886                   _clutter_marshal_VOID__VOID,
6887                   G_TYPE_NONE, 0);
6888   /**
6889    * ClutterActor::unrealize:
6890    * @actor: the #ClutterActor that received the signal
6891    *
6892    * The ::unrealize signal is emitted each time an actor is being
6893    * unrealized.
6894    *
6895    * Since: 0.8
6896    */
6897   actor_signals[UNREALIZE] =
6898     g_signal_new (I_("unrealize"),
6899                   G_TYPE_FROM_CLASS (object_class),
6900                   G_SIGNAL_RUN_LAST,
6901                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6902                   NULL, NULL,
6903                   _clutter_marshal_VOID__VOID,
6904                   G_TYPE_NONE, 0);
6905
6906   /**
6907    * ClutterActor::pick:
6908    * @actor: the #ClutterActor that received the signal
6909    * @color: the #ClutterColor to be used when picking
6910    *
6911    * The ::pick signal is emitted each time an actor is being painted
6912    * in "pick mode". The pick mode is used to identify the actor during
6913    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6914    * The actor should paint its shape using the passed @pick_color.
6915    *
6916    * Subclasses of #ClutterActor should override the class signal handler
6917    * and paint themselves in that function.
6918    *
6919    * It is possible to connect a handler to the ::pick signal in order
6920    * to set up some custom aspect of a paint in pick mode.
6921    *
6922    * Since: 1.0
6923    */
6924   actor_signals[PICK] =
6925     g_signal_new (I_("pick"),
6926                   G_TYPE_FROM_CLASS (object_class),
6927                   G_SIGNAL_RUN_LAST,
6928                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6929                   NULL, NULL,
6930                   _clutter_marshal_VOID__BOXED,
6931                   G_TYPE_NONE, 1,
6932                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6933
6934   /**
6935    * ClutterActor::allocation-changed:
6936    * @actor: the #ClutterActor that emitted the signal
6937    * @box: a #ClutterActorBox with the new allocation
6938    * @flags: #ClutterAllocationFlags for the allocation
6939    *
6940    * The ::allocation-changed signal is emitted when the
6941    * #ClutterActor:allocation property changes. Usually, application
6942    * code should just use the notifications for the :allocation property
6943    * but if you want to track the allocation flags as well, for instance
6944    * to know whether the absolute origin of @actor changed, then you might
6945    * want use this signal instead.
6946    *
6947    * Since: 1.0
6948    */
6949   actor_signals[ALLOCATION_CHANGED] =
6950     g_signal_new (I_("allocation-changed"),
6951                   G_TYPE_FROM_CLASS (object_class),
6952                   G_SIGNAL_RUN_LAST,
6953                   0,
6954                   NULL, NULL,
6955                   _clutter_marshal_VOID__BOXED_FLAGS,
6956                   G_TYPE_NONE, 2,
6957                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6958                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6959
6960   /**
6961    * ClutterActor::transitions-completed:
6962    * @actor: a #ClutterActor
6963    *
6964    * The ::transitions-completed signal is emitted once all transitions
6965    * involving @actor are complete.
6966    *
6967    * Since: 1.10
6968    */
6969   actor_signals[TRANSITIONS_COMPLETED] =
6970     g_signal_new (I_("transitions-completed"),
6971                   G_TYPE_FROM_CLASS (object_class),
6972                   G_SIGNAL_RUN_LAST,
6973                   0,
6974                   NULL, NULL,
6975                   _clutter_marshal_VOID__VOID,
6976                   G_TYPE_NONE, 0);
6977 }
6978
6979 static void
6980 clutter_actor_init (ClutterActor *self)
6981 {
6982   ClutterActorPrivate *priv;
6983
6984   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6985
6986   priv->id = _clutter_context_acquire_id (self);
6987   priv->pick_id = -1;
6988
6989   priv->opacity = 0xff;
6990   priv->show_on_set_parent = TRUE;
6991
6992   priv->needs_width_request = TRUE;
6993   priv->needs_height_request = TRUE;
6994   priv->needs_allocation = TRUE;
6995
6996   priv->cached_width_age = 1;
6997   priv->cached_height_age = 1;
6998
6999   priv->opacity_override = -1;
7000   priv->enable_model_view_transform = TRUE;
7001
7002   /* Initialize an empty paint volume to start with */
7003   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7004   priv->last_paint_volume_valid = TRUE;
7005
7006   priv->transform_valid = FALSE;
7007
7008   /* the default is to stretch the content, to match the
7009    * current behaviour of basically all actors. also, it's
7010    * the easiest thing to compute.
7011    */
7012   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7013   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7014   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7015 }
7016
7017 /**
7018  * clutter_actor_new:
7019  *
7020  * Creates a new #ClutterActor.
7021  *
7022  * A newly created actor has a floating reference, which will be sunk
7023  * when it is added to another actor.
7024  *
7025  * Return value: (transfer full): the newly created #ClutterActor
7026  *
7027  * Since: 1.10
7028  */
7029 ClutterActor *
7030 clutter_actor_new (void)
7031 {
7032   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7033 }
7034
7035 /**
7036  * clutter_actor_destroy:
7037  * @self: a #ClutterActor
7038  *
7039  * Destroys an actor.  When an actor is destroyed, it will break any
7040  * references it holds to other objects.  If the actor is inside a
7041  * container, the actor will be removed.
7042  *
7043  * When you destroy a container, its children will be destroyed as well.
7044  *
7045  * Note: you cannot destroy the #ClutterStage returned by
7046  * clutter_stage_get_default().
7047  */
7048 void
7049 clutter_actor_destroy (ClutterActor *self)
7050 {
7051   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7052
7053   g_object_ref (self);
7054
7055   /* avoid recursion while destroying */
7056   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7057     {
7058       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7059
7060       g_object_run_dispose (G_OBJECT (self));
7061
7062       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7063     }
7064
7065   g_object_unref (self);
7066 }
7067
7068 void
7069 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7070                                     ClutterPaintVolume *clip)
7071 {
7072   ClutterActorPrivate *priv = self->priv;
7073   ClutterPaintVolume *pv;
7074   gboolean clipped;
7075
7076   /* Remove queue entry early in the process, otherwise a new
7077      queue_redraw() during signal handling could put back this
7078      object in the stage redraw list (but the entry is freed as
7079      soon as we return from this function, causing a segfault
7080      later)
7081   */
7082   priv->queue_redraw_entry = NULL;
7083
7084   /* If we've been explicitly passed a clip volume then there's
7085    * nothing more to calculate, but otherwise the only thing we know
7086    * is that the change is constrained to the given actor.
7087    *
7088    * The idea is that if we know the paint volume for where the actor
7089    * was last drawn (in eye coordinates) and we also have the paint
7090    * volume for where it will be drawn next (in actor coordinates)
7091    * then if we queue a redraw for both these volumes that will cover
7092    * everything that needs to be redrawn to clear the old view and
7093    * show the latest view of the actor.
7094    *
7095    * Don't clip this redraw if we don't know what position we had for
7096    * the previous redraw since we don't know where to set the clip so
7097    * it will clear the actor as it is currently.
7098    */
7099   if (clip)
7100     {
7101       _clutter_actor_set_queue_redraw_clip (self, clip);
7102       clipped = TRUE;
7103     }
7104   else if (G_LIKELY (priv->last_paint_volume_valid))
7105     {
7106       pv = _clutter_actor_get_paint_volume_mutable (self);
7107       if (pv)
7108         {
7109           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7110
7111           /* make sure we redraw the actors old position... */
7112           _clutter_actor_set_queue_redraw_clip (stage,
7113                                                 &priv->last_paint_volume);
7114           _clutter_actor_signal_queue_redraw (stage, stage);
7115           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7116
7117           /* XXX: Ideally the redraw signal would take a clip volume
7118            * argument, but that would be an ABI break. Until we can
7119            * break the ABI we pass the argument out-of-band
7120            */
7121
7122           /* setup the clip for the actors new position... */
7123           _clutter_actor_set_queue_redraw_clip (self, pv);
7124           clipped = TRUE;
7125         }
7126       else
7127         clipped = FALSE;
7128     }
7129   else
7130     clipped = FALSE;
7131
7132   _clutter_actor_signal_queue_redraw (self, self);
7133
7134   /* Just in case anyone is manually firing redraw signals without
7135    * using the public queue_redraw() API we are careful to ensure that
7136    * our out-of-band clip member is cleared before returning...
7137    *
7138    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7139    */
7140   if (G_LIKELY (clipped))
7141     _clutter_actor_set_queue_redraw_clip (self, NULL);
7142 }
7143
7144 static void
7145 _clutter_actor_get_allocation_clip (ClutterActor *self,
7146                                     ClutterActorBox *clip)
7147 {
7148   ClutterActorBox allocation;
7149
7150   /* XXX: we don't care if we get an out of date allocation here
7151    * because clutter_actor_queue_redraw_with_clip knows to ignore
7152    * the clip if the actor's allocation is invalid.
7153    *
7154    * This is noted because clutter_actor_get_allocation_box does some
7155    * unnecessary work to support buggy code with a comment suggesting
7156    * that it could be changed later which would be good for this use
7157    * case!
7158    */
7159   clutter_actor_get_allocation_box (self, &allocation);
7160
7161   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7162    * actor's own coordinate space but the allocation is in parent
7163    * coordinates */
7164   clip->x1 = 0;
7165   clip->y1 = 0;
7166   clip->x2 = allocation.x2 - allocation.x1;
7167   clip->y2 = allocation.y2 - allocation.y1;
7168 }
7169
7170 void
7171 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7172                                   ClutterRedrawFlags  flags,
7173                                   ClutterPaintVolume *volume,
7174                                   ClutterEffect      *effect)
7175 {
7176   ClutterActorPrivate *priv = self->priv;
7177   ClutterPaintVolume allocation_pv;
7178   ClutterPaintVolume *pv;
7179   gboolean should_free_pv;
7180   ClutterActor *stage;
7181
7182   /* Here's an outline of the actor queue redraw mechanism:
7183    *
7184    * The process starts in one of the following two functions which
7185    * are wrappers for this function:
7186    * clutter_actor_queue_redraw
7187    * _clutter_actor_queue_redraw_with_clip
7188    *
7189    * additionally, an effect can queue a redraw by wrapping this
7190    * function in clutter_effect_queue_rerun
7191    *
7192    * This functions queues an entry in a list associated with the
7193    * stage which is a list of actors that queued a redraw while
7194    * updating the timelines, performing layouting and processing other
7195    * mainloop sources before the next paint starts.
7196    *
7197    * We aim to minimize the processing done at this point because
7198    * there is a good chance other events will happen while updating
7199    * the scenegraph that would invalidate any expensive work we might
7200    * otherwise try to do here. For example we don't try and resolve
7201    * the screen space bounding box of an actor at this stage so as to
7202    * minimize how much of the screen redraw because it's possible
7203    * something else will happen which will force a full redraw anyway.
7204    *
7205    * When all updates are complete and we come to paint the stage then
7206    * we iterate this list and actually emit the "queue-redraw" signals
7207    * for each of the listed actors which will bubble up to the stage
7208    * for each actor and at that point we will transform the actors
7209    * paint volume into screen coordinates to determine the clip region
7210    * for what needs to be redrawn in the next paint.
7211    *
7212    * Besides minimizing redundant work another reason for this
7213    * deferred design is that it's more likely we will be able to
7214    * determine the paint volume of an actor once we've finished
7215    * updating the scenegraph because its allocation should be up to
7216    * date. NB: If we can't determine an actors paint volume then we
7217    * can't automatically queue a clipped redraw which can make a big
7218    * difference to performance.
7219    *
7220    * So the control flow goes like this:
7221    * One of clutter_actor_queue_redraw,
7222    *        _clutter_actor_queue_redraw_with_clip
7223    *     or clutter_effect_queue_rerun
7224    *
7225    * then control moves to:
7226    *   _clutter_stage_queue_actor_redraw
7227    *
7228    * later during _clutter_stage_do_update, once relayouting is done
7229    * and the scenegraph has been updated we will call:
7230    * _clutter_stage_finish_queue_redraws
7231    *
7232    * _clutter_stage_finish_queue_redraws will call
7233    * _clutter_actor_finish_queue_redraw for each listed actor.
7234    * Note: actors *are* allowed to queue further redraws during this
7235    * process (considering clone actors or texture_new_from_actor which
7236    * respond to their source queueing a redraw by queuing a redraw
7237    * themselves). We repeat the process until the list is empty.
7238    *
7239    * This will result in the "queue-redraw" signal being fired for
7240    * each actor which will pass control to the default signal handler:
7241    * clutter_actor_real_queue_redraw
7242    *
7243    * This will bubble up to the stages handler:
7244    * clutter_stage_real_queue_redraw
7245    *
7246    * clutter_stage_real_queue_redraw will transform the actors paint
7247    * volume into screen space and add it as a clip region for the next
7248    * paint.
7249    */
7250
7251   /* ignore queueing a redraw for actors being destroyed */
7252   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7253     return;
7254
7255   stage = _clutter_actor_get_stage_internal (self);
7256
7257   /* Ignore queueing a redraw for actors not descended from a stage */
7258   if (stage == NULL)
7259     return;
7260
7261   /* ignore queueing a redraw on stages that are being destroyed */
7262   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7263     return;
7264
7265   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7266     {
7267       ClutterActorBox allocation_clip;
7268       ClutterVertex origin;
7269
7270       /* If the actor doesn't have a valid allocation then we will
7271        * queue a full stage redraw. */
7272       if (priv->needs_allocation)
7273         {
7274           /* NB: NULL denotes an undefined clip which will result in a
7275            * full redraw... */
7276           _clutter_actor_set_queue_redraw_clip (self, NULL);
7277           _clutter_actor_signal_queue_redraw (self, self);
7278           return;
7279         }
7280
7281       _clutter_paint_volume_init_static (&allocation_pv, self);
7282       pv = &allocation_pv;
7283
7284       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7285
7286       origin.x = allocation_clip.x1;
7287       origin.y = allocation_clip.y1;
7288       origin.z = 0;
7289       clutter_paint_volume_set_origin (pv, &origin);
7290       clutter_paint_volume_set_width (pv,
7291                                       allocation_clip.x2 - allocation_clip.x1);
7292       clutter_paint_volume_set_height (pv,
7293                                        allocation_clip.y2 -
7294                                        allocation_clip.y1);
7295       should_free_pv = TRUE;
7296     }
7297   else
7298     {
7299       pv = volume;
7300       should_free_pv = FALSE;
7301     }
7302
7303   self->priv->queue_redraw_entry =
7304     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7305                                        priv->queue_redraw_entry,
7306                                        self,
7307                                        pv);
7308
7309   if (should_free_pv)
7310     clutter_paint_volume_free (pv);
7311
7312   /* If this is the first redraw queued then we can directly use the
7313      effect parameter */
7314   if (!priv->is_dirty)
7315     priv->effect_to_redraw = effect;
7316   /* Otherwise we need to merge it with the existing effect parameter */
7317   else if (effect != NULL)
7318     {
7319       /* If there's already an effect then we need to use whichever is
7320          later in the chain of actors. Otherwise a full redraw has
7321          already been queued on the actor so we need to ignore the
7322          effect parameter */
7323       if (priv->effect_to_redraw != NULL)
7324         {
7325           if (priv->effects == NULL)
7326             g_warning ("Redraw queued with an effect that is "
7327                        "not applied to the actor");
7328           else
7329             {
7330               const GList *l;
7331
7332               for (l = _clutter_meta_group_peek_metas (priv->effects);
7333                    l != NULL;
7334                    l = l->next)
7335                 {
7336                   if (l->data == priv->effect_to_redraw ||
7337                       l->data == effect)
7338                     priv->effect_to_redraw = l->data;
7339                 }
7340             }
7341         }
7342     }
7343   else
7344     {
7345       /* If no effect is specified then we need to redraw the whole
7346          actor */
7347       priv->effect_to_redraw = NULL;
7348     }
7349
7350   priv->is_dirty = TRUE;
7351 }
7352
7353 /**
7354  * clutter_actor_queue_redraw:
7355  * @self: A #ClutterActor
7356  *
7357  * Queues up a redraw of an actor and any children. The redraw occurs
7358  * once the main loop becomes idle (after the current batch of events
7359  * has been processed, roughly).
7360  *
7361  * Applications rarely need to call this, as redraws are handled
7362  * automatically by modification functions.
7363  *
7364  * This function will not do anything if @self is not visible, or
7365  * if the actor is inside an invisible part of the scenegraph.
7366  *
7367  * Also be aware that painting is a NOP for actors with an opacity of
7368  * 0
7369  *
7370  * When you are implementing a custom actor you must queue a redraw
7371  * whenever some private state changes that will affect painting or
7372  * picking of your actor.
7373  */
7374 void
7375 clutter_actor_queue_redraw (ClutterActor *self)
7376 {
7377   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7378
7379   _clutter_actor_queue_redraw_full (self,
7380                                     0, /* flags */
7381                                     NULL, /* clip volume */
7382                                     NULL /* effect */);
7383 }
7384
7385 /*< private >
7386  * _clutter_actor_queue_redraw_with_clip:
7387  * @self: A #ClutterActor
7388  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7389  *   this queue redraw.
7390  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7391  *   redrawn or %NULL if you are just using a @flag to state your
7392  *   desired clipping.
7393  *
7394  * Queues up a clipped redraw of an actor and any children. The redraw
7395  * occurs once the main loop becomes idle (after the current batch of
7396  * events has been processed, roughly).
7397  *
7398  * If no flags are given the clip volume is defined by @volume
7399  * specified in actor coordinates and tells Clutter that only content
7400  * within this volume has been changed so Clutter can optionally
7401  * optimize the redraw.
7402  *
7403  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7404  * should be %NULL and this tells Clutter to use the actor's current
7405  * allocation as a clip box. This flag can only be used for 2D actors,
7406  * because any actor with depth may be projected outside its
7407  * allocation.
7408  *
7409  * Applications rarely need to call this, as redraws are handled
7410  * automatically by modification functions.
7411  *
7412  * This function will not do anything if @self is not visible, or if
7413  * the actor is inside an invisible part of the scenegraph.
7414  *
7415  * Also be aware that painting is a NOP for actors with an opacity of
7416  * 0
7417  *
7418  * When you are implementing a custom actor you must queue a redraw
7419  * whenever some private state changes that will affect painting or
7420  * picking of your actor.
7421  */
7422 void
7423 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7424                                        ClutterRedrawFlags  flags,
7425                                        ClutterPaintVolume *volume)
7426 {
7427   _clutter_actor_queue_redraw_full (self,
7428                                     flags, /* flags */
7429                                     volume, /* clip volume */
7430                                     NULL /* effect */);
7431 }
7432
7433 static void
7434 _clutter_actor_queue_only_relayout (ClutterActor *self)
7435 {
7436   ClutterActorPrivate *priv = self->priv;
7437
7438   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7439     return;
7440
7441   if (priv->needs_width_request &&
7442       priv->needs_height_request &&
7443       priv->needs_allocation)
7444     return; /* save some cpu cycles */
7445
7446 #if CLUTTER_ENABLE_DEBUG
7447   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7448     {
7449       g_warning ("The actor '%s' is currently inside an allocation "
7450                  "cycle; calling clutter_actor_queue_relayout() is "
7451                  "not recommended",
7452                  _clutter_actor_get_debug_name (self));
7453     }
7454 #endif /* CLUTTER_ENABLE_DEBUG */
7455
7456   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7457 }
7458
7459 /**
7460  * clutter_actor_queue_redraw_with_clip:
7461  * @self: a #ClutterActor
7462  * @clip: (allow-none): a rectangular clip region, or %NULL
7463  *
7464  * Queues a redraw on @self limited to a specific, actor-relative
7465  * rectangular area.
7466  *
7467  * If @clip is %NULL this function is equivalent to
7468  * clutter_actor_queue_redraw().
7469  *
7470  * Since: 1.10
7471  */
7472 void
7473 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7474                                       const cairo_rectangle_int_t *clip)
7475 {
7476   ClutterPaintVolume volume;
7477   ClutterVertex origin;
7478
7479   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7480
7481   if (clip == NULL)
7482     {
7483       clutter_actor_queue_redraw (self);
7484       return;
7485     }
7486
7487   _clutter_paint_volume_init_static (&volume, self);
7488
7489   origin.x = clip->x;
7490   origin.y = clip->y;
7491   origin.z = 0.0f;
7492
7493   clutter_paint_volume_set_origin (&volume, &origin);
7494   clutter_paint_volume_set_width (&volume, clip->width);
7495   clutter_paint_volume_set_height (&volume, clip->height);
7496
7497   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7498
7499   clutter_paint_volume_free (&volume);
7500 }
7501
7502 /**
7503  * clutter_actor_queue_relayout:
7504  * @self: A #ClutterActor
7505  *
7506  * Indicates that the actor's size request or other layout-affecting
7507  * properties may have changed. This function is used inside #ClutterActor
7508  * subclass implementations, not by applications directly.
7509  *
7510  * Queueing a new layout automatically queues a redraw as well.
7511  *
7512  * Since: 0.8
7513  */
7514 void
7515 clutter_actor_queue_relayout (ClutterActor *self)
7516 {
7517   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7518
7519   _clutter_actor_queue_only_relayout (self);
7520   clutter_actor_queue_redraw (self);
7521 }
7522
7523 /**
7524  * clutter_actor_get_preferred_size:
7525  * @self: a #ClutterActor
7526  * @min_width_p: (out) (allow-none): return location for the minimum
7527  *   width, or %NULL
7528  * @min_height_p: (out) (allow-none): return location for the minimum
7529  *   height, or %NULL
7530  * @natural_width_p: (out) (allow-none): return location for the natural
7531  *   width, or %NULL
7532  * @natural_height_p: (out) (allow-none): return location for the natural
7533  *   height, or %NULL
7534  *
7535  * Computes the preferred minimum and natural size of an actor, taking into
7536  * account the actor's geometry management (either height-for-width
7537  * or width-for-height).
7538  *
7539  * The width and height used to compute the preferred height and preferred
7540  * width are the actor's natural ones.
7541  *
7542  * If you need to control the height for the preferred width, or the width for
7543  * the preferred height, you should use clutter_actor_get_preferred_width()
7544  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7545  * geometry management using the #ClutterActor:request-mode property.
7546  *
7547  * Since: 0.8
7548  */
7549 void
7550 clutter_actor_get_preferred_size (ClutterActor *self,
7551                                   gfloat       *min_width_p,
7552                                   gfloat       *min_height_p,
7553                                   gfloat       *natural_width_p,
7554                                   gfloat       *natural_height_p)
7555 {
7556   ClutterActorPrivate *priv;
7557   gfloat min_width, min_height;
7558   gfloat natural_width, natural_height;
7559
7560   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7561
7562   priv = self->priv;
7563
7564   min_width = min_height = 0;
7565   natural_width = natural_height = 0;
7566
7567   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7568     {
7569       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7570       clutter_actor_get_preferred_width (self, -1,
7571                                          &min_width,
7572                                          &natural_width);
7573       clutter_actor_get_preferred_height (self, natural_width,
7574                                           &min_height,
7575                                           &natural_height);
7576     }
7577   else
7578     {
7579       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7580       clutter_actor_get_preferred_height (self, -1,
7581                                           &min_height,
7582                                           &natural_height);
7583       clutter_actor_get_preferred_width (self, natural_height,
7584                                          &min_width,
7585                                          &natural_width);
7586     }
7587
7588   if (min_width_p)
7589     *min_width_p = min_width;
7590
7591   if (min_height_p)
7592     *min_height_p = min_height;
7593
7594   if (natural_width_p)
7595     *natural_width_p = natural_width;
7596
7597   if (natural_height_p)
7598     *natural_height_p = natural_height;
7599 }
7600
7601 /*< private >
7602  * effective_align:
7603  * @align: a #ClutterActorAlign
7604  * @direction: a #ClutterTextDirection
7605  *
7606  * Retrieves the correct alignment depending on the text direction
7607  *
7608  * Return value: the effective alignment
7609  */
7610 static ClutterActorAlign
7611 effective_align (ClutterActorAlign    align,
7612                  ClutterTextDirection direction)
7613 {
7614   ClutterActorAlign res;
7615
7616   switch (align)
7617     {
7618     case CLUTTER_ACTOR_ALIGN_START:
7619       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7620           ? CLUTTER_ACTOR_ALIGN_END
7621           : CLUTTER_ACTOR_ALIGN_START;
7622       break;
7623
7624     case CLUTTER_ACTOR_ALIGN_END:
7625       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7626           ? CLUTTER_ACTOR_ALIGN_START
7627           : CLUTTER_ACTOR_ALIGN_END;
7628       break;
7629
7630     default:
7631       res = align;
7632       break;
7633     }
7634
7635   return res;
7636 }
7637
7638 static inline void
7639 adjust_for_margin (float  margin_start,
7640                    float  margin_end,
7641                    float *minimum_size,
7642                    float *natural_size,
7643                    float *allocated_start,
7644                    float *allocated_end)
7645 {
7646   *minimum_size -= (margin_start + margin_end);
7647   *natural_size -= (margin_start + margin_end);
7648   *allocated_start += margin_start;
7649   *allocated_end -= margin_end;
7650 }
7651
7652 static inline void
7653 adjust_for_alignment (ClutterActorAlign  alignment,
7654                       float              natural_size,
7655                       float             *allocated_start,
7656                       float             *allocated_end)
7657 {
7658   float allocated_size = *allocated_end - *allocated_start;
7659
7660   switch (alignment)
7661     {
7662     case CLUTTER_ACTOR_ALIGN_FILL:
7663       /* do nothing */
7664       break;
7665
7666     case CLUTTER_ACTOR_ALIGN_START:
7667       /* keep start */
7668       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7669       break;
7670
7671     case CLUTTER_ACTOR_ALIGN_END:
7672       if (allocated_size > natural_size)
7673         {
7674           *allocated_start += (allocated_size - natural_size);
7675           *allocated_end = *allocated_start + natural_size;
7676         }
7677       break;
7678
7679     case CLUTTER_ACTOR_ALIGN_CENTER:
7680       if (allocated_size > natural_size)
7681         {
7682           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7683           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7684         }
7685       break;
7686     }
7687 }
7688
7689 /*< private >
7690  * clutter_actor_adjust_width:
7691  * @self: a #ClutterActor
7692  * @minimum_width: (inout): the actor's preferred minimum width, which
7693  *   will be adjusted depending on the margin
7694  * @natural_width: (inout): the actor's preferred natural width, which
7695  *   will be adjusted depending on the margin
7696  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7697  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7698  *
7699  * Adjusts the preferred and allocated position and size of an actor,
7700  * depending on the margin and alignment properties.
7701  */
7702 static void
7703 clutter_actor_adjust_width (ClutterActor *self,
7704                             gfloat       *minimum_width,
7705                             gfloat       *natural_width,
7706                             gfloat       *adjusted_x1,
7707                             gfloat       *adjusted_x2)
7708 {
7709   ClutterTextDirection text_dir;
7710   const ClutterLayoutInfo *info;
7711
7712   info = _clutter_actor_get_layout_info_or_defaults (self);
7713   text_dir = clutter_actor_get_text_direction (self);
7714
7715   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7716
7717   /* this will tweak natural_width to remove the margin, so that
7718    * adjust_for_alignment() will use the correct size
7719    */
7720   adjust_for_margin (info->margin.left, info->margin.right,
7721                      minimum_width, natural_width,
7722                      adjusted_x1, adjusted_x2);
7723
7724   adjust_for_alignment (effective_align (info->x_align, text_dir),
7725                         *natural_width,
7726                         adjusted_x1, adjusted_x2);
7727 }
7728
7729 /*< private >
7730  * clutter_actor_adjust_height:
7731  * @self: a #ClutterActor
7732  * @minimum_height: (inout): the actor's preferred minimum height, which
7733  *   will be adjusted depending on the margin
7734  * @natural_height: (inout): the actor's preferred natural height, which
7735  *   will be adjusted depending on the margin
7736  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7737  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7738  *
7739  * Adjusts the preferred and allocated position and size of an actor,
7740  * depending on the margin and alignment properties.
7741  */
7742 static void
7743 clutter_actor_adjust_height (ClutterActor *self,
7744                              gfloat       *minimum_height,
7745                              gfloat       *natural_height,
7746                              gfloat       *adjusted_y1,
7747                              gfloat       *adjusted_y2)
7748 {
7749   const ClutterLayoutInfo *info;
7750
7751   info = _clutter_actor_get_layout_info_or_defaults (self);
7752
7753   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7754
7755   /* this will tweak natural_height to remove the margin, so that
7756    * adjust_for_alignment() will use the correct size
7757    */
7758   adjust_for_margin (info->margin.top, info->margin.bottom,
7759                      minimum_height, natural_height,
7760                      adjusted_y1,
7761                      adjusted_y2);
7762
7763   /* we don't use effective_align() here, because text direction
7764    * only affects the horizontal axis
7765    */
7766   adjust_for_alignment (info->y_align,
7767                         *natural_height,
7768                         adjusted_y1,
7769                         adjusted_y2);
7770
7771 }
7772
7773 /* looks for a cached size request for this for_size. If not
7774  * found, returns the oldest entry so it can be overwritten */
7775 static gboolean
7776 _clutter_actor_get_cached_size_request (gfloat         for_size,
7777                                         SizeRequest   *cached_size_requests,
7778                                         SizeRequest  **result)
7779 {
7780   guint i;
7781
7782   *result = &cached_size_requests[0];
7783
7784   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7785     {
7786       SizeRequest *sr;
7787
7788       sr = &cached_size_requests[i];
7789
7790       if (sr->age > 0 &&
7791           sr->for_size == for_size)
7792         {
7793           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7794           *result = sr;
7795           return TRUE;
7796         }
7797       else if (sr->age < (*result)->age)
7798         {
7799           *result = sr;
7800         }
7801     }
7802
7803   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7804
7805   return FALSE;
7806 }
7807
7808 /**
7809  * clutter_actor_get_preferred_width:
7810  * @self: A #ClutterActor
7811  * @for_height: available height when computing the preferred width,
7812  *   or a negative value to indicate that no height is defined
7813  * @min_width_p: (out) (allow-none): return location for minimum width,
7814  *   or %NULL
7815  * @natural_width_p: (out) (allow-none): return location for the natural
7816  *   width, or %NULL
7817  *
7818  * Computes the requested minimum and natural widths for an actor,
7819  * optionally depending on the specified height, or if they are
7820  * already computed, returns the cached values.
7821  *
7822  * An actor may not get its request - depending on the layout
7823  * manager that's in effect.
7824  *
7825  * A request should not incorporate the actor's scale or anchor point;
7826  * those transformations do not affect layout, only rendering.
7827  *
7828  * Since: 0.8
7829  */
7830 void
7831 clutter_actor_get_preferred_width (ClutterActor *self,
7832                                    gfloat        for_height,
7833                                    gfloat       *min_width_p,
7834                                    gfloat       *natural_width_p)
7835 {
7836   float request_min_width, request_natural_width;
7837   SizeRequest *cached_size_request;
7838   const ClutterLayoutInfo *info;
7839   ClutterActorPrivate *priv;
7840   gboolean found_in_cache;
7841
7842   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7843
7844   priv = self->priv;
7845
7846   info = _clutter_actor_get_layout_info_or_defaults (self);
7847
7848   /* we shortcircuit the case of a fixed size set using set_width() */
7849   if (priv->min_width_set && priv->natural_width_set)
7850     {
7851       if (min_width_p != NULL)
7852         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7853
7854       if (natural_width_p != NULL)
7855         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7856
7857       return;
7858     }
7859
7860   /* the remaining cases are:
7861    *
7862    *   - either min_width or natural_width have been set
7863    *   - neither min_width or natural_width have been set
7864    *
7865    * in both cases, we go through the cache (and through the actor in case
7866    * of cache misses) and determine the authoritative value depending on
7867    * the *_set flags.
7868    */
7869
7870   if (!priv->needs_width_request)
7871     {
7872       found_in_cache =
7873         _clutter_actor_get_cached_size_request (for_height,
7874                                                 priv->width_requests,
7875                                                 &cached_size_request);
7876     }
7877   else
7878     {
7879       /* if the actor needs a width request we use the first slot */
7880       found_in_cache = FALSE;
7881       cached_size_request = &priv->width_requests[0];
7882     }
7883
7884   if (!found_in_cache)
7885     {
7886       gfloat minimum_width, natural_width;
7887       ClutterActorClass *klass;
7888
7889       minimum_width = natural_width = 0;
7890
7891       /* adjust for the margin */
7892       if (for_height >= 0)
7893         {
7894           for_height -= (info->margin.top + info->margin.bottom);
7895           if (for_height < 0)
7896             for_height = 0;
7897         }
7898
7899       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7900
7901       klass = CLUTTER_ACTOR_GET_CLASS (self);
7902       klass->get_preferred_width (self, for_height,
7903                                   &minimum_width,
7904                                   &natural_width);
7905
7906       /* adjust for the margin */
7907       minimum_width += (info->margin.left + info->margin.right);
7908       natural_width += (info->margin.left + info->margin.right);
7909
7910       /* Due to accumulated float errors, it's better not to warn
7911        * on this, but just fix it.
7912        */
7913       if (natural_width < minimum_width)
7914         natural_width = minimum_width;
7915
7916       cached_size_request->min_size = minimum_width;
7917       cached_size_request->natural_size = natural_width;
7918       cached_size_request->for_size = for_height;
7919       cached_size_request->age = priv->cached_width_age;
7920
7921       priv->cached_width_age += 1;
7922       priv->needs_width_request = FALSE;
7923     }
7924
7925   if (!priv->min_width_set)
7926     request_min_width = cached_size_request->min_size;
7927   else
7928     request_min_width = info->min_width;
7929
7930   if (!priv->natural_width_set)
7931     request_natural_width = cached_size_request->natural_size;
7932   else
7933     request_natural_width = info->natural_width;
7934
7935   if (min_width_p)
7936     *min_width_p = request_min_width;
7937
7938   if (natural_width_p)
7939     *natural_width_p = request_natural_width;
7940 }
7941
7942 /**
7943  * clutter_actor_get_preferred_height:
7944  * @self: A #ClutterActor
7945  * @for_width: available width to assume in computing desired height,
7946  *   or a negative value to indicate that no width is defined
7947  * @min_height_p: (out) (allow-none): return location for minimum height,
7948  *   or %NULL
7949  * @natural_height_p: (out) (allow-none): return location for natural
7950  *   height, or %NULL
7951  *
7952  * Computes the requested minimum and natural heights for an actor,
7953  * or if they are already computed, returns the cached values.
7954  *
7955  * An actor may not get its request - depending on the layout
7956  * manager that's in effect.
7957  *
7958  * A request should not incorporate the actor's scale or anchor point;
7959  * those transformations do not affect layout, only rendering.
7960  *
7961  * Since: 0.8
7962  */
7963 void
7964 clutter_actor_get_preferred_height (ClutterActor *self,
7965                                     gfloat        for_width,
7966                                     gfloat       *min_height_p,
7967                                     gfloat       *natural_height_p)
7968 {
7969   float request_min_height, request_natural_height;
7970   SizeRequest *cached_size_request;
7971   const ClutterLayoutInfo *info;
7972   ClutterActorPrivate *priv;
7973   gboolean found_in_cache;
7974
7975   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7976
7977   priv = self->priv;
7978
7979   info = _clutter_actor_get_layout_info_or_defaults (self);
7980
7981   /* we shortcircuit the case of a fixed size set using set_height() */
7982   if (priv->min_height_set && priv->natural_height_set)
7983     {
7984       if (min_height_p != NULL)
7985         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7986
7987       if (natural_height_p != NULL)
7988         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7989
7990       return;
7991     }
7992
7993   /* the remaining cases are:
7994    *
7995    *   - either min_height or natural_height have been set
7996    *   - neither min_height or natural_height have been set
7997    *
7998    * in both cases, we go through the cache (and through the actor in case
7999    * of cache misses) and determine the authoritative value depending on
8000    * the *_set flags.
8001    */
8002
8003   if (!priv->needs_height_request)
8004     {
8005       found_in_cache =
8006         _clutter_actor_get_cached_size_request (for_width,
8007                                                 priv->height_requests,
8008                                                 &cached_size_request);
8009     }
8010   else
8011     {
8012       found_in_cache = FALSE;
8013       cached_size_request = &priv->height_requests[0];
8014     }
8015
8016   if (!found_in_cache)
8017     {
8018       gfloat minimum_height, natural_height;
8019       ClutterActorClass *klass;
8020
8021       minimum_height = natural_height = 0;
8022
8023       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8024
8025       /* adjust for margin */
8026       if (for_width >= 0)
8027         {
8028           for_width -= (info->margin.left + info->margin.right);
8029           if (for_width < 0)
8030             for_width = 0;
8031         }
8032
8033       klass = CLUTTER_ACTOR_GET_CLASS (self);
8034       klass->get_preferred_height (self, for_width,
8035                                    &minimum_height,
8036                                    &natural_height);
8037
8038       /* adjust for margin */
8039       minimum_height += (info->margin.top + info->margin.bottom);
8040       natural_height += (info->margin.top + info->margin.bottom);
8041
8042       /* Due to accumulated float errors, it's better not to warn
8043        * on this, but just fix it.
8044        */
8045       if (natural_height < minimum_height)
8046         natural_height = minimum_height;
8047
8048       cached_size_request->min_size = minimum_height;
8049       cached_size_request->natural_size = natural_height;
8050       cached_size_request->for_size = for_width;
8051       cached_size_request->age = priv->cached_height_age;
8052
8053       priv->cached_height_age += 1;
8054       priv->needs_height_request = FALSE;
8055     }
8056
8057   if (!priv->min_height_set)
8058     request_min_height = cached_size_request->min_size;
8059   else
8060     request_min_height = info->min_height;
8061
8062   if (!priv->natural_height_set)
8063     request_natural_height = cached_size_request->natural_size;
8064   else
8065     request_natural_height = info->natural_height;
8066
8067   if (min_height_p)
8068     *min_height_p = request_min_height;
8069
8070   if (natural_height_p)
8071     *natural_height_p = request_natural_height;
8072 }
8073
8074 /**
8075  * clutter_actor_get_allocation_box:
8076  * @self: A #ClutterActor
8077  * @box: (out): the function fills this in with the actor's allocation
8078  *
8079  * Gets the layout box an actor has been assigned. The allocation can
8080  * only be assumed valid inside a paint() method; anywhere else, it
8081  * may be out-of-date.
8082  *
8083  * An allocation does not incorporate the actor's scale or anchor point;
8084  * those transformations do not affect layout, only rendering.
8085  *
8086  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8087  * of functions inside the implementation of the get_preferred_width()
8088  * or get_preferred_height() virtual functions.</note>
8089  *
8090  * Since: 0.8
8091  */
8092 void
8093 clutter_actor_get_allocation_box (ClutterActor    *self,
8094                                   ClutterActorBox *box)
8095 {
8096   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8097
8098   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8099    * which limits calling get_allocation to inside paint() basically; or
8100    * we can 2) force a layout, which could be expensive if someone calls
8101    * get_allocation somewhere silly; or we can 3) just return the latest
8102    * value, allowing it to be out-of-date, and assume people know what
8103    * they are doing.
8104    *
8105    * The least-surprises approach that keeps existing code working is
8106    * likely to be 2). People can end up doing some inefficient things,
8107    * though, and in general code that requires 2) is probably broken.
8108    */
8109
8110   /* this implements 2) */
8111   if (G_UNLIKELY (self->priv->needs_allocation))
8112     {
8113       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8114
8115       /* do not queue a relayout on an unparented actor */
8116       if (stage)
8117         _clutter_stage_maybe_relayout (stage);
8118     }
8119
8120   /* commenting out the code above and just keeping this assigment
8121    * implements 3)
8122    */
8123   *box = self->priv->allocation;
8124 }
8125
8126 /**
8127  * clutter_actor_get_allocation_geometry:
8128  * @self: A #ClutterActor
8129  * @geom: (out): allocation geometry in pixels
8130  *
8131  * Gets the layout box an actor has been assigned.  The allocation can
8132  * only be assumed valid inside a paint() method; anywhere else, it
8133  * may be out-of-date.
8134  *
8135  * An allocation does not incorporate the actor's scale or anchor point;
8136  * those transformations do not affect layout, only rendering.
8137  *
8138  * The returned rectangle is in pixels.
8139  *
8140  * Since: 0.8
8141  */
8142 void
8143 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8144                                        ClutterGeometry *geom)
8145 {
8146   ClutterActorBox box;
8147
8148   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8149   g_return_if_fail (geom != NULL);
8150
8151   clutter_actor_get_allocation_box (self, &box);
8152
8153   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8154   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8155   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8156   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8157 }
8158
8159 static void
8160 clutter_actor_update_constraints (ClutterActor    *self,
8161                                   ClutterActorBox *allocation)
8162 {
8163   ClutterActorPrivate *priv = self->priv;
8164   const GList *constraints, *l;
8165
8166   if (priv->constraints == NULL)
8167     return;
8168
8169   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8170   for (l = constraints; l != NULL; l = l->next)
8171     {
8172       ClutterConstraint *constraint = l->data;
8173       ClutterActorMeta *meta = l->data;
8174
8175       if (clutter_actor_meta_get_enabled (meta))
8176         {
8177           _clutter_constraint_update_allocation (constraint,
8178                                                  self,
8179                                                  allocation);
8180
8181           CLUTTER_NOTE (LAYOUT,
8182                         "Allocation of '%s' after constraint '%s': "
8183                         "{ %.2f, %.2f, %.2f, %.2f }",
8184                         _clutter_actor_get_debug_name (self),
8185                         _clutter_actor_meta_get_debug_name (meta),
8186                         allocation->x1,
8187                         allocation->y1,
8188                         allocation->x2,
8189                         allocation->y2);
8190         }
8191     }
8192 }
8193
8194 /*< private >
8195  * clutter_actor_adjust_allocation:
8196  * @self: a #ClutterActor
8197  * @allocation: (inout): the allocation to adjust
8198  *
8199  * Adjusts the passed allocation box taking into account the actor's
8200  * layout information, like alignment, expansion, and margin.
8201  */
8202 static void
8203 clutter_actor_adjust_allocation (ClutterActor    *self,
8204                                  ClutterActorBox *allocation)
8205 {
8206   ClutterActorBox adj_allocation;
8207   float alloc_width, alloc_height;
8208   float min_width, min_height;
8209   float nat_width, nat_height;
8210   ClutterRequestMode req_mode;
8211
8212   adj_allocation = *allocation;
8213
8214   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8215
8216   /* we want to hit the cache, so we use the public API */
8217   req_mode = clutter_actor_get_request_mode (self);
8218
8219   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8220     {
8221       clutter_actor_get_preferred_width (self, -1,
8222                                          &min_width,
8223                                          &nat_width);
8224       clutter_actor_get_preferred_height (self, alloc_width,
8225                                           &min_height,
8226                                           &nat_height);
8227     }
8228   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8229     {
8230       clutter_actor_get_preferred_height (self, -1,
8231                                           &min_height,
8232                                           &nat_height);
8233       clutter_actor_get_preferred_height (self, alloc_height,
8234                                           &min_width,
8235                                           &nat_width);
8236     }
8237
8238 #ifdef CLUTTER_ENABLE_DEBUG
8239   /* warn about underallocations */
8240   if (_clutter_diagnostic_enabled () &&
8241       (floorf (min_width - alloc_width) > 0 ||
8242        floorf (min_height - alloc_height) > 0))
8243     {
8244       ClutterActor *parent = clutter_actor_get_parent (self);
8245
8246       /* the only actors that are allowed to be underallocated are the Stage,
8247        * as it doesn't have an implicit size, and Actors that specifically
8248        * told us that they want to opt-out from layout control mechanisms
8249        * through the NO_LAYOUT escape hatch.
8250        */
8251       if (parent != NULL &&
8252           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8253         {
8254           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8255                      "of %.2f x %.2f from its parent actor '%s', but its "
8256                      "requested minimum size is of %.2f x %.2f",
8257                      _clutter_actor_get_debug_name (self),
8258                      alloc_width, alloc_height,
8259                      _clutter_actor_get_debug_name (parent),
8260                      min_width, min_height);
8261         }
8262     }
8263 #endif
8264
8265   clutter_actor_adjust_width (self,
8266                               &min_width,
8267                               &nat_width,
8268                               &adj_allocation.x1,
8269                               &adj_allocation.x2);
8270
8271   clutter_actor_adjust_height (self,
8272                                &min_height,
8273                                &nat_height,
8274                                &adj_allocation.y1,
8275                                &adj_allocation.y2);
8276
8277   /* we maintain the invariant that an allocation cannot be adjusted
8278    * to be outside the parent-given box
8279    */
8280   if (adj_allocation.x1 < allocation->x1 ||
8281       adj_allocation.y1 < allocation->y1 ||
8282       adj_allocation.x2 > allocation->x2 ||
8283       adj_allocation.y2 > allocation->y2)
8284     {
8285       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8286                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8287                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8288                  _clutter_actor_get_debug_name (self),
8289                  adj_allocation.x1, adj_allocation.y1,
8290                  adj_allocation.x2 - adj_allocation.x1,
8291                  adj_allocation.y2 - adj_allocation.y1,
8292                  allocation->x1, allocation->y1,
8293                  allocation->x2 - allocation->x1,
8294                  allocation->y2 - allocation->y1);
8295       return;
8296     }
8297
8298   *allocation = adj_allocation;
8299 }
8300
8301 /**
8302  * clutter_actor_allocate:
8303  * @self: A #ClutterActor
8304  * @box: new allocation of the actor, in parent-relative coordinates
8305  * @flags: flags that control the allocation
8306  *
8307  * Called by the parent of an actor to assign the actor its size.
8308  * Should never be called by applications (except when implementing
8309  * a container or layout manager).
8310  *
8311  * Actors can know from their allocation box whether they have moved
8312  * with respect to their parent actor. The @flags parameter describes
8313  * additional information about the allocation, for instance whether
8314  * the parent has moved with respect to the stage, for example because
8315  * a grandparent's origin has moved.
8316  *
8317  * Since: 0.8
8318  */
8319 void
8320 clutter_actor_allocate (ClutterActor           *self,
8321                         const ClutterActorBox  *box,
8322                         ClutterAllocationFlags  flags)
8323 {
8324   ClutterActorPrivate *priv;
8325   ClutterActorClass *klass;
8326   ClutterActorBox old_allocation, real_allocation;
8327   gboolean origin_changed, child_moved, size_changed;
8328   gboolean stage_allocation_changed;
8329
8330   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8331   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8332     {
8333       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8334                  "which isn't a descendent of the stage!\n",
8335                  self, _clutter_actor_get_debug_name (self));
8336       return;
8337     }
8338
8339   priv = self->priv;
8340
8341   old_allocation = priv->allocation;
8342   real_allocation = *box;
8343
8344   /* constraints are allowed to modify the allocation only here; we do
8345    * this prior to all the other checks so that we can bail out if the
8346    * allocation did not change
8347    */
8348   clutter_actor_update_constraints (self, &real_allocation);
8349
8350   /* adjust the allocation depending on the align/margin properties */
8351   clutter_actor_adjust_allocation (self, &real_allocation);
8352
8353   if (real_allocation.x2 < real_allocation.x1 ||
8354       real_allocation.y2 < real_allocation.y1)
8355     {
8356       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8357                  _clutter_actor_get_debug_name (self),
8358                  real_allocation.x2 - real_allocation.x1,
8359                  real_allocation.y2 - real_allocation.y1);
8360     }
8361
8362   /* we allow 0-sized actors, but not negative-sized ones */
8363   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8364   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8365
8366   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8367
8368   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8369                  real_allocation.y1 != old_allocation.y1);
8370
8371   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8372                   real_allocation.y2 != old_allocation.y2);
8373
8374   if (origin_changed || child_moved || size_changed)
8375     stage_allocation_changed = TRUE;
8376   else
8377     stage_allocation_changed = FALSE;
8378
8379   /* If we get an allocation "out of the blue"
8380    * (we did not queue relayout), then we want to
8381    * ignore it. But if we have needs_allocation set,
8382    * we want to guarantee that allocate() virtual
8383    * method is always called, i.e. that queue_relayout()
8384    * always results in an allocate() invocation on
8385    * an actor.
8386    *
8387    * The optimization here is to avoid re-allocating
8388    * actors that did not queue relayout and were
8389    * not moved.
8390    */
8391   if (!priv->needs_allocation && !stage_allocation_changed)
8392     {
8393       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8394       return;
8395     }
8396
8397   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8398    * clutter_actor_allocate(), it indicates whether the parent has its
8399    * absolute origin moved; when passed in to ClutterActor::allocate()
8400    * virtual method though, it indicates whether the child has its
8401    * absolute origin moved.  So we set it when child_moved is TRUE
8402    */
8403   if (child_moved)
8404     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8405
8406   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8407
8408   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8409                 _clutter_actor_get_debug_name (self));
8410
8411   klass = CLUTTER_ACTOR_GET_CLASS (self);
8412   klass->allocate (self, &real_allocation, flags);
8413
8414   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8415
8416   if (stage_allocation_changed)
8417     clutter_actor_queue_redraw (self);
8418 }
8419
8420 /**
8421  * clutter_actor_set_allocation:
8422  * @self: a #ClutterActor
8423  * @box: a #ClutterActorBox
8424  * @flags: allocation flags
8425  *
8426  * Stores the allocation of @self as defined by @box.
8427  *
8428  * This function can only be called from within the implementation of
8429  * the #ClutterActorClass.allocate() virtual function.
8430  *
8431  * The allocation should have been adjusted to take into account constraints,
8432  * alignment, and margin properties. If you are implementing a #ClutterActor
8433  * subclass that provides its own layout management policy for its children
8434  * instead of using a #ClutterLayoutManager delegate, you should not call
8435  * this function on the children of @self; instead, you should call
8436  * clutter_actor_allocate(), which will adjust the allocation box for
8437  * you.
8438  *
8439  * This function should only be used by subclasses of #ClutterActor
8440  * that wish to store their allocation but cannot chain up to the
8441  * parent's implementation; the default implementation of the
8442  * #ClutterActorClass.allocate() virtual function will call this
8443  * function.
8444  *
8445  * It is important to note that, while chaining up was the recommended
8446  * behaviour for #ClutterActor subclasses prior to the introduction of
8447  * this function, it is recommended to call clutter_actor_set_allocation()
8448  * instead.
8449  *
8450  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8451  * to handle the allocation of its children, this function will call
8452  * the clutter_layout_manager_allocate() function only if the
8453  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8454  * expected that the subclass will call clutter_layout_manager_allocate()
8455  * by itself. For instance, the following code:
8456  *
8457  * |[
8458  * static void
8459  * my_actor_allocate (ClutterActor *actor,
8460  *                    const ClutterActorBox *allocation,
8461  *                    ClutterAllocationFlags flags)
8462  * {
8463  *   ClutterActorBox new_alloc;
8464  *   ClutterAllocationFlags new_flags;
8465  *
8466  *   adjust_allocation (allocation, &amp;new_alloc);
8467  *
8468  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8469  *
8470  *   /&ast; this will use the layout manager set on the actor &ast;/
8471  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8472  * }
8473  * ]|
8474  *
8475  * is equivalent to this:
8476  *
8477  * |[
8478  * static void
8479  * my_actor_allocate (ClutterActor *actor,
8480  *                    const ClutterActorBox *allocation,
8481  *                    ClutterAllocationFlags flags)
8482  * {
8483  *   ClutterLayoutManager *layout;
8484  *   ClutterActorBox new_alloc;
8485  *
8486  *   adjust_allocation (allocation, &amp;new_alloc);
8487  *
8488  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8489  *
8490  *   layout = clutter_actor_get_layout_manager (actor);
8491  *   clutter_layout_manager_allocate (layout,
8492  *                                    CLUTTER_CONTAINER (actor),
8493  *                                    &amp;new_alloc,
8494  *                                    flags);
8495  * }
8496  * ]|
8497  *
8498  * Since: 1.10
8499  */
8500 void
8501 clutter_actor_set_allocation (ClutterActor           *self,
8502                               const ClutterActorBox  *box,
8503                               ClutterAllocationFlags  flags)
8504 {
8505   ClutterActorPrivate *priv;
8506   gboolean changed;
8507
8508   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8509   g_return_if_fail (box != NULL);
8510
8511   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8512     {
8513       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8514                   "can only be called from within the implementation of "
8515                   "the ClutterActor::allocate() virtual function.");
8516       return;
8517     }
8518
8519   priv = self->priv;
8520
8521   g_object_freeze_notify (G_OBJECT (self));
8522
8523   changed = clutter_actor_set_allocation_internal (self, box, flags);
8524
8525   /* we allocate our children before we notify changes in our geometry,
8526    * so that people connecting to properties will be able to get valid
8527    * data out of the sub-tree of the scene graph that has this actor at
8528    * the root.
8529    */
8530   clutter_actor_maybe_layout_children (self, box, flags);
8531
8532   if (changed)
8533     {
8534       ClutterActorBox signal_box = priv->allocation;
8535       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8536
8537       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8538                      &signal_box,
8539                      signal_flags);
8540     }
8541
8542   g_object_thaw_notify (G_OBJECT (self));
8543 }
8544
8545 /**
8546  * clutter_actor_set_geometry:
8547  * @self: A #ClutterActor
8548  * @geometry: A #ClutterGeometry
8549  *
8550  * Sets the actor's fixed position and forces its minimum and natural
8551  * size, in pixels. This means the untransformed actor will have the
8552  * given geometry. This is the same as calling clutter_actor_set_position()
8553  * and clutter_actor_set_size().
8554  *
8555  * Deprecated: 1.10: Use clutter_actor_set_position() and
8556  *   clutter_actor_set_size() instead.
8557  */
8558 void
8559 clutter_actor_set_geometry (ClutterActor          *self,
8560                             const ClutterGeometry *geometry)
8561 {
8562   g_object_freeze_notify (G_OBJECT (self));
8563
8564   clutter_actor_set_position (self, geometry->x, geometry->y);
8565   clutter_actor_set_size (self, geometry->width, geometry->height);
8566
8567   g_object_thaw_notify (G_OBJECT (self));
8568 }
8569
8570 /**
8571  * clutter_actor_get_geometry:
8572  * @self: A #ClutterActor
8573  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8574  *
8575  * Gets the size and position of an actor relative to its parent
8576  * actor. This is the same as calling clutter_actor_get_position() and
8577  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8578  * requested size and position if the actor's allocation is invalid.
8579  *
8580  * Deprecated: 1.10: Use clutter_actor_get_position() and
8581  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8582  *   instead.
8583  */
8584 void
8585 clutter_actor_get_geometry (ClutterActor    *self,
8586                             ClutterGeometry *geometry)
8587 {
8588   gfloat x, y, width, height;
8589
8590   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8591   g_return_if_fail (geometry != NULL);
8592
8593   clutter_actor_get_position (self, &x, &y);
8594   clutter_actor_get_size (self, &width, &height);
8595
8596   geometry->x = (int) x;
8597   geometry->y = (int) y;
8598   geometry->width = (int) width;
8599   geometry->height = (int) height;
8600 }
8601
8602 /**
8603  * clutter_actor_set_position:
8604  * @self: A #ClutterActor
8605  * @x: New left position of actor in pixels.
8606  * @y: New top position of actor in pixels.
8607  *
8608  * Sets the actor's fixed position in pixels relative to any parent
8609  * actor.
8610  *
8611  * If a layout manager is in use, this position will override the
8612  * layout manager and force a fixed position.
8613  */
8614 void
8615 clutter_actor_set_position (ClutterActor *self,
8616                             gfloat        x,
8617                             gfloat        y)
8618 {
8619   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8620
8621   g_object_freeze_notify (G_OBJECT (self));
8622
8623   clutter_actor_set_x (self, x);
8624   clutter_actor_set_y (self, y);
8625
8626   g_object_thaw_notify (G_OBJECT (self));
8627 }
8628
8629 /**
8630  * clutter_actor_get_fixed_position_set:
8631  * @self: A #ClutterActor
8632  *
8633  * Checks whether an actor has a fixed position set (and will thus be
8634  * unaffected by any layout manager).
8635  *
8636  * Return value: %TRUE if the fixed position is set on the actor
8637  *
8638  * Since: 0.8
8639  */
8640 gboolean
8641 clutter_actor_get_fixed_position_set (ClutterActor *self)
8642 {
8643   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8644
8645   return self->priv->position_set;
8646 }
8647
8648 /**
8649  * clutter_actor_set_fixed_position_set:
8650  * @self: A #ClutterActor
8651  * @is_set: whether to use fixed position
8652  *
8653  * Sets whether an actor has a fixed position set (and will thus be
8654  * unaffected by any layout manager).
8655  *
8656  * Since: 0.8
8657  */
8658 void
8659 clutter_actor_set_fixed_position_set (ClutterActor *self,
8660                                       gboolean      is_set)
8661 {
8662   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8663
8664   if (self->priv->position_set == (is_set != FALSE))
8665     return;
8666
8667   self->priv->position_set = is_set != FALSE;
8668   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8669
8670   clutter_actor_queue_relayout (self);
8671 }
8672
8673 /**
8674  * clutter_actor_move_by:
8675  * @self: A #ClutterActor
8676  * @dx: Distance to move Actor on X axis.
8677  * @dy: Distance to move Actor on Y axis.
8678  *
8679  * Moves an actor by the specified distance relative to its current
8680  * position in pixels.
8681  *
8682  * This function modifies the fixed position of an actor and thus removes
8683  * it from any layout management. Another way to move an actor is with an
8684  * anchor point, see clutter_actor_set_anchor_point().
8685  *
8686  * Since: 0.2
8687  */
8688 void
8689 clutter_actor_move_by (ClutterActor *self,
8690                        gfloat        dx,
8691                        gfloat        dy)
8692 {
8693   const ClutterLayoutInfo *info;
8694   gfloat x, y;
8695
8696   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8697
8698   info = _clutter_actor_get_layout_info_or_defaults (self);
8699   x = info->fixed_x;
8700   y = info->fixed_y;
8701
8702   clutter_actor_set_position (self, x + dx, y + dy);
8703 }
8704
8705 static void
8706 clutter_actor_set_min_width (ClutterActor *self,
8707                              gfloat        min_width)
8708 {
8709   ClutterActorPrivate *priv = self->priv;
8710   ClutterActorBox old = { 0, };
8711   ClutterLayoutInfo *info;
8712
8713   /* if we are setting the size on a top-level actor and the
8714    * backend only supports static top-levels (e.g. framebuffers)
8715    * then we ignore the passed value and we override it with
8716    * the stage implementation's preferred size.
8717    */
8718   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8719       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8720     return;
8721
8722   info = _clutter_actor_get_layout_info (self);
8723
8724   if (priv->min_width_set && min_width == info->min_width)
8725     return;
8726
8727   g_object_freeze_notify (G_OBJECT (self));
8728
8729   clutter_actor_store_old_geometry (self, &old);
8730
8731   info->min_width = min_width;
8732   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8733   clutter_actor_set_min_width_set (self, TRUE);
8734
8735   clutter_actor_notify_if_geometry_changed (self, &old);
8736
8737   g_object_thaw_notify (G_OBJECT (self));
8738
8739   clutter_actor_queue_relayout (self);
8740 }
8741
8742 static void
8743 clutter_actor_set_min_height (ClutterActor *self,
8744                               gfloat        min_height)
8745
8746 {
8747   ClutterActorPrivate *priv = self->priv;
8748   ClutterActorBox old = { 0, };
8749   ClutterLayoutInfo *info;
8750
8751   /* if we are setting the size on a top-level actor and the
8752    * backend only supports static top-levels (e.g. framebuffers)
8753    * then we ignore the passed value and we override it with
8754    * the stage implementation's preferred size.
8755    */
8756   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8757       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8758     return;
8759
8760   info = _clutter_actor_get_layout_info (self);
8761
8762   if (priv->min_height_set && min_height == info->min_height)
8763     return;
8764
8765   g_object_freeze_notify (G_OBJECT (self));
8766
8767   clutter_actor_store_old_geometry (self, &old);
8768
8769   info->min_height = min_height;
8770   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8771   clutter_actor_set_min_height_set (self, TRUE);
8772
8773   clutter_actor_notify_if_geometry_changed (self, &old);
8774
8775   g_object_thaw_notify (G_OBJECT (self));
8776
8777   clutter_actor_queue_relayout (self);
8778 }
8779
8780 static void
8781 clutter_actor_set_natural_width (ClutterActor *self,
8782                                  gfloat        natural_width)
8783 {
8784   ClutterActorPrivate *priv = self->priv;
8785   ClutterActorBox old = { 0, };
8786   ClutterLayoutInfo *info;
8787
8788   /* if we are setting the size on a top-level actor and the
8789    * backend only supports static top-levels (e.g. framebuffers)
8790    * then we ignore the passed value and we override it with
8791    * the stage implementation's preferred size.
8792    */
8793   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8794       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8795     return;
8796
8797   info = _clutter_actor_get_layout_info (self);
8798
8799   if (priv->natural_width_set && natural_width == info->natural_width)
8800     return;
8801
8802   g_object_freeze_notify (G_OBJECT (self));
8803
8804   clutter_actor_store_old_geometry (self, &old);
8805
8806   info->natural_width = natural_width;
8807   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8808   clutter_actor_set_natural_width_set (self, TRUE);
8809
8810   clutter_actor_notify_if_geometry_changed (self, &old);
8811
8812   g_object_thaw_notify (G_OBJECT (self));
8813
8814   clutter_actor_queue_relayout (self);
8815 }
8816
8817 static void
8818 clutter_actor_set_natural_height (ClutterActor *self,
8819                                   gfloat        natural_height)
8820 {
8821   ClutterActorPrivate *priv = self->priv;
8822   ClutterActorBox old = { 0, };
8823   ClutterLayoutInfo *info;
8824
8825   /* if we are setting the size on a top-level actor and the
8826    * backend only supports static top-levels (e.g. framebuffers)
8827    * then we ignore the passed value and we override it with
8828    * the stage implementation's preferred size.
8829    */
8830   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8831       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8832     return;
8833
8834   info = _clutter_actor_get_layout_info (self);
8835
8836   if (priv->natural_height_set && natural_height == info->natural_height)
8837     return;
8838
8839   g_object_freeze_notify (G_OBJECT (self));
8840
8841   clutter_actor_store_old_geometry (self, &old);
8842
8843   info->natural_height = natural_height;
8844   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8845   clutter_actor_set_natural_height_set (self, TRUE);
8846
8847   clutter_actor_notify_if_geometry_changed (self, &old);
8848
8849   g_object_thaw_notify (G_OBJECT (self));
8850
8851   clutter_actor_queue_relayout (self);
8852 }
8853
8854 static void
8855 clutter_actor_set_min_width_set (ClutterActor *self,
8856                                  gboolean      use_min_width)
8857 {
8858   ClutterActorPrivate *priv = self->priv;
8859   ClutterActorBox old = { 0, };
8860
8861   if (priv->min_width_set == (use_min_width != FALSE))
8862     return;
8863
8864   clutter_actor_store_old_geometry (self, &old);
8865
8866   priv->min_width_set = use_min_width != FALSE;
8867   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8868
8869   clutter_actor_notify_if_geometry_changed (self, &old);
8870
8871   clutter_actor_queue_relayout (self);
8872 }
8873
8874 static void
8875 clutter_actor_set_min_height_set (ClutterActor *self,
8876                                   gboolean      use_min_height)
8877 {
8878   ClutterActorPrivate *priv = self->priv;
8879   ClutterActorBox old = { 0, };
8880
8881   if (priv->min_height_set == (use_min_height != FALSE))
8882     return;
8883
8884   clutter_actor_store_old_geometry (self, &old);
8885
8886   priv->min_height_set = use_min_height != FALSE;
8887   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8888
8889   clutter_actor_notify_if_geometry_changed (self, &old);
8890
8891   clutter_actor_queue_relayout (self);
8892 }
8893
8894 static void
8895 clutter_actor_set_natural_width_set (ClutterActor *self,
8896                                      gboolean      use_natural_width)
8897 {
8898   ClutterActorPrivate *priv = self->priv;
8899   ClutterActorBox old = { 0, };
8900
8901   if (priv->natural_width_set == (use_natural_width != FALSE))
8902     return;
8903
8904   clutter_actor_store_old_geometry (self, &old);
8905
8906   priv->natural_width_set = use_natural_width != FALSE;
8907   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8908
8909   clutter_actor_notify_if_geometry_changed (self, &old);
8910
8911   clutter_actor_queue_relayout (self);
8912 }
8913
8914 static void
8915 clutter_actor_set_natural_height_set (ClutterActor *self,
8916                                       gboolean      use_natural_height)
8917 {
8918   ClutterActorPrivate *priv = self->priv;
8919   ClutterActorBox old = { 0, };
8920
8921   if (priv->natural_height_set == (use_natural_height != FALSE))
8922     return;
8923
8924   clutter_actor_store_old_geometry (self, &old);
8925
8926   priv->natural_height_set = use_natural_height != FALSE;
8927   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8928
8929   clutter_actor_notify_if_geometry_changed (self, &old);
8930
8931   clutter_actor_queue_relayout (self);
8932 }
8933
8934 /**
8935  * clutter_actor_set_request_mode:
8936  * @self: a #ClutterActor
8937  * @mode: the request mode
8938  *
8939  * Sets the geometry request mode of @self.
8940  *
8941  * The @mode determines the order for invoking
8942  * clutter_actor_get_preferred_width() and
8943  * clutter_actor_get_preferred_height()
8944  *
8945  * Since: 1.2
8946  */
8947 void
8948 clutter_actor_set_request_mode (ClutterActor       *self,
8949                                 ClutterRequestMode  mode)
8950 {
8951   ClutterActorPrivate *priv;
8952
8953   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8954
8955   priv = self->priv;
8956
8957   if (priv->request_mode == mode)
8958     return;
8959
8960   priv->request_mode = mode;
8961
8962   priv->needs_width_request = TRUE;
8963   priv->needs_height_request = TRUE;
8964
8965   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8966
8967   clutter_actor_queue_relayout (self);
8968 }
8969
8970 /**
8971  * clutter_actor_get_request_mode:
8972  * @self: a #ClutterActor
8973  *
8974  * Retrieves the geometry request mode of @self
8975  *
8976  * Return value: the request mode for the actor
8977  *
8978  * Since: 1.2
8979  */
8980 ClutterRequestMode
8981 clutter_actor_get_request_mode (ClutterActor *self)
8982 {
8983   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8984                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8985
8986   return self->priv->request_mode;
8987 }
8988
8989 /* variant of set_width() without checks and without notification
8990  * freeze+thaw, for internal usage only
8991  */
8992 static inline void
8993 clutter_actor_set_width_internal (ClutterActor *self,
8994                                   gfloat        width)
8995 {
8996   if (width >= 0)
8997     {
8998       /* the Stage will use the :min-width to control the minimum
8999        * width to be resized to, so we should not be setting it
9000        * along with the :natural-width
9001        */
9002       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9003         clutter_actor_set_min_width (self, width);
9004
9005       clutter_actor_set_natural_width (self, width);
9006     }
9007   else
9008     {
9009       /* we only unset the :natural-width for the Stage */
9010       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9011         clutter_actor_set_min_width_set (self, FALSE);
9012
9013       clutter_actor_set_natural_width_set (self, FALSE);
9014     }
9015 }
9016
9017 /* variant of set_height() without checks and without notification
9018  * freeze+thaw, for internal usage only
9019  */
9020 static inline void
9021 clutter_actor_set_height_internal (ClutterActor *self,
9022                                    gfloat        height)
9023 {
9024   if (height >= 0)
9025     {
9026       /* see the comment above in set_width_internal() */
9027       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9028         clutter_actor_set_min_height (self, height);
9029
9030       clutter_actor_set_natural_height (self, height);
9031     }
9032   else
9033     {
9034       /* see the comment above in set_width_internal() */
9035       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9036         clutter_actor_set_min_height_set (self, FALSE);
9037
9038       clutter_actor_set_natural_height_set (self, FALSE);
9039     }
9040 }
9041
9042 /**
9043  * clutter_actor_set_size:
9044  * @self: A #ClutterActor
9045  * @width: New width of actor in pixels, or -1
9046  * @height: New height of actor in pixels, or -1
9047  *
9048  * Sets the actor's size request in pixels. This overrides any
9049  * "normal" size request the actor would have. For example
9050  * a text actor might normally request the size of the text;
9051  * this function would force a specific size instead.
9052  *
9053  * If @width and/or @height are -1 the actor will use its
9054  * "normal" size request instead of overriding it, i.e.
9055  * you can "unset" the size with -1.
9056  *
9057  * This function sets or unsets both the minimum and natural size.
9058  */
9059 void
9060 clutter_actor_set_size (ClutterActor *self,
9061                         gfloat        width,
9062                         gfloat        height)
9063 {
9064   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9065
9066   g_object_freeze_notify (G_OBJECT (self));
9067
9068   clutter_actor_set_width (self, width);
9069   clutter_actor_set_height (self, height);
9070
9071   g_object_thaw_notify (G_OBJECT (self));
9072 }
9073
9074 /**
9075  * clutter_actor_get_size:
9076  * @self: A #ClutterActor
9077  * @width: (out) (allow-none): return location for the width, or %NULL.
9078  * @height: (out) (allow-none): return location for the height, or %NULL.
9079  *
9080  * This function tries to "do what you mean" and return
9081  * the size an actor will have. If the actor has a valid
9082  * allocation, the allocation will be returned; otherwise,
9083  * the actors natural size request will be returned.
9084  *
9085  * If you care whether you get the request vs. the allocation, you
9086  * should probably call a different function like
9087  * clutter_actor_get_allocation_box() or
9088  * clutter_actor_get_preferred_width().
9089  *
9090  * Since: 0.2
9091  */
9092 void
9093 clutter_actor_get_size (ClutterActor *self,
9094                         gfloat       *width,
9095                         gfloat       *height)
9096 {
9097   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9098
9099   if (width)
9100     *width = clutter_actor_get_width (self);
9101
9102   if (height)
9103     *height = clutter_actor_get_height (self);
9104 }
9105
9106 /**
9107  * clutter_actor_get_position:
9108  * @self: a #ClutterActor
9109  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9110  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9111  *
9112  * This function tries to "do what you mean" and tell you where the
9113  * actor is, prior to any transformations. Retrieves the fixed
9114  * position of an actor in pixels, if one has been set; otherwise, if
9115  * the allocation is valid, returns the actor's allocated position;
9116  * otherwise, returns 0,0.
9117  *
9118  * The returned position is in pixels.
9119  *
9120  * Since: 0.6
9121  */
9122 void
9123 clutter_actor_get_position (ClutterActor *self,
9124                             gfloat       *x,
9125                             gfloat       *y)
9126 {
9127   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9128
9129   if (x)
9130     *x = clutter_actor_get_x (self);
9131
9132   if (y)
9133     *y = clutter_actor_get_y (self);
9134 }
9135
9136 /**
9137  * clutter_actor_get_transformed_position:
9138  * @self: A #ClutterActor
9139  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9140  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9141  *
9142  * Gets the absolute position of an actor, in pixels relative to the stage.
9143  *
9144  * Since: 0.8
9145  */
9146 void
9147 clutter_actor_get_transformed_position (ClutterActor *self,
9148                                         gfloat       *x,
9149                                         gfloat       *y)
9150 {
9151   ClutterVertex v1;
9152   ClutterVertex v2;
9153
9154   v1.x = v1.y = v1.z = 0;
9155   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9156
9157   if (x)
9158     *x = v2.x;
9159
9160   if (y)
9161     *y = v2.y;
9162 }
9163
9164 /**
9165  * clutter_actor_get_transformed_size:
9166  * @self: A #ClutterActor
9167  * @width: (out) (allow-none): return location for the width, or %NULL
9168  * @height: (out) (allow-none): return location for the height, or %NULL
9169  *
9170  * Gets the absolute size of an actor in pixels, taking into account the
9171  * scaling factors.
9172  *
9173  * If the actor has a valid allocation, the allocated size will be used.
9174  * If the actor has not a valid allocation then the preferred size will
9175  * be transformed and returned.
9176  *
9177  * If you want the transformed allocation, see
9178  * clutter_actor_get_abs_allocation_vertices() instead.
9179  *
9180  * <note>When the actor (or one of its ancestors) is rotated around the
9181  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9182  * as a generic quadrangle; in that case this function returns the size
9183  * of the smallest rectangle that encapsulates the entire quad. Please
9184  * note that in this case no assumptions can be made about the relative
9185  * position of this envelope to the absolute position of the actor, as
9186  * returned by clutter_actor_get_transformed_position(); if you need this
9187  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9188  * to get the coords of the actual quadrangle.</note>
9189  *
9190  * Since: 0.8
9191  */
9192 void
9193 clutter_actor_get_transformed_size (ClutterActor *self,
9194                                     gfloat       *width,
9195                                     gfloat       *height)
9196 {
9197   ClutterActorPrivate *priv;
9198   ClutterVertex v[4];
9199   gfloat x_min, x_max, y_min, y_max;
9200   gint i;
9201
9202   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9203
9204   priv = self->priv;
9205
9206   /* if the actor hasn't been allocated yet, get the preferred
9207    * size and transform that
9208    */
9209   if (priv->needs_allocation)
9210     {
9211       gfloat natural_width, natural_height;
9212       ClutterActorBox box;
9213
9214       /* Make a fake allocation to transform.
9215        *
9216        * NB: _clutter_actor_transform_and_project_box expects a box in
9217        * the actor's coordinate space... */
9218
9219       box.x1 = 0;
9220       box.y1 = 0;
9221
9222       natural_width = natural_height = 0;
9223       clutter_actor_get_preferred_size (self, NULL, NULL,
9224                                         &natural_width,
9225                                         &natural_height);
9226
9227       box.x2 = natural_width;
9228       box.y2 = natural_height;
9229
9230       _clutter_actor_transform_and_project_box (self, &box, v);
9231     }
9232   else
9233     clutter_actor_get_abs_allocation_vertices (self, v);
9234
9235   x_min = x_max = v[0].x;
9236   y_min = y_max = v[0].y;
9237
9238   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9239     {
9240       if (v[i].x < x_min)
9241         x_min = v[i].x;
9242
9243       if (v[i].x > x_max)
9244         x_max = v[i].x;
9245
9246       if (v[i].y < y_min)
9247         y_min = v[i].y;
9248
9249       if (v[i].y > y_max)
9250         y_max = v[i].y;
9251     }
9252
9253   if (width)
9254     *width  = x_max - x_min;
9255
9256   if (height)
9257     *height = y_max - y_min;
9258 }
9259
9260 /**
9261  * clutter_actor_get_width:
9262  * @self: A #ClutterActor
9263  *
9264  * Retrieves the width of a #ClutterActor.
9265  *
9266  * If the actor has a valid allocation, this function will return the
9267  * width of the allocated area given to the actor.
9268  *
9269  * If the actor does not have a valid allocation, this function will
9270  * return the actor's natural width, that is the preferred width of
9271  * the actor.
9272  *
9273  * If you care whether you get the preferred width or the width that
9274  * has been assigned to the actor, you should probably call a different
9275  * function like clutter_actor_get_allocation_box() to retrieve the
9276  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9277  * preferred width.
9278  *
9279  * If an actor has a fixed width, for instance a width that has been
9280  * assigned using clutter_actor_set_width(), the width returned will
9281  * be the same value.
9282  *
9283  * Return value: the width of the actor, in pixels
9284  */
9285 gfloat
9286 clutter_actor_get_width (ClutterActor *self)
9287 {
9288   ClutterActorPrivate *priv;
9289
9290   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9291
9292   priv = self->priv;
9293
9294   if (priv->needs_allocation)
9295     {
9296       gfloat natural_width = 0;
9297
9298       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9299         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9300       else
9301         {
9302           gfloat natural_height = 0;
9303
9304           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9305           clutter_actor_get_preferred_width (self, natural_height,
9306                                              NULL,
9307                                              &natural_width);
9308         }
9309
9310       return natural_width;
9311     }
9312   else
9313     return priv->allocation.x2 - priv->allocation.x1;
9314 }
9315
9316 /**
9317  * clutter_actor_get_height:
9318  * @self: A #ClutterActor
9319  *
9320  * Retrieves the height of a #ClutterActor.
9321  *
9322  * If the actor has a valid allocation, this function will return the
9323  * height of the allocated area given to the actor.
9324  *
9325  * If the actor does not have a valid allocation, this function will
9326  * return the actor's natural height, that is the preferred height of
9327  * the actor.
9328  *
9329  * If you care whether you get the preferred height or the height that
9330  * has been assigned to the actor, you should probably call a different
9331  * function like clutter_actor_get_allocation_box() to retrieve the
9332  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9333  * preferred height.
9334  *
9335  * If an actor has a fixed height, for instance a height that has been
9336  * assigned using clutter_actor_set_height(), the height returned will
9337  * be the same value.
9338  *
9339  * Return value: the height of the actor, in pixels
9340  */
9341 gfloat
9342 clutter_actor_get_height (ClutterActor *self)
9343 {
9344   ClutterActorPrivate *priv;
9345
9346   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9347
9348   priv = self->priv;
9349
9350   if (priv->needs_allocation)
9351     {
9352       gfloat natural_height = 0;
9353
9354       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9355         {
9356           gfloat natural_width = 0;
9357
9358           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9359           clutter_actor_get_preferred_height (self, natural_width,
9360                                               NULL, &natural_height);
9361         }
9362       else
9363         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9364
9365       return natural_height;
9366     }
9367   else
9368     return priv->allocation.y2 - priv->allocation.y1;
9369 }
9370
9371 /**
9372  * clutter_actor_set_width:
9373  * @self: A #ClutterActor
9374  * @width: Requested new width for the actor, in pixels, or -1
9375  *
9376  * Forces a width on an actor, causing the actor's preferred width
9377  * and height (if any) to be ignored.
9378  *
9379  * If @width is -1 the actor will use its preferred width request
9380  * instead of overriding it, i.e. you can "unset" the width with -1.
9381  *
9382  * This function sets both the minimum and natural size of the actor.
9383  *
9384  * since: 0.2
9385  */
9386 void
9387 clutter_actor_set_width (ClutterActor *self,
9388                          gfloat        width)
9389 {
9390   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9391
9392   if (clutter_actor_get_easing_duration (self) != 0)
9393     {
9394       ClutterTransition *transition;
9395
9396       transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9397       if (transition == NULL)
9398         {
9399           float old_width = clutter_actor_get_width (self);
9400
9401           transition = _clutter_actor_create_transition (self,
9402                                                          obj_props[PROP_WIDTH],
9403                                                          old_width,
9404                                                          width);
9405         }
9406       else
9407         _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9408
9409       clutter_actor_queue_relayout (self);
9410     }
9411   else
9412     {
9413       g_object_freeze_notify (G_OBJECT (self));
9414
9415       clutter_actor_set_width_internal (self, width);
9416
9417       g_object_thaw_notify (G_OBJECT (self));
9418     }
9419 }
9420
9421 /**
9422  * clutter_actor_set_height:
9423  * @self: A #ClutterActor
9424  * @height: Requested new height for the actor, in pixels, or -1
9425  *
9426  * Forces a height on an actor, causing the actor's preferred width
9427  * and height (if any) to be ignored.
9428  *
9429  * If @height is -1 the actor will use its preferred height instead of
9430  * overriding it, i.e. you can "unset" the height with -1.
9431  *
9432  * This function sets both the minimum and natural size of the actor.
9433  *
9434  * since: 0.2
9435  */
9436 void
9437 clutter_actor_set_height (ClutterActor *self,
9438                           gfloat        height)
9439 {
9440   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9441
9442   if (clutter_actor_get_easing_duration (self) != 0)
9443     {
9444       ClutterTransition *transition;
9445
9446       transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9447       if (transition ==  NULL)
9448         {
9449           float old_height = clutter_actor_get_height (self);
9450
9451           transition = _clutter_actor_create_transition (self,
9452                                                          obj_props[PROP_HEIGHT],
9453                                                          old_height,
9454                                                          height);
9455         }
9456       else
9457         _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9458
9459       clutter_actor_queue_relayout (self);
9460     }
9461   else
9462     {
9463       g_object_freeze_notify (G_OBJECT (self));
9464
9465       clutter_actor_set_height_internal (self, height);
9466
9467       g_object_thaw_notify (G_OBJECT (self));
9468     }
9469 }
9470
9471 static inline void
9472 clutter_actor_set_x_internal (ClutterActor *self,
9473                               float         x)
9474 {
9475   ClutterActorPrivate *priv = self->priv;
9476   ClutterLayoutInfo *linfo;
9477   ClutterActorBox old = { 0, };
9478
9479   linfo = _clutter_actor_get_layout_info (self);
9480
9481   if (priv->position_set && linfo->fixed_x == x)
9482     return;
9483
9484   clutter_actor_store_old_geometry (self, &old);
9485
9486   linfo->fixed_x = x;
9487   clutter_actor_set_fixed_position_set (self, TRUE);
9488
9489   clutter_actor_notify_if_geometry_changed (self, &old);
9490
9491   clutter_actor_queue_relayout (self);
9492 }
9493
9494 static inline void
9495 clutter_actor_set_y_internal (ClutterActor *self,
9496                               float         y)
9497 {
9498   ClutterActorPrivate *priv = self->priv;
9499   ClutterLayoutInfo *linfo;
9500   ClutterActorBox old = { 0, };
9501
9502   linfo = _clutter_actor_get_layout_info (self);
9503
9504   if (priv->position_set && linfo->fixed_y == y)
9505     return;
9506
9507   clutter_actor_store_old_geometry (self, &old);
9508
9509   linfo->fixed_y = y;
9510   clutter_actor_set_fixed_position_set (self, TRUE);
9511
9512   clutter_actor_notify_if_geometry_changed (self, &old);
9513
9514   clutter_actor_queue_relayout (self);
9515 }
9516
9517 /**
9518  * clutter_actor_set_x:
9519  * @self: a #ClutterActor
9520  * @x: the actor's position on the X axis
9521  *
9522  * Sets the actor's X coordinate, relative to its parent, in pixels.
9523  *
9524  * Overrides any layout manager and forces a fixed position for
9525  * the actor.
9526  *
9527  * The #ClutterActor:x property is animatable.
9528  *
9529  * Since: 0.6
9530  */
9531 void
9532 clutter_actor_set_x (ClutterActor *self,
9533                      gfloat        x)
9534 {
9535   const ClutterLayoutInfo *linfo;
9536
9537   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9538
9539   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9540
9541   if (clutter_actor_get_easing_duration (self) != 0)
9542     {
9543       ClutterTransition *transition;
9544
9545       transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9546       if (transition == NULL)
9547         {
9548           transition = _clutter_actor_create_transition (self,
9549                                                          obj_props[PROP_X],
9550                                                          linfo->fixed_x,
9551                                                          x);
9552         }
9553       else
9554         _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9555
9556       clutter_actor_queue_relayout (self);
9557     }
9558   else
9559     clutter_actor_set_x_internal (self, x);
9560 }
9561
9562 /**
9563  * clutter_actor_set_y:
9564  * @self: a #ClutterActor
9565  * @y: the actor's position on the Y axis
9566  *
9567  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9568  *
9569  * Overrides any layout manager and forces a fixed position for
9570  * the actor.
9571  *
9572  * The #ClutterActor:y property is animatable.
9573  *
9574  * Since: 0.6
9575  */
9576 void
9577 clutter_actor_set_y (ClutterActor *self,
9578                      gfloat        y)
9579 {
9580   const ClutterLayoutInfo *linfo;
9581
9582   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9583
9584   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9585
9586   if (clutter_actor_get_easing_duration (self) != 0)
9587     {
9588       ClutterTransition *transition;
9589
9590       transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9591       if (transition == NULL)
9592         {
9593           transition = _clutter_actor_create_transition (self,
9594                                                          obj_props[PROP_Y],
9595                                                          linfo->fixed_y,
9596                                                          y);
9597         }
9598       else
9599         _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9600
9601       clutter_actor_queue_relayout (self);
9602     }
9603   else
9604     clutter_actor_set_y_internal (self, y);
9605
9606   clutter_actor_queue_relayout (self);
9607 }
9608
9609 /**
9610  * clutter_actor_get_x:
9611  * @self: A #ClutterActor
9612  *
9613  * Retrieves the X coordinate of a #ClutterActor.
9614  *
9615  * This function tries to "do what you mean", by returning the
9616  * correct value depending on the actor's state.
9617  *
9618  * If the actor has a valid allocation, this function will return
9619  * the X coordinate of the origin of the allocation box.
9620  *
9621  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9622  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9623  * function will return that coordinate.
9624  *
9625  * If both the allocation and a fixed position are missing, this function
9626  * will return 0.
9627  *
9628  * Return value: the X coordinate, in pixels, ignoring any
9629  *   transformation (i.e. scaling, rotation)
9630  */
9631 gfloat
9632 clutter_actor_get_x (ClutterActor *self)
9633 {
9634   ClutterActorPrivate *priv;
9635
9636   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9637
9638   priv = self->priv;
9639
9640   if (priv->needs_allocation)
9641     {
9642       if (priv->position_set)
9643         {
9644           const ClutterLayoutInfo *info;
9645
9646           info = _clutter_actor_get_layout_info_or_defaults (self);
9647
9648           return info->fixed_x;
9649         }
9650       else
9651         return 0;
9652     }
9653   else
9654     return priv->allocation.x1;
9655 }
9656
9657 /**
9658  * clutter_actor_get_y:
9659  * @self: A #ClutterActor
9660  *
9661  * Retrieves the Y coordinate of a #ClutterActor.
9662  *
9663  * This function tries to "do what you mean", by returning the
9664  * correct value depending on the actor's state.
9665  *
9666  * If the actor has a valid allocation, this function will return
9667  * the Y coordinate of the origin of the allocation box.
9668  *
9669  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9670  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9671  * function will return that coordinate.
9672  *
9673  * If both the allocation and a fixed position are missing, this function
9674  * will return 0.
9675  *
9676  * Return value: the Y coordinate, in pixels, ignoring any
9677  *   transformation (i.e. scaling, rotation)
9678  */
9679 gfloat
9680 clutter_actor_get_y (ClutterActor *self)
9681 {
9682   ClutterActorPrivate *priv;
9683
9684   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9685
9686   priv = self->priv;
9687
9688   if (priv->needs_allocation)
9689     {
9690       if (priv->position_set)
9691         {
9692           const ClutterLayoutInfo *info;
9693
9694           info = _clutter_actor_get_layout_info_or_defaults (self);
9695
9696           return info->fixed_y;
9697         }
9698       else
9699         return 0;
9700     }
9701   else
9702     return priv->allocation.y1;
9703 }
9704
9705 /**
9706  * clutter_actor_set_scale:
9707  * @self: A #ClutterActor
9708  * @scale_x: double factor to scale actor by horizontally.
9709  * @scale_y: double factor to scale actor by vertically.
9710  *
9711  * Scales an actor with the given factors. The scaling is relative to
9712  * the scale center and the anchor point. The scale center is
9713  * unchanged by this function and defaults to 0,0.
9714  *
9715  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9716  * animatable.
9717  *
9718  * Since: 0.2
9719  */
9720 void
9721 clutter_actor_set_scale (ClutterActor *self,
9722                          gdouble       scale_x,
9723                          gdouble       scale_y)
9724 {
9725   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9726
9727   g_object_freeze_notify (G_OBJECT (self));
9728
9729   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9730   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9731
9732   g_object_thaw_notify (G_OBJECT (self));
9733 }
9734
9735 /**
9736  * clutter_actor_set_scale_full:
9737  * @self: A #ClutterActor
9738  * @scale_x: double factor to scale actor by horizontally.
9739  * @scale_y: double factor to scale actor by vertically.
9740  * @center_x: X coordinate of the center of the scale.
9741  * @center_y: Y coordinate of the center of the scale
9742  *
9743  * Scales an actor with the given factors around the given center
9744  * point. The center point is specified in pixels relative to the
9745  * anchor point (usually the top left corner of the actor).
9746  *
9747  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9748  * are animatable.
9749  *
9750  * Since: 1.0
9751  */
9752 void
9753 clutter_actor_set_scale_full (ClutterActor *self,
9754                               gdouble       scale_x,
9755                               gdouble       scale_y,
9756                               gfloat        center_x,
9757                               gfloat        center_y)
9758 {
9759   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9760
9761   g_object_freeze_notify (G_OBJECT (self));
9762
9763   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9764   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9765   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9766   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9767
9768   g_object_thaw_notify (G_OBJECT (self));
9769 }
9770
9771 /**
9772  * clutter_actor_set_scale_with_gravity:
9773  * @self: A #ClutterActor
9774  * @scale_x: double factor to scale actor by horizontally.
9775  * @scale_y: double factor to scale actor by vertically.
9776  * @gravity: the location of the scale center expressed as a compass
9777  * direction.
9778  *
9779  * Scales an actor with the given factors around the given
9780  * center point. The center point is specified as one of the compass
9781  * directions in #ClutterGravity. For example, setting it to north
9782  * will cause the top of the actor to remain unchanged and the rest of
9783  * the actor to expand left, right and downwards.
9784  *
9785  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9786  * animatable.
9787  *
9788  * Since: 1.0
9789  */
9790 void
9791 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9792                                       gdouble         scale_x,
9793                                       gdouble         scale_y,
9794                                       ClutterGravity  gravity)
9795 {
9796   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9797
9798   g_object_freeze_notify (G_OBJECT (self));
9799
9800   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9801   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9802   clutter_actor_set_scale_gravity (self, gravity);
9803
9804   g_object_thaw_notify (G_OBJECT (self));
9805 }
9806
9807 /**
9808  * clutter_actor_get_scale:
9809  * @self: A #ClutterActor
9810  * @scale_x: (out) (allow-none): Location to store horizonal
9811  *   scale factor, or %NULL.
9812  * @scale_y: (out) (allow-none): Location to store vertical
9813  *   scale factor, or %NULL.
9814  *
9815  * Retrieves an actors scale factors.
9816  *
9817  * Since: 0.2
9818  */
9819 void
9820 clutter_actor_get_scale (ClutterActor *self,
9821                          gdouble      *scale_x,
9822                          gdouble      *scale_y)
9823 {
9824   const ClutterTransformInfo *info;
9825
9826   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9827
9828   info = _clutter_actor_get_transform_info_or_defaults (self);
9829
9830   if (scale_x)
9831     *scale_x = info->scale_x;
9832
9833   if (scale_y)
9834     *scale_y = info->scale_y;
9835 }
9836
9837 /**
9838  * clutter_actor_get_scale_center:
9839  * @self: A #ClutterActor
9840  * @center_x: (out) (allow-none): Location to store the X position
9841  *   of the scale center, or %NULL.
9842  * @center_y: (out) (allow-none): Location to store the Y position
9843  *   of the scale center, or %NULL.
9844  *
9845  * Retrieves the scale center coordinate in pixels relative to the top
9846  * left corner of the actor. If the scale center was specified using a
9847  * #ClutterGravity this will calculate the pixel offset using the
9848  * current size of the actor.
9849  *
9850  * Since: 1.0
9851  */
9852 void
9853 clutter_actor_get_scale_center (ClutterActor *self,
9854                                 gfloat       *center_x,
9855                                 gfloat       *center_y)
9856 {
9857   const ClutterTransformInfo *info;
9858
9859   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9860
9861   info = _clutter_actor_get_transform_info_or_defaults (self);
9862
9863   clutter_anchor_coord_get_units (self, &info->scale_center,
9864                                   center_x,
9865                                   center_y,
9866                                   NULL);
9867 }
9868
9869 /**
9870  * clutter_actor_get_scale_gravity:
9871  * @self: A #ClutterActor
9872  *
9873  * Retrieves the scale center as a compass direction. If the scale
9874  * center was specified in pixels or units this will return
9875  * %CLUTTER_GRAVITY_NONE.
9876  *
9877  * Return value: the scale gravity
9878  *
9879  * Since: 1.0
9880  */
9881 ClutterGravity
9882 clutter_actor_get_scale_gravity (ClutterActor *self)
9883 {
9884   const ClutterTransformInfo *info;
9885
9886   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9887
9888   info = _clutter_actor_get_transform_info_or_defaults (self);
9889
9890   return clutter_anchor_coord_get_gravity (&info->scale_center);
9891 }
9892
9893 static inline void
9894 clutter_actor_set_opacity_internal (ClutterActor *self,
9895                                     guint8        opacity)
9896 {
9897   ClutterActorPrivate *priv = self->priv;
9898
9899   if (priv->opacity != opacity)
9900     {
9901       priv->opacity = opacity;
9902
9903       /* Queue a redraw from the flatten effect so that it can use
9904          its cached image if available instead of having to redraw the
9905          actual actor. If it doesn't end up using the FBO then the
9906          effect is still able to continue the paint anyway. If there
9907          is no flatten effect yet then this is equivalent to queueing
9908          a full redraw */
9909       _clutter_actor_queue_redraw_full (self,
9910                                         0, /* flags */
9911                                         NULL, /* clip */
9912                                         priv->flatten_effect);
9913
9914       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9915     }
9916 }
9917
9918 /**
9919  * clutter_actor_set_opacity:
9920  * @self: A #ClutterActor
9921  * @opacity: New opacity value for the actor.
9922  *
9923  * Sets the actor's opacity, with zero being completely transparent and
9924  * 255 (0xff) being fully opaque.
9925  *
9926  * The #ClutterActor:opacity property is animatable.
9927  */
9928 void
9929 clutter_actor_set_opacity (ClutterActor *self,
9930                            guint8        opacity)
9931 {
9932   ClutterActorPrivate *priv;
9933
9934   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9935
9936   priv = self->priv;
9937
9938   if (clutter_actor_get_easing_duration (self) != 0)
9939     {
9940       ClutterTransition *transition;
9941
9942       transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9943       if (transition == NULL)
9944         {
9945           transition = _clutter_actor_create_transition (self,
9946                                                          obj_props[PROP_OPACITY],
9947                                                          priv->opacity,
9948                                                          opacity);
9949         }
9950       else
9951         _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9952
9953       clutter_actor_queue_redraw (self);
9954     }
9955   else
9956     clutter_actor_set_opacity_internal (self, opacity);
9957 }
9958
9959 /*
9960  * clutter_actor_get_paint_opacity_internal:
9961  * @self: a #ClutterActor
9962  *
9963  * Retrieves the absolute opacity of the actor, as it appears on the stage
9964  *
9965  * This function does not do type checks
9966  *
9967  * Return value: the absolute opacity of the actor
9968  */
9969 static guint8
9970 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9971 {
9972   ClutterActorPrivate *priv = self->priv;
9973   ClutterActor *parent;
9974
9975   /* override the top-level opacity to always be 255; even in
9976    * case of ClutterStage:use-alpha being TRUE we want the rest
9977    * of the scene to be painted
9978    */
9979   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9980     return 255;
9981
9982   if (priv->opacity_override >= 0)
9983     return priv->opacity_override;
9984
9985   parent = priv->parent;
9986
9987   /* Factor in the actual actors opacity with parents */
9988   if (parent != NULL)
9989     {
9990       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9991
9992       if (opacity != 0xff)
9993         return (opacity * priv->opacity) / 0xff;
9994     }
9995
9996   return priv->opacity;
9997
9998 }
9999
10000 /**
10001  * clutter_actor_get_paint_opacity:
10002  * @self: A #ClutterActor
10003  *
10004  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10005  *
10006  * This function traverses the hierarchy chain and composites the opacity of
10007  * the actor with that of its parents.
10008  *
10009  * This function is intended for subclasses to use in the paint virtual
10010  * function, to paint themselves with the correct opacity.
10011  *
10012  * Return value: The actor opacity value.
10013  *
10014  * Since: 0.8
10015  */
10016 guint8
10017 clutter_actor_get_paint_opacity (ClutterActor *self)
10018 {
10019   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10020
10021   return clutter_actor_get_paint_opacity_internal (self);
10022 }
10023
10024 /**
10025  * clutter_actor_get_opacity:
10026  * @self: a #ClutterActor
10027  *
10028  * Retrieves the opacity value of an actor, as set by
10029  * clutter_actor_set_opacity().
10030  *
10031  * For retrieving the absolute opacity of the actor inside a paint
10032  * virtual function, see clutter_actor_get_paint_opacity().
10033  *
10034  * Return value: the opacity of the actor
10035  */
10036 guint8
10037 clutter_actor_get_opacity (ClutterActor *self)
10038 {
10039   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10040
10041   return self->priv->opacity;
10042 }
10043
10044 /**
10045  * clutter_actor_set_offscreen_redirect:
10046  * @self: A #ClutterActor
10047  * @redirect: New offscreen redirect flags for the actor.
10048  *
10049  * Defines the circumstances where the actor should be redirected into
10050  * an offscreen image. The offscreen image is used to flatten the
10051  * actor into a single image while painting for two main reasons.
10052  * Firstly, when the actor is painted a second time without any of its
10053  * contents changing it can simply repaint the cached image without
10054  * descending further down the actor hierarchy. Secondly, it will make
10055  * the opacity look correct even if there are overlapping primitives
10056  * in the actor.
10057  *
10058  * Caching the actor could in some cases be a performance win and in
10059  * some cases be a performance lose so it is important to determine
10060  * which value is right for an actor before modifying this value. For
10061  * example, there is never any reason to flatten an actor that is just
10062  * a single texture (such as a #ClutterTexture) because it is
10063  * effectively already cached in an image so the offscreen would be
10064  * redundant. Also if the actor contains primitives that are far apart
10065  * with a large transparent area in the middle (such as a large
10066  * CluterGroup with a small actor in the top left and a small actor in
10067  * the bottom right) then the cached image will contain the entire
10068  * image of the large area and the paint will waste time blending all
10069  * of the transparent pixels in the middle.
10070  *
10071  * The default method of implementing opacity on a container simply
10072  * forwards on the opacity to all of the children. If the children are
10073  * overlapping then it will appear as if they are two separate glassy
10074  * objects and there will be a break in the color where they
10075  * overlap. By redirecting to an offscreen buffer it will be as if the
10076  * two opaque objects are combined into one and then made transparent
10077  * which is usually what is expected.
10078  *
10079  * The image below demonstrates the difference between redirecting and
10080  * not. The image shows two Clutter groups, each containing a red and
10081  * a green rectangle which overlap. The opacity on the group is set to
10082  * 128 (which is 50%). When the offscreen redirect is not used, the
10083  * red rectangle can be seen through the blue rectangle as if the two
10084  * rectangles were separately transparent. When the redirect is used
10085  * the group as a whole is transparent instead so the red rectangle is
10086  * not visible where they overlap.
10087  *
10088  * <figure id="offscreen-redirect">
10089  *   <title>Sample of using an offscreen redirect for transparency</title>
10090  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10091  * </figure>
10092  *
10093  * The default value for this property is 0, so we effectively will
10094  * never redirect an actor offscreen by default. This means that there
10095  * are times that transparent actors may look glassy as described
10096  * above. The reason this is the default is because there is a
10097  * performance trade off between quality and performance here. In many
10098  * cases the default form of glassy opacity looks good enough, but if
10099  * it's not you will need to set the
10100  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10101  * redirection for opacity.
10102  *
10103  * Custom actors that don't contain any overlapping primitives are
10104  * recommended to override the has_overlaps() virtual to return %FALSE
10105  * for maximum efficiency.
10106  *
10107  * Since: 1.8
10108  */
10109 void
10110 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10111                                       ClutterOffscreenRedirect redirect)
10112 {
10113   ClutterActorPrivate *priv;
10114
10115   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10116
10117   priv = self->priv;
10118
10119   if (priv->offscreen_redirect != redirect)
10120     {
10121       priv->offscreen_redirect = redirect;
10122
10123       /* Queue a redraw from the effect so that it can use its cached
10124          image if available instead of having to redraw the actual
10125          actor. If it doesn't end up using the FBO then the effect is
10126          still able to continue the paint anyway. If there is no
10127          effect then this is equivalent to queuing a full redraw */
10128       _clutter_actor_queue_redraw_full (self,
10129                                         0, /* flags */
10130                                         NULL, /* clip */
10131                                         priv->flatten_effect);
10132
10133       g_object_notify_by_pspec (G_OBJECT (self),
10134                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10135     }
10136 }
10137
10138 /**
10139  * clutter_actor_get_offscreen_redirect:
10140  * @self: a #ClutterActor
10141  *
10142  * Retrieves whether to redirect the actor to an offscreen buffer, as
10143  * set by clutter_actor_set_offscreen_redirect().
10144  *
10145  * Return value: the value of the offscreen-redirect property of the actor
10146  *
10147  * Since: 1.8
10148  */
10149 ClutterOffscreenRedirect
10150 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10151 {
10152   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10153
10154   return self->priv->offscreen_redirect;
10155 }
10156
10157 /**
10158  * clutter_actor_set_name:
10159  * @self: A #ClutterActor
10160  * @name: Textual tag to apply to actor
10161  *
10162  * Sets the given name to @self. The name can be used to identify
10163  * a #ClutterActor.
10164  */
10165 void
10166 clutter_actor_set_name (ClutterActor *self,
10167                         const gchar  *name)
10168 {
10169   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10170
10171   g_free (self->priv->name);
10172   self->priv->name = g_strdup (name);
10173
10174   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10175 }
10176
10177 /**
10178  * clutter_actor_get_name:
10179  * @self: A #ClutterActor
10180  *
10181  * Retrieves the name of @self.
10182  *
10183  * Return value: the name of the actor, or %NULL. The returned string is
10184  *   owned by the actor and should not be modified or freed.
10185  */
10186 const gchar *
10187 clutter_actor_get_name (ClutterActor *self)
10188 {
10189   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10190
10191   return self->priv->name;
10192 }
10193
10194 /**
10195  * clutter_actor_get_gid:
10196  * @self: A #ClutterActor
10197  *
10198  * Retrieves the unique id for @self.
10199  *
10200  * Return value: Globally unique value for this object instance.
10201  *
10202  * Since: 0.6
10203  *
10204  * Deprecated: 1.8: The id is not used any longer.
10205  */
10206 guint32
10207 clutter_actor_get_gid (ClutterActor *self)
10208 {
10209   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10210
10211   return self->priv->id;
10212 }
10213
10214 static inline void
10215 clutter_actor_set_depth_internal (ClutterActor *self,
10216                                   float         depth)
10217 {
10218   ClutterTransformInfo *info;
10219
10220   info = _clutter_actor_get_transform_info (self);
10221
10222   if (info->depth != depth)
10223     {
10224       /* Sets Z value - XXX 2.0: should we invert? */
10225       info->depth = depth;
10226
10227       self->priv->transform_valid = FALSE;
10228
10229       /* FIXME - remove this crap; sadly, there are still containers
10230        * in Clutter that depend on this utter brain damage
10231        */
10232       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10233
10234       clutter_actor_queue_redraw (self);
10235
10236       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10237     }
10238 }
10239
10240 /**
10241  * clutter_actor_set_depth:
10242  * @self: a #ClutterActor
10243  * @depth: Z co-ord
10244  *
10245  * Sets the Z coordinate of @self to @depth.
10246  *
10247  * The unit used by @depth is dependant on the perspective setup. See
10248  * also clutter_stage_set_perspective().
10249  */
10250 void
10251 clutter_actor_set_depth (ClutterActor *self,
10252                          gfloat        depth)
10253 {
10254   const ClutterTransformInfo *tinfo;
10255
10256   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10257
10258   tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10259
10260   if (clutter_actor_get_easing_duration (self) != 0)
10261     {
10262       ClutterTransition *transition;
10263
10264       transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10265       if (transition == NULL)
10266         {
10267           transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10268                                                          tinfo->depth,
10269                                                          depth);
10270         }
10271       else
10272         _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10273
10274       clutter_actor_queue_redraw (self);
10275     }
10276   else
10277     clutter_actor_set_depth_internal (self, depth);
10278 }
10279
10280 /**
10281  * clutter_actor_get_depth:
10282  * @self: a #ClutterActor
10283  *
10284  * Retrieves the depth of @self.
10285  *
10286  * Return value: the depth of the actor
10287  */
10288 gfloat
10289 clutter_actor_get_depth (ClutterActor *self)
10290 {
10291   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10292
10293   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10294 }
10295
10296 /**
10297  * clutter_actor_set_rotation:
10298  * @self: a #ClutterActor
10299  * @axis: the axis of rotation
10300  * @angle: the angle of rotation
10301  * @x: X coordinate of the rotation center
10302  * @y: Y coordinate of the rotation center
10303  * @z: Z coordinate of the rotation center
10304  *
10305  * Sets the rotation angle of @self around the given axis.
10306  *
10307  * The rotation center coordinates used depend on the value of @axis:
10308  * <itemizedlist>
10309  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10310  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10311  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10312  * </itemizedlist>
10313  *
10314  * The rotation coordinates are relative to the anchor point of the
10315  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10316  * point is set, the upper left corner is assumed as the origin.
10317  *
10318  * Since: 0.8
10319  */
10320 void
10321 clutter_actor_set_rotation (ClutterActor      *self,
10322                             ClutterRotateAxis  axis,
10323                             gdouble            angle,
10324                             gfloat             x,
10325                             gfloat             y,
10326                             gfloat             z)
10327 {
10328   ClutterVertex v;
10329
10330   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10331
10332   v.x = x;
10333   v.y = y;
10334   v.z = z;
10335
10336   g_object_freeze_notify (G_OBJECT (self));
10337
10338   clutter_actor_set_rotation_angle (self, axis, angle);
10339   clutter_actor_set_rotation_center_internal (self, axis, &v);
10340
10341   g_object_thaw_notify (G_OBJECT (self));
10342 }
10343
10344 /**
10345  * clutter_actor_set_z_rotation_from_gravity:
10346  * @self: a #ClutterActor
10347  * @angle: the angle of rotation
10348  * @gravity: the center point of the rotation
10349  *
10350  * Sets the rotation angle of @self around the Z axis using the center
10351  * point specified as a compass point. For example to rotate such that
10352  * the center of the actor remains static you can use
10353  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10354  * will move accordingly.
10355  *
10356  * Since: 1.0
10357  */
10358 void
10359 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10360                                            gdouble         angle,
10361                                            ClutterGravity  gravity)
10362 {
10363   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10364
10365   if (gravity == CLUTTER_GRAVITY_NONE)
10366     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10367   else
10368     {
10369       GObject *obj = G_OBJECT (self);
10370       ClutterTransformInfo *info;
10371
10372       info = _clutter_actor_get_transform_info (self);
10373
10374       g_object_freeze_notify (obj);
10375
10376       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10377
10378       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10379       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10380       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10381
10382       g_object_thaw_notify (obj);
10383     }
10384 }
10385
10386 /**
10387  * clutter_actor_get_rotation:
10388  * @self: a #ClutterActor
10389  * @axis: the axis of rotation
10390  * @x: (out): return value for the X coordinate of the center of rotation
10391  * @y: (out): return value for the Y coordinate of the center of rotation
10392  * @z: (out): return value for the Z coordinate of the center of rotation
10393  *
10394  * Retrieves the angle and center of rotation on the given axis,
10395  * set using clutter_actor_set_rotation().
10396  *
10397  * Return value: the angle of rotation
10398  *
10399  * Since: 0.8
10400  */
10401 gdouble
10402 clutter_actor_get_rotation (ClutterActor      *self,
10403                             ClutterRotateAxis  axis,
10404                             gfloat            *x,
10405                             gfloat            *y,
10406                             gfloat            *z)
10407 {
10408   const ClutterTransformInfo *info;
10409   const AnchorCoord *anchor_coord;
10410   gdouble retval = 0;
10411
10412   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10413
10414   info = _clutter_actor_get_transform_info_or_defaults (self);
10415
10416   switch (axis)
10417     {
10418     case CLUTTER_X_AXIS:
10419       anchor_coord = &info->rx_center;
10420       retval = info->rx_angle;
10421       break;
10422
10423     case CLUTTER_Y_AXIS:
10424       anchor_coord = &info->ry_center;
10425       retval = info->ry_angle;
10426       break;
10427
10428     case CLUTTER_Z_AXIS:
10429       anchor_coord = &info->rz_center;
10430       retval = info->rz_angle;
10431       break;
10432
10433     default:
10434       anchor_coord = NULL;
10435       retval = 0.0;
10436       break;
10437     }
10438
10439   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10440
10441   return retval;
10442 }
10443
10444 /**
10445  * clutter_actor_get_z_rotation_gravity:
10446  * @self: A #ClutterActor
10447  *
10448  * Retrieves the center for the rotation around the Z axis as a
10449  * compass direction. If the center was specified in pixels or units
10450  * this will return %CLUTTER_GRAVITY_NONE.
10451  *
10452  * Return value: the Z rotation center
10453  *
10454  * Since: 1.0
10455  */
10456 ClutterGravity
10457 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10458 {
10459   const ClutterTransformInfo *info;
10460
10461   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10462
10463   info = _clutter_actor_get_transform_info_or_defaults (self);
10464
10465   return clutter_anchor_coord_get_gravity (&info->rz_center);
10466 }
10467
10468 /**
10469  * clutter_actor_set_clip:
10470  * @self: A #ClutterActor
10471  * @xoff: X offset of the clip rectangle
10472  * @yoff: Y offset of the clip rectangle
10473  * @width: Width of the clip rectangle
10474  * @height: Height of the clip rectangle
10475  *
10476  * Sets clip area for @self. The clip area is always computed from the
10477  * upper left corner of the actor, even if the anchor point is set
10478  * otherwise.
10479  *
10480  * Since: 0.6
10481  */
10482 void
10483 clutter_actor_set_clip (ClutterActor *self,
10484                         gfloat        xoff,
10485                         gfloat        yoff,
10486                         gfloat        width,
10487                         gfloat        height)
10488 {
10489   ClutterActorPrivate *priv;
10490
10491   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10492
10493   priv = self->priv;
10494
10495   if (priv->has_clip &&
10496       priv->clip.x == xoff &&
10497       priv->clip.y == yoff &&
10498       priv->clip.width == width &&
10499       priv->clip.height == height)
10500     return;
10501
10502   priv->clip.x = xoff;
10503   priv->clip.y = yoff;
10504   priv->clip.width = width;
10505   priv->clip.height = height;
10506
10507   priv->has_clip = TRUE;
10508
10509   clutter_actor_queue_redraw (self);
10510
10511   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10512   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10513 }
10514
10515 /**
10516  * clutter_actor_remove_clip:
10517  * @self: A #ClutterActor
10518  *
10519  * Removes clip area from @self.
10520  */
10521 void
10522 clutter_actor_remove_clip (ClutterActor *self)
10523 {
10524   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10525
10526   if (!self->priv->has_clip)
10527     return;
10528
10529   self->priv->has_clip = FALSE;
10530
10531   clutter_actor_queue_redraw (self);
10532
10533   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10534 }
10535
10536 /**
10537  * clutter_actor_has_clip:
10538  * @self: a #ClutterActor
10539  *
10540  * Determines whether the actor has a clip area set or not.
10541  *
10542  * Return value: %TRUE if the actor has a clip area set.
10543  *
10544  * Since: 0.1.1
10545  */
10546 gboolean
10547 clutter_actor_has_clip (ClutterActor *self)
10548 {
10549   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10550
10551   return self->priv->has_clip;
10552 }
10553
10554 /**
10555  * clutter_actor_get_clip:
10556  * @self: a #ClutterActor
10557  * @xoff: (out) (allow-none): return location for the X offset of
10558  *   the clip rectangle, or %NULL
10559  * @yoff: (out) (allow-none): return location for the Y offset of
10560  *   the clip rectangle, or %NULL
10561  * @width: (out) (allow-none): return location for the width of
10562  *   the clip rectangle, or %NULL
10563  * @height: (out) (allow-none): return location for the height of
10564  *   the clip rectangle, or %NULL
10565  *
10566  * Gets the clip area for @self, if any is set
10567  *
10568  * Since: 0.6
10569  */
10570 void
10571 clutter_actor_get_clip (ClutterActor *self,
10572                         gfloat       *xoff,
10573                         gfloat       *yoff,
10574                         gfloat       *width,
10575                         gfloat       *height)
10576 {
10577   ClutterActorPrivate *priv;
10578
10579   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10580
10581   priv = self->priv;
10582
10583   if (!priv->has_clip)
10584     return;
10585
10586   if (xoff != NULL)
10587     *xoff = priv->clip.x;
10588
10589   if (yoff != NULL)
10590     *yoff = priv->clip.y;
10591
10592   if (width != NULL)
10593     *width = priv->clip.width;
10594
10595   if (height != NULL)
10596     *height = priv->clip.height;
10597 }
10598
10599 /**
10600  * clutter_actor_get_children:
10601  * @self: a #ClutterActor
10602  *
10603  * Retrieves the list of children of @self.
10604  *
10605  * Return value: (transfer container) (element-type ClutterActor): A newly
10606  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10607  *   done.
10608  *
10609  * Since: 1.10
10610  */
10611 GList *
10612 clutter_actor_get_children (ClutterActor *self)
10613 {
10614   ClutterActor *iter;
10615   GList *res;
10616
10617   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10618
10619   /* we walk the list backward so that we can use prepend(),
10620    * which is O(1)
10621    */
10622   for (iter = self->priv->last_child, res = NULL;
10623        iter != NULL;
10624        iter = iter->priv->prev_sibling)
10625     {
10626       res = g_list_prepend (res, iter);
10627     }
10628
10629   return res;
10630 }
10631
10632 /*< private >
10633  * insert_child_at_depth:
10634  * @self: a #ClutterActor
10635  * @child: a #ClutterActor
10636  *
10637  * Inserts @child inside the list of children held by @self, using
10638  * the depth as the insertion criteria.
10639  *
10640  * This sadly makes the insertion not O(1), but we can keep the
10641  * list sorted so that the painters algorithm we use for painting
10642  * the children will work correctly.
10643  */
10644 static void
10645 insert_child_at_depth (ClutterActor *self,
10646                        ClutterActor *child,
10647                        gpointer      dummy G_GNUC_UNUSED)
10648 {
10649   ClutterActor *iter;
10650   float child_depth;
10651
10652   child->priv->parent = self;
10653
10654   child_depth =
10655     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10656
10657   /* special-case the first child */
10658   if (self->priv->n_children == 0)
10659     {
10660       self->priv->first_child = child;
10661       self->priv->last_child = child;
10662
10663       child->priv->next_sibling = NULL;
10664       child->priv->prev_sibling = NULL;
10665
10666       return;
10667     }
10668
10669   /* Find the right place to insert the child so that it will still be
10670      sorted and the child will be after all of the actors at the same
10671      dept */
10672   for (iter = self->priv->first_child;
10673        iter != NULL;
10674        iter = iter->priv->next_sibling)
10675     {
10676       float iter_depth;
10677
10678       iter_depth =
10679         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10680
10681       if (iter_depth > child_depth)
10682         break;
10683     }
10684
10685   if (iter != NULL)
10686     {
10687       ClutterActor *tmp = iter->priv->prev_sibling;
10688
10689       if (tmp != NULL)
10690         tmp->priv->next_sibling = child;
10691
10692       /* Insert the node before the found one */
10693       child->priv->prev_sibling = iter->priv->prev_sibling;
10694       child->priv->next_sibling = iter;
10695       iter->priv->prev_sibling = child;
10696     }
10697   else
10698     {
10699       ClutterActor *tmp = self->priv->last_child;
10700
10701       if (tmp != NULL)
10702         tmp->priv->next_sibling = child;
10703
10704       /* insert the node at the end of the list */
10705       child->priv->prev_sibling = self->priv->last_child;
10706       child->priv->next_sibling = NULL;
10707     }
10708
10709   if (child->priv->prev_sibling == NULL)
10710     self->priv->first_child = child;
10711
10712   if (child->priv->next_sibling == NULL)
10713     self->priv->last_child = child;
10714 }
10715
10716 static void
10717 insert_child_at_index (ClutterActor *self,
10718                        ClutterActor *child,
10719                        gpointer      data_)
10720 {
10721   gint index_ = GPOINTER_TO_INT (data_);
10722
10723   child->priv->parent = self;
10724
10725   if (index_ == 0)
10726     {
10727       ClutterActor *tmp = self->priv->first_child;
10728
10729       if (tmp != NULL)
10730         tmp->priv->prev_sibling = child;
10731
10732       child->priv->prev_sibling = NULL;
10733       child->priv->next_sibling = tmp;
10734     }
10735   else if (index_ < 0 || index_ >= self->priv->n_children)
10736     {
10737       ClutterActor *tmp = self->priv->last_child;
10738
10739       if (tmp != NULL)
10740         tmp->priv->next_sibling = child;
10741
10742       child->priv->prev_sibling = tmp;
10743       child->priv->next_sibling = NULL;
10744     }
10745   else
10746     {
10747       ClutterActor *iter;
10748       int i;
10749
10750       for (iter = self->priv->first_child, i = 0;
10751            iter != NULL;
10752            iter = iter->priv->next_sibling, i += 1)
10753         {
10754           if (index_ == i)
10755             {
10756               ClutterActor *tmp = iter->priv->prev_sibling;
10757
10758               child->priv->prev_sibling = tmp;
10759               child->priv->next_sibling = iter;
10760
10761               iter->priv->prev_sibling = child;
10762
10763               if (tmp != NULL)
10764                 tmp->priv->next_sibling = child;
10765
10766               break;
10767             }
10768         }
10769     }
10770
10771   if (child->priv->prev_sibling == NULL)
10772     self->priv->first_child = child;
10773
10774   if (child->priv->next_sibling == NULL)
10775     self->priv->last_child = child;
10776 }
10777
10778 static void
10779 insert_child_above (ClutterActor *self,
10780                     ClutterActor *child,
10781                     gpointer      data)
10782 {
10783   ClutterActor *sibling = data;
10784
10785   child->priv->parent = self;
10786
10787   if (sibling == NULL)
10788     sibling = self->priv->last_child;
10789
10790   child->priv->prev_sibling = sibling;
10791
10792   if (sibling != NULL)
10793     {
10794       ClutterActor *tmp = sibling->priv->next_sibling;
10795
10796       child->priv->next_sibling = tmp;
10797
10798       if (tmp != NULL)
10799         tmp->priv->prev_sibling = child;
10800
10801       sibling->priv->next_sibling = child;
10802     }
10803   else
10804     child->priv->next_sibling = NULL;
10805
10806   if (child->priv->prev_sibling == NULL)
10807     self->priv->first_child = child;
10808
10809   if (child->priv->next_sibling == NULL)
10810     self->priv->last_child = child;
10811 }
10812
10813 static void
10814 insert_child_below (ClutterActor *self,
10815                     ClutterActor *child,
10816                     gpointer      data)
10817 {
10818   ClutterActor *sibling = data;
10819
10820   child->priv->parent = self;
10821
10822   if (sibling == NULL)
10823     sibling = self->priv->first_child;
10824
10825   child->priv->next_sibling = sibling;
10826
10827   if (sibling != NULL)
10828     {
10829       ClutterActor *tmp = sibling->priv->prev_sibling;
10830
10831       child->priv->prev_sibling = tmp;
10832
10833       if (tmp != NULL)
10834         tmp->priv->next_sibling = child;
10835
10836       sibling->priv->prev_sibling = child;
10837     }
10838   else
10839     child->priv->prev_sibling = NULL;
10840
10841   if (child->priv->prev_sibling == NULL)
10842     self->priv->first_child = child;
10843
10844   if (child->priv->next_sibling == NULL)
10845     self->priv->last_child = child;
10846 }
10847
10848 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10849                                            ClutterActor *child,
10850                                            gpointer      data);
10851
10852 typedef enum {
10853   ADD_CHILD_CREATE_META       = 1 << 0,
10854   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10855   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10856   ADD_CHILD_CHECK_STATE       = 1 << 3,
10857   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10858
10859   /* default flags for public API */
10860   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10861                                ADD_CHILD_EMIT_PARENT_SET |
10862                                ADD_CHILD_EMIT_ACTOR_ADDED |
10863                                ADD_CHILD_CHECK_STATE |
10864                                ADD_CHILD_NOTIFY_FIRST_LAST,
10865
10866   /* flags for legacy/deprecated API */
10867   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10868                                ADD_CHILD_CHECK_STATE |
10869                                ADD_CHILD_NOTIFY_FIRST_LAST
10870 } ClutterActorAddChildFlags;
10871
10872 /*< private >
10873  * clutter_actor_add_child_internal:
10874  * @self: a #ClutterActor
10875  * @child: a #ClutterActor
10876  * @flags: control flags for actions
10877  * @add_func: delegate function
10878  * @data: (closure): data to pass to @add_func
10879  *
10880  * Adds @child to the list of children of @self.
10881  *
10882  * The actual insertion inside the list is delegated to @add_func: this
10883  * function will just set up the state, perform basic checks, and emit
10884  * signals.
10885  *
10886  * The @flags argument is used to perform additional operations.
10887  */
10888 static inline void
10889 clutter_actor_add_child_internal (ClutterActor              *self,
10890                                   ClutterActor              *child,
10891                                   ClutterActorAddChildFlags  flags,
10892                                   ClutterActorAddChildFunc   add_func,
10893                                   gpointer                   data)
10894 {
10895   ClutterTextDirection text_dir;
10896   gboolean create_meta;
10897   gboolean emit_parent_set, emit_actor_added;
10898   gboolean check_state;
10899   gboolean notify_first_last;
10900   ClutterActor *old_first_child, *old_last_child;
10901
10902   if (child->priv->parent != NULL)
10903     {
10904       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10905                  "use clutter_actor_remove_child() first.",
10906                  _clutter_actor_get_debug_name (child),
10907                  _clutter_actor_get_debug_name (child->priv->parent));
10908       return;
10909     }
10910
10911   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10912     {
10913       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10914                  "a child of another actor.",
10915                  _clutter_actor_get_debug_name (child));
10916       return;
10917     }
10918
10919 #if 0
10920   /* XXX - this check disallows calling methods that change the stacking
10921    * order within the destruction sequence, by triggering a critical
10922    * warning first, and leaving the actor in an undefined state, which
10923    * then ends up being caught by an assertion.
10924    *
10925    * the reproducible sequence is:
10926    *
10927    *   - actor gets destroyed;
10928    *   - another actor, linked to the first, will try to change the
10929    *     stacking order of the first actor;
10930    *   - changing the stacking order is a composite operation composed
10931    *     by the following steps:
10932    *     1. ref() the child;
10933    *     2. remove_child_internal(), which removes the reference;
10934    *     3. add_child_internal(), which adds a reference;
10935    *   - the state of the actor is not changed between (2) and (3), as
10936    *     it could be an expensive recomputation;
10937    *   - if (3) bails out, then the actor is in an undefined state, but
10938    *     still alive;
10939    *   - the destruction sequence terminates, but the actor is unparented
10940    *     while its state indicates being parented instead.
10941    *   - assertion failure.
10942    *
10943    * the obvious fix would be to decompose each set_child_*_sibling()
10944    * method into proper remove_child()/add_child(), with state validation;
10945    * this may cause excessive work, though, and trigger a cascade of other
10946    * bugs in code that assumes that a change in the stacking order is an
10947    * atomic operation.
10948    *
10949    * another potential fix is to just remove this check here, and let
10950    * code doing stacking order changes inside the destruction sequence
10951    * of an actor continue doing the work.
10952    *
10953    * the third fix is to silently bail out early from every
10954    * set_child_*_sibling() and set_child_at_index() method, and avoid
10955    * doing work.
10956    *
10957    * I have a preference for the second solution, since it involves the
10958    * least amount of work, and the least amount of code duplication.
10959    *
10960    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10961    */
10962   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10963     {
10964       g_warning ("The actor '%s' is currently being destroyed, and "
10965                  "cannot be added as a child of another actor.",
10966                  _clutter_actor_get_debug_name (child));
10967       return;
10968     }
10969 #endif
10970
10971   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10972   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10973   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10974   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10975   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10976
10977   old_first_child = self->priv->first_child;
10978   old_last_child = self->priv->last_child;
10979
10980   g_object_freeze_notify (G_OBJECT (self));
10981
10982   if (create_meta)
10983     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10984
10985   g_object_ref_sink (child);
10986   child->priv->parent = NULL;
10987   child->priv->next_sibling = NULL;
10988   child->priv->prev_sibling = NULL;
10989
10990   /* delegate the actual insertion */
10991   add_func (self, child, data);
10992
10993   g_assert (child->priv->parent == self);
10994
10995   self->priv->n_children += 1;
10996
10997   self->priv->age += 1;
10998
10999   /* if push_internal() has been called then we automatically set
11000    * the flag on the actor
11001    */
11002   if (self->priv->internal_child)
11003     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11004
11005   /* clutter_actor_reparent() will emit ::parent-set for us */
11006   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11007     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11008
11009   if (check_state)
11010     {
11011       /* If parent is mapped or realized, we need to also be mapped or
11012        * realized once we're inside the parent.
11013        */
11014       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11015
11016       /* propagate the parent's text direction to the child */
11017       text_dir = clutter_actor_get_text_direction (self);
11018       clutter_actor_set_text_direction (child, text_dir);
11019     }
11020
11021   if (child->priv->show_on_set_parent)
11022     clutter_actor_show (child);
11023
11024   if (CLUTTER_ACTOR_IS_MAPPED (child))
11025     clutter_actor_queue_redraw (child);
11026
11027   /* maintain the invariant that if an actor needs layout,
11028    * its parents do as well
11029    */
11030   if (child->priv->needs_width_request ||
11031       child->priv->needs_height_request ||
11032       child->priv->needs_allocation)
11033     {
11034       /* we work around the short-circuiting we do
11035        * in clutter_actor_queue_relayout() since we
11036        * want to force a relayout
11037        */
11038       child->priv->needs_width_request = TRUE;
11039       child->priv->needs_height_request = TRUE;
11040       child->priv->needs_allocation = TRUE;
11041
11042       clutter_actor_queue_relayout (child->priv->parent);
11043     }
11044
11045   if (emit_actor_added)
11046     g_signal_emit_by_name (self, "actor-added", child);
11047
11048   if (notify_first_last)
11049     {
11050       if (old_first_child != self->priv->first_child)
11051         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11052
11053       if (old_last_child != self->priv->last_child)
11054         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11055     }
11056
11057   g_object_thaw_notify (G_OBJECT (self));
11058 }
11059
11060 /**
11061  * clutter_actor_add_child:
11062  * @self: a #ClutterActor
11063  * @child: a #ClutterActor
11064  *
11065  * Adds @child to the children of @self.
11066  *
11067  * This function will acquire a reference on @child that will only
11068  * be released when calling clutter_actor_remove_child().
11069  *
11070  * This function will take into consideration the #ClutterActor:depth
11071  * of @child, and will keep the list of children sorted.
11072  *
11073  * This function will emit the #ClutterContainer::actor-added signal
11074  * on @self.
11075  *
11076  * Since: 1.10
11077  */
11078 void
11079 clutter_actor_add_child (ClutterActor *self,
11080                          ClutterActor *child)
11081 {
11082   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11083   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11084   g_return_if_fail (self != child);
11085   g_return_if_fail (child->priv->parent == NULL);
11086
11087   clutter_actor_add_child_internal (self, child,
11088                                     ADD_CHILD_DEFAULT_FLAGS,
11089                                     insert_child_at_depth,
11090                                     NULL);
11091 }
11092
11093 /**
11094  * clutter_actor_insert_child_at_index:
11095  * @self: a #ClutterActor
11096  * @child: a #ClutterActor
11097  * @index_: the index
11098  *
11099  * Inserts @child into the list of children of @self, using the
11100  * given @index_. If @index_ is greater than the number of children
11101  * in @self, or is less than 0, then the new child is added at the end.
11102  *
11103  * This function will acquire a reference on @child that will only
11104  * be released when calling clutter_actor_remove_child().
11105  *
11106  * This function will not take into consideration the #ClutterActor:depth
11107  * of @child.
11108  *
11109  * This function will emit the #ClutterContainer::actor-added signal
11110  * on @self.
11111  *
11112  * Since: 1.10
11113  */
11114 void
11115 clutter_actor_insert_child_at_index (ClutterActor *self,
11116                                      ClutterActor *child,
11117                                      gint          index_)
11118 {
11119   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11120   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11121   g_return_if_fail (self != child);
11122   g_return_if_fail (child->priv->parent == NULL);
11123
11124   clutter_actor_add_child_internal (self, child,
11125                                     ADD_CHILD_DEFAULT_FLAGS,
11126                                     insert_child_at_index,
11127                                     GINT_TO_POINTER (index_));
11128 }
11129
11130 /**
11131  * clutter_actor_insert_child_above:
11132  * @self: a #ClutterActor
11133  * @child: a #ClutterActor
11134  * @sibling: (allow-none): a child of @self, or %NULL
11135  *
11136  * Inserts @child into the list of children of @self, above another
11137  * child of @self or, if @sibling is %NULL, above all the children
11138  * of @self.
11139  *
11140  * This function will acquire a reference on @child that will only
11141  * be released when calling clutter_actor_remove_child().
11142  *
11143  * This function will not take into consideration the #ClutterActor:depth
11144  * of @child.
11145  *
11146  * This function will emit the #ClutterContainer::actor-added signal
11147  * on @self.
11148  *
11149  * Since: 1.10
11150  */
11151 void
11152 clutter_actor_insert_child_above (ClutterActor *self,
11153                                   ClutterActor *child,
11154                                   ClutterActor *sibling)
11155 {
11156   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11157   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11158   g_return_if_fail (self != child);
11159   g_return_if_fail (child != sibling);
11160   g_return_if_fail (child->priv->parent == NULL);
11161   g_return_if_fail (sibling == NULL ||
11162                     (CLUTTER_IS_ACTOR (sibling) &&
11163                      sibling->priv->parent == self));
11164
11165   clutter_actor_add_child_internal (self, child,
11166                                     ADD_CHILD_DEFAULT_FLAGS,
11167                                     insert_child_above,
11168                                     sibling);
11169 }
11170
11171 /**
11172  * clutter_actor_insert_child_below:
11173  * @self: a #ClutterActor
11174  * @child: a #ClutterActor
11175  * @sibling: (allow-none): a child of @self, or %NULL
11176  *
11177  * Inserts @child into the list of children of @self, below another
11178  * child of @self or, if @sibling is %NULL, below all the children
11179  * of @self.
11180  *
11181  * This function will acquire a reference on @child that will only
11182  * be released when calling clutter_actor_remove_child().
11183  *
11184  * This function will not take into consideration the #ClutterActor:depth
11185  * of @child.
11186  *
11187  * This function will emit the #ClutterContainer::actor-added signal
11188  * on @self.
11189  *
11190  * Since: 1.10
11191  */
11192 void
11193 clutter_actor_insert_child_below (ClutterActor *self,
11194                                   ClutterActor *child,
11195                                   ClutterActor *sibling)
11196 {
11197   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11198   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11199   g_return_if_fail (self != child);
11200   g_return_if_fail (child != sibling);
11201   g_return_if_fail (child->priv->parent == NULL);
11202   g_return_if_fail (sibling == NULL ||
11203                     (CLUTTER_IS_ACTOR (sibling) &&
11204                      sibling->priv->parent == self));
11205
11206   clutter_actor_add_child_internal (self, child,
11207                                     ADD_CHILD_DEFAULT_FLAGS,
11208                                     insert_child_below,
11209                                     sibling);
11210 }
11211
11212 /**
11213  * clutter_actor_set_parent:
11214  * @self: A #ClutterActor
11215  * @parent: A new #ClutterActor parent
11216  *
11217  * Sets the parent of @self to @parent.
11218  *
11219  * This function will result in @parent acquiring a reference on @self,
11220  * eventually by sinking its floating reference first. The reference
11221  * will be released by clutter_actor_unparent().
11222  *
11223  * This function should only be called by legacy #ClutterActor<!-- -->s
11224  * implementing the #ClutterContainer interface.
11225  *
11226  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11227  */
11228 void
11229 clutter_actor_set_parent (ClutterActor *self,
11230                           ClutterActor *parent)
11231 {
11232   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11233   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11234   g_return_if_fail (self != parent);
11235   g_return_if_fail (self->priv->parent == NULL);
11236
11237   /* as this function will be called inside ClutterContainer::add
11238    * implementations or when building up a composite actor, we have
11239    * to preserve the old behaviour, and not create child meta or
11240    * emit the ::actor-added signal, to avoid recursion or double
11241    * emissions
11242    */
11243   clutter_actor_add_child_internal (parent, self,
11244                                     ADD_CHILD_LEGACY_FLAGS,
11245                                     insert_child_at_depth,
11246                                     NULL);
11247 }
11248
11249 /**
11250  * clutter_actor_get_parent:
11251  * @self: A #ClutterActor
11252  *
11253  * Retrieves the parent of @self.
11254  *
11255  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11256  *  if no parent is set
11257  */
11258 ClutterActor *
11259 clutter_actor_get_parent (ClutterActor *self)
11260 {
11261   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11262
11263   return self->priv->parent;
11264 }
11265
11266 /**
11267  * clutter_actor_get_paint_visibility:
11268  * @self: A #ClutterActor
11269  *
11270  * Retrieves the 'paint' visibility of an actor recursively checking for non
11271  * visible parents.
11272  *
11273  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11274  *
11275  * Return Value: %TRUE if the actor is visibile and will be painted.
11276  *
11277  * Since: 0.8.4
11278  */
11279 gboolean
11280 clutter_actor_get_paint_visibility (ClutterActor *actor)
11281 {
11282   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11283
11284   return CLUTTER_ACTOR_IS_MAPPED (actor);
11285 }
11286
11287 /**
11288  * clutter_actor_remove_child:
11289  * @self: a #ClutterActor
11290  * @child: a #ClutterActor
11291  *
11292  * Removes @child from the children of @self.
11293  *
11294  * This function will release the reference added by
11295  * clutter_actor_add_child(), so if you want to keep using @child
11296  * you will have to acquire a referenced on it before calling this
11297  * function.
11298  *
11299  * This function will emit the #ClutterContainer::actor-removed
11300  * signal on @self.
11301  *
11302  * Since: 1.10
11303  */
11304 void
11305 clutter_actor_remove_child (ClutterActor *self,
11306                             ClutterActor *child)
11307 {
11308   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11309   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11310   g_return_if_fail (self != child);
11311   g_return_if_fail (child->priv->parent != NULL);
11312   g_return_if_fail (child->priv->parent == self);
11313
11314   clutter_actor_remove_child_internal (self, child,
11315                                        REMOVE_CHILD_DEFAULT_FLAGS);
11316 }
11317
11318 /**
11319  * clutter_actor_remove_all_children:
11320  * @self: a #ClutterActor
11321  *
11322  * Removes all children of @self.
11323  *
11324  * This function releases the reference added by inserting a child actor
11325  * in the list of children of @self.
11326  *
11327  * If the reference count of a child drops to zero, the child will be
11328  * destroyed. If you want to ensure the destruction of all the children
11329  * of @self, use clutter_actor_destroy_all_children().
11330  *
11331  * Since: 1.10
11332  */
11333 void
11334 clutter_actor_remove_all_children (ClutterActor *self)
11335 {
11336   ClutterActorIter iter;
11337
11338   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11339
11340   if (self->priv->n_children == 0)
11341     return;
11342
11343   g_object_freeze_notify (G_OBJECT (self));
11344
11345   clutter_actor_iter_init (&iter, self);
11346   while (clutter_actor_iter_next (&iter, NULL))
11347     clutter_actor_iter_remove (&iter);
11348
11349   g_object_thaw_notify (G_OBJECT (self));
11350
11351   /* sanity check */
11352   g_assert (self->priv->first_child == NULL);
11353   g_assert (self->priv->last_child == NULL);
11354   g_assert (self->priv->n_children == 0);
11355 }
11356
11357 /**
11358  * clutter_actor_destroy_all_children:
11359  * @self: a #ClutterActor
11360  *
11361  * Destroys all children of @self.
11362  *
11363  * This function releases the reference added by inserting a child
11364  * actor in the list of children of @self, and ensures that the
11365  * #ClutterActor::destroy signal is emitted on each child of the
11366  * actor.
11367  *
11368  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11369  * when its reference count drops to 0; the default handler of the
11370  * #ClutterActor::destroy signal will destroy all the children of an
11371  * actor. This function ensures that all children are destroyed, instead
11372  * of just removed from @self, unlike clutter_actor_remove_all_children()
11373  * which will merely release the reference and remove each child.
11374  *
11375  * Unless you acquired an additional reference on each child of @self
11376  * prior to calling clutter_actor_remove_all_children() and want to reuse
11377  * the actors, you should use clutter_actor_destroy_all_children() in
11378  * order to make sure that children are destroyed and signal handlers
11379  * are disconnected even in cases where circular references prevent this
11380  * from automatically happening through reference counting alone.
11381  *
11382  * Since: 1.10
11383  */
11384 void
11385 clutter_actor_destroy_all_children (ClutterActor *self)
11386 {
11387   ClutterActorIter iter;
11388
11389   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11390
11391   if (self->priv->n_children == 0)
11392     return;
11393
11394   g_object_freeze_notify (G_OBJECT (self));
11395
11396   clutter_actor_iter_init (&iter, self);
11397   while (clutter_actor_iter_next (&iter, NULL))
11398     clutter_actor_iter_destroy (&iter);
11399
11400   g_object_thaw_notify (G_OBJECT (self));
11401
11402   /* sanity check */
11403   g_assert (self->priv->first_child == NULL);
11404   g_assert (self->priv->last_child == NULL);
11405   g_assert (self->priv->n_children == 0);
11406 }
11407
11408 typedef struct _InsertBetweenData {
11409   ClutterActor *prev_sibling;
11410   ClutterActor *next_sibling;
11411 } InsertBetweenData;
11412
11413 static void
11414 insert_child_between (ClutterActor *self,
11415                       ClutterActor *child,
11416                       gpointer      data_)
11417 {
11418   InsertBetweenData *data = data_;
11419   ClutterActor *prev_sibling = data->prev_sibling;
11420   ClutterActor *next_sibling = data->next_sibling;
11421
11422   child->priv->parent = self;
11423   child->priv->prev_sibling = prev_sibling;
11424   child->priv->next_sibling = next_sibling;
11425
11426   if (prev_sibling != NULL)
11427     prev_sibling->priv->next_sibling = child;
11428
11429   if (next_sibling != NULL)
11430     next_sibling->priv->prev_sibling = child;
11431
11432   if (child->priv->prev_sibling == NULL)
11433     self->priv->first_child = child;
11434
11435   if (child->priv->next_sibling == NULL)
11436     self->priv->last_child = child;
11437 }
11438
11439 /**
11440  * clutter_actor_replace_child:
11441  * @self: a #ClutterActor
11442  * @old_child: the child of @self to replace
11443  * @new_child: the #ClutterActor to replace @old_child
11444  *
11445  * Replaces @old_child with @new_child in the list of children of @self.
11446  *
11447  * Since: 1.10
11448  */
11449 void
11450 clutter_actor_replace_child (ClutterActor *self,
11451                              ClutterActor *old_child,
11452                              ClutterActor *new_child)
11453 {
11454   ClutterActor *prev_sibling, *next_sibling;
11455   InsertBetweenData clos;
11456
11457   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11458   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11459   g_return_if_fail (old_child->priv->parent == self);
11460   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11461   g_return_if_fail (old_child != new_child);
11462   g_return_if_fail (new_child != self);
11463   g_return_if_fail (new_child->priv->parent == NULL);
11464
11465   prev_sibling = old_child->priv->prev_sibling;
11466   next_sibling = old_child->priv->next_sibling;
11467   clutter_actor_remove_child_internal (self, old_child,
11468                                        REMOVE_CHILD_DEFAULT_FLAGS);
11469
11470   clos.prev_sibling = prev_sibling;
11471   clos.next_sibling = next_sibling;
11472   clutter_actor_add_child_internal (self, new_child,
11473                                     ADD_CHILD_DEFAULT_FLAGS,
11474                                     insert_child_between,
11475                                     &clos);
11476 }
11477
11478 /**
11479  * clutter_actor_unparent:
11480  * @self: a #ClutterActor
11481  *
11482  * Removes the parent of @self.
11483  *
11484  * This will cause the parent of @self to release the reference
11485  * acquired when calling clutter_actor_set_parent(), so if you
11486  * want to keep @self you will have to acquire a reference of
11487  * your own, through g_object_ref().
11488  *
11489  * This function should only be called by legacy #ClutterActor<!-- -->s
11490  * implementing the #ClutterContainer interface.
11491  *
11492  * Since: 0.1.1
11493  *
11494  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11495  */
11496 void
11497 clutter_actor_unparent (ClutterActor *self)
11498 {
11499   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11500
11501   if (self->priv->parent == NULL)
11502     return;
11503
11504   clutter_actor_remove_child_internal (self->priv->parent, self,
11505                                        REMOVE_CHILD_LEGACY_FLAGS);
11506 }
11507
11508 /**
11509  * clutter_actor_reparent:
11510  * @self: a #ClutterActor
11511  * @new_parent: the new #ClutterActor parent
11512  *
11513  * Resets the parent actor of @self.
11514  *
11515  * This function is logically equivalent to calling clutter_actor_unparent()
11516  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11517  * ensures the child is not finalized when unparented, and emits the
11518  * #ClutterActor::parent-set signal only once.
11519  *
11520  * In reality, calling this function is less useful than it sounds, as some
11521  * application code may rely on changes in the intermediate state between
11522  * removal and addition of the actor from its old parent to the @new_parent.
11523  * Thus, it is strongly encouraged to avoid using this function in application
11524  * code.
11525  *
11526  * Since: 0.2
11527  *
11528  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11529  *   clutter_actor_add_child() instead; remember to take a reference on
11530  *   the actor being removed before calling clutter_actor_remove_child()
11531  *   to avoid the reference count dropping to zero and the actor being
11532  *   destroyed.
11533  */
11534 void
11535 clutter_actor_reparent (ClutterActor *self,
11536                         ClutterActor *new_parent)
11537 {
11538   ClutterActorPrivate *priv;
11539
11540   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11541   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11542   g_return_if_fail (self != new_parent);
11543
11544   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11545     {
11546       g_warning ("Cannot set a parent on a toplevel actor");
11547       return;
11548     }
11549
11550   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11551     {
11552       g_warning ("Cannot set a parent currently being destroyed");
11553       return;
11554     }
11555
11556   priv = self->priv;
11557
11558   if (priv->parent != new_parent)
11559     {
11560       ClutterActor *old_parent;
11561
11562       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11563
11564       old_parent = priv->parent;
11565
11566       g_object_ref (self);
11567
11568       if (old_parent != NULL)
11569         {
11570          /* go through the Container implementation if this is a regular
11571           * child and not an internal one
11572           */
11573          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11574            {
11575              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11576
11577              /* this will have to call unparent() */
11578              clutter_container_remove_actor (parent, self);
11579            }
11580          else
11581            clutter_actor_remove_child_internal (old_parent, self,
11582                                                 REMOVE_CHILD_LEGACY_FLAGS);
11583         }
11584
11585       /* Note, will call set_parent() */
11586       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11587         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11588       else
11589         clutter_actor_add_child_internal (new_parent, self,
11590                                           ADD_CHILD_LEGACY_FLAGS,
11591                                           insert_child_at_depth,
11592                                           NULL);
11593
11594       /* we emit the ::parent-set signal once */
11595       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11596
11597       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11598
11599       /* the IN_REPARENT flag suspends state updates */
11600       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11601
11602       g_object_unref (self);
11603    }
11604 }
11605
11606 /**
11607  * clutter_actor_contains:
11608  * @self: A #ClutterActor
11609  * @descendant: A #ClutterActor, possibly contained in @self
11610  *
11611  * Determines if @descendant is contained inside @self (either as an
11612  * immediate child, or as a deeper descendant). If @self and
11613  * @descendant point to the same actor then it will also return %TRUE.
11614  *
11615  * Return value: whether @descendent is contained within @self
11616  *
11617  * Since: 1.4
11618  */
11619 gboolean
11620 clutter_actor_contains (ClutterActor *self,
11621                         ClutterActor *descendant)
11622 {
11623   ClutterActor *actor;
11624
11625   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11626   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11627
11628   for (actor = descendant; actor; actor = actor->priv->parent)
11629     if (actor == self)
11630       return TRUE;
11631
11632   return FALSE;
11633 }
11634
11635 /**
11636  * clutter_actor_set_child_above_sibling:
11637  * @self: a #ClutterActor
11638  * @child: a #ClutterActor child of @self
11639  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11640  *
11641  * Sets @child to be above @sibling in the list of children of @self.
11642  *
11643  * If @sibling is %NULL, @child will be the new last child of @self.
11644  *
11645  * This function is logically equivalent to removing @child and using
11646  * clutter_actor_insert_child_above(), but it will not emit signals
11647  * or change state on @child.
11648  *
11649  * Since: 1.10
11650  */
11651 void
11652 clutter_actor_set_child_above_sibling (ClutterActor *self,
11653                                        ClutterActor *child,
11654                                        ClutterActor *sibling)
11655 {
11656   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11657   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11658   g_return_if_fail (child->priv->parent == self);
11659   g_return_if_fail (child != sibling);
11660   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11661
11662   if (sibling != NULL)
11663     g_return_if_fail (sibling->priv->parent == self);
11664
11665   /* we don't want to change the state of child, or emit signals, or
11666    * regenerate ChildMeta instances here, but we still want to follow
11667    * the correct sequence of steps encoded in remove_child() and
11668    * add_child(), so that correctness is ensured, and we only go
11669    * through one known code path.
11670    */
11671   g_object_ref (child);
11672   clutter_actor_remove_child_internal (self, child, 0);
11673   clutter_actor_add_child_internal (self, child,
11674                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11675                                     insert_child_above,
11676                                     sibling);
11677
11678   clutter_actor_queue_relayout (self);
11679 }
11680
11681 /**
11682  * clutter_actor_set_child_below_sibling:
11683  * @self: a #ClutterActor
11684  * @child: a #ClutterActor child of @self
11685  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11686  *
11687  * Sets @child to be below @sibling in the list of children of @self.
11688  *
11689  * If @sibling is %NULL, @child will be the new first child of @self.
11690  *
11691  * This function is logically equivalent to removing @self and using
11692  * clutter_actor_insert_child_below(), but it will not emit signals
11693  * or change state on @child.
11694  *
11695  * Since: 1.10
11696  */
11697 void
11698 clutter_actor_set_child_below_sibling (ClutterActor *self,
11699                                        ClutterActor *child,
11700                                        ClutterActor *sibling)
11701 {
11702   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11703   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11704   g_return_if_fail (child->priv->parent == self);
11705   g_return_if_fail (child != sibling);
11706   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11707
11708   if (sibling != NULL)
11709     g_return_if_fail (sibling->priv->parent == self);
11710
11711   /* see the comment in set_child_above_sibling() */
11712   g_object_ref (child);
11713   clutter_actor_remove_child_internal (self, child, 0);
11714   clutter_actor_add_child_internal (self, child,
11715                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11716                                     insert_child_below,
11717                                     sibling);
11718
11719   clutter_actor_queue_relayout (self);
11720 }
11721
11722 /**
11723  * clutter_actor_set_child_at_index:
11724  * @self: a #ClutterActor
11725  * @child: a #ClutterActor child of @self
11726  * @index_: the new index for @child
11727  *
11728  * Changes the index of @child in the list of children of @self.
11729  *
11730  * This function is logically equivalent to removing @child and
11731  * calling clutter_actor_insert_child_at_index(), but it will not
11732  * emit signals or change state on @child.
11733  *
11734  * Since: 1.10
11735  */
11736 void
11737 clutter_actor_set_child_at_index (ClutterActor *self,
11738                                   ClutterActor *child,
11739                                   gint          index_)
11740 {
11741   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11742   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11743   g_return_if_fail (child->priv->parent == self);
11744   g_return_if_fail (index_ <= self->priv->n_children);
11745
11746   g_object_ref (child);
11747   clutter_actor_remove_child_internal (self, child, 0);
11748   clutter_actor_add_child_internal (self, child,
11749                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11750                                     insert_child_at_index,
11751                                     GINT_TO_POINTER (index_));
11752
11753   clutter_actor_queue_relayout (self);
11754 }
11755
11756 /**
11757  * clutter_actor_raise:
11758  * @self: A #ClutterActor
11759  * @below: (allow-none): A #ClutterActor to raise above.
11760  *
11761  * Puts @self above @below.
11762  *
11763  * Both actors must have the same parent, and the parent must implement
11764  * the #ClutterContainer interface
11765  *
11766  * This function calls clutter_container_raise_child() internally.
11767  *
11768  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11769  */
11770 void
11771 clutter_actor_raise (ClutterActor *self,
11772                      ClutterActor *below)
11773 {
11774   ClutterActor *parent;
11775
11776   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11777
11778   parent = clutter_actor_get_parent (self);
11779   if (parent == NULL)
11780     {
11781       g_warning ("%s: Actor '%s' is not inside a container",
11782                  G_STRFUNC,
11783                  _clutter_actor_get_debug_name (self));
11784       return;
11785     }
11786
11787   if (below != NULL)
11788     {
11789       if (parent != clutter_actor_get_parent (below))
11790         {
11791           g_warning ("%s Actor '%s' is not in the same container as "
11792                      "actor '%s'",
11793                      G_STRFUNC,
11794                      _clutter_actor_get_debug_name (self),
11795                      _clutter_actor_get_debug_name (below));
11796           return;
11797         }
11798     }
11799
11800   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11801 }
11802
11803 /**
11804  * clutter_actor_lower:
11805  * @self: A #ClutterActor
11806  * @above: (allow-none): A #ClutterActor to lower below
11807  *
11808  * Puts @self below @above.
11809  *
11810  * Both actors must have the same parent, and the parent must implement
11811  * the #ClutterContainer interface.
11812  *
11813  * This function calls clutter_container_lower_child() internally.
11814  *
11815  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11816  */
11817 void
11818 clutter_actor_lower (ClutterActor *self,
11819                      ClutterActor *above)
11820 {
11821   ClutterActor *parent;
11822
11823   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11824
11825   parent = clutter_actor_get_parent (self);
11826   if (parent == NULL)
11827     {
11828       g_warning ("%s: Actor of type %s is not inside a container",
11829                  G_STRFUNC,
11830                  _clutter_actor_get_debug_name (self));
11831       return;
11832     }
11833
11834   if (above)
11835     {
11836       if (parent != clutter_actor_get_parent (above))
11837         {
11838           g_warning ("%s: Actor '%s' is not in the same container as "
11839                      "actor '%s'",
11840                      G_STRFUNC,
11841                      _clutter_actor_get_debug_name (self),
11842                      _clutter_actor_get_debug_name (above));
11843           return;
11844         }
11845     }
11846
11847   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11848 }
11849
11850 /**
11851  * clutter_actor_raise_top:
11852  * @self: A #ClutterActor
11853  *
11854  * Raises @self to the top.
11855  *
11856  * This function calls clutter_actor_raise() internally.
11857  *
11858  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11859  *   a %NULL sibling, instead.
11860  */
11861 void
11862 clutter_actor_raise_top (ClutterActor *self)
11863 {
11864   clutter_actor_raise (self, NULL);
11865 }
11866
11867 /**
11868  * clutter_actor_lower_bottom:
11869  * @self: A #ClutterActor
11870  *
11871  * Lowers @self to the bottom.
11872  *
11873  * This function calls clutter_actor_lower() internally.
11874  *
11875  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11876  *   a %NULL sibling, instead.
11877  */
11878 void
11879 clutter_actor_lower_bottom (ClutterActor *self)
11880 {
11881   clutter_actor_lower (self, NULL);
11882 }
11883
11884 /*
11885  * Event handling
11886  */
11887
11888 /**
11889  * clutter_actor_event:
11890  * @actor: a #ClutterActor
11891  * @event: a #ClutterEvent
11892  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11893  *
11894  * This function is used to emit an event on the main stage.
11895  * You should rarely need to use this function, except for
11896  * synthetising events.
11897  *
11898  * Return value: the return value from the signal emission: %TRUE
11899  *   if the actor handled the event, or %FALSE if the event was
11900  *   not handled
11901  *
11902  * Since: 0.6
11903  */
11904 gboolean
11905 clutter_actor_event (ClutterActor *actor,
11906                      ClutterEvent *event,
11907                      gboolean      capture)
11908 {
11909   gboolean retval = FALSE;
11910   gint signal_num = -1;
11911
11912   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11913   g_return_val_if_fail (event != NULL, FALSE);
11914
11915   g_object_ref (actor);
11916
11917   if (capture)
11918     {
11919       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11920                      event,
11921                      &retval);
11922       goto out;
11923     }
11924
11925   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11926
11927   if (!retval)
11928     {
11929       switch (event->type)
11930         {
11931         case CLUTTER_NOTHING:
11932           break;
11933         case CLUTTER_BUTTON_PRESS:
11934           signal_num = BUTTON_PRESS_EVENT;
11935           break;
11936         case CLUTTER_BUTTON_RELEASE:
11937           signal_num = BUTTON_RELEASE_EVENT;
11938           break;
11939         case CLUTTER_SCROLL:
11940           signal_num = SCROLL_EVENT;
11941           break;
11942         case CLUTTER_KEY_PRESS:
11943           signal_num = KEY_PRESS_EVENT;
11944           break;
11945         case CLUTTER_KEY_RELEASE:
11946           signal_num = KEY_RELEASE_EVENT;
11947           break;
11948         case CLUTTER_MOTION:
11949           signal_num = MOTION_EVENT;
11950           break;
11951         case CLUTTER_ENTER:
11952           signal_num = ENTER_EVENT;
11953           break;
11954         case CLUTTER_LEAVE:
11955           signal_num = LEAVE_EVENT;
11956           break;
11957         case CLUTTER_DELETE:
11958         case CLUTTER_DESTROY_NOTIFY:
11959         case CLUTTER_CLIENT_MESSAGE:
11960         default:
11961           signal_num = -1;
11962           break;
11963         }
11964
11965       if (signal_num != -1)
11966         g_signal_emit (actor, actor_signals[signal_num], 0,
11967                        event, &retval);
11968     }
11969
11970 out:
11971   g_object_unref (actor);
11972
11973   return retval;
11974 }
11975
11976 /**
11977  * clutter_actor_set_reactive:
11978  * @actor: a #ClutterActor
11979  * @reactive: whether the actor should be reactive to events
11980  *
11981  * Sets @actor as reactive. Reactive actors will receive events.
11982  *
11983  * Since: 0.6
11984  */
11985 void
11986 clutter_actor_set_reactive (ClutterActor *actor,
11987                             gboolean      reactive)
11988 {
11989   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11990
11991   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11992     return;
11993
11994   if (reactive)
11995     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11996   else
11997     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11998
11999   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12000 }
12001
12002 /**
12003  * clutter_actor_get_reactive:
12004  * @actor: a #ClutterActor
12005  *
12006  * Checks whether @actor is marked as reactive.
12007  *
12008  * Return value: %TRUE if the actor is reactive
12009  *
12010  * Since: 0.6
12011  */
12012 gboolean
12013 clutter_actor_get_reactive (ClutterActor *actor)
12014 {
12015   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12016
12017   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12018 }
12019
12020 /**
12021  * clutter_actor_get_anchor_point:
12022  * @self: a #ClutterActor
12023  * @anchor_x: (out): return location for the X coordinate of the anchor point
12024  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12025  *
12026  * Gets the current anchor point of the @actor in pixels.
12027  *
12028  * Since: 0.6
12029  */
12030 void
12031 clutter_actor_get_anchor_point (ClutterActor *self,
12032                                 gfloat       *anchor_x,
12033                                 gfloat       *anchor_y)
12034 {
12035   const ClutterTransformInfo *info;
12036
12037   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12038
12039   info = _clutter_actor_get_transform_info_or_defaults (self);
12040   clutter_anchor_coord_get_units (self, &info->anchor,
12041                                   anchor_x,
12042                                   anchor_y,
12043                                   NULL);
12044 }
12045
12046 /**
12047  * clutter_actor_set_anchor_point:
12048  * @self: a #ClutterActor
12049  * @anchor_x: X coordinate of the anchor point
12050  * @anchor_y: Y coordinate of the anchor point
12051  *
12052  * Sets an anchor point for @self. The anchor point is a point in the
12053  * coordinate space of an actor to which the actor position within its
12054  * parent is relative; the default is (0, 0), i.e. the top-left corner
12055  * of the actor.
12056  *
12057  * Since: 0.6
12058  */
12059 void
12060 clutter_actor_set_anchor_point (ClutterActor *self,
12061                                 gfloat        anchor_x,
12062                                 gfloat        anchor_y)
12063 {
12064   ClutterTransformInfo *info;
12065   ClutterActorPrivate *priv;
12066   gboolean changed = FALSE;
12067   gfloat old_anchor_x, old_anchor_y;
12068   GObject *obj;
12069
12070   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12071
12072   obj = G_OBJECT (self);
12073   priv = self->priv;
12074   info = _clutter_actor_get_transform_info (self);
12075
12076   g_object_freeze_notify (obj);
12077
12078   clutter_anchor_coord_get_units (self, &info->anchor,
12079                                   &old_anchor_x,
12080                                   &old_anchor_y,
12081                                   NULL);
12082
12083   if (info->anchor.is_fractional)
12084     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12085
12086   if (old_anchor_x != anchor_x)
12087     {
12088       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12089       changed = TRUE;
12090     }
12091
12092   if (old_anchor_y != anchor_y)
12093     {
12094       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12095       changed = TRUE;
12096     }
12097
12098   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12099
12100   if (changed)
12101     {
12102       priv->transform_valid = FALSE;
12103       clutter_actor_queue_redraw (self);
12104     }
12105
12106   g_object_thaw_notify (obj);
12107 }
12108
12109 /**
12110  * clutter_actor_get_anchor_point_gravity:
12111  * @self: a #ClutterActor
12112  *
12113  * Retrieves the anchor position expressed as a #ClutterGravity. If
12114  * the anchor point was specified using pixels or units this will
12115  * return %CLUTTER_GRAVITY_NONE.
12116  *
12117  * Return value: the #ClutterGravity used by the anchor point
12118  *
12119  * Since: 1.0
12120  */
12121 ClutterGravity
12122 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12123 {
12124   const ClutterTransformInfo *info;
12125
12126   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12127
12128   info = _clutter_actor_get_transform_info_or_defaults (self);
12129
12130   return clutter_anchor_coord_get_gravity (&info->anchor);
12131 }
12132
12133 /**
12134  * clutter_actor_move_anchor_point:
12135  * @self: a #ClutterActor
12136  * @anchor_x: X coordinate of the anchor point
12137  * @anchor_y: Y coordinate of the anchor point
12138  *
12139  * Sets an anchor point for the actor, and adjusts the actor postion so that
12140  * the relative position of the actor toward its parent remains the same.
12141  *
12142  * Since: 0.6
12143  */
12144 void
12145 clutter_actor_move_anchor_point (ClutterActor *self,
12146                                  gfloat        anchor_x,
12147                                  gfloat        anchor_y)
12148 {
12149   gfloat old_anchor_x, old_anchor_y;
12150   const ClutterTransformInfo *info;
12151
12152   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12153
12154   info = _clutter_actor_get_transform_info (self);
12155   clutter_anchor_coord_get_units (self, &info->anchor,
12156                                   &old_anchor_x,
12157                                   &old_anchor_y,
12158                                   NULL);
12159
12160   g_object_freeze_notify (G_OBJECT (self));
12161
12162   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12163
12164   if (self->priv->position_set)
12165     clutter_actor_move_by (self,
12166                            anchor_x - old_anchor_x,
12167                            anchor_y - old_anchor_y);
12168
12169   g_object_thaw_notify (G_OBJECT (self));
12170 }
12171
12172 /**
12173  * clutter_actor_move_anchor_point_from_gravity:
12174  * @self: a #ClutterActor
12175  * @gravity: #ClutterGravity.
12176  *
12177  * Sets an anchor point on the actor based on the given gravity, adjusting the
12178  * actor postion so that its relative position within its parent remains
12179  * unchanged.
12180  *
12181  * Since version 1.0 the anchor point will be stored as a gravity so
12182  * that if the actor changes size then the anchor point will move. For
12183  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12184  * and later double the size of the actor, the anchor point will move
12185  * to the bottom right.
12186  *
12187  * Since: 0.6
12188  */
12189 void
12190 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12191                                               ClutterGravity  gravity)
12192 {
12193   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12194   const ClutterTransformInfo *info;
12195   ClutterActorPrivate *priv;
12196
12197   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12198
12199   priv = self->priv;
12200   info = _clutter_actor_get_transform_info (self);
12201
12202   g_object_freeze_notify (G_OBJECT (self));
12203
12204   clutter_anchor_coord_get_units (self, &info->anchor,
12205                                   &old_anchor_x,
12206                                   &old_anchor_y,
12207                                   NULL);
12208   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12209   clutter_anchor_coord_get_units (self, &info->anchor,
12210                                   &new_anchor_x,
12211                                   &new_anchor_y,
12212                                   NULL);
12213
12214   if (priv->position_set)
12215     clutter_actor_move_by (self,
12216                            new_anchor_x - old_anchor_x,
12217                            new_anchor_y - old_anchor_y);
12218
12219   g_object_thaw_notify (G_OBJECT (self));
12220 }
12221
12222 /**
12223  * clutter_actor_set_anchor_point_from_gravity:
12224  * @self: a #ClutterActor
12225  * @gravity: #ClutterGravity.
12226  *
12227  * Sets an anchor point on the actor, based on the given gravity (this is a
12228  * convenience function wrapping clutter_actor_set_anchor_point()).
12229  *
12230  * Since version 1.0 the anchor point will be stored as a gravity so
12231  * that if the actor changes size then the anchor point will move. For
12232  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12233  * and later double the size of the actor, the anchor point will move
12234  * to the bottom right.
12235  *
12236  * Since: 0.6
12237  */
12238 void
12239 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12240                                              ClutterGravity  gravity)
12241 {
12242   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12243
12244   if (gravity == CLUTTER_GRAVITY_NONE)
12245     clutter_actor_set_anchor_point (self, 0, 0);
12246   else
12247     {
12248       GObject *obj = G_OBJECT (self);
12249       ClutterTransformInfo *info;
12250
12251       g_object_freeze_notify (obj);
12252
12253       info = _clutter_actor_get_transform_info (self);
12254       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12255
12256       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12257       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12258       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12259
12260       self->priv->transform_valid = FALSE;
12261
12262       clutter_actor_queue_redraw (self);
12263
12264       g_object_thaw_notify (obj);
12265     }
12266 }
12267
12268 static void
12269 clutter_container_iface_init (ClutterContainerIface *iface)
12270 {
12271   /* we don't override anything, as ClutterContainer already has a default
12272    * implementation that we can use, and which calls into our own API.
12273    */
12274 }
12275
12276 typedef enum
12277 {
12278   PARSE_X,
12279   PARSE_Y,
12280   PARSE_WIDTH,
12281   PARSE_HEIGHT,
12282   PARSE_ANCHOR_X,
12283   PARSE_ANCHOR_Y
12284 } ParseDimension;
12285
12286 static gfloat
12287 parse_units (ClutterActor   *self,
12288              ParseDimension  dimension,
12289              JsonNode       *node)
12290 {
12291   GValue value = G_VALUE_INIT;
12292   gfloat retval = 0;
12293
12294   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12295     return 0;
12296
12297   json_node_get_value (node, &value);
12298
12299   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12300     {
12301       retval = (gfloat) g_value_get_int64 (&value);
12302     }
12303   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12304     {
12305       retval = g_value_get_double (&value);
12306     }
12307   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12308     {
12309       ClutterUnits units;
12310       gboolean res;
12311
12312       res = clutter_units_from_string (&units, g_value_get_string (&value));
12313       if (res)
12314         retval = clutter_units_to_pixels (&units);
12315       else
12316         {
12317           g_warning ("Invalid value '%s': integers, strings or floating point "
12318                      "values can be used for the x, y, width and height "
12319                      "properties. Valid modifiers for strings are 'px', 'mm', "
12320                      "'pt' and 'em'.",
12321                      g_value_get_string (&value));
12322           retval = 0;
12323         }
12324     }
12325   else
12326     {
12327       g_warning ("Invalid value of type '%s': integers, strings of floating "
12328                  "point values can be used for the x, y, width, height "
12329                  "anchor-x and anchor-y properties.",
12330                  g_type_name (G_VALUE_TYPE (&value)));
12331     }
12332
12333   g_value_unset (&value);
12334
12335   return retval;
12336 }
12337
12338 typedef struct {
12339   ClutterRotateAxis axis;
12340
12341   gdouble angle;
12342
12343   gfloat center_x;
12344   gfloat center_y;
12345   gfloat center_z;
12346 } RotationInfo;
12347
12348 static inline gboolean
12349 parse_rotation_array (ClutterActor *actor,
12350                       JsonArray    *array,
12351                       RotationInfo *info)
12352 {
12353   JsonNode *element;
12354
12355   if (json_array_get_length (array) != 2)
12356     return FALSE;
12357
12358   /* angle */
12359   element = json_array_get_element (array, 0);
12360   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12361     info->angle = json_node_get_double (element);
12362   else
12363     return FALSE;
12364
12365   /* center */
12366   element = json_array_get_element (array, 1);
12367   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12368     {
12369       JsonArray *center = json_node_get_array (element);
12370
12371       if (json_array_get_length (center) != 2)
12372         return FALSE;
12373
12374       switch (info->axis)
12375         {
12376         case CLUTTER_X_AXIS:
12377           info->center_y = parse_units (actor, PARSE_Y,
12378                                         json_array_get_element (center, 0));
12379           info->center_z = parse_units (actor, PARSE_Y,
12380                                         json_array_get_element (center, 1));
12381           return TRUE;
12382
12383         case CLUTTER_Y_AXIS:
12384           info->center_x = parse_units (actor, PARSE_X,
12385                                         json_array_get_element (center, 0));
12386           info->center_z = parse_units (actor, PARSE_X,
12387                                         json_array_get_element (center, 1));
12388           return TRUE;
12389
12390         case CLUTTER_Z_AXIS:
12391           info->center_x = parse_units (actor, PARSE_X,
12392                                         json_array_get_element (center, 0));
12393           info->center_y = parse_units (actor, PARSE_Y,
12394                                         json_array_get_element (center, 1));
12395           return TRUE;
12396         }
12397     }
12398
12399   return FALSE;
12400 }
12401
12402 static gboolean
12403 parse_rotation (ClutterActor *actor,
12404                 JsonNode     *node,
12405                 RotationInfo *info)
12406 {
12407   JsonArray *array;
12408   guint len, i;
12409   gboolean retval = FALSE;
12410
12411   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12412     {
12413       g_warning ("Invalid node of type '%s' found, expecting an array",
12414                  json_node_type_name (node));
12415       return FALSE;
12416     }
12417
12418   array = json_node_get_array (node);
12419   len = json_array_get_length (array);
12420
12421   for (i = 0; i < len; i++)
12422     {
12423       JsonNode *element = json_array_get_element (array, i);
12424       JsonObject *object;
12425       JsonNode *member;
12426
12427       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12428         {
12429           g_warning ("Invalid node of type '%s' found, expecting an object",
12430                      json_node_type_name (element));
12431           return FALSE;
12432         }
12433
12434       object = json_node_get_object (element);
12435
12436       if (json_object_has_member (object, "x-axis"))
12437         {
12438           member = json_object_get_member (object, "x-axis");
12439
12440           info->axis = CLUTTER_X_AXIS;
12441
12442           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12443             {
12444               info->angle = json_node_get_double (member);
12445               retval = TRUE;
12446             }
12447           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12448             retval = parse_rotation_array (actor,
12449                                            json_node_get_array (member),
12450                                            info);
12451           else
12452             retval = FALSE;
12453         }
12454       else if (json_object_has_member (object, "y-axis"))
12455         {
12456           member = json_object_get_member (object, "y-axis");
12457
12458           info->axis = CLUTTER_Y_AXIS;
12459
12460           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12461             {
12462               info->angle = json_node_get_double (member);
12463               retval = TRUE;
12464             }
12465           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12466             retval = parse_rotation_array (actor,
12467                                            json_node_get_array (member),
12468                                            info);
12469           else
12470             retval = FALSE;
12471         }
12472       else if (json_object_has_member (object, "z-axis"))
12473         {
12474           member = json_object_get_member (object, "z-axis");
12475
12476           info->axis = CLUTTER_Z_AXIS;
12477
12478           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12479             {
12480               info->angle = json_node_get_double (member);
12481               retval = TRUE;
12482             }
12483           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12484             retval = parse_rotation_array (actor,
12485                                            json_node_get_array (member),
12486                                            info);
12487           else
12488             retval = FALSE;
12489         }
12490     }
12491
12492   return retval;
12493 }
12494
12495 static GSList *
12496 parse_actor_metas (ClutterScript *script,
12497                    ClutterActor  *actor,
12498                    JsonNode      *node)
12499 {
12500   GList *elements, *l;
12501   GSList *retval = NULL;
12502
12503   if (!JSON_NODE_HOLDS_ARRAY (node))
12504     return NULL;
12505
12506   elements = json_array_get_elements (json_node_get_array (node));
12507
12508   for (l = elements; l != NULL; l = l->next)
12509     {
12510       JsonNode *element = l->data;
12511       const gchar *id_ = _clutter_script_get_id_from_node (element);
12512       GObject *meta;
12513
12514       if (id_ == NULL || *id_ == '\0')
12515         continue;
12516
12517       meta = clutter_script_get_object (script, id_);
12518       if (meta == NULL)
12519         continue;
12520
12521       retval = g_slist_prepend (retval, meta);
12522     }
12523
12524   g_list_free (elements);
12525
12526   return g_slist_reverse (retval);
12527 }
12528
12529 static GSList *
12530 parse_behaviours (ClutterScript *script,
12531                   ClutterActor  *actor,
12532                   JsonNode      *node)
12533 {
12534   GList *elements, *l;
12535   GSList *retval = NULL;
12536
12537   if (!JSON_NODE_HOLDS_ARRAY (node))
12538     return NULL;
12539
12540   elements = json_array_get_elements (json_node_get_array (node));
12541
12542   for (l = elements; l != NULL; l = l->next)
12543     {
12544       JsonNode *element = l->data;
12545       const gchar *id_ = _clutter_script_get_id_from_node (element);
12546       GObject *behaviour;
12547
12548       if (id_ == NULL || *id_ == '\0')
12549         continue;
12550
12551       behaviour = clutter_script_get_object (script, id_);
12552       if (behaviour == NULL)
12553         continue;
12554
12555       retval = g_slist_prepend (retval, behaviour);
12556     }
12557
12558   g_list_free (elements);
12559
12560   return g_slist_reverse (retval);
12561 }
12562
12563 static gboolean
12564 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12565                                  ClutterScript     *script,
12566                                  GValue            *value,
12567                                  const gchar       *name,
12568                                  JsonNode          *node)
12569 {
12570   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12571   gboolean retval = FALSE;
12572
12573   if ((name[0] == 'x' && name[1] == '\0') ||
12574       (name[0] == 'y' && name[1] == '\0') ||
12575       (strcmp (name, "width") == 0) ||
12576       (strcmp (name, "height") == 0) ||
12577       (strcmp (name, "anchor_x") == 0) ||
12578       (strcmp (name, "anchor_y") == 0))
12579     {
12580       ParseDimension dimension;
12581       gfloat units;
12582
12583       if (name[0] == 'x')
12584         dimension = PARSE_X;
12585       else if (name[0] == 'y')
12586         dimension = PARSE_Y;
12587       else if (name[0] == 'w')
12588         dimension = PARSE_WIDTH;
12589       else if (name[0] == 'h')
12590         dimension = PARSE_HEIGHT;
12591       else if (name[0] == 'a' && name[7] == 'x')
12592         dimension = PARSE_ANCHOR_X;
12593       else if (name[0] == 'a' && name[7] == 'y')
12594         dimension = PARSE_ANCHOR_Y;
12595       else
12596         return FALSE;
12597
12598       units = parse_units (actor, dimension, node);
12599
12600       /* convert back to pixels: all properties are pixel-based */
12601       g_value_init (value, G_TYPE_FLOAT);
12602       g_value_set_float (value, units);
12603
12604       retval = TRUE;
12605     }
12606   else if (strcmp (name, "rotation") == 0)
12607     {
12608       RotationInfo *info;
12609
12610       info = g_slice_new0 (RotationInfo);
12611       retval = parse_rotation (actor, node, info);
12612
12613       if (retval)
12614         {
12615           g_value_init (value, G_TYPE_POINTER);
12616           g_value_set_pointer (value, info);
12617         }
12618       else
12619         g_slice_free (RotationInfo, info);
12620     }
12621   else if (strcmp (name, "behaviours") == 0)
12622     {
12623       GSList *l;
12624
12625 #ifdef CLUTTER_ENABLE_DEBUG
12626       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12627         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12628                                      "and it should not be used in newly "
12629                                      "written ClutterScript definitions.");
12630 #endif
12631
12632       l = parse_behaviours (script, actor, node);
12633
12634       g_value_init (value, G_TYPE_POINTER);
12635       g_value_set_pointer (value, l);
12636
12637       retval = TRUE;
12638     }
12639   else if (strcmp (name, "actions") == 0 ||
12640            strcmp (name, "constraints") == 0 ||
12641            strcmp (name, "effects") == 0)
12642     {
12643       GSList *l;
12644
12645       l = parse_actor_metas (script, actor, node);
12646
12647       g_value_init (value, G_TYPE_POINTER);
12648       g_value_set_pointer (value, l);
12649
12650       retval = TRUE;
12651     }
12652
12653   return retval;
12654 }
12655
12656 static void
12657 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12658                                    ClutterScript     *script,
12659                                    const gchar       *name,
12660                                    const GValue      *value)
12661 {
12662   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12663
12664 #ifdef CLUTTER_ENABLE_DEBUG
12665   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12666     {
12667       gchar *tmp = g_strdup_value_contents (value);
12668
12669       CLUTTER_NOTE (SCRIPT,
12670                     "in ClutterActor::set_custom_property('%s') = %s",
12671                     name,
12672                     tmp);
12673
12674       g_free (tmp);
12675     }
12676 #endif /* CLUTTER_ENABLE_DEBUG */
12677
12678   if (strcmp (name, "rotation") == 0)
12679     {
12680       RotationInfo *info;
12681
12682       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12683         return;
12684
12685       info = g_value_get_pointer (value);
12686
12687       clutter_actor_set_rotation (actor,
12688                                   info->axis, info->angle,
12689                                   info->center_x,
12690                                   info->center_y,
12691                                   info->center_z);
12692
12693       g_slice_free (RotationInfo, info);
12694
12695       return;
12696     }
12697
12698   if (strcmp (name, "behaviours") == 0)
12699     {
12700       GSList *behaviours, *l;
12701
12702       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12703         return;
12704
12705       behaviours = g_value_get_pointer (value);
12706       for (l = behaviours; l != NULL; l = l->next)
12707         {
12708           ClutterBehaviour *behaviour = l->data;
12709
12710           clutter_behaviour_apply (behaviour, actor);
12711         }
12712
12713       g_slist_free (behaviours);
12714
12715       return;
12716     }
12717
12718   if (strcmp (name, "actions") == 0 ||
12719       strcmp (name, "constraints") == 0 ||
12720       strcmp (name, "effects") == 0)
12721     {
12722       GSList *metas, *l;
12723
12724       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12725         return;
12726
12727       metas = g_value_get_pointer (value);
12728       for (l = metas; l != NULL; l = l->next)
12729         {
12730           if (name[0] == 'a')
12731             clutter_actor_add_action (actor, l->data);
12732
12733           if (name[0] == 'c')
12734             clutter_actor_add_constraint (actor, l->data);
12735
12736           if (name[0] == 'e')
12737             clutter_actor_add_effect (actor, l->data);
12738         }
12739
12740       g_slist_free (metas);
12741
12742       return;
12743     }
12744
12745   g_object_set_property (G_OBJECT (scriptable), name, value);
12746 }
12747
12748 static void
12749 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12750 {
12751   iface->parse_custom_node = clutter_actor_parse_custom_node;
12752   iface->set_custom_property = clutter_actor_set_custom_property;
12753 }
12754
12755 static ClutterActorMeta *
12756 get_meta_from_animation_property (ClutterActor  *actor,
12757                                   const gchar   *name,
12758                                   gchar        **name_p)
12759 {
12760   ClutterActorPrivate *priv = actor->priv;
12761   ClutterActorMeta *meta = NULL;
12762   gchar **tokens;
12763
12764   /* if this is not a special property, fall through */
12765   if (name[0] != '@')
12766     return NULL;
12767
12768   /* detect the properties named using the following spec:
12769    *
12770    *   @<section>.<meta-name>.<property-name>
12771    *
12772    * where <section> can be one of the following:
12773    *
12774    *   - actions
12775    *   - constraints
12776    *   - effects
12777    *
12778    * and <meta-name> is the name set on a specific ActorMeta
12779    */
12780
12781   tokens = g_strsplit (name + 1, ".", -1);
12782   if (tokens == NULL || g_strv_length (tokens) != 3)
12783     {
12784       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12785                     name + 1);
12786       g_strfreev (tokens);
12787       return NULL;
12788     }
12789
12790   if (strcmp (tokens[0], "actions") == 0)
12791     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12792
12793   if (strcmp (tokens[0], "constraints") == 0)
12794     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12795
12796   if (strcmp (tokens[0], "effects") == 0)
12797     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12798
12799   if (name_p != NULL)
12800     *name_p = g_strdup (tokens[2]);
12801
12802   CLUTTER_NOTE (ANIMATION,
12803                 "Looking for property '%s' of object '%s' in section '%s'",
12804                 tokens[2],
12805                 tokens[1],
12806                 tokens[0]);
12807
12808   g_strfreev (tokens);
12809
12810   return meta;
12811 }
12812
12813 static GParamSpec *
12814 clutter_actor_find_property (ClutterAnimatable *animatable,
12815                              const gchar       *property_name)
12816 {
12817   ClutterActorMeta *meta = NULL;
12818   GObjectClass *klass = NULL;
12819   GParamSpec *pspec = NULL;
12820   gchar *p_name = NULL;
12821
12822   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12823                                            property_name,
12824                                            &p_name);
12825
12826   if (meta != NULL)
12827     {
12828       klass = G_OBJECT_GET_CLASS (meta);
12829
12830       pspec = g_object_class_find_property (klass, p_name);
12831     }
12832   else
12833     {
12834       klass = G_OBJECT_GET_CLASS (animatable);
12835
12836       pspec = g_object_class_find_property (klass, property_name);
12837     }
12838
12839   g_free (p_name);
12840
12841   return pspec;
12842 }
12843
12844 static void
12845 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12846                                  const gchar       *property_name,
12847                                  GValue            *initial)
12848 {
12849   ClutterActorMeta *meta = NULL;
12850   gchar *p_name = NULL;
12851
12852   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12853                                            property_name,
12854                                            &p_name);
12855
12856   if (meta != NULL)
12857     g_object_get_property (G_OBJECT (meta), p_name, initial);
12858   else
12859     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12860
12861   g_free (p_name);
12862 }
12863
12864 /*
12865  * clutter_actor_set_animatable_property:
12866  * @actor: a #ClutterActor
12867  * @prop_id: the paramspec id
12868  * @value: the value to set
12869  * @pspec: the paramspec
12870  *
12871  * Sets values of animatable properties.
12872  *
12873  * This is a variant of clutter_actor_set_property() that gets called
12874  * by the #ClutterAnimatable implementation of #ClutterActor for the
12875  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12876  * #GParamSpec.
12877  *
12878  * Unlike the implementation of #GObjectClass.set_property(), this
12879  * function will not update the interval if a transition involving an
12880  * animatable property is in progress - this avoids cycles with the
12881  * transition API calling the public API.
12882  */
12883 static void
12884 clutter_actor_set_animatable_property (ClutterActor *actor,
12885                                        guint         prop_id,
12886                                        const GValue *value,
12887                                        GParamSpec   *pspec)
12888 {
12889   switch (prop_id)
12890     {
12891     case PROP_X:
12892       clutter_actor_set_x_internal (actor, g_value_get_float (value));
12893       break;
12894
12895     case PROP_Y:
12896       clutter_actor_set_y_internal (actor, g_value_get_float (value));
12897       break;
12898
12899     case PROP_WIDTH:
12900       clutter_actor_set_width_internal (actor, g_value_get_float (value));
12901       break;
12902
12903     case PROP_HEIGHT:
12904       clutter_actor_set_height_internal (actor, g_value_get_float (value));
12905       break;
12906
12907     case PROP_DEPTH:
12908       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12909       break;
12910
12911     case PROP_OPACITY:
12912       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12913       break;
12914
12915     case PROP_BACKGROUND_COLOR:
12916       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12917       break;
12918
12919     case PROP_SCALE_X:
12920       clutter_actor_set_scale_factor_internal (actor,
12921                                                g_value_get_double (value),
12922                                                pspec);
12923       break;
12924
12925     case PROP_SCALE_Y:
12926       clutter_actor_set_scale_factor_internal (actor,
12927                                                g_value_get_double (value),
12928                                                pspec);
12929       break;
12930
12931     case PROP_ROTATION_ANGLE_X:
12932       clutter_actor_set_rotation_angle_internal (actor,
12933                                                  CLUTTER_X_AXIS,
12934                                                  g_value_get_double (value));
12935       break;
12936
12937     case PROP_ROTATION_ANGLE_Y:
12938       clutter_actor_set_rotation_angle_internal (actor,
12939                                                  CLUTTER_Y_AXIS,
12940                                                  g_value_get_double (value));
12941       break;
12942
12943     case PROP_ROTATION_ANGLE_Z:
12944       clutter_actor_set_rotation_angle_internal (actor,
12945                                                  CLUTTER_Z_AXIS,
12946                                                  g_value_get_double (value));
12947       break;
12948
12949     default:
12950       g_object_set_property (G_OBJECT (actor), pspec->name, value);
12951       break;
12952     }
12953 }
12954
12955 static void
12956 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12957                                const gchar       *property_name,
12958                                const GValue      *final)
12959 {
12960   ClutterActor *actor = CLUTTER_ACTOR (animatable);
12961   ClutterActorMeta *meta = NULL;
12962   gchar *p_name = NULL;
12963
12964   meta = get_meta_from_animation_property (actor,
12965                                            property_name,
12966                                            &p_name);
12967   if (meta != NULL)
12968     g_object_set_property (G_OBJECT (meta), p_name, final);
12969   else
12970     {
12971       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12972       GParamSpec *pspec;
12973
12974       pspec = g_object_class_find_property (obj_class, property_name);
12975
12976       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12977         {
12978           /* XXX - I'm going to the special hell for this */
12979           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12980         }
12981       else
12982         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
12983     }
12984
12985   g_free (p_name);
12986 }
12987
12988 static void
12989 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12990 {
12991   iface->find_property = clutter_actor_find_property;
12992   iface->get_initial_state = clutter_actor_get_initial_state;
12993   iface->set_final_state = clutter_actor_set_final_state;
12994 }
12995
12996 /**
12997  * clutter_actor_transform_stage_point:
12998  * @self: A #ClutterActor
12999  * @x: (in): x screen coordinate of the point to unproject
13000  * @y: (in): y screen coordinate of the point to unproject
13001  * @x_out: (out): return location for the unprojected x coordinance
13002  * @y_out: (out): return location for the unprojected y coordinance
13003  *
13004  * This function translates screen coordinates (@x, @y) to
13005  * coordinates relative to the actor. For example, it can be used to translate
13006  * screen events from global screen coordinates into actor-local coordinates.
13007  *
13008  * The conversion can fail, notably if the transform stack results in the
13009  * actor being projected on the screen as a mere line.
13010  *
13011  * The conversion should not be expected to be pixel-perfect due to the
13012  * nature of the operation. In general the error grows when the skewing
13013  * of the actor rectangle on screen increases.
13014  *
13015  * <note><para>This function can be computationally intensive.</para></note>
13016  *
13017  * <note><para>This function only works when the allocation is up-to-date,
13018  * i.e. inside of paint().</para></note>
13019  *
13020  * Return value: %TRUE if conversion was successful.
13021  *
13022  * Since: 0.6
13023  */
13024 gboolean
13025 clutter_actor_transform_stage_point (ClutterActor *self,
13026                                      gfloat        x,
13027                                      gfloat        y,
13028                                      gfloat       *x_out,
13029                                      gfloat       *y_out)
13030 {
13031   ClutterVertex v[4];
13032   float ST[3][3];
13033   float RQ[3][3];
13034   int du, dv, xi, yi;
13035   float px, py;
13036   float xf, yf, wf, det;
13037   ClutterActorPrivate *priv;
13038
13039   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13040
13041   priv = self->priv;
13042
13043   /* This implementation is based on the quad -> quad projection algorithm
13044    * described by Paul Heckbert in:
13045    *
13046    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13047    *
13048    * and the sample implementation at:
13049    *
13050    *   http://www.cs.cmu.edu/~ph/src/texfund/
13051    *
13052    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13053    * quad to rectangle only, which significantly simplifies things; the
13054    * function calls have been unrolled, and most of the math is done in fixed
13055    * point.
13056    */
13057
13058   clutter_actor_get_abs_allocation_vertices (self, v);
13059
13060   /* Keeping these as ints simplifies the multiplication (no significant
13061    * loss of precision here).
13062    */
13063   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13064   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13065
13066   if (!du || !dv)
13067     return FALSE;
13068
13069 #define UX2FP(x)        (x)
13070 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13071
13072   /* First, find mapping from unit uv square to xy quadrilateral; this
13073    * equivalent to the pmap_square_quad() functions in the sample
13074    * implementation, which we can simplify, since our target is always
13075    * a rectangle.
13076    */
13077   px = v[0].x - v[1].x + v[3].x - v[2].x;
13078   py = v[0].y - v[1].y + v[3].y - v[2].y;
13079
13080   if (!px && !py)
13081     {
13082       /* affine transform */
13083       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13084       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13085       RQ[2][0] = UX2FP (v[0].x);
13086       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13087       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13088       RQ[2][1] = UX2FP (v[0].y);
13089       RQ[0][2] = 0;
13090       RQ[1][2] = 0;
13091       RQ[2][2] = 1.0;
13092     }
13093   else
13094     {
13095       /* projective transform */
13096       double dx1, dx2, dy1, dy2, del;
13097
13098       dx1 = UX2FP (v[1].x - v[3].x);
13099       dx2 = UX2FP (v[2].x - v[3].x);
13100       dy1 = UX2FP (v[1].y - v[3].y);
13101       dy2 = UX2FP (v[2].y - v[3].y);
13102
13103       del = DET2FP (dx1, dx2, dy1, dy2);
13104       if (!del)
13105         return FALSE;
13106
13107       /*
13108        * The division here needs to be done in floating point for
13109        * precisions reasons.
13110        */
13111       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13112       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13113       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13114       RQ[2][2] = 1.0;
13115       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13116       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13117       RQ[2][0] = UX2FP (v[0].x);
13118       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13119       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13120       RQ[2][1] = UX2FP (v[0].y);
13121     }
13122
13123   /*
13124    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13125    * square. Since our rectangle is based at 0,0 we only need to scale.
13126    */
13127   RQ[0][0] /= du;
13128   RQ[1][0] /= dv;
13129   RQ[0][1] /= du;
13130   RQ[1][1] /= dv;
13131   RQ[0][2] /= du;
13132   RQ[1][2] /= dv;
13133
13134   /*
13135    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13136    * inverse of that.
13137    */
13138   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13139   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13140   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13141   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13142   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13143   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13144   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13145   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13146   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13147
13148   /*
13149    * Check the resulting matrix is OK.
13150    */
13151   det = (RQ[0][0] * ST[0][0])
13152       + (RQ[0][1] * ST[0][1])
13153       + (RQ[0][2] * ST[0][2]);
13154   if (!det)
13155     return FALSE;
13156
13157   /*
13158    * Now transform our point with the ST matrix; the notional w
13159    * coordinate is 1, hence the last part is simply added.
13160    */
13161   xi = (int) x;
13162   yi = (int) y;
13163
13164   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13165   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13166   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13167
13168   if (x_out)
13169     *x_out = xf / wf;
13170
13171   if (y_out)
13172     *y_out = yf / wf;
13173
13174 #undef UX2FP
13175 #undef DET2FP
13176
13177   return TRUE;
13178 }
13179
13180 /*
13181  * ClutterGeometry
13182  */
13183
13184 static ClutterGeometry*
13185 clutter_geometry_copy (const ClutterGeometry *geometry)
13186 {
13187   return g_slice_dup (ClutterGeometry, geometry);
13188 }
13189
13190 static void
13191 clutter_geometry_free (ClutterGeometry *geometry)
13192 {
13193   if (G_LIKELY (geometry != NULL))
13194     g_slice_free (ClutterGeometry, geometry);
13195 }
13196
13197 /**
13198  * clutter_geometry_union:
13199  * @geometry_a: a #ClutterGeometry
13200  * @geometry_b: another #ClutterGeometry
13201  * @result: (out): location to store the result
13202  *
13203  * Find the union of two rectangles represented as #ClutterGeometry.
13204  *
13205  * Since: 1.4
13206  */
13207 void
13208 clutter_geometry_union (const ClutterGeometry *geometry_a,
13209                         const ClutterGeometry *geometry_b,
13210                         ClutterGeometry       *result)
13211 {
13212   /* We don't try to handle rectangles that can't be represented
13213    * as a signed integer box */
13214   gint x_1 = MIN (geometry_a->x, geometry_b->x);
13215   gint y_1 = MIN (geometry_a->y, geometry_b->y);
13216   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13217                   geometry_b->x + (gint)geometry_b->width);
13218   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13219                   geometry_b->y + (gint)geometry_b->height);
13220   result->x = x_1;
13221   result->y = y_1;
13222   result->width = x_2 - x_1;
13223   result->height = y_2 - y_1;
13224 }
13225
13226 /**
13227  * clutter_geometry_intersects:
13228  * @geometry0: The first geometry to test
13229  * @geometry1: The second geometry to test
13230  *
13231  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13232  * they do else %FALSE.
13233  *
13234  * Return value: %TRUE of @geometry0 and geometry1 intersect else
13235  * %FALSE.
13236  *
13237  * Since: 1.4
13238  */
13239 gboolean
13240 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13241                              const ClutterGeometry *geometry1)
13242 {
13243   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13244       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13245       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13246       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13247     return FALSE;
13248   else
13249     return TRUE;
13250 }
13251
13252 static gboolean
13253 clutter_geometry_progress (const GValue *a,
13254                            const GValue *b,
13255                            gdouble       progress,
13256                            GValue       *retval)
13257 {
13258   const ClutterGeometry *a_geom = g_value_get_boxed (a);
13259   const ClutterGeometry *b_geom = g_value_get_boxed (b);
13260   ClutterGeometry res = { 0, };
13261   gint a_width = a_geom->width;
13262   gint b_width = b_geom->width;
13263   gint a_height = a_geom->height;
13264   gint b_height = b_geom->height;
13265
13266   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13267   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13268
13269   res.width = a_width + (b_width - a_width) * progress;
13270   res.height = a_height + (b_height - a_height) * progress;
13271
13272   g_value_set_boxed (retval, &res);
13273
13274   return TRUE;
13275 }
13276
13277 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13278                                clutter_geometry_copy,
13279                                clutter_geometry_free,
13280                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13281
13282 /*
13283  * ClutterVertices
13284  */
13285
13286 /**
13287  * clutter_vertex_new:
13288  * @x: X coordinate
13289  * @y: Y coordinate
13290  * @z: Z coordinate
13291  *
13292  * Creates a new #ClutterVertex for the point in 3D space
13293  * identified by the 3 coordinates @x, @y, @z
13294  *
13295  * Return value: the newly allocate #ClutterVertex. Use
13296  *   clutter_vertex_free() to free the resources
13297  *
13298  * Since: 1.0
13299  */
13300 ClutterVertex *
13301 clutter_vertex_new (gfloat x,
13302                     gfloat y,
13303                     gfloat z)
13304 {
13305   ClutterVertex *vertex;
13306
13307   vertex = g_slice_new (ClutterVertex);
13308   clutter_vertex_init (vertex, x, y, z);
13309
13310   return vertex;
13311 }
13312
13313 /**
13314  * clutter_vertex_init:
13315  * @vertex: a #ClutterVertex
13316  * @x: X coordinate
13317  * @y: Y coordinate
13318  * @z: Z coordinate
13319  *
13320  * Initializes @vertex with the given coordinates.
13321  *
13322  * Since: 1.10
13323  */
13324 void
13325 clutter_vertex_init (ClutterVertex *vertex,
13326                      gfloat         x,
13327                      gfloat         y,
13328                      gfloat         z)
13329 {
13330   g_return_if_fail (vertex != NULL);
13331
13332   vertex->x = x;
13333   vertex->y = y;
13334   vertex->z = z;
13335 }
13336
13337 /**
13338  * clutter_vertex_copy:
13339  * @vertex: a #ClutterVertex
13340  *
13341  * Copies @vertex
13342  *
13343  * Return value: a newly allocated copy of #ClutterVertex. Use
13344  *   clutter_vertex_free() to free the allocated resources
13345  *
13346  * Since: 1.0
13347  */
13348 ClutterVertex *
13349 clutter_vertex_copy (const ClutterVertex *vertex)
13350 {
13351   if (G_LIKELY (vertex != NULL))
13352     return g_slice_dup (ClutterVertex, vertex);
13353
13354   return NULL;
13355 }
13356
13357 /**
13358  * clutter_vertex_free:
13359  * @vertex: a #ClutterVertex
13360  *
13361  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13362  *
13363  * Since: 1.0
13364  */
13365 void
13366 clutter_vertex_free (ClutterVertex *vertex)
13367 {
13368   if (G_UNLIKELY (vertex != NULL))
13369     g_slice_free (ClutterVertex, vertex);
13370 }
13371
13372 /**
13373  * clutter_vertex_equal:
13374  * @vertex_a: a #ClutterVertex
13375  * @vertex_b: a #ClutterVertex
13376  *
13377  * Compares @vertex_a and @vertex_b for equality
13378  *
13379  * Return value: %TRUE if the passed #ClutterVertex are equal
13380  *
13381  * Since: 1.0
13382  */
13383 gboolean
13384 clutter_vertex_equal (const ClutterVertex *vertex_a,
13385                       const ClutterVertex *vertex_b)
13386 {
13387   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13388
13389   if (vertex_a == vertex_b)
13390     return TRUE;
13391
13392   return vertex_a->x == vertex_b->x &&
13393          vertex_a->y == vertex_b->y &&
13394          vertex_a->z == vertex_b->z;
13395 }
13396
13397 static gboolean
13398 clutter_vertex_progress (const GValue *a,
13399                          const GValue *b,
13400                          gdouble       progress,
13401                          GValue       *retval)
13402 {
13403   const ClutterVertex *av = g_value_get_boxed (a);
13404   const ClutterVertex *bv = g_value_get_boxed (b);
13405   ClutterVertex res = { 0, };
13406
13407   res.x = av->x + (bv->x - av->x) * progress;
13408   res.y = av->y + (bv->y - av->y) * progress;
13409   res.z = av->z + (bv->z - av->z) * progress;
13410
13411   g_value_set_boxed (retval, &res);
13412
13413   return TRUE;
13414 }
13415
13416 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13417                                clutter_vertex_copy,
13418                                clutter_vertex_free,
13419                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13420
13421 /**
13422  * clutter_actor_is_rotated:
13423  * @self: a #ClutterActor
13424  *
13425  * Checks whether any rotation is applied to the actor.
13426  *
13427  * Return value: %TRUE if the actor is rotated.
13428  *
13429  * Since: 0.6
13430  */
13431 gboolean
13432 clutter_actor_is_rotated (ClutterActor *self)
13433 {
13434   const ClutterTransformInfo *info;
13435
13436   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13437
13438   info = _clutter_actor_get_transform_info_or_defaults (self);
13439
13440   if (info->rx_angle || info->ry_angle || info->rz_angle)
13441     return TRUE;
13442
13443   return FALSE;
13444 }
13445
13446 /**
13447  * clutter_actor_is_scaled:
13448  * @self: a #ClutterActor
13449  *
13450  * Checks whether the actor is scaled in either dimension.
13451  *
13452  * Return value: %TRUE if the actor is scaled.
13453  *
13454  * Since: 0.6
13455  */
13456 gboolean
13457 clutter_actor_is_scaled (ClutterActor *self)
13458 {
13459   const ClutterTransformInfo *info;
13460
13461   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13462
13463   info = _clutter_actor_get_transform_info_or_defaults (self);
13464
13465   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13466     return TRUE;
13467
13468   return FALSE;
13469 }
13470
13471 ClutterActor *
13472 _clutter_actor_get_stage_internal (ClutterActor *actor)
13473 {
13474   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13475     actor = actor->priv->parent;
13476
13477   return actor;
13478 }
13479
13480 /**
13481  * clutter_actor_get_stage:
13482  * @actor: a #ClutterActor
13483  *
13484  * Retrieves the #ClutterStage where @actor is contained.
13485  *
13486  * Return value: (transfer none) (type Clutter.Stage): the stage
13487  *   containing the actor, or %NULL
13488  *
13489  * Since: 0.8
13490  */
13491 ClutterActor *
13492 clutter_actor_get_stage (ClutterActor *actor)
13493 {
13494   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13495
13496   return _clutter_actor_get_stage_internal (actor);
13497 }
13498
13499 /**
13500  * clutter_actor_allocate_available_size:
13501  * @self: a #ClutterActor
13502  * @x: the actor's X coordinate
13503  * @y: the actor's Y coordinate
13504  * @available_width: the maximum available width, or -1 to use the
13505  *   actor's natural width
13506  * @available_height: the maximum available height, or -1 to use the
13507  *   actor's natural height
13508  * @flags: flags controlling the allocation
13509  *
13510  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13511  * preferred size, but limiting it to the maximum available width
13512  * and height provided.
13513  *
13514  * This function will do the right thing when dealing with the
13515  * actor's request mode.
13516  *
13517  * The implementation of this function is equivalent to:
13518  *
13519  * |[
13520  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13521  *     {
13522  *       clutter_actor_get_preferred_width (self, available_height,
13523  *                                          &amp;min_width,
13524  *                                          &amp;natural_width);
13525  *       width = CLAMP (natural_width, min_width, available_width);
13526  *
13527  *       clutter_actor_get_preferred_height (self, width,
13528  *                                           &amp;min_height,
13529  *                                           &amp;natural_height);
13530  *       height = CLAMP (natural_height, min_height, available_height);
13531  *     }
13532  *   else
13533  *     {
13534  *       clutter_actor_get_preferred_height (self, available_width,
13535  *                                           &amp;min_height,
13536  *                                           &amp;natural_height);
13537  *       height = CLAMP (natural_height, min_height, available_height);
13538  *
13539  *       clutter_actor_get_preferred_width (self, height,
13540  *                                          &amp;min_width,
13541  *                                          &amp;natural_width);
13542  *       width = CLAMP (natural_width, min_width, available_width);
13543  *     }
13544  *
13545  *   box.x1 = x; box.y1 = y;
13546  *   box.x2 = box.x1 + available_width;
13547  *   box.y2 = box.y1 + available_height;
13548  *   clutter_actor_allocate (self, &amp;box, flags);
13549  * ]|
13550  *
13551  * This function can be used by fluid layout managers to allocate
13552  * an actor's preferred size without making it bigger than the area
13553  * available for the container.
13554  *
13555  * Since: 1.0
13556  */
13557 void
13558 clutter_actor_allocate_available_size (ClutterActor           *self,
13559                                        gfloat                  x,
13560                                        gfloat                  y,
13561                                        gfloat                  available_width,
13562                                        gfloat                  available_height,
13563                                        ClutterAllocationFlags  flags)
13564 {
13565   ClutterActorPrivate *priv;
13566   gfloat width, height;
13567   gfloat min_width, min_height;
13568   gfloat natural_width, natural_height;
13569   ClutterActorBox box;
13570
13571   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13572
13573   priv = self->priv;
13574
13575   width = height = 0.0;
13576
13577   switch (priv->request_mode)
13578     {
13579     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13580       clutter_actor_get_preferred_width (self, available_height,
13581                                          &min_width,
13582                                          &natural_width);
13583       width  = CLAMP (natural_width, min_width, available_width);
13584
13585       clutter_actor_get_preferred_height (self, width,
13586                                           &min_height,
13587                                           &natural_height);
13588       height = CLAMP (natural_height, min_height, available_height);
13589       break;
13590
13591     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13592       clutter_actor_get_preferred_height (self, available_width,
13593                                           &min_height,
13594                                           &natural_height);
13595       height = CLAMP (natural_height, min_height, available_height);
13596
13597       clutter_actor_get_preferred_width (self, height,
13598                                          &min_width,
13599                                          &natural_width);
13600       width  = CLAMP (natural_width, min_width, available_width);
13601       break;
13602     }
13603
13604
13605   box.x1 = x;
13606   box.y1 = y;
13607   box.x2 = box.x1 + width;
13608   box.y2 = box.y1 + height;
13609   clutter_actor_allocate (self, &box, flags);
13610 }
13611
13612 /**
13613  * clutter_actor_allocate_preferred_size:
13614  * @self: a #ClutterActor
13615  * @flags: flags controlling the allocation
13616  *
13617  * Allocates the natural size of @self.
13618  *
13619  * This function is a utility call for #ClutterActor implementations
13620  * that allocates the actor's preferred natural size. It can be used
13621  * by fixed layout managers (like #ClutterGroup or so called
13622  * 'composite actors') inside the ClutterActor::allocate
13623  * implementation to give each child exactly how much space it
13624  * requires.
13625  *
13626  * This function is not meant to be used by applications. It is also
13627  * not meant to be used outside the implementation of the
13628  * ClutterActor::allocate virtual function.
13629  *
13630  * Since: 0.8
13631  */
13632 void
13633 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13634                                        ClutterAllocationFlags  flags)
13635 {
13636   gfloat actor_x, actor_y;
13637   gfloat natural_width, natural_height;
13638   ClutterActorBox actor_box;
13639
13640   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13641
13642   actor_x = clutter_actor_get_x (self);
13643   actor_y = clutter_actor_get_y (self);
13644
13645   clutter_actor_get_preferred_size (self,
13646                                     NULL, NULL,
13647                                     &natural_width,
13648                                     &natural_height);
13649
13650   actor_box.x1 = actor_x;
13651   actor_box.y1 = actor_y;
13652   actor_box.x2 = actor_box.x1 + natural_width;
13653   actor_box.y2 = actor_box.y1 + natural_height;
13654
13655   clutter_actor_allocate (self, &actor_box, flags);
13656 }
13657
13658 /**
13659  * clutter_actor_allocate_align_fill:
13660  * @self: a #ClutterActor
13661  * @box: a #ClutterActorBox, containing the available width and height
13662  * @x_align: the horizontal alignment, between 0 and 1
13663  * @y_align: the vertical alignment, between 0 and 1
13664  * @x_fill: whether the actor should fill horizontally
13665  * @y_fill: whether the actor should fill vertically
13666  * @flags: allocation flags to be passed to clutter_actor_allocate()
13667  *
13668  * Allocates @self by taking into consideration the available allocation
13669  * area; an alignment factor on either axis; and whether the actor should
13670  * fill the allocation on either axis.
13671  *
13672  * The @box should contain the available allocation width and height;
13673  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13674  * allocation will be offset by their value.
13675  *
13676  * This function takes into consideration the geometry request specified by
13677  * the #ClutterActor:request-mode property, and the text direction.
13678  *
13679  * This function is useful for fluid layout managers, like #ClutterBinLayout
13680  * or #ClutterTableLayout
13681  *
13682  * Since: 1.4
13683  */
13684 void
13685 clutter_actor_allocate_align_fill (ClutterActor           *self,
13686                                    const ClutterActorBox  *box,
13687                                    gdouble                 x_align,
13688                                    gdouble                 y_align,
13689                                    gboolean                x_fill,
13690                                    gboolean                y_fill,
13691                                    ClutterAllocationFlags  flags)
13692 {
13693   ClutterActorPrivate *priv;
13694   ClutterActorBox allocation = { 0, };
13695   gfloat x_offset, y_offset;
13696   gfloat available_width, available_height;
13697   gfloat child_width, child_height;
13698
13699   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13700   g_return_if_fail (box != NULL);
13701   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13702   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13703
13704   priv = self->priv;
13705
13706   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13707   clutter_actor_box_get_size (box, &available_width, &available_height);
13708
13709   if (available_width < 0)
13710     available_width = 0;
13711
13712   if (available_height < 0)
13713     available_height = 0;
13714
13715   if (x_fill)
13716     {
13717       allocation.x1 = x_offset;
13718       allocation.x2 = allocation.x1 + available_width;
13719     }
13720
13721   if (y_fill)
13722     {
13723       allocation.y1 = y_offset;
13724       allocation.y2 = allocation.y1 + available_height;
13725     }
13726
13727   /* if we are filling horizontally and vertically then we're done */
13728   if (x_fill && y_fill)
13729     goto out;
13730
13731   child_width = child_height = 0.0f;
13732
13733   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13734     {
13735       gfloat min_width, natural_width;
13736       gfloat min_height, natural_height;
13737
13738       clutter_actor_get_preferred_width (self, available_height,
13739                                          &min_width,
13740                                          &natural_width);
13741
13742       child_width = CLAMP (natural_width, min_width, available_width);
13743
13744       if (!y_fill)
13745         {
13746           clutter_actor_get_preferred_height (self, child_width,
13747                                               &min_height,
13748                                               &natural_height);
13749
13750           child_height = CLAMP (natural_height, min_height, available_height);
13751         }
13752     }
13753   else
13754     {
13755       gfloat min_width, natural_width;
13756       gfloat min_height, natural_height;
13757
13758       clutter_actor_get_preferred_height (self, available_width,
13759                                           &min_height,
13760                                           &natural_height);
13761
13762       child_height = CLAMP (natural_height, min_height, available_height);
13763
13764       if (!x_fill)
13765         {
13766           clutter_actor_get_preferred_width (self, child_height,
13767                                              &min_width,
13768                                              &natural_width);
13769
13770           child_width = CLAMP (natural_width, min_width, available_width);
13771         }
13772     }
13773
13774   /* invert the horizontal alignment for RTL languages */
13775   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13776     x_align = 1.0 - x_align;
13777
13778   if (!x_fill)
13779     {
13780       allocation.x1 = x_offset
13781                     + ((available_width - child_width) * x_align);
13782       allocation.x2 = allocation.x1 + child_width;
13783     }
13784
13785   if (!y_fill)
13786     {
13787       allocation.y1 = y_offset
13788                     + ((available_height - child_height) * y_align);
13789       allocation.y2 = allocation.y1 + child_height;
13790     }
13791
13792 out:
13793   clutter_actor_box_clamp_to_pixel (&allocation);
13794   clutter_actor_allocate (self, &allocation, flags);
13795 }
13796
13797 /**
13798  * clutter_actor_grab_key_focus:
13799  * @self: a #ClutterActor
13800  *
13801  * Sets the key focus of the #ClutterStage including @self
13802  * to this #ClutterActor.
13803  *
13804  * Since: 1.0
13805  */
13806 void
13807 clutter_actor_grab_key_focus (ClutterActor *self)
13808 {
13809   ClutterActor *stage;
13810
13811   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13812
13813   stage = _clutter_actor_get_stage_internal (self);
13814   if (stage != NULL)
13815     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13816 }
13817
13818 /**
13819  * clutter_actor_get_pango_context:
13820  * @self: a #ClutterActor
13821  *
13822  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13823  * is already configured using the appropriate font map, resolution
13824  * and font options.
13825  *
13826  * Unlike clutter_actor_create_pango_context(), this context is owend
13827  * by the #ClutterActor and it will be updated each time the options
13828  * stored by the #ClutterBackend change.
13829  *
13830  * You can use the returned #PangoContext to create a #PangoLayout
13831  * and render text using cogl_pango_render_layout() to reuse the
13832  * glyphs cache also used by Clutter.
13833  *
13834  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13835  *   The returned #PangoContext is owned by the actor and should not be
13836  *   unreferenced by the application code
13837  *
13838  * Since: 1.0
13839  */
13840 PangoContext *
13841 clutter_actor_get_pango_context (ClutterActor *self)
13842 {
13843   ClutterActorPrivate *priv;
13844
13845   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13846
13847   priv = self->priv;
13848
13849   if (priv->pango_context != NULL)
13850     return priv->pango_context;
13851
13852   priv->pango_context = _clutter_context_get_pango_context ();
13853   g_object_ref (priv->pango_context);
13854
13855   return priv->pango_context;
13856 }
13857
13858 /**
13859  * clutter_actor_create_pango_context:
13860  * @self: a #ClutterActor
13861  *
13862  * Creates a #PangoContext for the given actor. The #PangoContext
13863  * is already configured using the appropriate font map, resolution
13864  * and font options.
13865  *
13866  * See also clutter_actor_get_pango_context().
13867  *
13868  * Return value: (transfer full): the newly created #PangoContext.
13869  *   Use g_object_unref() on the returned value to deallocate its
13870  *   resources
13871  *
13872  * Since: 1.0
13873  */
13874 PangoContext *
13875 clutter_actor_create_pango_context (ClutterActor *self)
13876 {
13877   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13878
13879   return _clutter_context_create_pango_context ();
13880 }
13881
13882 /**
13883  * clutter_actor_create_pango_layout:
13884  * @self: a #ClutterActor
13885  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13886  *
13887  * Creates a new #PangoLayout from the same #PangoContext used
13888  * by the #ClutterActor. The #PangoLayout is already configured
13889  * with the font map, resolution and font options, and the
13890  * given @text.
13891  *
13892  * If you want to keep around a #PangoLayout created by this
13893  * function you will have to connect to the #ClutterBackend::font-changed
13894  * and #ClutterBackend::resolution-changed signals, and call
13895  * pango_layout_context_changed() in response to them.
13896  *
13897  * Return value: (transfer full): the newly created #PangoLayout.
13898  *   Use g_object_unref() when done
13899  *
13900  * Since: 1.0
13901  */
13902 PangoLayout *
13903 clutter_actor_create_pango_layout (ClutterActor *self,
13904                                    const gchar  *text)
13905 {
13906   PangoContext *context;
13907   PangoLayout *layout;
13908
13909   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13910
13911   context = clutter_actor_get_pango_context (self);
13912   layout = pango_layout_new (context);
13913
13914   if (text)
13915     pango_layout_set_text (layout, text, -1);
13916
13917   return layout;
13918 }
13919
13920 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13921  * ClutterOffscreenEffect.
13922  */
13923 void
13924 _clutter_actor_set_opacity_override (ClutterActor *self,
13925                                      gint          opacity)
13926 {
13927   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13928
13929   self->priv->opacity_override = opacity;
13930 }
13931
13932 gint
13933 _clutter_actor_get_opacity_override (ClutterActor *self)
13934 {
13935   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13936
13937   return self->priv->opacity_override;
13938 }
13939
13940 /* Allows you to disable applying the actors model view transform during
13941  * a paint. Used by ClutterClone. */
13942 void
13943 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13944                                                 gboolean      enable)
13945 {
13946   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13947
13948   self->priv->enable_model_view_transform = enable;
13949 }
13950
13951 void
13952 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13953                                           gboolean      enable)
13954 {
13955   ClutterActorPrivate *priv;
13956
13957   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13958
13959   priv = self->priv;
13960
13961   priv->enable_paint_unmapped = enable;
13962
13963   if (priv->enable_paint_unmapped)
13964     {
13965       /* Make sure that the parents of the widget are realized first;
13966        * otherwise checks in clutter_actor_update_map_state() will
13967        * fail.
13968        */
13969       clutter_actor_realize (self);
13970
13971       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13972     }
13973   else
13974     {
13975       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13976     }
13977 }
13978
13979 static void
13980 clutter_anchor_coord_get_units (ClutterActor      *self,
13981                                 const AnchorCoord *coord,
13982                                 gfloat            *x,
13983                                 gfloat            *y,
13984                                 gfloat            *z)
13985 {
13986   if (coord->is_fractional)
13987     {
13988       gfloat actor_width, actor_height;
13989
13990       clutter_actor_get_size (self, &actor_width, &actor_height);
13991
13992       if (x)
13993         *x = actor_width * coord->v.fraction.x;
13994
13995       if (y)
13996         *y = actor_height * coord->v.fraction.y;
13997
13998       if (z)
13999         *z = 0;
14000     }
14001   else
14002     {
14003       if (x)
14004         *x = coord->v.units.x;
14005
14006       if (y)
14007         *y = coord->v.units.y;
14008
14009       if (z)
14010         *z = coord->v.units.z;
14011     }
14012 }
14013
14014 static void
14015 clutter_anchor_coord_set_units (AnchorCoord *coord,
14016                                 gfloat       x,
14017                                 gfloat       y,
14018                                 gfloat       z)
14019 {
14020   coord->is_fractional = FALSE;
14021   coord->v.units.x = x;
14022   coord->v.units.y = y;
14023   coord->v.units.z = z;
14024 }
14025
14026 static ClutterGravity
14027 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14028 {
14029   if (coord->is_fractional)
14030     {
14031       if (coord->v.fraction.x == 0.0)
14032         {
14033           if (coord->v.fraction.y == 0.0)
14034             return CLUTTER_GRAVITY_NORTH_WEST;
14035           else if (coord->v.fraction.y == 0.5)
14036             return CLUTTER_GRAVITY_WEST;
14037           else if (coord->v.fraction.y == 1.0)
14038             return CLUTTER_GRAVITY_SOUTH_WEST;
14039           else
14040             return CLUTTER_GRAVITY_NONE;
14041         }
14042       else if (coord->v.fraction.x == 0.5)
14043         {
14044           if (coord->v.fraction.y == 0.0)
14045             return CLUTTER_GRAVITY_NORTH;
14046           else if (coord->v.fraction.y == 0.5)
14047             return CLUTTER_GRAVITY_CENTER;
14048           else if (coord->v.fraction.y == 1.0)
14049             return CLUTTER_GRAVITY_SOUTH;
14050           else
14051             return CLUTTER_GRAVITY_NONE;
14052         }
14053       else if (coord->v.fraction.x == 1.0)
14054         {
14055           if (coord->v.fraction.y == 0.0)
14056             return CLUTTER_GRAVITY_NORTH_EAST;
14057           else if (coord->v.fraction.y == 0.5)
14058             return CLUTTER_GRAVITY_EAST;
14059           else if (coord->v.fraction.y == 1.0)
14060             return CLUTTER_GRAVITY_SOUTH_EAST;
14061           else
14062             return CLUTTER_GRAVITY_NONE;
14063         }
14064       else
14065         return CLUTTER_GRAVITY_NONE;
14066     }
14067   else
14068     return CLUTTER_GRAVITY_NONE;
14069 }
14070
14071 static void
14072 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14073                                   ClutterGravity  gravity)
14074 {
14075   switch (gravity)
14076     {
14077     case CLUTTER_GRAVITY_NORTH:
14078       coord->v.fraction.x = 0.5;
14079       coord->v.fraction.y = 0.0;
14080       break;
14081
14082     case CLUTTER_GRAVITY_NORTH_EAST:
14083       coord->v.fraction.x = 1.0;
14084       coord->v.fraction.y = 0.0;
14085       break;
14086
14087     case CLUTTER_GRAVITY_EAST:
14088       coord->v.fraction.x = 1.0;
14089       coord->v.fraction.y = 0.5;
14090       break;
14091
14092     case CLUTTER_GRAVITY_SOUTH_EAST:
14093       coord->v.fraction.x = 1.0;
14094       coord->v.fraction.y = 1.0;
14095       break;
14096
14097     case CLUTTER_GRAVITY_SOUTH:
14098       coord->v.fraction.x = 0.5;
14099       coord->v.fraction.y = 1.0;
14100       break;
14101
14102     case CLUTTER_GRAVITY_SOUTH_WEST:
14103       coord->v.fraction.x = 0.0;
14104       coord->v.fraction.y = 1.0;
14105       break;
14106
14107     case CLUTTER_GRAVITY_WEST:
14108       coord->v.fraction.x = 0.0;
14109       coord->v.fraction.y = 0.5;
14110       break;
14111
14112     case CLUTTER_GRAVITY_NORTH_WEST:
14113       coord->v.fraction.x = 0.0;
14114       coord->v.fraction.y = 0.0;
14115       break;
14116
14117     case CLUTTER_GRAVITY_CENTER:
14118       coord->v.fraction.x = 0.5;
14119       coord->v.fraction.y = 0.5;
14120       break;
14121
14122     default:
14123       coord->v.fraction.x = 0.0;
14124       coord->v.fraction.y = 0.0;
14125       break;
14126     }
14127
14128   coord->is_fractional = TRUE;
14129 }
14130
14131 static gboolean
14132 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14133 {
14134   if (coord->is_fractional)
14135     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14136   else
14137     return (coord->v.units.x == 0.0
14138             && coord->v.units.y == 0.0
14139             && coord->v.units.z == 0.0);
14140 }
14141
14142 /**
14143  * clutter_actor_get_flags:
14144  * @self: a #ClutterActor
14145  *
14146  * Retrieves the flags set on @self
14147  *
14148  * Return value: a bitwise or of #ClutterActorFlags or 0
14149  *
14150  * Since: 1.0
14151  */
14152 ClutterActorFlags
14153 clutter_actor_get_flags (ClutterActor *self)
14154 {
14155   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14156
14157   return self->flags;
14158 }
14159
14160 /**
14161  * clutter_actor_set_flags:
14162  * @self: a #ClutterActor
14163  * @flags: the flags to set
14164  *
14165  * Sets @flags on @self
14166  *
14167  * This function will emit notifications for the changed properties
14168  *
14169  * Since: 1.0
14170  */
14171 void
14172 clutter_actor_set_flags (ClutterActor      *self,
14173                          ClutterActorFlags  flags)
14174 {
14175   ClutterActorFlags old_flags;
14176   GObject *obj;
14177   gboolean was_reactive_set, reactive_set;
14178   gboolean was_realized_set, realized_set;
14179   gboolean was_mapped_set, mapped_set;
14180   gboolean was_visible_set, visible_set;
14181
14182   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14183
14184   if (self->flags == flags)
14185     return;
14186
14187   obj = G_OBJECT (self);
14188   g_object_ref (obj);
14189   g_object_freeze_notify (obj);
14190
14191   old_flags = self->flags;
14192
14193   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14194   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14195   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14196   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14197
14198   self->flags |= flags;
14199
14200   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14201   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14202   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14203   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14204
14205   if (reactive_set != was_reactive_set)
14206     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14207
14208   if (realized_set != was_realized_set)
14209     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14210
14211   if (mapped_set != was_mapped_set)
14212     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14213
14214   if (visible_set != was_visible_set)
14215     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14216
14217   g_object_thaw_notify (obj);
14218   g_object_unref (obj);
14219 }
14220
14221 /**
14222  * clutter_actor_unset_flags:
14223  * @self: a #ClutterActor
14224  * @flags: the flags to unset
14225  *
14226  * Unsets @flags on @self
14227  *
14228  * This function will emit notifications for the changed properties
14229  *
14230  * Since: 1.0
14231  */
14232 void
14233 clutter_actor_unset_flags (ClutterActor      *self,
14234                            ClutterActorFlags  flags)
14235 {
14236   ClutterActorFlags old_flags;
14237   GObject *obj;
14238   gboolean was_reactive_set, reactive_set;
14239   gboolean was_realized_set, realized_set;
14240   gboolean was_mapped_set, mapped_set;
14241   gboolean was_visible_set, visible_set;
14242
14243   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14244
14245   obj = G_OBJECT (self);
14246   g_object_freeze_notify (obj);
14247
14248   old_flags = self->flags;
14249
14250   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14251   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14252   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14253   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14254
14255   self->flags &= ~flags;
14256
14257   if (self->flags == old_flags)
14258     return;
14259
14260   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14261   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14262   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14263   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14264
14265   if (reactive_set != was_reactive_set)
14266     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14267
14268   if (realized_set != was_realized_set)
14269     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14270
14271   if (mapped_set != was_mapped_set)
14272     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14273
14274   if (visible_set != was_visible_set)
14275     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14276
14277   g_object_thaw_notify (obj);
14278 }
14279
14280 /**
14281  * clutter_actor_get_transformation_matrix:
14282  * @self: a #ClutterActor
14283  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14284  *
14285  * Retrieves the transformations applied to @self relative to its
14286  * parent.
14287  *
14288  * Since: 1.0
14289  */
14290 void
14291 clutter_actor_get_transformation_matrix (ClutterActor *self,
14292                                          CoglMatrix   *matrix)
14293 {
14294   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14295
14296   cogl_matrix_init_identity (matrix);
14297
14298   _clutter_actor_apply_modelview_transform (self, matrix);
14299 }
14300
14301 void
14302 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14303                                    gboolean      is_in_clone_paint)
14304 {
14305   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14306   self->priv->in_clone_paint = is_in_clone_paint;
14307 }
14308
14309 /**
14310  * clutter_actor_is_in_clone_paint:
14311  * @self: a #ClutterActor
14312  *
14313  * Checks whether @self is being currently painted by a #ClutterClone
14314  *
14315  * This function is useful only inside the ::paint virtual function
14316  * implementations or within handlers for the #ClutterActor::paint
14317  * signal
14318  *
14319  * This function should not be used by applications
14320  *
14321  * Return value: %TRUE if the #ClutterActor is currently being painted
14322  *   by a #ClutterClone, and %FALSE otherwise
14323  *
14324  * Since: 1.0
14325  */
14326 gboolean
14327 clutter_actor_is_in_clone_paint (ClutterActor *self)
14328 {
14329   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14330
14331   return self->priv->in_clone_paint;
14332 }
14333
14334 static gboolean
14335 set_direction_recursive (ClutterActor *actor,
14336                          gpointer      user_data)
14337 {
14338   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14339
14340   clutter_actor_set_text_direction (actor, text_dir);
14341
14342   return TRUE;
14343 }
14344
14345 /**
14346  * clutter_actor_set_text_direction:
14347  * @self: a #ClutterActor
14348  * @text_dir: the text direction for @self
14349  *
14350  * Sets the #ClutterTextDirection for an actor
14351  *
14352  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14353  *
14354  * If @self implements #ClutterContainer then this function will recurse
14355  * inside all the children of @self (including the internal ones).
14356  *
14357  * Composite actors not implementing #ClutterContainer, or actors requiring
14358  * special handling when the text direction changes, should connect to
14359  * the #GObject::notify signal for the #ClutterActor:text-direction property
14360  *
14361  * Since: 1.2
14362  */
14363 void
14364 clutter_actor_set_text_direction (ClutterActor         *self,
14365                                   ClutterTextDirection  text_dir)
14366 {
14367   ClutterActorPrivate *priv;
14368
14369   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14370   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14371
14372   priv = self->priv;
14373
14374   if (priv->text_direction != text_dir)
14375     {
14376       priv->text_direction = text_dir;
14377
14378       /* we need to emit the notify::text-direction first, so that
14379        * the sub-classes can catch that and do specific handling of
14380        * the text direction; see clutter_text_direction_changed_cb()
14381        * inside clutter-text.c
14382        */
14383       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14384
14385       _clutter_actor_foreach_child (self, set_direction_recursive,
14386                                     GINT_TO_POINTER (text_dir));
14387
14388       clutter_actor_queue_relayout (self);
14389     }
14390 }
14391
14392 void
14393 _clutter_actor_set_has_pointer (ClutterActor *self,
14394                                 gboolean      has_pointer)
14395 {
14396   ClutterActorPrivate *priv = self->priv;
14397
14398   if (priv->has_pointer != has_pointer)
14399     {
14400       priv->has_pointer = has_pointer;
14401
14402       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14403     }
14404 }
14405
14406 /**
14407  * clutter_actor_get_text_direction:
14408  * @self: a #ClutterActor
14409  *
14410  * Retrieves the value set using clutter_actor_set_text_direction()
14411  *
14412  * If no text direction has been previously set, the default text
14413  * direction, as returned by clutter_get_default_text_direction(), will
14414  * be returned instead
14415  *
14416  * Return value: the #ClutterTextDirection for the actor
14417  *
14418  * Since: 1.2
14419  */
14420 ClutterTextDirection
14421 clutter_actor_get_text_direction (ClutterActor *self)
14422 {
14423   ClutterActorPrivate *priv;
14424
14425   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14426                         CLUTTER_TEXT_DIRECTION_LTR);
14427
14428   priv = self->priv;
14429
14430   /* if no direction has been set yet use the default */
14431   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14432     priv->text_direction = clutter_get_default_text_direction ();
14433
14434   return priv->text_direction;
14435 }
14436
14437 /**
14438  * clutter_actor_push_internal:
14439  * @self: a #ClutterActor
14440  *
14441  * Should be used by actors implementing the #ClutterContainer and with
14442  * internal children added through clutter_actor_set_parent(), for instance:
14443  *
14444  * |[
14445  *   static void
14446  *   my_actor_init (MyActor *self)
14447  *   {
14448  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14449  *
14450  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14451  *
14452  *     /&ast; calling clutter_actor_set_parent() now will result in
14453  *      &ast; the internal flag being set on a child of MyActor
14454  *      &ast;/
14455  *
14456  *     /&ast; internal child - a background texture &ast;/
14457  *     self->priv->background_tex = clutter_texture_new ();
14458  *     clutter_actor_set_parent (self->priv->background_tex,
14459  *                               CLUTTER_ACTOR (self));
14460  *
14461  *     /&ast; internal child - a label &ast;/
14462  *     self->priv->label = clutter_text_new ();
14463  *     clutter_actor_set_parent (self->priv->label,
14464  *                               CLUTTER_ACTOR (self));
14465  *
14466  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14467  *
14468  *     /&ast; calling clutter_actor_set_parent() now will not result in
14469  *      &ast; the internal flag being set on a child of MyActor
14470  *      &ast;/
14471  *   }
14472  * ]|
14473  *
14474  * This function will be used by Clutter to toggle an "internal child"
14475  * flag whenever clutter_actor_set_parent() is called; internal children
14476  * are handled differently by Clutter, specifically when destroying their
14477  * parent.
14478  *
14479  * Call clutter_actor_pop_internal() when you finished adding internal
14480  * children.
14481  *
14482  * Nested calls to clutter_actor_push_internal() are allowed, but each
14483  * one must by followed by a clutter_actor_pop_internal() call.
14484  *
14485  * Since: 1.2
14486  *
14487  * Deprecated: 1.10: All children of an actor are accessible through
14488  *   the #ClutterActor API, and #ClutterActor implements the
14489  *   #ClutterContainer interface, so this function is only useful
14490  *   for legacy containers overriding the default implementation.
14491  */
14492 void
14493 clutter_actor_push_internal (ClutterActor *self)
14494 {
14495   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14496
14497   self->priv->internal_child += 1;
14498 }
14499
14500 /**
14501  * clutter_actor_pop_internal:
14502  * @self: a #ClutterActor
14503  *
14504  * Disables the effects of clutter_actor_push_internal().
14505  *
14506  * Since: 1.2
14507  *
14508  * Deprecated: 1.10: All children of an actor are accessible through
14509  *   the #ClutterActor API. This function is only useful for legacy
14510  *   containers overriding the default implementation of the
14511  *   #ClutterContainer interface.
14512  */
14513 void
14514 clutter_actor_pop_internal (ClutterActor *self)
14515 {
14516   ClutterActorPrivate *priv;
14517
14518   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14519
14520   priv = self->priv;
14521
14522   if (priv->internal_child == 0)
14523     {
14524       g_warning ("Mismatched %s: you need to call "
14525                  "clutter_actor_push_composite() at least once before "
14526                  "calling this function", G_STRFUNC);
14527       return;
14528     }
14529
14530   priv->internal_child -= 1;
14531 }
14532
14533 /**
14534  * clutter_actor_has_pointer:
14535  * @self: a #ClutterActor
14536  *
14537  * Checks whether an actor contains the pointer of a
14538  * #ClutterInputDevice
14539  *
14540  * Return value: %TRUE if the actor contains the pointer, and
14541  *   %FALSE otherwise
14542  *
14543  * Since: 1.2
14544  */
14545 gboolean
14546 clutter_actor_has_pointer (ClutterActor *self)
14547 {
14548   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14549
14550   return self->priv->has_pointer;
14551 }
14552
14553 /* XXX: This is a workaround for not being able to break the ABI of
14554  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14555  * clutter_actor_queue_clipped_redraw() for details.
14556  */
14557 ClutterPaintVolume *
14558 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14559 {
14560   return g_object_get_data (G_OBJECT (self),
14561                             "-clutter-actor-queue-redraw-clip");
14562 }
14563
14564 void
14565 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14566                                       ClutterPaintVolume *clip)
14567 {
14568   g_object_set_data (G_OBJECT (self),
14569                      "-clutter-actor-queue-redraw-clip",
14570                      clip);
14571 }
14572
14573 /**
14574  * clutter_actor_has_allocation:
14575  * @self: a #ClutterActor
14576  *
14577  * Checks if the actor has an up-to-date allocation assigned to
14578  * it. This means that the actor should have an allocation: it's
14579  * visible and has a parent. It also means that there is no
14580  * outstanding relayout request in progress for the actor or its
14581  * children (There might be other outstanding layout requests in
14582  * progress that will cause the actor to get a new allocation
14583  * when the stage is laid out, however).
14584  *
14585  * If this function returns %FALSE, then the actor will normally
14586  * be allocated before it is next drawn on the screen.
14587  *
14588  * Return value: %TRUE if the actor has an up-to-date allocation
14589  *
14590  * Since: 1.4
14591  */
14592 gboolean
14593 clutter_actor_has_allocation (ClutterActor *self)
14594 {
14595   ClutterActorPrivate *priv;
14596
14597   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14598
14599   priv = self->priv;
14600
14601   return priv->parent != NULL &&
14602          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14603          !priv->needs_allocation;
14604 }
14605
14606 /**
14607  * clutter_actor_add_action:
14608  * @self: a #ClutterActor
14609  * @action: a #ClutterAction
14610  *
14611  * Adds @action to the list of actions applied to @self
14612  *
14613  * A #ClutterAction can only belong to one actor at a time
14614  *
14615  * The #ClutterActor will hold a reference on @action until either
14616  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14617  * is called
14618  *
14619  * Since: 1.4
14620  */
14621 void
14622 clutter_actor_add_action (ClutterActor  *self,
14623                           ClutterAction *action)
14624 {
14625   ClutterActorPrivate *priv;
14626
14627   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14628   g_return_if_fail (CLUTTER_IS_ACTION (action));
14629
14630   priv = self->priv;
14631
14632   if (priv->actions == NULL)
14633     {
14634       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14635       priv->actions->actor = self;
14636     }
14637
14638   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14639
14640   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14641 }
14642
14643 /**
14644  * clutter_actor_add_action_with_name:
14645  * @self: a #ClutterActor
14646  * @name: the name to set on the action
14647  * @action: a #ClutterAction
14648  *
14649  * A convenience function for setting the name of a #ClutterAction
14650  * while adding it to the list of actions applied to @self
14651  *
14652  * This function is the logical equivalent of:
14653  *
14654  * |[
14655  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14656  *   clutter_actor_add_action (self, action);
14657  * ]|
14658  *
14659  * Since: 1.4
14660  */
14661 void
14662 clutter_actor_add_action_with_name (ClutterActor  *self,
14663                                     const gchar   *name,
14664                                     ClutterAction *action)
14665 {
14666   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14667   g_return_if_fail (name != NULL);
14668   g_return_if_fail (CLUTTER_IS_ACTION (action));
14669
14670   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14671   clutter_actor_add_action (self, action);
14672 }
14673
14674 /**
14675  * clutter_actor_remove_action:
14676  * @self: a #ClutterActor
14677  * @action: a #ClutterAction
14678  *
14679  * Removes @action from the list of actions applied to @self
14680  *
14681  * The reference held by @self on the #ClutterAction will be released
14682  *
14683  * Since: 1.4
14684  */
14685 void
14686 clutter_actor_remove_action (ClutterActor  *self,
14687                              ClutterAction *action)
14688 {
14689   ClutterActorPrivate *priv;
14690
14691   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14692   g_return_if_fail (CLUTTER_IS_ACTION (action));
14693
14694   priv = self->priv;
14695
14696   if (priv->actions == NULL)
14697     return;
14698
14699   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14700
14701   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14702 }
14703
14704 /**
14705  * clutter_actor_remove_action_by_name:
14706  * @self: a #ClutterActor
14707  * @name: the name of the action to remove
14708  *
14709  * Removes the #ClutterAction with the given name from the list
14710  * of actions applied to @self
14711  *
14712  * Since: 1.4
14713  */
14714 void
14715 clutter_actor_remove_action_by_name (ClutterActor *self,
14716                                      const gchar  *name)
14717 {
14718   ClutterActorPrivate *priv;
14719   ClutterActorMeta *meta;
14720
14721   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14722   g_return_if_fail (name != NULL);
14723
14724   priv = self->priv;
14725
14726   if (priv->actions == NULL)
14727     return;
14728
14729   meta = _clutter_meta_group_get_meta (priv->actions, name);
14730   if (meta == NULL)
14731     return;
14732
14733   _clutter_meta_group_remove_meta (priv->actions, meta);
14734
14735   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14736 }
14737
14738 /**
14739  * clutter_actor_get_actions:
14740  * @self: a #ClutterActor
14741  *
14742  * Retrieves the list of actions applied to @self
14743  *
14744  * Return value: (transfer container) (element-type Clutter.Action): a copy
14745  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14746  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14747  *   allocated by the returned #GList
14748  *
14749  * Since: 1.4
14750  */
14751 GList *
14752 clutter_actor_get_actions (ClutterActor *self)
14753 {
14754   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14755
14756   if (self->priv->actions == NULL)
14757     return NULL;
14758
14759   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14760 }
14761
14762 /**
14763  * clutter_actor_get_action:
14764  * @self: a #ClutterActor
14765  * @name: the name of the action to retrieve
14766  *
14767  * Retrieves the #ClutterAction with the given name in the list
14768  * of actions applied to @self
14769  *
14770  * Return value: (transfer none): a #ClutterAction for the given
14771  *   name, or %NULL. The returned #ClutterAction is owned by the
14772  *   actor and it should not be unreferenced directly
14773  *
14774  * Since: 1.4
14775  */
14776 ClutterAction *
14777 clutter_actor_get_action (ClutterActor *self,
14778                           const gchar  *name)
14779 {
14780   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14781   g_return_val_if_fail (name != NULL, NULL);
14782
14783   if (self->priv->actions == NULL)
14784     return NULL;
14785
14786   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14787 }
14788
14789 /**
14790  * clutter_actor_clear_actions:
14791  * @self: a #ClutterActor
14792  *
14793  * Clears the list of actions applied to @self
14794  *
14795  * Since: 1.4
14796  */
14797 void
14798 clutter_actor_clear_actions (ClutterActor *self)
14799 {
14800   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14801
14802   if (self->priv->actions == NULL)
14803     return;
14804
14805   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14806 }
14807
14808 /**
14809  * clutter_actor_add_constraint:
14810  * @self: a #ClutterActor
14811  * @constraint: a #ClutterConstraint
14812  *
14813  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14814  * to @self
14815  *
14816  * The #ClutterActor will hold a reference on the @constraint until
14817  * either clutter_actor_remove_constraint() or
14818  * clutter_actor_clear_constraints() is called.
14819  *
14820  * Since: 1.4
14821  */
14822 void
14823 clutter_actor_add_constraint (ClutterActor      *self,
14824                               ClutterConstraint *constraint)
14825 {
14826   ClutterActorPrivate *priv;
14827
14828   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14829   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14830
14831   priv = self->priv;
14832
14833   if (priv->constraints == NULL)
14834     {
14835       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14836       priv->constraints->actor = self;
14837     }
14838
14839   _clutter_meta_group_add_meta (priv->constraints,
14840                                 CLUTTER_ACTOR_META (constraint));
14841   clutter_actor_queue_relayout (self);
14842
14843   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14844 }
14845
14846 /**
14847  * clutter_actor_add_constraint_with_name:
14848  * @self: a #ClutterActor
14849  * @name: the name to set on the constraint
14850  * @constraint: a #ClutterConstraint
14851  *
14852  * A convenience function for setting the name of a #ClutterConstraint
14853  * while adding it to the list of constraints applied to @self
14854  *
14855  * This function is the logical equivalent of:
14856  *
14857  * |[
14858  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14859  *   clutter_actor_add_constraint (self, constraint);
14860  * ]|
14861  *
14862  * Since: 1.4
14863  */
14864 void
14865 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14866                                         const gchar       *name,
14867                                         ClutterConstraint *constraint)
14868 {
14869   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14870   g_return_if_fail (name != NULL);
14871   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14872
14873   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14874   clutter_actor_add_constraint (self, constraint);
14875 }
14876
14877 /**
14878  * clutter_actor_remove_constraint:
14879  * @self: a #ClutterActor
14880  * @constraint: a #ClutterConstraint
14881  *
14882  * Removes @constraint from the list of constraints applied to @self
14883  *
14884  * The reference held by @self on the #ClutterConstraint will be released
14885  *
14886  * Since: 1.4
14887  */
14888 void
14889 clutter_actor_remove_constraint (ClutterActor      *self,
14890                                  ClutterConstraint *constraint)
14891 {
14892   ClutterActorPrivate *priv;
14893
14894   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14895   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14896
14897   priv = self->priv;
14898
14899   if (priv->constraints == NULL)
14900     return;
14901
14902   _clutter_meta_group_remove_meta (priv->constraints,
14903                                    CLUTTER_ACTOR_META (constraint));
14904   clutter_actor_queue_relayout (self);
14905
14906   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14907 }
14908
14909 /**
14910  * clutter_actor_remove_constraint_by_name:
14911  * @self: a #ClutterActor
14912  * @name: the name of the constraint to remove
14913  *
14914  * Removes the #ClutterConstraint with the given name from the list
14915  * of constraints applied to @self
14916  *
14917  * Since: 1.4
14918  */
14919 void
14920 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14921                                          const gchar  *name)
14922 {
14923   ClutterActorPrivate *priv;
14924   ClutterActorMeta *meta;
14925
14926   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14927   g_return_if_fail (name != NULL);
14928
14929   priv = self->priv;
14930
14931   if (priv->constraints == NULL)
14932     return;
14933
14934   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14935   if (meta == NULL)
14936     return;
14937
14938   _clutter_meta_group_remove_meta (priv->constraints, meta);
14939   clutter_actor_queue_relayout (self);
14940 }
14941
14942 /**
14943  * clutter_actor_get_constraints:
14944  * @self: a #ClutterActor
14945  *
14946  * Retrieves the list of constraints applied to @self
14947  *
14948  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14949  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14950  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14951  *   allocated by the returned #GList
14952  *
14953  * Since: 1.4
14954  */
14955 GList *
14956 clutter_actor_get_constraints (ClutterActor *self)
14957 {
14958   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14959
14960   if (self->priv->constraints == NULL)
14961     return NULL;
14962
14963   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14964 }
14965
14966 /**
14967  * clutter_actor_get_constraint:
14968  * @self: a #ClutterActor
14969  * @name: the name of the constraint to retrieve
14970  *
14971  * Retrieves the #ClutterConstraint with the given name in the list
14972  * of constraints applied to @self
14973  *
14974  * Return value: (transfer none): a #ClutterConstraint for the given
14975  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14976  *   actor and it should not be unreferenced directly
14977  *
14978  * Since: 1.4
14979  */
14980 ClutterConstraint *
14981 clutter_actor_get_constraint (ClutterActor *self,
14982                               const gchar  *name)
14983 {
14984   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14985   g_return_val_if_fail (name != NULL, NULL);
14986
14987   if (self->priv->constraints == NULL)
14988     return NULL;
14989
14990   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14991 }
14992
14993 /**
14994  * clutter_actor_clear_constraints:
14995  * @self: a #ClutterActor
14996  *
14997  * Clears the list of constraints applied to @self
14998  *
14999  * Since: 1.4
15000  */
15001 void
15002 clutter_actor_clear_constraints (ClutterActor *self)
15003 {
15004   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15005
15006   if (self->priv->constraints == NULL)
15007     return;
15008
15009   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15010
15011   clutter_actor_queue_relayout (self);
15012 }
15013
15014 /**
15015  * clutter_actor_set_clip_to_allocation:
15016  * @self: a #ClutterActor
15017  * @clip_set: %TRUE to apply a clip tracking the allocation
15018  *
15019  * Sets whether @self should be clipped to the same size as its
15020  * allocation
15021  *
15022  * Since: 1.4
15023  */
15024 void
15025 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15026                                       gboolean      clip_set)
15027 {
15028   ClutterActorPrivate *priv;
15029
15030   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15031
15032   clip_set = !!clip_set;
15033
15034   priv = self->priv;
15035
15036   if (priv->clip_to_allocation != clip_set)
15037     {
15038       priv->clip_to_allocation = clip_set;
15039
15040       clutter_actor_queue_redraw (self);
15041
15042       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15043     }
15044 }
15045
15046 /**
15047  * clutter_actor_get_clip_to_allocation:
15048  * @self: a #ClutterActor
15049  *
15050  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15051  *
15052  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15053  *
15054  * Since: 1.4
15055  */
15056 gboolean
15057 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15058 {
15059   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15060
15061   return self->priv->clip_to_allocation;
15062 }
15063
15064 /**
15065  * clutter_actor_add_effect:
15066  * @self: a #ClutterActor
15067  * @effect: a #ClutterEffect
15068  *
15069  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15070  *
15071  * The #ClutterActor will hold a reference on the @effect until either
15072  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15073  * called.
15074  *
15075  * Since: 1.4
15076  */
15077 void
15078 clutter_actor_add_effect (ClutterActor  *self,
15079                           ClutterEffect *effect)
15080 {
15081   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15082   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15083
15084   _clutter_actor_add_effect_internal (self, effect);
15085
15086   clutter_actor_queue_redraw (self);
15087
15088   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15089 }
15090
15091 /**
15092  * clutter_actor_add_effect_with_name:
15093  * @self: a #ClutterActor
15094  * @name: the name to set on the effect
15095  * @effect: a #ClutterEffect
15096  *
15097  * A convenience function for setting the name of a #ClutterEffect
15098  * while adding it to the list of effectss applied to @self
15099  *
15100  * This function is the logical equivalent of:
15101  *
15102  * |[
15103  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15104  *   clutter_actor_add_effect (self, effect);
15105  * ]|
15106  *
15107  * Since: 1.4
15108  */
15109 void
15110 clutter_actor_add_effect_with_name (ClutterActor  *self,
15111                                     const gchar   *name,
15112                                     ClutterEffect *effect)
15113 {
15114   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15115   g_return_if_fail (name != NULL);
15116   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15117
15118   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15119   clutter_actor_add_effect (self, effect);
15120 }
15121
15122 /**
15123  * clutter_actor_remove_effect:
15124  * @self: a #ClutterActor
15125  * @effect: a #ClutterEffect
15126  *
15127  * Removes @effect from the list of effects applied to @self
15128  *
15129  * The reference held by @self on the #ClutterEffect will be released
15130  *
15131  * Since: 1.4
15132  */
15133 void
15134 clutter_actor_remove_effect (ClutterActor  *self,
15135                              ClutterEffect *effect)
15136 {
15137   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15138   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15139
15140   _clutter_actor_remove_effect_internal (self, effect);
15141
15142   clutter_actor_queue_redraw (self);
15143
15144   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15145 }
15146
15147 /**
15148  * clutter_actor_remove_effect_by_name:
15149  * @self: a #ClutterActor
15150  * @name: the name of the effect to remove
15151  *
15152  * Removes the #ClutterEffect with the given name from the list
15153  * of effects applied to @self
15154  *
15155  * Since: 1.4
15156  */
15157 void
15158 clutter_actor_remove_effect_by_name (ClutterActor *self,
15159                                      const gchar  *name)
15160 {
15161   ClutterActorPrivate *priv;
15162   ClutterActorMeta *meta;
15163
15164   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15165   g_return_if_fail (name != NULL);
15166
15167   priv = self->priv;
15168
15169   if (priv->effects == NULL)
15170     return;
15171
15172   meta = _clutter_meta_group_get_meta (priv->effects, name);
15173   if (meta == NULL)
15174     return;
15175
15176   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15177 }
15178
15179 /**
15180  * clutter_actor_get_effects:
15181  * @self: a #ClutterActor
15182  *
15183  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15184  *
15185  * Return value: (transfer container) (element-type Clutter.Effect): a list
15186  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15187  *   list are owned by Clutter and they should not be freed. You should
15188  *   free the returned list using g_list_free() when done
15189  *
15190  * Since: 1.4
15191  */
15192 GList *
15193 clutter_actor_get_effects (ClutterActor *self)
15194 {
15195   ClutterActorPrivate *priv;
15196
15197   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15198
15199   priv = self->priv;
15200
15201   if (priv->effects == NULL)
15202     return NULL;
15203
15204   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15205 }
15206
15207 /**
15208  * clutter_actor_get_effect:
15209  * @self: a #ClutterActor
15210  * @name: the name of the effect to retrieve
15211  *
15212  * Retrieves the #ClutterEffect with the given name in the list
15213  * of effects applied to @self
15214  *
15215  * Return value: (transfer none): a #ClutterEffect for the given
15216  *   name, or %NULL. The returned #ClutterEffect is owned by the
15217  *   actor and it should not be unreferenced directly
15218  *
15219  * Since: 1.4
15220  */
15221 ClutterEffect *
15222 clutter_actor_get_effect (ClutterActor *self,
15223                           const gchar  *name)
15224 {
15225   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15226   g_return_val_if_fail (name != NULL, NULL);
15227
15228   if (self->priv->effects == NULL)
15229     return NULL;
15230
15231   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15232 }
15233
15234 /**
15235  * clutter_actor_clear_effects:
15236  * @self: a #ClutterActor
15237  *
15238  * Clears the list of effects applied to @self
15239  *
15240  * Since: 1.4
15241  */
15242 void
15243 clutter_actor_clear_effects (ClutterActor *self)
15244 {
15245   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15246
15247   if (self->priv->effects == NULL)
15248     return;
15249
15250   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15251
15252   clutter_actor_queue_redraw (self);
15253 }
15254
15255 /**
15256  * clutter_actor_has_key_focus:
15257  * @self: a #ClutterActor
15258  *
15259  * Checks whether @self is the #ClutterActor that has key focus
15260  *
15261  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15262  *
15263  * Since: 1.4
15264  */
15265 gboolean
15266 clutter_actor_has_key_focus (ClutterActor *self)
15267 {
15268   ClutterActor *stage;
15269
15270   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15271
15272   stage = _clutter_actor_get_stage_internal (self);
15273   if (stage == NULL)
15274     return FALSE;
15275
15276   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15277 }
15278
15279 static gboolean
15280 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15281                                       ClutterPaintVolume *pv)
15282 {
15283   ClutterActorPrivate *priv = self->priv;
15284
15285   /* Actors are only expected to report a valid paint volume
15286    * while they have a valid allocation. */
15287   if (G_UNLIKELY (priv->needs_allocation))
15288     {
15289       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15290                     "Actor needs allocation",
15291                     _clutter_actor_get_debug_name (self));
15292       return FALSE;
15293     }
15294
15295   /* Check if there are any handlers connected to the paint
15296    * signal. If there are then all bets are off for what the paint
15297    * volume for this actor might possibly be!
15298    *
15299    * XXX: It's expected that this is going to end up being quite a
15300    * costly check to have to do here, but we haven't come up with
15301    * another solution that can reliably catch paint signal handlers at
15302    * the right time to either avoid artefacts due to invalid stage
15303    * clipping or due to incorrect culling.
15304    *
15305    * Previously we checked in clutter_actor_paint(), but at that time
15306    * we may already be using a stage clip that could be derived from
15307    * an invalid paint-volume. We used to try and handle that by
15308    * queuing a follow up, unclipped, redraw but still the previous
15309    * checking wasn't enough to catch invalid volumes involved in
15310    * culling (considering that containers may derive their volume from
15311    * children that haven't yet been painted)
15312    *
15313    * Longer term, improved solutions could be:
15314    * - Disallow painting in the paint signal, only allow using it
15315    *   for tracking when paints happen. We can add another API that
15316    *   allows monkey patching the paint of arbitrary actors but in a
15317    *   more controlled way and that also supports modifying the
15318    *   paint-volume.
15319    * - If we could be notified somehow when signal handlers are
15320    *   connected we wouldn't have to poll for handlers like this.
15321    */
15322   if (g_signal_has_handler_pending (self,
15323                                     actor_signals[PAINT],
15324                                     0,
15325                                     TRUE))
15326     {
15327       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15328                     "Actor has \"paint\" signal handlers",
15329                     _clutter_actor_get_debug_name (self));
15330       return FALSE;
15331     }
15332
15333   _clutter_paint_volume_init_static (pv, self);
15334
15335   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15336     {
15337       clutter_paint_volume_free (pv);
15338       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15339                     "Actor failed to report a volume",
15340                     _clutter_actor_get_debug_name (self));
15341       return FALSE;
15342     }
15343
15344   /* since effects can modify the paint volume, we allow them to actually
15345    * do this by making get_paint_volume() "context sensitive"
15346    */
15347   if (priv->effects != NULL)
15348     {
15349       if (priv->current_effect != NULL)
15350         {
15351           const GList *effects, *l;
15352
15353           /* if we are being called from within the paint sequence of
15354            * an actor, get the paint volume up to the current effect
15355            */
15356           effects = _clutter_meta_group_peek_metas (priv->effects);
15357           for (l = effects;
15358                l != NULL || (l != NULL && l->data != priv->current_effect);
15359                l = l->next)
15360             {
15361               if (!_clutter_effect_get_paint_volume (l->data, pv))
15362                 {
15363                   clutter_paint_volume_free (pv);
15364                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15365                                 "Effect (%s) failed to report a volume",
15366                                 _clutter_actor_get_debug_name (self),
15367                                 _clutter_actor_meta_get_debug_name (l->data));
15368                   return FALSE;
15369                 }
15370             }
15371         }
15372       else
15373         {
15374           const GList *effects, *l;
15375
15376           /* otherwise, get the cumulative volume */
15377           effects = _clutter_meta_group_peek_metas (priv->effects);
15378           for (l = effects; l != NULL; l = l->next)
15379             if (!_clutter_effect_get_paint_volume (l->data, pv))
15380               {
15381                 clutter_paint_volume_free (pv);
15382                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15383                               "Effect (%s) failed to report a volume",
15384                               _clutter_actor_get_debug_name (self),
15385                               _clutter_actor_meta_get_debug_name (l->data));
15386                 return FALSE;
15387               }
15388         }
15389     }
15390
15391   return TRUE;
15392 }
15393
15394 /* The public clutter_actor_get_paint_volume API returns a const
15395  * pointer since we return a pointer directly to the cached
15396  * PaintVolume associated with the actor and don't want the user to
15397  * inadvertently modify it, but for internal uses we sometimes need
15398  * access to the same PaintVolume but need to apply some book-keeping
15399  * modifications to it so we don't want a const pointer.
15400  */
15401 static ClutterPaintVolume *
15402 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15403 {
15404   ClutterActorPrivate *priv;
15405
15406   priv = self->priv;
15407
15408   if (priv->paint_volume_valid)
15409     clutter_paint_volume_free (&priv->paint_volume);
15410
15411   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15412     {
15413       priv->paint_volume_valid = TRUE;
15414       return &priv->paint_volume;
15415     }
15416   else
15417     {
15418       priv->paint_volume_valid = FALSE;
15419       return NULL;
15420     }
15421 }
15422
15423 /**
15424  * clutter_actor_get_paint_volume:
15425  * @self: a #ClutterActor
15426  *
15427  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15428  * when a paint volume can't be determined.
15429  *
15430  * The paint volume is defined as the 3D space occupied by an actor
15431  * when being painted.
15432  *
15433  * This function will call the <function>get_paint_volume()</function>
15434  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15435  * should not usually care about overriding the default implementation,
15436  * unless they are, for instance: painting outside their allocation, or
15437  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15438  * 3D depth).
15439  *
15440  * <note>2D actors overriding <function>get_paint_volume()</function>
15441  * ensure their volume has a depth of 0. (This will be true so long as
15442  * you don't call clutter_paint_volume_set_depth().)</note>
15443  *
15444  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15445  *   or %NULL if no volume could be determined. The returned pointer
15446  *   is not guaranteed to be valid across multiple frames; if you want
15447  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15448  *
15449  * Since: 1.6
15450  */
15451 const ClutterPaintVolume *
15452 clutter_actor_get_paint_volume (ClutterActor *self)
15453 {
15454   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15455
15456   return _clutter_actor_get_paint_volume_mutable (self);
15457 }
15458
15459 /**
15460  * clutter_actor_get_transformed_paint_volume:
15461  * @self: a #ClutterActor
15462  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15463  *    (or %NULL for the stage)
15464  *
15465  * Retrieves the 3D paint volume of an actor like
15466  * clutter_actor_get_paint_volume() does (Please refer to the
15467  * documentation of clutter_actor_get_paint_volume() for more
15468  * details.) and it additionally transforms the paint volume into the
15469  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15470  * is passed for @relative_to_ancestor)
15471  *
15472  * This can be used by containers that base their paint volume on
15473  * the volume of their children. Such containers can query the
15474  * transformed paint volume of all of its children and union them
15475  * together using clutter_paint_volume_union().
15476  *
15477  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15478  *   or %NULL if no volume could be determined. The returned pointer is
15479  *   not guaranteed to be valid across multiple frames; if you wish to
15480  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15481  *
15482  * Since: 1.6
15483  */
15484 const ClutterPaintVolume *
15485 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15486                                             ClutterActor *relative_to_ancestor)
15487 {
15488   const ClutterPaintVolume *volume;
15489   ClutterActor *stage;
15490   ClutterPaintVolume *transformed_volume;
15491
15492   stage = _clutter_actor_get_stage_internal (self);
15493   if (G_UNLIKELY (stage == NULL))
15494     return NULL;
15495
15496   if (relative_to_ancestor == NULL)
15497     relative_to_ancestor = stage;
15498
15499   volume = clutter_actor_get_paint_volume (self);
15500   if (volume == NULL)
15501     return NULL;
15502
15503   transformed_volume =
15504     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15505
15506   _clutter_paint_volume_copy_static (volume, transformed_volume);
15507
15508   _clutter_paint_volume_transform_relative (transformed_volume,
15509                                             relative_to_ancestor);
15510
15511   return transformed_volume;
15512 }
15513
15514 /**
15515  * clutter_actor_get_paint_box:
15516  * @self: a #ClutterActor
15517  * @box: (out): return location for a #ClutterActorBox
15518  *
15519  * Retrieves the paint volume of the passed #ClutterActor, and
15520  * transforms it into a 2D bounding box in stage coordinates.
15521  *
15522  * This function is useful to determine the on screen area occupied by
15523  * the actor. The box is only an approximation and may often be
15524  * considerably larger due to the optimizations used to calculate the
15525  * box. The box is never smaller though, so it can reliably be used
15526  * for culling.
15527  *
15528  * There are times when a 2D paint box can't be determined, e.g.
15529  * because the actor isn't yet parented under a stage or because
15530  * the actor is unable to determine a paint volume.
15531  *
15532  * Return value: %TRUE if a 2D paint box could be determined, else
15533  * %FALSE.
15534  *
15535  * Since: 1.6
15536  */
15537 gboolean
15538 clutter_actor_get_paint_box (ClutterActor    *self,
15539                              ClutterActorBox *box)
15540 {
15541   ClutterActor *stage;
15542   ClutterPaintVolume *pv;
15543
15544   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15545   g_return_val_if_fail (box != NULL, FALSE);
15546
15547   stage = _clutter_actor_get_stage_internal (self);
15548   if (G_UNLIKELY (!stage))
15549     return FALSE;
15550
15551   pv = _clutter_actor_get_paint_volume_mutable (self);
15552   if (G_UNLIKELY (!pv))
15553     return FALSE;
15554
15555   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15556
15557   return TRUE;
15558 }
15559
15560 /**
15561  * clutter_actor_has_overlaps:
15562  * @self: A #ClutterActor
15563  *
15564  * Asks the actor's implementation whether it may contain overlapping
15565  * primitives.
15566  *
15567  * For example; Clutter may use this to determine whether the painting
15568  * should be redirected to an offscreen buffer to correctly implement
15569  * the opacity property.
15570  *
15571  * Custom actors can override the default response by implementing the
15572  * #ClutterActor <function>has_overlaps</function> virtual function. See
15573  * clutter_actor_set_offscreen_redirect() for more information.
15574  *
15575  * Return value: %TRUE if the actor may have overlapping primitives, and
15576  *   %FALSE otherwise
15577  *
15578  * Since: 1.8
15579  */
15580 gboolean
15581 clutter_actor_has_overlaps (ClutterActor *self)
15582 {
15583   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15584
15585   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15586 }
15587
15588 /**
15589  * clutter_actor_has_effects:
15590  * @self: A #ClutterActor
15591  *
15592  * Returns whether the actor has any effects applied.
15593  *
15594  * Return value: %TRUE if the actor has any effects,
15595  *   %FALSE otherwise
15596  *
15597  * Since: 1.10
15598  */
15599 gboolean
15600 clutter_actor_has_effects (ClutterActor *self)
15601 {
15602   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15603
15604   if (self->priv->effects == NULL)
15605     return FALSE;
15606
15607   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15608 }
15609
15610 /**
15611  * clutter_actor_has_constraints:
15612  * @self: A #ClutterActor
15613  *
15614  * Returns whether the actor has any constraints applied.
15615  *
15616  * Return value: %TRUE if the actor has any constraints,
15617  *   %FALSE otherwise
15618  *
15619  * Since: 1.10
15620  */
15621 gboolean
15622 clutter_actor_has_constraints (ClutterActor *self)
15623 {
15624   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15625
15626   return self->priv->constraints != NULL;
15627 }
15628
15629 /**
15630  * clutter_actor_has_actions:
15631  * @self: A #ClutterActor
15632  *
15633  * Returns whether the actor has any actions applied.
15634  *
15635  * Return value: %TRUE if the actor has any actions,
15636  *   %FALSE otherwise
15637  *
15638  * Since: 1.10
15639  */
15640 gboolean
15641 clutter_actor_has_actions (ClutterActor *self)
15642 {
15643   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15644
15645   return self->priv->actions != NULL;
15646 }
15647
15648 /**
15649  * clutter_actor_get_n_children:
15650  * @self: a #ClutterActor
15651  *
15652  * Retrieves the number of children of @self.
15653  *
15654  * Return value: the number of children of an actor
15655  *
15656  * Since: 1.10
15657  */
15658 gint
15659 clutter_actor_get_n_children (ClutterActor *self)
15660 {
15661   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15662
15663   return self->priv->n_children;
15664 }
15665
15666 /**
15667  * clutter_actor_get_child_at_index:
15668  * @self: a #ClutterActor
15669  * @index_: the position in the list of children
15670  *
15671  * Retrieves the actor at the given @index_ inside the list of
15672  * children of @self.
15673  *
15674  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15675  *
15676  * Since: 1.10
15677  */
15678 ClutterActor *
15679 clutter_actor_get_child_at_index (ClutterActor *self,
15680                                   gint          index_)
15681 {
15682   ClutterActor *iter;
15683   int i;
15684
15685   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15686   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15687
15688   for (iter = self->priv->first_child, i = 0;
15689        iter != NULL && i < index_;
15690        iter = iter->priv->next_sibling, i += 1)
15691     ;
15692
15693   return iter;
15694 }
15695
15696 /*< private >
15697  * _clutter_actor_foreach_child:
15698  * @actor: The actor whos children you want to iterate
15699  * @callback: The function to call for each child
15700  * @user_data: Private data to pass to @callback
15701  *
15702  * Calls a given @callback once for each child of the specified @actor and
15703  * passing the @user_data pointer each time.
15704  *
15705  * Return value: returns %TRUE if all children were iterated, else
15706  *    %FALSE if a callback broke out of iteration early.
15707  */
15708 gboolean
15709 _clutter_actor_foreach_child (ClutterActor           *self,
15710                               ClutterForeachCallback  callback,
15711                               gpointer                user_data)
15712 {
15713   ClutterActorPrivate *priv = self->priv;
15714   ClutterActor *iter;
15715   gboolean cont;
15716
15717   for (cont = TRUE, iter = priv->first_child;
15718        cont && iter != NULL;
15719        iter = iter->priv->next_sibling)
15720     {
15721       cont = callback (iter, user_data);
15722     }
15723
15724   return cont;
15725 }
15726
15727 #if 0
15728 /* For debugging purposes this gives us a simple way to print out
15729  * the scenegraph e.g in gdb using:
15730  * [|
15731  *   _clutter_actor_traverse (stage,
15732  *                            0,
15733  *                            clutter_debug_print_actor_cb,
15734  *                            NULL,
15735  *                            NULL);
15736  * |]
15737  */
15738 static ClutterActorTraverseVisitFlags
15739 clutter_debug_print_actor_cb (ClutterActor *actor,
15740                               int depth,
15741                               void *user_data)
15742 {
15743   g_print ("%*s%s:%p\n",
15744            depth * 2, "",
15745            _clutter_actor_get_debug_name (actor),
15746            actor);
15747
15748   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15749 }
15750 #endif
15751
15752 static void
15753 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15754                                  ClutterTraverseCallback callback,
15755                                  gpointer                user_data)
15756 {
15757   GQueue *queue = g_queue_new ();
15758   ClutterActor dummy;
15759   int current_depth = 0;
15760
15761   g_queue_push_tail (queue, actor);
15762   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15763
15764   while ((actor = g_queue_pop_head (queue)))
15765     {
15766       ClutterActorTraverseVisitFlags flags;
15767
15768       if (actor == &dummy)
15769         {
15770           current_depth++;
15771           g_queue_push_tail (queue, &dummy);
15772           continue;
15773         }
15774
15775       flags = callback (actor, current_depth, user_data);
15776       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15777         break;
15778       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15779         {
15780           ClutterActor *iter;
15781
15782           for (iter = actor->priv->first_child;
15783                iter != NULL;
15784                iter = iter->priv->next_sibling)
15785             {
15786               g_queue_push_tail (queue, iter);
15787             }
15788         }
15789     }
15790
15791   g_queue_free (queue);
15792 }
15793
15794 static ClutterActorTraverseVisitFlags
15795 _clutter_actor_traverse_depth (ClutterActor           *actor,
15796                                ClutterTraverseCallback before_children_callback,
15797                                ClutterTraverseCallback after_children_callback,
15798                                int                     current_depth,
15799                                gpointer                user_data)
15800 {
15801   ClutterActorTraverseVisitFlags flags;
15802
15803   flags = before_children_callback (actor, current_depth, user_data);
15804   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15805     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15806
15807   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15808     {
15809       ClutterActor *iter;
15810
15811       for (iter = actor->priv->first_child;
15812            iter != NULL;
15813            iter = iter->priv->next_sibling)
15814         {
15815           flags = _clutter_actor_traverse_depth (iter,
15816                                                  before_children_callback,
15817                                                  after_children_callback,
15818                                                  current_depth + 1,
15819                                                  user_data);
15820
15821           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15822             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15823         }
15824     }
15825
15826   if (after_children_callback)
15827     return after_children_callback (actor, current_depth, user_data);
15828   else
15829     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15830 }
15831
15832 /* _clutter_actor_traverse:
15833  * @actor: The actor to start traversing the graph from
15834  * @flags: These flags may affect how the traversal is done
15835  * @before_children_callback: A function to call before visiting the
15836  *   children of the current actor.
15837  * @after_children_callback: A function to call after visiting the
15838  *   children of the current actor. (Ignored if
15839  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15840  * @user_data: The private data to pass to the callbacks
15841  *
15842  * Traverses the scenegraph starting at the specified @actor and
15843  * descending through all its children and its children's children.
15844  * For each actor traversed @before_children_callback and
15845  * @after_children_callback are called with the specified
15846  * @user_data, before and after visiting that actor's children.
15847  *
15848  * The callbacks can return flags that affect the ongoing traversal
15849  * such as by skipping over an actors children or bailing out of
15850  * any further traversing.
15851  */
15852 void
15853 _clutter_actor_traverse (ClutterActor              *actor,
15854                          ClutterActorTraverseFlags  flags,
15855                          ClutterTraverseCallback    before_children_callback,
15856                          ClutterTraverseCallback    after_children_callback,
15857                          gpointer                   user_data)
15858 {
15859   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15860     _clutter_actor_traverse_breadth (actor,
15861                                      before_children_callback,
15862                                      user_data);
15863   else /* DEPTH_FIRST */
15864     _clutter_actor_traverse_depth (actor,
15865                                    before_children_callback,
15866                                    after_children_callback,
15867                                    0, /* start depth */
15868                                    user_data);
15869 }
15870
15871 static void
15872 on_layout_manager_changed (ClutterLayoutManager *manager,
15873                            ClutterActor         *self)
15874 {
15875   clutter_actor_queue_relayout (self);
15876 }
15877
15878 /**
15879  * clutter_actor_set_layout_manager:
15880  * @self: a #ClutterActor
15881  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15882  *
15883  * Sets the #ClutterLayoutManager delegate object that will be used to
15884  * lay out the children of @self.
15885  *
15886  * The #ClutterActor will take a reference on the passed @manager which
15887  * will be released either when the layout manager is removed, or when
15888  * the actor is destroyed.
15889  *
15890  * Since: 1.10
15891  */
15892 void
15893 clutter_actor_set_layout_manager (ClutterActor         *self,
15894                                   ClutterLayoutManager *manager)
15895 {
15896   ClutterActorPrivate *priv;
15897
15898   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15899   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15900
15901   priv = self->priv;
15902
15903   if (priv->layout_manager != NULL)
15904     {
15905       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15906                                             G_CALLBACK (on_layout_manager_changed),
15907                                             self);
15908       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15909       g_clear_object (&priv->layout_manager);
15910     }
15911
15912   priv->layout_manager = manager;
15913
15914   if (priv->layout_manager != NULL)
15915     {
15916       g_object_ref_sink (priv->layout_manager);
15917       clutter_layout_manager_set_container (priv->layout_manager,
15918                                             CLUTTER_CONTAINER (self));
15919       g_signal_connect (priv->layout_manager, "layout-changed",
15920                         G_CALLBACK (on_layout_manager_changed),
15921                         self);
15922     }
15923
15924   clutter_actor_queue_relayout (self);
15925
15926   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15927 }
15928
15929 /**
15930  * clutter_actor_get_layout_manager:
15931  * @self: a #ClutterActor
15932  *
15933  * Retrieves the #ClutterLayoutManager used by @self.
15934  *
15935  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15936  *   or %NULL
15937  *
15938  * Since: 1.10
15939  */
15940 ClutterLayoutManager *
15941 clutter_actor_get_layout_manager (ClutterActor *self)
15942 {
15943   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15944
15945   return self->priv->layout_manager;
15946 }
15947
15948 static const ClutterLayoutInfo default_layout_info = {
15949   0.f,                          /* fixed-x */
15950   0.f,                          /* fixed-y */
15951   { 0, 0, 0, 0 },               /* margin */
15952   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15953   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15954   0.f, 0.f,                     /* min_width, natural_width */
15955   0.f, 0.f,                     /* natual_width, natural_height */
15956 };
15957
15958 static void
15959 layout_info_free (gpointer data)
15960 {
15961   if (G_LIKELY (data != NULL))
15962     g_slice_free (ClutterLayoutInfo, data);
15963 }
15964
15965 /*< private >
15966  * _clutter_actor_get_layout_info:
15967  * @self: a #ClutterActor
15968  *
15969  * Retrieves a pointer to the ClutterLayoutInfo structure.
15970  *
15971  * If the actor does not have a ClutterLayoutInfo associated to it, one
15972  * will be created and initialized to the default values.
15973  *
15974  * This function should be used for setters.
15975  *
15976  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15977  * instead.
15978  *
15979  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15980  */
15981 ClutterLayoutInfo *
15982 _clutter_actor_get_layout_info (ClutterActor *self)
15983 {
15984   ClutterLayoutInfo *retval;
15985
15986   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15987   if (retval == NULL)
15988     {
15989       retval = g_slice_new (ClutterLayoutInfo);
15990
15991       *retval = default_layout_info;
15992
15993       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15994                                retval,
15995                                layout_info_free);
15996     }
15997
15998   return retval;
15999 }
16000
16001 /*< private >
16002  * _clutter_actor_get_layout_info_or_defaults:
16003  * @self: a #ClutterActor
16004  *
16005  * Retrieves the ClutterLayoutInfo structure associated to an actor.
16006  *
16007  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16008  * then the default structure will be returned.
16009  *
16010  * This function should only be used for getters.
16011  *
16012  * Return value: a const pointer to the ClutterLayoutInfo structure
16013  */
16014 const ClutterLayoutInfo *
16015 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16016 {
16017   const ClutterLayoutInfo *info;
16018
16019   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16020   if (info == NULL)
16021     return &default_layout_info;
16022
16023   return info;
16024 }
16025
16026 /**
16027  * clutter_actor_set_x_align:
16028  * @self: a #ClutterActor
16029  * @x_align: the horizontal alignment policy
16030  *
16031  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16032  * actor received extra horizontal space.
16033  *
16034  * See also the #ClutterActor:x-align property.
16035  *
16036  * Since: 1.10
16037  */
16038 void
16039 clutter_actor_set_x_align (ClutterActor      *self,
16040                            ClutterActorAlign  x_align)
16041 {
16042   ClutterLayoutInfo *info;
16043
16044   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16045
16046   info = _clutter_actor_get_layout_info (self);
16047
16048   if (info->x_align != x_align)
16049     {
16050       info->x_align = x_align;
16051
16052       clutter_actor_queue_relayout (self);
16053
16054       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16055     }
16056 }
16057
16058 /**
16059  * clutter_actor_get_x_align:
16060  * @self: a #ClutterActor
16061  *
16062  * Retrieves the horizontal alignment policy set using
16063  * clutter_actor_set_x_align().
16064  *
16065  * Return value: the horizontal alignment policy.
16066  *
16067  * Since: 1.10
16068  */
16069 ClutterActorAlign
16070 clutter_actor_get_x_align (ClutterActor *self)
16071 {
16072   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16073
16074   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16075 }
16076
16077 /**
16078  * clutter_actor_set_y_align:
16079  * @self: a #ClutterActor
16080  * @y_align: the vertical alignment policy
16081  *
16082  * Sets the vertical alignment policy of a #ClutterActor, in case the
16083  * actor received extra vertical space.
16084  *
16085  * See also the #ClutterActor:y-align property.
16086  *
16087  * Since: 1.10
16088  */
16089 void
16090 clutter_actor_set_y_align (ClutterActor      *self,
16091                            ClutterActorAlign  y_align)
16092 {
16093   ClutterLayoutInfo *info;
16094
16095   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16096
16097   info = _clutter_actor_get_layout_info (self);
16098
16099   if (info->y_align != y_align)
16100     {
16101       info->y_align = y_align;
16102
16103       clutter_actor_queue_relayout (self);
16104
16105       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16106     }
16107 }
16108
16109 /**
16110  * clutter_actor_get_y_align:
16111  * @self: a #ClutterActor
16112  *
16113  * Retrieves the vertical alignment policy set using
16114  * clutter_actor_set_y_align().
16115  *
16116  * Return value: the vertical alignment policy.
16117  *
16118  * Since: 1.10
16119  */
16120 ClutterActorAlign
16121 clutter_actor_get_y_align (ClutterActor *self)
16122 {
16123   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16124
16125   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16126 }
16127
16128
16129 /**
16130  * clutter_margin_new:
16131  *
16132  * Creates a new #ClutterMargin.
16133  *
16134  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16135  *   clutter_margin_free() to free the resources associated with it when
16136  *   done.
16137  *
16138  * Since: 1.10
16139  */
16140 ClutterMargin *
16141 clutter_margin_new (void)
16142 {
16143   return g_slice_new0 (ClutterMargin);
16144 }
16145
16146 /**
16147  * clutter_margin_copy:
16148  * @margin_: a #ClutterMargin
16149  *
16150  * Creates a new #ClutterMargin and copies the contents of @margin_ into
16151  * the newly created structure.
16152  *
16153  * Return value: (transfer full): a copy of the #ClutterMargin.
16154  *
16155  * Since: 1.10
16156  */
16157 ClutterMargin *
16158 clutter_margin_copy (const ClutterMargin *margin_)
16159 {
16160   if (G_LIKELY (margin_ != NULL))
16161     return g_slice_dup (ClutterMargin, margin_);
16162
16163   return NULL;
16164 }
16165
16166 /**
16167  * clutter_margin_free:
16168  * @margin_: a #ClutterMargin
16169  *
16170  * Frees the resources allocated by clutter_margin_new() and
16171  * clutter_margin_copy().
16172  *
16173  * Since: 1.10
16174  */
16175 void
16176 clutter_margin_free (ClutterMargin *margin_)
16177 {
16178   if (G_LIKELY (margin_ != NULL))
16179     g_slice_free (ClutterMargin, margin_);
16180 }
16181
16182 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16183                      clutter_margin_copy,
16184                      clutter_margin_free)
16185
16186 /**
16187  * clutter_actor_set_margin:
16188  * @self: a #ClutterActor
16189  * @margin: a #ClutterMargin
16190  *
16191  * Sets all the components of the margin of a #ClutterActor.
16192  *
16193  * Since: 1.10
16194  */
16195 void
16196 clutter_actor_set_margin (ClutterActor        *self,
16197                           const ClutterMargin *margin)
16198 {
16199   ClutterLayoutInfo *info;
16200   gboolean changed;
16201   GObject *obj;
16202
16203   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16204   g_return_if_fail (margin != NULL);
16205
16206   obj = G_OBJECT (self);
16207   changed = FALSE;
16208
16209   g_object_freeze_notify (obj);
16210
16211   info = _clutter_actor_get_layout_info (self);
16212
16213   if (info->margin.top != margin->top)
16214     {
16215       info->margin.top = margin->top;
16216       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16217       changed = TRUE;
16218     }
16219
16220   if (info->margin.right != margin->right)
16221     {
16222       info->margin.right = margin->right;
16223       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16224       changed = TRUE;
16225     }
16226
16227   if (info->margin.bottom != margin->bottom)
16228     {
16229       info->margin.bottom = margin->bottom;
16230       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16231       changed = TRUE;
16232     }
16233
16234   if (info->margin.left != margin->left)
16235     {
16236       info->margin.left = margin->left;
16237       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16238       changed = TRUE;
16239     }
16240
16241   if (changed)
16242     clutter_actor_queue_relayout (self);
16243
16244   g_object_thaw_notify (obj);
16245 }
16246
16247 /**
16248  * clutter_actor_get_margin:
16249  * @self: a #ClutterActor
16250  * @margin: (out caller-allocates): return location for a #ClutterMargin
16251  *
16252  * Retrieves all the components of the margin of a #ClutterActor.
16253  *
16254  * Since: 1.10
16255  */
16256 void
16257 clutter_actor_get_margin (ClutterActor  *self,
16258                           ClutterMargin *margin)
16259 {
16260   const ClutterLayoutInfo *info;
16261
16262   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16263   g_return_if_fail (margin != NULL);
16264
16265   info = _clutter_actor_get_layout_info_or_defaults (self);
16266
16267   *margin = info->margin;
16268 }
16269
16270 /**
16271  * clutter_actor_set_margin_top:
16272  * @self: a #ClutterActor
16273  * @margin: the top margin
16274  *
16275  * Sets the margin from the top of a #ClutterActor.
16276  *
16277  * Since: 1.10
16278  */
16279 void
16280 clutter_actor_set_margin_top (ClutterActor *self,
16281                               gfloat        margin)
16282 {
16283   ClutterLayoutInfo *info;
16284
16285   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16286   g_return_if_fail (margin >= 0.f);
16287
16288   info = _clutter_actor_get_layout_info (self);
16289
16290   if (info->margin.top == margin)
16291     return;
16292
16293   info->margin.top = margin;
16294
16295   clutter_actor_queue_relayout (self);
16296
16297   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16298 }
16299
16300 /**
16301  * clutter_actor_get_margin_top:
16302  * @self: a #ClutterActor
16303  *
16304  * Retrieves the top margin of a #ClutterActor.
16305  *
16306  * Return value: the top margin
16307  *
16308  * Since: 1.10
16309  */
16310 gfloat
16311 clutter_actor_get_margin_top (ClutterActor *self)
16312 {
16313   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16314
16315   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16316 }
16317
16318 /**
16319  * clutter_actor_set_margin_bottom:
16320  * @self: a #ClutterActor
16321  * @margin: the bottom margin
16322  *
16323  * Sets the margin from the bottom of a #ClutterActor.
16324  *
16325  * Since: 1.10
16326  */
16327 void
16328 clutter_actor_set_margin_bottom (ClutterActor *self,
16329                                  gfloat        margin)
16330 {
16331   ClutterLayoutInfo *info;
16332
16333   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16334   g_return_if_fail (margin >= 0.f);
16335
16336   info = _clutter_actor_get_layout_info (self);
16337
16338   if (info->margin.bottom == margin)
16339     return;
16340
16341   info->margin.bottom = margin;
16342
16343   clutter_actor_queue_relayout (self);
16344
16345   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16346 }
16347
16348 /**
16349  * clutter_actor_get_margin_bottom:
16350  * @self: a #ClutterActor
16351  *
16352  * Retrieves the bottom margin of a #ClutterActor.
16353  *
16354  * Return value: the bottom margin
16355  *
16356  * Since: 1.10
16357  */
16358 gfloat
16359 clutter_actor_get_margin_bottom (ClutterActor *self)
16360 {
16361   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16362
16363   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16364 }
16365
16366 /**
16367  * clutter_actor_set_margin_left:
16368  * @self: a #ClutterActor
16369  * @margin: the left margin
16370  *
16371  * Sets the margin from the left of a #ClutterActor.
16372  *
16373  * Since: 1.10
16374  */
16375 void
16376 clutter_actor_set_margin_left (ClutterActor *self,
16377                                gfloat        margin)
16378 {
16379   ClutterLayoutInfo *info;
16380
16381   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16382   g_return_if_fail (margin >= 0.f);
16383
16384   info = _clutter_actor_get_layout_info (self);
16385
16386   if (info->margin.left == margin)
16387     return;
16388
16389   info->margin.left = margin;
16390
16391   clutter_actor_queue_relayout (self);
16392
16393   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16394 }
16395
16396 /**
16397  * clutter_actor_get_margin_left:
16398  * @self: a #ClutterActor
16399  *
16400  * Retrieves the left margin of a #ClutterActor.
16401  *
16402  * Return value: the left margin
16403  *
16404  * Since: 1.10
16405  */
16406 gfloat
16407 clutter_actor_get_margin_left (ClutterActor *self)
16408 {
16409   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16410
16411   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16412 }
16413
16414 /**
16415  * clutter_actor_set_margin_right:
16416  * @self: a #ClutterActor
16417  * @margin: the right margin
16418  *
16419  * Sets the margin from the right of a #ClutterActor.
16420  *
16421  * Since: 1.10
16422  */
16423 void
16424 clutter_actor_set_margin_right (ClutterActor *self,
16425                                 gfloat        margin)
16426 {
16427   ClutterLayoutInfo *info;
16428
16429   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16430   g_return_if_fail (margin >= 0.f);
16431
16432   info = _clutter_actor_get_layout_info (self);
16433
16434   if (info->margin.right == margin)
16435     return;
16436
16437   info->margin.right = margin;
16438
16439   clutter_actor_queue_relayout (self);
16440
16441   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16442 }
16443
16444 /**
16445  * clutter_actor_get_margin_right:
16446  * @self: a #ClutterActor
16447  *
16448  * Retrieves the right margin of a #ClutterActor.
16449  *
16450  * Return value: the right margin
16451  *
16452  * Since: 1.10
16453  */
16454 gfloat
16455 clutter_actor_get_margin_right (ClutterActor *self)
16456 {
16457   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16458
16459   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16460 }
16461
16462 static inline void
16463 clutter_actor_set_background_color_internal (ClutterActor *self,
16464                                              const ClutterColor *color)
16465 {
16466   ClutterActorPrivate *priv = self->priv;
16467   GObject *obj;
16468
16469   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16470     return;
16471
16472   obj = G_OBJECT (self);
16473
16474   priv->bg_color = *color;
16475   priv->bg_color_set = TRUE;
16476
16477   clutter_actor_queue_redraw (self);
16478
16479   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16480   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16481 }
16482
16483 /**
16484  * clutter_actor_set_background_color:
16485  * @self: a #ClutterActor
16486  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16487  *  set color
16488  *
16489  * Sets the background color of a #ClutterActor.
16490  *
16491  * The background color will be used to cover the whole allocation of the
16492  * actor. The default background color of an actor is transparent.
16493  *
16494  * To check whether an actor has a background color, you can use the
16495  * #ClutterActor:background-color-set actor property.
16496  *
16497  * The #ClutterActor:background-color property is animatable.
16498  *
16499  * Since: 1.10
16500  */
16501 void
16502 clutter_actor_set_background_color (ClutterActor       *self,
16503                                     const ClutterColor *color)
16504 {
16505   ClutterActorPrivate *priv;
16506   GObject *obj;
16507   GParamSpec *bg_color_pspec;
16508
16509   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16510
16511   obj = G_OBJECT (self);
16512
16513   priv = self->priv;
16514
16515   if (color == NULL)
16516     {
16517       priv->bg_color_set = FALSE;
16518       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16519       clutter_actor_queue_redraw (self);
16520       return;
16521     }
16522
16523   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16524   if (clutter_actor_get_easing_duration (self) != 0)
16525     {
16526       ClutterTransition *transition;
16527
16528       transition = _clutter_actor_get_transition (self, bg_color_pspec);
16529       if (transition == NULL)
16530         {
16531           transition = _clutter_actor_create_transition (self, bg_color_pspec,
16532                                                          &priv->bg_color,
16533                                                          color);
16534         }
16535       else
16536         _clutter_actor_update_transition (self, bg_color_pspec, color);
16537
16538       clutter_actor_queue_redraw (self);
16539     }
16540   else
16541     clutter_actor_set_background_color_internal (self, color);
16542 }
16543
16544 /**
16545  * clutter_actor_get_background_color:
16546  * @self: a #ClutterActor
16547  * @color: (out caller-allocates): return location for a #ClutterColor
16548  *
16549  * Retrieves the color set using clutter_actor_set_background_color().
16550  *
16551  * Since: 1.10
16552  */
16553 void
16554 clutter_actor_get_background_color (ClutterActor *self,
16555                                     ClutterColor *color)
16556 {
16557   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16558   g_return_if_fail (color != NULL);
16559
16560   *color = self->priv->bg_color;
16561 }
16562
16563 /**
16564  * clutter_actor_get_previous_sibling:
16565  * @self: a #ClutterActor
16566  *
16567  * Retrieves the sibling of @self that comes before it in the list
16568  * of children of @self's parent.
16569  *
16570  * The returned pointer is only valid until the scene graph changes; it
16571  * is not safe to modify the list of children of @self while iterating
16572  * it.
16573  *
16574  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16575  *
16576  * Since: 1.10
16577  */
16578 ClutterActor *
16579 clutter_actor_get_previous_sibling (ClutterActor *self)
16580 {
16581   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16582
16583   return self->priv->prev_sibling;
16584 }
16585
16586 /**
16587  * clutter_actor_get_next_sibling:
16588  * @self: a #ClutterActor
16589  *
16590  * Retrieves the sibling of @self that comes after it in the list
16591  * of children of @self's parent.
16592  *
16593  * The returned pointer is only valid until the scene graph changes; it
16594  * is not safe to modify the list of children of @self while iterating
16595  * it.
16596  *
16597  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16598  *
16599  * Since: 1.10
16600  */
16601 ClutterActor *
16602 clutter_actor_get_next_sibling (ClutterActor *self)
16603 {
16604   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16605
16606   return self->priv->next_sibling;
16607 }
16608
16609 /**
16610  * clutter_actor_get_first_child:
16611  * @self: a #ClutterActor
16612  *
16613  * Retrieves the first child of @self.
16614  *
16615  * The returned pointer is only valid until the scene graph changes; it
16616  * is not safe to modify the list of children of @self while iterating
16617  * it.
16618  *
16619  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16620  *
16621  * Since: 1.10
16622  */
16623 ClutterActor *
16624 clutter_actor_get_first_child (ClutterActor *self)
16625 {
16626   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16627
16628   return self->priv->first_child;
16629 }
16630
16631 /**
16632  * clutter_actor_get_last_child:
16633  * @self: a #ClutterActor
16634  *
16635  * Retrieves the last child of @self.
16636  *
16637  * The returned pointer is only valid until the scene graph changes; it
16638  * is not safe to modify the list of children of @self while iterating
16639  * it.
16640  *
16641  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16642  *
16643  * Since: 1.10
16644  */
16645 ClutterActor *
16646 clutter_actor_get_last_child (ClutterActor *self)
16647 {
16648   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16649
16650   return self->priv->last_child;
16651 }
16652
16653 /* easy way to have properly named fields instead of the dummy ones
16654  * we use in the public structure
16655  */
16656 typedef struct _RealActorIter
16657 {
16658   ClutterActor *root;           /* dummy1 */
16659   ClutterActor *current;        /* dummy2 */
16660   gpointer padding_1;           /* dummy3 */
16661   gint age;                     /* dummy4 */
16662   gpointer padding_2;           /* dummy5 */
16663 } RealActorIter;
16664
16665 /**
16666  * clutter_actor_iter_init:
16667  * @iter: a #ClutterActorIter
16668  * @root: a #ClutterActor
16669  *
16670  * Initializes a #ClutterActorIter, which can then be used to iterate
16671  * efficiently over a section of the scene graph, and associates it
16672  * with @root.
16673  *
16674  * Modifying the scene graph section that contains @root will invalidate
16675  * the iterator.
16676  *
16677  * |[
16678  *   ClutterActorIter iter;
16679  *   ClutterActor *child;
16680  *
16681  *   clutter_actor_iter_init (&iter, container);
16682  *   while (clutter_actor_iter_next (&iter, &child))
16683  *     {
16684  *       /&ast; do something with child &ast;/
16685  *     }
16686  * ]|
16687  *
16688  * Since: 1.10
16689  */
16690 void
16691 clutter_actor_iter_init (ClutterActorIter *iter,
16692                          ClutterActor     *root)
16693 {
16694   RealActorIter *ri = (RealActorIter *) iter;
16695
16696   g_return_if_fail (iter != NULL);
16697   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16698
16699   ri->root = root;
16700   ri->current = NULL;
16701   ri->age = root->priv->age;
16702 }
16703
16704 /**
16705  * clutter_actor_iter_next:
16706  * @iter: a #ClutterActorIter
16707  * @child: (out): return location for a #ClutterActor
16708  *
16709  * Advances the @iter and retrieves the next child of the root #ClutterActor
16710  * that was used to initialize the #ClutterActorIterator.
16711  *
16712  * If the iterator can advance, this function returns %TRUE and sets the
16713  * @child argument.
16714  *
16715  * If the iterator cannot advance, this function returns %FALSE, and
16716  * the contents of @child are undefined.
16717  *
16718  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16719  *
16720  * Since: 1.10
16721  */
16722 gboolean
16723 clutter_actor_iter_next (ClutterActorIter  *iter,
16724                          ClutterActor     **child)
16725 {
16726   RealActorIter *ri = (RealActorIter *) iter;
16727
16728   g_return_val_if_fail (iter != NULL, FALSE);
16729   g_return_val_if_fail (ri->root != NULL, FALSE);
16730 #ifndef G_DISABLE_ASSERT
16731   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16732 #endif
16733
16734   if (ri->current == NULL)
16735     ri->current = ri->root->priv->first_child;
16736   else
16737     ri->current = ri->current->priv->next_sibling;
16738
16739   if (child != NULL)
16740     *child = ri->current;
16741
16742   return ri->current != NULL;
16743 }
16744
16745 /**
16746  * clutter_actor_iter_prev:
16747  * @iter: a #ClutterActorIter
16748  * @child: (out): return location for a #ClutterActor
16749  *
16750  * Advances the @iter and retrieves the previous child of the root
16751  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16752  *
16753  * If the iterator can advance, this function returns %TRUE and sets the
16754  * @child argument.
16755  *
16756  * If the iterator cannot advance, this function returns %FALSE, and
16757  * the contents of @child are undefined.
16758  *
16759  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16760  *
16761  * Since: 1.10
16762  */
16763 gboolean
16764 clutter_actor_iter_prev (ClutterActorIter  *iter,
16765                          ClutterActor     **child)
16766 {
16767   RealActorIter *ri = (RealActorIter *) iter;
16768
16769   g_return_val_if_fail (iter != NULL, FALSE);
16770   g_return_val_if_fail (ri->root != NULL, FALSE);
16771 #ifndef G_DISABLE_ASSERT
16772   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16773 #endif
16774
16775   if (ri->current == NULL)
16776     ri->current = ri->root->priv->last_child;
16777   else
16778     ri->current = ri->current->priv->prev_sibling;
16779
16780   if (child != NULL)
16781     *child = ri->current;
16782
16783   return ri->current != NULL;
16784 }
16785
16786 /**
16787  * clutter_actor_iter_remove:
16788  * @iter: a #ClutterActorIter
16789  *
16790  * Safely removes the #ClutterActor currently pointer to by the iterator
16791  * from its parent.
16792  *
16793  * This function can only be called after clutter_actor_iter_next() or
16794  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16795  * than once for the same actor.
16796  *
16797  * This function will call clutter_actor_remove_child() internally.
16798  *
16799  * Since: 1.10
16800  */
16801 void
16802 clutter_actor_iter_remove (ClutterActorIter *iter)
16803 {
16804   RealActorIter *ri = (RealActorIter *) iter;
16805   ClutterActor *cur;
16806
16807   g_return_if_fail (iter != NULL);
16808   g_return_if_fail (ri->root != NULL);
16809 #ifndef G_DISABLE_ASSERT
16810   g_return_if_fail (ri->age == ri->root->priv->age);
16811 #endif
16812   g_return_if_fail (ri->current != NULL);
16813
16814   cur = ri->current;
16815
16816   if (cur != NULL)
16817     {
16818       ri->current = cur->priv->prev_sibling;
16819
16820       clutter_actor_remove_child_internal (ri->root, cur,
16821                                            REMOVE_CHILD_DEFAULT_FLAGS);
16822
16823       ri->age += 1;
16824     }
16825 }
16826
16827 /**
16828  * clutter_actor_iter_destroy:
16829  * @iter: a #ClutterActorIter
16830  *
16831  * Safely destroys the #ClutterActor currently pointer to by the iterator
16832  * from its parent.
16833  *
16834  * This function can only be called after clutter_actor_iter_next() or
16835  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16836  * than once for the same actor.
16837  *
16838  * This function will call clutter_actor_destroy() internally.
16839  *
16840  * Since: 1.10
16841  */
16842 void
16843 clutter_actor_iter_destroy (ClutterActorIter *iter)
16844 {
16845   RealActorIter *ri = (RealActorIter *) iter;
16846   ClutterActor *cur;
16847
16848   g_return_if_fail (iter != NULL);
16849   g_return_if_fail (ri->root != NULL);
16850 #ifndef G_DISABLE_ASSERT
16851   g_return_if_fail (ri->age == ri->root->priv->age);
16852 #endif
16853   g_return_if_fail (ri->current != NULL);
16854
16855   cur = ri->current;
16856
16857   if (cur != NULL)
16858     {
16859       ri->current = cur->priv->prev_sibling;
16860
16861       clutter_actor_destroy (cur);
16862
16863       ri->age += 1;
16864     }
16865 }
16866
16867 static const ClutterAnimationInfo default_animation_info = {
16868   NULL,         /* transitions */
16869   NULL,         /* states */
16870   NULL,         /* cur_state */
16871 };
16872
16873 static void
16874 clutter_animation_info_free (gpointer data)
16875 {
16876   if (data != NULL)
16877     {
16878       ClutterAnimationInfo *info = data;
16879
16880       if (info->transitions != NULL)
16881         g_hash_table_unref (info->transitions);
16882
16883       if (info->states != NULL)
16884         g_array_unref (info->states);
16885
16886       g_slice_free (ClutterAnimationInfo, info);
16887     }
16888 }
16889
16890 const ClutterAnimationInfo *
16891 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16892 {
16893   const ClutterAnimationInfo *res;
16894   GObject *obj = G_OBJECT (self);
16895
16896   res = g_object_get_qdata (obj, quark_actor_animation_info);
16897   if (res != NULL)
16898     return res;
16899
16900   return &default_animation_info;
16901 }
16902
16903 ClutterAnimationInfo *
16904 _clutter_actor_get_animation_info (ClutterActor *self)
16905 {
16906   GObject *obj = G_OBJECT (self);
16907   ClutterAnimationInfo *res;
16908
16909   res = g_object_get_qdata (obj, quark_actor_animation_info);
16910   if (res == NULL)
16911     {
16912       res = g_slice_new (ClutterAnimationInfo);
16913
16914       *res = default_animation_info;
16915
16916       g_object_set_qdata_full (obj, quark_actor_animation_info,
16917                                res,
16918                                clutter_animation_info_free);
16919     }
16920
16921   return res;
16922 }
16923
16924 ClutterTransition *
16925 _clutter_actor_get_transition (ClutterActor *actor,
16926                                GParamSpec   *pspec)
16927 {
16928   const ClutterAnimationInfo *info;
16929
16930   info = _clutter_actor_get_animation_info_or_defaults (actor);
16931
16932   if (info->transitions == NULL)
16933     return NULL;
16934
16935   return g_hash_table_lookup (info->transitions, pspec->name);
16936 }
16937
16938 typedef struct _TransitionClosure
16939 {
16940   ClutterActor *actor;
16941   ClutterTransition *transition;
16942   gchar *name;
16943   gulong completed_id;
16944 } TransitionClosure;
16945
16946 static void
16947 transition_closure_free (gpointer data)
16948 {
16949   if (G_LIKELY (data != NULL))
16950     {
16951       TransitionClosure *clos = data;
16952
16953       if (clutter_timeline_is_playing (CLUTTER_TIMELINE (clos->transition)))
16954         clutter_timeline_stop (CLUTTER_TIMELINE (clos->transition));
16955
16956       g_signal_handler_disconnect (clos->transition, clos->completed_id);
16957
16958       g_object_unref (clos->transition);
16959       g_free (clos->name);
16960
16961       g_slice_free (TransitionClosure, clos);
16962     }
16963 }
16964
16965 static void
16966 on_transition_completed (ClutterTransition *transition,
16967                          TransitionClosure *clos)
16968 {
16969   ClutterActor *actor = clos->actor;
16970   ClutterAnimationInfo *info;
16971
16972   info = _clutter_actor_get_animation_info (actor);
16973
16974   /* this will take care of cleaning clos for us */
16975   if (clutter_transition_get_remove_on_complete (transition))
16976     {
16977       /* we take a reference here because removing the closure
16978        * will release the reference on the transition, and we
16979        * want the transition to survive the signal emission;
16980        * the master clock will release the laste reference at
16981        * the end of the frame processing.
16982        */
16983       g_object_ref (transition);
16984       g_hash_table_remove (info->transitions, clos->name);
16985     }
16986
16987   /* if it's the last transition then we clean up */
16988   if (g_hash_table_size (info->transitions) == 0)
16989     {
16990       g_hash_table_unref (info->transitions);
16991       info->transitions = NULL;
16992
16993       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
16994                     _clutter_actor_get_debug_name (actor));
16995
16996       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
16997     }
16998 }
16999
17000 void
17001 _clutter_actor_update_transition (ClutterActor *actor,
17002                                   GParamSpec   *pspec,
17003                                   ...)
17004 {
17005   TransitionClosure *clos;
17006   ClutterInterval *interval;
17007   const ClutterAnimationInfo *info;
17008   va_list var_args;
17009   GType ptype;
17010   GValue initial = G_VALUE_INIT;
17011   GValue final = G_VALUE_INIT;
17012   char *error = NULL;
17013
17014   info = _clutter_actor_get_animation_info_or_defaults (actor);
17015
17016   if (info->transitions == NULL)
17017     return;
17018
17019   clos = g_hash_table_lookup (info->transitions, pspec->name);
17020   if (clos == NULL)
17021     return;
17022
17023   va_start (var_args, pspec);
17024
17025   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17026
17027   g_value_init (&initial, ptype);
17028   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17029                                         pspec->name,
17030                                         &initial);
17031
17032   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17033   if (error != NULL)
17034     {
17035       g_critical ("%s: %s", G_STRLOC, error);
17036       g_free (error);
17037       goto out;
17038     }
17039
17040   interval = clutter_transition_get_interval (clos->transition);
17041   clutter_interval_set_initial_value (interval, &initial);
17042   clutter_interval_set_final_value (interval, &final);
17043
17044   clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
17045
17046 out:
17047   g_value_unset (&initial);
17048   g_value_unset (&final);
17049
17050   va_end (var_args);
17051 }
17052
17053 /*< private >*
17054  * _clutter_actor_create_transition:
17055  * @actor: a #ClutterActor
17056  * @pspec: the property used for the transition
17057  * @...: initial and final state
17058  *
17059  * Creates a #ClutterTransition for the property represented by @pspec.
17060  *
17061  * Return value: a #ClutterTransition
17062  */
17063 ClutterTransition *
17064 _clutter_actor_create_transition (ClutterActor *actor,
17065                                   GParamSpec   *pspec,
17066                                   ...)
17067 {
17068   ClutterAnimationInfo *info;
17069   ClutterTransition *res = NULL;
17070   gboolean call_restore = FALSE;
17071   TransitionClosure *clos;
17072   va_list var_args;
17073
17074   info = _clutter_actor_get_animation_info (actor);
17075
17076   if (info->states == NULL)
17077     {
17078       clutter_actor_save_easing_state (actor);
17079       call_restore = TRUE;
17080     }
17081
17082   if (info->transitions == NULL)
17083     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17084                                                NULL,
17085                                                transition_closure_free);
17086
17087   va_start (var_args, pspec);
17088
17089   clos = g_hash_table_lookup (info->transitions, pspec->name);
17090   if (clos == NULL)
17091     {
17092       ClutterInterval *interval;
17093       GValue initial = G_VALUE_INIT;
17094       GValue final = G_VALUE_INIT;
17095       GType ptype;
17096       char *error;
17097
17098       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17099
17100       G_VALUE_COLLECT_INIT (&initial, ptype,
17101                             var_args, 0,
17102                             &error);
17103       if (error != NULL)
17104         {
17105           g_critical ("%s: %s", G_STRLOC, error);
17106           g_free (error);
17107           goto out;
17108         }
17109
17110       G_VALUE_COLLECT_INIT (&final, ptype,
17111                             var_args, 0,
17112                             &error);
17113
17114       if (error != NULL)
17115         {
17116           g_critical ("%s: %s", G_STRLOC, error);
17117           g_value_unset (&initial);
17118           g_free (error);
17119           goto out;
17120         }
17121
17122       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17123
17124       g_value_unset (&initial);
17125       g_value_unset (&final);
17126
17127       res = clutter_property_transition_new (pspec->name);
17128
17129       clutter_transition_set_interval (res, interval);
17130       clutter_transition_set_remove_on_complete (res, TRUE);
17131
17132       /* this will start the transition as well */
17133       clutter_actor_add_transition (actor, pspec->name, res);
17134
17135       /* the actor now owns the transition */
17136       g_object_unref (res);
17137     }
17138   else
17139     res = clos->transition;
17140
17141 out:
17142   if (call_restore)
17143     clutter_actor_restore_easing_state (actor);
17144
17145   va_end (var_args);
17146
17147   return res;
17148 }
17149
17150 /**
17151  * clutter_actor_add_transition:
17152  * @self: a #ClutterActor
17153  * @name: the name of the transition to add
17154  * @transition: the #ClutterTransition to add
17155  *
17156  * Adds a @transition to the #ClutterActor's list of animations.
17157  *
17158  * The @name string is a per-actor unique identifier of the @transition: only
17159  * one #ClutterTransition can be associated to the specified @name.
17160  *
17161  * The @transition will be given the easing duration, mode, and delay
17162  * associated to the actor's current easing state; it is possible to modify
17163  * these values after calling clutter_actor_add_transition().
17164  *
17165  * The @transition will be started once added.
17166  *
17167  * This function will take a reference on the @transition.
17168  *
17169  * This function is usually called implicitly when modifying an animatable
17170  * property.
17171  *
17172  * Since: 1.10
17173  */
17174 void
17175 clutter_actor_add_transition (ClutterActor      *self,
17176                               const char        *name,
17177                               ClutterTransition *transition)
17178 {
17179   ClutterTimeline *timeline;
17180   TransitionClosure *clos;
17181   ClutterAnimationInfo *info;
17182
17183   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17184   g_return_if_fail (name != NULL);
17185   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17186
17187   info = _clutter_actor_get_animation_info (self);
17188
17189   if (info->cur_state == NULL)
17190     {
17191       g_warning ("No easing state is defined for the actor '%s'; you "
17192                  "must call clutter_actor_save_easing_state() before "
17193                  "calling clutter_actor_add_transition().",
17194                  _clutter_actor_get_debug_name (self));
17195       return;
17196     }
17197
17198   if (info->transitions == NULL)
17199     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17200                                                NULL,
17201                                                transition_closure_free);
17202
17203   if (g_hash_table_lookup (info->transitions, name) != NULL)
17204     {
17205       g_warning ("A transition with name '%s' already exists for "
17206                  "the actor '%s'",
17207                  name,
17208                  _clutter_actor_get_debug_name (self));
17209       return;
17210     }
17211
17212   clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17213
17214   timeline = CLUTTER_TIMELINE (transition);
17215
17216   clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17217   clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17218   clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17219
17220   clos = g_slice_new (TransitionClosure);
17221   clos->actor = self;
17222   clos->transition = g_object_ref (transition);
17223   clos->name = g_strdup (name);
17224   clos->completed_id = g_signal_connect (timeline, "completed",
17225                                          G_CALLBACK (on_transition_completed),
17226                                          clos);
17227
17228   g_hash_table_insert (info->transitions, clos->name, clos);
17229   clutter_timeline_start (timeline);
17230 }
17231
17232 /**
17233  * clutter_actor_remove_transition:
17234  * @self: a #ClutterActor
17235  * @name: the name of the transition to remove
17236  *
17237  * Removes the transition stored inside a #ClutterActor using @name
17238  * identifier.
17239  *
17240  * If the transition is currently in progress, it will be stopped.
17241  *
17242  * This function releases the reference acquired when the transition
17243  * was added to the #ClutterActor.
17244  *
17245  * Since: 1.10
17246  */
17247 void
17248 clutter_actor_remove_transition (ClutterActor *self,
17249                                  const char   *name)
17250 {
17251   const ClutterAnimationInfo *info;
17252
17253   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17254   g_return_if_fail (name != NULL);
17255
17256   info = _clutter_actor_get_animation_info_or_defaults (self);
17257
17258   if (info->transitions == NULL)
17259     return;
17260
17261   g_hash_table_remove (info->transitions, name);
17262 }
17263
17264 /**
17265  * clutter_actor_remove_all_transitions:
17266  * @self: a #ClutterActor
17267  *
17268  * Removes all transitions associated to @self.
17269  *
17270  * Since: 1.10
17271  */
17272 void
17273 clutter_actor_remove_all_transitions (ClutterActor *self)
17274 {
17275   const ClutterAnimationInfo *info;
17276
17277   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17278
17279   info = _clutter_actor_get_animation_info_or_defaults (self);
17280   if (info->transitions == NULL)
17281     return;
17282
17283   g_hash_table_remove_all (info->transitions);
17284 }
17285
17286 /**
17287  * clutter_actor_set_easing_duration:
17288  * @self: a #ClutterActor
17289  * @msecs: the duration of the easing, or %NULL
17290  *
17291  * Sets the duration of the tweening for animatable properties
17292  * of @self for the current easing state.
17293  *
17294  * Since: 1.10
17295  */
17296 void
17297 clutter_actor_set_easing_duration (ClutterActor *self,
17298                                    guint         msecs)
17299 {
17300   ClutterAnimationInfo *info;
17301
17302   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17303
17304   info = _clutter_actor_get_animation_info (self);
17305
17306   if (info->cur_state == NULL)
17307     {
17308       g_warning ("You must call clutter_actor_save_easing_state() prior "
17309                  "to calling clutter_actor_set_easing_duration().");
17310       return;
17311     }
17312
17313   if (info->cur_state->easing_duration != msecs)
17314     info->cur_state->easing_duration = msecs;
17315 }
17316
17317 /**
17318  * clutter_actor_get_easing_duration:
17319  * @self: a #ClutterActor
17320  *
17321  * Retrieves the duration of the tweening for animatable
17322  * properties of @self for the current easing state.
17323  *
17324  * Return value: the duration of the tweening, in milliseconds
17325  *
17326  * Since: 1.10
17327  */
17328 guint
17329 clutter_actor_get_easing_duration (ClutterActor *self)
17330 {
17331   const ClutterAnimationInfo *info;
17332
17333   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17334
17335   info = _clutter_actor_get_animation_info_or_defaults (self);
17336
17337   if (info->cur_state != NULL)
17338     return info->cur_state->easing_duration;
17339
17340   return 0;
17341 }
17342
17343 /**
17344  * clutter_actor_set_easing_mode:
17345  * @self: a #ClutterActor
17346  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17347  *
17348  * Sets the easing mode for the tweening of animatable properties
17349  * of @self.
17350  *
17351  * Since: 1.10
17352  */
17353 void
17354 clutter_actor_set_easing_mode (ClutterActor         *self,
17355                                ClutterAnimationMode  mode)
17356 {
17357   ClutterAnimationInfo *info;
17358
17359   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17360   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17361   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17362
17363   info = _clutter_actor_get_animation_info (self);
17364
17365   if (info->cur_state == NULL)
17366     {
17367       g_warning ("You must call clutter_actor_save_easing_state() prior "
17368                  "to calling clutter_actor_set_easing_mode().");
17369       return;
17370     }
17371
17372   if (info->cur_state->easing_mode != mode)
17373     info->cur_state->easing_mode = mode;
17374 }
17375
17376 /**
17377  * clutter_actor_get_easing_mode:
17378  * @self: a #ClutterActor
17379  *
17380  * Retrieves the easing mode for the tweening of animatable properties
17381  * of @self for the current easing state.
17382  *
17383  * Return value: an easing mode
17384  *
17385  * Since: 1.10
17386  */
17387 ClutterAnimationMode
17388 clutter_actor_get_easing_mode (ClutterActor *self)
17389 {
17390   const ClutterAnimationInfo *info;
17391
17392   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17393
17394   info = _clutter_actor_get_animation_info_or_defaults (self);
17395
17396   if (info->cur_state != NULL)
17397     return info->cur_state->easing_mode;
17398
17399   return CLUTTER_EASE_OUT_CUBIC;
17400 }
17401
17402 /**
17403  * clutter_actor_set_easing_delay:
17404  * @self: a #ClutterActor
17405  * @msecs: the delay before the start of the tweening, in milliseconds
17406  *
17407  * Sets the delay that should be applied before tweening animatable
17408  * properties.
17409  *
17410  * Since: 1.10
17411  */
17412 void
17413 clutter_actor_set_easing_delay (ClutterActor *self,
17414                                 guint         msecs)
17415 {
17416   ClutterAnimationInfo *info;
17417
17418   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17419
17420   info = _clutter_actor_get_animation_info (self);
17421
17422   if (info->cur_state == NULL)
17423     {
17424       g_warning ("You must call clutter_actor_save_easing_state() prior "
17425                  "to calling clutter_actor_set_easing_delay().");
17426       return;
17427     }
17428
17429   if (info->cur_state->easing_delay != msecs)
17430     info->cur_state->easing_delay = msecs;
17431 }
17432
17433 /**
17434  * clutter_actor_get_easing_delay:
17435  * @self: a #ClutterActor
17436  *
17437  * Retrieves the delay that should be applied when tweening animatable
17438  * properties.
17439  *
17440  * Return value: a delay, in milliseconds
17441  *
17442  * Since: 1.10
17443  */
17444 guint
17445 clutter_actor_get_easing_delay (ClutterActor *self)
17446 {
17447   const ClutterAnimationInfo *info;
17448
17449   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17450
17451   info = _clutter_actor_get_animation_info_or_defaults (self);
17452
17453   if (info->cur_state != NULL)
17454     return info->cur_state->easing_delay;
17455
17456   return 0;
17457 }
17458
17459 /**
17460  * clutter_actor_get_transition:
17461  * @self: a #ClutterActor
17462  * @name: the name of the transition
17463  *
17464  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17465  * transition @name.
17466  *
17467  * Transitions created for animatable properties use the name of the
17468  * property itself, for instance the code below:
17469  *
17470  * |[
17471  *   clutter_actor_set_easing_duration (actor, 1000);
17472  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17473  *
17474  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17475  *   g_signal_connect (transition, "completed",
17476  *                     G_CALLBACK (on_transition_complete),
17477  *                     actor);
17478  * ]|
17479  *
17480  * will call the <function>on_transition_complete</function> callback when
17481  * the transition is complete.
17482  *
17483  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17484  *   was found to match the passed name; the returned instance is owned
17485  *   by Clutter and it should not be freed
17486  *
17487  * Since: 1.10
17488  */
17489 ClutterTransition *
17490 clutter_actor_get_transition (ClutterActor *self,
17491                               const char   *name)
17492 {
17493   TransitionClosure *clos;
17494   const ClutterAnimationInfo *info;
17495
17496   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17497   g_return_val_if_fail (name != NULL, NULL);
17498
17499   info = _clutter_actor_get_animation_info_or_defaults (self);
17500
17501   if (info->transitions == NULL)
17502     return NULL;
17503
17504   clos = g_hash_table_lookup (info->transitions, name);
17505   if (clos == NULL)
17506     return NULL;
17507
17508   return clos->transition;
17509 }
17510
17511 /**
17512  * clutter_actor_save_easing_state:
17513  * @self: a #ClutterActor
17514  *
17515  * Saves the current easing state for animatable properties, and creates
17516  * a new state with the default values for easing mode and duration.
17517  *
17518  * Since: 1.10
17519  */
17520 void
17521 clutter_actor_save_easing_state (ClutterActor *self)
17522 {
17523   ClutterAnimationInfo *info;
17524   AState new_state;
17525
17526   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17527
17528   info = _clutter_actor_get_animation_info (self);
17529
17530   if (info->states == NULL)
17531     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17532
17533   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17534   new_state.easing_duration = 250;
17535   new_state.easing_delay = 0;
17536
17537   g_array_append_val (info->states, new_state);
17538
17539   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17540 }
17541
17542 /**
17543  * clutter_actor_restore_easing_state:
17544  * @self: a #ClutterActor
17545  *
17546  * Restores the easing state as it was prior to a call to
17547  * clutter_actor_save_easing_state().
17548  *
17549  * Since: 1.10
17550  */
17551 void
17552 clutter_actor_restore_easing_state (ClutterActor *self)
17553 {
17554   ClutterAnimationInfo *info;
17555
17556   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17557
17558   info = _clutter_actor_get_animation_info (self);
17559
17560   if (info->states == NULL)
17561     {
17562       g_critical ("The function clutter_actor_restore_easing_state() has "
17563                   "called without a previous call to "
17564                   "clutter_actor_save_easing_state().");
17565       return;
17566     }
17567
17568   g_array_remove_index (info->states, info->states->len - 1);
17569
17570   if (info->states->len > 0)
17571     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17572   else
17573     {
17574       g_array_unref (info->states);
17575       info->states = NULL;
17576     }
17577 }
17578
17579 /**
17580  * clutter_actor_set_content:
17581  * @self: a #ClutterActor
17582  * @content: (allow-none): a #ClutterContent, or %NULL
17583  *
17584  * Sets the contents of a #ClutterActor.
17585  *
17586  * Since: 1.10
17587  */
17588 void
17589 clutter_actor_set_content (ClutterActor   *self,
17590                            ClutterContent *content)
17591 {
17592   ClutterActorPrivate *priv;
17593
17594   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17595   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17596
17597   priv = self->priv;
17598
17599   if (priv->content != NULL)
17600     {
17601       _clutter_content_detached (priv->content, self);
17602       g_clear_object (&priv->content);
17603     }
17604
17605   priv->content = content;
17606
17607   if (priv->content != NULL)
17608     {
17609       g_object_ref (priv->content);
17610       _clutter_content_attached (priv->content, self);
17611     }
17612
17613   /* given that the content is always painted within the allocation,
17614    * we only need to queue a redraw here
17615    */
17616   clutter_actor_queue_redraw (self);
17617
17618   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17619
17620   /* if the content gravity is not resize-fill, and the new content has a
17621    * different preferred size than the previous one, then the content box
17622    * may have been changed. since we compute that lazily, we just notify
17623    * here, and let whomever watches :content-box do whatever they need to
17624    * do.
17625    */
17626   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17627     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17628 }
17629
17630 /**
17631  * clutter_actor_get_content:
17632  * @self: a #ClutterActor
17633  *
17634  * Retrieves the contents of @self.
17635  *
17636  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17637  *   or %NULL if none was set
17638  *
17639  * Since: 1.10
17640  */
17641 ClutterContent *
17642 clutter_actor_get_content (ClutterActor *self)
17643 {
17644   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17645
17646   return self->priv->content;
17647 }
17648
17649 /**
17650  * clutter_actor_set_content_gravity:
17651  * @self: a #ClutterActor
17652  * @gravity: the #ClutterContentGravity
17653  *
17654  * Sets the gravity of the #ClutterContent used by @self.
17655  *
17656  * See the description of the #ClutterActor:content-gravity property for
17657  * more information.
17658  *
17659  * Since: 1.10
17660  */
17661 void
17662 clutter_actor_set_content_gravity (ClutterActor *self,
17663                                    ClutterContentGravity  gravity)
17664 {
17665   ClutterActorPrivate *priv;
17666
17667   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17668
17669   priv = self->priv;
17670
17671   if (priv->content_gravity == gravity)
17672     return;
17673
17674   priv->content_gravity = gravity;
17675
17676   clutter_actor_queue_redraw (self);
17677
17678   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17679   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17680 }
17681
17682 /**
17683  * clutter_actor_get_content_gravity:
17684  * @self: a #ClutterActor
17685  *
17686  * Retrieves the content gravity as set using
17687  * clutter_actor_get_content_gravity().
17688  *
17689  * Return value: the content gravity
17690  *
17691  * Since: 1.10
17692  */
17693 ClutterContentGravity
17694 clutter_actor_get_content_gravity (ClutterActor *self)
17695 {
17696   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17697                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17698
17699   return self->priv->content_gravity;
17700 }
17701
17702 /**
17703  * clutter_actor_get_content_box:
17704  * @self: a #ClutterActor
17705  * @box: (out caller-allocates): the return location for the bounding
17706  *   box for the #ClutterContent
17707  *
17708  * Retrieves the bounding box for the #ClutterContent of @self.
17709  *
17710  * The bounding box is relative to the actor's allocation.
17711  *
17712  * If no #ClutterContent is set for @self, or if @self has not been
17713  * allocated yet, then the result is undefined.
17714  *
17715  * The content box is guaranteed to be, at most, as big as the allocation
17716  * of the #ClutterActor.
17717  *
17718  * If the #ClutterContent used by the actor has a preferred size, then
17719  * it is possible to modify the content box by using the
17720  * #ClutterActor:content-gravity property.
17721  *
17722  * Since: 1.10
17723  */
17724 void
17725 clutter_actor_get_content_box (ClutterActor    *self,
17726                                ClutterActorBox *box)
17727 {
17728   ClutterActorPrivate *priv;
17729   gfloat content_w, content_h;
17730   gfloat alloc_w, alloc_h;
17731
17732   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17733   g_return_if_fail (box != NULL);
17734
17735   priv = self->priv;
17736
17737   box->x1 = 0.f;
17738   box->y1 = 0.f;
17739   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17740   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17741
17742   if (priv->content == NULL)
17743     return;
17744
17745   /* no need to do any more work */
17746   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17747     return;
17748
17749   /* if the content does not have a preferred size then there is
17750    * no point in computing the content box
17751    */
17752   if (!clutter_content_get_preferred_size (priv->content,
17753                                            &content_w,
17754                                            &content_h))
17755     return;
17756
17757   alloc_w = box->x2;
17758   alloc_h = box->y2;
17759
17760   switch (priv->content_gravity)
17761     {
17762     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17763       box->x2 = box->x1 + MIN (content_w, alloc_w);
17764       box->y2 = box->y1 + MIN (content_h, alloc_h);
17765       break;
17766
17767     case CLUTTER_CONTENT_GRAVITY_TOP:
17768       if (alloc_w > content_w)
17769         {
17770           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17771           box->x2 = box->x1 + content_w;
17772         }
17773       box->y2 = box->y1 + MIN (content_h, alloc_h);
17774       break;
17775
17776     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17777       if (alloc_w > content_w)
17778         {
17779           box->x1 += (alloc_w - content_w);
17780           box->x2 = box->x1 + content_w;
17781         }
17782       box->y2 = box->y1 + MIN (content_h, alloc_h);
17783       break;
17784
17785     case CLUTTER_CONTENT_GRAVITY_LEFT:
17786       box->x2 = box->x1 + MIN (content_w, alloc_w);
17787       if (alloc_h > content_h)
17788         {
17789           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17790           box->y2 = box->y1 + content_h;
17791         }
17792       break;
17793
17794     case CLUTTER_CONTENT_GRAVITY_CENTER:
17795       if (alloc_w > content_w)
17796         {
17797           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17798           box->x2 = box->x1 + content_w;
17799         }
17800       if (alloc_h > content_h)
17801         {
17802           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17803           box->y2 = box->y1 + content_h;
17804         }
17805       break;
17806
17807     case CLUTTER_CONTENT_GRAVITY_RIGHT:
17808       if (alloc_w > content_w)
17809         {
17810           box->x1 += (alloc_w - content_w);
17811           box->x2 = box->x1 + content_w;
17812         }
17813       if (alloc_h > content_h)
17814         {
17815           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17816           box->y2 = box->y1 + content_h;
17817         }
17818       break;
17819
17820     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17821       box->x2 = box->x1 + MIN (content_w, alloc_w);
17822       if (alloc_h > content_h)
17823         {
17824           box->y1 += (alloc_h - content_h);
17825           box->y2 = box->y1 + content_h;
17826         }
17827       break;
17828
17829     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17830       if (alloc_w > content_w)
17831         {
17832           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17833           box->x2 = box->x1 + content_w;
17834         }
17835       if (alloc_h > content_h)
17836         {
17837           box->y1 += (alloc_h - content_h);
17838           box->y2 = box->y1 + content_h;
17839         }
17840       break;
17841
17842     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17843       if (alloc_w > content_w)
17844         {
17845           box->x1 += (alloc_w - content_w);
17846           box->x2 = box->x1 + content_w;
17847         }
17848       if (alloc_h > content_h)
17849         {
17850           box->y1 += (alloc_h - content_h);
17851           box->y2 = box->y1 + content_h;
17852         }
17853       break;
17854
17855     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17856       g_assert_not_reached ();
17857       break;
17858
17859     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17860       {
17861         double r_c = content_w / content_h;
17862         double r_a = alloc_w / alloc_h;
17863
17864         if (r_c >= 1.0)
17865           {
17866             if (r_a >= 1.0)
17867               {
17868                 box->x1 = 0.f;
17869                 box->x2 = alloc_w;
17870
17871                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17872                 box->y2 = box->y1 + (alloc_w * r_c);
17873               }
17874             else
17875               {
17876                 box->y1 = 0.f;
17877                 box->y2 = alloc_h;
17878
17879                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17880                 box->x2 = box->x1 + (alloc_h * r_c);
17881               }
17882           }
17883         else
17884           {
17885             if (r_a >= 1.0)
17886               {
17887                 box->y1 = 0.f;
17888                 box->y2 = alloc_h;
17889
17890                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17891                 box->x2 = box->x1 + (alloc_h * r_c);
17892               }
17893             else
17894               {
17895                 box->x1 = 0.f;
17896                 box->x2 = alloc_w;
17897
17898                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17899                 box->y2 = box->y1 + (alloc_w * r_c);
17900               }
17901           }
17902       }
17903       break;
17904     }
17905 }
17906
17907 /**
17908  * clutter_actor_set_content_scaling_filters:
17909  * @self: a #ClutterActor
17910  * @min_filter: the minification filter for the content
17911  * @mag_filter: the magnification filter for the content
17912  *
17913  * Sets the minification and magnification filter to be applied when
17914  * scaling the #ClutterActor:content of a #ClutterActor.
17915  *
17916  * The #ClutterActor:minification-filter will be used when reducing
17917  * the size of the content; the #ClutterActor:magnification-filter
17918  * will be used when increasing the size of the content.
17919  *
17920  * Since: 1.10
17921  */
17922 void
17923 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
17924                                            ClutterScalingFilter  min_filter,
17925                                            ClutterScalingFilter  mag_filter)
17926 {
17927   ClutterActorPrivate *priv;
17928   gboolean changed;
17929   GObject *obj;
17930
17931   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17932
17933   priv = self->priv;
17934   obj = G_OBJECT (self);
17935
17936   g_object_freeze_notify (obj);
17937
17938   changed = FALSE;
17939
17940   if (priv->min_filter != min_filter)
17941     {
17942       priv->min_filter = min_filter;
17943       changed = TRUE;
17944
17945       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
17946     }
17947
17948   if (priv->mag_filter != mag_filter)
17949     {
17950       priv->mag_filter = mag_filter;
17951       changed = TRUE;
17952
17953       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
17954     }
17955
17956   if (changed)
17957     clutter_actor_queue_redraw (self);
17958
17959   g_object_thaw_notify (obj);
17960 }
17961
17962 /**
17963  * clutter_actor_get_content_scaling_filters:
17964  * @self: a #ClutterActor
17965  * @min_filter: (out) (allow-none): return location for the minification
17966  *   filter, or %NULL
17967  * @mag_filter: (out) (allow-none): return location for the magnification
17968  *   filter, or %NULL
17969  *
17970  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
17971  *
17972  * Since: 1.10
17973  */
17974 void
17975 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
17976                                            ClutterScalingFilter *min_filter,
17977                                            ClutterScalingFilter *mag_filter)
17978 {
17979   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17980
17981   if (min_filter != NULL)
17982     *min_filter = self->priv->min_filter;
17983
17984   if (mag_filter != NULL)
17985     *mag_filter = self->priv->mag_filter;
17986 }