actor: Add ::transitions-completed signal
[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_object_unref (priv->flatten_effect);
3184           priv->flatten_effect = NULL;
3185         }
3186     }
3187 }
3188
3189 static void
3190 clutter_actor_real_paint (ClutterActor *actor)
3191 {
3192   ClutterActorPrivate *priv = actor->priv;
3193   ClutterActor *iter;
3194
3195   for (iter = priv->first_child;
3196        iter != NULL;
3197        iter = iter->priv->next_sibling)
3198     {
3199       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3200                     _clutter_actor_get_debug_name (iter),
3201                     _clutter_actor_get_debug_name (actor),
3202                     iter->priv->allocation.x1,
3203                     iter->priv->allocation.y1,
3204                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3205                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3206
3207       clutter_actor_paint (iter);
3208     }
3209 }
3210
3211 static gboolean
3212 clutter_actor_paint_node (ClutterActor     *actor,
3213                           ClutterPaintNode *root)
3214 {
3215   ClutterActorPrivate *priv = actor->priv;
3216
3217   if (root == NULL)
3218     return FALSE;
3219
3220   if (priv->bg_color_set &&
3221       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3222     {
3223       ClutterPaintNode *node;
3224       ClutterColor bg_color;
3225       ClutterActorBox box;
3226
3227       box.x1 = 0.f;
3228       box.y1 = 0.f;
3229       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3230       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3231
3232       bg_color = priv->bg_color;
3233       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3234                      * priv->bg_color.alpha
3235                      / 255;
3236
3237       node = clutter_color_node_new (&bg_color);
3238       clutter_paint_node_set_name (node, "backgroundColor");
3239       clutter_paint_node_add_rectangle (node, &box);
3240       clutter_paint_node_add_child (root, node);
3241       clutter_paint_node_unref (node);
3242     }
3243
3244   if (priv->content != NULL)
3245     _clutter_content_paint_content (priv->content, actor, root);
3246
3247   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3248     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3249
3250   if (clutter_paint_node_get_n_children (root) == 0)
3251     return FALSE;
3252
3253 #ifdef CLUTTER_ENABLE_DEBUG
3254   if (CLUTTER_HAS_DEBUG (PAINT))
3255     {
3256       /* dump the tree only if we have one */
3257       _clutter_paint_node_dump_tree (root);
3258     }
3259 #endif /* CLUTTER_ENABLE_DEBUG */
3260
3261   _clutter_paint_node_paint (root);
3262
3263 #if 0
3264   /* XXX: Uncomment this when we disable emitting the paint signal */
3265   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3266 #endif
3267
3268   return TRUE;
3269 }
3270
3271 /**
3272  * clutter_actor_paint:
3273  * @self: A #ClutterActor
3274  *
3275  * Renders the actor to display.
3276  *
3277  * This function should not be called directly by applications.
3278  * Call clutter_actor_queue_redraw() to queue paints, instead.
3279  *
3280  * This function is context-aware, and will either cause a
3281  * regular paint or a pick paint.
3282  *
3283  * This function will emit the #ClutterActor::paint signal or
3284  * the #ClutterActor::pick signal, depending on the context.
3285  *
3286  * This function does not paint the actor if the actor is set to 0,
3287  * unless it is performing a pick paint.
3288  */
3289 void
3290 clutter_actor_paint (ClutterActor *self)
3291 {
3292   ClutterActorPrivate *priv;
3293   ClutterPickMode pick_mode;
3294   gboolean clip_set = FALSE;
3295   gboolean shader_applied = FALSE;
3296
3297   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3298                           "Actor real-paint counter",
3299                           "Increments each time any actor is painted",
3300                           0 /* no application private data */);
3301   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3302                           "Actor pick-paint counter",
3303                           "Increments each time any actor is painted "
3304                           "for picking",
3305                           0 /* no application private data */);
3306
3307   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3308
3309   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3310     return;
3311
3312   priv = self->priv;
3313
3314   pick_mode = _clutter_context_get_pick_mode ();
3315
3316   if (pick_mode == CLUTTER_PICK_NONE)
3317     priv->propagated_one_redraw = FALSE;
3318
3319   /* It's an important optimization that we consider painting of
3320    * actors with 0 opacity to be a NOP... */
3321   if (pick_mode == CLUTTER_PICK_NONE &&
3322       /* ignore top-levels, since they might be transparent */
3323       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3324       /* Use the override opacity if its been set */
3325       ((priv->opacity_override >= 0) ?
3326        priv->opacity_override : priv->opacity) == 0)
3327     return;
3328
3329   /* if we aren't paintable (not in a toplevel with all
3330    * parents paintable) then do nothing.
3331    */
3332   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3333     return;
3334
3335   /* mark that we are in the paint process */
3336   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3337
3338   cogl_push_matrix();
3339
3340   if (priv->enable_model_view_transform)
3341     {
3342       CoglMatrix matrix;
3343
3344       /* XXX: It could be better to cache the modelview with the actor
3345        * instead of progressively building up the transformations on
3346        * the matrix stack every time we paint. */
3347       cogl_get_modelview_matrix (&matrix);
3348       _clutter_actor_apply_modelview_transform (self, &matrix);
3349
3350 #ifdef CLUTTER_ENABLE_DEBUG
3351       /* Catch when out-of-band transforms have been made by actors not as part
3352        * of an apply_transform vfunc... */
3353       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3354         {
3355           CoglMatrix expected_matrix;
3356
3357           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3358                                                              &expected_matrix);
3359
3360           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3361             {
3362               GString *buf = g_string_sized_new (1024);
3363               ClutterActor *parent;
3364
3365               parent = self;
3366               while (parent != NULL)
3367                 {
3368                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3369
3370                   if (parent->priv->parent != NULL)
3371                     g_string_append (buf, "->");
3372
3373                   parent = parent->priv->parent;
3374                 }
3375
3376               g_warning ("Unexpected transform found when painting actor "
3377                          "\"%s\". This will be caused by one of the actor's "
3378                          "ancestors (%s) using the Cogl API directly to transform "
3379                          "children instead of using ::apply_transform().",
3380                          _clutter_actor_get_debug_name (self),
3381                          buf->str);
3382
3383               g_string_free (buf, TRUE);
3384             }
3385         }
3386 #endif /* CLUTTER_ENABLE_DEBUG */
3387
3388       cogl_set_modelview_matrix (&matrix);
3389     }
3390
3391   if (priv->has_clip)
3392     {
3393       cogl_clip_push_rectangle (priv->clip.x,
3394                                 priv->clip.y,
3395                                 priv->clip.x + priv->clip.width,
3396                                 priv->clip.y + priv->clip.height);
3397       clip_set = TRUE;
3398     }
3399   else if (priv->clip_to_allocation)
3400     {
3401       gfloat width, height;
3402
3403       width  = priv->allocation.x2 - priv->allocation.x1;
3404       height = priv->allocation.y2 - priv->allocation.y1;
3405
3406       cogl_clip_push_rectangle (0, 0, width, height);
3407       clip_set = TRUE;
3408     }
3409
3410   if (pick_mode == CLUTTER_PICK_NONE)
3411     {
3412       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3413
3414       /* We check whether we need to add the flatten effect before
3415          each paint so that we can avoid having a mechanism for
3416          applications to notify when the value of the
3417          has_overlaps virtual changes. */
3418       add_or_remove_flatten_effect (self);
3419     }
3420   else
3421     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3422
3423   /* We save the current paint volume so that the next time the
3424    * actor queues a redraw we can constrain the redraw to just
3425    * cover the union of the new bounding box and the old.
3426    *
3427    * We also fetch the current paint volume to perform culling so
3428    * we can avoid painting actors outside the current clip region.
3429    *
3430    * If we are painting inside a clone, we should neither update
3431    * the paint volume or use it to cull painting, since the paint
3432    * box represents the location of the source actor on the
3433    * screen.
3434    *
3435    * XXX: We are starting to do a lot of vertex transforms on
3436    * the CPU in a typical paint, so at some point we should
3437    * audit these and consider caching some things.
3438    *
3439    * NB: We don't perform culling while picking at this point because
3440    * clutter-stage.c doesn't setup the clipping planes appropriately.
3441    *
3442    * NB: We don't want to update the last-paint-volume during picking
3443    * because the last-paint-volume is used to determine the old screen
3444    * space location of an actor that has moved so we can know the
3445    * minimal region to redraw to clear an old view of the actor. If we
3446    * update this during picking then by the time we come around to
3447    * paint then the last-paint-volume would likely represent the new
3448    * actor position not the old.
3449    */
3450   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3451     {
3452       gboolean success;
3453       /* annoyingly gcc warns if uninitialized even though
3454        * the initialization is redundant :-( */
3455       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3456
3457       if (G_LIKELY ((clutter_paint_debug_flags &
3458                      (CLUTTER_DEBUG_DISABLE_CULLING |
3459                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3460                     (CLUTTER_DEBUG_DISABLE_CULLING |
3461                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3462         _clutter_actor_update_last_paint_volume (self);
3463
3464       success = cull_actor (self, &result);
3465
3466       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3467         _clutter_actor_paint_cull_result (self, success, result);
3468       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3469         goto done;
3470     }
3471
3472   if (priv->effects == NULL)
3473     {
3474       if (pick_mode == CLUTTER_PICK_NONE &&
3475           actor_has_shader_data (self))
3476         {
3477           _clutter_actor_shader_pre_paint (self, FALSE);
3478           shader_applied = TRUE;
3479         }
3480
3481       priv->next_effect_to_paint = NULL;
3482     }
3483   else
3484     priv->next_effect_to_paint =
3485       _clutter_meta_group_peek_metas (priv->effects);
3486
3487   clutter_actor_continue_paint (self);
3488
3489   if (shader_applied)
3490     _clutter_actor_shader_post_paint (self);
3491
3492   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3493                   pick_mode == CLUTTER_PICK_NONE))
3494     _clutter_actor_draw_paint_volume (self);
3495
3496 done:
3497   /* If we make it here then the actor has run through a complete
3498      paint run including all the effects so it's no longer dirty */
3499   if (pick_mode == CLUTTER_PICK_NONE)
3500     priv->is_dirty = FALSE;
3501
3502   if (clip_set)
3503     cogl_clip_pop();
3504
3505   cogl_pop_matrix();
3506
3507   /* paint sequence complete */
3508   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3509 }
3510
3511 /**
3512  * clutter_actor_continue_paint:
3513  * @self: A #ClutterActor
3514  *
3515  * Run the next stage of the paint sequence. This function should only
3516  * be called within the implementation of the ‘run’ virtual of a
3517  * #ClutterEffect. It will cause the run method of the next effect to
3518  * be applied, or it will paint the actual actor if the current effect
3519  * is the last effect in the chain.
3520  *
3521  * Since: 1.8
3522  */
3523 void
3524 clutter_actor_continue_paint (ClutterActor *self)
3525 {
3526   ClutterActorPrivate *priv;
3527
3528   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3529   /* This should only be called from with in the ‘run’ implementation
3530      of a ClutterEffect */
3531   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3532
3533   priv = self->priv;
3534
3535   /* Skip any effects that are disabled */
3536   while (priv->next_effect_to_paint &&
3537          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3538     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3539
3540   /* If this has come from the last effect then we'll just paint the
3541      actual actor */
3542   if (priv->next_effect_to_paint == NULL)
3543     {
3544       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3545         {
3546           ClutterPaintNode *dummy;
3547
3548           /* XXX - this will go away in 2.0, when we can get rid of this
3549            * stuff and switch to a pure retained render tree of PaintNodes
3550            * for the entire frame, starting from the Stage; the paint()
3551            * virtual function can then be called directly.
3552            */
3553           dummy = _clutter_dummy_node_new (self);
3554           clutter_paint_node_set_name (dummy, "Root");
3555
3556           /* XXX - for 1.12, we use the return value of paint_node() to
3557            * decide whether we should emit the ::paint signal.
3558            */
3559           clutter_actor_paint_node (self, dummy);
3560           clutter_paint_node_unref (dummy);
3561
3562           g_signal_emit (self, actor_signals[PAINT], 0);
3563         }
3564       else
3565         {
3566           ClutterColor col = { 0, };
3567
3568           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3569
3570           /* Actor will then paint silhouette of itself in supplied
3571            * color.  See clutter_stage_get_actor_at_pos() for where
3572            * picking is enabled.
3573            */
3574           g_signal_emit (self, actor_signals[PICK], 0, &col);
3575         }
3576     }
3577   else
3578     {
3579       ClutterEffect *old_current_effect;
3580       ClutterEffectPaintFlags run_flags = 0;
3581
3582       /* Cache the current effect so that we can put it back before
3583          returning */
3584       old_current_effect = priv->current_effect;
3585
3586       priv->current_effect = priv->next_effect_to_paint->data;
3587       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3588
3589       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3590         {
3591           if (priv->is_dirty)
3592             {
3593               /* If there's an effect queued with this redraw then all
3594                  effects up to that one will be considered dirty. It
3595                  is expected the queued effect will paint the cached
3596                  image and not call clutter_actor_continue_paint again
3597                  (although it should work ok if it does) */
3598               if (priv->effect_to_redraw == NULL ||
3599                   priv->current_effect != priv->effect_to_redraw)
3600                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3601             }
3602
3603           _clutter_effect_paint (priv->current_effect, run_flags);
3604         }
3605       else
3606         {
3607           /* We can't determine when an actor has been modified since
3608              its last pick so lets just assume it has always been
3609              modified */
3610           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3611
3612           _clutter_effect_pick (priv->current_effect, run_flags);
3613         }
3614
3615       priv->current_effect = old_current_effect;
3616     }
3617 }
3618
3619 static ClutterActorTraverseVisitFlags
3620 invalidate_queue_redraw_entry (ClutterActor *self,
3621                                int           depth,
3622                                gpointer      user_data)
3623 {
3624   ClutterActorPrivate *priv = self->priv;
3625
3626   if (priv->queue_redraw_entry != NULL)
3627     {
3628       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3629       priv->queue_redraw_entry = NULL;
3630     }
3631
3632   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3633 }
3634
3635 static inline void
3636 remove_child (ClutterActor *self,
3637               ClutterActor *child)
3638 {
3639   ClutterActor *prev_sibling, *next_sibling;
3640
3641   prev_sibling = child->priv->prev_sibling;
3642   next_sibling = child->priv->next_sibling;
3643
3644   if (prev_sibling != NULL)
3645     prev_sibling->priv->next_sibling = next_sibling;
3646
3647   if (next_sibling != NULL)
3648     next_sibling->priv->prev_sibling = prev_sibling;
3649
3650   if (self->priv->first_child == child)
3651     self->priv->first_child = next_sibling;
3652
3653   if (self->priv->last_child == child)
3654     self->priv->last_child = prev_sibling;
3655
3656   child->priv->parent = NULL;
3657   child->priv->prev_sibling = NULL;
3658   child->priv->next_sibling = NULL;
3659 }
3660
3661 typedef enum {
3662   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3663   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3664   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3665   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3666   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3667   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3668
3669   /* default flags for public API */
3670   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3671                                     REMOVE_CHILD_EMIT_PARENT_SET |
3672                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3673                                     REMOVE_CHILD_CHECK_STATE |
3674                                     REMOVE_CHILD_FLUSH_QUEUE |
3675                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3676
3677   /* flags for legacy/deprecated API */
3678   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3679                                     REMOVE_CHILD_FLUSH_QUEUE |
3680                                     REMOVE_CHILD_EMIT_PARENT_SET |
3681                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3682 } ClutterActorRemoveChildFlags;
3683
3684 /*< private >
3685  * clutter_actor_remove_child_internal:
3686  * @self: a #ClutterActor
3687  * @child: the child of @self that has to be removed
3688  * @flags: control the removal operations
3689  *
3690  * Removes @child from the list of children of @self.
3691  */
3692 static void
3693 clutter_actor_remove_child_internal (ClutterActor                 *self,
3694                                      ClutterActor                 *child,
3695                                      ClutterActorRemoveChildFlags  flags)
3696 {
3697   ClutterActor *old_first, *old_last;
3698   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3699   gboolean flush_queue;
3700   gboolean notify_first_last;
3701   gboolean was_mapped;
3702
3703   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3704   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3705   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3706   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3707   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3708   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3709
3710   g_object_freeze_notify (G_OBJECT (self));
3711
3712   if (destroy_meta)
3713     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3714
3715   if (check_state)
3716     {
3717       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3718
3719       /* we need to unrealize *before* we set parent_actor to NULL,
3720        * because in an unrealize method actors are dissociating from the
3721        * stage, which means they need to be able to
3722        * clutter_actor_get_stage().
3723        *
3724        * yhis should unmap and unrealize, unless we're reparenting.
3725        */
3726       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3727     }
3728   else
3729     was_mapped = FALSE;
3730
3731   if (flush_queue)
3732     {
3733       /* We take this opportunity to invalidate any queue redraw entry
3734        * associated with the actor and descendants since we won't be able to
3735        * determine the appropriate stage after this.
3736        *
3737        * we do this after we updated the mapped state because actors might
3738        * end up queueing redraws inside their mapped/unmapped virtual
3739        * functions, and if we invalidate the redraw entry we could end up
3740        * with an inconsistent state and weird memory corruption. see
3741        * bugs:
3742        *
3743        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3744        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3745        */
3746       _clutter_actor_traverse (child,
3747                                0,
3748                                invalidate_queue_redraw_entry,
3749                                NULL,
3750                                NULL);
3751     }
3752
3753   old_first = self->priv->first_child;
3754   old_last = self->priv->last_child;
3755
3756   remove_child (self, child);
3757
3758   self->priv->n_children -= 1;
3759
3760   self->priv->age += 1;
3761
3762   /* clutter_actor_reparent() will emit ::parent-set for us */
3763   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3764     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3765
3766   /* if the child was mapped then we need to relayout ourselves to account
3767    * for the removed child
3768    */
3769   if (was_mapped)
3770     clutter_actor_queue_relayout (self);
3771
3772   /* we need to emit the signal before dropping the reference */
3773   if (emit_actor_removed)
3774     g_signal_emit_by_name (self, "actor-removed", child);
3775
3776   if (notify_first_last)
3777     {
3778       if (old_first != self->priv->first_child)
3779         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3780
3781       if (old_last != self->priv->last_child)
3782         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3783     }
3784
3785   g_object_thaw_notify (G_OBJECT (self));
3786
3787   /* remove the reference we acquired in clutter_actor_add_child() */
3788   g_object_unref (child);
3789 }
3790
3791 static const ClutterTransformInfo default_transform_info = {
3792   0.0, { 0, },          /* rotation-x */
3793   0.0, { 0, },          /* rotation-y */
3794   0.0, { 0, },          /* rotation-z */
3795
3796   1.0, 1.0, { 0, },     /* scale */
3797
3798   { 0, },               /* anchor */
3799
3800   0.0,                  /* depth */
3801 };
3802
3803 /*< private >
3804  * _clutter_actor_get_transform_info_or_defaults:
3805  * @self: a #ClutterActor
3806  *
3807  * Retrieves the ClutterTransformInfo structure associated to an actor.
3808  *
3809  * If the actor does not have a ClutterTransformInfo structure associated
3810  * to it, then the default structure will be returned.
3811  *
3812  * This function should only be used for getters.
3813  *
3814  * Return value: a const pointer to the ClutterTransformInfo structure
3815  */
3816 const ClutterTransformInfo *
3817 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3818 {
3819   ClutterTransformInfo *info;
3820
3821   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3822   if (info != NULL)
3823     return info;
3824
3825   return &default_transform_info;
3826 }
3827
3828 static void
3829 clutter_transform_info_free (gpointer data)
3830 {
3831   if (data != NULL)
3832     g_slice_free (ClutterTransformInfo, data);
3833 }
3834
3835 /*< private >
3836  * _clutter_actor_get_transform_info:
3837  * @self: a #ClutterActor
3838  *
3839  * Retrieves a pointer to the ClutterTransformInfo structure.
3840  *
3841  * If the actor does not have a ClutterTransformInfo associated to it, one
3842  * will be created and initialized to the default values.
3843  *
3844  * This function should be used for setters.
3845  *
3846  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3847  * instead.
3848  *
3849  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3850  *   structure
3851  */
3852 ClutterTransformInfo *
3853 _clutter_actor_get_transform_info (ClutterActor *self)
3854 {
3855   ClutterTransformInfo *info;
3856
3857   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3858   if (info == NULL)
3859     {
3860       info = g_slice_new (ClutterTransformInfo);
3861
3862       *info = default_transform_info;
3863
3864       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3865                                info,
3866                                clutter_transform_info_free);
3867     }
3868
3869   return info;
3870 }
3871
3872 /*< private >
3873  * clutter_actor_set_rotation_angle_internal:
3874  * @self: a #ClutterActor
3875  * @axis: the axis of the angle to change
3876  * @angle: the angle of rotation
3877  *
3878  * Sets the rotation angle on the given axis without affecting the
3879  * rotation center point.
3880  */
3881 static inline void
3882 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3883                                            ClutterRotateAxis  axis,
3884                                            gdouble            angle)
3885 {
3886   GObject *obj = G_OBJECT (self);
3887   ClutterTransformInfo *info;
3888
3889   info = _clutter_actor_get_transform_info (self);
3890
3891   g_object_freeze_notify (obj);
3892
3893   switch (axis)
3894     {
3895     case CLUTTER_X_AXIS:
3896       info->rx_angle = angle;
3897       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3898       break;
3899
3900     case CLUTTER_Y_AXIS:
3901       info->ry_angle = angle;
3902       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3903       break;
3904
3905     case CLUTTER_Z_AXIS:
3906       info->rz_angle = angle;
3907       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3908       break;
3909     }
3910
3911   self->priv->transform_valid = FALSE;
3912
3913   g_object_thaw_notify (obj);
3914
3915   clutter_actor_queue_redraw (self);
3916 }
3917
3918 static inline void
3919 clutter_actor_set_rotation_angle (ClutterActor      *self,
3920                                   ClutterRotateAxis  axis,
3921                                   gdouble            angle)
3922 {
3923   ClutterTransformInfo *info;
3924
3925   info = _clutter_actor_get_transform_info (self);
3926
3927   if (clutter_actor_get_easing_duration (self) != 0)
3928     {
3929       ClutterTransition *transition;
3930       GParamSpec *pspec = NULL;
3931       double *cur_angle_p = NULL;
3932
3933       switch (axis)
3934         {
3935         case CLUTTER_X_AXIS:
3936           cur_angle_p = &info->rx_angle;
3937           pspec = obj_props[PROP_ROTATION_ANGLE_X];
3938           break;
3939
3940         case CLUTTER_Y_AXIS:
3941           cur_angle_p = &info->ry_angle;
3942           pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3943           break;
3944
3945         case CLUTTER_Z_AXIS:
3946           cur_angle_p = &info->rz_angle;
3947           pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3948           break;
3949         }
3950
3951       g_assert (pspec != NULL);
3952       g_assert (cur_angle_p != NULL);
3953
3954       transition = _clutter_actor_get_transition (self, pspec);
3955       if (transition == NULL)
3956         {
3957           transition = _clutter_actor_create_transition (self, pspec,
3958                                                          *cur_angle_p,
3959                                                          angle);
3960           clutter_timeline_start (CLUTTER_TIMELINE (transition));
3961         }
3962       else
3963         _clutter_actor_update_transition (self, pspec, angle);
3964
3965       self->priv->transform_valid = FALSE;
3966       clutter_actor_queue_redraw (self);
3967     }
3968   else
3969     clutter_actor_set_rotation_angle_internal (self, axis, angle);
3970 }
3971
3972 /*< private >
3973  * clutter_actor_set_rotation_center_internal:
3974  * @self: a #ClutterActor
3975  * @axis: the axis of the center to change
3976  * @center: the coordinates of the rotation center
3977  *
3978  * Sets the rotation center on the given axis without affecting the
3979  * rotation angle.
3980  */
3981 static inline void
3982 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3983                                             ClutterRotateAxis    axis,
3984                                             const ClutterVertex *center)
3985 {
3986   GObject *obj = G_OBJECT (self);
3987   ClutterTransformInfo *info;
3988   ClutterVertex v = { 0, 0, 0 };
3989
3990   info = _clutter_actor_get_transform_info (self);
3991
3992   if (center != NULL)
3993     v = *center;
3994
3995   g_object_freeze_notify (obj);
3996
3997   switch (axis)
3998     {
3999     case CLUTTER_X_AXIS:
4000       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4001       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4002       break;
4003
4004     case CLUTTER_Y_AXIS:
4005       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4006       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4007       break;
4008
4009     case CLUTTER_Z_AXIS:
4010       /* if the previously set rotation center was fractional, then
4011        * setting explicit coordinates will have to notify the
4012        * :rotation-center-z-gravity property as well
4013        */
4014       if (info->rz_center.is_fractional)
4015         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4016
4017       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4018       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4019       break;
4020     }
4021
4022   self->priv->transform_valid = FALSE;
4023
4024   g_object_thaw_notify (obj);
4025
4026   clutter_actor_queue_redraw (self);
4027 }
4028
4029 static void
4030 clutter_actor_animate_scale_factor (ClutterActor *self,
4031                                     double        old_factor,
4032                                     double        new_factor,
4033                                     GParamSpec   *pspec)
4034 {
4035   ClutterTransition *transition;
4036
4037   transition = _clutter_actor_get_transition (self, pspec);
4038   if (transition == NULL)
4039     {
4040       transition = _clutter_actor_create_transition (self, pspec,
4041                                                      old_factor,
4042                                                      new_factor);
4043       clutter_timeline_start (CLUTTER_TIMELINE (transition));
4044     }
4045   else
4046     _clutter_actor_update_transition (self, pspec, new_factor);
4047
4048
4049   self->priv->transform_valid = FALSE;
4050   clutter_actor_queue_redraw (self);
4051 }
4052
4053 static void
4054 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4055                                          double factor,
4056                                          GParamSpec *pspec)
4057 {
4058   GObject *obj = G_OBJECT (self);
4059   ClutterTransformInfo *info;
4060
4061   info = _clutter_actor_get_transform_info (self);
4062
4063   if (pspec == obj_props[PROP_SCALE_X])
4064     info->scale_x = factor;
4065   else
4066     info->scale_y = factor;
4067
4068   self->priv->transform_valid = FALSE;
4069   clutter_actor_queue_redraw (self);
4070   g_object_notify_by_pspec (obj, pspec);
4071 }
4072
4073 static inline void
4074 clutter_actor_set_scale_factor (ClutterActor      *self,
4075                                 ClutterRotateAxis  axis,
4076                                 gdouble            factor)
4077 {
4078   GObject *obj = G_OBJECT (self);
4079   ClutterTransformInfo *info;
4080   GParamSpec *pspec;
4081
4082   info = _clutter_actor_get_transform_info (self);
4083
4084   g_object_freeze_notify (obj);
4085
4086   switch (axis)
4087     {
4088     case CLUTTER_X_AXIS:
4089       pspec = obj_props[PROP_SCALE_X];
4090
4091       if (clutter_actor_get_easing_duration (self) != 0)
4092         clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
4093       else
4094         clutter_actor_set_scale_factor_internal (self, factor, pspec);
4095       break;
4096
4097     case CLUTTER_Y_AXIS:
4098       pspec = obj_props[PROP_SCALE_Y];
4099
4100       if (clutter_actor_get_easing_duration (self) != 0)
4101         clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4102       else
4103         clutter_actor_set_scale_factor_internal (self, factor, pspec);
4104       break;
4105
4106     default:
4107       g_assert_not_reached ();
4108     }
4109
4110   g_object_thaw_notify (obj);
4111 }
4112
4113 static inline void
4114 clutter_actor_set_scale_center (ClutterActor      *self,
4115                                 ClutterRotateAxis  axis,
4116                                 gfloat             coord)
4117 {
4118   GObject *obj = G_OBJECT (self);
4119   ClutterTransformInfo *info;
4120   gfloat center_x, center_y;
4121
4122   info = _clutter_actor_get_transform_info (self);
4123
4124   g_object_freeze_notify (obj);
4125
4126   /* get the current scale center coordinates */
4127   clutter_anchor_coord_get_units (self, &info->scale_center,
4128                                   &center_x,
4129                                   &center_y,
4130                                   NULL);
4131
4132   /* we need to notify this too, because setting explicit coordinates will
4133    * change the gravity as a side effect
4134    */
4135   if (info->scale_center.is_fractional)
4136     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4137
4138   switch (axis)
4139     {
4140     case CLUTTER_X_AXIS:
4141       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4142       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4143       break;
4144
4145     case CLUTTER_Y_AXIS:
4146       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4147       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4148       break;
4149
4150     default:
4151       g_assert_not_reached ();
4152     }
4153
4154   self->priv->transform_valid = FALSE;
4155
4156   clutter_actor_queue_redraw (self);
4157
4158   g_object_thaw_notify (obj);
4159 }
4160
4161 static inline void
4162 clutter_actor_set_scale_gravity (ClutterActor   *self,
4163                                  ClutterGravity  gravity)
4164 {
4165   ClutterTransformInfo *info;
4166   GObject *obj;
4167
4168   info = _clutter_actor_get_transform_info (self);
4169   obj = G_OBJECT (self);
4170
4171   if (gravity == CLUTTER_GRAVITY_NONE)
4172     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4173   else
4174     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4175
4176   self->priv->transform_valid = FALSE;
4177
4178   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4179   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4180   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4181
4182   clutter_actor_queue_redraw (self);
4183 }
4184
4185 static inline void
4186 clutter_actor_set_anchor_coord (ClutterActor      *self,
4187                                 ClutterRotateAxis  axis,
4188                                 gfloat             coord)
4189 {
4190   GObject *obj = G_OBJECT (self);
4191   ClutterTransformInfo *info;
4192   gfloat anchor_x, anchor_y;
4193
4194   info = _clutter_actor_get_transform_info (self);
4195
4196   g_object_freeze_notify (obj);
4197
4198   clutter_anchor_coord_get_units (self, &info->anchor,
4199                                   &anchor_x,
4200                                   &anchor_y,
4201                                   NULL);
4202
4203   if (info->anchor.is_fractional)
4204     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4205
4206   switch (axis)
4207     {
4208     case CLUTTER_X_AXIS:
4209       clutter_anchor_coord_set_units (&info->anchor,
4210                                       coord,
4211                                       anchor_y,
4212                                       0.0);
4213       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4214       break;
4215
4216     case CLUTTER_Y_AXIS:
4217       clutter_anchor_coord_set_units (&info->anchor,
4218                                       anchor_x,
4219                                       coord,
4220                                       0.0);
4221       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4222       break;
4223
4224     default:
4225       g_assert_not_reached ();
4226     }
4227
4228   self->priv->transform_valid = FALSE;
4229
4230   clutter_actor_queue_redraw (self);
4231
4232   g_object_thaw_notify (obj);
4233 }
4234
4235 static void
4236 clutter_actor_set_property (GObject      *object,
4237                             guint         prop_id,
4238                             const GValue *value,
4239                             GParamSpec   *pspec)
4240 {
4241   ClutterActor *actor = CLUTTER_ACTOR (object);
4242   ClutterActorPrivate *priv = actor->priv;
4243
4244   switch (prop_id)
4245     {
4246     case PROP_X:
4247       clutter_actor_set_x (actor, g_value_get_float (value));
4248       break;
4249
4250     case PROP_Y:
4251       clutter_actor_set_y (actor, g_value_get_float (value));
4252       break;
4253
4254     case PROP_WIDTH:
4255       clutter_actor_set_width (actor, g_value_get_float (value));
4256       break;
4257
4258     case PROP_HEIGHT:
4259       clutter_actor_set_height (actor, g_value_get_float (value));
4260       break;
4261
4262     case PROP_FIXED_X:
4263       clutter_actor_set_x (actor, g_value_get_float (value));
4264       break;
4265
4266     case PROP_FIXED_Y:
4267       clutter_actor_set_y (actor, g_value_get_float (value));
4268       break;
4269
4270     case PROP_FIXED_POSITION_SET:
4271       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4272       break;
4273
4274     case PROP_MIN_WIDTH:
4275       clutter_actor_set_min_width (actor, g_value_get_float (value));
4276       break;
4277
4278     case PROP_MIN_HEIGHT:
4279       clutter_actor_set_min_height (actor, g_value_get_float (value));
4280       break;
4281
4282     case PROP_NATURAL_WIDTH:
4283       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4284       break;
4285
4286     case PROP_NATURAL_HEIGHT:
4287       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4288       break;
4289
4290     case PROP_MIN_WIDTH_SET:
4291       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4292       break;
4293
4294     case PROP_MIN_HEIGHT_SET:
4295       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4296       break;
4297
4298     case PROP_NATURAL_WIDTH_SET:
4299       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4300       break;
4301
4302     case PROP_NATURAL_HEIGHT_SET:
4303       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4304       break;
4305
4306     case PROP_REQUEST_MODE:
4307       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4308       break;
4309
4310     case PROP_DEPTH:
4311       clutter_actor_set_depth (actor, g_value_get_float (value));
4312       break;
4313
4314     case PROP_OPACITY:
4315       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4316       break;
4317
4318     case PROP_OFFSCREEN_REDIRECT:
4319       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4320       break;
4321
4322     case PROP_NAME:
4323       clutter_actor_set_name (actor, g_value_get_string (value));
4324       break;
4325
4326     case PROP_VISIBLE:
4327       if (g_value_get_boolean (value) == TRUE)
4328         clutter_actor_show (actor);
4329       else
4330         clutter_actor_hide (actor);
4331       break;
4332
4333     case PROP_SCALE_X:
4334       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4335                                       g_value_get_double (value));
4336       break;
4337
4338     case PROP_SCALE_Y:
4339       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4340                                       g_value_get_double (value));
4341       break;
4342
4343     case PROP_SCALE_CENTER_X:
4344       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4345                                       g_value_get_float (value));
4346       break;
4347
4348     case PROP_SCALE_CENTER_Y:
4349       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4350                                       g_value_get_float (value));
4351       break;
4352
4353     case PROP_SCALE_GRAVITY:
4354       clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4355       break;
4356
4357     case PROP_CLIP:
4358       {
4359         const ClutterGeometry *geom = g_value_get_boxed (value);
4360
4361         clutter_actor_set_clip (actor,
4362                                 geom->x, geom->y,
4363                                 geom->width, geom->height);
4364       }
4365       break;
4366
4367     case PROP_CLIP_TO_ALLOCATION:
4368       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4369       break;
4370
4371     case PROP_REACTIVE:
4372       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4373       break;
4374
4375     case PROP_ROTATION_ANGLE_X:
4376       clutter_actor_set_rotation_angle (actor,
4377                                         CLUTTER_X_AXIS,
4378                                         g_value_get_double (value));
4379       break;
4380
4381     case PROP_ROTATION_ANGLE_Y:
4382       clutter_actor_set_rotation_angle (actor,
4383                                         CLUTTER_Y_AXIS,
4384                                         g_value_get_double (value));
4385       break;
4386
4387     case PROP_ROTATION_ANGLE_Z:
4388       clutter_actor_set_rotation_angle (actor,
4389                                         CLUTTER_Z_AXIS,
4390                                         g_value_get_double (value));
4391       break;
4392
4393     case PROP_ROTATION_CENTER_X:
4394       clutter_actor_set_rotation_center_internal (actor,
4395                                                   CLUTTER_X_AXIS,
4396                                                   g_value_get_boxed (value));
4397       break;
4398
4399     case PROP_ROTATION_CENTER_Y:
4400       clutter_actor_set_rotation_center_internal (actor,
4401                                                   CLUTTER_Y_AXIS,
4402                                                   g_value_get_boxed (value));
4403       break;
4404
4405     case PROP_ROTATION_CENTER_Z:
4406       clutter_actor_set_rotation_center_internal (actor,
4407                                                   CLUTTER_Z_AXIS,
4408                                                   g_value_get_boxed (value));
4409       break;
4410
4411     case PROP_ROTATION_CENTER_Z_GRAVITY:
4412       {
4413         const ClutterTransformInfo *info;
4414
4415         info = _clutter_actor_get_transform_info_or_defaults (actor);
4416         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4417                                                    g_value_get_enum (value));
4418       }
4419       break;
4420
4421     case PROP_ANCHOR_X:
4422       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4423                                       g_value_get_float (value));
4424       break;
4425
4426     case PROP_ANCHOR_Y:
4427       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4428                                       g_value_get_float (value));
4429       break;
4430
4431     case PROP_ANCHOR_GRAVITY:
4432       clutter_actor_set_anchor_point_from_gravity (actor,
4433                                                    g_value_get_enum (value));
4434       break;
4435
4436     case PROP_SHOW_ON_SET_PARENT:
4437       priv->show_on_set_parent = g_value_get_boolean (value);
4438       break;
4439
4440     case PROP_TEXT_DIRECTION:
4441       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4442       break;
4443
4444     case PROP_ACTIONS:
4445       clutter_actor_add_action (actor, g_value_get_object (value));
4446       break;
4447
4448     case PROP_CONSTRAINTS:
4449       clutter_actor_add_constraint (actor, g_value_get_object (value));
4450       break;
4451
4452     case PROP_EFFECT:
4453       clutter_actor_add_effect (actor, g_value_get_object (value));
4454       break;
4455
4456     case PROP_LAYOUT_MANAGER:
4457       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4458       break;
4459
4460     case PROP_X_ALIGN:
4461       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4462       break;
4463
4464     case PROP_Y_ALIGN:
4465       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4466       break;
4467
4468     case PROP_MARGIN_TOP:
4469       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4470       break;
4471
4472     case PROP_MARGIN_BOTTOM:
4473       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4474       break;
4475
4476     case PROP_MARGIN_LEFT:
4477       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4478       break;
4479
4480     case PROP_MARGIN_RIGHT:
4481       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4482       break;
4483
4484     case PROP_BACKGROUND_COLOR:
4485       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4486       break;
4487
4488     case PROP_CONTENT:
4489       clutter_actor_set_content (actor, g_value_get_object (value));
4490       break;
4491
4492     case PROP_CONTENT_GRAVITY:
4493       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4494       break;
4495
4496     case PROP_MINIFICATION_FILTER:
4497       clutter_actor_set_content_scaling_filters (actor,
4498                                                  g_value_get_enum (value),
4499                                                  actor->priv->mag_filter);
4500       break;
4501
4502     case PROP_MAGNIFICATION_FILTER:
4503       clutter_actor_set_content_scaling_filters (actor,
4504                                                  actor->priv->min_filter,
4505                                                  g_value_get_enum (value));
4506       break;
4507
4508     default:
4509       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4510       break;
4511     }
4512 }
4513
4514 static void
4515 clutter_actor_get_property (GObject    *object,
4516                             guint       prop_id,
4517                             GValue     *value,
4518                             GParamSpec *pspec)
4519 {
4520   ClutterActor *actor = CLUTTER_ACTOR (object);
4521   ClutterActorPrivate *priv = actor->priv;
4522
4523   switch (prop_id)
4524     {
4525     case PROP_X:
4526       g_value_set_float (value, clutter_actor_get_x (actor));
4527       break;
4528
4529     case PROP_Y:
4530       g_value_set_float (value, clutter_actor_get_y (actor));
4531       break;
4532
4533     case PROP_WIDTH:
4534       g_value_set_float (value, clutter_actor_get_width (actor));
4535       break;
4536
4537     case PROP_HEIGHT:
4538       g_value_set_float (value, clutter_actor_get_height (actor));
4539       break;
4540
4541     case PROP_FIXED_X:
4542       {
4543         const ClutterLayoutInfo *info;
4544
4545         info = _clutter_actor_get_layout_info_or_defaults (actor);
4546         g_value_set_float (value, info->fixed_x);
4547       }
4548       break;
4549
4550     case PROP_FIXED_Y:
4551       {
4552         const ClutterLayoutInfo *info;
4553
4554         info = _clutter_actor_get_layout_info_or_defaults (actor);
4555         g_value_set_float (value, info->fixed_y);
4556       }
4557       break;
4558
4559     case PROP_FIXED_POSITION_SET:
4560       g_value_set_boolean (value, priv->position_set);
4561       break;
4562
4563     case PROP_MIN_WIDTH:
4564       {
4565         const ClutterLayoutInfo *info;
4566
4567         info = _clutter_actor_get_layout_info_or_defaults (actor);
4568         g_value_set_float (value, info->min_width);
4569       }
4570       break;
4571
4572     case PROP_MIN_HEIGHT:
4573       {
4574         const ClutterLayoutInfo *info;
4575
4576         info = _clutter_actor_get_layout_info_or_defaults (actor);
4577         g_value_set_float (value, info->min_height);
4578       }
4579       break;
4580
4581     case PROP_NATURAL_WIDTH:
4582       {
4583         const ClutterLayoutInfo *info;
4584
4585         info = _clutter_actor_get_layout_info_or_defaults (actor);
4586         g_value_set_float (value, info->natural_width);
4587       }
4588       break;
4589
4590     case PROP_NATURAL_HEIGHT:
4591       {
4592         const ClutterLayoutInfo *info;
4593
4594         info = _clutter_actor_get_layout_info_or_defaults (actor);
4595         g_value_set_float (value, info->natural_height);
4596       }
4597       break;
4598
4599     case PROP_MIN_WIDTH_SET:
4600       g_value_set_boolean (value, priv->min_width_set);
4601       break;
4602
4603     case PROP_MIN_HEIGHT_SET:
4604       g_value_set_boolean (value, priv->min_height_set);
4605       break;
4606
4607     case PROP_NATURAL_WIDTH_SET:
4608       g_value_set_boolean (value, priv->natural_width_set);
4609       break;
4610
4611     case PROP_NATURAL_HEIGHT_SET:
4612       g_value_set_boolean (value, priv->natural_height_set);
4613       break;
4614
4615     case PROP_REQUEST_MODE:
4616       g_value_set_enum (value, priv->request_mode);
4617       break;
4618
4619     case PROP_ALLOCATION:
4620       g_value_set_boxed (value, &priv->allocation);
4621       break;
4622
4623     case PROP_DEPTH:
4624       g_value_set_float (value, clutter_actor_get_depth (actor));
4625       break;
4626
4627     case PROP_OPACITY:
4628       g_value_set_uint (value, priv->opacity);
4629       break;
4630
4631     case PROP_OFFSCREEN_REDIRECT:
4632       g_value_set_enum (value, priv->offscreen_redirect);
4633       break;
4634
4635     case PROP_NAME:
4636       g_value_set_string (value, priv->name);
4637       break;
4638
4639     case PROP_VISIBLE:
4640       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4641       break;
4642
4643     case PROP_MAPPED:
4644       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4645       break;
4646
4647     case PROP_REALIZED:
4648       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4649       break;
4650
4651     case PROP_HAS_CLIP:
4652       g_value_set_boolean (value, priv->has_clip);
4653       break;
4654
4655     case PROP_CLIP:
4656       {
4657         ClutterGeometry clip;
4658
4659         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4660         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4661         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4662         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4663
4664         g_value_set_boxed (value, &clip);
4665       }
4666       break;
4667
4668     case PROP_CLIP_TO_ALLOCATION:
4669       g_value_set_boolean (value, priv->clip_to_allocation);
4670       break;
4671
4672     case PROP_SCALE_X:
4673       {
4674         const ClutterTransformInfo *info;
4675
4676         info = _clutter_actor_get_transform_info_or_defaults (actor);
4677         g_value_set_double (value, info->scale_x);
4678       }
4679       break;
4680
4681     case PROP_SCALE_Y:
4682       {
4683         const ClutterTransformInfo *info;
4684
4685         info = _clutter_actor_get_transform_info_or_defaults (actor);
4686         g_value_set_double (value, info->scale_y);
4687       }
4688       break;
4689
4690     case PROP_SCALE_CENTER_X:
4691       {
4692         gfloat center;
4693
4694         clutter_actor_get_scale_center (actor, &center, NULL);
4695
4696         g_value_set_float (value, center);
4697       }
4698       break;
4699
4700     case PROP_SCALE_CENTER_Y:
4701       {
4702         gfloat center;
4703
4704         clutter_actor_get_scale_center (actor, NULL, &center);
4705
4706         g_value_set_float (value, center);
4707       }
4708       break;
4709
4710     case PROP_SCALE_GRAVITY:
4711       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4712       break;
4713
4714     case PROP_REACTIVE:
4715       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4716       break;
4717
4718     case PROP_ROTATION_ANGLE_X:
4719       {
4720         const ClutterTransformInfo *info;
4721
4722         info = _clutter_actor_get_transform_info_or_defaults (actor);
4723         g_value_set_double (value, info->rx_angle);
4724       }
4725       break;
4726
4727     case PROP_ROTATION_ANGLE_Y:
4728       {
4729         const ClutterTransformInfo *info;
4730
4731         info = _clutter_actor_get_transform_info_or_defaults (actor);
4732         g_value_set_double (value, info->ry_angle);
4733       }
4734       break;
4735
4736     case PROP_ROTATION_ANGLE_Z:
4737       {
4738         const ClutterTransformInfo *info;
4739
4740         info = _clutter_actor_get_transform_info_or_defaults (actor);
4741         g_value_set_double (value, info->rz_angle);
4742       }
4743       break;
4744
4745     case PROP_ROTATION_CENTER_X:
4746       {
4747         ClutterVertex center;
4748
4749         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4750                                     &center.x,
4751                                     &center.y,
4752                                     &center.z);
4753
4754         g_value_set_boxed (value, &center);
4755       }
4756       break;
4757
4758     case PROP_ROTATION_CENTER_Y:
4759       {
4760         ClutterVertex center;
4761
4762         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4763                                     &center.x,
4764                                     &center.y,
4765                                     &center.z);
4766
4767         g_value_set_boxed (value, &center);
4768       }
4769       break;
4770
4771     case PROP_ROTATION_CENTER_Z:
4772       {
4773         ClutterVertex center;
4774
4775         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4776                                     &center.x,
4777                                     &center.y,
4778                                     &center.z);
4779
4780         g_value_set_boxed (value, &center);
4781       }
4782       break;
4783
4784     case PROP_ROTATION_CENTER_Z_GRAVITY:
4785       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4786       break;
4787
4788     case PROP_ANCHOR_X:
4789       {
4790         const ClutterTransformInfo *info;
4791         gfloat anchor_x;
4792
4793         info = _clutter_actor_get_transform_info_or_defaults (actor);
4794         clutter_anchor_coord_get_units (actor, &info->anchor,
4795                                         &anchor_x,
4796                                         NULL,
4797                                         NULL);
4798         g_value_set_float (value, anchor_x);
4799       }
4800       break;
4801
4802     case PROP_ANCHOR_Y:
4803       {
4804         const ClutterTransformInfo *info;
4805         gfloat anchor_y;
4806
4807         info = _clutter_actor_get_transform_info_or_defaults (actor);
4808         clutter_anchor_coord_get_units (actor, &info->anchor,
4809                                         NULL,
4810                                         &anchor_y,
4811                                         NULL);
4812         g_value_set_float (value, anchor_y);
4813       }
4814       break;
4815
4816     case PROP_ANCHOR_GRAVITY:
4817       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4818       break;
4819
4820     case PROP_SHOW_ON_SET_PARENT:
4821       g_value_set_boolean (value, priv->show_on_set_parent);
4822       break;
4823
4824     case PROP_TEXT_DIRECTION:
4825       g_value_set_enum (value, priv->text_direction);
4826       break;
4827
4828     case PROP_HAS_POINTER:
4829       g_value_set_boolean (value, priv->has_pointer);
4830       break;
4831
4832     case PROP_LAYOUT_MANAGER:
4833       g_value_set_object (value, priv->layout_manager);
4834       break;
4835
4836     case PROP_X_ALIGN:
4837       {
4838         const ClutterLayoutInfo *info;
4839
4840         info = _clutter_actor_get_layout_info_or_defaults (actor);
4841         g_value_set_enum (value, info->x_align);
4842       }
4843       break;
4844
4845     case PROP_Y_ALIGN:
4846       {
4847         const ClutterLayoutInfo *info;
4848
4849         info = _clutter_actor_get_layout_info_or_defaults (actor);
4850         g_value_set_enum (value, info->y_align);
4851       }
4852       break;
4853
4854     case PROP_MARGIN_TOP:
4855       {
4856         const ClutterLayoutInfo *info;
4857
4858         info = _clutter_actor_get_layout_info_or_defaults (actor);
4859         g_value_set_float (value, info->margin.top);
4860       }
4861       break;
4862
4863     case PROP_MARGIN_BOTTOM:
4864       {
4865         const ClutterLayoutInfo *info;
4866
4867         info = _clutter_actor_get_layout_info_or_defaults (actor);
4868         g_value_set_float (value, info->margin.bottom);
4869       }
4870       break;
4871
4872     case PROP_MARGIN_LEFT:
4873       {
4874         const ClutterLayoutInfo *info;
4875
4876         info = _clutter_actor_get_layout_info_or_defaults (actor);
4877         g_value_set_float (value, info->margin.left);
4878       }
4879       break;
4880
4881     case PROP_MARGIN_RIGHT:
4882       {
4883         const ClutterLayoutInfo *info;
4884
4885         info = _clutter_actor_get_layout_info_or_defaults (actor);
4886         g_value_set_float (value, info->margin.right);
4887       }
4888       break;
4889
4890     case PROP_BACKGROUND_COLOR_SET:
4891       g_value_set_boolean (value, priv->bg_color_set);
4892       break;
4893
4894     case PROP_BACKGROUND_COLOR:
4895       g_value_set_boxed (value, &priv->bg_color);
4896       break;
4897
4898     case PROP_FIRST_CHILD:
4899       g_value_set_object (value, priv->first_child);
4900       break;
4901
4902     case PROP_LAST_CHILD:
4903       g_value_set_object (value, priv->last_child);
4904       break;
4905
4906     case PROP_CONTENT:
4907       g_value_set_object (value, priv->content);
4908       break;
4909
4910     case PROP_CONTENT_GRAVITY:
4911       g_value_set_enum (value, priv->content_gravity);
4912       break;
4913
4914     case PROP_CONTENT_BOX:
4915       {
4916         ClutterActorBox box = { 0, };
4917
4918         clutter_actor_get_content_box (actor, &box);
4919         g_value_set_boxed (value, &box);
4920       }
4921       break;
4922
4923     case PROP_MINIFICATION_FILTER:
4924       g_value_set_enum (value, priv->min_filter);
4925       break;
4926
4927     case PROP_MAGNIFICATION_FILTER:
4928       g_value_set_enum (value, priv->mag_filter);
4929       break;
4930
4931     default:
4932       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4933       break;
4934     }
4935 }
4936
4937 static void
4938 clutter_actor_dispose (GObject *object)
4939 {
4940   ClutterActor *self = CLUTTER_ACTOR (object);
4941   ClutterActorPrivate *priv = self->priv;
4942
4943   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4944                 priv->id,
4945                 g_type_name (G_OBJECT_TYPE (self)),
4946                 object->ref_count);
4947
4948   g_signal_emit (self, actor_signals[DESTROY], 0);
4949
4950   /* avoid recursing when called from clutter_actor_destroy() */
4951   if (priv->parent != NULL)
4952     {
4953       ClutterActor *parent = priv->parent;
4954
4955       /* go through the Container implementation unless this
4956        * is an internal child and has been marked as such.
4957        *
4958        * removing the actor from its parent will reset the
4959        * realized and mapped states.
4960        */
4961       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4962         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4963       else
4964         clutter_actor_remove_child_internal (parent, self,
4965                                              REMOVE_CHILD_LEGACY_FLAGS);
4966     }
4967
4968   /* parent must be gone at this point */
4969   g_assert (priv->parent == NULL);
4970
4971   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4972     {
4973       /* can't be mapped or realized with no parent */
4974       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4975       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4976     }
4977
4978   g_clear_object (&priv->pango_context);
4979   g_clear_object (&priv->actions);
4980   g_clear_object (&priv->constraints);
4981   g_clear_object (&priv->effects);
4982   g_clear_object (&priv->flatten_effect);
4983
4984   if (priv->layout_manager != NULL)
4985     {
4986       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4987       g_clear_object (&priv->layout_manager);
4988     }
4989
4990   if (priv->content != NULL)
4991     {
4992       _clutter_content_detached (priv->content, self);
4993       g_clear_object (&priv->content);
4994     }
4995
4996   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4997 }
4998
4999 static void
5000 clutter_actor_finalize (GObject *object)
5001 {
5002   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5003
5004   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5005                 priv->name != NULL ? priv->name : "<none>",
5006                 priv->id,
5007                 g_type_name (G_OBJECT_TYPE (object)));
5008
5009   _clutter_context_release_id (priv->id);
5010
5011   g_free (priv->name);
5012
5013   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5014 }
5015
5016
5017 /**
5018  * clutter_actor_get_accessible:
5019  * @self: a #ClutterActor
5020  *
5021  * Returns the accessible object that describes the actor to an
5022  * assistive technology.
5023  *
5024  * If no class-specific #AtkObject implementation is available for the
5025  * actor instance in question, it will inherit an #AtkObject
5026  * implementation from the first ancestor class for which such an
5027  * implementation is defined.
5028  *
5029  * The documentation of the <ulink
5030  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5031  * library contains more information about accessible objects and
5032  * their uses.
5033  *
5034  * Returns: (transfer none): the #AtkObject associated with @actor
5035  */
5036 AtkObject *
5037 clutter_actor_get_accessible (ClutterActor *self)
5038 {
5039   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5040
5041   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5042 }
5043
5044 static AtkObject *
5045 clutter_actor_real_get_accessible (ClutterActor *actor)
5046 {
5047   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5048 }
5049
5050 static AtkObject *
5051 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5052 {
5053   AtkObject *accessible;
5054
5055   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5056   if (accessible != NULL)
5057     g_object_ref (accessible);
5058
5059   return accessible;
5060 }
5061
5062 static void
5063 atk_implementor_iface_init (AtkImplementorIface *iface)
5064 {
5065   iface->ref_accessible = _clutter_actor_ref_accessible;
5066 }
5067
5068 static gboolean
5069 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5070                                            ClutterPaintVolume *volume)
5071 {
5072   ClutterActorPrivate *priv = self->priv;
5073   gboolean res = FALSE;
5074
5075   /* we start from the allocation */
5076   clutter_paint_volume_set_width (volume,
5077                                   priv->allocation.x2 - priv->allocation.x1);
5078   clutter_paint_volume_set_height (volume,
5079                                    priv->allocation.y2 - priv->allocation.y1);
5080
5081   /* if the actor has a clip set then we have a pretty definite
5082    * size for the paint volume: the actor cannot possibly paint
5083    * outside the clip region.
5084    */
5085   if (priv->clip_to_allocation)
5086     {
5087       /* the allocation has already been set, so we just flip the
5088        * return value
5089        */
5090       res = TRUE;
5091     }
5092   else
5093     {
5094       ClutterActor *child;
5095
5096       if (priv->has_clip &&
5097           priv->clip.width >= 0 &&
5098           priv->clip.height >= 0)
5099         {
5100           ClutterVertex origin;
5101
5102           origin.x = priv->clip.x;
5103           origin.y = priv->clip.y;
5104           origin.z = 0;
5105
5106           clutter_paint_volume_set_origin (volume, &origin);
5107           clutter_paint_volume_set_width (volume, priv->clip.width);
5108           clutter_paint_volume_set_height (volume, priv->clip.height);
5109
5110           res = TRUE;
5111         }
5112
5113       /* if we don't have children we just bail out here... */
5114       if (priv->n_children == 0)
5115         return res;
5116
5117       /* ...but if we have children then we ask for their paint volume in
5118        * our coordinates. if any of our children replies that it doesn't
5119        * have a paint volume, we bail out
5120        */
5121       for (child = priv->first_child;
5122            child != NULL;
5123            child = child->priv->next_sibling)
5124         {
5125           const ClutterPaintVolume *child_volume;
5126
5127           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5128           if (child_volume == NULL)
5129             {
5130               res = FALSE;
5131               break;
5132             }
5133
5134           clutter_paint_volume_union (volume, child_volume);
5135           res = TRUE;
5136         }
5137     }
5138
5139   return res;
5140
5141 }
5142
5143 static gboolean
5144 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5145                                      ClutterPaintVolume *volume)
5146 {
5147   ClutterActorClass *klass;
5148   gboolean res;
5149
5150   klass = CLUTTER_ACTOR_GET_CLASS (self);
5151
5152   /* XXX - this thoroughly sucks, but we don't want to penalize users
5153    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5154    * redraw. This should go away in 2.0.
5155    */
5156   if (klass->paint == clutter_actor_real_paint &&
5157       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5158     {
5159       res = TRUE;
5160     }
5161   else
5162     {
5163       /* this is the default return value: we cannot know if a class
5164        * is going to paint outside its allocation, so we take the
5165        * conservative approach.
5166        */
5167       res = FALSE;
5168     }
5169
5170   if (clutter_actor_update_default_paint_volume (self, volume))
5171     return res;
5172
5173   return FALSE;
5174 }
5175
5176 /**
5177  * clutter_actor_get_default_paint_volume:
5178  * @self: a #ClutterActor
5179  *
5180  * Retrieves the default paint volume for @self.
5181  *
5182  * This function provides the same #ClutterPaintVolume that would be
5183  * computed by the default implementation inside #ClutterActor of the
5184  * #ClutterActorClass.get_paint_volume() virtual function.
5185  *
5186  * This function should only be used by #ClutterActor subclasses that
5187  * cannot chain up to the parent implementation when computing their
5188  * paint volume.
5189  *
5190  * Return value: (transfer none): a pointer to the default
5191  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5192  *   the actor could not compute a valid paint volume. The returned value
5193  *   is not guaranteed to be stable across multiple frames, so if you
5194  *   want to retain it, you will need to copy it using
5195  *   clutter_paint_volume_copy().
5196  *
5197  * Since: 1.10
5198  */
5199 const ClutterPaintVolume *
5200 clutter_actor_get_default_paint_volume (ClutterActor *self)
5201 {
5202   ClutterPaintVolume volume;
5203   ClutterPaintVolume *res;
5204
5205   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5206
5207   res = NULL;
5208   _clutter_paint_volume_init_static (&volume, self);
5209   if (clutter_actor_update_default_paint_volume (self, &volume))
5210     {
5211       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5212
5213       if (stage != NULL)
5214         {
5215           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5216           _clutter_paint_volume_copy_static (&volume, res);
5217         }
5218     }
5219
5220   clutter_paint_volume_free (&volume);
5221
5222   return res;
5223 }
5224
5225 static gboolean
5226 clutter_actor_real_has_overlaps (ClutterActor *self)
5227 {
5228   /* By default we'll assume that all actors need an offscreen redirect to get
5229    * the correct opacity. Actors such as ClutterTexture that would never need
5230    * an offscreen redirect can override this to return FALSE. */
5231   return TRUE;
5232 }
5233
5234 static void
5235 clutter_actor_real_destroy (ClutterActor *actor)
5236 {
5237   ClutterActorIter iter;
5238
5239   clutter_actor_iter_init (&iter, actor);
5240   while (clutter_actor_iter_next (&iter, NULL))
5241     clutter_actor_iter_destroy (&iter);
5242 }
5243
5244 static GObject *
5245 clutter_actor_constructor (GType gtype,
5246                            guint n_props,
5247                            GObjectConstructParam *props)
5248 {
5249   GObjectClass *gobject_class;
5250   ClutterActor *self;
5251   GObject *retval;
5252
5253   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5254   retval = gobject_class->constructor (gtype, n_props, props);
5255   self = CLUTTER_ACTOR (retval);
5256
5257   if (self->priv->layout_manager == NULL)
5258     {
5259       ClutterLayoutManager *default_layout;
5260
5261       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5262
5263       default_layout = clutter_fixed_layout_new ();
5264       clutter_actor_set_layout_manager (self, default_layout);
5265     }
5266
5267   return retval;
5268 }
5269
5270 static void
5271 clutter_actor_class_init (ClutterActorClass *klass)
5272 {
5273   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5274
5275   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5276   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5277   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5278   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5279
5280   object_class->constructor = clutter_actor_constructor;
5281   object_class->set_property = clutter_actor_set_property;
5282   object_class->get_property = clutter_actor_get_property;
5283   object_class->dispose = clutter_actor_dispose;
5284   object_class->finalize = clutter_actor_finalize;
5285
5286   klass->show = clutter_actor_real_show;
5287   klass->show_all = clutter_actor_show;
5288   klass->hide = clutter_actor_real_hide;
5289   klass->hide_all = clutter_actor_hide;
5290   klass->map = clutter_actor_real_map;
5291   klass->unmap = clutter_actor_real_unmap;
5292   klass->unrealize = clutter_actor_real_unrealize;
5293   klass->pick = clutter_actor_real_pick;
5294   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5295   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5296   klass->allocate = clutter_actor_real_allocate;
5297   klass->queue_redraw = clutter_actor_real_queue_redraw;
5298   klass->queue_relayout = clutter_actor_real_queue_relayout;
5299   klass->apply_transform = clutter_actor_real_apply_transform;
5300   klass->get_accessible = clutter_actor_real_get_accessible;
5301   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5302   klass->has_overlaps = clutter_actor_real_has_overlaps;
5303   klass->paint = clutter_actor_real_paint;
5304   klass->destroy = clutter_actor_real_destroy;
5305
5306   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5307
5308   /**
5309    * ClutterActor:x:
5310    *
5311    * X coordinate of the actor in pixels. If written, forces a fixed
5312    * position for the actor. If read, returns the fixed position if any,
5313    * otherwise the allocation if available, otherwise 0.
5314    *
5315    * The #ClutterActor:x property is animatable.
5316    */
5317   obj_props[PROP_X] =
5318     g_param_spec_float ("x",
5319                         P_("X coordinate"),
5320                         P_("X coordinate of the actor"),
5321                         -G_MAXFLOAT, G_MAXFLOAT,
5322                         0.0,
5323                         G_PARAM_READWRITE |
5324                         G_PARAM_STATIC_STRINGS |
5325                         CLUTTER_PARAM_ANIMATABLE);
5326
5327   /**
5328    * ClutterActor:y:
5329    *
5330    * Y coordinate of the actor in pixels. If written, forces a fixed
5331    * position for the actor.  If read, returns the fixed position if
5332    * any, otherwise the allocation if available, otherwise 0.
5333    *
5334    * The #ClutterActor:y property is animatable.
5335    */
5336   obj_props[PROP_Y] =
5337     g_param_spec_float ("y",
5338                         P_("Y coordinate"),
5339                         P_("Y coordinate of the actor"),
5340                         -G_MAXFLOAT, G_MAXFLOAT,
5341                         0.0,
5342                         G_PARAM_READWRITE |
5343                         G_PARAM_STATIC_STRINGS |
5344                         CLUTTER_PARAM_ANIMATABLE);
5345
5346   /**
5347    * ClutterActor:width:
5348    *
5349    * Width of the actor (in pixels). If written, forces the minimum and
5350    * natural size request of the actor to the given width. If read, returns
5351    * the allocated width if available, otherwise the width request.
5352    *
5353    * The #ClutterActor:width property is animatable.
5354    */
5355   obj_props[PROP_WIDTH] =
5356     g_param_spec_float ("width",
5357                         P_("Width"),
5358                         P_("Width of the actor"),
5359                         0.0, G_MAXFLOAT,
5360                         0.0,
5361                         G_PARAM_READWRITE |
5362                         G_PARAM_STATIC_STRINGS |
5363                         CLUTTER_PARAM_ANIMATABLE);
5364
5365   /**
5366    * ClutterActor:height:
5367    *
5368    * Height of the actor (in pixels).  If written, forces the minimum and
5369    * natural size request of the actor to the given height. If read, returns
5370    * the allocated height if available, otherwise the height request.
5371    *
5372    * The #ClutterActor:height property is animatable.
5373    */
5374   obj_props[PROP_HEIGHT] =
5375     g_param_spec_float ("height",
5376                         P_("Height"),
5377                         P_("Height of the actor"),
5378                         0.0, G_MAXFLOAT,
5379                         0.0,
5380                         G_PARAM_READWRITE |
5381                         G_PARAM_STATIC_STRINGS |
5382                         CLUTTER_PARAM_ANIMATABLE);
5383
5384   /**
5385    * ClutterActor:fixed-x:
5386    *
5387    * The fixed X position of the actor in pixels.
5388    *
5389    * Writing this property sets #ClutterActor:fixed-position-set
5390    * property as well, as a side effect
5391    *
5392    * Since: 0.8
5393    */
5394   obj_props[PROP_FIXED_X] =
5395     g_param_spec_float ("fixed-x",
5396                         P_("Fixed X"),
5397                         P_("Forced X position of the actor"),
5398                         -G_MAXFLOAT, G_MAXFLOAT,
5399                         0.0,
5400                         CLUTTER_PARAM_READWRITE);
5401
5402   /**
5403    * ClutterActor:fixed-y:
5404    *
5405    * The fixed Y position of the actor in pixels.
5406    *
5407    * Writing this property sets the #ClutterActor:fixed-position-set
5408    * property as well, as a side effect
5409    *
5410    * Since: 0.8
5411    */
5412   obj_props[PROP_FIXED_Y] =
5413     g_param_spec_float ("fixed-y",
5414                         P_("Fixed Y"),
5415                         P_("Forced Y position of the actor"),
5416                         -G_MAXFLOAT, G_MAXFLOAT,
5417                         0,
5418                         CLUTTER_PARAM_READWRITE);
5419
5420   /**
5421    * ClutterActor:fixed-position-set:
5422    *
5423    * This flag controls whether the #ClutterActor:fixed-x and
5424    * #ClutterActor:fixed-y properties are used
5425    *
5426    * Since: 0.8
5427    */
5428   obj_props[PROP_FIXED_POSITION_SET] =
5429     g_param_spec_boolean ("fixed-position-set",
5430                           P_("Fixed position set"),
5431                           P_("Whether to use fixed positioning for the actor"),
5432                           FALSE,
5433                           CLUTTER_PARAM_READWRITE);
5434
5435   /**
5436    * ClutterActor:min-width:
5437    *
5438    * A forced minimum width request for the actor, in pixels
5439    *
5440    * Writing this property sets the #ClutterActor:min-width-set property
5441    * as well, as a side effect.
5442    *
5443    *This property overrides the usual width request of the actor.
5444    *
5445    * Since: 0.8
5446    */
5447   obj_props[PROP_MIN_WIDTH] =
5448     g_param_spec_float ("min-width",
5449                         P_("Min Width"),
5450                         P_("Forced minimum width request for the actor"),
5451                         0.0, G_MAXFLOAT,
5452                         0.0,
5453                         CLUTTER_PARAM_READWRITE);
5454
5455   /**
5456    * ClutterActor:min-height:
5457    *
5458    * A forced minimum height request for the actor, in pixels
5459    *
5460    * Writing this property sets the #ClutterActor:min-height-set property
5461    * as well, as a side effect. This property overrides the usual height
5462    * request of the actor.
5463    *
5464    * Since: 0.8
5465    */
5466   obj_props[PROP_MIN_HEIGHT] =
5467     g_param_spec_float ("min-height",
5468                         P_("Min Height"),
5469                         P_("Forced minimum height request for the actor"),
5470                         0.0, G_MAXFLOAT,
5471                         0.0,
5472                         CLUTTER_PARAM_READWRITE);
5473
5474   /**
5475    * ClutterActor:natural-width:
5476    *
5477    * A forced natural width request for the actor, in pixels
5478    *
5479    * Writing this property sets the #ClutterActor:natural-width-set
5480    * property as well, as a side effect. This property overrides the
5481    * usual width request of the actor
5482    *
5483    * Since: 0.8
5484    */
5485   obj_props[PROP_NATURAL_WIDTH] =
5486     g_param_spec_float ("natural-width",
5487                         P_("Natural Width"),
5488                         P_("Forced natural width request for the actor"),
5489                         0.0, G_MAXFLOAT,
5490                         0.0,
5491                         CLUTTER_PARAM_READWRITE);
5492
5493   /**
5494    * ClutterActor:natural-height:
5495    *
5496    * A forced natural height request for the actor, in pixels
5497    *
5498    * Writing this property sets the #ClutterActor:natural-height-set
5499    * property as well, as a side effect. This property overrides the
5500    * usual height request of the actor
5501    *
5502    * Since: 0.8
5503    */
5504   obj_props[PROP_NATURAL_HEIGHT] =
5505     g_param_spec_float ("natural-height",
5506                         P_("Natural Height"),
5507                         P_("Forced natural height request for the actor"),
5508                         0.0, G_MAXFLOAT,
5509                         0.0,
5510                         CLUTTER_PARAM_READWRITE);
5511
5512   /**
5513    * ClutterActor:min-width-set:
5514    *
5515    * This flag controls whether the #ClutterActor:min-width property
5516    * is used
5517    *
5518    * Since: 0.8
5519    */
5520   obj_props[PROP_MIN_WIDTH_SET] =
5521     g_param_spec_boolean ("min-width-set",
5522                           P_("Minimum width set"),
5523                           P_("Whether to use the min-width property"),
5524                           FALSE,
5525                           CLUTTER_PARAM_READWRITE);
5526
5527   /**
5528    * ClutterActor:min-height-set:
5529    *
5530    * This flag controls whether the #ClutterActor:min-height property
5531    * is used
5532    *
5533    * Since: 0.8
5534    */
5535   obj_props[PROP_MIN_HEIGHT_SET] =
5536     g_param_spec_boolean ("min-height-set",
5537                           P_("Minimum height set"),
5538                           P_("Whether to use the min-height property"),
5539                           FALSE,
5540                           CLUTTER_PARAM_READWRITE);
5541
5542   /**
5543    * ClutterActor:natural-width-set:
5544    *
5545    * This flag controls whether the #ClutterActor:natural-width property
5546    * is used
5547    *
5548    * Since: 0.8
5549    */
5550   obj_props[PROP_NATURAL_WIDTH_SET] =
5551     g_param_spec_boolean ("natural-width-set",
5552                           P_("Natural width set"),
5553                           P_("Whether to use the natural-width property"),
5554                           FALSE,
5555                           CLUTTER_PARAM_READWRITE);
5556
5557   /**
5558    * ClutterActor:natural-height-set:
5559    *
5560    * This flag controls whether the #ClutterActor:natural-height property
5561    * is used
5562    *
5563    * Since: 0.8
5564    */
5565   obj_props[PROP_NATURAL_HEIGHT_SET] =
5566     g_param_spec_boolean ("natural-height-set",
5567                           P_("Natural height set"),
5568                           P_("Whether to use the natural-height property"),
5569                           FALSE,
5570                           CLUTTER_PARAM_READWRITE);
5571
5572   /**
5573    * ClutterActor:allocation:
5574    *
5575    * The allocation for the actor, in pixels
5576    *
5577    * This is property is read-only, but you might monitor it to know when an
5578    * actor moves or resizes
5579    *
5580    * Since: 0.8
5581    */
5582   obj_props[PROP_ALLOCATION] =
5583     g_param_spec_boxed ("allocation",
5584                         P_("Allocation"),
5585                         P_("The actor's allocation"),
5586                         CLUTTER_TYPE_ACTOR_BOX,
5587                         CLUTTER_PARAM_READABLE);
5588
5589   /**
5590    * ClutterActor:request-mode:
5591    *
5592    * Request mode for the #ClutterActor. The request mode determines the
5593    * type of geometry management used by the actor, either height for width
5594    * (the default) or width for height.
5595    *
5596    * For actors implementing height for width, the parent container should get
5597    * the preferred width first, and then the preferred height for that width.
5598    *
5599    * For actors implementing width for height, the parent container should get
5600    * the preferred height first, and then the preferred width for that height.
5601    *
5602    * For instance:
5603    *
5604    * |[
5605    *   ClutterRequestMode mode;
5606    *   gfloat natural_width, min_width;
5607    *   gfloat natural_height, min_height;
5608    *
5609    *   mode = clutter_actor_get_request_mode (child);
5610    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5611    *     {
5612    *       clutter_actor_get_preferred_width (child, -1,
5613    *                                          &amp;min_width,
5614    *                                          &amp;natural_width);
5615    *       clutter_actor_get_preferred_height (child, natural_width,
5616    *                                           &amp;min_height,
5617    *                                           &amp;natural_height);
5618    *     }
5619    *   else
5620    *     {
5621    *       clutter_actor_get_preferred_height (child, -1,
5622    *                                           &amp;min_height,
5623    *                                           &amp;natural_height);
5624    *       clutter_actor_get_preferred_width (child, natural_height,
5625    *                                          &amp;min_width,
5626    *                                          &amp;natural_width);
5627    *     }
5628    * ]|
5629    *
5630    * will retrieve the minimum and natural width and height depending on the
5631    * preferred request mode of the #ClutterActor "child".
5632    *
5633    * The clutter_actor_get_preferred_size() function will implement this
5634    * check for you.
5635    *
5636    * Since: 0.8
5637    */
5638   obj_props[PROP_REQUEST_MODE] =
5639     g_param_spec_enum ("request-mode",
5640                        P_("Request Mode"),
5641                        P_("The actor's request mode"),
5642                        CLUTTER_TYPE_REQUEST_MODE,
5643                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5644                        CLUTTER_PARAM_READWRITE);
5645
5646   /**
5647    * ClutterActor:depth:
5648    *
5649    * The position of the actor on the Z axis.
5650    *
5651    * The #ClutterActor:depth property is relative to the parent's
5652    * modelview matrix.
5653    *
5654    * The #ClutterActor:depth property is animatable.
5655    *
5656    * Since: 0.6
5657    */
5658   obj_props[PROP_DEPTH] =
5659     g_param_spec_float ("depth",
5660                         P_("Depth"),
5661                         P_("Position on the Z axis"),
5662                         -G_MAXFLOAT, G_MAXFLOAT,
5663                         0.0,
5664                         G_PARAM_READWRITE |
5665                         G_PARAM_STATIC_STRINGS |
5666                         CLUTTER_PARAM_ANIMATABLE);
5667
5668   /**
5669    * ClutterActor:opacity:
5670    *
5671    * Opacity of an actor, between 0 (fully transparent) and
5672    * 255 (fully opaque)
5673    *
5674    * The #ClutterActor:opacity property is animatable.
5675    */
5676   obj_props[PROP_OPACITY] =
5677     g_param_spec_uint ("opacity",
5678                        P_("Opacity"),
5679                        P_("Opacity of an actor"),
5680                        0, 255,
5681                        255,
5682                        G_PARAM_READWRITE |
5683                        G_PARAM_STATIC_STRINGS |
5684                        CLUTTER_PARAM_ANIMATABLE);
5685
5686   /**
5687    * ClutterActor:offscreen-redirect:
5688    *
5689    * Determines the conditions in which the actor will be redirected
5690    * to an offscreen framebuffer while being painted. For example this
5691    * can be used to cache an actor in a framebuffer or for improved
5692    * handling of transparent actors. See
5693    * clutter_actor_set_offscreen_redirect() for details.
5694    *
5695    * Since: 1.8
5696    */
5697   obj_props[PROP_OFFSCREEN_REDIRECT] =
5698     g_param_spec_flags ("offscreen-redirect",
5699                         P_("Offscreen redirect"),
5700                         P_("Flags controlling when to flatten the actor into a single image"),
5701                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5702                         0,
5703                         CLUTTER_PARAM_READWRITE);
5704
5705   /**
5706    * ClutterActor:visible:
5707    *
5708    * Whether the actor is set to be visible or not
5709    *
5710    * See also #ClutterActor:mapped
5711    */
5712   obj_props[PROP_VISIBLE] =
5713     g_param_spec_boolean ("visible",
5714                           P_("Visible"),
5715                           P_("Whether the actor is visible or not"),
5716                           FALSE,
5717                           CLUTTER_PARAM_READWRITE);
5718
5719   /**
5720    * ClutterActor:mapped:
5721    *
5722    * Whether the actor is mapped (will be painted when the stage
5723    * to which it belongs is mapped)
5724    *
5725    * Since: 1.0
5726    */
5727   obj_props[PROP_MAPPED] =
5728     g_param_spec_boolean ("mapped",
5729                           P_("Mapped"),
5730                           P_("Whether the actor will be painted"),
5731                           FALSE,
5732                           CLUTTER_PARAM_READABLE);
5733
5734   /**
5735    * ClutterActor:realized:
5736    *
5737    * Whether the actor has been realized
5738    *
5739    * Since: 1.0
5740    */
5741   obj_props[PROP_REALIZED] =
5742     g_param_spec_boolean ("realized",
5743                           P_("Realized"),
5744                           P_("Whether the actor has been realized"),
5745                           FALSE,
5746                           CLUTTER_PARAM_READABLE);
5747
5748   /**
5749    * ClutterActor:reactive:
5750    *
5751    * Whether the actor is reactive to events or not
5752    *
5753    * Only reactive actors will emit event-related signals
5754    *
5755    * Since: 0.6
5756    */
5757   obj_props[PROP_REACTIVE] =
5758     g_param_spec_boolean ("reactive",
5759                           P_("Reactive"),
5760                           P_("Whether the actor is reactive to events"),
5761                           FALSE,
5762                           CLUTTER_PARAM_READWRITE);
5763
5764   /**
5765    * ClutterActor:has-clip:
5766    *
5767    * Whether the actor has the #ClutterActor:clip property set or not
5768    */
5769   obj_props[PROP_HAS_CLIP] =
5770     g_param_spec_boolean ("has-clip",
5771                           P_("Has Clip"),
5772                           P_("Whether the actor has a clip set"),
5773                           FALSE,
5774                           CLUTTER_PARAM_READABLE);
5775
5776   /**
5777    * ClutterActor:clip:
5778    *
5779    * The clip region for the actor, in actor-relative coordinates
5780    *
5781    * Every part of the actor outside the clip region will not be
5782    * painted
5783    */
5784   obj_props[PROP_CLIP] =
5785     g_param_spec_boxed ("clip",
5786                         P_("Clip"),
5787                         P_("The clip region for the actor"),
5788                         CLUTTER_TYPE_GEOMETRY,
5789                         CLUTTER_PARAM_READWRITE);
5790
5791   /**
5792    * ClutterActor:name:
5793    *
5794    * The name of the actor
5795    *
5796    * Since: 0.2
5797    */
5798   obj_props[PROP_NAME] =
5799     g_param_spec_string ("name",
5800                          P_("Name"),
5801                          P_("Name of the actor"),
5802                          NULL,
5803                          CLUTTER_PARAM_READWRITE);
5804
5805   /**
5806    * ClutterActor:scale-x:
5807    *
5808    * The horizontal scale of the actor.
5809    *
5810    * The #ClutterActor:scale-x property is animatable.
5811    *
5812    * Since: 0.6
5813    */
5814   obj_props[PROP_SCALE_X] =
5815     g_param_spec_double ("scale-x",
5816                          P_("Scale X"),
5817                          P_("Scale factor on the X axis"),
5818                          0.0, G_MAXDOUBLE,
5819                          1.0,
5820                          G_PARAM_READWRITE |
5821                          G_PARAM_STATIC_STRINGS |
5822                          CLUTTER_PARAM_ANIMATABLE);
5823
5824   /**
5825    * ClutterActor:scale-y:
5826    *
5827    * The vertical scale of the actor.
5828    *
5829    * The #ClutterActor:scale-y property is animatable.
5830    *
5831    * Since: 0.6
5832    */
5833   obj_props[PROP_SCALE_Y] =
5834     g_param_spec_double ("scale-y",
5835                          P_("Scale Y"),
5836                          P_("Scale factor on the Y axis"),
5837                          0.0, G_MAXDOUBLE,
5838                          1.0,
5839                          G_PARAM_READWRITE |
5840                          G_PARAM_STATIC_STRINGS |
5841                          CLUTTER_PARAM_ANIMATABLE);
5842
5843   /**
5844    * ClutterActor:scale-center-x:
5845    *
5846    * The horizontal center point for scaling
5847    *
5848    * Since: 1.0
5849    */
5850   obj_props[PROP_SCALE_CENTER_X] =
5851     g_param_spec_float ("scale-center-x",
5852                         P_("Scale Center X"),
5853                         P_("Horizontal scale center"),
5854                         -G_MAXFLOAT, G_MAXFLOAT,
5855                         0.0,
5856                         CLUTTER_PARAM_READWRITE);
5857
5858   /**
5859    * ClutterActor:scale-center-y:
5860    *
5861    * The vertical center point for scaling
5862    *
5863    * Since: 1.0
5864    */
5865   obj_props[PROP_SCALE_CENTER_Y] =
5866     g_param_spec_float ("scale-center-y",
5867                         P_("Scale Center Y"),
5868                         P_("Vertical scale center"),
5869                         -G_MAXFLOAT, G_MAXFLOAT,
5870                         0.0,
5871                         CLUTTER_PARAM_READWRITE);
5872
5873   /**
5874    * ClutterActor:scale-gravity:
5875    *
5876    * The center point for scaling expressed as a #ClutterGravity
5877    *
5878    * Since: 1.0
5879    */
5880   obj_props[PROP_SCALE_GRAVITY] =
5881     g_param_spec_enum ("scale-gravity",
5882                        P_("Scale Gravity"),
5883                        P_("The center of scaling"),
5884                        CLUTTER_TYPE_GRAVITY,
5885                        CLUTTER_GRAVITY_NONE,
5886                        CLUTTER_PARAM_READWRITE);
5887
5888   /**
5889    * ClutterActor:rotation-angle-x:
5890    *
5891    * The rotation angle on the X axis.
5892    *
5893    * The #ClutterActor:rotation-angle-x property is animatable.
5894    *
5895    * Since: 0.6
5896    */
5897   obj_props[PROP_ROTATION_ANGLE_X] =
5898     g_param_spec_double ("rotation-angle-x",
5899                          P_("Rotation Angle X"),
5900                          P_("The rotation angle on the X axis"),
5901                          -G_MAXDOUBLE, G_MAXDOUBLE,
5902                          0.0,
5903                          G_PARAM_READWRITE |
5904                          G_PARAM_STATIC_STRINGS |
5905                          CLUTTER_PARAM_ANIMATABLE);
5906
5907   /**
5908    * ClutterActor:rotation-angle-y:
5909    *
5910    * The rotation angle on the Y axis
5911    *
5912    * The #ClutterActor:rotation-angle-y property is animatable.
5913    *
5914    * Since: 0.6
5915    */
5916   obj_props[PROP_ROTATION_ANGLE_Y] =
5917     g_param_spec_double ("rotation-angle-y",
5918                          P_("Rotation Angle Y"),
5919                          P_("The rotation angle on the Y axis"),
5920                          -G_MAXDOUBLE, G_MAXDOUBLE,
5921                          0.0,
5922                          G_PARAM_READWRITE |
5923                          G_PARAM_STATIC_STRINGS |
5924                          CLUTTER_PARAM_ANIMATABLE);
5925
5926   /**
5927    * ClutterActor:rotation-angle-z:
5928    *
5929    * The rotation angle on the Z axis
5930    *
5931    * The #ClutterActor:rotation-angle-z property is animatable.
5932    *
5933    * Since: 0.6
5934    */
5935   obj_props[PROP_ROTATION_ANGLE_Z] =
5936     g_param_spec_double ("rotation-angle-z",
5937                          P_("Rotation Angle Z"),
5938                          P_("The rotation angle on the Z axis"),
5939                          -G_MAXDOUBLE, G_MAXDOUBLE,
5940                          0.0,
5941                          G_PARAM_READWRITE |
5942                          G_PARAM_STATIC_STRINGS |
5943                          CLUTTER_PARAM_ANIMATABLE);
5944
5945   /**
5946    * ClutterActor:rotation-center-x:
5947    *
5948    * The rotation center on the X axis.
5949    *
5950    * Since: 0.6
5951    */
5952   obj_props[PROP_ROTATION_CENTER_X] =
5953     g_param_spec_boxed ("rotation-center-x",
5954                         P_("Rotation Center X"),
5955                         P_("The rotation center on the X axis"),
5956                         CLUTTER_TYPE_VERTEX,
5957                         CLUTTER_PARAM_READWRITE);
5958
5959   /**
5960    * ClutterActor:rotation-center-y:
5961    *
5962    * The rotation center on the Y axis.
5963    *
5964    * Since: 0.6
5965    */
5966   obj_props[PROP_ROTATION_CENTER_Y] =
5967     g_param_spec_boxed ("rotation-center-y",
5968                         P_("Rotation Center Y"),
5969                         P_("The rotation center on the Y axis"),
5970                         CLUTTER_TYPE_VERTEX,
5971                         CLUTTER_PARAM_READWRITE);
5972
5973   /**
5974    * ClutterActor:rotation-center-z:
5975    *
5976    * The rotation center on the Z axis.
5977    *
5978    * Since: 0.6
5979    */
5980   obj_props[PROP_ROTATION_CENTER_Z] =
5981     g_param_spec_boxed ("rotation-center-z",
5982                         P_("Rotation Center Z"),
5983                         P_("The rotation center on the Z axis"),
5984                         CLUTTER_TYPE_VERTEX,
5985                         CLUTTER_PARAM_READWRITE);
5986
5987   /**
5988    * ClutterActor:rotation-center-z-gravity:
5989    *
5990    * The rotation center on the Z axis expressed as a #ClutterGravity.
5991    *
5992    * Since: 1.0
5993    */
5994   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5995     g_param_spec_enum ("rotation-center-z-gravity",
5996                        P_("Rotation Center Z Gravity"),
5997                        P_("Center point for rotation around the Z axis"),
5998                        CLUTTER_TYPE_GRAVITY,
5999                        CLUTTER_GRAVITY_NONE,
6000                        CLUTTER_PARAM_READWRITE);
6001
6002   /**
6003    * ClutterActor:anchor-x:
6004    *
6005    * The X coordinate of an actor's anchor point, relative to
6006    * the actor coordinate space, in pixels
6007    *
6008    * Since: 0.8
6009    */
6010   obj_props[PROP_ANCHOR_X] =
6011     g_param_spec_float ("anchor-x",
6012                         P_("Anchor X"),
6013                         P_("X coordinate of the anchor point"),
6014                         -G_MAXFLOAT, G_MAXFLOAT,
6015                         0,
6016                         CLUTTER_PARAM_READWRITE);
6017
6018   /**
6019    * ClutterActor:anchor-y:
6020    *
6021    * The Y coordinate of an actor's anchor point, relative to
6022    * the actor coordinate space, in pixels
6023    *
6024    * Since: 0.8
6025    */
6026   obj_props[PROP_ANCHOR_Y] =
6027     g_param_spec_float ("anchor-y",
6028                         P_("Anchor Y"),
6029                         P_("Y coordinate of the anchor point"),
6030                         -G_MAXFLOAT, G_MAXFLOAT,
6031                         0,
6032                         CLUTTER_PARAM_READWRITE);
6033
6034   /**
6035    * ClutterActor:anchor-gravity:
6036    *
6037    * The anchor point expressed as a #ClutterGravity
6038    *
6039    * Since: 1.0
6040    */
6041   obj_props[PROP_ANCHOR_GRAVITY] =
6042     g_param_spec_enum ("anchor-gravity",
6043                        P_("Anchor Gravity"),
6044                        P_("The anchor point as a ClutterGravity"),
6045                        CLUTTER_TYPE_GRAVITY,
6046                        CLUTTER_GRAVITY_NONE,
6047                        CLUTTER_PARAM_READWRITE);
6048
6049   /**
6050    * ClutterActor:show-on-set-parent:
6051    *
6052    * If %TRUE, the actor is automatically shown when parented.
6053    *
6054    * Calling clutter_actor_hide() on an actor which has not been
6055    * parented will set this property to %FALSE as a side effect.
6056    *
6057    * Since: 0.8
6058    */
6059   obj_props[PROP_SHOW_ON_SET_PARENT] =
6060     g_param_spec_boolean ("show-on-set-parent",
6061                           P_("Show on set parent"),
6062                           P_("Whether the actor is shown when parented"),
6063                           TRUE,
6064                           CLUTTER_PARAM_READWRITE);
6065
6066   /**
6067    * ClutterActor:clip-to-allocation:
6068    *
6069    * Whether the clip region should track the allocated area
6070    * of the actor.
6071    *
6072    * This property is ignored if a clip area has been explicitly
6073    * set using clutter_actor_set_clip().
6074    *
6075    * Since: 1.0
6076    */
6077   obj_props[PROP_CLIP_TO_ALLOCATION] =
6078     g_param_spec_boolean ("clip-to-allocation",
6079                           P_("Clip to Allocation"),
6080                           P_("Sets the clip region to track the actor's allocation"),
6081                           FALSE,
6082                           CLUTTER_PARAM_READWRITE);
6083
6084   /**
6085    * ClutterActor:text-direction:
6086    *
6087    * The direction of the text inside a #ClutterActor.
6088    *
6089    * Since: 1.0
6090    */
6091   obj_props[PROP_TEXT_DIRECTION] =
6092     g_param_spec_enum ("text-direction",
6093                        P_("Text Direction"),
6094                        P_("Direction of the text"),
6095                        CLUTTER_TYPE_TEXT_DIRECTION,
6096                        CLUTTER_TEXT_DIRECTION_LTR,
6097                        CLUTTER_PARAM_READWRITE);
6098
6099   /**
6100    * ClutterActor:has-pointer:
6101    *
6102    * Whether the actor contains the pointer of a #ClutterInputDevice
6103    * or not.
6104    *
6105    * Since: 1.2
6106    */
6107   obj_props[PROP_HAS_POINTER] =
6108     g_param_spec_boolean ("has-pointer",
6109                           P_("Has Pointer"),
6110                           P_("Whether the actor contains the pointer of an input device"),
6111                           FALSE,
6112                           CLUTTER_PARAM_READABLE);
6113
6114   /**
6115    * ClutterActor:actions:
6116    *
6117    * Adds a #ClutterAction to the actor
6118    *
6119    * Since: 1.4
6120    */
6121   obj_props[PROP_ACTIONS] =
6122     g_param_spec_object ("actions",
6123                          P_("Actions"),
6124                          P_("Adds an action to the actor"),
6125                          CLUTTER_TYPE_ACTION,
6126                          CLUTTER_PARAM_WRITABLE);
6127
6128   /**
6129    * ClutterActor:constraints:
6130    *
6131    * Adds a #ClutterConstraint to the actor
6132    *
6133    * Since: 1.4
6134    */
6135   obj_props[PROP_CONSTRAINTS] =
6136     g_param_spec_object ("constraints",
6137                          P_("Constraints"),
6138                          P_("Adds a constraint to the actor"),
6139                          CLUTTER_TYPE_CONSTRAINT,
6140                          CLUTTER_PARAM_WRITABLE);
6141
6142   /**
6143    * ClutterActor:effect:
6144    *
6145    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6146    *
6147    * Since: 1.4
6148    */
6149   obj_props[PROP_EFFECT] =
6150     g_param_spec_object ("effect",
6151                          P_("Effect"),
6152                          P_("Add an effect to be applied on the actor"),
6153                          CLUTTER_TYPE_EFFECT,
6154                          CLUTTER_PARAM_WRITABLE);
6155
6156   /**
6157    * ClutterActor:layout-manager:
6158    *
6159    * A delegate object for controlling the layout of the children of
6160    * an actor.
6161    *
6162    * Since: 1.10
6163    */
6164   obj_props[PROP_LAYOUT_MANAGER] =
6165     g_param_spec_object ("layout-manager",
6166                          P_("Layout Manager"),
6167                          P_("The object controlling the layout of an actor's children"),
6168                          CLUTTER_TYPE_LAYOUT_MANAGER,
6169                          CLUTTER_PARAM_READWRITE);
6170
6171
6172   /**
6173    * ClutterActor:x-align:
6174    *
6175    * The alignment of an actor on the X axis, if the actor has been given
6176    * extra space for its allocation.
6177    *
6178    * Since: 1.10
6179    */
6180   obj_props[PROP_X_ALIGN] =
6181     g_param_spec_enum ("x-align",
6182                        P_("X Alignment"),
6183                        P_("The alignment of the actor on the X axis within its allocation"),
6184                        CLUTTER_TYPE_ACTOR_ALIGN,
6185                        CLUTTER_ACTOR_ALIGN_FILL,
6186                        CLUTTER_PARAM_READWRITE);
6187
6188   /**
6189    * ClutterActor:y-align:
6190    *
6191    * The alignment of an actor on the Y axis, if the actor has been given
6192    * extra space for its allocation.
6193    *
6194    * Since: 1.10
6195    */
6196   obj_props[PROP_Y_ALIGN] =
6197     g_param_spec_enum ("y-align",
6198                        P_("Y Alignment"),
6199                        P_("The alignment of the actor on the Y axis within its allocation"),
6200                        CLUTTER_TYPE_ACTOR_ALIGN,
6201                        CLUTTER_ACTOR_ALIGN_FILL,
6202                        CLUTTER_PARAM_READWRITE);
6203
6204   /**
6205    * ClutterActor:margin-top:
6206    *
6207    * The margin (in pixels) from the top of the actor.
6208    *
6209    * This property adds a margin to the actor's preferred size; the margin
6210    * will be automatically taken into account when allocating the actor.
6211    *
6212    * Since: 1.10
6213    */
6214   obj_props[PROP_MARGIN_TOP] =
6215     g_param_spec_float ("margin-top",
6216                         P_("Margin Top"),
6217                         P_("Extra space at the top"),
6218                         0.0, G_MAXFLOAT,
6219                         0.0,
6220                         CLUTTER_PARAM_READWRITE);
6221
6222   /**
6223    * ClutterActor:margin-bottom:
6224    *
6225    * The margin (in pixels) from the bottom of the actor.
6226    *
6227    * This property adds a margin to the actor's preferred size; the margin
6228    * will be automatically taken into account when allocating the actor.
6229    *
6230    * Since: 1.10
6231    */
6232   obj_props[PROP_MARGIN_BOTTOM] =
6233     g_param_spec_float ("margin-bottom",
6234                         P_("Margin Bottom"),
6235                         P_("Extra space at the bottom"),
6236                         0.0, G_MAXFLOAT,
6237                         0.0,
6238                         CLUTTER_PARAM_READWRITE);
6239
6240   /**
6241    * ClutterActor:margin-left:
6242    *
6243    * The margin (in pixels) from the left of the actor.
6244    *
6245    * This property adds a margin to the actor's preferred size; the margin
6246    * will be automatically taken into account when allocating the actor.
6247    *
6248    * Since: 1.10
6249    */
6250   obj_props[PROP_MARGIN_LEFT] =
6251     g_param_spec_float ("margin-left",
6252                         P_("Margin Left"),
6253                         P_("Extra space at the left"),
6254                         0.0, G_MAXFLOAT,
6255                         0.0,
6256                         CLUTTER_PARAM_READWRITE);
6257
6258   /**
6259    * ClutterActor:margin-right:
6260    *
6261    * The margin (in pixels) from the right of the actor.
6262    *
6263    * This property adds a margin to the actor's preferred size; the margin
6264    * will be automatically taken into account when allocating the actor.
6265    *
6266    * Since: 1.10
6267    */
6268   obj_props[PROP_MARGIN_RIGHT] =
6269     g_param_spec_float ("margin-right",
6270                         P_("Margin Right"),
6271                         P_("Extra space at the right"),
6272                         0.0, G_MAXFLOAT,
6273                         0.0,
6274                         CLUTTER_PARAM_READWRITE);
6275
6276   /**
6277    * ClutterActor:background-color-set:
6278    *
6279    * Whether the #ClutterActor:background-color property has been set.
6280    *
6281    * Since: 1.10
6282    */
6283   obj_props[PROP_BACKGROUND_COLOR_SET] =
6284     g_param_spec_boolean ("background-color-set",
6285                           P_("Background Color Set"),
6286                           P_("Whether the background color is set"),
6287                           FALSE,
6288                           CLUTTER_PARAM_READABLE);
6289
6290   /**
6291    * ClutterActor:background-color:
6292    *
6293    * Paints a solid fill of the actor's allocation using the specified
6294    * color.
6295    *
6296    * The #ClutterActor:background-color property is animatable.
6297    *
6298    * Since: 1.10
6299    */
6300   obj_props[PROP_BACKGROUND_COLOR] =
6301     clutter_param_spec_color ("background-color",
6302                               P_("Background color"),
6303                               P_("The actor's background color"),
6304                               CLUTTER_COLOR_Transparent,
6305                               G_PARAM_READWRITE |
6306                               G_PARAM_STATIC_STRINGS |
6307                               CLUTTER_PARAM_ANIMATABLE);
6308
6309   /**
6310    * ClutterActor:first-child:
6311    *
6312    * The actor's first child.
6313    *
6314    * Since: 1.10
6315    */
6316   obj_props[PROP_FIRST_CHILD] =
6317     g_param_spec_object ("first-child",
6318                          P_("First Child"),
6319                          P_("The actor's first child"),
6320                          CLUTTER_TYPE_ACTOR,
6321                          CLUTTER_PARAM_READABLE);
6322
6323   /**
6324    * ClutterActor:last-child:
6325    *
6326    * The actor's last child.
6327    *
6328    * Since: 1.10
6329    */
6330   obj_props[PROP_LAST_CHILD] =
6331     g_param_spec_object ("last-child",
6332                          P_("Last Child"),
6333                          P_("The actor's last child"),
6334                          CLUTTER_TYPE_ACTOR,
6335                          CLUTTER_PARAM_READABLE);
6336
6337   /**
6338    * ClutterActor:content:
6339    *
6340    * The #ClutterContent implementation that controls the content
6341    * of the actor.
6342    *
6343    * Since: 1.10
6344    */
6345   obj_props[PROP_CONTENT] =
6346     g_param_spec_object ("content",
6347                          P_("Content"),
6348                          P_("Delegate object for painting the actor's content"),
6349                          CLUTTER_TYPE_CONTENT,
6350                          CLUTTER_PARAM_READWRITE);
6351
6352   /**
6353    * ClutterActor:content-gravity:
6354    *
6355    * The alignment that should be honoured by the #ClutterContent
6356    * set with the #ClutterActor:content property.
6357    *
6358    * Changing the value of this property will change the bounding box of
6359    * the content; you can use the #ClutterActor:content-box property to
6360    * get the position and size of the content within the actor's
6361    * allocation.
6362    *
6363    * This property is meaningful only for #ClutterContent implementations
6364    * that have a preferred size, and if the preferred size is smaller than
6365    * the actor's allocation.
6366    *
6367    * Since: 1.10
6368    */
6369   obj_props[PROP_CONTENT_GRAVITY] =
6370     g_param_spec_enum ("content-gravity",
6371                        P_("Content Gravity"),
6372                        P_("Alignment of the actor's content"),
6373                        CLUTTER_TYPE_CONTENT_GRAVITY,
6374                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6375                        CLUTTER_PARAM_READWRITE);
6376
6377   /**
6378    * ClutterActor:content-box:
6379    *
6380    * The bounding box for the #ClutterContent used by the actor.
6381    *
6382    * The value of this property is controlled by the #ClutterActor:allocation
6383    * and #ClutterActor:content-gravity properties of #ClutterActor.
6384    *
6385    * The bounding box for the content is guaranteed to never exceed the
6386    * allocation's of the actor.
6387    *
6388    * Since: 1.10
6389    */
6390   obj_props[PROP_CONTENT_BOX] =
6391     g_param_spec_boxed ("content-box",
6392                         P_("Content Box"),
6393                         P_("The bounding box of the actor's content"),
6394                         CLUTTER_TYPE_ACTOR_BOX,
6395                         CLUTTER_PARAM_READABLE);
6396
6397   obj_props[PROP_MINIFICATION_FILTER] =
6398     g_param_spec_enum ("minification-filter",
6399                        P_("Minification Filter"),
6400                        P_("The filter used when reducing the size of the content"),
6401                        CLUTTER_TYPE_SCALING_FILTER,
6402                        CLUTTER_SCALING_FILTER_LINEAR,
6403                        CLUTTER_PARAM_READWRITE);
6404
6405   obj_props[PROP_MAGNIFICATION_FILTER] =
6406     g_param_spec_enum ("magnification-filter",
6407                        P_("Magnification Filter"),
6408                        P_("The filter used when increasing the size of the content"),
6409                        CLUTTER_TYPE_SCALING_FILTER,
6410                        CLUTTER_SCALING_FILTER_LINEAR,
6411                        CLUTTER_PARAM_READWRITE);
6412
6413   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6414
6415   /**
6416    * ClutterActor::destroy:
6417    * @actor: the #ClutterActor which emitted the signal
6418    *
6419    * The ::destroy signal notifies that all references held on the
6420    * actor which emitted it should be released.
6421    *
6422    * The ::destroy signal should be used by all holders of a reference
6423    * on @actor.
6424    *
6425    * This signal might result in the finalization of the #ClutterActor
6426    * if all references are released.
6427    *
6428    * Composite actors and actors implementing the #ClutterContainer
6429    * interface should override the default implementation of the
6430    * class handler of this signal and call clutter_actor_destroy() on
6431    * their children. When overriding the default class handler, it is
6432    * required to chain up to the parent's implementation.
6433    *
6434    * Since: 0.2
6435    */
6436   actor_signals[DESTROY] =
6437     g_signal_new (I_("destroy"),
6438                   G_TYPE_FROM_CLASS (object_class),
6439                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6440                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6441                   NULL, NULL,
6442                   _clutter_marshal_VOID__VOID,
6443                   G_TYPE_NONE, 0);
6444   /**
6445    * ClutterActor::show:
6446    * @actor: the object which received the signal
6447    *
6448    * The ::show signal is emitted when an actor is visible and
6449    * rendered on the stage.
6450    *
6451    * Since: 0.2
6452    */
6453   actor_signals[SHOW] =
6454     g_signal_new (I_("show"),
6455                   G_TYPE_FROM_CLASS (object_class),
6456                   G_SIGNAL_RUN_FIRST,
6457                   G_STRUCT_OFFSET (ClutterActorClass, show),
6458                   NULL, NULL,
6459                   _clutter_marshal_VOID__VOID,
6460                   G_TYPE_NONE, 0);
6461   /**
6462    * ClutterActor::hide:
6463    * @actor: the object which received the signal
6464    *
6465    * The ::hide signal is emitted when an actor is no longer rendered
6466    * on the stage.
6467    *
6468    * Since: 0.2
6469    */
6470   actor_signals[HIDE] =
6471     g_signal_new (I_("hide"),
6472                   G_TYPE_FROM_CLASS (object_class),
6473                   G_SIGNAL_RUN_FIRST,
6474                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6475                   NULL, NULL,
6476                   _clutter_marshal_VOID__VOID,
6477                   G_TYPE_NONE, 0);
6478   /**
6479    * ClutterActor::parent-set:
6480    * @actor: the object which received the signal
6481    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6482    *
6483    * This signal is emitted when the parent of the actor changes.
6484    *
6485    * Since: 0.2
6486    */
6487   actor_signals[PARENT_SET] =
6488     g_signal_new (I_("parent-set"),
6489                   G_TYPE_FROM_CLASS (object_class),
6490                   G_SIGNAL_RUN_LAST,
6491                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6492                   NULL, NULL,
6493                   _clutter_marshal_VOID__OBJECT,
6494                   G_TYPE_NONE, 1,
6495                   CLUTTER_TYPE_ACTOR);
6496
6497   /**
6498    * ClutterActor::queue-redraw:
6499    * @actor: the actor we're bubbling the redraw request through
6500    * @origin: the actor which initiated the redraw request
6501    *
6502    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6503    * is called on @origin.
6504    *
6505    * The default implementation for #ClutterActor chains up to the
6506    * parent actor and queues a redraw on the parent, thus "bubbling"
6507    * the redraw queue up through the actor graph. The default
6508    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6509    * in a main loop idle handler.
6510    *
6511    * Note that the @origin actor may be the stage, or a container; it
6512    * does not have to be a leaf node in the actor graph.
6513    *
6514    * Toolkits embedding a #ClutterStage which require a redraw and
6515    * relayout cycle can stop the emission of this signal using the
6516    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6517    * themselves, like:
6518    *
6519    * |[
6520    *   static void
6521    *   on_redraw_complete (gpointer data)
6522    *   {
6523    *     ClutterStage *stage = data;
6524    *
6525    *     /&ast; execute the Clutter drawing pipeline &ast;/
6526    *     clutter_stage_ensure_redraw (stage);
6527    *   }
6528    *
6529    *   static void
6530    *   on_stage_queue_redraw (ClutterStage *stage)
6531    *   {
6532    *     /&ast; this prevents the default handler to run &ast;/
6533    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6534    *
6535    *     /&ast; queue a redraw with the host toolkit and call
6536    *      &ast; a function when the redraw has been completed
6537    *      &ast;/
6538    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6539    *   }
6540    * ]|
6541    *
6542    * <note><para>This signal is emitted before the Clutter paint
6543    * pipeline is executed. If you want to know when the pipeline has
6544    * been completed you should connect to the ::paint signal on the
6545    * Stage with g_signal_connect_after().</para></note>
6546    *
6547    * Since: 1.0
6548    */
6549   actor_signals[QUEUE_REDRAW] =
6550     g_signal_new (I_("queue-redraw"),
6551                   G_TYPE_FROM_CLASS (object_class),
6552                   G_SIGNAL_RUN_LAST |
6553                   G_SIGNAL_NO_HOOKS,
6554                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6555                   NULL, NULL,
6556                   _clutter_marshal_VOID__OBJECT,
6557                   G_TYPE_NONE, 1,
6558                   CLUTTER_TYPE_ACTOR);
6559
6560   /**
6561    * ClutterActor::queue-relayout
6562    * @actor: the actor being queued for relayout
6563    *
6564    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6565    * is called on an actor.
6566    *
6567    * The default implementation for #ClutterActor chains up to the
6568    * parent actor and queues a relayout on the parent, thus "bubbling"
6569    * the relayout queue up through the actor graph.
6570    *
6571    * The main purpose of this signal is to allow relayout to be propagated
6572    * properly in the procense of #ClutterClone actors. Applications will
6573    * not normally need to connect to this signal.
6574    *
6575    * Since: 1.2
6576    */
6577   actor_signals[QUEUE_RELAYOUT] =
6578     g_signal_new (I_("queue-relayout"),
6579                   G_TYPE_FROM_CLASS (object_class),
6580                   G_SIGNAL_RUN_LAST |
6581                   G_SIGNAL_NO_HOOKS,
6582                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6583                   NULL, NULL,
6584                   _clutter_marshal_VOID__VOID,
6585                   G_TYPE_NONE, 0);
6586
6587   /**
6588    * ClutterActor::event:
6589    * @actor: the actor which received the event
6590    * @event: a #ClutterEvent
6591    *
6592    * The ::event signal is emitted each time an event is received
6593    * by the @actor. This signal will be emitted on every actor,
6594    * following the hierarchy chain, until it reaches the top-level
6595    * container (the #ClutterStage).
6596    *
6597    * Return value: %TRUE if the event has been handled by the actor,
6598    *   or %FALSE to continue the emission.
6599    *
6600    * Since: 0.6
6601    */
6602   actor_signals[EVENT] =
6603     g_signal_new (I_("event"),
6604                   G_TYPE_FROM_CLASS (object_class),
6605                   G_SIGNAL_RUN_LAST,
6606                   G_STRUCT_OFFSET (ClutterActorClass, event),
6607                   _clutter_boolean_handled_accumulator, NULL,
6608                   _clutter_marshal_BOOLEAN__BOXED,
6609                   G_TYPE_BOOLEAN, 1,
6610                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6611   /**
6612    * ClutterActor::button-press-event:
6613    * @actor: the actor which received the event
6614    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6615    *
6616    * The ::button-press-event signal is emitted each time a mouse button
6617    * is pressed on @actor.
6618    *
6619    * Return value: %TRUE if the event has been handled by the actor,
6620    *   or %FALSE to continue the emission.
6621    *
6622    * Since: 0.6
6623    */
6624   actor_signals[BUTTON_PRESS_EVENT] =
6625     g_signal_new (I_("button-press-event"),
6626                   G_TYPE_FROM_CLASS (object_class),
6627                   G_SIGNAL_RUN_LAST,
6628                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6629                   _clutter_boolean_handled_accumulator, NULL,
6630                   _clutter_marshal_BOOLEAN__BOXED,
6631                   G_TYPE_BOOLEAN, 1,
6632                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6633   /**
6634    * ClutterActor::button-release-event:
6635    * @actor: the actor which received the event
6636    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6637    *
6638    * The ::button-release-event signal is emitted each time a mouse button
6639    * is released on @actor.
6640    *
6641    * Return value: %TRUE if the event has been handled by the actor,
6642    *   or %FALSE to continue the emission.
6643    *
6644    * Since: 0.6
6645    */
6646   actor_signals[BUTTON_RELEASE_EVENT] =
6647     g_signal_new (I_("button-release-event"),
6648                   G_TYPE_FROM_CLASS (object_class),
6649                   G_SIGNAL_RUN_LAST,
6650                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6651                   _clutter_boolean_handled_accumulator, NULL,
6652                   _clutter_marshal_BOOLEAN__BOXED,
6653                   G_TYPE_BOOLEAN, 1,
6654                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6655   /**
6656    * ClutterActor::scroll-event:
6657    * @actor: the actor which received the event
6658    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6659    *
6660    * The ::scroll-event signal is emitted each time the mouse is
6661    * scrolled on @actor
6662    *
6663    * Return value: %TRUE if the event has been handled by the actor,
6664    *   or %FALSE to continue the emission.
6665    *
6666    * Since: 0.6
6667    */
6668   actor_signals[SCROLL_EVENT] =
6669     g_signal_new (I_("scroll-event"),
6670                   G_TYPE_FROM_CLASS (object_class),
6671                   G_SIGNAL_RUN_LAST,
6672                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6673                   _clutter_boolean_handled_accumulator, NULL,
6674                   _clutter_marshal_BOOLEAN__BOXED,
6675                   G_TYPE_BOOLEAN, 1,
6676                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6677   /**
6678    * ClutterActor::key-press-event:
6679    * @actor: the actor which received the event
6680    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6681    *
6682    * The ::key-press-event signal is emitted each time a keyboard button
6683    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6684    *
6685    * Return value: %TRUE if the event has been handled by the actor,
6686    *   or %FALSE to continue the emission.
6687    *
6688    * Since: 0.6
6689    */
6690   actor_signals[KEY_PRESS_EVENT] =
6691     g_signal_new (I_("key-press-event"),
6692                   G_TYPE_FROM_CLASS (object_class),
6693                   G_SIGNAL_RUN_LAST,
6694                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6695                   _clutter_boolean_handled_accumulator, NULL,
6696                   _clutter_marshal_BOOLEAN__BOXED,
6697                   G_TYPE_BOOLEAN, 1,
6698                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6699   /**
6700    * ClutterActor::key-release-event:
6701    * @actor: the actor which received the event
6702    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6703    *
6704    * The ::key-release-event signal is emitted each time a keyboard button
6705    * is released while @actor has key focus (see
6706    * clutter_stage_set_key_focus()).
6707    *
6708    * Return value: %TRUE if the event has been handled by the actor,
6709    *   or %FALSE to continue the emission.
6710    *
6711    * Since: 0.6
6712    */
6713   actor_signals[KEY_RELEASE_EVENT] =
6714     g_signal_new (I_("key-release-event"),
6715                   G_TYPE_FROM_CLASS (object_class),
6716                   G_SIGNAL_RUN_LAST,
6717                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6718                   _clutter_boolean_handled_accumulator, NULL,
6719                   _clutter_marshal_BOOLEAN__BOXED,
6720                   G_TYPE_BOOLEAN, 1,
6721                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6722   /**
6723    * ClutterActor::motion-event:
6724    * @actor: the actor which received the event
6725    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6726    *
6727    * The ::motion-event signal is emitted each time the mouse pointer is
6728    * moved over @actor.
6729    *
6730    * Return value: %TRUE if the event has been handled by the actor,
6731    *   or %FALSE to continue the emission.
6732    *
6733    * Since: 0.6
6734    */
6735   actor_signals[MOTION_EVENT] =
6736     g_signal_new (I_("motion-event"),
6737                   G_TYPE_FROM_CLASS (object_class),
6738                   G_SIGNAL_RUN_LAST,
6739                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6740                   _clutter_boolean_handled_accumulator, NULL,
6741                   _clutter_marshal_BOOLEAN__BOXED,
6742                   G_TYPE_BOOLEAN, 1,
6743                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6744
6745   /**
6746    * ClutterActor::key-focus-in:
6747    * @actor: the actor which now has key focus
6748    *
6749    * The ::key-focus-in signal is emitted when @actor receives key focus.
6750    *
6751    * Since: 0.6
6752    */
6753   actor_signals[KEY_FOCUS_IN] =
6754     g_signal_new (I_("key-focus-in"),
6755                   G_TYPE_FROM_CLASS (object_class),
6756                   G_SIGNAL_RUN_LAST,
6757                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6758                   NULL, NULL,
6759                   _clutter_marshal_VOID__VOID,
6760                   G_TYPE_NONE, 0);
6761
6762   /**
6763    * ClutterActor::key-focus-out:
6764    * @actor: the actor which now has key focus
6765    *
6766    * The ::key-focus-out signal is emitted when @actor loses key focus.
6767    *
6768    * Since: 0.6
6769    */
6770   actor_signals[KEY_FOCUS_OUT] =
6771     g_signal_new (I_("key-focus-out"),
6772                   G_TYPE_FROM_CLASS (object_class),
6773                   G_SIGNAL_RUN_LAST,
6774                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6775                   NULL, NULL,
6776                   _clutter_marshal_VOID__VOID,
6777                   G_TYPE_NONE, 0);
6778
6779   /**
6780    * ClutterActor::enter-event:
6781    * @actor: the actor which the pointer has entered.
6782    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6783    *
6784    * The ::enter-event signal is emitted when the pointer enters the @actor
6785    *
6786    * Return value: %TRUE if the event has been handled by the actor,
6787    *   or %FALSE to continue the emission.
6788    *
6789    * Since: 0.6
6790    */
6791   actor_signals[ENTER_EVENT] =
6792     g_signal_new (I_("enter-event"),
6793                   G_TYPE_FROM_CLASS (object_class),
6794                   G_SIGNAL_RUN_LAST,
6795                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6796                   _clutter_boolean_handled_accumulator, NULL,
6797                   _clutter_marshal_BOOLEAN__BOXED,
6798                   G_TYPE_BOOLEAN, 1,
6799                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6800
6801   /**
6802    * ClutterActor::leave-event:
6803    * @actor: the actor which the pointer has left
6804    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6805    *
6806    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6807    *
6808    * Return value: %TRUE if the event has been handled by the actor,
6809    *   or %FALSE to continue the emission.
6810    *
6811    * Since: 0.6
6812    */
6813   actor_signals[LEAVE_EVENT] =
6814     g_signal_new (I_("leave-event"),
6815                   G_TYPE_FROM_CLASS (object_class),
6816                   G_SIGNAL_RUN_LAST,
6817                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6818                   _clutter_boolean_handled_accumulator, NULL,
6819                   _clutter_marshal_BOOLEAN__BOXED,
6820                   G_TYPE_BOOLEAN, 1,
6821                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6822
6823   /**
6824    * ClutterActor::captured-event:
6825    * @actor: the actor which received the signal
6826    * @event: a #ClutterEvent
6827    *
6828    * The ::captured-event signal is emitted when an event is captured
6829    * by Clutter. This signal will be emitted starting from the top-level
6830    * container (the #ClutterStage) to the actor which received the event
6831    * going down the hierarchy. This signal can be used to intercept every
6832    * event before the specialized events (like
6833    * ClutterActor::button-press-event or ::key-released-event) are
6834    * emitted.
6835    *
6836    * Return value: %TRUE if the event has been handled by the actor,
6837    *   or %FALSE to continue the emission.
6838    *
6839    * Since: 0.6
6840    */
6841   actor_signals[CAPTURED_EVENT] =
6842     g_signal_new (I_("captured-event"),
6843                   G_TYPE_FROM_CLASS (object_class),
6844                   G_SIGNAL_RUN_LAST,
6845                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6846                   _clutter_boolean_handled_accumulator, NULL,
6847                   _clutter_marshal_BOOLEAN__BOXED,
6848                   G_TYPE_BOOLEAN, 1,
6849                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6850
6851   /**
6852    * ClutterActor::paint:
6853    * @actor: the #ClutterActor that received the signal
6854    *
6855    * The ::paint signal is emitted each time an actor is being painted.
6856    *
6857    * Subclasses of #ClutterActor should override the class signal handler
6858    * and paint themselves in that function.
6859    *
6860    * It is possible to connect a handler to the ::paint signal in order
6861    * to set up some custom aspect of a paint.
6862    *
6863    * Since: 0.8
6864    */
6865   actor_signals[PAINT] =
6866     g_signal_new (I_("paint"),
6867                   G_TYPE_FROM_CLASS (object_class),
6868                   G_SIGNAL_RUN_LAST |
6869                   G_SIGNAL_NO_HOOKS,
6870                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6871                   NULL, NULL,
6872                   _clutter_marshal_VOID__VOID,
6873                   G_TYPE_NONE, 0);
6874   /**
6875    * ClutterActor::realize:
6876    * @actor: the #ClutterActor that received the signal
6877    *
6878    * The ::realize signal is emitted each time an actor is being
6879    * realized.
6880    *
6881    * Since: 0.8
6882    */
6883   actor_signals[REALIZE] =
6884     g_signal_new (I_("realize"),
6885                   G_TYPE_FROM_CLASS (object_class),
6886                   G_SIGNAL_RUN_LAST,
6887                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6888                   NULL, NULL,
6889                   _clutter_marshal_VOID__VOID,
6890                   G_TYPE_NONE, 0);
6891   /**
6892    * ClutterActor::unrealize:
6893    * @actor: the #ClutterActor that received the signal
6894    *
6895    * The ::unrealize signal is emitted each time an actor is being
6896    * unrealized.
6897    *
6898    * Since: 0.8
6899    */
6900   actor_signals[UNREALIZE] =
6901     g_signal_new (I_("unrealize"),
6902                   G_TYPE_FROM_CLASS (object_class),
6903                   G_SIGNAL_RUN_LAST,
6904                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6905                   NULL, NULL,
6906                   _clutter_marshal_VOID__VOID,
6907                   G_TYPE_NONE, 0);
6908
6909   /**
6910    * ClutterActor::pick:
6911    * @actor: the #ClutterActor that received the signal
6912    * @color: the #ClutterColor to be used when picking
6913    *
6914    * The ::pick signal is emitted each time an actor is being painted
6915    * in "pick mode". The pick mode is used to identify the actor during
6916    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6917    * The actor should paint its shape using the passed @pick_color.
6918    *
6919    * Subclasses of #ClutterActor should override the class signal handler
6920    * and paint themselves in that function.
6921    *
6922    * It is possible to connect a handler to the ::pick signal in order
6923    * to set up some custom aspect of a paint in pick mode.
6924    *
6925    * Since: 1.0
6926    */
6927   actor_signals[PICK] =
6928     g_signal_new (I_("pick"),
6929                   G_TYPE_FROM_CLASS (object_class),
6930                   G_SIGNAL_RUN_LAST,
6931                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6932                   NULL, NULL,
6933                   _clutter_marshal_VOID__BOXED,
6934                   G_TYPE_NONE, 1,
6935                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6936
6937   /**
6938    * ClutterActor::allocation-changed:
6939    * @actor: the #ClutterActor that emitted the signal
6940    * @box: a #ClutterActorBox with the new allocation
6941    * @flags: #ClutterAllocationFlags for the allocation
6942    *
6943    * The ::allocation-changed signal is emitted when the
6944    * #ClutterActor:allocation property changes. Usually, application
6945    * code should just use the notifications for the :allocation property
6946    * but if you want to track the allocation flags as well, for instance
6947    * to know whether the absolute origin of @actor changed, then you might
6948    * want use this signal instead.
6949    *
6950    * Since: 1.0
6951    */
6952   actor_signals[ALLOCATION_CHANGED] =
6953     g_signal_new (I_("allocation-changed"),
6954                   G_TYPE_FROM_CLASS (object_class),
6955                   G_SIGNAL_RUN_LAST,
6956                   0,
6957                   NULL, NULL,
6958                   _clutter_marshal_VOID__BOXED_FLAGS,
6959                   G_TYPE_NONE, 2,
6960                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6961                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6962
6963   /**
6964    * ClutterActor::transitions-completed:
6965    * @actor: a #ClutterActor
6966    *
6967    * The ::transitions-completed signal is emitted once all transitions
6968    * involving @actor are complete.
6969    *
6970    * Since: 1.10
6971    */
6972   actor_signals[TRANSITIONS_COMPLETED] =
6973     g_signal_new (I_("transitions-completed"),
6974                   G_TYPE_FROM_CLASS (object_class),
6975                   G_SIGNAL_RUN_LAST,
6976                   0,
6977                   NULL, NULL,
6978                   _clutter_marshal_VOID__VOID,
6979                   G_TYPE_NONE, 0);
6980 }
6981
6982 static void
6983 clutter_actor_init (ClutterActor *self)
6984 {
6985   ClutterActorPrivate *priv;
6986
6987   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6988
6989   priv->id = _clutter_context_acquire_id (self);
6990   priv->pick_id = -1;
6991
6992   priv->opacity = 0xff;
6993   priv->show_on_set_parent = TRUE;
6994
6995   priv->needs_width_request = TRUE;
6996   priv->needs_height_request = TRUE;
6997   priv->needs_allocation = TRUE;
6998
6999   priv->cached_width_age = 1;
7000   priv->cached_height_age = 1;
7001
7002   priv->opacity_override = -1;
7003   priv->enable_model_view_transform = TRUE;
7004
7005   /* Initialize an empty paint volume to start with */
7006   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7007   priv->last_paint_volume_valid = TRUE;
7008
7009   priv->transform_valid = FALSE;
7010
7011   /* the default is to stretch the content, to match the
7012    * current behaviour of basically all actors. also, it's
7013    * the easiest thing to compute.
7014    */
7015   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7016   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7017   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7018 }
7019
7020 /**
7021  * clutter_actor_new:
7022  *
7023  * Creates a new #ClutterActor.
7024  *
7025  * A newly created actor has a floating reference, which will be sunk
7026  * when it is added to another actor.
7027  *
7028  * Return value: (transfer full): the newly created #ClutterActor
7029  *
7030  * Since: 1.10
7031  */
7032 ClutterActor *
7033 clutter_actor_new (void)
7034 {
7035   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7036 }
7037
7038 /**
7039  * clutter_actor_destroy:
7040  * @self: a #ClutterActor
7041  *
7042  * Destroys an actor.  When an actor is destroyed, it will break any
7043  * references it holds to other objects.  If the actor is inside a
7044  * container, the actor will be removed.
7045  *
7046  * When you destroy a container, its children will be destroyed as well.
7047  *
7048  * Note: you cannot destroy the #ClutterStage returned by
7049  * clutter_stage_get_default().
7050  */
7051 void
7052 clutter_actor_destroy (ClutterActor *self)
7053 {
7054   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7055
7056   g_object_ref (self);
7057
7058   /* avoid recursion while destroying */
7059   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7060     {
7061       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7062
7063       g_object_run_dispose (G_OBJECT (self));
7064
7065       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7066     }
7067
7068   g_object_unref (self);
7069 }
7070
7071 void
7072 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7073                                     ClutterPaintVolume *clip)
7074 {
7075   ClutterActorPrivate *priv = self->priv;
7076   ClutterPaintVolume *pv;
7077   gboolean clipped;
7078
7079   /* Remove queue entry early in the process, otherwise a new
7080      queue_redraw() during signal handling could put back this
7081      object in the stage redraw list (but the entry is freed as
7082      soon as we return from this function, causing a segfault
7083      later)
7084   */
7085   priv->queue_redraw_entry = NULL;
7086
7087   /* If we've been explicitly passed a clip volume then there's
7088    * nothing more to calculate, but otherwise the only thing we know
7089    * is that the change is constrained to the given actor.
7090    *
7091    * The idea is that if we know the paint volume for where the actor
7092    * was last drawn (in eye coordinates) and we also have the paint
7093    * volume for where it will be drawn next (in actor coordinates)
7094    * then if we queue a redraw for both these volumes that will cover
7095    * everything that needs to be redrawn to clear the old view and
7096    * show the latest view of the actor.
7097    *
7098    * Don't clip this redraw if we don't know what position we had for
7099    * the previous redraw since we don't know where to set the clip so
7100    * it will clear the actor as it is currently.
7101    */
7102   if (clip)
7103     {
7104       _clutter_actor_set_queue_redraw_clip (self, clip);
7105       clipped = TRUE;
7106     }
7107   else if (G_LIKELY (priv->last_paint_volume_valid))
7108     {
7109       pv = _clutter_actor_get_paint_volume_mutable (self);
7110       if (pv)
7111         {
7112           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7113
7114           /* make sure we redraw the actors old position... */
7115           _clutter_actor_set_queue_redraw_clip (stage,
7116                                                 &priv->last_paint_volume);
7117           _clutter_actor_signal_queue_redraw (stage, stage);
7118           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7119
7120           /* XXX: Ideally the redraw signal would take a clip volume
7121            * argument, but that would be an ABI break. Until we can
7122            * break the ABI we pass the argument out-of-band
7123            */
7124
7125           /* setup the clip for the actors new position... */
7126           _clutter_actor_set_queue_redraw_clip (self, pv);
7127           clipped = TRUE;
7128         }
7129       else
7130         clipped = FALSE;
7131     }
7132   else
7133     clipped = FALSE;
7134
7135   _clutter_actor_signal_queue_redraw (self, self);
7136
7137   /* Just in case anyone is manually firing redraw signals without
7138    * using the public queue_redraw() API we are careful to ensure that
7139    * our out-of-band clip member is cleared before returning...
7140    *
7141    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7142    */
7143   if (G_LIKELY (clipped))
7144     _clutter_actor_set_queue_redraw_clip (self, NULL);
7145 }
7146
7147 static void
7148 _clutter_actor_get_allocation_clip (ClutterActor *self,
7149                                     ClutterActorBox *clip)
7150 {
7151   ClutterActorBox allocation;
7152
7153   /* XXX: we don't care if we get an out of date allocation here
7154    * because clutter_actor_queue_redraw_with_clip knows to ignore
7155    * the clip if the actor's allocation is invalid.
7156    *
7157    * This is noted because clutter_actor_get_allocation_box does some
7158    * unnecessary work to support buggy code with a comment suggesting
7159    * that it could be changed later which would be good for this use
7160    * case!
7161    */
7162   clutter_actor_get_allocation_box (self, &allocation);
7163
7164   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7165    * actor's own coordinate space but the allocation is in parent
7166    * coordinates */
7167   clip->x1 = 0;
7168   clip->y1 = 0;
7169   clip->x2 = allocation.x2 - allocation.x1;
7170   clip->y2 = allocation.y2 - allocation.y1;
7171 }
7172
7173 void
7174 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7175                                   ClutterRedrawFlags  flags,
7176                                   ClutterPaintVolume *volume,
7177                                   ClutterEffect      *effect)
7178 {
7179   ClutterActorPrivate *priv = self->priv;
7180   ClutterPaintVolume allocation_pv;
7181   ClutterPaintVolume *pv;
7182   gboolean should_free_pv;
7183   ClutterActor *stage;
7184
7185   /* Here's an outline of the actor queue redraw mechanism:
7186    *
7187    * The process starts in one of the following two functions which
7188    * are wrappers for this function:
7189    * clutter_actor_queue_redraw
7190    * _clutter_actor_queue_redraw_with_clip
7191    *
7192    * additionally, an effect can queue a redraw by wrapping this
7193    * function in clutter_effect_queue_rerun
7194    *
7195    * This functions queues an entry in a list associated with the
7196    * stage which is a list of actors that queued a redraw while
7197    * updating the timelines, performing layouting and processing other
7198    * mainloop sources before the next paint starts.
7199    *
7200    * We aim to minimize the processing done at this point because
7201    * there is a good chance other events will happen while updating
7202    * the scenegraph that would invalidate any expensive work we might
7203    * otherwise try to do here. For example we don't try and resolve
7204    * the screen space bounding box of an actor at this stage so as to
7205    * minimize how much of the screen redraw because it's possible
7206    * something else will happen which will force a full redraw anyway.
7207    *
7208    * When all updates are complete and we come to paint the stage then
7209    * we iterate this list and actually emit the "queue-redraw" signals
7210    * for each of the listed actors which will bubble up to the stage
7211    * for each actor and at that point we will transform the actors
7212    * paint volume into screen coordinates to determine the clip region
7213    * for what needs to be redrawn in the next paint.
7214    *
7215    * Besides minimizing redundant work another reason for this
7216    * deferred design is that it's more likely we will be able to
7217    * determine the paint volume of an actor once we've finished
7218    * updating the scenegraph because its allocation should be up to
7219    * date. NB: If we can't determine an actors paint volume then we
7220    * can't automatically queue a clipped redraw which can make a big
7221    * difference to performance.
7222    *
7223    * So the control flow goes like this:
7224    * One of clutter_actor_queue_redraw,
7225    *        _clutter_actor_queue_redraw_with_clip
7226    *     or clutter_effect_queue_rerun
7227    *
7228    * then control moves to:
7229    *   _clutter_stage_queue_actor_redraw
7230    *
7231    * later during _clutter_stage_do_update, once relayouting is done
7232    * and the scenegraph has been updated we will call:
7233    * _clutter_stage_finish_queue_redraws
7234    *
7235    * _clutter_stage_finish_queue_redraws will call
7236    * _clutter_actor_finish_queue_redraw for each listed actor.
7237    * Note: actors *are* allowed to queue further redraws during this
7238    * process (considering clone actors or texture_new_from_actor which
7239    * respond to their source queueing a redraw by queuing a redraw
7240    * themselves). We repeat the process until the list is empty.
7241    *
7242    * This will result in the "queue-redraw" signal being fired for
7243    * each actor which will pass control to the default signal handler:
7244    * clutter_actor_real_queue_redraw
7245    *
7246    * This will bubble up to the stages handler:
7247    * clutter_stage_real_queue_redraw
7248    *
7249    * clutter_stage_real_queue_redraw will transform the actors paint
7250    * volume into screen space and add it as a clip region for the next
7251    * paint.
7252    */
7253
7254   /* ignore queueing a redraw for actors being destroyed */
7255   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7256     return;
7257
7258   stage = _clutter_actor_get_stage_internal (self);
7259
7260   /* Ignore queueing a redraw for actors not descended from a stage */
7261   if (stage == NULL)
7262     return;
7263
7264   /* ignore queueing a redraw on stages that are being destroyed */
7265   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7266     return;
7267
7268   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7269     {
7270       ClutterActorBox allocation_clip;
7271       ClutterVertex origin;
7272
7273       /* If the actor doesn't have a valid allocation then we will
7274        * queue a full stage redraw. */
7275       if (priv->needs_allocation)
7276         {
7277           /* NB: NULL denotes an undefined clip which will result in a
7278            * full redraw... */
7279           _clutter_actor_set_queue_redraw_clip (self, NULL);
7280           _clutter_actor_signal_queue_redraw (self, self);
7281           return;
7282         }
7283
7284       _clutter_paint_volume_init_static (&allocation_pv, self);
7285       pv = &allocation_pv;
7286
7287       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7288
7289       origin.x = allocation_clip.x1;
7290       origin.y = allocation_clip.y1;
7291       origin.z = 0;
7292       clutter_paint_volume_set_origin (pv, &origin);
7293       clutter_paint_volume_set_width (pv,
7294                                       allocation_clip.x2 - allocation_clip.x1);
7295       clutter_paint_volume_set_height (pv,
7296                                        allocation_clip.y2 -
7297                                        allocation_clip.y1);
7298       should_free_pv = TRUE;
7299     }
7300   else
7301     {
7302       pv = volume;
7303       should_free_pv = FALSE;
7304     }
7305
7306   self->priv->queue_redraw_entry =
7307     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7308                                        priv->queue_redraw_entry,
7309                                        self,
7310                                        pv);
7311
7312   if (should_free_pv)
7313     clutter_paint_volume_free (pv);
7314
7315   /* If this is the first redraw queued then we can directly use the
7316      effect parameter */
7317   if (!priv->is_dirty)
7318     priv->effect_to_redraw = effect;
7319   /* Otherwise we need to merge it with the existing effect parameter */
7320   else if (effect != NULL)
7321     {
7322       /* If there's already an effect then we need to use whichever is
7323          later in the chain of actors. Otherwise a full redraw has
7324          already been queued on the actor so we need to ignore the
7325          effect parameter */
7326       if (priv->effect_to_redraw != NULL)
7327         {
7328           if (priv->effects == NULL)
7329             g_warning ("Redraw queued with an effect that is "
7330                        "not applied to the actor");
7331           else
7332             {
7333               const GList *l;
7334
7335               for (l = _clutter_meta_group_peek_metas (priv->effects);
7336                    l != NULL;
7337                    l = l->next)
7338                 {
7339                   if (l->data == priv->effect_to_redraw ||
7340                       l->data == effect)
7341                     priv->effect_to_redraw = l->data;
7342                 }
7343             }
7344         }
7345     }
7346   else
7347     {
7348       /* If no effect is specified then we need to redraw the whole
7349          actor */
7350       priv->effect_to_redraw = NULL;
7351     }
7352
7353   priv->is_dirty = TRUE;
7354 }
7355
7356 /**
7357  * clutter_actor_queue_redraw:
7358  * @self: A #ClutterActor
7359  *
7360  * Queues up a redraw of an actor and any children. The redraw occurs
7361  * once the main loop becomes idle (after the current batch of events
7362  * has been processed, roughly).
7363  *
7364  * Applications rarely need to call this, as redraws are handled
7365  * automatically by modification functions.
7366  *
7367  * This function will not do anything if @self is not visible, or
7368  * if the actor is inside an invisible part of the scenegraph.
7369  *
7370  * Also be aware that painting is a NOP for actors with an opacity of
7371  * 0
7372  *
7373  * When you are implementing a custom actor you must queue a redraw
7374  * whenever some private state changes that will affect painting or
7375  * picking of your actor.
7376  */
7377 void
7378 clutter_actor_queue_redraw (ClutterActor *self)
7379 {
7380   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7381
7382   _clutter_actor_queue_redraw_full (self,
7383                                     0, /* flags */
7384                                     NULL, /* clip volume */
7385                                     NULL /* effect */);
7386 }
7387
7388 /*< private >
7389  * _clutter_actor_queue_redraw_with_clip:
7390  * @self: A #ClutterActor
7391  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7392  *   this queue redraw.
7393  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7394  *   redrawn or %NULL if you are just using a @flag to state your
7395  *   desired clipping.
7396  *
7397  * Queues up a clipped redraw of an actor and any children. The redraw
7398  * occurs once the main loop becomes idle (after the current batch of
7399  * events has been processed, roughly).
7400  *
7401  * If no flags are given the clip volume is defined by @volume
7402  * specified in actor coordinates and tells Clutter that only content
7403  * within this volume has been changed so Clutter can optionally
7404  * optimize the redraw.
7405  *
7406  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7407  * should be %NULL and this tells Clutter to use the actor's current
7408  * allocation as a clip box. This flag can only be used for 2D actors,
7409  * because any actor with depth may be projected outside its
7410  * allocation.
7411  *
7412  * Applications rarely need to call this, as redraws are handled
7413  * automatically by modification functions.
7414  *
7415  * This function will not do anything if @self is not visible, or if
7416  * the actor is inside an invisible part of the scenegraph.
7417  *
7418  * Also be aware that painting is a NOP for actors with an opacity of
7419  * 0
7420  *
7421  * When you are implementing a custom actor you must queue a redraw
7422  * whenever some private state changes that will affect painting or
7423  * picking of your actor.
7424  */
7425 void
7426 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7427                                        ClutterRedrawFlags  flags,
7428                                        ClutterPaintVolume *volume)
7429 {
7430   _clutter_actor_queue_redraw_full (self,
7431                                     flags, /* flags */
7432                                     volume, /* clip volume */
7433                                     NULL /* effect */);
7434 }
7435
7436 static void
7437 _clutter_actor_queue_only_relayout (ClutterActor *self)
7438 {
7439   ClutterActorPrivate *priv = self->priv;
7440
7441   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7442     return;
7443
7444   if (priv->needs_width_request &&
7445       priv->needs_height_request &&
7446       priv->needs_allocation)
7447     return; /* save some cpu cycles */
7448
7449 #if CLUTTER_ENABLE_DEBUG
7450   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7451     {
7452       g_warning ("The actor '%s' is currently inside an allocation "
7453                  "cycle; calling clutter_actor_queue_relayout() is "
7454                  "not recommended",
7455                  _clutter_actor_get_debug_name (self));
7456     }
7457 #endif /* CLUTTER_ENABLE_DEBUG */
7458
7459   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7460 }
7461
7462 /**
7463  * clutter_actor_queue_redraw_with_clip:
7464  * @self: a #ClutterActor
7465  * @clip: (allow-none): a rectangular clip region, or %NULL
7466  *
7467  * Queues a redraw on @self limited to a specific, actor-relative
7468  * rectangular area.
7469  *
7470  * If @clip is %NULL this function is equivalent to
7471  * clutter_actor_queue_redraw().
7472  *
7473  * Since: 1.10
7474  */
7475 void
7476 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7477                                       const cairo_rectangle_int_t *clip)
7478 {
7479   ClutterPaintVolume volume;
7480   ClutterVertex origin;
7481
7482   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7483
7484   if (clip == NULL)
7485     {
7486       clutter_actor_queue_redraw (self);
7487       return;
7488     }
7489
7490   _clutter_paint_volume_init_static (&volume, self);
7491
7492   origin.x = clip->x;
7493   origin.y = clip->y;
7494   origin.z = 0.0f;
7495
7496   clutter_paint_volume_set_origin (&volume, &origin);
7497   clutter_paint_volume_set_width (&volume, clip->width);
7498   clutter_paint_volume_set_height (&volume, clip->height);
7499
7500   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7501
7502   clutter_paint_volume_free (&volume);
7503 }
7504
7505 /**
7506  * clutter_actor_queue_relayout:
7507  * @self: A #ClutterActor
7508  *
7509  * Indicates that the actor's size request or other layout-affecting
7510  * properties may have changed. This function is used inside #ClutterActor
7511  * subclass implementations, not by applications directly.
7512  *
7513  * Queueing a new layout automatically queues a redraw as well.
7514  *
7515  * Since: 0.8
7516  */
7517 void
7518 clutter_actor_queue_relayout (ClutterActor *self)
7519 {
7520   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7521
7522   _clutter_actor_queue_only_relayout (self);
7523   clutter_actor_queue_redraw (self);
7524 }
7525
7526 /**
7527  * clutter_actor_get_preferred_size:
7528  * @self: a #ClutterActor
7529  * @min_width_p: (out) (allow-none): return location for the minimum
7530  *   width, or %NULL
7531  * @min_height_p: (out) (allow-none): return location for the minimum
7532  *   height, or %NULL
7533  * @natural_width_p: (out) (allow-none): return location for the natural
7534  *   width, or %NULL
7535  * @natural_height_p: (out) (allow-none): return location for the natural
7536  *   height, or %NULL
7537  *
7538  * Computes the preferred minimum and natural size of an actor, taking into
7539  * account the actor's geometry management (either height-for-width
7540  * or width-for-height).
7541  *
7542  * The width and height used to compute the preferred height and preferred
7543  * width are the actor's natural ones.
7544  *
7545  * If you need to control the height for the preferred width, or the width for
7546  * the preferred height, you should use clutter_actor_get_preferred_width()
7547  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7548  * geometry management using the #ClutterActor:request-mode property.
7549  *
7550  * Since: 0.8
7551  */
7552 void
7553 clutter_actor_get_preferred_size (ClutterActor *self,
7554                                   gfloat       *min_width_p,
7555                                   gfloat       *min_height_p,
7556                                   gfloat       *natural_width_p,
7557                                   gfloat       *natural_height_p)
7558 {
7559   ClutterActorPrivate *priv;
7560   gfloat min_width, min_height;
7561   gfloat natural_width, natural_height;
7562
7563   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7564
7565   priv = self->priv;
7566
7567   min_width = min_height = 0;
7568   natural_width = natural_height = 0;
7569
7570   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7571     {
7572       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7573       clutter_actor_get_preferred_width (self, -1,
7574                                          &min_width,
7575                                          &natural_width);
7576       clutter_actor_get_preferred_height (self, natural_width,
7577                                           &min_height,
7578                                           &natural_height);
7579     }
7580   else
7581     {
7582       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7583       clutter_actor_get_preferred_height (self, -1,
7584                                           &min_height,
7585                                           &natural_height);
7586       clutter_actor_get_preferred_width (self, natural_height,
7587                                          &min_width,
7588                                          &natural_width);
7589     }
7590
7591   if (min_width_p)
7592     *min_width_p = min_width;
7593
7594   if (min_height_p)
7595     *min_height_p = min_height;
7596
7597   if (natural_width_p)
7598     *natural_width_p = natural_width;
7599
7600   if (natural_height_p)
7601     *natural_height_p = natural_height;
7602 }
7603
7604 /*< private >
7605  * effective_align:
7606  * @align: a #ClutterActorAlign
7607  * @direction: a #ClutterTextDirection
7608  *
7609  * Retrieves the correct alignment depending on the text direction
7610  *
7611  * Return value: the effective alignment
7612  */
7613 static ClutterActorAlign
7614 effective_align (ClutterActorAlign    align,
7615                  ClutterTextDirection direction)
7616 {
7617   ClutterActorAlign res;
7618
7619   switch (align)
7620     {
7621     case CLUTTER_ACTOR_ALIGN_START:
7622       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7623           ? CLUTTER_ACTOR_ALIGN_END
7624           : CLUTTER_ACTOR_ALIGN_START;
7625       break;
7626
7627     case CLUTTER_ACTOR_ALIGN_END:
7628       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7629           ? CLUTTER_ACTOR_ALIGN_START
7630           : CLUTTER_ACTOR_ALIGN_END;
7631       break;
7632
7633     default:
7634       res = align;
7635       break;
7636     }
7637
7638   return res;
7639 }
7640
7641 static inline void
7642 adjust_for_margin (float  margin_start,
7643                    float  margin_end,
7644                    float *minimum_size,
7645                    float *natural_size,
7646                    float *allocated_start,
7647                    float *allocated_end)
7648 {
7649   *minimum_size -= (margin_start + margin_end);
7650   *natural_size -= (margin_start + margin_end);
7651   *allocated_start += margin_start;
7652   *allocated_end -= margin_end;
7653 }
7654
7655 static inline void
7656 adjust_for_alignment (ClutterActorAlign  alignment,
7657                       float              natural_size,
7658                       float             *allocated_start,
7659                       float             *allocated_end)
7660 {
7661   float allocated_size = *allocated_end - *allocated_start;
7662
7663   switch (alignment)
7664     {
7665     case CLUTTER_ACTOR_ALIGN_FILL:
7666       /* do nothing */
7667       break;
7668
7669     case CLUTTER_ACTOR_ALIGN_START:
7670       /* keep start */
7671       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7672       break;
7673
7674     case CLUTTER_ACTOR_ALIGN_END:
7675       if (allocated_size > natural_size)
7676         {
7677           *allocated_start += (allocated_size - natural_size);
7678           *allocated_end = *allocated_start + natural_size;
7679         }
7680       break;
7681
7682     case CLUTTER_ACTOR_ALIGN_CENTER:
7683       if (allocated_size > natural_size)
7684         {
7685           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7686           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7687         }
7688       break;
7689     }
7690 }
7691
7692 /*< private >
7693  * clutter_actor_adjust_width:
7694  * @self: a #ClutterActor
7695  * @minimum_width: (inout): the actor's preferred minimum width, which
7696  *   will be adjusted depending on the margin
7697  * @natural_width: (inout): the actor's preferred natural width, which
7698  *   will be adjusted depending on the margin
7699  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7700  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7701  *
7702  * Adjusts the preferred and allocated position and size of an actor,
7703  * depending on the margin and alignment properties.
7704  */
7705 static void
7706 clutter_actor_adjust_width (ClutterActor *self,
7707                             gfloat       *minimum_width,
7708                             gfloat       *natural_width,
7709                             gfloat       *adjusted_x1,
7710                             gfloat       *adjusted_x2)
7711 {
7712   ClutterTextDirection text_dir;
7713   const ClutterLayoutInfo *info;
7714
7715   info = _clutter_actor_get_layout_info_or_defaults (self);
7716   text_dir = clutter_actor_get_text_direction (self);
7717
7718   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7719
7720   /* this will tweak natural_width to remove the margin, so that
7721    * adjust_for_alignment() will use the correct size
7722    */
7723   adjust_for_margin (info->margin.left, info->margin.right,
7724                      minimum_width, natural_width,
7725                      adjusted_x1, adjusted_x2);
7726
7727   adjust_for_alignment (effective_align (info->x_align, text_dir),
7728                         *natural_width,
7729                         adjusted_x1, adjusted_x2);
7730 }
7731
7732 /*< private >
7733  * clutter_actor_adjust_height:
7734  * @self: a #ClutterActor
7735  * @minimum_height: (inout): the actor's preferred minimum height, which
7736  *   will be adjusted depending on the margin
7737  * @natural_height: (inout): the actor's preferred natural height, which
7738  *   will be adjusted depending on the margin
7739  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7740  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7741  *
7742  * Adjusts the preferred and allocated position and size of an actor,
7743  * depending on the margin and alignment properties.
7744  */
7745 static void
7746 clutter_actor_adjust_height (ClutterActor *self,
7747                              gfloat       *minimum_height,
7748                              gfloat       *natural_height,
7749                              gfloat       *adjusted_y1,
7750                              gfloat       *adjusted_y2)
7751 {
7752   const ClutterLayoutInfo *info;
7753
7754   info = _clutter_actor_get_layout_info_or_defaults (self);
7755
7756   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7757
7758   /* this will tweak natural_height to remove the margin, so that
7759    * adjust_for_alignment() will use the correct size
7760    */
7761   adjust_for_margin (info->margin.top, info->margin.bottom,
7762                      minimum_height, natural_height,
7763                      adjusted_y1,
7764                      adjusted_y2);
7765
7766   /* we don't use effective_align() here, because text direction
7767    * only affects the horizontal axis
7768    */
7769   adjust_for_alignment (info->y_align,
7770                         *natural_height,
7771                         adjusted_y1,
7772                         adjusted_y2);
7773
7774 }
7775
7776 /* looks for a cached size request for this for_size. If not
7777  * found, returns the oldest entry so it can be overwritten */
7778 static gboolean
7779 _clutter_actor_get_cached_size_request (gfloat         for_size,
7780                                         SizeRequest   *cached_size_requests,
7781                                         SizeRequest  **result)
7782 {
7783   guint i;
7784
7785   *result = &cached_size_requests[0];
7786
7787   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7788     {
7789       SizeRequest *sr;
7790
7791       sr = &cached_size_requests[i];
7792
7793       if (sr->age > 0 &&
7794           sr->for_size == for_size)
7795         {
7796           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7797           *result = sr;
7798           return TRUE;
7799         }
7800       else if (sr->age < (*result)->age)
7801         {
7802           *result = sr;
7803         }
7804     }
7805
7806   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7807
7808   return FALSE;
7809 }
7810
7811 /**
7812  * clutter_actor_get_preferred_width:
7813  * @self: A #ClutterActor
7814  * @for_height: available height when computing the preferred width,
7815  *   or a negative value to indicate that no height is defined
7816  * @min_width_p: (out) (allow-none): return location for minimum width,
7817  *   or %NULL
7818  * @natural_width_p: (out) (allow-none): return location for the natural
7819  *   width, or %NULL
7820  *
7821  * Computes the requested minimum and natural widths for an actor,
7822  * optionally depending on the specified height, or if they are
7823  * already computed, returns the cached values.
7824  *
7825  * An actor may not get its request - depending on the layout
7826  * manager that's in effect.
7827  *
7828  * A request should not incorporate the actor's scale or anchor point;
7829  * those transformations do not affect layout, only rendering.
7830  *
7831  * Since: 0.8
7832  */
7833 void
7834 clutter_actor_get_preferred_width (ClutterActor *self,
7835                                    gfloat        for_height,
7836                                    gfloat       *min_width_p,
7837                                    gfloat       *natural_width_p)
7838 {
7839   float request_min_width, request_natural_width;
7840   SizeRequest *cached_size_request;
7841   const ClutterLayoutInfo *info;
7842   ClutterActorPrivate *priv;
7843   gboolean found_in_cache;
7844
7845   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7846
7847   priv = self->priv;
7848
7849   info = _clutter_actor_get_layout_info_or_defaults (self);
7850
7851   /* we shortcircuit the case of a fixed size set using set_width() */
7852   if (priv->min_width_set && priv->natural_width_set)
7853     {
7854       if (min_width_p != NULL)
7855         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7856
7857       if (natural_width_p != NULL)
7858         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7859
7860       return;
7861     }
7862
7863   /* the remaining cases are:
7864    *
7865    *   - either min_width or natural_width have been set
7866    *   - neither min_width or natural_width have been set
7867    *
7868    * in both cases, we go through the cache (and through the actor in case
7869    * of cache misses) and determine the authoritative value depending on
7870    * the *_set flags.
7871    */
7872
7873   if (!priv->needs_width_request)
7874     {
7875       found_in_cache =
7876         _clutter_actor_get_cached_size_request (for_height,
7877                                                 priv->width_requests,
7878                                                 &cached_size_request);
7879     }
7880   else
7881     {
7882       /* if the actor needs a width request we use the first slot */
7883       found_in_cache = FALSE;
7884       cached_size_request = &priv->width_requests[0];
7885     }
7886
7887   if (!found_in_cache)
7888     {
7889       gfloat minimum_width, natural_width;
7890       ClutterActorClass *klass;
7891
7892       minimum_width = natural_width = 0;
7893
7894       /* adjust for the margin */
7895       if (for_height >= 0)
7896         {
7897           for_height -= (info->margin.top + info->margin.bottom);
7898           if (for_height < 0)
7899             for_height = 0;
7900         }
7901
7902       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7903
7904       klass = CLUTTER_ACTOR_GET_CLASS (self);
7905       klass->get_preferred_width (self, for_height,
7906                                   &minimum_width,
7907                                   &natural_width);
7908
7909       /* adjust for the margin */
7910       minimum_width += (info->margin.left + info->margin.right);
7911       natural_width += (info->margin.left + info->margin.right);
7912
7913       /* Due to accumulated float errors, it's better not to warn
7914        * on this, but just fix it.
7915        */
7916       if (natural_width < minimum_width)
7917         natural_width = minimum_width;
7918
7919       cached_size_request->min_size = minimum_width;
7920       cached_size_request->natural_size = natural_width;
7921       cached_size_request->for_size = for_height;
7922       cached_size_request->age = priv->cached_width_age;
7923
7924       priv->cached_width_age += 1;
7925       priv->needs_width_request = FALSE;
7926     }
7927
7928   if (!priv->min_width_set)
7929     request_min_width = cached_size_request->min_size;
7930   else
7931     request_min_width = info->min_width;
7932
7933   if (!priv->natural_width_set)
7934     request_natural_width = cached_size_request->natural_size;
7935   else
7936     request_natural_width = info->natural_width;
7937
7938   if (min_width_p)
7939     *min_width_p = request_min_width;
7940
7941   if (natural_width_p)
7942     *natural_width_p = request_natural_width;
7943 }
7944
7945 /**
7946  * clutter_actor_get_preferred_height:
7947  * @self: A #ClutterActor
7948  * @for_width: available width to assume in computing desired height,
7949  *   or a negative value to indicate that no width is defined
7950  * @min_height_p: (out) (allow-none): return location for minimum height,
7951  *   or %NULL
7952  * @natural_height_p: (out) (allow-none): return location for natural
7953  *   height, or %NULL
7954  *
7955  * Computes the requested minimum and natural heights for an actor,
7956  * or if they are already computed, returns the cached values.
7957  *
7958  * An actor may not get its request - depending on the layout
7959  * manager that's in effect.
7960  *
7961  * A request should not incorporate the actor's scale or anchor point;
7962  * those transformations do not affect layout, only rendering.
7963  *
7964  * Since: 0.8
7965  */
7966 void
7967 clutter_actor_get_preferred_height (ClutterActor *self,
7968                                     gfloat        for_width,
7969                                     gfloat       *min_height_p,
7970                                     gfloat       *natural_height_p)
7971 {
7972   float request_min_height, request_natural_height;
7973   SizeRequest *cached_size_request;
7974   const ClutterLayoutInfo *info;
7975   ClutterActorPrivate *priv;
7976   gboolean found_in_cache;
7977
7978   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7979
7980   priv = self->priv;
7981
7982   info = _clutter_actor_get_layout_info_or_defaults (self);
7983
7984   /* we shortcircuit the case of a fixed size set using set_height() */
7985   if (priv->min_height_set && priv->natural_height_set)
7986     {
7987       if (min_height_p != NULL)
7988         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7989
7990       if (natural_height_p != NULL)
7991         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7992
7993       return;
7994     }
7995
7996   /* the remaining cases are:
7997    *
7998    *   - either min_height or natural_height have been set
7999    *   - neither min_height or natural_height have been set
8000    *
8001    * in both cases, we go through the cache (and through the actor in case
8002    * of cache misses) and determine the authoritative value depending on
8003    * the *_set flags.
8004    */
8005
8006   if (!priv->needs_height_request)
8007     {
8008       found_in_cache =
8009         _clutter_actor_get_cached_size_request (for_width,
8010                                                 priv->height_requests,
8011                                                 &cached_size_request);
8012     }
8013   else
8014     {
8015       found_in_cache = FALSE;
8016       cached_size_request = &priv->height_requests[0];
8017     }
8018
8019   if (!found_in_cache)
8020     {
8021       gfloat minimum_height, natural_height;
8022       ClutterActorClass *klass;
8023
8024       minimum_height = natural_height = 0;
8025
8026       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8027
8028       /* adjust for margin */
8029       if (for_width >= 0)
8030         {
8031           for_width -= (info->margin.left + info->margin.right);
8032           if (for_width < 0)
8033             for_width = 0;
8034         }
8035
8036       klass = CLUTTER_ACTOR_GET_CLASS (self);
8037       klass->get_preferred_height (self, for_width,
8038                                    &minimum_height,
8039                                    &natural_height);
8040
8041       /* adjust for margin */
8042       minimum_height += (info->margin.top + info->margin.bottom);
8043       natural_height += (info->margin.top + info->margin.bottom);
8044
8045       /* Due to accumulated float errors, it's better not to warn
8046        * on this, but just fix it.
8047        */
8048       if (natural_height < minimum_height)
8049         natural_height = minimum_height;
8050
8051       cached_size_request->min_size = minimum_height;
8052       cached_size_request->natural_size = natural_height;
8053       cached_size_request->for_size = for_width;
8054       cached_size_request->age = priv->cached_height_age;
8055
8056       priv->cached_height_age += 1;
8057       priv->needs_height_request = FALSE;
8058     }
8059
8060   if (!priv->min_height_set)
8061     request_min_height = cached_size_request->min_size;
8062   else
8063     request_min_height = info->min_height;
8064
8065   if (!priv->natural_height_set)
8066     request_natural_height = cached_size_request->natural_size;
8067   else
8068     request_natural_height = info->natural_height;
8069
8070   if (min_height_p)
8071     *min_height_p = request_min_height;
8072
8073   if (natural_height_p)
8074     *natural_height_p = request_natural_height;
8075 }
8076
8077 /**
8078  * clutter_actor_get_allocation_box:
8079  * @self: A #ClutterActor
8080  * @box: (out): the function fills this in with the actor's allocation
8081  *
8082  * Gets the layout box an actor has been assigned. The allocation can
8083  * only be assumed valid inside a paint() method; anywhere else, it
8084  * may be out-of-date.
8085  *
8086  * An allocation does not incorporate the actor's scale or anchor point;
8087  * those transformations do not affect layout, only rendering.
8088  *
8089  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8090  * of functions inside the implementation of the get_preferred_width()
8091  * or get_preferred_height() virtual functions.</note>
8092  *
8093  * Since: 0.8
8094  */
8095 void
8096 clutter_actor_get_allocation_box (ClutterActor    *self,
8097                                   ClutterActorBox *box)
8098 {
8099   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8100
8101   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8102    * which limits calling get_allocation to inside paint() basically; or
8103    * we can 2) force a layout, which could be expensive if someone calls
8104    * get_allocation somewhere silly; or we can 3) just return the latest
8105    * value, allowing it to be out-of-date, and assume people know what
8106    * they are doing.
8107    *
8108    * The least-surprises approach that keeps existing code working is
8109    * likely to be 2). People can end up doing some inefficient things,
8110    * though, and in general code that requires 2) is probably broken.
8111    */
8112
8113   /* this implements 2) */
8114   if (G_UNLIKELY (self->priv->needs_allocation))
8115     {
8116       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8117
8118       /* do not queue a relayout on an unparented actor */
8119       if (stage)
8120         _clutter_stage_maybe_relayout (stage);
8121     }
8122
8123   /* commenting out the code above and just keeping this assigment
8124    * implements 3)
8125    */
8126   *box = self->priv->allocation;
8127 }
8128
8129 /**
8130  * clutter_actor_get_allocation_geometry:
8131  * @self: A #ClutterActor
8132  * @geom: (out): allocation geometry in pixels
8133  *
8134  * Gets the layout box an actor has been assigned.  The allocation can
8135  * only be assumed valid inside a paint() method; anywhere else, it
8136  * may be out-of-date.
8137  *
8138  * An allocation does not incorporate the actor's scale or anchor point;
8139  * those transformations do not affect layout, only rendering.
8140  *
8141  * The returned rectangle is in pixels.
8142  *
8143  * Since: 0.8
8144  */
8145 void
8146 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8147                                        ClutterGeometry *geom)
8148 {
8149   ClutterActorBox box;
8150
8151   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8152   g_return_if_fail (geom != NULL);
8153
8154   clutter_actor_get_allocation_box (self, &box);
8155
8156   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8157   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8158   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8159   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8160 }
8161
8162 static void
8163 clutter_actor_update_constraints (ClutterActor    *self,
8164                                   ClutterActorBox *allocation)
8165 {
8166   ClutterActorPrivate *priv = self->priv;
8167   const GList *constraints, *l;
8168
8169   if (priv->constraints == NULL)
8170     return;
8171
8172   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8173   for (l = constraints; l != NULL; l = l->next)
8174     {
8175       ClutterConstraint *constraint = l->data;
8176       ClutterActorMeta *meta = l->data;
8177
8178       if (clutter_actor_meta_get_enabled (meta))
8179         {
8180           _clutter_constraint_update_allocation (constraint,
8181                                                  self,
8182                                                  allocation);
8183
8184           CLUTTER_NOTE (LAYOUT,
8185                         "Allocation of '%s' after constraint '%s': "
8186                         "{ %.2f, %.2f, %.2f, %.2f }",
8187                         _clutter_actor_get_debug_name (self),
8188                         _clutter_actor_meta_get_debug_name (meta),
8189                         allocation->x1,
8190                         allocation->y1,
8191                         allocation->x2,
8192                         allocation->y2);
8193         }
8194     }
8195 }
8196
8197 /*< private >
8198  * clutter_actor_adjust_allocation:
8199  * @self: a #ClutterActor
8200  * @allocation: (inout): the allocation to adjust
8201  *
8202  * Adjusts the passed allocation box taking into account the actor's
8203  * layout information, like alignment, expansion, and margin.
8204  */
8205 static void
8206 clutter_actor_adjust_allocation (ClutterActor    *self,
8207                                  ClutterActorBox *allocation)
8208 {
8209   ClutterActorBox adj_allocation;
8210   float alloc_width, alloc_height;
8211   float min_width, min_height;
8212   float nat_width, nat_height;
8213   ClutterRequestMode req_mode;
8214
8215   adj_allocation = *allocation;
8216
8217   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8218
8219   /* we want to hit the cache, so we use the public API */
8220   req_mode = clutter_actor_get_request_mode (self);
8221
8222   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8223     {
8224       clutter_actor_get_preferred_width (self, -1,
8225                                          &min_width,
8226                                          &nat_width);
8227       clutter_actor_get_preferred_height (self, alloc_width,
8228                                           &min_height,
8229                                           &nat_height);
8230     }
8231   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8232     {
8233       clutter_actor_get_preferred_height (self, -1,
8234                                           &min_height,
8235                                           &nat_height);
8236       clutter_actor_get_preferred_height (self, alloc_height,
8237                                           &min_width,
8238                                           &nat_width);
8239     }
8240
8241 #ifdef CLUTTER_ENABLE_DEBUG
8242   /* warn about underallocations */
8243   if (_clutter_diagnostic_enabled () &&
8244       (floorf (min_width - alloc_width) > 0 ||
8245        floorf (min_height - alloc_height) > 0))
8246     {
8247       ClutterActor *parent = clutter_actor_get_parent (self);
8248
8249       /* the only actors that are allowed to be underallocated are the Stage,
8250        * as it doesn't have an implicit size, and Actors that specifically
8251        * told us that they want to opt-out from layout control mechanisms
8252        * through the NO_LAYOUT escape hatch.
8253        */
8254       if (parent != NULL &&
8255           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8256         {
8257           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8258                      "of %.2f x %.2f from its parent actor '%s', but its "
8259                      "requested minimum size is of %.2f x %.2f",
8260                      _clutter_actor_get_debug_name (self),
8261                      alloc_width, alloc_height,
8262                      _clutter_actor_get_debug_name (parent),
8263                      min_width, min_height);
8264         }
8265     }
8266 #endif
8267
8268   clutter_actor_adjust_width (self,
8269                               &min_width,
8270                               &nat_width,
8271                               &adj_allocation.x1,
8272                               &adj_allocation.x2);
8273
8274   clutter_actor_adjust_height (self,
8275                                &min_height,
8276                                &nat_height,
8277                                &adj_allocation.y1,
8278                                &adj_allocation.y2);
8279
8280   /* we maintain the invariant that an allocation cannot be adjusted
8281    * to be outside the parent-given box
8282    */
8283   if (adj_allocation.x1 < allocation->x1 ||
8284       adj_allocation.y1 < allocation->y1 ||
8285       adj_allocation.x2 > allocation->x2 ||
8286       adj_allocation.y2 > allocation->y2)
8287     {
8288       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8289                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8290                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8291                  _clutter_actor_get_debug_name (self),
8292                  adj_allocation.x1, adj_allocation.y1,
8293                  adj_allocation.x2 - adj_allocation.x1,
8294                  adj_allocation.y2 - adj_allocation.y1,
8295                  allocation->x1, allocation->y1,
8296                  allocation->x2 - allocation->x1,
8297                  allocation->y2 - allocation->y1);
8298       return;
8299     }
8300
8301   *allocation = adj_allocation;
8302 }
8303
8304 /**
8305  * clutter_actor_allocate:
8306  * @self: A #ClutterActor
8307  * @box: new allocation of the actor, in parent-relative coordinates
8308  * @flags: flags that control the allocation
8309  *
8310  * Called by the parent of an actor to assign the actor its size.
8311  * Should never be called by applications (except when implementing
8312  * a container or layout manager).
8313  *
8314  * Actors can know from their allocation box whether they have moved
8315  * with respect to their parent actor. The @flags parameter describes
8316  * additional information about the allocation, for instance whether
8317  * the parent has moved with respect to the stage, for example because
8318  * a grandparent's origin has moved.
8319  *
8320  * Since: 0.8
8321  */
8322 void
8323 clutter_actor_allocate (ClutterActor           *self,
8324                         const ClutterActorBox  *box,
8325                         ClutterAllocationFlags  flags)
8326 {
8327   ClutterActorPrivate *priv;
8328   ClutterActorClass *klass;
8329   ClutterActorBox old_allocation, real_allocation;
8330   gboolean origin_changed, child_moved, size_changed;
8331   gboolean stage_allocation_changed;
8332
8333   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8334   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8335     {
8336       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8337                  "which isn't a descendent of the stage!\n",
8338                  self, _clutter_actor_get_debug_name (self));
8339       return;
8340     }
8341
8342   priv = self->priv;
8343
8344   old_allocation = priv->allocation;
8345   real_allocation = *box;
8346
8347   /* constraints are allowed to modify the allocation only here; we do
8348    * this prior to all the other checks so that we can bail out if the
8349    * allocation did not change
8350    */
8351   clutter_actor_update_constraints (self, &real_allocation);
8352
8353   /* adjust the allocation depending on the align/margin properties */
8354   clutter_actor_adjust_allocation (self, &real_allocation);
8355
8356   if (real_allocation.x2 < real_allocation.x1 ||
8357       real_allocation.y2 < real_allocation.y1)
8358     {
8359       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8360                  _clutter_actor_get_debug_name (self),
8361                  real_allocation.x2 - real_allocation.x1,
8362                  real_allocation.y2 - real_allocation.y1);
8363     }
8364
8365   /* we allow 0-sized actors, but not negative-sized ones */
8366   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8367   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8368
8369   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8370
8371   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8372                  real_allocation.y1 != old_allocation.y1);
8373
8374   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8375                   real_allocation.y2 != old_allocation.y2);
8376
8377   if (origin_changed || child_moved || size_changed)
8378     stage_allocation_changed = TRUE;
8379   else
8380     stage_allocation_changed = FALSE;
8381
8382   /* If we get an allocation "out of the blue"
8383    * (we did not queue relayout), then we want to
8384    * ignore it. But if we have needs_allocation set,
8385    * we want to guarantee that allocate() virtual
8386    * method is always called, i.e. that queue_relayout()
8387    * always results in an allocate() invocation on
8388    * an actor.
8389    *
8390    * The optimization here is to avoid re-allocating
8391    * actors that did not queue relayout and were
8392    * not moved.
8393    */
8394   if (!priv->needs_allocation && !stage_allocation_changed)
8395     {
8396       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8397       return;
8398     }
8399
8400   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8401    * clutter_actor_allocate(), it indicates whether the parent has its
8402    * absolute origin moved; when passed in to ClutterActor::allocate()
8403    * virtual method though, it indicates whether the child has its
8404    * absolute origin moved.  So we set it when child_moved is TRUE
8405    */
8406   if (child_moved)
8407     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8408
8409   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8410
8411   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8412                 _clutter_actor_get_debug_name (self));
8413
8414   klass = CLUTTER_ACTOR_GET_CLASS (self);
8415   klass->allocate (self, &real_allocation, flags);
8416
8417   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8418
8419   if (stage_allocation_changed)
8420     clutter_actor_queue_redraw (self);
8421 }
8422
8423 /**
8424  * clutter_actor_set_allocation:
8425  * @self: a #ClutterActor
8426  * @box: a #ClutterActorBox
8427  * @flags: allocation flags
8428  *
8429  * Stores the allocation of @self as defined by @box.
8430  *
8431  * This function can only be called from within the implementation of
8432  * the #ClutterActorClass.allocate() virtual function.
8433  *
8434  * The allocation should have been adjusted to take into account constraints,
8435  * alignment, and margin properties. If you are implementing a #ClutterActor
8436  * subclass that provides its own layout management policy for its children
8437  * instead of using a #ClutterLayoutManager delegate, you should not call
8438  * this function on the children of @self; instead, you should call
8439  * clutter_actor_allocate(), which will adjust the allocation box for
8440  * you.
8441  *
8442  * This function should only be used by subclasses of #ClutterActor
8443  * that wish to store their allocation but cannot chain up to the
8444  * parent's implementation; the default implementation of the
8445  * #ClutterActorClass.allocate() virtual function will call this
8446  * function.
8447  *
8448  * It is important to note that, while chaining up was the recommended
8449  * behaviour for #ClutterActor subclasses prior to the introduction of
8450  * this function, it is recommended to call clutter_actor_set_allocation()
8451  * instead.
8452  *
8453  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8454  * to handle the allocation of its children, this function will call
8455  * the clutter_layout_manager_allocate() function only if the
8456  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8457  * expected that the subclass will call clutter_layout_manager_allocate()
8458  * by itself. For instance, the following code:
8459  *
8460  * |[
8461  * static void
8462  * my_actor_allocate (ClutterActor *actor,
8463  *                    const ClutterActorBox *allocation,
8464  *                    ClutterAllocationFlags flags)
8465  * {
8466  *   ClutterActorBox new_alloc;
8467  *   ClutterAllocationFlags new_flags;
8468  *
8469  *   adjust_allocation (allocation, &amp;new_alloc);
8470  *
8471  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8472  *
8473  *   /&ast; this will use the layout manager set on the actor &ast;/
8474  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8475  * }
8476  * ]|
8477  *
8478  * is equivalent to this:
8479  *
8480  * |[
8481  * static void
8482  * my_actor_allocate (ClutterActor *actor,
8483  *                    const ClutterActorBox *allocation,
8484  *                    ClutterAllocationFlags flags)
8485  * {
8486  *   ClutterLayoutManager *layout;
8487  *   ClutterActorBox new_alloc;
8488  *
8489  *   adjust_allocation (allocation, &amp;new_alloc);
8490  *
8491  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8492  *
8493  *   layout = clutter_actor_get_layout_manager (actor);
8494  *   clutter_layout_manager_allocate (layout,
8495  *                                    CLUTTER_CONTAINER (actor),
8496  *                                    &amp;new_alloc,
8497  *                                    flags);
8498  * }
8499  * ]|
8500  *
8501  * Since: 1.10
8502  */
8503 void
8504 clutter_actor_set_allocation (ClutterActor           *self,
8505                               const ClutterActorBox  *box,
8506                               ClutterAllocationFlags  flags)
8507 {
8508   ClutterActorPrivate *priv;
8509   gboolean changed;
8510
8511   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8512   g_return_if_fail (box != NULL);
8513
8514   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8515     {
8516       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8517                   "can only be called from within the implementation of "
8518                   "the ClutterActor::allocate() virtual function.");
8519       return;
8520     }
8521
8522   priv = self->priv;
8523
8524   g_object_freeze_notify (G_OBJECT (self));
8525
8526   changed = clutter_actor_set_allocation_internal (self, box, flags);
8527
8528   /* we allocate our children before we notify changes in our geometry,
8529    * so that people connecting to properties will be able to get valid
8530    * data out of the sub-tree of the scene graph that has this actor at
8531    * the root.
8532    */
8533   clutter_actor_maybe_layout_children (self, box, flags);
8534
8535   if (changed)
8536     {
8537       ClutterActorBox signal_box = priv->allocation;
8538       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8539
8540       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8541                      &signal_box,
8542                      signal_flags);
8543     }
8544
8545   g_object_thaw_notify (G_OBJECT (self));
8546 }
8547
8548 /**
8549  * clutter_actor_set_geometry:
8550  * @self: A #ClutterActor
8551  * @geometry: A #ClutterGeometry
8552  *
8553  * Sets the actor's fixed position and forces its minimum and natural
8554  * size, in pixels. This means the untransformed actor will have the
8555  * given geometry. This is the same as calling clutter_actor_set_position()
8556  * and clutter_actor_set_size().
8557  *
8558  * Deprecated: 1.10: Use clutter_actor_set_position() and
8559  *   clutter_actor_set_size() instead.
8560  */
8561 void
8562 clutter_actor_set_geometry (ClutterActor          *self,
8563                             const ClutterGeometry *geometry)
8564 {
8565   g_object_freeze_notify (G_OBJECT (self));
8566
8567   clutter_actor_set_position (self, geometry->x, geometry->y);
8568   clutter_actor_set_size (self, geometry->width, geometry->height);
8569
8570   g_object_thaw_notify (G_OBJECT (self));
8571 }
8572
8573 /**
8574  * clutter_actor_get_geometry:
8575  * @self: A #ClutterActor
8576  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8577  *
8578  * Gets the size and position of an actor relative to its parent
8579  * actor. This is the same as calling clutter_actor_get_position() and
8580  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8581  * requested size and position if the actor's allocation is invalid.
8582  *
8583  * Deprecated: 1.10: Use clutter_actor_get_position() and
8584  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8585  *   instead.
8586  */
8587 void
8588 clutter_actor_get_geometry (ClutterActor    *self,
8589                             ClutterGeometry *geometry)
8590 {
8591   gfloat x, y, width, height;
8592
8593   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8594   g_return_if_fail (geometry != NULL);
8595
8596   clutter_actor_get_position (self, &x, &y);
8597   clutter_actor_get_size (self, &width, &height);
8598
8599   geometry->x = (int) x;
8600   geometry->y = (int) y;
8601   geometry->width = (int) width;
8602   geometry->height = (int) height;
8603 }
8604
8605 /**
8606  * clutter_actor_set_position:
8607  * @self: A #ClutterActor
8608  * @x: New left position of actor in pixels.
8609  * @y: New top position of actor in pixels.
8610  *
8611  * Sets the actor's fixed position in pixels relative to any parent
8612  * actor.
8613  *
8614  * If a layout manager is in use, this position will override the
8615  * layout manager and force a fixed position.
8616  */
8617 void
8618 clutter_actor_set_position (ClutterActor *self,
8619                             gfloat        x,
8620                             gfloat        y)
8621 {
8622   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8623
8624   g_object_freeze_notify (G_OBJECT (self));
8625
8626   clutter_actor_set_x (self, x);
8627   clutter_actor_set_y (self, y);
8628
8629   g_object_thaw_notify (G_OBJECT (self));
8630 }
8631
8632 /**
8633  * clutter_actor_get_fixed_position_set:
8634  * @self: A #ClutterActor
8635  *
8636  * Checks whether an actor has a fixed position set (and will thus be
8637  * unaffected by any layout manager).
8638  *
8639  * Return value: %TRUE if the fixed position is set on the actor
8640  *
8641  * Since: 0.8
8642  */
8643 gboolean
8644 clutter_actor_get_fixed_position_set (ClutterActor *self)
8645 {
8646   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8647
8648   return self->priv->position_set;
8649 }
8650
8651 /**
8652  * clutter_actor_set_fixed_position_set:
8653  * @self: A #ClutterActor
8654  * @is_set: whether to use fixed position
8655  *
8656  * Sets whether an actor has a fixed position set (and will thus be
8657  * unaffected by any layout manager).
8658  *
8659  * Since: 0.8
8660  */
8661 void
8662 clutter_actor_set_fixed_position_set (ClutterActor *self,
8663                                       gboolean      is_set)
8664 {
8665   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8666
8667   if (self->priv->position_set == (is_set != FALSE))
8668     return;
8669
8670   self->priv->position_set = is_set != FALSE;
8671   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8672
8673   clutter_actor_queue_relayout (self);
8674 }
8675
8676 /**
8677  * clutter_actor_move_by:
8678  * @self: A #ClutterActor
8679  * @dx: Distance to move Actor on X axis.
8680  * @dy: Distance to move Actor on Y axis.
8681  *
8682  * Moves an actor by the specified distance relative to its current
8683  * position in pixels.
8684  *
8685  * This function modifies the fixed position of an actor and thus removes
8686  * it from any layout management. Another way to move an actor is with an
8687  * anchor point, see clutter_actor_set_anchor_point().
8688  *
8689  * Since: 0.2
8690  */
8691 void
8692 clutter_actor_move_by (ClutterActor *self,
8693                        gfloat        dx,
8694                        gfloat        dy)
8695 {
8696   const ClutterLayoutInfo *info;
8697   gfloat x, y;
8698
8699   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8700
8701   info = _clutter_actor_get_layout_info_or_defaults (self);
8702   x = info->fixed_x;
8703   y = info->fixed_y;
8704
8705   clutter_actor_set_position (self, x + dx, y + dy);
8706 }
8707
8708 static void
8709 clutter_actor_set_min_width (ClutterActor *self,
8710                              gfloat        min_width)
8711 {
8712   ClutterActorPrivate *priv = self->priv;
8713   ClutterActorBox old = { 0, };
8714   ClutterLayoutInfo *info;
8715
8716   /* if we are setting the size on a top-level actor and the
8717    * backend only supports static top-levels (e.g. framebuffers)
8718    * then we ignore the passed value and we override it with
8719    * the stage implementation's preferred size.
8720    */
8721   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8722       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8723     return;
8724
8725   info = _clutter_actor_get_layout_info (self);
8726
8727   if (priv->min_width_set && min_width == info->min_width)
8728     return;
8729
8730   g_object_freeze_notify (G_OBJECT (self));
8731
8732   clutter_actor_store_old_geometry (self, &old);
8733
8734   info->min_width = min_width;
8735   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8736   clutter_actor_set_min_width_set (self, TRUE);
8737
8738   clutter_actor_notify_if_geometry_changed (self, &old);
8739
8740   g_object_thaw_notify (G_OBJECT (self));
8741
8742   clutter_actor_queue_relayout (self);
8743 }
8744
8745 static void
8746 clutter_actor_set_min_height (ClutterActor *self,
8747                               gfloat        min_height)
8748
8749 {
8750   ClutterActorPrivate *priv = self->priv;
8751   ClutterActorBox old = { 0, };
8752   ClutterLayoutInfo *info;
8753
8754   /* if we are setting the size on a top-level actor and the
8755    * backend only supports static top-levels (e.g. framebuffers)
8756    * then we ignore the passed value and we override it with
8757    * the stage implementation's preferred size.
8758    */
8759   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8760       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8761     return;
8762
8763   info = _clutter_actor_get_layout_info (self);
8764
8765   if (priv->min_height_set && min_height == info->min_height)
8766     return;
8767
8768   g_object_freeze_notify (G_OBJECT (self));
8769
8770   clutter_actor_store_old_geometry (self, &old);
8771
8772   info->min_height = min_height;
8773   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8774   clutter_actor_set_min_height_set (self, TRUE);
8775
8776   clutter_actor_notify_if_geometry_changed (self, &old);
8777
8778   g_object_thaw_notify (G_OBJECT (self));
8779
8780   clutter_actor_queue_relayout (self);
8781 }
8782
8783 static void
8784 clutter_actor_set_natural_width (ClutterActor *self,
8785                                  gfloat        natural_width)
8786 {
8787   ClutterActorPrivate *priv = self->priv;
8788   ClutterActorBox old = { 0, };
8789   ClutterLayoutInfo *info;
8790
8791   /* if we are setting the size on a top-level actor and the
8792    * backend only supports static top-levels (e.g. framebuffers)
8793    * then we ignore the passed value and we override it with
8794    * the stage implementation's preferred size.
8795    */
8796   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8797       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8798     return;
8799
8800   info = _clutter_actor_get_layout_info (self);
8801
8802   if (priv->natural_width_set && natural_width == info->natural_width)
8803     return;
8804
8805   g_object_freeze_notify (G_OBJECT (self));
8806
8807   clutter_actor_store_old_geometry (self, &old);
8808
8809   info->natural_width = natural_width;
8810   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8811   clutter_actor_set_natural_width_set (self, TRUE);
8812
8813   clutter_actor_notify_if_geometry_changed (self, &old);
8814
8815   g_object_thaw_notify (G_OBJECT (self));
8816
8817   clutter_actor_queue_relayout (self);
8818 }
8819
8820 static void
8821 clutter_actor_set_natural_height (ClutterActor *self,
8822                                   gfloat        natural_height)
8823 {
8824   ClutterActorPrivate *priv = self->priv;
8825   ClutterActorBox old = { 0, };
8826   ClutterLayoutInfo *info;
8827
8828   /* if we are setting the size on a top-level actor and the
8829    * backend only supports static top-levels (e.g. framebuffers)
8830    * then we ignore the passed value and we override it with
8831    * the stage implementation's preferred size.
8832    */
8833   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8834       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8835     return;
8836
8837   info = _clutter_actor_get_layout_info (self);
8838
8839   if (priv->natural_height_set && natural_height == info->natural_height)
8840     return;
8841
8842   g_object_freeze_notify (G_OBJECT (self));
8843
8844   clutter_actor_store_old_geometry (self, &old);
8845
8846   info->natural_height = natural_height;
8847   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8848   clutter_actor_set_natural_height_set (self, TRUE);
8849
8850   clutter_actor_notify_if_geometry_changed (self, &old);
8851
8852   g_object_thaw_notify (G_OBJECT (self));
8853
8854   clutter_actor_queue_relayout (self);
8855 }
8856
8857 static void
8858 clutter_actor_set_min_width_set (ClutterActor *self,
8859                                  gboolean      use_min_width)
8860 {
8861   ClutterActorPrivate *priv = self->priv;
8862   ClutterActorBox old = { 0, };
8863
8864   if (priv->min_width_set == (use_min_width != FALSE))
8865     return;
8866
8867   clutter_actor_store_old_geometry (self, &old);
8868
8869   priv->min_width_set = use_min_width != FALSE;
8870   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8871
8872   clutter_actor_notify_if_geometry_changed (self, &old);
8873
8874   clutter_actor_queue_relayout (self);
8875 }
8876
8877 static void
8878 clutter_actor_set_min_height_set (ClutterActor *self,
8879                                   gboolean      use_min_height)
8880 {
8881   ClutterActorPrivate *priv = self->priv;
8882   ClutterActorBox old = { 0, };
8883
8884   if (priv->min_height_set == (use_min_height != FALSE))
8885     return;
8886
8887   clutter_actor_store_old_geometry (self, &old);
8888
8889   priv->min_height_set = use_min_height != FALSE;
8890   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8891
8892   clutter_actor_notify_if_geometry_changed (self, &old);
8893
8894   clutter_actor_queue_relayout (self);
8895 }
8896
8897 static void
8898 clutter_actor_set_natural_width_set (ClutterActor *self,
8899                                      gboolean      use_natural_width)
8900 {
8901   ClutterActorPrivate *priv = self->priv;
8902   ClutterActorBox old = { 0, };
8903
8904   if (priv->natural_width_set == (use_natural_width != FALSE))
8905     return;
8906
8907   clutter_actor_store_old_geometry (self, &old);
8908
8909   priv->natural_width_set = use_natural_width != FALSE;
8910   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8911
8912   clutter_actor_notify_if_geometry_changed (self, &old);
8913
8914   clutter_actor_queue_relayout (self);
8915 }
8916
8917 static void
8918 clutter_actor_set_natural_height_set (ClutterActor *self,
8919                                       gboolean      use_natural_height)
8920 {
8921   ClutterActorPrivate *priv = self->priv;
8922   ClutterActorBox old = { 0, };
8923
8924   if (priv->natural_height_set == (use_natural_height != FALSE))
8925     return;
8926
8927   clutter_actor_store_old_geometry (self, &old);
8928
8929   priv->natural_height_set = use_natural_height != FALSE;
8930   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8931
8932   clutter_actor_notify_if_geometry_changed (self, &old);
8933
8934   clutter_actor_queue_relayout (self);
8935 }
8936
8937 /**
8938  * clutter_actor_set_request_mode:
8939  * @self: a #ClutterActor
8940  * @mode: the request mode
8941  *
8942  * Sets the geometry request mode of @self.
8943  *
8944  * The @mode determines the order for invoking
8945  * clutter_actor_get_preferred_width() and
8946  * clutter_actor_get_preferred_height()
8947  *
8948  * Since: 1.2
8949  */
8950 void
8951 clutter_actor_set_request_mode (ClutterActor       *self,
8952                                 ClutterRequestMode  mode)
8953 {
8954   ClutterActorPrivate *priv;
8955
8956   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8957
8958   priv = self->priv;
8959
8960   if (priv->request_mode == mode)
8961     return;
8962
8963   priv->request_mode = mode;
8964
8965   priv->needs_width_request = TRUE;
8966   priv->needs_height_request = TRUE;
8967
8968   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8969
8970   clutter_actor_queue_relayout (self);
8971 }
8972
8973 /**
8974  * clutter_actor_get_request_mode:
8975  * @self: a #ClutterActor
8976  *
8977  * Retrieves the geometry request mode of @self
8978  *
8979  * Return value: the request mode for the actor
8980  *
8981  * Since: 1.2
8982  */
8983 ClutterRequestMode
8984 clutter_actor_get_request_mode (ClutterActor *self)
8985 {
8986   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8987                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8988
8989   return self->priv->request_mode;
8990 }
8991
8992 /* variant of set_width() without checks and without notification
8993  * freeze+thaw, for internal usage only
8994  */
8995 static inline void
8996 clutter_actor_set_width_internal (ClutterActor *self,
8997                                   gfloat        width)
8998 {
8999   if (width >= 0)
9000     {
9001       /* the Stage will use the :min-width to control the minimum
9002        * width to be resized to, so we should not be setting it
9003        * along with the :natural-width
9004        */
9005       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9006         clutter_actor_set_min_width (self, width);
9007
9008       clutter_actor_set_natural_width (self, width);
9009     }
9010   else
9011     {
9012       /* we only unset the :natural-width for the Stage */
9013       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9014         clutter_actor_set_min_width_set (self, FALSE);
9015
9016       clutter_actor_set_natural_width_set (self, FALSE);
9017     }
9018 }
9019
9020 /* variant of set_height() without checks and without notification
9021  * freeze+thaw, for internal usage only
9022  */
9023 static inline void
9024 clutter_actor_set_height_internal (ClutterActor *self,
9025                                    gfloat        height)
9026 {
9027   if (height >= 0)
9028     {
9029       /* see the comment above in set_width_internal() */
9030       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9031         clutter_actor_set_min_height (self, height);
9032
9033       clutter_actor_set_natural_height (self, height);
9034     }
9035   else
9036     {
9037       /* see the comment above in set_width_internal() */
9038       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9039         clutter_actor_set_min_height_set (self, FALSE);
9040
9041       clutter_actor_set_natural_height_set (self, FALSE);
9042     }
9043 }
9044
9045 /**
9046  * clutter_actor_set_size:
9047  * @self: A #ClutterActor
9048  * @width: New width of actor in pixels, or -1
9049  * @height: New height of actor in pixels, or -1
9050  *
9051  * Sets the actor's size request in pixels. This overrides any
9052  * "normal" size request the actor would have. For example
9053  * a text actor might normally request the size of the text;
9054  * this function would force a specific size instead.
9055  *
9056  * If @width and/or @height are -1 the actor will use its
9057  * "normal" size request instead of overriding it, i.e.
9058  * you can "unset" the size with -1.
9059  *
9060  * This function sets or unsets both the minimum and natural size.
9061  */
9062 void
9063 clutter_actor_set_size (ClutterActor *self,
9064                         gfloat        width,
9065                         gfloat        height)
9066 {
9067   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9068
9069   g_object_freeze_notify (G_OBJECT (self));
9070
9071   clutter_actor_set_width (self, width);
9072   clutter_actor_set_height (self, height);
9073
9074   g_object_thaw_notify (G_OBJECT (self));
9075 }
9076
9077 /**
9078  * clutter_actor_get_size:
9079  * @self: A #ClutterActor
9080  * @width: (out) (allow-none): return location for the width, or %NULL.
9081  * @height: (out) (allow-none): return location for the height, or %NULL.
9082  *
9083  * This function tries to "do what you mean" and return
9084  * the size an actor will have. If the actor has a valid
9085  * allocation, the allocation will be returned; otherwise,
9086  * the actors natural size request will be returned.
9087  *
9088  * If you care whether you get the request vs. the allocation, you
9089  * should probably call a different function like
9090  * clutter_actor_get_allocation_box() or
9091  * clutter_actor_get_preferred_width().
9092  *
9093  * Since: 0.2
9094  */
9095 void
9096 clutter_actor_get_size (ClutterActor *self,
9097                         gfloat       *width,
9098                         gfloat       *height)
9099 {
9100   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9101
9102   if (width)
9103     *width = clutter_actor_get_width (self);
9104
9105   if (height)
9106     *height = clutter_actor_get_height (self);
9107 }
9108
9109 /**
9110  * clutter_actor_get_position:
9111  * @self: a #ClutterActor
9112  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9113  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9114  *
9115  * This function tries to "do what you mean" and tell you where the
9116  * actor is, prior to any transformations. Retrieves the fixed
9117  * position of an actor in pixels, if one has been set; otherwise, if
9118  * the allocation is valid, returns the actor's allocated position;
9119  * otherwise, returns 0,0.
9120  *
9121  * The returned position is in pixels.
9122  *
9123  * Since: 0.6
9124  */
9125 void
9126 clutter_actor_get_position (ClutterActor *self,
9127                             gfloat       *x,
9128                             gfloat       *y)
9129 {
9130   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9131
9132   if (x)
9133     *x = clutter_actor_get_x (self);
9134
9135   if (y)
9136     *y = clutter_actor_get_y (self);
9137 }
9138
9139 /**
9140  * clutter_actor_get_transformed_position:
9141  * @self: A #ClutterActor
9142  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9143  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9144  *
9145  * Gets the absolute position of an actor, in pixels relative to the stage.
9146  *
9147  * Since: 0.8
9148  */
9149 void
9150 clutter_actor_get_transformed_position (ClutterActor *self,
9151                                         gfloat       *x,
9152                                         gfloat       *y)
9153 {
9154   ClutterVertex v1;
9155   ClutterVertex v2;
9156
9157   v1.x = v1.y = v1.z = 0;
9158   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9159
9160   if (x)
9161     *x = v2.x;
9162
9163   if (y)
9164     *y = v2.y;
9165 }
9166
9167 /**
9168  * clutter_actor_get_transformed_size:
9169  * @self: A #ClutterActor
9170  * @width: (out) (allow-none): return location for the width, or %NULL
9171  * @height: (out) (allow-none): return location for the height, or %NULL
9172  *
9173  * Gets the absolute size of an actor in pixels, taking into account the
9174  * scaling factors.
9175  *
9176  * If the actor has a valid allocation, the allocated size will be used.
9177  * If the actor has not a valid allocation then the preferred size will
9178  * be transformed and returned.
9179  *
9180  * If you want the transformed allocation, see
9181  * clutter_actor_get_abs_allocation_vertices() instead.
9182  *
9183  * <note>When the actor (or one of its ancestors) is rotated around the
9184  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9185  * as a generic quadrangle; in that case this function returns the size
9186  * of the smallest rectangle that encapsulates the entire quad. Please
9187  * note that in this case no assumptions can be made about the relative
9188  * position of this envelope to the absolute position of the actor, as
9189  * returned by clutter_actor_get_transformed_position(); if you need this
9190  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9191  * to get the coords of the actual quadrangle.</note>
9192  *
9193  * Since: 0.8
9194  */
9195 void
9196 clutter_actor_get_transformed_size (ClutterActor *self,
9197                                     gfloat       *width,
9198                                     gfloat       *height)
9199 {
9200   ClutterActorPrivate *priv;
9201   ClutterVertex v[4];
9202   gfloat x_min, x_max, y_min, y_max;
9203   gint i;
9204
9205   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9206
9207   priv = self->priv;
9208
9209   /* if the actor hasn't been allocated yet, get the preferred
9210    * size and transform that
9211    */
9212   if (priv->needs_allocation)
9213     {
9214       gfloat natural_width, natural_height;
9215       ClutterActorBox box;
9216
9217       /* Make a fake allocation to transform.
9218        *
9219        * NB: _clutter_actor_transform_and_project_box expects a box in
9220        * the actor's coordinate space... */
9221
9222       box.x1 = 0;
9223       box.y1 = 0;
9224
9225       natural_width = natural_height = 0;
9226       clutter_actor_get_preferred_size (self, NULL, NULL,
9227                                         &natural_width,
9228                                         &natural_height);
9229
9230       box.x2 = natural_width;
9231       box.y2 = natural_height;
9232
9233       _clutter_actor_transform_and_project_box (self, &box, v);
9234     }
9235   else
9236     clutter_actor_get_abs_allocation_vertices (self, v);
9237
9238   x_min = x_max = v[0].x;
9239   y_min = y_max = v[0].y;
9240
9241   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9242     {
9243       if (v[i].x < x_min)
9244         x_min = v[i].x;
9245
9246       if (v[i].x > x_max)
9247         x_max = v[i].x;
9248
9249       if (v[i].y < y_min)
9250         y_min = v[i].y;
9251
9252       if (v[i].y > y_max)
9253         y_max = v[i].y;
9254     }
9255
9256   if (width)
9257     *width  = x_max - x_min;
9258
9259   if (height)
9260     *height = y_max - y_min;
9261 }
9262
9263 /**
9264  * clutter_actor_get_width:
9265  * @self: A #ClutterActor
9266  *
9267  * Retrieves the width of a #ClutterActor.
9268  *
9269  * If the actor has a valid allocation, this function will return the
9270  * width of the allocated area given to the actor.
9271  *
9272  * If the actor does not have a valid allocation, this function will
9273  * return the actor's natural width, that is the preferred width of
9274  * the actor.
9275  *
9276  * If you care whether you get the preferred width or the width that
9277  * has been assigned to the actor, you should probably call a different
9278  * function like clutter_actor_get_allocation_box() to retrieve the
9279  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9280  * preferred width.
9281  *
9282  * If an actor has a fixed width, for instance a width that has been
9283  * assigned using clutter_actor_set_width(), the width returned will
9284  * be the same value.
9285  *
9286  * Return value: the width of the actor, in pixels
9287  */
9288 gfloat
9289 clutter_actor_get_width (ClutterActor *self)
9290 {
9291   ClutterActorPrivate *priv;
9292
9293   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9294
9295   priv = self->priv;
9296
9297   if (priv->needs_allocation)
9298     {
9299       gfloat natural_width = 0;
9300
9301       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9302         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9303       else
9304         {
9305           gfloat natural_height = 0;
9306
9307           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9308           clutter_actor_get_preferred_width (self, natural_height,
9309                                              NULL,
9310                                              &natural_width);
9311         }
9312
9313       return natural_width;
9314     }
9315   else
9316     return priv->allocation.x2 - priv->allocation.x1;
9317 }
9318
9319 /**
9320  * clutter_actor_get_height:
9321  * @self: A #ClutterActor
9322  *
9323  * Retrieves the height of a #ClutterActor.
9324  *
9325  * If the actor has a valid allocation, this function will return the
9326  * height of the allocated area given to the actor.
9327  *
9328  * If the actor does not have a valid allocation, this function will
9329  * return the actor's natural height, that is the preferred height of
9330  * the actor.
9331  *
9332  * If you care whether you get the preferred height or the height that
9333  * has been assigned to the actor, you should probably call a different
9334  * function like clutter_actor_get_allocation_box() to retrieve the
9335  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9336  * preferred height.
9337  *
9338  * If an actor has a fixed height, for instance a height that has been
9339  * assigned using clutter_actor_set_height(), the height returned will
9340  * be the same value.
9341  *
9342  * Return value: the height of the actor, in pixels
9343  */
9344 gfloat
9345 clutter_actor_get_height (ClutterActor *self)
9346 {
9347   ClutterActorPrivate *priv;
9348
9349   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9350
9351   priv = self->priv;
9352
9353   if (priv->needs_allocation)
9354     {
9355       gfloat natural_height = 0;
9356
9357       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9358         {
9359           gfloat natural_width = 0;
9360
9361           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9362           clutter_actor_get_preferred_height (self, natural_width,
9363                                               NULL, &natural_height);
9364         }
9365       else
9366         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9367
9368       return natural_height;
9369     }
9370   else
9371     return priv->allocation.y2 - priv->allocation.y1;
9372 }
9373
9374 /**
9375  * clutter_actor_set_width:
9376  * @self: A #ClutterActor
9377  * @width: Requested new width for the actor, in pixels, or -1
9378  *
9379  * Forces a width on an actor, causing the actor's preferred width
9380  * and height (if any) to be ignored.
9381  *
9382  * If @width is -1 the actor will use its preferred width request
9383  * instead of overriding it, i.e. you can "unset" the width with -1.
9384  *
9385  * This function sets both the minimum and natural size of the actor.
9386  *
9387  * since: 0.2
9388  */
9389 void
9390 clutter_actor_set_width (ClutterActor *self,
9391                          gfloat        width)
9392 {
9393   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9394
9395   if (clutter_actor_get_easing_duration (self) != 0)
9396     {
9397       ClutterTransition *transition;
9398
9399       transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9400       if (transition == NULL)
9401         {
9402           float old_width = clutter_actor_get_width (self);
9403
9404           transition = _clutter_actor_create_transition (self,
9405                                                          obj_props[PROP_WIDTH],
9406                                                          old_width,
9407                                                          width);
9408           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9409         }
9410       else
9411         _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9412
9413       clutter_actor_queue_relayout (self);
9414     }
9415   else
9416     {
9417       g_object_freeze_notify (G_OBJECT (self));
9418
9419       clutter_actor_set_width_internal (self, width);
9420
9421       g_object_thaw_notify (G_OBJECT (self));
9422     }
9423 }
9424
9425 /**
9426  * clutter_actor_set_height:
9427  * @self: A #ClutterActor
9428  * @height: Requested new height for the actor, in pixels, or -1
9429  *
9430  * Forces a height on an actor, causing the actor's preferred width
9431  * and height (if any) to be ignored.
9432  *
9433  * If @height is -1 the actor will use its preferred height instead of
9434  * overriding it, i.e. you can "unset" the height with -1.
9435  *
9436  * This function sets both the minimum and natural size of the actor.
9437  *
9438  * since: 0.2
9439  */
9440 void
9441 clutter_actor_set_height (ClutterActor *self,
9442                           gfloat        height)
9443 {
9444   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9445
9446   if (clutter_actor_get_easing_duration (self) != 0)
9447     {
9448       ClutterTransition *transition;
9449
9450       transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9451       if (transition ==  NULL)
9452         {
9453           float old_height = clutter_actor_get_height (self);
9454
9455           transition = _clutter_actor_create_transition (self,
9456                                                          obj_props[PROP_HEIGHT],
9457                                                          old_height,
9458                                                          height);
9459           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9460         }
9461       else
9462         _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9463
9464       clutter_actor_queue_relayout (self);
9465     }
9466   else
9467     {
9468       g_object_freeze_notify (G_OBJECT (self));
9469
9470       clutter_actor_set_height_internal (self, height);
9471
9472       g_object_thaw_notify (G_OBJECT (self));
9473     }
9474 }
9475
9476 static inline void
9477 clutter_actor_set_x_internal (ClutterActor *self,
9478                               float         x)
9479 {
9480   ClutterActorPrivate *priv = self->priv;
9481   ClutterLayoutInfo *linfo;
9482   ClutterActorBox old = { 0, };
9483
9484   linfo = _clutter_actor_get_layout_info (self);
9485
9486   if (priv->position_set && linfo->fixed_x == x)
9487     return;
9488
9489   clutter_actor_store_old_geometry (self, &old);
9490
9491   linfo->fixed_x = x;
9492   clutter_actor_set_fixed_position_set (self, TRUE);
9493
9494   clutter_actor_notify_if_geometry_changed (self, &old);
9495
9496   clutter_actor_queue_relayout (self);
9497 }
9498
9499 static inline void
9500 clutter_actor_set_y_internal (ClutterActor *self,
9501                               float         y)
9502 {
9503   ClutterActorPrivate *priv = self->priv;
9504   ClutterLayoutInfo *linfo;
9505   ClutterActorBox old = { 0, };
9506
9507   linfo = _clutter_actor_get_layout_info (self);
9508
9509   if (priv->position_set && linfo->fixed_y == y)
9510     return;
9511
9512   clutter_actor_store_old_geometry (self, &old);
9513
9514   linfo->fixed_y = y;
9515   clutter_actor_set_fixed_position_set (self, TRUE);
9516
9517   clutter_actor_notify_if_geometry_changed (self, &old);
9518
9519   clutter_actor_queue_relayout (self);
9520 }
9521
9522 /**
9523  * clutter_actor_set_x:
9524  * @self: a #ClutterActor
9525  * @x: the actor's position on the X axis
9526  *
9527  * Sets the actor's X coordinate, relative to its parent, in pixels.
9528  *
9529  * Overrides any layout manager and forces a fixed position for
9530  * the actor.
9531  *
9532  * The #ClutterActor:x property is animatable.
9533  *
9534  * Since: 0.6
9535  */
9536 void
9537 clutter_actor_set_x (ClutterActor *self,
9538                      gfloat        x)
9539 {
9540   const ClutterLayoutInfo *linfo;
9541
9542   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9543
9544   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9545
9546   if (clutter_actor_get_easing_duration (self) != 0)
9547     {
9548       ClutterTransition *transition;
9549
9550       transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9551       if (transition == NULL)
9552         {
9553           transition = _clutter_actor_create_transition (self,
9554                                                          obj_props[PROP_X],
9555                                                          linfo->fixed_x,
9556                                                          x);
9557
9558           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9559         }
9560       else
9561         _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9562
9563       clutter_actor_queue_relayout (self);
9564     }
9565   else
9566     clutter_actor_set_x_internal (self, x);
9567 }
9568
9569 /**
9570  * clutter_actor_set_y:
9571  * @self: a #ClutterActor
9572  * @y: the actor's position on the Y axis
9573  *
9574  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9575  *
9576  * Overrides any layout manager and forces a fixed position for
9577  * the actor.
9578  *
9579  * The #ClutterActor:y property is animatable.
9580  *
9581  * Since: 0.6
9582  */
9583 void
9584 clutter_actor_set_y (ClutterActor *self,
9585                      gfloat        y)
9586 {
9587   const ClutterLayoutInfo *linfo;
9588
9589   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9590
9591   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9592
9593   if (clutter_actor_get_easing_duration (self) != 0)
9594     {
9595       ClutterTransition *transition;
9596
9597       transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9598       if (transition == NULL)
9599         {
9600           transition = _clutter_actor_create_transition (self,
9601                                                          obj_props[PROP_Y],
9602                                                          linfo->fixed_y,
9603                                                          y);
9604
9605           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9606         }
9607       else
9608         _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9609
9610       clutter_actor_queue_relayout (self);
9611     }
9612   else
9613     clutter_actor_set_y_internal (self, y);
9614
9615   clutter_actor_queue_relayout (self);
9616 }
9617
9618 /**
9619  * clutter_actor_get_x:
9620  * @self: A #ClutterActor
9621  *
9622  * Retrieves the X coordinate of a #ClutterActor.
9623  *
9624  * This function tries to "do what you mean", by returning the
9625  * correct value depending on the actor's state.
9626  *
9627  * If the actor has a valid allocation, this function will return
9628  * the X coordinate of the origin of the allocation box.
9629  *
9630  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9631  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9632  * function will return that coordinate.
9633  *
9634  * If both the allocation and a fixed position are missing, this function
9635  * will return 0.
9636  *
9637  * Return value: the X coordinate, in pixels, ignoring any
9638  *   transformation (i.e. scaling, rotation)
9639  */
9640 gfloat
9641 clutter_actor_get_x (ClutterActor *self)
9642 {
9643   ClutterActorPrivate *priv;
9644
9645   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9646
9647   priv = self->priv;
9648
9649   if (priv->needs_allocation)
9650     {
9651       if (priv->position_set)
9652         {
9653           const ClutterLayoutInfo *info;
9654
9655           info = _clutter_actor_get_layout_info_or_defaults (self);
9656
9657           return info->fixed_x;
9658         }
9659       else
9660         return 0;
9661     }
9662   else
9663     return priv->allocation.x1;
9664 }
9665
9666 /**
9667  * clutter_actor_get_y:
9668  * @self: A #ClutterActor
9669  *
9670  * Retrieves the Y coordinate of a #ClutterActor.
9671  *
9672  * This function tries to "do what you mean", by returning the
9673  * correct value depending on the actor's state.
9674  *
9675  * If the actor has a valid allocation, this function will return
9676  * the Y coordinate of the origin of the allocation box.
9677  *
9678  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9679  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9680  * function will return that coordinate.
9681  *
9682  * If both the allocation and a fixed position are missing, this function
9683  * will return 0.
9684  *
9685  * Return value: the Y coordinate, in pixels, ignoring any
9686  *   transformation (i.e. scaling, rotation)
9687  */
9688 gfloat
9689 clutter_actor_get_y (ClutterActor *self)
9690 {
9691   ClutterActorPrivate *priv;
9692
9693   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9694
9695   priv = self->priv;
9696
9697   if (priv->needs_allocation)
9698     {
9699       if (priv->position_set)
9700         {
9701           const ClutterLayoutInfo *info;
9702
9703           info = _clutter_actor_get_layout_info_or_defaults (self);
9704
9705           return info->fixed_y;
9706         }
9707       else
9708         return 0;
9709     }
9710   else
9711     return priv->allocation.y1;
9712 }
9713
9714 /**
9715  * clutter_actor_set_scale:
9716  * @self: A #ClutterActor
9717  * @scale_x: double factor to scale actor by horizontally.
9718  * @scale_y: double factor to scale actor by vertically.
9719  *
9720  * Scales an actor with the given factors. The scaling is relative to
9721  * the scale center and the anchor point. The scale center is
9722  * unchanged by this function and defaults to 0,0.
9723  *
9724  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9725  * animatable.
9726  *
9727  * Since: 0.2
9728  */
9729 void
9730 clutter_actor_set_scale (ClutterActor *self,
9731                          gdouble       scale_x,
9732                          gdouble       scale_y)
9733 {
9734   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9735
9736   g_object_freeze_notify (G_OBJECT (self));
9737
9738   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9739   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9740
9741   g_object_thaw_notify (G_OBJECT (self));
9742 }
9743
9744 /**
9745  * clutter_actor_set_scale_full:
9746  * @self: A #ClutterActor
9747  * @scale_x: double factor to scale actor by horizontally.
9748  * @scale_y: double factor to scale actor by vertically.
9749  * @center_x: X coordinate of the center of the scale.
9750  * @center_y: Y coordinate of the center of the scale
9751  *
9752  * Scales an actor with the given factors around the given center
9753  * point. The center point is specified in pixels relative to the
9754  * anchor point (usually the top left corner of the actor).
9755  *
9756  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9757  * are animatable.
9758  *
9759  * Since: 1.0
9760  */
9761 void
9762 clutter_actor_set_scale_full (ClutterActor *self,
9763                               gdouble       scale_x,
9764                               gdouble       scale_y,
9765                               gfloat        center_x,
9766                               gfloat        center_y)
9767 {
9768   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9769
9770   g_object_freeze_notify (G_OBJECT (self));
9771
9772   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9773   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9774   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9775   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9776
9777   g_object_thaw_notify (G_OBJECT (self));
9778 }
9779
9780 /**
9781  * clutter_actor_set_scale_with_gravity:
9782  * @self: A #ClutterActor
9783  * @scale_x: double factor to scale actor by horizontally.
9784  * @scale_y: double factor to scale actor by vertically.
9785  * @gravity: the location of the scale center expressed as a compass
9786  * direction.
9787  *
9788  * Scales an actor with the given factors around the given
9789  * center point. The center point is specified as one of the compass
9790  * directions in #ClutterGravity. For example, setting it to north
9791  * will cause the top of the actor to remain unchanged and the rest of
9792  * the actor to expand left, right and downwards.
9793  *
9794  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9795  * animatable.
9796  *
9797  * Since: 1.0
9798  */
9799 void
9800 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9801                                       gdouble         scale_x,
9802                                       gdouble         scale_y,
9803                                       ClutterGravity  gravity)
9804 {
9805   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9806
9807   g_object_freeze_notify (G_OBJECT (self));
9808
9809   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9810   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9811   clutter_actor_set_scale_gravity (self, gravity);
9812
9813   g_object_thaw_notify (G_OBJECT (self));
9814 }
9815
9816 /**
9817  * clutter_actor_get_scale:
9818  * @self: A #ClutterActor
9819  * @scale_x: (out) (allow-none): Location to store horizonal
9820  *   scale factor, or %NULL.
9821  * @scale_y: (out) (allow-none): Location to store vertical
9822  *   scale factor, or %NULL.
9823  *
9824  * Retrieves an actors scale factors.
9825  *
9826  * Since: 0.2
9827  */
9828 void
9829 clutter_actor_get_scale (ClutterActor *self,
9830                          gdouble      *scale_x,
9831                          gdouble      *scale_y)
9832 {
9833   const ClutterTransformInfo *info;
9834
9835   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9836
9837   info = _clutter_actor_get_transform_info_or_defaults (self);
9838
9839   if (scale_x)
9840     *scale_x = info->scale_x;
9841
9842   if (scale_y)
9843     *scale_y = info->scale_y;
9844 }
9845
9846 /**
9847  * clutter_actor_get_scale_center:
9848  * @self: A #ClutterActor
9849  * @center_x: (out) (allow-none): Location to store the X position
9850  *   of the scale center, or %NULL.
9851  * @center_y: (out) (allow-none): Location to store the Y position
9852  *   of the scale center, or %NULL.
9853  *
9854  * Retrieves the scale center coordinate in pixels relative to the top
9855  * left corner of the actor. If the scale center was specified using a
9856  * #ClutterGravity this will calculate the pixel offset using the
9857  * current size of the actor.
9858  *
9859  * Since: 1.0
9860  */
9861 void
9862 clutter_actor_get_scale_center (ClutterActor *self,
9863                                 gfloat       *center_x,
9864                                 gfloat       *center_y)
9865 {
9866   const ClutterTransformInfo *info;
9867
9868   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9869
9870   info = _clutter_actor_get_transform_info_or_defaults (self);
9871
9872   clutter_anchor_coord_get_units (self, &info->scale_center,
9873                                   center_x,
9874                                   center_y,
9875                                   NULL);
9876 }
9877
9878 /**
9879  * clutter_actor_get_scale_gravity:
9880  * @self: A #ClutterActor
9881  *
9882  * Retrieves the scale center as a compass direction. If the scale
9883  * center was specified in pixels or units this will return
9884  * %CLUTTER_GRAVITY_NONE.
9885  *
9886  * Return value: the scale gravity
9887  *
9888  * Since: 1.0
9889  */
9890 ClutterGravity
9891 clutter_actor_get_scale_gravity (ClutterActor *self)
9892 {
9893   const ClutterTransformInfo *info;
9894
9895   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9896
9897   info = _clutter_actor_get_transform_info_or_defaults (self);
9898
9899   return clutter_anchor_coord_get_gravity (&info->scale_center);
9900 }
9901
9902 static inline void
9903 clutter_actor_set_opacity_internal (ClutterActor *self,
9904                                     guint8        opacity)
9905 {
9906   ClutterActorPrivate *priv = self->priv;
9907
9908   if (priv->opacity != opacity)
9909     {
9910       priv->opacity = opacity;
9911
9912       /* Queue a redraw from the flatten effect so that it can use
9913          its cached image if available instead of having to redraw the
9914          actual actor. If it doesn't end up using the FBO then the
9915          effect is still able to continue the paint anyway. If there
9916          is no flatten effect yet then this is equivalent to queueing
9917          a full redraw */
9918       _clutter_actor_queue_redraw_full (self,
9919                                         0, /* flags */
9920                                         NULL, /* clip */
9921                                         priv->flatten_effect);
9922
9923       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9924     }
9925 }
9926
9927 /**
9928  * clutter_actor_set_opacity:
9929  * @self: A #ClutterActor
9930  * @opacity: New opacity value for the actor.
9931  *
9932  * Sets the actor's opacity, with zero being completely transparent and
9933  * 255 (0xff) being fully opaque.
9934  *
9935  * The #ClutterActor:opacity property is animatable.
9936  */
9937 void
9938 clutter_actor_set_opacity (ClutterActor *self,
9939                            guint8        opacity)
9940 {
9941   ClutterActorPrivate *priv;
9942
9943   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9944
9945   priv = self->priv;
9946
9947   if (clutter_actor_get_easing_duration (self) != 0)
9948     {
9949       ClutterTransition *transition;
9950
9951       transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9952       if (transition == NULL)
9953         {
9954           transition = _clutter_actor_create_transition (self,
9955                                                          obj_props[PROP_OPACITY],
9956                                                          priv->opacity,
9957                                                          opacity);
9958           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9959         }
9960       else
9961         _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9962
9963       clutter_actor_queue_redraw (self);
9964     }
9965   else
9966     clutter_actor_set_opacity_internal (self, opacity);
9967 }
9968
9969 /*
9970  * clutter_actor_get_paint_opacity_internal:
9971  * @self: a #ClutterActor
9972  *
9973  * Retrieves the absolute opacity of the actor, as it appears on the stage
9974  *
9975  * This function does not do type checks
9976  *
9977  * Return value: the absolute opacity of the actor
9978  */
9979 static guint8
9980 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9981 {
9982   ClutterActorPrivate *priv = self->priv;
9983   ClutterActor *parent;
9984
9985   /* override the top-level opacity to always be 255; even in
9986    * case of ClutterStage:use-alpha being TRUE we want the rest
9987    * of the scene to be painted
9988    */
9989   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9990     return 255;
9991
9992   if (priv->opacity_override >= 0)
9993     return priv->opacity_override;
9994
9995   parent = priv->parent;
9996
9997   /* Factor in the actual actors opacity with parents */
9998   if (parent != NULL)
9999     {
10000       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10001
10002       if (opacity != 0xff)
10003         return (opacity * priv->opacity) / 0xff;
10004     }
10005
10006   return priv->opacity;
10007
10008 }
10009
10010 /**
10011  * clutter_actor_get_paint_opacity:
10012  * @self: A #ClutterActor
10013  *
10014  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10015  *
10016  * This function traverses the hierarchy chain and composites the opacity of
10017  * the actor with that of its parents.
10018  *
10019  * This function is intended for subclasses to use in the paint virtual
10020  * function, to paint themselves with the correct opacity.
10021  *
10022  * Return value: The actor opacity value.
10023  *
10024  * Since: 0.8
10025  */
10026 guint8
10027 clutter_actor_get_paint_opacity (ClutterActor *self)
10028 {
10029   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10030
10031   return clutter_actor_get_paint_opacity_internal (self);
10032 }
10033
10034 /**
10035  * clutter_actor_get_opacity:
10036  * @self: a #ClutterActor
10037  *
10038  * Retrieves the opacity value of an actor, as set by
10039  * clutter_actor_set_opacity().
10040  *
10041  * For retrieving the absolute opacity of the actor inside a paint
10042  * virtual function, see clutter_actor_get_paint_opacity().
10043  *
10044  * Return value: the opacity of the actor
10045  */
10046 guint8
10047 clutter_actor_get_opacity (ClutterActor *self)
10048 {
10049   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10050
10051   return self->priv->opacity;
10052 }
10053
10054 /**
10055  * clutter_actor_set_offscreen_redirect:
10056  * @self: A #ClutterActor
10057  * @redirect: New offscreen redirect flags for the actor.
10058  *
10059  * Defines the circumstances where the actor should be redirected into
10060  * an offscreen image. The offscreen image is used to flatten the
10061  * actor into a single image while painting for two main reasons.
10062  * Firstly, when the actor is painted a second time without any of its
10063  * contents changing it can simply repaint the cached image without
10064  * descending further down the actor hierarchy. Secondly, it will make
10065  * the opacity look correct even if there are overlapping primitives
10066  * in the actor.
10067  *
10068  * Caching the actor could in some cases be a performance win and in
10069  * some cases be a performance lose so it is important to determine
10070  * which value is right for an actor before modifying this value. For
10071  * example, there is never any reason to flatten an actor that is just
10072  * a single texture (such as a #ClutterTexture) because it is
10073  * effectively already cached in an image so the offscreen would be
10074  * redundant. Also if the actor contains primitives that are far apart
10075  * with a large transparent area in the middle (such as a large
10076  * CluterGroup with a small actor in the top left and a small actor in
10077  * the bottom right) then the cached image will contain the entire
10078  * image of the large area and the paint will waste time blending all
10079  * of the transparent pixels in the middle.
10080  *
10081  * The default method of implementing opacity on a container simply
10082  * forwards on the opacity to all of the children. If the children are
10083  * overlapping then it will appear as if they are two separate glassy
10084  * objects and there will be a break in the color where they
10085  * overlap. By redirecting to an offscreen buffer it will be as if the
10086  * two opaque objects are combined into one and then made transparent
10087  * which is usually what is expected.
10088  *
10089  * The image below demonstrates the difference between redirecting and
10090  * not. The image shows two Clutter groups, each containing a red and
10091  * a green rectangle which overlap. The opacity on the group is set to
10092  * 128 (which is 50%). When the offscreen redirect is not used, the
10093  * red rectangle can be seen through the blue rectangle as if the two
10094  * rectangles were separately transparent. When the redirect is used
10095  * the group as a whole is transparent instead so the red rectangle is
10096  * not visible where they overlap.
10097  *
10098  * <figure id="offscreen-redirect">
10099  *   <title>Sample of using an offscreen redirect for transparency</title>
10100  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10101  * </figure>
10102  *
10103  * The default value for this property is 0, so we effectively will
10104  * never redirect an actor offscreen by default. This means that there
10105  * are times that transparent actors may look glassy as described
10106  * above. The reason this is the default is because there is a
10107  * performance trade off between quality and performance here. In many
10108  * cases the default form of glassy opacity looks good enough, but if
10109  * it's not you will need to set the
10110  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10111  * redirection for opacity.
10112  *
10113  * Custom actors that don't contain any overlapping primitives are
10114  * recommended to override the has_overlaps() virtual to return %FALSE
10115  * for maximum efficiency.
10116  *
10117  * Since: 1.8
10118  */
10119 void
10120 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10121                                       ClutterOffscreenRedirect redirect)
10122 {
10123   ClutterActorPrivate *priv;
10124
10125   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10126
10127   priv = self->priv;
10128
10129   if (priv->offscreen_redirect != redirect)
10130     {
10131       priv->offscreen_redirect = redirect;
10132
10133       /* Queue a redraw from the effect so that it can use its cached
10134          image if available instead of having to redraw the actual
10135          actor. If it doesn't end up using the FBO then the effect is
10136          still able to continue the paint anyway. If there is no
10137          effect then this is equivalent to queuing a full redraw */
10138       _clutter_actor_queue_redraw_full (self,
10139                                         0, /* flags */
10140                                         NULL, /* clip */
10141                                         priv->flatten_effect);
10142
10143       g_object_notify_by_pspec (G_OBJECT (self),
10144                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10145     }
10146 }
10147
10148 /**
10149  * clutter_actor_get_offscreen_redirect:
10150  * @self: a #ClutterActor
10151  *
10152  * Retrieves whether to redirect the actor to an offscreen buffer, as
10153  * set by clutter_actor_set_offscreen_redirect().
10154  *
10155  * Return value: the value of the offscreen-redirect property of the actor
10156  *
10157  * Since: 1.8
10158  */
10159 ClutterOffscreenRedirect
10160 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10161 {
10162   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10163
10164   return self->priv->offscreen_redirect;
10165 }
10166
10167 /**
10168  * clutter_actor_set_name:
10169  * @self: A #ClutterActor
10170  * @name: Textual tag to apply to actor
10171  *
10172  * Sets the given name to @self. The name can be used to identify
10173  * a #ClutterActor.
10174  */
10175 void
10176 clutter_actor_set_name (ClutterActor *self,
10177                         const gchar  *name)
10178 {
10179   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10180
10181   g_free (self->priv->name);
10182   self->priv->name = g_strdup (name);
10183
10184   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10185 }
10186
10187 /**
10188  * clutter_actor_get_name:
10189  * @self: A #ClutterActor
10190  *
10191  * Retrieves the name of @self.
10192  *
10193  * Return value: the name of the actor, or %NULL. The returned string is
10194  *   owned by the actor and should not be modified or freed.
10195  */
10196 const gchar *
10197 clutter_actor_get_name (ClutterActor *self)
10198 {
10199   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10200
10201   return self->priv->name;
10202 }
10203
10204 /**
10205  * clutter_actor_get_gid:
10206  * @self: A #ClutterActor
10207  *
10208  * Retrieves the unique id for @self.
10209  *
10210  * Return value: Globally unique value for this object instance.
10211  *
10212  * Since: 0.6
10213  *
10214  * Deprecated: 1.8: The id is not used any longer.
10215  */
10216 guint32
10217 clutter_actor_get_gid (ClutterActor *self)
10218 {
10219   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10220
10221   return self->priv->id;
10222 }
10223
10224 static inline void
10225 clutter_actor_set_depth_internal (ClutterActor *self,
10226                                   float         depth)
10227 {
10228   ClutterTransformInfo *info;
10229
10230   info = _clutter_actor_get_transform_info (self);
10231
10232   if (info->depth != depth)
10233     {
10234       /* Sets Z value - XXX 2.0: should we invert? */
10235       info->depth = depth;
10236
10237       self->priv->transform_valid = FALSE;
10238
10239       /* FIXME - remove this crap; sadly, there are still containers
10240        * in Clutter that depend on this utter brain damage
10241        */
10242       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10243
10244       clutter_actor_queue_redraw (self);
10245
10246       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10247     }
10248 }
10249
10250 /**
10251  * clutter_actor_set_depth:
10252  * @self: a #ClutterActor
10253  * @depth: Z co-ord
10254  *
10255  * Sets the Z coordinate of @self to @depth.
10256  *
10257  * The unit used by @depth is dependant on the perspective setup. See
10258  * also clutter_stage_set_perspective().
10259  */
10260 void
10261 clutter_actor_set_depth (ClutterActor *self,
10262                          gfloat        depth)
10263 {
10264   const ClutterTransformInfo *tinfo;
10265
10266   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10267
10268   tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10269
10270   if (clutter_actor_get_easing_duration (self) != 0)
10271     {
10272       ClutterTransition *transition;
10273
10274       transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10275       if (transition == NULL)
10276         {
10277           transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10278                                                          tinfo->depth,
10279                                                          depth);
10280           clutter_timeline_start (CLUTTER_TIMELINE (transition));
10281         }
10282       else
10283         _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10284
10285       clutter_actor_queue_redraw (self);
10286     }
10287   else
10288     clutter_actor_set_depth_internal (self, depth);
10289 }
10290
10291 /**
10292  * clutter_actor_get_depth:
10293  * @self: a #ClutterActor
10294  *
10295  * Retrieves the depth of @self.
10296  *
10297  * Return value: the depth of the actor
10298  */
10299 gfloat
10300 clutter_actor_get_depth (ClutterActor *self)
10301 {
10302   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10303
10304   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10305 }
10306
10307 /**
10308  * clutter_actor_set_rotation:
10309  * @self: a #ClutterActor
10310  * @axis: the axis of rotation
10311  * @angle: the angle of rotation
10312  * @x: X coordinate of the rotation center
10313  * @y: Y coordinate of the rotation center
10314  * @z: Z coordinate of the rotation center
10315  *
10316  * Sets the rotation angle of @self around the given axis.
10317  *
10318  * The rotation center coordinates used depend on the value of @axis:
10319  * <itemizedlist>
10320  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10321  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10322  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10323  * </itemizedlist>
10324  *
10325  * The rotation coordinates are relative to the anchor point of the
10326  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10327  * point is set, the upper left corner is assumed as the origin.
10328  *
10329  * Since: 0.8
10330  */
10331 void
10332 clutter_actor_set_rotation (ClutterActor      *self,
10333                             ClutterRotateAxis  axis,
10334                             gdouble            angle,
10335                             gfloat             x,
10336                             gfloat             y,
10337                             gfloat             z)
10338 {
10339   ClutterVertex v;
10340
10341   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10342
10343   v.x = x;
10344   v.y = y;
10345   v.z = z;
10346
10347   g_object_freeze_notify (G_OBJECT (self));
10348
10349   clutter_actor_set_rotation_angle (self, axis, angle);
10350   clutter_actor_set_rotation_center_internal (self, axis, &v);
10351
10352   g_object_thaw_notify (G_OBJECT (self));
10353 }
10354
10355 /**
10356  * clutter_actor_set_z_rotation_from_gravity:
10357  * @self: a #ClutterActor
10358  * @angle: the angle of rotation
10359  * @gravity: the center point of the rotation
10360  *
10361  * Sets the rotation angle of @self around the Z axis using the center
10362  * point specified as a compass point. For example to rotate such that
10363  * the center of the actor remains static you can use
10364  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10365  * will move accordingly.
10366  *
10367  * Since: 1.0
10368  */
10369 void
10370 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10371                                            gdouble         angle,
10372                                            ClutterGravity  gravity)
10373 {
10374   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10375
10376   if (gravity == CLUTTER_GRAVITY_NONE)
10377     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10378   else
10379     {
10380       GObject *obj = G_OBJECT (self);
10381       ClutterTransformInfo *info;
10382
10383       info = _clutter_actor_get_transform_info (self);
10384
10385       g_object_freeze_notify (obj);
10386
10387       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10388
10389       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10390       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10391       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10392
10393       g_object_thaw_notify (obj);
10394     }
10395 }
10396
10397 /**
10398  * clutter_actor_get_rotation:
10399  * @self: a #ClutterActor
10400  * @axis: the axis of rotation
10401  * @x: (out): return value for the X coordinate of the center of rotation
10402  * @y: (out): return value for the Y coordinate of the center of rotation
10403  * @z: (out): return value for the Z coordinate of the center of rotation
10404  *
10405  * Retrieves the angle and center of rotation on the given axis,
10406  * set using clutter_actor_set_rotation().
10407  *
10408  * Return value: the angle of rotation
10409  *
10410  * Since: 0.8
10411  */
10412 gdouble
10413 clutter_actor_get_rotation (ClutterActor      *self,
10414                             ClutterRotateAxis  axis,
10415                             gfloat            *x,
10416                             gfloat            *y,
10417                             gfloat            *z)
10418 {
10419   const ClutterTransformInfo *info;
10420   const AnchorCoord *anchor_coord;
10421   gdouble retval = 0;
10422
10423   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10424
10425   info = _clutter_actor_get_transform_info_or_defaults (self);
10426
10427   switch (axis)
10428     {
10429     case CLUTTER_X_AXIS:
10430       anchor_coord = &info->rx_center;
10431       retval = info->rx_angle;
10432       break;
10433
10434     case CLUTTER_Y_AXIS:
10435       anchor_coord = &info->ry_center;
10436       retval = info->ry_angle;
10437       break;
10438
10439     case CLUTTER_Z_AXIS:
10440       anchor_coord = &info->rz_center;
10441       retval = info->rz_angle;
10442       break;
10443
10444     default:
10445       anchor_coord = NULL;
10446       retval = 0.0;
10447       break;
10448     }
10449
10450   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10451
10452   return retval;
10453 }
10454
10455 /**
10456  * clutter_actor_get_z_rotation_gravity:
10457  * @self: A #ClutterActor
10458  *
10459  * Retrieves the center for the rotation around the Z axis as a
10460  * compass direction. If the center was specified in pixels or units
10461  * this will return %CLUTTER_GRAVITY_NONE.
10462  *
10463  * Return value: the Z rotation center
10464  *
10465  * Since: 1.0
10466  */
10467 ClutterGravity
10468 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10469 {
10470   const ClutterTransformInfo *info;
10471
10472   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10473
10474   info = _clutter_actor_get_transform_info_or_defaults (self);
10475
10476   return clutter_anchor_coord_get_gravity (&info->rz_center);
10477 }
10478
10479 /**
10480  * clutter_actor_set_clip:
10481  * @self: A #ClutterActor
10482  * @xoff: X offset of the clip rectangle
10483  * @yoff: Y offset of the clip rectangle
10484  * @width: Width of the clip rectangle
10485  * @height: Height of the clip rectangle
10486  *
10487  * Sets clip area for @self. The clip area is always computed from the
10488  * upper left corner of the actor, even if the anchor point is set
10489  * otherwise.
10490  *
10491  * Since: 0.6
10492  */
10493 void
10494 clutter_actor_set_clip (ClutterActor *self,
10495                         gfloat        xoff,
10496                         gfloat        yoff,
10497                         gfloat        width,
10498                         gfloat        height)
10499 {
10500   ClutterActorPrivate *priv;
10501
10502   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10503
10504   priv = self->priv;
10505
10506   if (priv->has_clip &&
10507       priv->clip.x == xoff &&
10508       priv->clip.y == yoff &&
10509       priv->clip.width == width &&
10510       priv->clip.height == height)
10511     return;
10512
10513   priv->clip.x = xoff;
10514   priv->clip.y = yoff;
10515   priv->clip.width = width;
10516   priv->clip.height = height;
10517
10518   priv->has_clip = TRUE;
10519
10520   clutter_actor_queue_redraw (self);
10521
10522   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10523   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10524 }
10525
10526 /**
10527  * clutter_actor_remove_clip:
10528  * @self: A #ClutterActor
10529  *
10530  * Removes clip area from @self.
10531  */
10532 void
10533 clutter_actor_remove_clip (ClutterActor *self)
10534 {
10535   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10536
10537   if (!self->priv->has_clip)
10538     return;
10539
10540   self->priv->has_clip = FALSE;
10541
10542   clutter_actor_queue_redraw (self);
10543
10544   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10545 }
10546
10547 /**
10548  * clutter_actor_has_clip:
10549  * @self: a #ClutterActor
10550  *
10551  * Determines whether the actor has a clip area set or not.
10552  *
10553  * Return value: %TRUE if the actor has a clip area set.
10554  *
10555  * Since: 0.1.1
10556  */
10557 gboolean
10558 clutter_actor_has_clip (ClutterActor *self)
10559 {
10560   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10561
10562   return self->priv->has_clip;
10563 }
10564
10565 /**
10566  * clutter_actor_get_clip:
10567  * @self: a #ClutterActor
10568  * @xoff: (out) (allow-none): return location for the X offset of
10569  *   the clip rectangle, or %NULL
10570  * @yoff: (out) (allow-none): return location for the Y offset of
10571  *   the clip rectangle, or %NULL
10572  * @width: (out) (allow-none): return location for the width of
10573  *   the clip rectangle, or %NULL
10574  * @height: (out) (allow-none): return location for the height of
10575  *   the clip rectangle, or %NULL
10576  *
10577  * Gets the clip area for @self, if any is set
10578  *
10579  * Since: 0.6
10580  */
10581 void
10582 clutter_actor_get_clip (ClutterActor *self,
10583                         gfloat       *xoff,
10584                         gfloat       *yoff,
10585                         gfloat       *width,
10586                         gfloat       *height)
10587 {
10588   ClutterActorPrivate *priv;
10589
10590   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10591
10592   priv = self->priv;
10593
10594   if (!priv->has_clip)
10595     return;
10596
10597   if (xoff != NULL)
10598     *xoff = priv->clip.x;
10599
10600   if (yoff != NULL)
10601     *yoff = priv->clip.y;
10602
10603   if (width != NULL)
10604     *width = priv->clip.width;
10605
10606   if (height != NULL)
10607     *height = priv->clip.height;
10608 }
10609
10610 /**
10611  * clutter_actor_get_children:
10612  * @self: a #ClutterActor
10613  *
10614  * Retrieves the list of children of @self.
10615  *
10616  * Return value: (transfer container) (element-type ClutterActor): A newly
10617  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10618  *   done.
10619  *
10620  * Since: 1.10
10621  */
10622 GList *
10623 clutter_actor_get_children (ClutterActor *self)
10624 {
10625   ClutterActor *iter;
10626   GList *res;
10627
10628   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10629
10630   /* we walk the list backward so that we can use prepend(),
10631    * which is O(1)
10632    */
10633   for (iter = self->priv->last_child, res = NULL;
10634        iter != NULL;
10635        iter = iter->priv->prev_sibling)
10636     {
10637       res = g_list_prepend (res, iter);
10638     }
10639
10640   return res;
10641 }
10642
10643 /*< private >
10644  * insert_child_at_depth:
10645  * @self: a #ClutterActor
10646  * @child: a #ClutterActor
10647  *
10648  * Inserts @child inside the list of children held by @self, using
10649  * the depth as the insertion criteria.
10650  *
10651  * This sadly makes the insertion not O(1), but we can keep the
10652  * list sorted so that the painters algorithm we use for painting
10653  * the children will work correctly.
10654  */
10655 static void
10656 insert_child_at_depth (ClutterActor *self,
10657                        ClutterActor *child,
10658                        gpointer      dummy G_GNUC_UNUSED)
10659 {
10660   ClutterActor *iter;
10661   float child_depth;
10662
10663   child->priv->parent = self;
10664
10665   child_depth =
10666     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10667
10668   /* special-case the first child */
10669   if (self->priv->n_children == 0)
10670     {
10671       self->priv->first_child = child;
10672       self->priv->last_child = child;
10673
10674       child->priv->next_sibling = NULL;
10675       child->priv->prev_sibling = NULL;
10676
10677       return;
10678     }
10679
10680   /* Find the right place to insert the child so that it will still be
10681      sorted and the child will be after all of the actors at the same
10682      dept */
10683   for (iter = self->priv->first_child;
10684        iter != NULL;
10685        iter = iter->priv->next_sibling)
10686     {
10687       float iter_depth;
10688
10689       iter_depth =
10690         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10691
10692       if (iter_depth > child_depth)
10693         break;
10694     }
10695
10696   if (iter != NULL)
10697     {
10698       ClutterActor *tmp = iter->priv->prev_sibling;
10699
10700       if (tmp != NULL)
10701         tmp->priv->next_sibling = child;
10702
10703       /* Insert the node before the found one */
10704       child->priv->prev_sibling = iter->priv->prev_sibling;
10705       child->priv->next_sibling = iter;
10706       iter->priv->prev_sibling = child;
10707     }
10708   else
10709     {
10710       ClutterActor *tmp = self->priv->last_child;
10711
10712       if (tmp != NULL)
10713         tmp->priv->next_sibling = child;
10714
10715       /* insert the node at the end of the list */
10716       child->priv->prev_sibling = self->priv->last_child;
10717       child->priv->next_sibling = NULL;
10718     }
10719
10720   if (child->priv->prev_sibling == NULL)
10721     self->priv->first_child = child;
10722
10723   if (child->priv->next_sibling == NULL)
10724     self->priv->last_child = child;
10725 }
10726
10727 static void
10728 insert_child_at_index (ClutterActor *self,
10729                        ClutterActor *child,
10730                        gpointer      data_)
10731 {
10732   gint index_ = GPOINTER_TO_INT (data_);
10733
10734   child->priv->parent = self;
10735
10736   if (index_ == 0)
10737     {
10738       ClutterActor *tmp = self->priv->first_child;
10739
10740       if (tmp != NULL)
10741         tmp->priv->prev_sibling = child;
10742
10743       child->priv->prev_sibling = NULL;
10744       child->priv->next_sibling = tmp;
10745     }
10746   else if (index_ < 0 || index_ >= self->priv->n_children)
10747     {
10748       ClutterActor *tmp = self->priv->last_child;
10749
10750       if (tmp != NULL)
10751         tmp->priv->next_sibling = child;
10752
10753       child->priv->prev_sibling = tmp;
10754       child->priv->next_sibling = NULL;
10755     }
10756   else
10757     {
10758       ClutterActor *iter;
10759       int i;
10760
10761       for (iter = self->priv->first_child, i = 0;
10762            iter != NULL;
10763            iter = iter->priv->next_sibling, i += 1)
10764         {
10765           if (index_ == i)
10766             {
10767               ClutterActor *tmp = iter->priv->prev_sibling;
10768
10769               child->priv->prev_sibling = tmp;
10770               child->priv->next_sibling = iter;
10771
10772               iter->priv->prev_sibling = child;
10773
10774               if (tmp != NULL)
10775                 tmp->priv->next_sibling = child;
10776
10777               break;
10778             }
10779         }
10780     }
10781
10782   if (child->priv->prev_sibling == NULL)
10783     self->priv->first_child = child;
10784
10785   if (child->priv->next_sibling == NULL)
10786     self->priv->last_child = child;
10787 }
10788
10789 static void
10790 insert_child_above (ClutterActor *self,
10791                     ClutterActor *child,
10792                     gpointer      data)
10793 {
10794   ClutterActor *sibling = data;
10795
10796   child->priv->parent = self;
10797
10798   if (sibling == NULL)
10799     sibling = self->priv->last_child;
10800
10801   child->priv->prev_sibling = sibling;
10802
10803   if (sibling != NULL)
10804     {
10805       ClutterActor *tmp = sibling->priv->next_sibling;
10806
10807       child->priv->next_sibling = tmp;
10808
10809       if (tmp != NULL)
10810         tmp->priv->prev_sibling = child;
10811
10812       sibling->priv->next_sibling = child;
10813     }
10814   else
10815     child->priv->next_sibling = NULL;
10816
10817   if (child->priv->prev_sibling == NULL)
10818     self->priv->first_child = child;
10819
10820   if (child->priv->next_sibling == NULL)
10821     self->priv->last_child = child;
10822 }
10823
10824 static void
10825 insert_child_below (ClutterActor *self,
10826                     ClutterActor *child,
10827                     gpointer      data)
10828 {
10829   ClutterActor *sibling = data;
10830
10831   child->priv->parent = self;
10832
10833   if (sibling == NULL)
10834     sibling = self->priv->first_child;
10835
10836   child->priv->next_sibling = sibling;
10837
10838   if (sibling != NULL)
10839     {
10840       ClutterActor *tmp = sibling->priv->prev_sibling;
10841
10842       child->priv->prev_sibling = tmp;
10843
10844       if (tmp != NULL)
10845         tmp->priv->next_sibling = child;
10846
10847       sibling->priv->prev_sibling = child;
10848     }
10849   else
10850     child->priv->prev_sibling = NULL;
10851
10852   if (child->priv->prev_sibling == NULL)
10853     self->priv->first_child = child;
10854
10855   if (child->priv->next_sibling == NULL)
10856     self->priv->last_child = child;
10857 }
10858
10859 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10860                                            ClutterActor *child,
10861                                            gpointer      data);
10862
10863 typedef enum {
10864   ADD_CHILD_CREATE_META       = 1 << 0,
10865   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10866   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10867   ADD_CHILD_CHECK_STATE       = 1 << 3,
10868   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10869
10870   /* default flags for public API */
10871   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10872                                ADD_CHILD_EMIT_PARENT_SET |
10873                                ADD_CHILD_EMIT_ACTOR_ADDED |
10874                                ADD_CHILD_CHECK_STATE |
10875                                ADD_CHILD_NOTIFY_FIRST_LAST,
10876
10877   /* flags for legacy/deprecated API */
10878   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10879                                ADD_CHILD_CHECK_STATE |
10880                                ADD_CHILD_NOTIFY_FIRST_LAST
10881 } ClutterActorAddChildFlags;
10882
10883 /*< private >
10884  * clutter_actor_add_child_internal:
10885  * @self: a #ClutterActor
10886  * @child: a #ClutterActor
10887  * @flags: control flags for actions
10888  * @add_func: delegate function
10889  * @data: (closure): data to pass to @add_func
10890  *
10891  * Adds @child to the list of children of @self.
10892  *
10893  * The actual insertion inside the list is delegated to @add_func: this
10894  * function will just set up the state, perform basic checks, and emit
10895  * signals.
10896  *
10897  * The @flags argument is used to perform additional operations.
10898  */
10899 static inline void
10900 clutter_actor_add_child_internal (ClutterActor              *self,
10901                                   ClutterActor              *child,
10902                                   ClutterActorAddChildFlags  flags,
10903                                   ClutterActorAddChildFunc   add_func,
10904                                   gpointer                   data)
10905 {
10906   ClutterTextDirection text_dir;
10907   gboolean create_meta;
10908   gboolean emit_parent_set, emit_actor_added;
10909   gboolean check_state;
10910   gboolean notify_first_last;
10911   ClutterActor *old_first_child, *old_last_child;
10912
10913   if (child->priv->parent != NULL)
10914     {
10915       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10916                  "use clutter_actor_remove_child() first.",
10917                  _clutter_actor_get_debug_name (child),
10918                  _clutter_actor_get_debug_name (child->priv->parent));
10919       return;
10920     }
10921
10922   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10923     {
10924       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10925                  "a child of another actor.",
10926                  _clutter_actor_get_debug_name (child));
10927       return;
10928     }
10929
10930 #if 0
10931   /* XXX - this check disallows calling methods that change the stacking
10932    * order within the destruction sequence, by triggering a critical
10933    * warning first, and leaving the actor in an undefined state, which
10934    * then ends up being caught by an assertion.
10935    *
10936    * the reproducible sequence is:
10937    *
10938    *   - actor gets destroyed;
10939    *   - another actor, linked to the first, will try to change the
10940    *     stacking order of the first actor;
10941    *   - changing the stacking order is a composite operation composed
10942    *     by the following steps:
10943    *     1. ref() the child;
10944    *     2. remove_child_internal(), which removes the reference;
10945    *     3. add_child_internal(), which adds a reference;
10946    *   - the state of the actor is not changed between (2) and (3), as
10947    *     it could be an expensive recomputation;
10948    *   - if (3) bails out, then the actor is in an undefined state, but
10949    *     still alive;
10950    *   - the destruction sequence terminates, but the actor is unparented
10951    *     while its state indicates being parented instead.
10952    *   - assertion failure.
10953    *
10954    * the obvious fix would be to decompose each set_child_*_sibling()
10955    * method into proper remove_child()/add_child(), with state validation;
10956    * this may cause excessive work, though, and trigger a cascade of other
10957    * bugs in code that assumes that a change in the stacking order is an
10958    * atomic operation.
10959    *
10960    * another potential fix is to just remove this check here, and let
10961    * code doing stacking order changes inside the destruction sequence
10962    * of an actor continue doing the work.
10963    *
10964    * the third fix is to silently bail out early from every
10965    * set_child_*_sibling() and set_child_at_index() method, and avoid
10966    * doing work.
10967    *
10968    * I have a preference for the second solution, since it involves the
10969    * least amount of work, and the least amount of code duplication.
10970    *
10971    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10972    */
10973   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10974     {
10975       g_warning ("The actor '%s' is currently being destroyed, and "
10976                  "cannot be added as a child of another actor.",
10977                  _clutter_actor_get_debug_name (child));
10978       return;
10979     }
10980 #endif
10981
10982   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10983   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10984   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10985   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10986   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10987
10988   old_first_child = self->priv->first_child;
10989   old_last_child = self->priv->last_child;
10990
10991   g_object_freeze_notify (G_OBJECT (self));
10992
10993   if (create_meta)
10994     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10995
10996   g_object_ref_sink (child);
10997   child->priv->parent = NULL;
10998   child->priv->next_sibling = NULL;
10999   child->priv->prev_sibling = NULL;
11000
11001   /* delegate the actual insertion */
11002   add_func (self, child, data);
11003
11004   g_assert (child->priv->parent == self);
11005
11006   self->priv->n_children += 1;
11007
11008   self->priv->age += 1;
11009
11010   /* if push_internal() has been called then we automatically set
11011    * the flag on the actor
11012    */
11013   if (self->priv->internal_child)
11014     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11015
11016   /* clutter_actor_reparent() will emit ::parent-set for us */
11017   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11018     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11019
11020   if (check_state)
11021     {
11022       /* If parent is mapped or realized, we need to also be mapped or
11023        * realized once we're inside the parent.
11024        */
11025       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11026
11027       /* propagate the parent's text direction to the child */
11028       text_dir = clutter_actor_get_text_direction (self);
11029       clutter_actor_set_text_direction (child, text_dir);
11030     }
11031
11032   if (child->priv->show_on_set_parent)
11033     clutter_actor_show (child);
11034
11035   if (CLUTTER_ACTOR_IS_MAPPED (child))
11036     clutter_actor_queue_redraw (child);
11037
11038   /* maintain the invariant that if an actor needs layout,
11039    * its parents do as well
11040    */
11041   if (child->priv->needs_width_request ||
11042       child->priv->needs_height_request ||
11043       child->priv->needs_allocation)
11044     {
11045       /* we work around the short-circuiting we do
11046        * in clutter_actor_queue_relayout() since we
11047        * want to force a relayout
11048        */
11049       child->priv->needs_width_request = TRUE;
11050       child->priv->needs_height_request = TRUE;
11051       child->priv->needs_allocation = TRUE;
11052
11053       clutter_actor_queue_relayout (child->priv->parent);
11054     }
11055
11056   if (emit_actor_added)
11057     g_signal_emit_by_name (self, "actor-added", child);
11058
11059   if (notify_first_last)
11060     {
11061       if (old_first_child != self->priv->first_child)
11062         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11063
11064       if (old_last_child != self->priv->last_child)
11065         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11066     }
11067
11068   g_object_thaw_notify (G_OBJECT (self));
11069 }
11070
11071 /**
11072  * clutter_actor_add_child:
11073  * @self: a #ClutterActor
11074  * @child: a #ClutterActor
11075  *
11076  * Adds @child to the children of @self.
11077  *
11078  * This function will acquire a reference on @child that will only
11079  * be released when calling clutter_actor_remove_child().
11080  *
11081  * This function will take into consideration the #ClutterActor:depth
11082  * of @child, and will keep the list of children sorted.
11083  *
11084  * This function will emit the #ClutterContainer::actor-added signal
11085  * on @self.
11086  *
11087  * Since: 1.10
11088  */
11089 void
11090 clutter_actor_add_child (ClutterActor *self,
11091                          ClutterActor *child)
11092 {
11093   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11094   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11095   g_return_if_fail (self != child);
11096   g_return_if_fail (child->priv->parent == NULL);
11097
11098   clutter_actor_add_child_internal (self, child,
11099                                     ADD_CHILD_DEFAULT_FLAGS,
11100                                     insert_child_at_depth,
11101                                     NULL);
11102 }
11103
11104 /**
11105  * clutter_actor_insert_child_at_index:
11106  * @self: a #ClutterActor
11107  * @child: a #ClutterActor
11108  * @index_: the index
11109  *
11110  * Inserts @child into the list of children of @self, using the
11111  * given @index_. If @index_ is greater than the number of children
11112  * in @self, or is less than 0, then the new child is added at the end.
11113  *
11114  * This function will acquire a reference on @child that will only
11115  * be released when calling clutter_actor_remove_child().
11116  *
11117  * This function will not take into consideration the #ClutterActor:depth
11118  * of @child.
11119  *
11120  * This function will emit the #ClutterContainer::actor-added signal
11121  * on @self.
11122  *
11123  * Since: 1.10
11124  */
11125 void
11126 clutter_actor_insert_child_at_index (ClutterActor *self,
11127                                      ClutterActor *child,
11128                                      gint          index_)
11129 {
11130   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11131   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11132   g_return_if_fail (self != child);
11133   g_return_if_fail (child->priv->parent == NULL);
11134
11135   clutter_actor_add_child_internal (self, child,
11136                                     ADD_CHILD_DEFAULT_FLAGS,
11137                                     insert_child_at_index,
11138                                     GINT_TO_POINTER (index_));
11139 }
11140
11141 /**
11142  * clutter_actor_insert_child_above:
11143  * @self: a #ClutterActor
11144  * @child: a #ClutterActor
11145  * @sibling: (allow-none): a child of @self, or %NULL
11146  *
11147  * Inserts @child into the list of children of @self, above another
11148  * child of @self or, if @sibling is %NULL, above all the children
11149  * of @self.
11150  *
11151  * This function will acquire a reference on @child that will only
11152  * be released when calling clutter_actor_remove_child().
11153  *
11154  * This function will not take into consideration the #ClutterActor:depth
11155  * of @child.
11156  *
11157  * This function will emit the #ClutterContainer::actor-added signal
11158  * on @self.
11159  *
11160  * Since: 1.10
11161  */
11162 void
11163 clutter_actor_insert_child_above (ClutterActor *self,
11164                                   ClutterActor *child,
11165                                   ClutterActor *sibling)
11166 {
11167   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11168   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11169   g_return_if_fail (self != child);
11170   g_return_if_fail (child != sibling);
11171   g_return_if_fail (child->priv->parent == NULL);
11172   g_return_if_fail (sibling == NULL ||
11173                     (CLUTTER_IS_ACTOR (sibling) &&
11174                      sibling->priv->parent == self));
11175
11176   clutter_actor_add_child_internal (self, child,
11177                                     ADD_CHILD_DEFAULT_FLAGS,
11178                                     insert_child_above,
11179                                     sibling);
11180 }
11181
11182 /**
11183  * clutter_actor_insert_child_below:
11184  * @self: a #ClutterActor
11185  * @child: a #ClutterActor
11186  * @sibling: (allow-none): a child of @self, or %NULL
11187  *
11188  * Inserts @child into the list of children of @self, below another
11189  * child of @self or, if @sibling is %NULL, below all the children
11190  * of @self.
11191  *
11192  * This function will acquire a reference on @child that will only
11193  * be released when calling clutter_actor_remove_child().
11194  *
11195  * This function will not take into consideration the #ClutterActor:depth
11196  * of @child.
11197  *
11198  * This function will emit the #ClutterContainer::actor-added signal
11199  * on @self.
11200  *
11201  * Since: 1.10
11202  */
11203 void
11204 clutter_actor_insert_child_below (ClutterActor *self,
11205                                   ClutterActor *child,
11206                                   ClutterActor *sibling)
11207 {
11208   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11209   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11210   g_return_if_fail (self != child);
11211   g_return_if_fail (child != sibling);
11212   g_return_if_fail (child->priv->parent == NULL);
11213   g_return_if_fail (sibling == NULL ||
11214                     (CLUTTER_IS_ACTOR (sibling) &&
11215                      sibling->priv->parent == self));
11216
11217   clutter_actor_add_child_internal (self, child,
11218                                     ADD_CHILD_DEFAULT_FLAGS,
11219                                     insert_child_below,
11220                                     sibling);
11221 }
11222
11223 /**
11224  * clutter_actor_set_parent:
11225  * @self: A #ClutterActor
11226  * @parent: A new #ClutterActor parent
11227  *
11228  * Sets the parent of @self to @parent.
11229  *
11230  * This function will result in @parent acquiring a reference on @self,
11231  * eventually by sinking its floating reference first. The reference
11232  * will be released by clutter_actor_unparent().
11233  *
11234  * This function should only be called by legacy #ClutterActor<!-- -->s
11235  * implementing the #ClutterContainer interface.
11236  *
11237  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11238  */
11239 void
11240 clutter_actor_set_parent (ClutterActor *self,
11241                           ClutterActor *parent)
11242 {
11243   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11244   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11245   g_return_if_fail (self != parent);
11246   g_return_if_fail (self->priv->parent == NULL);
11247
11248   /* as this function will be called inside ClutterContainer::add
11249    * implementations or when building up a composite actor, we have
11250    * to preserve the old behaviour, and not create child meta or
11251    * emit the ::actor-added signal, to avoid recursion or double
11252    * emissions
11253    */
11254   clutter_actor_add_child_internal (parent, self,
11255                                     ADD_CHILD_LEGACY_FLAGS,
11256                                     insert_child_at_depth,
11257                                     NULL);
11258 }
11259
11260 /**
11261  * clutter_actor_get_parent:
11262  * @self: A #ClutterActor
11263  *
11264  * Retrieves the parent of @self.
11265  *
11266  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11267  *  if no parent is set
11268  */
11269 ClutterActor *
11270 clutter_actor_get_parent (ClutterActor *self)
11271 {
11272   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11273
11274   return self->priv->parent;
11275 }
11276
11277 /**
11278  * clutter_actor_get_paint_visibility:
11279  * @self: A #ClutterActor
11280  *
11281  * Retrieves the 'paint' visibility of an actor recursively checking for non
11282  * visible parents.
11283  *
11284  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11285  *
11286  * Return Value: %TRUE if the actor is visibile and will be painted.
11287  *
11288  * Since: 0.8.4
11289  */
11290 gboolean
11291 clutter_actor_get_paint_visibility (ClutterActor *actor)
11292 {
11293   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11294
11295   return CLUTTER_ACTOR_IS_MAPPED (actor);
11296 }
11297
11298 /**
11299  * clutter_actor_remove_child:
11300  * @self: a #ClutterActor
11301  * @child: a #ClutterActor
11302  *
11303  * Removes @child from the children of @self.
11304  *
11305  * This function will release the reference added by
11306  * clutter_actor_add_child(), so if you want to keep using @child
11307  * you will have to acquire a referenced on it before calling this
11308  * function.
11309  *
11310  * This function will emit the #ClutterContainer::actor-removed
11311  * signal on @self.
11312  *
11313  * Since: 1.10
11314  */
11315 void
11316 clutter_actor_remove_child (ClutterActor *self,
11317                             ClutterActor *child)
11318 {
11319   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11320   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11321   g_return_if_fail (self != child);
11322   g_return_if_fail (child->priv->parent != NULL);
11323   g_return_if_fail (child->priv->parent == self);
11324
11325   clutter_actor_remove_child_internal (self, child,
11326                                        REMOVE_CHILD_DEFAULT_FLAGS);
11327 }
11328
11329 /**
11330  * clutter_actor_remove_all_children:
11331  * @self: a #ClutterActor
11332  *
11333  * Removes all children of @self.
11334  *
11335  * This function releases the reference added by inserting a child actor
11336  * in the list of children of @self.
11337  *
11338  * If the reference count of a child drops to zero, the child will be
11339  * destroyed. If you want to ensure the destruction of all the children
11340  * of @self, use clutter_actor_destroy_all_children().
11341  *
11342  * Since: 1.10
11343  */
11344 void
11345 clutter_actor_remove_all_children (ClutterActor *self)
11346 {
11347   ClutterActorIter iter;
11348
11349   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11350
11351   if (self->priv->n_children == 0)
11352     return;
11353
11354   g_object_freeze_notify (G_OBJECT (self));
11355
11356   clutter_actor_iter_init (&iter, self);
11357   while (clutter_actor_iter_next (&iter, NULL))
11358     clutter_actor_iter_remove (&iter);
11359
11360   g_object_thaw_notify (G_OBJECT (self));
11361
11362   /* sanity check */
11363   g_assert (self->priv->first_child == NULL);
11364   g_assert (self->priv->last_child == NULL);
11365   g_assert (self->priv->n_children == 0);
11366 }
11367
11368 /**
11369  * clutter_actor_destroy_all_children:
11370  * @self: a #ClutterActor
11371  *
11372  * Destroys all children of @self.
11373  *
11374  * This function releases the reference added by inserting a child
11375  * actor in the list of children of @self, and ensures that the
11376  * #ClutterActor::destroy signal is emitted on each child of the
11377  * actor.
11378  *
11379  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11380  * when its reference count drops to 0; the default handler of the
11381  * #ClutterActor::destroy signal will destroy all the children of an
11382  * actor. This function ensures that all children are destroyed, instead
11383  * of just removed from @self, unlike clutter_actor_remove_all_children()
11384  * which will merely release the reference and remove each child.
11385  *
11386  * Unless you acquired an additional reference on each child of @self
11387  * prior to calling clutter_actor_remove_all_children() and want to reuse
11388  * the actors, you should use clutter_actor_destroy_all_children() in
11389  * order to make sure that children are destroyed and signal handlers
11390  * are disconnected even in cases where circular references prevent this
11391  * from automatically happening through reference counting alone.
11392  *
11393  * Since: 1.10
11394  */
11395 void
11396 clutter_actor_destroy_all_children (ClutterActor *self)
11397 {
11398   ClutterActorIter iter;
11399
11400   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11401
11402   if (self->priv->n_children == 0)
11403     return;
11404
11405   g_object_freeze_notify (G_OBJECT (self));
11406
11407   clutter_actor_iter_init (&iter, self);
11408   while (clutter_actor_iter_next (&iter, NULL))
11409     clutter_actor_iter_destroy (&iter);
11410
11411   g_object_thaw_notify (G_OBJECT (self));
11412
11413   /* sanity check */
11414   g_assert (self->priv->first_child == NULL);
11415   g_assert (self->priv->last_child == NULL);
11416   g_assert (self->priv->n_children == 0);
11417 }
11418
11419 typedef struct _InsertBetweenData {
11420   ClutterActor *prev_sibling;
11421   ClutterActor *next_sibling;
11422 } InsertBetweenData;
11423
11424 static void
11425 insert_child_between (ClutterActor *self,
11426                       ClutterActor *child,
11427                       gpointer      data_)
11428 {
11429   InsertBetweenData *data = data_;
11430   ClutterActor *prev_sibling = data->prev_sibling;
11431   ClutterActor *next_sibling = data->next_sibling;
11432
11433   child->priv->parent = self;
11434   child->priv->prev_sibling = prev_sibling;
11435   child->priv->next_sibling = next_sibling;
11436
11437   if (prev_sibling != NULL)
11438     prev_sibling->priv->next_sibling = child;
11439
11440   if (next_sibling != NULL)
11441     next_sibling->priv->prev_sibling = child;
11442
11443   if (child->priv->prev_sibling == NULL)
11444     self->priv->first_child = child;
11445
11446   if (child->priv->next_sibling == NULL)
11447     self->priv->last_child = child;
11448 }
11449
11450 /**
11451  * clutter_actor_replace_child:
11452  * @self: a #ClutterActor
11453  * @old_child: the child of @self to replace
11454  * @new_child: the #ClutterActor to replace @old_child
11455  *
11456  * Replaces @old_child with @new_child in the list of children of @self.
11457  *
11458  * Since: 1.10
11459  */
11460 void
11461 clutter_actor_replace_child (ClutterActor *self,
11462                              ClutterActor *old_child,
11463                              ClutterActor *new_child)
11464 {
11465   ClutterActor *prev_sibling, *next_sibling;
11466   InsertBetweenData clos;
11467
11468   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11469   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11470   g_return_if_fail (old_child->priv->parent == self);
11471   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11472   g_return_if_fail (old_child != new_child);
11473   g_return_if_fail (new_child != self);
11474   g_return_if_fail (new_child->priv->parent == NULL);
11475
11476   prev_sibling = old_child->priv->prev_sibling;
11477   next_sibling = old_child->priv->next_sibling;
11478   clutter_actor_remove_child_internal (self, old_child,
11479                                        REMOVE_CHILD_DEFAULT_FLAGS);
11480
11481   clos.prev_sibling = prev_sibling;
11482   clos.next_sibling = next_sibling;
11483   clutter_actor_add_child_internal (self, new_child,
11484                                     ADD_CHILD_DEFAULT_FLAGS,
11485                                     insert_child_between,
11486                                     &clos);
11487 }
11488
11489 /**
11490  * clutter_actor_unparent:
11491  * @self: a #ClutterActor
11492  *
11493  * Removes the parent of @self.
11494  *
11495  * This will cause the parent of @self to release the reference
11496  * acquired when calling clutter_actor_set_parent(), so if you
11497  * want to keep @self you will have to acquire a reference of
11498  * your own, through g_object_ref().
11499  *
11500  * This function should only be called by legacy #ClutterActor<!-- -->s
11501  * implementing the #ClutterContainer interface.
11502  *
11503  * Since: 0.1.1
11504  *
11505  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11506  */
11507 void
11508 clutter_actor_unparent (ClutterActor *self)
11509 {
11510   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11511
11512   if (self->priv->parent == NULL)
11513     return;
11514
11515   clutter_actor_remove_child_internal (self->priv->parent, self,
11516                                        REMOVE_CHILD_LEGACY_FLAGS);
11517 }
11518
11519 /**
11520  * clutter_actor_reparent:
11521  * @self: a #ClutterActor
11522  * @new_parent: the new #ClutterActor parent
11523  *
11524  * Resets the parent actor of @self.
11525  *
11526  * This function is logically equivalent to calling clutter_actor_unparent()
11527  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11528  * ensures the child is not finalized when unparented, and emits the
11529  * #ClutterActor::parent-set signal only once.
11530  *
11531  * In reality, calling this function is less useful than it sounds, as some
11532  * application code may rely on changes in the intermediate state between
11533  * removal and addition of the actor from its old parent to the @new_parent.
11534  * Thus, it is strongly encouraged to avoid using this function in application
11535  * code.
11536  *
11537  * Since: 0.2
11538  *
11539  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11540  *   clutter_actor_add_child() instead; remember to take a reference on
11541  *   the actor being removed before calling clutter_actor_remove_child()
11542  *   to avoid the reference count dropping to zero and the actor being
11543  *   destroyed.
11544  */
11545 void
11546 clutter_actor_reparent (ClutterActor *self,
11547                         ClutterActor *new_parent)
11548 {
11549   ClutterActorPrivate *priv;
11550
11551   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11552   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11553   g_return_if_fail (self != new_parent);
11554
11555   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11556     {
11557       g_warning ("Cannot set a parent on a toplevel actor");
11558       return;
11559     }
11560
11561   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11562     {
11563       g_warning ("Cannot set a parent currently being destroyed");
11564       return;
11565     }
11566
11567   priv = self->priv;
11568
11569   if (priv->parent != new_parent)
11570     {
11571       ClutterActor *old_parent;
11572
11573       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11574
11575       old_parent = priv->parent;
11576
11577       g_object_ref (self);
11578
11579       if (old_parent != NULL)
11580         {
11581          /* go through the Container implementation if this is a regular
11582           * child and not an internal one
11583           */
11584          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11585            {
11586              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11587
11588              /* this will have to call unparent() */
11589              clutter_container_remove_actor (parent, self);
11590            }
11591          else
11592            clutter_actor_remove_child_internal (old_parent, self,
11593                                                 REMOVE_CHILD_LEGACY_FLAGS);
11594         }
11595
11596       /* Note, will call set_parent() */
11597       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11598         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11599       else
11600         clutter_actor_add_child_internal (new_parent, self,
11601                                           ADD_CHILD_LEGACY_FLAGS,
11602                                           insert_child_at_depth,
11603                                           NULL);
11604
11605       /* we emit the ::parent-set signal once */
11606       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11607
11608       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11609
11610       /* the IN_REPARENT flag suspends state updates */
11611       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11612
11613       g_object_unref (self);
11614    }
11615 }
11616
11617 /**
11618  * clutter_actor_contains:
11619  * @self: A #ClutterActor
11620  * @descendant: A #ClutterActor, possibly contained in @self
11621  *
11622  * Determines if @descendant is contained inside @self (either as an
11623  * immediate child, or as a deeper descendant). If @self and
11624  * @descendant point to the same actor then it will also return %TRUE.
11625  *
11626  * Return value: whether @descendent is contained within @self
11627  *
11628  * Since: 1.4
11629  */
11630 gboolean
11631 clutter_actor_contains (ClutterActor *self,
11632                         ClutterActor *descendant)
11633 {
11634   ClutterActor *actor;
11635
11636   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11637   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11638
11639   for (actor = descendant; actor; actor = actor->priv->parent)
11640     if (actor == self)
11641       return TRUE;
11642
11643   return FALSE;
11644 }
11645
11646 /**
11647  * clutter_actor_set_child_above_sibling:
11648  * @self: a #ClutterActor
11649  * @child: a #ClutterActor child of @self
11650  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11651  *
11652  * Sets @child to be above @sibling in the list of children of @self.
11653  *
11654  * If @sibling is %NULL, @child will be the new last child of @self.
11655  *
11656  * This function is logically equivalent to removing @child and using
11657  * clutter_actor_insert_child_above(), but it will not emit signals
11658  * or change state on @child.
11659  *
11660  * Since: 1.10
11661  */
11662 void
11663 clutter_actor_set_child_above_sibling (ClutterActor *self,
11664                                        ClutterActor *child,
11665                                        ClutterActor *sibling)
11666 {
11667   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11668   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11669   g_return_if_fail (child->priv->parent == self);
11670   g_return_if_fail (child != sibling);
11671   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11672
11673   if (sibling != NULL)
11674     g_return_if_fail (sibling->priv->parent == self);
11675
11676   /* we don't want to change the state of child, or emit signals, or
11677    * regenerate ChildMeta instances here, but we still want to follow
11678    * the correct sequence of steps encoded in remove_child() and
11679    * add_child(), so that correctness is ensured, and we only go
11680    * through one known code path.
11681    */
11682   g_object_ref (child);
11683   clutter_actor_remove_child_internal (self, child, 0);
11684   clutter_actor_add_child_internal (self, child,
11685                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11686                                     insert_child_above,
11687                                     sibling);
11688
11689   clutter_actor_queue_relayout (self);
11690 }
11691
11692 /**
11693  * clutter_actor_set_child_below_sibling:
11694  * @self: a #ClutterActor
11695  * @child: a #ClutterActor child of @self
11696  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11697  *
11698  * Sets @child to be below @sibling in the list of children of @self.
11699  *
11700  * If @sibling is %NULL, @child will be the new first child of @self.
11701  *
11702  * This function is logically equivalent to removing @self and using
11703  * clutter_actor_insert_child_below(), but it will not emit signals
11704  * or change state on @child.
11705  *
11706  * Since: 1.10
11707  */
11708 void
11709 clutter_actor_set_child_below_sibling (ClutterActor *self,
11710                                        ClutterActor *child,
11711                                        ClutterActor *sibling)
11712 {
11713   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11714   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11715   g_return_if_fail (child->priv->parent == self);
11716   g_return_if_fail (child != sibling);
11717   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11718
11719   if (sibling != NULL)
11720     g_return_if_fail (sibling->priv->parent == self);
11721
11722   /* see the comment in set_child_above_sibling() */
11723   g_object_ref (child);
11724   clutter_actor_remove_child_internal (self, child, 0);
11725   clutter_actor_add_child_internal (self, child,
11726                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11727                                     insert_child_below,
11728                                     sibling);
11729
11730   clutter_actor_queue_relayout (self);
11731 }
11732
11733 /**
11734  * clutter_actor_set_child_at_index:
11735  * @self: a #ClutterActor
11736  * @child: a #ClutterActor child of @self
11737  * @index_: the new index for @child
11738  *
11739  * Changes the index of @child in the list of children of @self.
11740  *
11741  * This function is logically equivalent to removing @child and
11742  * calling clutter_actor_insert_child_at_index(), but it will not
11743  * emit signals or change state on @child.
11744  *
11745  * Since: 1.10
11746  */
11747 void
11748 clutter_actor_set_child_at_index (ClutterActor *self,
11749                                   ClutterActor *child,
11750                                   gint          index_)
11751 {
11752   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11753   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11754   g_return_if_fail (child->priv->parent == self);
11755   g_return_if_fail (index_ <= self->priv->n_children);
11756
11757   g_object_ref (child);
11758   clutter_actor_remove_child_internal (self, child, 0);
11759   clutter_actor_add_child_internal (self, child,
11760                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11761                                     insert_child_at_index,
11762                                     GINT_TO_POINTER (index_));
11763
11764   clutter_actor_queue_relayout (self);
11765 }
11766
11767 /**
11768  * clutter_actor_raise:
11769  * @self: A #ClutterActor
11770  * @below: (allow-none): A #ClutterActor to raise above.
11771  *
11772  * Puts @self above @below.
11773  *
11774  * Both actors must have the same parent, and the parent must implement
11775  * the #ClutterContainer interface
11776  *
11777  * This function calls clutter_container_raise_child() internally.
11778  *
11779  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11780  */
11781 void
11782 clutter_actor_raise (ClutterActor *self,
11783                      ClutterActor *below)
11784 {
11785   ClutterActor *parent;
11786
11787   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11788
11789   parent = clutter_actor_get_parent (self);
11790   if (parent == NULL)
11791     {
11792       g_warning ("%s: Actor '%s' is not inside a container",
11793                  G_STRFUNC,
11794                  _clutter_actor_get_debug_name (self));
11795       return;
11796     }
11797
11798   if (below != NULL)
11799     {
11800       if (parent != clutter_actor_get_parent (below))
11801         {
11802           g_warning ("%s Actor '%s' is not in the same container as "
11803                      "actor '%s'",
11804                      G_STRFUNC,
11805                      _clutter_actor_get_debug_name (self),
11806                      _clutter_actor_get_debug_name (below));
11807           return;
11808         }
11809     }
11810
11811   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11812 }
11813
11814 /**
11815  * clutter_actor_lower:
11816  * @self: A #ClutterActor
11817  * @above: (allow-none): A #ClutterActor to lower below
11818  *
11819  * Puts @self below @above.
11820  *
11821  * Both actors must have the same parent, and the parent must implement
11822  * the #ClutterContainer interface.
11823  *
11824  * This function calls clutter_container_lower_child() internally.
11825  *
11826  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11827  */
11828 void
11829 clutter_actor_lower (ClutterActor *self,
11830                      ClutterActor *above)
11831 {
11832   ClutterActor *parent;
11833
11834   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11835
11836   parent = clutter_actor_get_parent (self);
11837   if (parent == NULL)
11838     {
11839       g_warning ("%s: Actor of type %s is not inside a container",
11840                  G_STRFUNC,
11841                  _clutter_actor_get_debug_name (self));
11842       return;
11843     }
11844
11845   if (above)
11846     {
11847       if (parent != clutter_actor_get_parent (above))
11848         {
11849           g_warning ("%s: Actor '%s' is not in the same container as "
11850                      "actor '%s'",
11851                      G_STRFUNC,
11852                      _clutter_actor_get_debug_name (self),
11853                      _clutter_actor_get_debug_name (above));
11854           return;
11855         }
11856     }
11857
11858   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11859 }
11860
11861 /**
11862  * clutter_actor_raise_top:
11863  * @self: A #ClutterActor
11864  *
11865  * Raises @self to the top.
11866  *
11867  * This function calls clutter_actor_raise() internally.
11868  *
11869  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11870  *   a %NULL sibling, instead.
11871  */
11872 void
11873 clutter_actor_raise_top (ClutterActor *self)
11874 {
11875   clutter_actor_raise (self, NULL);
11876 }
11877
11878 /**
11879  * clutter_actor_lower_bottom:
11880  * @self: A #ClutterActor
11881  *
11882  * Lowers @self to the bottom.
11883  *
11884  * This function calls clutter_actor_lower() internally.
11885  *
11886  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11887  *   a %NULL sibling, instead.
11888  */
11889 void
11890 clutter_actor_lower_bottom (ClutterActor *self)
11891 {
11892   clutter_actor_lower (self, NULL);
11893 }
11894
11895 /*
11896  * Event handling
11897  */
11898
11899 /**
11900  * clutter_actor_event:
11901  * @actor: a #ClutterActor
11902  * @event: a #ClutterEvent
11903  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11904  *
11905  * This function is used to emit an event on the main stage.
11906  * You should rarely need to use this function, except for
11907  * synthetising events.
11908  *
11909  * Return value: the return value from the signal emission: %TRUE
11910  *   if the actor handled the event, or %FALSE if the event was
11911  *   not handled
11912  *
11913  * Since: 0.6
11914  */
11915 gboolean
11916 clutter_actor_event (ClutterActor *actor,
11917                      ClutterEvent *event,
11918                      gboolean      capture)
11919 {
11920   gboolean retval = FALSE;
11921   gint signal_num = -1;
11922
11923   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11924   g_return_val_if_fail (event != NULL, FALSE);
11925
11926   g_object_ref (actor);
11927
11928   if (capture)
11929     {
11930       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11931                      event,
11932                      &retval);
11933       goto out;
11934     }
11935
11936   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11937
11938   if (!retval)
11939     {
11940       switch (event->type)
11941         {
11942         case CLUTTER_NOTHING:
11943           break;
11944         case CLUTTER_BUTTON_PRESS:
11945           signal_num = BUTTON_PRESS_EVENT;
11946           break;
11947         case CLUTTER_BUTTON_RELEASE:
11948           signal_num = BUTTON_RELEASE_EVENT;
11949           break;
11950         case CLUTTER_SCROLL:
11951           signal_num = SCROLL_EVENT;
11952           break;
11953         case CLUTTER_KEY_PRESS:
11954           signal_num = KEY_PRESS_EVENT;
11955           break;
11956         case CLUTTER_KEY_RELEASE:
11957           signal_num = KEY_RELEASE_EVENT;
11958           break;
11959         case CLUTTER_MOTION:
11960           signal_num = MOTION_EVENT;
11961           break;
11962         case CLUTTER_ENTER:
11963           signal_num = ENTER_EVENT;
11964           break;
11965         case CLUTTER_LEAVE:
11966           signal_num = LEAVE_EVENT;
11967           break;
11968         case CLUTTER_DELETE:
11969         case CLUTTER_DESTROY_NOTIFY:
11970         case CLUTTER_CLIENT_MESSAGE:
11971         default:
11972           signal_num = -1;
11973           break;
11974         }
11975
11976       if (signal_num != -1)
11977         g_signal_emit (actor, actor_signals[signal_num], 0,
11978                        event, &retval);
11979     }
11980
11981 out:
11982   g_object_unref (actor);
11983
11984   return retval;
11985 }
11986
11987 /**
11988  * clutter_actor_set_reactive:
11989  * @actor: a #ClutterActor
11990  * @reactive: whether the actor should be reactive to events
11991  *
11992  * Sets @actor as reactive. Reactive actors will receive events.
11993  *
11994  * Since: 0.6
11995  */
11996 void
11997 clutter_actor_set_reactive (ClutterActor *actor,
11998                             gboolean      reactive)
11999 {
12000   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12001
12002   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12003     return;
12004
12005   if (reactive)
12006     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12007   else
12008     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12009
12010   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12011 }
12012
12013 /**
12014  * clutter_actor_get_reactive:
12015  * @actor: a #ClutterActor
12016  *
12017  * Checks whether @actor is marked as reactive.
12018  *
12019  * Return value: %TRUE if the actor is reactive
12020  *
12021  * Since: 0.6
12022  */
12023 gboolean
12024 clutter_actor_get_reactive (ClutterActor *actor)
12025 {
12026   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12027
12028   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12029 }
12030
12031 /**
12032  * clutter_actor_get_anchor_point:
12033  * @self: a #ClutterActor
12034  * @anchor_x: (out): return location for the X coordinate of the anchor point
12035  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12036  *
12037  * Gets the current anchor point of the @actor in pixels.
12038  *
12039  * Since: 0.6
12040  */
12041 void
12042 clutter_actor_get_anchor_point (ClutterActor *self,
12043                                 gfloat       *anchor_x,
12044                                 gfloat       *anchor_y)
12045 {
12046   const ClutterTransformInfo *info;
12047
12048   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12049
12050   info = _clutter_actor_get_transform_info_or_defaults (self);
12051   clutter_anchor_coord_get_units (self, &info->anchor,
12052                                   anchor_x,
12053                                   anchor_y,
12054                                   NULL);
12055 }
12056
12057 /**
12058  * clutter_actor_set_anchor_point:
12059  * @self: a #ClutterActor
12060  * @anchor_x: X coordinate of the anchor point
12061  * @anchor_y: Y coordinate of the anchor point
12062  *
12063  * Sets an anchor point for @self. The anchor point is a point in the
12064  * coordinate space of an actor to which the actor position within its
12065  * parent is relative; the default is (0, 0), i.e. the top-left corner
12066  * of the actor.
12067  *
12068  * Since: 0.6
12069  */
12070 void
12071 clutter_actor_set_anchor_point (ClutterActor *self,
12072                                 gfloat        anchor_x,
12073                                 gfloat        anchor_y)
12074 {
12075   ClutterTransformInfo *info;
12076   ClutterActorPrivate *priv;
12077   gboolean changed = FALSE;
12078   gfloat old_anchor_x, old_anchor_y;
12079   GObject *obj;
12080
12081   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12082
12083   obj = G_OBJECT (self);
12084   priv = self->priv;
12085   info = _clutter_actor_get_transform_info (self);
12086
12087   g_object_freeze_notify (obj);
12088
12089   clutter_anchor_coord_get_units (self, &info->anchor,
12090                                   &old_anchor_x,
12091                                   &old_anchor_y,
12092                                   NULL);
12093
12094   if (info->anchor.is_fractional)
12095     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12096
12097   if (old_anchor_x != anchor_x)
12098     {
12099       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12100       changed = TRUE;
12101     }
12102
12103   if (old_anchor_y != anchor_y)
12104     {
12105       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12106       changed = TRUE;
12107     }
12108
12109   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12110
12111   if (changed)
12112     {
12113       priv->transform_valid = FALSE;
12114       clutter_actor_queue_redraw (self);
12115     }
12116
12117   g_object_thaw_notify (obj);
12118 }
12119
12120 /**
12121  * clutter_actor_get_anchor_point_gravity:
12122  * @self: a #ClutterActor
12123  *
12124  * Retrieves the anchor position expressed as a #ClutterGravity. If
12125  * the anchor point was specified using pixels or units this will
12126  * return %CLUTTER_GRAVITY_NONE.
12127  *
12128  * Return value: the #ClutterGravity used by the anchor point
12129  *
12130  * Since: 1.0
12131  */
12132 ClutterGravity
12133 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12134 {
12135   const ClutterTransformInfo *info;
12136
12137   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12138
12139   info = _clutter_actor_get_transform_info_or_defaults (self);
12140
12141   return clutter_anchor_coord_get_gravity (&info->anchor);
12142 }
12143
12144 /**
12145  * clutter_actor_move_anchor_point:
12146  * @self: a #ClutterActor
12147  * @anchor_x: X coordinate of the anchor point
12148  * @anchor_y: Y coordinate of the anchor point
12149  *
12150  * Sets an anchor point for the actor, and adjusts the actor postion so that
12151  * the relative position of the actor toward its parent remains the same.
12152  *
12153  * Since: 0.6
12154  */
12155 void
12156 clutter_actor_move_anchor_point (ClutterActor *self,
12157                                  gfloat        anchor_x,
12158                                  gfloat        anchor_y)
12159 {
12160   gfloat old_anchor_x, old_anchor_y;
12161   const ClutterTransformInfo *info;
12162
12163   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12164
12165   info = _clutter_actor_get_transform_info (self);
12166   clutter_anchor_coord_get_units (self, &info->anchor,
12167                                   &old_anchor_x,
12168                                   &old_anchor_y,
12169                                   NULL);
12170
12171   g_object_freeze_notify (G_OBJECT (self));
12172
12173   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12174
12175   if (self->priv->position_set)
12176     clutter_actor_move_by (self,
12177                            anchor_x - old_anchor_x,
12178                            anchor_y - old_anchor_y);
12179
12180   g_object_thaw_notify (G_OBJECT (self));
12181 }
12182
12183 /**
12184  * clutter_actor_move_anchor_point_from_gravity:
12185  * @self: a #ClutterActor
12186  * @gravity: #ClutterGravity.
12187  *
12188  * Sets an anchor point on the actor based on the given gravity, adjusting the
12189  * actor postion so that its relative position within its parent remains
12190  * unchanged.
12191  *
12192  * Since version 1.0 the anchor point will be stored as a gravity so
12193  * that if the actor changes size then the anchor point will move. For
12194  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12195  * and later double the size of the actor, the anchor point will move
12196  * to the bottom right.
12197  *
12198  * Since: 0.6
12199  */
12200 void
12201 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12202                                               ClutterGravity  gravity)
12203 {
12204   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12205   const ClutterTransformInfo *info;
12206   ClutterActorPrivate *priv;
12207
12208   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12209
12210   priv = self->priv;
12211   info = _clutter_actor_get_transform_info (self);
12212
12213   g_object_freeze_notify (G_OBJECT (self));
12214
12215   clutter_anchor_coord_get_units (self, &info->anchor,
12216                                   &old_anchor_x,
12217                                   &old_anchor_y,
12218                                   NULL);
12219   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12220   clutter_anchor_coord_get_units (self, &info->anchor,
12221                                   &new_anchor_x,
12222                                   &new_anchor_y,
12223                                   NULL);
12224
12225   if (priv->position_set)
12226     clutter_actor_move_by (self,
12227                            new_anchor_x - old_anchor_x,
12228                            new_anchor_y - old_anchor_y);
12229
12230   g_object_thaw_notify (G_OBJECT (self));
12231 }
12232
12233 /**
12234  * clutter_actor_set_anchor_point_from_gravity:
12235  * @self: a #ClutterActor
12236  * @gravity: #ClutterGravity.
12237  *
12238  * Sets an anchor point on the actor, based on the given gravity (this is a
12239  * convenience function wrapping clutter_actor_set_anchor_point()).
12240  *
12241  * Since version 1.0 the anchor point will be stored as a gravity so
12242  * that if the actor changes size then the anchor point will move. For
12243  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12244  * and later double the size of the actor, the anchor point will move
12245  * to the bottom right.
12246  *
12247  * Since: 0.6
12248  */
12249 void
12250 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12251                                              ClutterGravity  gravity)
12252 {
12253   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12254
12255   if (gravity == CLUTTER_GRAVITY_NONE)
12256     clutter_actor_set_anchor_point (self, 0, 0);
12257   else
12258     {
12259       GObject *obj = G_OBJECT (self);
12260       ClutterTransformInfo *info;
12261
12262       g_object_freeze_notify (obj);
12263
12264       info = _clutter_actor_get_transform_info (self);
12265       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12266
12267       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12268       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12269       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12270
12271       self->priv->transform_valid = FALSE;
12272
12273       clutter_actor_queue_redraw (self);
12274
12275       g_object_thaw_notify (obj);
12276     }
12277 }
12278
12279 static void
12280 clutter_container_iface_init (ClutterContainerIface *iface)
12281 {
12282   /* we don't override anything, as ClutterContainer already has a default
12283    * implementation that we can use, and which calls into our own API.
12284    */
12285 }
12286
12287 typedef enum
12288 {
12289   PARSE_X,
12290   PARSE_Y,
12291   PARSE_WIDTH,
12292   PARSE_HEIGHT,
12293   PARSE_ANCHOR_X,
12294   PARSE_ANCHOR_Y
12295 } ParseDimension;
12296
12297 static gfloat
12298 parse_units (ClutterActor   *self,
12299              ParseDimension  dimension,
12300              JsonNode       *node)
12301 {
12302   GValue value = G_VALUE_INIT;
12303   gfloat retval = 0;
12304
12305   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12306     return 0;
12307
12308   json_node_get_value (node, &value);
12309
12310   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12311     {
12312       retval = (gfloat) g_value_get_int64 (&value);
12313     }
12314   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12315     {
12316       retval = g_value_get_double (&value);
12317     }
12318   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12319     {
12320       ClutterUnits units;
12321       gboolean res;
12322
12323       res = clutter_units_from_string (&units, g_value_get_string (&value));
12324       if (res)
12325         retval = clutter_units_to_pixels (&units);
12326       else
12327         {
12328           g_warning ("Invalid value '%s': integers, strings or floating point "
12329                      "values can be used for the x, y, width and height "
12330                      "properties. Valid modifiers for strings are 'px', 'mm', "
12331                      "'pt' and 'em'.",
12332                      g_value_get_string (&value));
12333           retval = 0;
12334         }
12335     }
12336   else
12337     {
12338       g_warning ("Invalid value of type '%s': integers, strings of floating "
12339                  "point values can be used for the x, y, width, height "
12340                  "anchor-x and anchor-y properties.",
12341                  g_type_name (G_VALUE_TYPE (&value)));
12342     }
12343
12344   g_value_unset (&value);
12345
12346   return retval;
12347 }
12348
12349 typedef struct {
12350   ClutterRotateAxis axis;
12351
12352   gdouble angle;
12353
12354   gfloat center_x;
12355   gfloat center_y;
12356   gfloat center_z;
12357 } RotationInfo;
12358
12359 static inline gboolean
12360 parse_rotation_array (ClutterActor *actor,
12361                       JsonArray    *array,
12362                       RotationInfo *info)
12363 {
12364   JsonNode *element;
12365
12366   if (json_array_get_length (array) != 2)
12367     return FALSE;
12368
12369   /* angle */
12370   element = json_array_get_element (array, 0);
12371   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12372     info->angle = json_node_get_double (element);
12373   else
12374     return FALSE;
12375
12376   /* center */
12377   element = json_array_get_element (array, 1);
12378   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12379     {
12380       JsonArray *center = json_node_get_array (element);
12381
12382       if (json_array_get_length (center) != 2)
12383         return FALSE;
12384
12385       switch (info->axis)
12386         {
12387         case CLUTTER_X_AXIS:
12388           info->center_y = parse_units (actor, PARSE_Y,
12389                                         json_array_get_element (center, 0));
12390           info->center_z = parse_units (actor, PARSE_Y,
12391                                         json_array_get_element (center, 1));
12392           return TRUE;
12393
12394         case CLUTTER_Y_AXIS:
12395           info->center_x = parse_units (actor, PARSE_X,
12396                                         json_array_get_element (center, 0));
12397           info->center_z = parse_units (actor, PARSE_X,
12398                                         json_array_get_element (center, 1));
12399           return TRUE;
12400
12401         case CLUTTER_Z_AXIS:
12402           info->center_x = parse_units (actor, PARSE_X,
12403                                         json_array_get_element (center, 0));
12404           info->center_y = parse_units (actor, PARSE_Y,
12405                                         json_array_get_element (center, 1));
12406           return TRUE;
12407         }
12408     }
12409
12410   return FALSE;
12411 }
12412
12413 static gboolean
12414 parse_rotation (ClutterActor *actor,
12415                 JsonNode     *node,
12416                 RotationInfo *info)
12417 {
12418   JsonArray *array;
12419   guint len, i;
12420   gboolean retval = FALSE;
12421
12422   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12423     {
12424       g_warning ("Invalid node of type '%s' found, expecting an array",
12425                  json_node_type_name (node));
12426       return FALSE;
12427     }
12428
12429   array = json_node_get_array (node);
12430   len = json_array_get_length (array);
12431
12432   for (i = 0; i < len; i++)
12433     {
12434       JsonNode *element = json_array_get_element (array, i);
12435       JsonObject *object;
12436       JsonNode *member;
12437
12438       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12439         {
12440           g_warning ("Invalid node of type '%s' found, expecting an object",
12441                      json_node_type_name (element));
12442           return FALSE;
12443         }
12444
12445       object = json_node_get_object (element);
12446
12447       if (json_object_has_member (object, "x-axis"))
12448         {
12449           member = json_object_get_member (object, "x-axis");
12450
12451           info->axis = CLUTTER_X_AXIS;
12452
12453           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12454             {
12455               info->angle = json_node_get_double (member);
12456               retval = TRUE;
12457             }
12458           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12459             retval = parse_rotation_array (actor,
12460                                            json_node_get_array (member),
12461                                            info);
12462           else
12463             retval = FALSE;
12464         }
12465       else if (json_object_has_member (object, "y-axis"))
12466         {
12467           member = json_object_get_member (object, "y-axis");
12468
12469           info->axis = CLUTTER_Y_AXIS;
12470
12471           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12472             {
12473               info->angle = json_node_get_double (member);
12474               retval = TRUE;
12475             }
12476           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12477             retval = parse_rotation_array (actor,
12478                                            json_node_get_array (member),
12479                                            info);
12480           else
12481             retval = FALSE;
12482         }
12483       else if (json_object_has_member (object, "z-axis"))
12484         {
12485           member = json_object_get_member (object, "z-axis");
12486
12487           info->axis = CLUTTER_Z_AXIS;
12488
12489           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12490             {
12491               info->angle = json_node_get_double (member);
12492               retval = TRUE;
12493             }
12494           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12495             retval = parse_rotation_array (actor,
12496                                            json_node_get_array (member),
12497                                            info);
12498           else
12499             retval = FALSE;
12500         }
12501     }
12502
12503   return retval;
12504 }
12505
12506 static GSList *
12507 parse_actor_metas (ClutterScript *script,
12508                    ClutterActor  *actor,
12509                    JsonNode      *node)
12510 {
12511   GList *elements, *l;
12512   GSList *retval = NULL;
12513
12514   if (!JSON_NODE_HOLDS_ARRAY (node))
12515     return NULL;
12516
12517   elements = json_array_get_elements (json_node_get_array (node));
12518
12519   for (l = elements; l != NULL; l = l->next)
12520     {
12521       JsonNode *element = l->data;
12522       const gchar *id_ = _clutter_script_get_id_from_node (element);
12523       GObject *meta;
12524
12525       if (id_ == NULL || *id_ == '\0')
12526         continue;
12527
12528       meta = clutter_script_get_object (script, id_);
12529       if (meta == NULL)
12530         continue;
12531
12532       retval = g_slist_prepend (retval, meta);
12533     }
12534
12535   g_list_free (elements);
12536
12537   return g_slist_reverse (retval);
12538 }
12539
12540 static GSList *
12541 parse_behaviours (ClutterScript *script,
12542                   ClutterActor  *actor,
12543                   JsonNode      *node)
12544 {
12545   GList *elements, *l;
12546   GSList *retval = NULL;
12547
12548   if (!JSON_NODE_HOLDS_ARRAY (node))
12549     return NULL;
12550
12551   elements = json_array_get_elements (json_node_get_array (node));
12552
12553   for (l = elements; l != NULL; l = l->next)
12554     {
12555       JsonNode *element = l->data;
12556       const gchar *id_ = _clutter_script_get_id_from_node (element);
12557       GObject *behaviour;
12558
12559       if (id_ == NULL || *id_ == '\0')
12560         continue;
12561
12562       behaviour = clutter_script_get_object (script, id_);
12563       if (behaviour == NULL)
12564         continue;
12565
12566       retval = g_slist_prepend (retval, behaviour);
12567     }
12568
12569   g_list_free (elements);
12570
12571   return g_slist_reverse (retval);
12572 }
12573
12574 static gboolean
12575 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12576                                  ClutterScript     *script,
12577                                  GValue            *value,
12578                                  const gchar       *name,
12579                                  JsonNode          *node)
12580 {
12581   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12582   gboolean retval = FALSE;
12583
12584   if ((name[0] == 'x' && name[1] == '\0') ||
12585       (name[0] == 'y' && name[1] == '\0') ||
12586       (strcmp (name, "width") == 0) ||
12587       (strcmp (name, "height") == 0) ||
12588       (strcmp (name, "anchor_x") == 0) ||
12589       (strcmp (name, "anchor_y") == 0))
12590     {
12591       ParseDimension dimension;
12592       gfloat units;
12593
12594       if (name[0] == 'x')
12595         dimension = PARSE_X;
12596       else if (name[0] == 'y')
12597         dimension = PARSE_Y;
12598       else if (name[0] == 'w')
12599         dimension = PARSE_WIDTH;
12600       else if (name[0] == 'h')
12601         dimension = PARSE_HEIGHT;
12602       else if (name[0] == 'a' && name[7] == 'x')
12603         dimension = PARSE_ANCHOR_X;
12604       else if (name[0] == 'a' && name[7] == 'y')
12605         dimension = PARSE_ANCHOR_Y;
12606       else
12607         return FALSE;
12608
12609       units = parse_units (actor, dimension, node);
12610
12611       /* convert back to pixels: all properties are pixel-based */
12612       g_value_init (value, G_TYPE_FLOAT);
12613       g_value_set_float (value, units);
12614
12615       retval = TRUE;
12616     }
12617   else if (strcmp (name, "rotation") == 0)
12618     {
12619       RotationInfo *info;
12620
12621       info = g_slice_new0 (RotationInfo);
12622       retval = parse_rotation (actor, node, info);
12623
12624       if (retval)
12625         {
12626           g_value_init (value, G_TYPE_POINTER);
12627           g_value_set_pointer (value, info);
12628         }
12629       else
12630         g_slice_free (RotationInfo, info);
12631     }
12632   else if (strcmp (name, "behaviours") == 0)
12633     {
12634       GSList *l;
12635
12636 #ifdef CLUTTER_ENABLE_DEBUG
12637       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12638         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12639                                      "and it should not be used in newly "
12640                                      "written ClutterScript definitions.");
12641 #endif
12642
12643       l = parse_behaviours (script, actor, node);
12644
12645       g_value_init (value, G_TYPE_POINTER);
12646       g_value_set_pointer (value, l);
12647
12648       retval = TRUE;
12649     }
12650   else if (strcmp (name, "actions") == 0 ||
12651            strcmp (name, "constraints") == 0 ||
12652            strcmp (name, "effects") == 0)
12653     {
12654       GSList *l;
12655
12656       l = parse_actor_metas (script, actor, node);
12657
12658       g_value_init (value, G_TYPE_POINTER);
12659       g_value_set_pointer (value, l);
12660
12661       retval = TRUE;
12662     }
12663
12664   return retval;
12665 }
12666
12667 static void
12668 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12669                                    ClutterScript     *script,
12670                                    const gchar       *name,
12671                                    const GValue      *value)
12672 {
12673   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12674
12675 #ifdef CLUTTER_ENABLE_DEBUG
12676   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12677     {
12678       gchar *tmp = g_strdup_value_contents (value);
12679
12680       CLUTTER_NOTE (SCRIPT,
12681                     "in ClutterActor::set_custom_property('%s') = %s",
12682                     name,
12683                     tmp);
12684
12685       g_free (tmp);
12686     }
12687 #endif /* CLUTTER_ENABLE_DEBUG */
12688
12689   if (strcmp (name, "rotation") == 0)
12690     {
12691       RotationInfo *info;
12692
12693       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12694         return;
12695
12696       info = g_value_get_pointer (value);
12697
12698       clutter_actor_set_rotation (actor,
12699                                   info->axis, info->angle,
12700                                   info->center_x,
12701                                   info->center_y,
12702                                   info->center_z);
12703
12704       g_slice_free (RotationInfo, info);
12705
12706       return;
12707     }
12708
12709   if (strcmp (name, "behaviours") == 0)
12710     {
12711       GSList *behaviours, *l;
12712
12713       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12714         return;
12715
12716       behaviours = g_value_get_pointer (value);
12717       for (l = behaviours; l != NULL; l = l->next)
12718         {
12719           ClutterBehaviour *behaviour = l->data;
12720
12721           clutter_behaviour_apply (behaviour, actor);
12722         }
12723
12724       g_slist_free (behaviours);
12725
12726       return;
12727     }
12728
12729   if (strcmp (name, "actions") == 0 ||
12730       strcmp (name, "constraints") == 0 ||
12731       strcmp (name, "effects") == 0)
12732     {
12733       GSList *metas, *l;
12734
12735       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12736         return;
12737
12738       metas = g_value_get_pointer (value);
12739       for (l = metas; l != NULL; l = l->next)
12740         {
12741           if (name[0] == 'a')
12742             clutter_actor_add_action (actor, l->data);
12743
12744           if (name[0] == 'c')
12745             clutter_actor_add_constraint (actor, l->data);
12746
12747           if (name[0] == 'e')
12748             clutter_actor_add_effect (actor, l->data);
12749         }
12750
12751       g_slist_free (metas);
12752
12753       return;
12754     }
12755
12756   g_object_set_property (G_OBJECT (scriptable), name, value);
12757 }
12758
12759 static void
12760 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12761 {
12762   iface->parse_custom_node = clutter_actor_parse_custom_node;
12763   iface->set_custom_property = clutter_actor_set_custom_property;
12764 }
12765
12766 static ClutterActorMeta *
12767 get_meta_from_animation_property (ClutterActor  *actor,
12768                                   const gchar   *name,
12769                                   gchar        **name_p)
12770 {
12771   ClutterActorPrivate *priv = actor->priv;
12772   ClutterActorMeta *meta = NULL;
12773   gchar **tokens;
12774
12775   /* if this is not a special property, fall through */
12776   if (name[0] != '@')
12777     return NULL;
12778
12779   /* detect the properties named using the following spec:
12780    *
12781    *   @<section>.<meta-name>.<property-name>
12782    *
12783    * where <section> can be one of the following:
12784    *
12785    *   - actions
12786    *   - constraints
12787    *   - effects
12788    *
12789    * and <meta-name> is the name set on a specific ActorMeta
12790    */
12791
12792   tokens = g_strsplit (name + 1, ".", -1);
12793   if (tokens == NULL || g_strv_length (tokens) != 3)
12794     {
12795       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12796                     name + 1);
12797       g_strfreev (tokens);
12798       return NULL;
12799     }
12800
12801   if (strcmp (tokens[0], "actions") == 0)
12802     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12803
12804   if (strcmp (tokens[0], "constraints") == 0)
12805     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12806
12807   if (strcmp (tokens[0], "effects") == 0)
12808     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12809
12810   if (name_p != NULL)
12811     *name_p = g_strdup (tokens[2]);
12812
12813   CLUTTER_NOTE (ANIMATION,
12814                 "Looking for property '%s' of object '%s' in section '%s'",
12815                 tokens[2],
12816                 tokens[1],
12817                 tokens[0]);
12818
12819   g_strfreev (tokens);
12820
12821   return meta;
12822 }
12823
12824 static GParamSpec *
12825 clutter_actor_find_property (ClutterAnimatable *animatable,
12826                              const gchar       *property_name)
12827 {
12828   ClutterActorMeta *meta = NULL;
12829   GObjectClass *klass = NULL;
12830   GParamSpec *pspec = NULL;
12831   gchar *p_name = NULL;
12832
12833   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12834                                            property_name,
12835                                            &p_name);
12836
12837   if (meta != NULL)
12838     {
12839       klass = G_OBJECT_GET_CLASS (meta);
12840
12841       pspec = g_object_class_find_property (klass, p_name);
12842     }
12843   else
12844     {
12845       klass = G_OBJECT_GET_CLASS (animatable);
12846
12847       pspec = g_object_class_find_property (klass, property_name);
12848     }
12849
12850   g_free (p_name);
12851
12852   return pspec;
12853 }
12854
12855 static void
12856 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12857                                  const gchar       *property_name,
12858                                  GValue            *initial)
12859 {
12860   ClutterActorMeta *meta = NULL;
12861   gchar *p_name = NULL;
12862
12863   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12864                                            property_name,
12865                                            &p_name);
12866
12867   if (meta != NULL)
12868     g_object_get_property (G_OBJECT (meta), p_name, initial);
12869   else
12870     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12871
12872   g_free (p_name);
12873 }
12874
12875 /*
12876  * clutter_actor_set_animatable_property:
12877  * @actor: a #ClutterActor
12878  * @prop_id: the paramspec id
12879  * @value: the value to set
12880  * @pspec: the paramspec
12881  *
12882  * Sets values of animatable properties.
12883  *
12884  * This is a variant of clutter_actor_set_property() that gets called
12885  * by the #ClutterAnimatable implementation of #ClutterActor for the
12886  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12887  * #GParamSpec.
12888  *
12889  * Unlike the implementation of #GObjectClass.set_property(), this
12890  * function will not update the interval if a transition involving an
12891  * animatable property is in progress - this avoids cycles with the
12892  * transition API calling the public API.
12893  */
12894 static void
12895 clutter_actor_set_animatable_property (ClutterActor *actor,
12896                                        guint         prop_id,
12897                                        const GValue *value,
12898                                        GParamSpec   *pspec)
12899 {
12900   switch (prop_id)
12901     {
12902     case PROP_X:
12903       clutter_actor_set_x_internal (actor, g_value_get_float (value));
12904       break;
12905
12906     case PROP_Y:
12907       clutter_actor_set_y_internal (actor, g_value_get_float (value));
12908       break;
12909
12910     case PROP_WIDTH:
12911       clutter_actor_set_width_internal (actor, g_value_get_float (value));
12912       break;
12913
12914     case PROP_HEIGHT:
12915       clutter_actor_set_height_internal (actor, g_value_get_float (value));
12916       break;
12917
12918     case PROP_DEPTH:
12919       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12920       break;
12921
12922     case PROP_OPACITY:
12923       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12924       break;
12925
12926     case PROP_BACKGROUND_COLOR:
12927       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12928       break;
12929
12930     case PROP_SCALE_X:
12931       clutter_actor_set_scale_factor_internal (actor,
12932                                                g_value_get_double (value),
12933                                                pspec);
12934       break;
12935
12936     case PROP_SCALE_Y:
12937       clutter_actor_set_scale_factor_internal (actor,
12938                                                g_value_get_double (value),
12939                                                pspec);
12940       break;
12941
12942     case PROP_ROTATION_ANGLE_X:
12943       clutter_actor_set_rotation_angle_internal (actor,
12944                                                  CLUTTER_X_AXIS,
12945                                                  g_value_get_double (value));
12946       break;
12947
12948     case PROP_ROTATION_ANGLE_Y:
12949       clutter_actor_set_rotation_angle_internal (actor,
12950                                                  CLUTTER_Y_AXIS,
12951                                                  g_value_get_double (value));
12952       break;
12953
12954     case PROP_ROTATION_ANGLE_Z:
12955       clutter_actor_set_rotation_angle_internal (actor,
12956                                                  CLUTTER_Z_AXIS,
12957                                                  g_value_get_double (value));
12958       break;
12959
12960     default:
12961       g_object_set_property (G_OBJECT (actor), pspec->name, value);
12962       break;
12963     }
12964 }
12965
12966 static void
12967 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12968                                const gchar       *property_name,
12969                                const GValue      *final)
12970 {
12971   ClutterActor *actor = CLUTTER_ACTOR (animatable);
12972   ClutterActorMeta *meta = NULL;
12973   gchar *p_name = NULL;
12974
12975   meta = get_meta_from_animation_property (actor,
12976                                            property_name,
12977                                            &p_name);
12978   if (meta != NULL)
12979     g_object_set_property (G_OBJECT (meta), p_name, final);
12980   else
12981     {
12982       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12983       GParamSpec *pspec;
12984
12985       pspec = g_object_class_find_property (obj_class, property_name);
12986
12987       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12988         {
12989           /* XXX - I'm going to the special hell for this */
12990           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12991         }
12992       else
12993         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
12994     }
12995
12996   g_free (p_name);
12997 }
12998
12999 static void
13000 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13001 {
13002   iface->find_property = clutter_actor_find_property;
13003   iface->get_initial_state = clutter_actor_get_initial_state;
13004   iface->set_final_state = clutter_actor_set_final_state;
13005 }
13006
13007 /**
13008  * clutter_actor_transform_stage_point:
13009  * @self: A #ClutterActor
13010  * @x: (in): x screen coordinate of the point to unproject
13011  * @y: (in): y screen coordinate of the point to unproject
13012  * @x_out: (out): return location for the unprojected x coordinance
13013  * @y_out: (out): return location for the unprojected y coordinance
13014  *
13015  * This function translates screen coordinates (@x, @y) to
13016  * coordinates relative to the actor. For example, it can be used to translate
13017  * screen events from global screen coordinates into actor-local coordinates.
13018  *
13019  * The conversion can fail, notably if the transform stack results in the
13020  * actor being projected on the screen as a mere line.
13021  *
13022  * The conversion should not be expected to be pixel-perfect due to the
13023  * nature of the operation. In general the error grows when the skewing
13024  * of the actor rectangle on screen increases.
13025  *
13026  * <note><para>This function can be computationally intensive.</para></note>
13027  *
13028  * <note><para>This function only works when the allocation is up-to-date,
13029  * i.e. inside of paint().</para></note>
13030  *
13031  * Return value: %TRUE if conversion was successful.
13032  *
13033  * Since: 0.6
13034  */
13035 gboolean
13036 clutter_actor_transform_stage_point (ClutterActor *self,
13037                                      gfloat        x,
13038                                      gfloat        y,
13039                                      gfloat       *x_out,
13040                                      gfloat       *y_out)
13041 {
13042   ClutterVertex v[4];
13043   float ST[3][3];
13044   float RQ[3][3];
13045   int du, dv, xi, yi;
13046   float px, py;
13047   float xf, yf, wf, det;
13048   ClutterActorPrivate *priv;
13049
13050   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13051
13052   priv = self->priv;
13053
13054   /* This implementation is based on the quad -> quad projection algorithm
13055    * described by Paul Heckbert in:
13056    *
13057    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13058    *
13059    * and the sample implementation at:
13060    *
13061    *   http://www.cs.cmu.edu/~ph/src/texfund/
13062    *
13063    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13064    * quad to rectangle only, which significantly simplifies things; the
13065    * function calls have been unrolled, and most of the math is done in fixed
13066    * point.
13067    */
13068
13069   clutter_actor_get_abs_allocation_vertices (self, v);
13070
13071   /* Keeping these as ints simplifies the multiplication (no significant
13072    * loss of precision here).
13073    */
13074   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13075   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13076
13077   if (!du || !dv)
13078     return FALSE;
13079
13080 #define UX2FP(x)        (x)
13081 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13082
13083   /* First, find mapping from unit uv square to xy quadrilateral; this
13084    * equivalent to the pmap_square_quad() functions in the sample
13085    * implementation, which we can simplify, since our target is always
13086    * a rectangle.
13087    */
13088   px = v[0].x - v[1].x + v[3].x - v[2].x;
13089   py = v[0].y - v[1].y + v[3].y - v[2].y;
13090
13091   if (!px && !py)
13092     {
13093       /* affine transform */
13094       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13095       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13096       RQ[2][0] = UX2FP (v[0].x);
13097       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13098       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13099       RQ[2][1] = UX2FP (v[0].y);
13100       RQ[0][2] = 0;
13101       RQ[1][2] = 0;
13102       RQ[2][2] = 1.0;
13103     }
13104   else
13105     {
13106       /* projective transform */
13107       double dx1, dx2, dy1, dy2, del;
13108
13109       dx1 = UX2FP (v[1].x - v[3].x);
13110       dx2 = UX2FP (v[2].x - v[3].x);
13111       dy1 = UX2FP (v[1].y - v[3].y);
13112       dy2 = UX2FP (v[2].y - v[3].y);
13113
13114       del = DET2FP (dx1, dx2, dy1, dy2);
13115       if (!del)
13116         return FALSE;
13117
13118       /*
13119        * The division here needs to be done in floating point for
13120        * precisions reasons.
13121        */
13122       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13123       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13124       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13125       RQ[2][2] = 1.0;
13126       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13127       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13128       RQ[2][0] = UX2FP (v[0].x);
13129       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13130       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13131       RQ[2][1] = UX2FP (v[0].y);
13132     }
13133
13134   /*
13135    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13136    * square. Since our rectangle is based at 0,0 we only need to scale.
13137    */
13138   RQ[0][0] /= du;
13139   RQ[1][0] /= dv;
13140   RQ[0][1] /= du;
13141   RQ[1][1] /= dv;
13142   RQ[0][2] /= du;
13143   RQ[1][2] /= dv;
13144
13145   /*
13146    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13147    * inverse of that.
13148    */
13149   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13150   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13151   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13152   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13153   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13154   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13155   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13156   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13157   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13158
13159   /*
13160    * Check the resulting matrix is OK.
13161    */
13162   det = (RQ[0][0] * ST[0][0])
13163       + (RQ[0][1] * ST[0][1])
13164       + (RQ[0][2] * ST[0][2]);
13165   if (!det)
13166     return FALSE;
13167
13168   /*
13169    * Now transform our point with the ST matrix; the notional w
13170    * coordinate is 1, hence the last part is simply added.
13171    */
13172   xi = (int) x;
13173   yi = (int) y;
13174
13175   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13176   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13177   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13178
13179   if (x_out)
13180     *x_out = xf / wf;
13181
13182   if (y_out)
13183     *y_out = yf / wf;
13184
13185 #undef UX2FP
13186 #undef DET2FP
13187
13188   return TRUE;
13189 }
13190
13191 /*
13192  * ClutterGeometry
13193  */
13194
13195 static ClutterGeometry*
13196 clutter_geometry_copy (const ClutterGeometry *geometry)
13197 {
13198   return g_slice_dup (ClutterGeometry, geometry);
13199 }
13200
13201 static void
13202 clutter_geometry_free (ClutterGeometry *geometry)
13203 {
13204   if (G_LIKELY (geometry != NULL))
13205     g_slice_free (ClutterGeometry, geometry);
13206 }
13207
13208 /**
13209  * clutter_geometry_union:
13210  * @geometry_a: a #ClutterGeometry
13211  * @geometry_b: another #ClutterGeometry
13212  * @result: (out): location to store the result
13213  *
13214  * Find the union of two rectangles represented as #ClutterGeometry.
13215  *
13216  * Since: 1.4
13217  */
13218 void
13219 clutter_geometry_union (const ClutterGeometry *geometry_a,
13220                         const ClutterGeometry *geometry_b,
13221                         ClutterGeometry       *result)
13222 {
13223   /* We don't try to handle rectangles that can't be represented
13224    * as a signed integer box */
13225   gint x_1 = MIN (geometry_a->x, geometry_b->x);
13226   gint y_1 = MIN (geometry_a->y, geometry_b->y);
13227   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13228                   geometry_b->x + (gint)geometry_b->width);
13229   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13230                   geometry_b->y + (gint)geometry_b->height);
13231   result->x = x_1;
13232   result->y = y_1;
13233   result->width = x_2 - x_1;
13234   result->height = y_2 - y_1;
13235 }
13236
13237 /**
13238  * clutter_geometry_intersects:
13239  * @geometry0: The first geometry to test
13240  * @geometry1: The second geometry to test
13241  *
13242  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13243  * they do else %FALSE.
13244  *
13245  * Return value: %TRUE of @geometry0 and geometry1 intersect else
13246  * %FALSE.
13247  *
13248  * Since: 1.4
13249  */
13250 gboolean
13251 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13252                              const ClutterGeometry *geometry1)
13253 {
13254   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13255       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13256       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13257       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13258     return FALSE;
13259   else
13260     return TRUE;
13261 }
13262
13263 static gboolean
13264 clutter_geometry_progress (const GValue *a,
13265                            const GValue *b,
13266                            gdouble       progress,
13267                            GValue       *retval)
13268 {
13269   const ClutterGeometry *a_geom = g_value_get_boxed (a);
13270   const ClutterGeometry *b_geom = g_value_get_boxed (b);
13271   ClutterGeometry res = { 0, };
13272   gint a_width = a_geom->width;
13273   gint b_width = b_geom->width;
13274   gint a_height = a_geom->height;
13275   gint b_height = b_geom->height;
13276
13277   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13278   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13279
13280   res.width = a_width + (b_width - a_width) * progress;
13281   res.height = a_height + (b_height - a_height) * progress;
13282
13283   g_value_set_boxed (retval, &res);
13284
13285   return TRUE;
13286 }
13287
13288 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13289                                clutter_geometry_copy,
13290                                clutter_geometry_free,
13291                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13292
13293 /*
13294  * ClutterVertices
13295  */
13296
13297 /**
13298  * clutter_vertex_new:
13299  * @x: X coordinate
13300  * @y: Y coordinate
13301  * @z: Z coordinate
13302  *
13303  * Creates a new #ClutterVertex for the point in 3D space
13304  * identified by the 3 coordinates @x, @y, @z
13305  *
13306  * Return value: the newly allocate #ClutterVertex. Use
13307  *   clutter_vertex_free() to free the resources
13308  *
13309  * Since: 1.0
13310  */
13311 ClutterVertex *
13312 clutter_vertex_new (gfloat x,
13313                     gfloat y,
13314                     gfloat z)
13315 {
13316   ClutterVertex *vertex;
13317
13318   vertex = g_slice_new (ClutterVertex);
13319   clutter_vertex_init (vertex, x, y, z);
13320
13321   return vertex;
13322 }
13323
13324 /**
13325  * clutter_vertex_init:
13326  * @vertex: a #ClutterVertex
13327  * @x: X coordinate
13328  * @y: Y coordinate
13329  * @z: Z coordinate
13330  *
13331  * Initializes @vertex with the given coordinates.
13332  *
13333  * Since: 1.10
13334  */
13335 void
13336 clutter_vertex_init (ClutterVertex *vertex,
13337                      gfloat         x,
13338                      gfloat         y,
13339                      gfloat         z)
13340 {
13341   g_return_if_fail (vertex != NULL);
13342
13343   vertex->x = x;
13344   vertex->y = y;
13345   vertex->z = z;
13346 }
13347
13348 /**
13349  * clutter_vertex_copy:
13350  * @vertex: a #ClutterVertex
13351  *
13352  * Copies @vertex
13353  *
13354  * Return value: a newly allocated copy of #ClutterVertex. Use
13355  *   clutter_vertex_free() to free the allocated resources
13356  *
13357  * Since: 1.0
13358  */
13359 ClutterVertex *
13360 clutter_vertex_copy (const ClutterVertex *vertex)
13361 {
13362   if (G_LIKELY (vertex != NULL))
13363     return g_slice_dup (ClutterVertex, vertex);
13364
13365   return NULL;
13366 }
13367
13368 /**
13369  * clutter_vertex_free:
13370  * @vertex: a #ClutterVertex
13371  *
13372  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13373  *
13374  * Since: 1.0
13375  */
13376 void
13377 clutter_vertex_free (ClutterVertex *vertex)
13378 {
13379   if (G_UNLIKELY (vertex != NULL))
13380     g_slice_free (ClutterVertex, vertex);
13381 }
13382
13383 /**
13384  * clutter_vertex_equal:
13385  * @vertex_a: a #ClutterVertex
13386  * @vertex_b: a #ClutterVertex
13387  *
13388  * Compares @vertex_a and @vertex_b for equality
13389  *
13390  * Return value: %TRUE if the passed #ClutterVertex are equal
13391  *
13392  * Since: 1.0
13393  */
13394 gboolean
13395 clutter_vertex_equal (const ClutterVertex *vertex_a,
13396                       const ClutterVertex *vertex_b)
13397 {
13398   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13399
13400   if (vertex_a == vertex_b)
13401     return TRUE;
13402
13403   return vertex_a->x == vertex_b->x &&
13404          vertex_a->y == vertex_b->y &&
13405          vertex_a->z == vertex_b->z;
13406 }
13407
13408 static gboolean
13409 clutter_vertex_progress (const GValue *a,
13410                          const GValue *b,
13411                          gdouble       progress,
13412                          GValue       *retval)
13413 {
13414   const ClutterVertex *av = g_value_get_boxed (a);
13415   const ClutterVertex *bv = g_value_get_boxed (b);
13416   ClutterVertex res = { 0, };
13417
13418   res.x = av->x + (bv->x - av->x) * progress;
13419   res.y = av->y + (bv->y - av->y) * progress;
13420   res.z = av->z + (bv->z - av->z) * progress;
13421
13422   g_value_set_boxed (retval, &res);
13423
13424   return TRUE;
13425 }
13426
13427 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13428                                clutter_vertex_copy,
13429                                clutter_vertex_free,
13430                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13431
13432 /**
13433  * clutter_actor_is_rotated:
13434  * @self: a #ClutterActor
13435  *
13436  * Checks whether any rotation is applied to the actor.
13437  *
13438  * Return value: %TRUE if the actor is rotated.
13439  *
13440  * Since: 0.6
13441  */
13442 gboolean
13443 clutter_actor_is_rotated (ClutterActor *self)
13444 {
13445   const ClutterTransformInfo *info;
13446
13447   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13448
13449   info = _clutter_actor_get_transform_info_or_defaults (self);
13450
13451   if (info->rx_angle || info->ry_angle || info->rz_angle)
13452     return TRUE;
13453
13454   return FALSE;
13455 }
13456
13457 /**
13458  * clutter_actor_is_scaled:
13459  * @self: a #ClutterActor
13460  *
13461  * Checks whether the actor is scaled in either dimension.
13462  *
13463  * Return value: %TRUE if the actor is scaled.
13464  *
13465  * Since: 0.6
13466  */
13467 gboolean
13468 clutter_actor_is_scaled (ClutterActor *self)
13469 {
13470   const ClutterTransformInfo *info;
13471
13472   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13473
13474   info = _clutter_actor_get_transform_info_or_defaults (self);
13475
13476   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13477     return TRUE;
13478
13479   return FALSE;
13480 }
13481
13482 ClutterActor *
13483 _clutter_actor_get_stage_internal (ClutterActor *actor)
13484 {
13485   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13486     actor = actor->priv->parent;
13487
13488   return actor;
13489 }
13490
13491 /**
13492  * clutter_actor_get_stage:
13493  * @actor: a #ClutterActor
13494  *
13495  * Retrieves the #ClutterStage where @actor is contained.
13496  *
13497  * Return value: (transfer none) (type Clutter.Stage): the stage
13498  *   containing the actor, or %NULL
13499  *
13500  * Since: 0.8
13501  */
13502 ClutterActor *
13503 clutter_actor_get_stage (ClutterActor *actor)
13504 {
13505   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13506
13507   return _clutter_actor_get_stage_internal (actor);
13508 }
13509
13510 /**
13511  * clutter_actor_allocate_available_size:
13512  * @self: a #ClutterActor
13513  * @x: the actor's X coordinate
13514  * @y: the actor's Y coordinate
13515  * @available_width: the maximum available width, or -1 to use the
13516  *   actor's natural width
13517  * @available_height: the maximum available height, or -1 to use the
13518  *   actor's natural height
13519  * @flags: flags controlling the allocation
13520  *
13521  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13522  * preferred size, but limiting it to the maximum available width
13523  * and height provided.
13524  *
13525  * This function will do the right thing when dealing with the
13526  * actor's request mode.
13527  *
13528  * The implementation of this function is equivalent to:
13529  *
13530  * |[
13531  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13532  *     {
13533  *       clutter_actor_get_preferred_width (self, available_height,
13534  *                                          &amp;min_width,
13535  *                                          &amp;natural_width);
13536  *       width = CLAMP (natural_width, min_width, available_width);
13537  *
13538  *       clutter_actor_get_preferred_height (self, width,
13539  *                                           &amp;min_height,
13540  *                                           &amp;natural_height);
13541  *       height = CLAMP (natural_height, min_height, available_height);
13542  *     }
13543  *   else
13544  *     {
13545  *       clutter_actor_get_preferred_height (self, available_width,
13546  *                                           &amp;min_height,
13547  *                                           &amp;natural_height);
13548  *       height = CLAMP (natural_height, min_height, available_height);
13549  *
13550  *       clutter_actor_get_preferred_width (self, height,
13551  *                                          &amp;min_width,
13552  *                                          &amp;natural_width);
13553  *       width = CLAMP (natural_width, min_width, available_width);
13554  *     }
13555  *
13556  *   box.x1 = x; box.y1 = y;
13557  *   box.x2 = box.x1 + available_width;
13558  *   box.y2 = box.y1 + available_height;
13559  *   clutter_actor_allocate (self, &amp;box, flags);
13560  * ]|
13561  *
13562  * This function can be used by fluid layout managers to allocate
13563  * an actor's preferred size without making it bigger than the area
13564  * available for the container.
13565  *
13566  * Since: 1.0
13567  */
13568 void
13569 clutter_actor_allocate_available_size (ClutterActor           *self,
13570                                        gfloat                  x,
13571                                        gfloat                  y,
13572                                        gfloat                  available_width,
13573                                        gfloat                  available_height,
13574                                        ClutterAllocationFlags  flags)
13575 {
13576   ClutterActorPrivate *priv;
13577   gfloat width, height;
13578   gfloat min_width, min_height;
13579   gfloat natural_width, natural_height;
13580   ClutterActorBox box;
13581
13582   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13583
13584   priv = self->priv;
13585
13586   width = height = 0.0;
13587
13588   switch (priv->request_mode)
13589     {
13590     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13591       clutter_actor_get_preferred_width (self, available_height,
13592                                          &min_width,
13593                                          &natural_width);
13594       width  = CLAMP (natural_width, min_width, available_width);
13595
13596       clutter_actor_get_preferred_height (self, width,
13597                                           &min_height,
13598                                           &natural_height);
13599       height = CLAMP (natural_height, min_height, available_height);
13600       break;
13601
13602     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13603       clutter_actor_get_preferred_height (self, available_width,
13604                                           &min_height,
13605                                           &natural_height);
13606       height = CLAMP (natural_height, min_height, available_height);
13607
13608       clutter_actor_get_preferred_width (self, height,
13609                                          &min_width,
13610                                          &natural_width);
13611       width  = CLAMP (natural_width, min_width, available_width);
13612       break;
13613     }
13614
13615
13616   box.x1 = x;
13617   box.y1 = y;
13618   box.x2 = box.x1 + width;
13619   box.y2 = box.y1 + height;
13620   clutter_actor_allocate (self, &box, flags);
13621 }
13622
13623 /**
13624  * clutter_actor_allocate_preferred_size:
13625  * @self: a #ClutterActor
13626  * @flags: flags controlling the allocation
13627  *
13628  * Allocates the natural size of @self.
13629  *
13630  * This function is a utility call for #ClutterActor implementations
13631  * that allocates the actor's preferred natural size. It can be used
13632  * by fixed layout managers (like #ClutterGroup or so called
13633  * 'composite actors') inside the ClutterActor::allocate
13634  * implementation to give each child exactly how much space it
13635  * requires.
13636  *
13637  * This function is not meant to be used by applications. It is also
13638  * not meant to be used outside the implementation of the
13639  * ClutterActor::allocate virtual function.
13640  *
13641  * Since: 0.8
13642  */
13643 void
13644 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13645                                        ClutterAllocationFlags  flags)
13646 {
13647   gfloat actor_x, actor_y;
13648   gfloat natural_width, natural_height;
13649   ClutterActorBox actor_box;
13650
13651   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13652
13653   actor_x = clutter_actor_get_x (self);
13654   actor_y = clutter_actor_get_y (self);
13655
13656   clutter_actor_get_preferred_size (self,
13657                                     NULL, NULL,
13658                                     &natural_width,
13659                                     &natural_height);
13660
13661   actor_box.x1 = actor_x;
13662   actor_box.y1 = actor_y;
13663   actor_box.x2 = actor_box.x1 + natural_width;
13664   actor_box.y2 = actor_box.y1 + natural_height;
13665
13666   clutter_actor_allocate (self, &actor_box, flags);
13667 }
13668
13669 /**
13670  * clutter_actor_allocate_align_fill:
13671  * @self: a #ClutterActor
13672  * @box: a #ClutterActorBox, containing the available width and height
13673  * @x_align: the horizontal alignment, between 0 and 1
13674  * @y_align: the vertical alignment, between 0 and 1
13675  * @x_fill: whether the actor should fill horizontally
13676  * @y_fill: whether the actor should fill vertically
13677  * @flags: allocation flags to be passed to clutter_actor_allocate()
13678  *
13679  * Allocates @self by taking into consideration the available allocation
13680  * area; an alignment factor on either axis; and whether the actor should
13681  * fill the allocation on either axis.
13682  *
13683  * The @box should contain the available allocation width and height;
13684  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13685  * allocation will be offset by their value.
13686  *
13687  * This function takes into consideration the geometry request specified by
13688  * the #ClutterActor:request-mode property, and the text direction.
13689  *
13690  * This function is useful for fluid layout managers, like #ClutterBinLayout
13691  * or #ClutterTableLayout
13692  *
13693  * Since: 1.4
13694  */
13695 void
13696 clutter_actor_allocate_align_fill (ClutterActor           *self,
13697                                    const ClutterActorBox  *box,
13698                                    gdouble                 x_align,
13699                                    gdouble                 y_align,
13700                                    gboolean                x_fill,
13701                                    gboolean                y_fill,
13702                                    ClutterAllocationFlags  flags)
13703 {
13704   ClutterActorPrivate *priv;
13705   ClutterActorBox allocation = { 0, };
13706   gfloat x_offset, y_offset;
13707   gfloat available_width, available_height;
13708   gfloat child_width, child_height;
13709
13710   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13711   g_return_if_fail (box != NULL);
13712   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13713   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13714
13715   priv = self->priv;
13716
13717   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13718   clutter_actor_box_get_size (box, &available_width, &available_height);
13719
13720   if (available_width < 0)
13721     available_width = 0;
13722
13723   if (available_height < 0)
13724     available_height = 0;
13725
13726   if (x_fill)
13727     {
13728       allocation.x1 = x_offset;
13729       allocation.x2 = allocation.x1 + available_width;
13730     }
13731
13732   if (y_fill)
13733     {
13734       allocation.y1 = y_offset;
13735       allocation.y2 = allocation.y1 + available_height;
13736     }
13737
13738   /* if we are filling horizontally and vertically then we're done */
13739   if (x_fill && y_fill)
13740     goto out;
13741
13742   child_width = child_height = 0.0f;
13743
13744   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13745     {
13746       gfloat min_width, natural_width;
13747       gfloat min_height, natural_height;
13748
13749       clutter_actor_get_preferred_width (self, available_height,
13750                                          &min_width,
13751                                          &natural_width);
13752
13753       child_width = CLAMP (natural_width, min_width, available_width);
13754
13755       if (!y_fill)
13756         {
13757           clutter_actor_get_preferred_height (self, child_width,
13758                                               &min_height,
13759                                               &natural_height);
13760
13761           child_height = CLAMP (natural_height, min_height, available_height);
13762         }
13763     }
13764   else
13765     {
13766       gfloat min_width, natural_width;
13767       gfloat min_height, natural_height;
13768
13769       clutter_actor_get_preferred_height (self, available_width,
13770                                           &min_height,
13771                                           &natural_height);
13772
13773       child_height = CLAMP (natural_height, min_height, available_height);
13774
13775       if (!x_fill)
13776         {
13777           clutter_actor_get_preferred_width (self, child_height,
13778                                              &min_width,
13779                                              &natural_width);
13780
13781           child_width = CLAMP (natural_width, min_width, available_width);
13782         }
13783     }
13784
13785   /* invert the horizontal alignment for RTL languages */
13786   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13787     x_align = 1.0 - x_align;
13788
13789   if (!x_fill)
13790     {
13791       allocation.x1 = x_offset
13792                     + ((available_width - child_width) * x_align);
13793       allocation.x2 = allocation.x1 + child_width;
13794     }
13795
13796   if (!y_fill)
13797     {
13798       allocation.y1 = y_offset
13799                     + ((available_height - child_height) * y_align);
13800       allocation.y2 = allocation.y1 + child_height;
13801     }
13802
13803 out:
13804   clutter_actor_box_clamp_to_pixel (&allocation);
13805   clutter_actor_allocate (self, &allocation, flags);
13806 }
13807
13808 /**
13809  * clutter_actor_grab_key_focus:
13810  * @self: a #ClutterActor
13811  *
13812  * Sets the key focus of the #ClutterStage including @self
13813  * to this #ClutterActor.
13814  *
13815  * Since: 1.0
13816  */
13817 void
13818 clutter_actor_grab_key_focus (ClutterActor *self)
13819 {
13820   ClutterActor *stage;
13821
13822   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13823
13824   stage = _clutter_actor_get_stage_internal (self);
13825   if (stage != NULL)
13826     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13827 }
13828
13829 /**
13830  * clutter_actor_get_pango_context:
13831  * @self: a #ClutterActor
13832  *
13833  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13834  * is already configured using the appropriate font map, resolution
13835  * and font options.
13836  *
13837  * Unlike clutter_actor_create_pango_context(), this context is owend
13838  * by the #ClutterActor and it will be updated each time the options
13839  * stored by the #ClutterBackend change.
13840  *
13841  * You can use the returned #PangoContext to create a #PangoLayout
13842  * and render text using cogl_pango_render_layout() to reuse the
13843  * glyphs cache also used by Clutter.
13844  *
13845  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13846  *   The returned #PangoContext is owned by the actor and should not be
13847  *   unreferenced by the application code
13848  *
13849  * Since: 1.0
13850  */
13851 PangoContext *
13852 clutter_actor_get_pango_context (ClutterActor *self)
13853 {
13854   ClutterActorPrivate *priv;
13855
13856   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13857
13858   priv = self->priv;
13859
13860   if (priv->pango_context != NULL)
13861     return priv->pango_context;
13862
13863   priv->pango_context = _clutter_context_get_pango_context ();
13864   g_object_ref (priv->pango_context);
13865
13866   return priv->pango_context;
13867 }
13868
13869 /**
13870  * clutter_actor_create_pango_context:
13871  * @self: a #ClutterActor
13872  *
13873  * Creates a #PangoContext for the given actor. The #PangoContext
13874  * is already configured using the appropriate font map, resolution
13875  * and font options.
13876  *
13877  * See also clutter_actor_get_pango_context().
13878  *
13879  * Return value: (transfer full): the newly created #PangoContext.
13880  *   Use g_object_unref() on the returned value to deallocate its
13881  *   resources
13882  *
13883  * Since: 1.0
13884  */
13885 PangoContext *
13886 clutter_actor_create_pango_context (ClutterActor *self)
13887 {
13888   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13889
13890   return _clutter_context_create_pango_context ();
13891 }
13892
13893 /**
13894  * clutter_actor_create_pango_layout:
13895  * @self: a #ClutterActor
13896  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13897  *
13898  * Creates a new #PangoLayout from the same #PangoContext used
13899  * by the #ClutterActor. The #PangoLayout is already configured
13900  * with the font map, resolution and font options, and the
13901  * given @text.
13902  *
13903  * If you want to keep around a #PangoLayout created by this
13904  * function you will have to connect to the #ClutterBackend::font-changed
13905  * and #ClutterBackend::resolution-changed signals, and call
13906  * pango_layout_context_changed() in response to them.
13907  *
13908  * Return value: (transfer full): the newly created #PangoLayout.
13909  *   Use g_object_unref() when done
13910  *
13911  * Since: 1.0
13912  */
13913 PangoLayout *
13914 clutter_actor_create_pango_layout (ClutterActor *self,
13915                                    const gchar  *text)
13916 {
13917   PangoContext *context;
13918   PangoLayout *layout;
13919
13920   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13921
13922   context = clutter_actor_get_pango_context (self);
13923   layout = pango_layout_new (context);
13924
13925   if (text)
13926     pango_layout_set_text (layout, text, -1);
13927
13928   return layout;
13929 }
13930
13931 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13932  * ClutterOffscreenEffect.
13933  */
13934 void
13935 _clutter_actor_set_opacity_override (ClutterActor *self,
13936                                      gint          opacity)
13937 {
13938   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13939
13940   self->priv->opacity_override = opacity;
13941 }
13942
13943 gint
13944 _clutter_actor_get_opacity_override (ClutterActor *self)
13945 {
13946   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13947
13948   return self->priv->opacity_override;
13949 }
13950
13951 /* Allows you to disable applying the actors model view transform during
13952  * a paint. Used by ClutterClone. */
13953 void
13954 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13955                                                 gboolean      enable)
13956 {
13957   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13958
13959   self->priv->enable_model_view_transform = enable;
13960 }
13961
13962 void
13963 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13964                                           gboolean      enable)
13965 {
13966   ClutterActorPrivate *priv;
13967
13968   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13969
13970   priv = self->priv;
13971
13972   priv->enable_paint_unmapped = enable;
13973
13974   if (priv->enable_paint_unmapped)
13975     {
13976       /* Make sure that the parents of the widget are realized first;
13977        * otherwise checks in clutter_actor_update_map_state() will
13978        * fail.
13979        */
13980       clutter_actor_realize (self);
13981
13982       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13983     }
13984   else
13985     {
13986       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13987     }
13988 }
13989
13990 static void
13991 clutter_anchor_coord_get_units (ClutterActor      *self,
13992                                 const AnchorCoord *coord,
13993                                 gfloat            *x,
13994                                 gfloat            *y,
13995                                 gfloat            *z)
13996 {
13997   if (coord->is_fractional)
13998     {
13999       gfloat actor_width, actor_height;
14000
14001       clutter_actor_get_size (self, &actor_width, &actor_height);
14002
14003       if (x)
14004         *x = actor_width * coord->v.fraction.x;
14005
14006       if (y)
14007         *y = actor_height * coord->v.fraction.y;
14008
14009       if (z)
14010         *z = 0;
14011     }
14012   else
14013     {
14014       if (x)
14015         *x = coord->v.units.x;
14016
14017       if (y)
14018         *y = coord->v.units.y;
14019
14020       if (z)
14021         *z = coord->v.units.z;
14022     }
14023 }
14024
14025 static void
14026 clutter_anchor_coord_set_units (AnchorCoord *coord,
14027                                 gfloat       x,
14028                                 gfloat       y,
14029                                 gfloat       z)
14030 {
14031   coord->is_fractional = FALSE;
14032   coord->v.units.x = x;
14033   coord->v.units.y = y;
14034   coord->v.units.z = z;
14035 }
14036
14037 static ClutterGravity
14038 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14039 {
14040   if (coord->is_fractional)
14041     {
14042       if (coord->v.fraction.x == 0.0)
14043         {
14044           if (coord->v.fraction.y == 0.0)
14045             return CLUTTER_GRAVITY_NORTH_WEST;
14046           else if (coord->v.fraction.y == 0.5)
14047             return CLUTTER_GRAVITY_WEST;
14048           else if (coord->v.fraction.y == 1.0)
14049             return CLUTTER_GRAVITY_SOUTH_WEST;
14050           else
14051             return CLUTTER_GRAVITY_NONE;
14052         }
14053       else if (coord->v.fraction.x == 0.5)
14054         {
14055           if (coord->v.fraction.y == 0.0)
14056             return CLUTTER_GRAVITY_NORTH;
14057           else if (coord->v.fraction.y == 0.5)
14058             return CLUTTER_GRAVITY_CENTER;
14059           else if (coord->v.fraction.y == 1.0)
14060             return CLUTTER_GRAVITY_SOUTH;
14061           else
14062             return CLUTTER_GRAVITY_NONE;
14063         }
14064       else if (coord->v.fraction.x == 1.0)
14065         {
14066           if (coord->v.fraction.y == 0.0)
14067             return CLUTTER_GRAVITY_NORTH_EAST;
14068           else if (coord->v.fraction.y == 0.5)
14069             return CLUTTER_GRAVITY_EAST;
14070           else if (coord->v.fraction.y == 1.0)
14071             return CLUTTER_GRAVITY_SOUTH_EAST;
14072           else
14073             return CLUTTER_GRAVITY_NONE;
14074         }
14075       else
14076         return CLUTTER_GRAVITY_NONE;
14077     }
14078   else
14079     return CLUTTER_GRAVITY_NONE;
14080 }
14081
14082 static void
14083 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14084                                   ClutterGravity  gravity)
14085 {
14086   switch (gravity)
14087     {
14088     case CLUTTER_GRAVITY_NORTH:
14089       coord->v.fraction.x = 0.5;
14090       coord->v.fraction.y = 0.0;
14091       break;
14092
14093     case CLUTTER_GRAVITY_NORTH_EAST:
14094       coord->v.fraction.x = 1.0;
14095       coord->v.fraction.y = 0.0;
14096       break;
14097
14098     case CLUTTER_GRAVITY_EAST:
14099       coord->v.fraction.x = 1.0;
14100       coord->v.fraction.y = 0.5;
14101       break;
14102
14103     case CLUTTER_GRAVITY_SOUTH_EAST:
14104       coord->v.fraction.x = 1.0;
14105       coord->v.fraction.y = 1.0;
14106       break;
14107
14108     case CLUTTER_GRAVITY_SOUTH:
14109       coord->v.fraction.x = 0.5;
14110       coord->v.fraction.y = 1.0;
14111       break;
14112
14113     case CLUTTER_GRAVITY_SOUTH_WEST:
14114       coord->v.fraction.x = 0.0;
14115       coord->v.fraction.y = 1.0;
14116       break;
14117
14118     case CLUTTER_GRAVITY_WEST:
14119       coord->v.fraction.x = 0.0;
14120       coord->v.fraction.y = 0.5;
14121       break;
14122
14123     case CLUTTER_GRAVITY_NORTH_WEST:
14124       coord->v.fraction.x = 0.0;
14125       coord->v.fraction.y = 0.0;
14126       break;
14127
14128     case CLUTTER_GRAVITY_CENTER:
14129       coord->v.fraction.x = 0.5;
14130       coord->v.fraction.y = 0.5;
14131       break;
14132
14133     default:
14134       coord->v.fraction.x = 0.0;
14135       coord->v.fraction.y = 0.0;
14136       break;
14137     }
14138
14139   coord->is_fractional = TRUE;
14140 }
14141
14142 static gboolean
14143 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14144 {
14145   if (coord->is_fractional)
14146     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14147   else
14148     return (coord->v.units.x == 0.0
14149             && coord->v.units.y == 0.0
14150             && coord->v.units.z == 0.0);
14151 }
14152
14153 /**
14154  * clutter_actor_get_flags:
14155  * @self: a #ClutterActor
14156  *
14157  * Retrieves the flags set on @self
14158  *
14159  * Return value: a bitwise or of #ClutterActorFlags or 0
14160  *
14161  * Since: 1.0
14162  */
14163 ClutterActorFlags
14164 clutter_actor_get_flags (ClutterActor *self)
14165 {
14166   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14167
14168   return self->flags;
14169 }
14170
14171 /**
14172  * clutter_actor_set_flags:
14173  * @self: a #ClutterActor
14174  * @flags: the flags to set
14175  *
14176  * Sets @flags on @self
14177  *
14178  * This function will emit notifications for the changed properties
14179  *
14180  * Since: 1.0
14181  */
14182 void
14183 clutter_actor_set_flags (ClutterActor      *self,
14184                          ClutterActorFlags  flags)
14185 {
14186   ClutterActorFlags old_flags;
14187   GObject *obj;
14188   gboolean was_reactive_set, reactive_set;
14189   gboolean was_realized_set, realized_set;
14190   gboolean was_mapped_set, mapped_set;
14191   gboolean was_visible_set, visible_set;
14192
14193   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14194
14195   if (self->flags == flags)
14196     return;
14197
14198   obj = G_OBJECT (self);
14199   g_object_ref (obj);
14200   g_object_freeze_notify (obj);
14201
14202   old_flags = self->flags;
14203
14204   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14205   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14206   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14207   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14208
14209   self->flags |= flags;
14210
14211   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14212   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14213   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14214   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14215
14216   if (reactive_set != was_reactive_set)
14217     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14218
14219   if (realized_set != was_realized_set)
14220     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14221
14222   if (mapped_set != was_mapped_set)
14223     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14224
14225   if (visible_set != was_visible_set)
14226     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14227
14228   g_object_thaw_notify (obj);
14229   g_object_unref (obj);
14230 }
14231
14232 /**
14233  * clutter_actor_unset_flags:
14234  * @self: a #ClutterActor
14235  * @flags: the flags to unset
14236  *
14237  * Unsets @flags on @self
14238  *
14239  * This function will emit notifications for the changed properties
14240  *
14241  * Since: 1.0
14242  */
14243 void
14244 clutter_actor_unset_flags (ClutterActor      *self,
14245                            ClutterActorFlags  flags)
14246 {
14247   ClutterActorFlags old_flags;
14248   GObject *obj;
14249   gboolean was_reactive_set, reactive_set;
14250   gboolean was_realized_set, realized_set;
14251   gboolean was_mapped_set, mapped_set;
14252   gboolean was_visible_set, visible_set;
14253
14254   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14255
14256   obj = G_OBJECT (self);
14257   g_object_freeze_notify (obj);
14258
14259   old_flags = self->flags;
14260
14261   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14262   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14263   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14264   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14265
14266   self->flags &= ~flags;
14267
14268   if (self->flags == old_flags)
14269     return;
14270
14271   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14272   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14273   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14274   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14275
14276   if (reactive_set != was_reactive_set)
14277     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14278
14279   if (realized_set != was_realized_set)
14280     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14281
14282   if (mapped_set != was_mapped_set)
14283     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14284
14285   if (visible_set != was_visible_set)
14286     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14287
14288   g_object_thaw_notify (obj);
14289 }
14290
14291 /**
14292  * clutter_actor_get_transformation_matrix:
14293  * @self: a #ClutterActor
14294  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14295  *
14296  * Retrieves the transformations applied to @self relative to its
14297  * parent.
14298  *
14299  * Since: 1.0
14300  */
14301 void
14302 clutter_actor_get_transformation_matrix (ClutterActor *self,
14303                                          CoglMatrix   *matrix)
14304 {
14305   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14306
14307   cogl_matrix_init_identity (matrix);
14308
14309   _clutter_actor_apply_modelview_transform (self, matrix);
14310 }
14311
14312 void
14313 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14314                                    gboolean      is_in_clone_paint)
14315 {
14316   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14317   self->priv->in_clone_paint = is_in_clone_paint;
14318 }
14319
14320 /**
14321  * clutter_actor_is_in_clone_paint:
14322  * @self: a #ClutterActor
14323  *
14324  * Checks whether @self is being currently painted by a #ClutterClone
14325  *
14326  * This function is useful only inside the ::paint virtual function
14327  * implementations or within handlers for the #ClutterActor::paint
14328  * signal
14329  *
14330  * This function should not be used by applications
14331  *
14332  * Return value: %TRUE if the #ClutterActor is currently being painted
14333  *   by a #ClutterClone, and %FALSE otherwise
14334  *
14335  * Since: 1.0
14336  */
14337 gboolean
14338 clutter_actor_is_in_clone_paint (ClutterActor *self)
14339 {
14340   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14341
14342   return self->priv->in_clone_paint;
14343 }
14344
14345 static gboolean
14346 set_direction_recursive (ClutterActor *actor,
14347                          gpointer      user_data)
14348 {
14349   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14350
14351   clutter_actor_set_text_direction (actor, text_dir);
14352
14353   return TRUE;
14354 }
14355
14356 /**
14357  * clutter_actor_set_text_direction:
14358  * @self: a #ClutterActor
14359  * @text_dir: the text direction for @self
14360  *
14361  * Sets the #ClutterTextDirection for an actor
14362  *
14363  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14364  *
14365  * If @self implements #ClutterContainer then this function will recurse
14366  * inside all the children of @self (including the internal ones).
14367  *
14368  * Composite actors not implementing #ClutterContainer, or actors requiring
14369  * special handling when the text direction changes, should connect to
14370  * the #GObject::notify signal for the #ClutterActor:text-direction property
14371  *
14372  * Since: 1.2
14373  */
14374 void
14375 clutter_actor_set_text_direction (ClutterActor         *self,
14376                                   ClutterTextDirection  text_dir)
14377 {
14378   ClutterActorPrivate *priv;
14379
14380   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14381   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14382
14383   priv = self->priv;
14384
14385   if (priv->text_direction != text_dir)
14386     {
14387       priv->text_direction = text_dir;
14388
14389       /* we need to emit the notify::text-direction first, so that
14390        * the sub-classes can catch that and do specific handling of
14391        * the text direction; see clutter_text_direction_changed_cb()
14392        * inside clutter-text.c
14393        */
14394       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14395
14396       _clutter_actor_foreach_child (self, set_direction_recursive,
14397                                     GINT_TO_POINTER (text_dir));
14398
14399       clutter_actor_queue_relayout (self);
14400     }
14401 }
14402
14403 void
14404 _clutter_actor_set_has_pointer (ClutterActor *self,
14405                                 gboolean      has_pointer)
14406 {
14407   ClutterActorPrivate *priv = self->priv;
14408
14409   if (priv->has_pointer != has_pointer)
14410     {
14411       priv->has_pointer = has_pointer;
14412
14413       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14414     }
14415 }
14416
14417 /**
14418  * clutter_actor_get_text_direction:
14419  * @self: a #ClutterActor
14420  *
14421  * Retrieves the value set using clutter_actor_set_text_direction()
14422  *
14423  * If no text direction has been previously set, the default text
14424  * direction, as returned by clutter_get_default_text_direction(), will
14425  * be returned instead
14426  *
14427  * Return value: the #ClutterTextDirection for the actor
14428  *
14429  * Since: 1.2
14430  */
14431 ClutterTextDirection
14432 clutter_actor_get_text_direction (ClutterActor *self)
14433 {
14434   ClutterActorPrivate *priv;
14435
14436   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14437                         CLUTTER_TEXT_DIRECTION_LTR);
14438
14439   priv = self->priv;
14440
14441   /* if no direction has been set yet use the default */
14442   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14443     priv->text_direction = clutter_get_default_text_direction ();
14444
14445   return priv->text_direction;
14446 }
14447
14448 /**
14449  * clutter_actor_push_internal:
14450  * @self: a #ClutterActor
14451  *
14452  * Should be used by actors implementing the #ClutterContainer and with
14453  * internal children added through clutter_actor_set_parent(), for instance:
14454  *
14455  * |[
14456  *   static void
14457  *   my_actor_init (MyActor *self)
14458  *   {
14459  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14460  *
14461  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14462  *
14463  *     /&ast; calling clutter_actor_set_parent() now will result in
14464  *      &ast; the internal flag being set on a child of MyActor
14465  *      &ast;/
14466  *
14467  *     /&ast; internal child - a background texture &ast;/
14468  *     self->priv->background_tex = clutter_texture_new ();
14469  *     clutter_actor_set_parent (self->priv->background_tex,
14470  *                               CLUTTER_ACTOR (self));
14471  *
14472  *     /&ast; internal child - a label &ast;/
14473  *     self->priv->label = clutter_text_new ();
14474  *     clutter_actor_set_parent (self->priv->label,
14475  *                               CLUTTER_ACTOR (self));
14476  *
14477  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14478  *
14479  *     /&ast; calling clutter_actor_set_parent() now will not result in
14480  *      &ast; the internal flag being set on a child of MyActor
14481  *      &ast;/
14482  *   }
14483  * ]|
14484  *
14485  * This function will be used by Clutter to toggle an "internal child"
14486  * flag whenever clutter_actor_set_parent() is called; internal children
14487  * are handled differently by Clutter, specifically when destroying their
14488  * parent.
14489  *
14490  * Call clutter_actor_pop_internal() when you finished adding internal
14491  * children.
14492  *
14493  * Nested calls to clutter_actor_push_internal() are allowed, but each
14494  * one must by followed by a clutter_actor_pop_internal() call.
14495  *
14496  * Since: 1.2
14497  *
14498  * Deprecated: 1.10: All children of an actor are accessible through
14499  *   the #ClutterActor API, and #ClutterActor implements the
14500  *   #ClutterContainer interface, so this function is only useful
14501  *   for legacy containers overriding the default implementation.
14502  */
14503 void
14504 clutter_actor_push_internal (ClutterActor *self)
14505 {
14506   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14507
14508   self->priv->internal_child += 1;
14509 }
14510
14511 /**
14512  * clutter_actor_pop_internal:
14513  * @self: a #ClutterActor
14514  *
14515  * Disables the effects of clutter_actor_push_internal().
14516  *
14517  * Since: 1.2
14518  *
14519  * Deprecated: 1.10: All children of an actor are accessible through
14520  *   the #ClutterActor API. This function is only useful for legacy
14521  *   containers overriding the default implementation of the
14522  *   #ClutterContainer interface.
14523  */
14524 void
14525 clutter_actor_pop_internal (ClutterActor *self)
14526 {
14527   ClutterActorPrivate *priv;
14528
14529   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14530
14531   priv = self->priv;
14532
14533   if (priv->internal_child == 0)
14534     {
14535       g_warning ("Mismatched %s: you need to call "
14536                  "clutter_actor_push_composite() at least once before "
14537                  "calling this function", G_STRFUNC);
14538       return;
14539     }
14540
14541   priv->internal_child -= 1;
14542 }
14543
14544 /**
14545  * clutter_actor_has_pointer:
14546  * @self: a #ClutterActor
14547  *
14548  * Checks whether an actor contains the pointer of a
14549  * #ClutterInputDevice
14550  *
14551  * Return value: %TRUE if the actor contains the pointer, and
14552  *   %FALSE otherwise
14553  *
14554  * Since: 1.2
14555  */
14556 gboolean
14557 clutter_actor_has_pointer (ClutterActor *self)
14558 {
14559   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14560
14561   return self->priv->has_pointer;
14562 }
14563
14564 /* XXX: This is a workaround for not being able to break the ABI of
14565  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14566  * clutter_actor_queue_clipped_redraw() for details.
14567  */
14568 ClutterPaintVolume *
14569 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14570 {
14571   return g_object_get_data (G_OBJECT (self),
14572                             "-clutter-actor-queue-redraw-clip");
14573 }
14574
14575 void
14576 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14577                                       ClutterPaintVolume *clip)
14578 {
14579   g_object_set_data (G_OBJECT (self),
14580                      "-clutter-actor-queue-redraw-clip",
14581                      clip);
14582 }
14583
14584 /**
14585  * clutter_actor_has_allocation:
14586  * @self: a #ClutterActor
14587  *
14588  * Checks if the actor has an up-to-date allocation assigned to
14589  * it. This means that the actor should have an allocation: it's
14590  * visible and has a parent. It also means that there is no
14591  * outstanding relayout request in progress for the actor or its
14592  * children (There might be other outstanding layout requests in
14593  * progress that will cause the actor to get a new allocation
14594  * when the stage is laid out, however).
14595  *
14596  * If this function returns %FALSE, then the actor will normally
14597  * be allocated before it is next drawn on the screen.
14598  *
14599  * Return value: %TRUE if the actor has an up-to-date allocation
14600  *
14601  * Since: 1.4
14602  */
14603 gboolean
14604 clutter_actor_has_allocation (ClutterActor *self)
14605 {
14606   ClutterActorPrivate *priv;
14607
14608   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14609
14610   priv = self->priv;
14611
14612   return priv->parent != NULL &&
14613          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14614          !priv->needs_allocation;
14615 }
14616
14617 /**
14618  * clutter_actor_add_action:
14619  * @self: a #ClutterActor
14620  * @action: a #ClutterAction
14621  *
14622  * Adds @action to the list of actions applied to @self
14623  *
14624  * A #ClutterAction can only belong to one actor at a time
14625  *
14626  * The #ClutterActor will hold a reference on @action until either
14627  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14628  * is called
14629  *
14630  * Since: 1.4
14631  */
14632 void
14633 clutter_actor_add_action (ClutterActor  *self,
14634                           ClutterAction *action)
14635 {
14636   ClutterActorPrivate *priv;
14637
14638   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14639   g_return_if_fail (CLUTTER_IS_ACTION (action));
14640
14641   priv = self->priv;
14642
14643   if (priv->actions == NULL)
14644     {
14645       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14646       priv->actions->actor = self;
14647     }
14648
14649   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14650
14651   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14652 }
14653
14654 /**
14655  * clutter_actor_add_action_with_name:
14656  * @self: a #ClutterActor
14657  * @name: the name to set on the action
14658  * @action: a #ClutterAction
14659  *
14660  * A convenience function for setting the name of a #ClutterAction
14661  * while adding it to the list of actions applied to @self
14662  *
14663  * This function is the logical equivalent of:
14664  *
14665  * |[
14666  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14667  *   clutter_actor_add_action (self, action);
14668  * ]|
14669  *
14670  * Since: 1.4
14671  */
14672 void
14673 clutter_actor_add_action_with_name (ClutterActor  *self,
14674                                     const gchar   *name,
14675                                     ClutterAction *action)
14676 {
14677   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14678   g_return_if_fail (name != NULL);
14679   g_return_if_fail (CLUTTER_IS_ACTION (action));
14680
14681   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14682   clutter_actor_add_action (self, action);
14683 }
14684
14685 /**
14686  * clutter_actor_remove_action:
14687  * @self: a #ClutterActor
14688  * @action: a #ClutterAction
14689  *
14690  * Removes @action from the list of actions applied to @self
14691  *
14692  * The reference held by @self on the #ClutterAction will be released
14693  *
14694  * Since: 1.4
14695  */
14696 void
14697 clutter_actor_remove_action (ClutterActor  *self,
14698                              ClutterAction *action)
14699 {
14700   ClutterActorPrivate *priv;
14701
14702   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14703   g_return_if_fail (CLUTTER_IS_ACTION (action));
14704
14705   priv = self->priv;
14706
14707   if (priv->actions == NULL)
14708     return;
14709
14710   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14711
14712   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14713 }
14714
14715 /**
14716  * clutter_actor_remove_action_by_name:
14717  * @self: a #ClutterActor
14718  * @name: the name of the action to remove
14719  *
14720  * Removes the #ClutterAction with the given name from the list
14721  * of actions applied to @self
14722  *
14723  * Since: 1.4
14724  */
14725 void
14726 clutter_actor_remove_action_by_name (ClutterActor *self,
14727                                      const gchar  *name)
14728 {
14729   ClutterActorPrivate *priv;
14730   ClutterActorMeta *meta;
14731
14732   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14733   g_return_if_fail (name != NULL);
14734
14735   priv = self->priv;
14736
14737   if (priv->actions == NULL)
14738     return;
14739
14740   meta = _clutter_meta_group_get_meta (priv->actions, name);
14741   if (meta == NULL)
14742     return;
14743
14744   _clutter_meta_group_remove_meta (priv->actions, meta);
14745
14746   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14747 }
14748
14749 /**
14750  * clutter_actor_get_actions:
14751  * @self: a #ClutterActor
14752  *
14753  * Retrieves the list of actions applied to @self
14754  *
14755  * Return value: (transfer container) (element-type Clutter.Action): a copy
14756  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14757  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14758  *   allocated by the returned #GList
14759  *
14760  * Since: 1.4
14761  */
14762 GList *
14763 clutter_actor_get_actions (ClutterActor *self)
14764 {
14765   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14766
14767   if (self->priv->actions == NULL)
14768     return NULL;
14769
14770   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14771 }
14772
14773 /**
14774  * clutter_actor_get_action:
14775  * @self: a #ClutterActor
14776  * @name: the name of the action to retrieve
14777  *
14778  * Retrieves the #ClutterAction with the given name in the list
14779  * of actions applied to @self
14780  *
14781  * Return value: (transfer none): a #ClutterAction for the given
14782  *   name, or %NULL. The returned #ClutterAction is owned by the
14783  *   actor and it should not be unreferenced directly
14784  *
14785  * Since: 1.4
14786  */
14787 ClutterAction *
14788 clutter_actor_get_action (ClutterActor *self,
14789                           const gchar  *name)
14790 {
14791   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14792   g_return_val_if_fail (name != NULL, NULL);
14793
14794   if (self->priv->actions == NULL)
14795     return NULL;
14796
14797   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14798 }
14799
14800 /**
14801  * clutter_actor_clear_actions:
14802  * @self: a #ClutterActor
14803  *
14804  * Clears the list of actions applied to @self
14805  *
14806  * Since: 1.4
14807  */
14808 void
14809 clutter_actor_clear_actions (ClutterActor *self)
14810 {
14811   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14812
14813   if (self->priv->actions == NULL)
14814     return;
14815
14816   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14817 }
14818
14819 /**
14820  * clutter_actor_add_constraint:
14821  * @self: a #ClutterActor
14822  * @constraint: a #ClutterConstraint
14823  *
14824  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14825  * to @self
14826  *
14827  * The #ClutterActor will hold a reference on the @constraint until
14828  * either clutter_actor_remove_constraint() or
14829  * clutter_actor_clear_constraints() is called.
14830  *
14831  * Since: 1.4
14832  */
14833 void
14834 clutter_actor_add_constraint (ClutterActor      *self,
14835                               ClutterConstraint *constraint)
14836 {
14837   ClutterActorPrivate *priv;
14838
14839   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14840   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14841
14842   priv = self->priv;
14843
14844   if (priv->constraints == NULL)
14845     {
14846       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14847       priv->constraints->actor = self;
14848     }
14849
14850   _clutter_meta_group_add_meta (priv->constraints,
14851                                 CLUTTER_ACTOR_META (constraint));
14852   clutter_actor_queue_relayout (self);
14853
14854   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14855 }
14856
14857 /**
14858  * clutter_actor_add_constraint_with_name:
14859  * @self: a #ClutterActor
14860  * @name: the name to set on the constraint
14861  * @constraint: a #ClutterConstraint
14862  *
14863  * A convenience function for setting the name of a #ClutterConstraint
14864  * while adding it to the list of constraints applied to @self
14865  *
14866  * This function is the logical equivalent of:
14867  *
14868  * |[
14869  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14870  *   clutter_actor_add_constraint (self, constraint);
14871  * ]|
14872  *
14873  * Since: 1.4
14874  */
14875 void
14876 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14877                                         const gchar       *name,
14878                                         ClutterConstraint *constraint)
14879 {
14880   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14881   g_return_if_fail (name != NULL);
14882   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14883
14884   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14885   clutter_actor_add_constraint (self, constraint);
14886 }
14887
14888 /**
14889  * clutter_actor_remove_constraint:
14890  * @self: a #ClutterActor
14891  * @constraint: a #ClutterConstraint
14892  *
14893  * Removes @constraint from the list of constraints applied to @self
14894  *
14895  * The reference held by @self on the #ClutterConstraint will be released
14896  *
14897  * Since: 1.4
14898  */
14899 void
14900 clutter_actor_remove_constraint (ClutterActor      *self,
14901                                  ClutterConstraint *constraint)
14902 {
14903   ClutterActorPrivate *priv;
14904
14905   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14906   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14907
14908   priv = self->priv;
14909
14910   if (priv->constraints == NULL)
14911     return;
14912
14913   _clutter_meta_group_remove_meta (priv->constraints,
14914                                    CLUTTER_ACTOR_META (constraint));
14915   clutter_actor_queue_relayout (self);
14916
14917   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14918 }
14919
14920 /**
14921  * clutter_actor_remove_constraint_by_name:
14922  * @self: a #ClutterActor
14923  * @name: the name of the constraint to remove
14924  *
14925  * Removes the #ClutterConstraint with the given name from the list
14926  * of constraints applied to @self
14927  *
14928  * Since: 1.4
14929  */
14930 void
14931 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14932                                          const gchar  *name)
14933 {
14934   ClutterActorPrivate *priv;
14935   ClutterActorMeta *meta;
14936
14937   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14938   g_return_if_fail (name != NULL);
14939
14940   priv = self->priv;
14941
14942   if (priv->constraints == NULL)
14943     return;
14944
14945   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14946   if (meta == NULL)
14947     return;
14948
14949   _clutter_meta_group_remove_meta (priv->constraints, meta);
14950   clutter_actor_queue_relayout (self);
14951 }
14952
14953 /**
14954  * clutter_actor_get_constraints:
14955  * @self: a #ClutterActor
14956  *
14957  * Retrieves the list of constraints applied to @self
14958  *
14959  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14960  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14961  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14962  *   allocated by the returned #GList
14963  *
14964  * Since: 1.4
14965  */
14966 GList *
14967 clutter_actor_get_constraints (ClutterActor *self)
14968 {
14969   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14970
14971   if (self->priv->constraints == NULL)
14972     return NULL;
14973
14974   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14975 }
14976
14977 /**
14978  * clutter_actor_get_constraint:
14979  * @self: a #ClutterActor
14980  * @name: the name of the constraint to retrieve
14981  *
14982  * Retrieves the #ClutterConstraint with the given name in the list
14983  * of constraints applied to @self
14984  *
14985  * Return value: (transfer none): a #ClutterConstraint for the given
14986  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14987  *   actor and it should not be unreferenced directly
14988  *
14989  * Since: 1.4
14990  */
14991 ClutterConstraint *
14992 clutter_actor_get_constraint (ClutterActor *self,
14993                               const gchar  *name)
14994 {
14995   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14996   g_return_val_if_fail (name != NULL, NULL);
14997
14998   if (self->priv->constraints == NULL)
14999     return NULL;
15000
15001   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15002 }
15003
15004 /**
15005  * clutter_actor_clear_constraints:
15006  * @self: a #ClutterActor
15007  *
15008  * Clears the list of constraints applied to @self
15009  *
15010  * Since: 1.4
15011  */
15012 void
15013 clutter_actor_clear_constraints (ClutterActor *self)
15014 {
15015   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15016
15017   if (self->priv->constraints == NULL)
15018     return;
15019
15020   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15021
15022   clutter_actor_queue_relayout (self);
15023 }
15024
15025 /**
15026  * clutter_actor_set_clip_to_allocation:
15027  * @self: a #ClutterActor
15028  * @clip_set: %TRUE to apply a clip tracking the allocation
15029  *
15030  * Sets whether @self should be clipped to the same size as its
15031  * allocation
15032  *
15033  * Since: 1.4
15034  */
15035 void
15036 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15037                                       gboolean      clip_set)
15038 {
15039   ClutterActorPrivate *priv;
15040
15041   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15042
15043   clip_set = !!clip_set;
15044
15045   priv = self->priv;
15046
15047   if (priv->clip_to_allocation != clip_set)
15048     {
15049       priv->clip_to_allocation = clip_set;
15050
15051       clutter_actor_queue_redraw (self);
15052
15053       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15054     }
15055 }
15056
15057 /**
15058  * clutter_actor_get_clip_to_allocation:
15059  * @self: a #ClutterActor
15060  *
15061  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15062  *
15063  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15064  *
15065  * Since: 1.4
15066  */
15067 gboolean
15068 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15069 {
15070   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15071
15072   return self->priv->clip_to_allocation;
15073 }
15074
15075 /**
15076  * clutter_actor_add_effect:
15077  * @self: a #ClutterActor
15078  * @effect: a #ClutterEffect
15079  *
15080  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15081  *
15082  * The #ClutterActor will hold a reference on the @effect until either
15083  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15084  * called.
15085  *
15086  * Since: 1.4
15087  */
15088 void
15089 clutter_actor_add_effect (ClutterActor  *self,
15090                           ClutterEffect *effect)
15091 {
15092   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15093   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15094
15095   _clutter_actor_add_effect_internal (self, effect);
15096
15097   clutter_actor_queue_redraw (self);
15098
15099   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15100 }
15101
15102 /**
15103  * clutter_actor_add_effect_with_name:
15104  * @self: a #ClutterActor
15105  * @name: the name to set on the effect
15106  * @effect: a #ClutterEffect
15107  *
15108  * A convenience function for setting the name of a #ClutterEffect
15109  * while adding it to the list of effectss applied to @self
15110  *
15111  * This function is the logical equivalent of:
15112  *
15113  * |[
15114  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15115  *   clutter_actor_add_effect (self, effect);
15116  * ]|
15117  *
15118  * Since: 1.4
15119  */
15120 void
15121 clutter_actor_add_effect_with_name (ClutterActor  *self,
15122                                     const gchar   *name,
15123                                     ClutterEffect *effect)
15124 {
15125   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15126   g_return_if_fail (name != NULL);
15127   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15128
15129   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15130   clutter_actor_add_effect (self, effect);
15131 }
15132
15133 /**
15134  * clutter_actor_remove_effect:
15135  * @self: a #ClutterActor
15136  * @effect: a #ClutterEffect
15137  *
15138  * Removes @effect from the list of effects applied to @self
15139  *
15140  * The reference held by @self on the #ClutterEffect will be released
15141  *
15142  * Since: 1.4
15143  */
15144 void
15145 clutter_actor_remove_effect (ClutterActor  *self,
15146                              ClutterEffect *effect)
15147 {
15148   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15149   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15150
15151   _clutter_actor_remove_effect_internal (self, effect);
15152
15153   clutter_actor_queue_redraw (self);
15154
15155   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15156 }
15157
15158 /**
15159  * clutter_actor_remove_effect_by_name:
15160  * @self: a #ClutterActor
15161  * @name: the name of the effect to remove
15162  *
15163  * Removes the #ClutterEffect with the given name from the list
15164  * of effects applied to @self
15165  *
15166  * Since: 1.4
15167  */
15168 void
15169 clutter_actor_remove_effect_by_name (ClutterActor *self,
15170                                      const gchar  *name)
15171 {
15172   ClutterActorPrivate *priv;
15173   ClutterActorMeta *meta;
15174
15175   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15176   g_return_if_fail (name != NULL);
15177
15178   priv = self->priv;
15179
15180   if (priv->effects == NULL)
15181     return;
15182
15183   meta = _clutter_meta_group_get_meta (priv->effects, name);
15184   if (meta == NULL)
15185     return;
15186
15187   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15188 }
15189
15190 /**
15191  * clutter_actor_get_effects:
15192  * @self: a #ClutterActor
15193  *
15194  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15195  *
15196  * Return value: (transfer container) (element-type Clutter.Effect): a list
15197  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15198  *   list are owned by Clutter and they should not be freed. You should
15199  *   free the returned list using g_list_free() when done
15200  *
15201  * Since: 1.4
15202  */
15203 GList *
15204 clutter_actor_get_effects (ClutterActor *self)
15205 {
15206   ClutterActorPrivate *priv;
15207
15208   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15209
15210   priv = self->priv;
15211
15212   if (priv->effects == NULL)
15213     return NULL;
15214
15215   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15216 }
15217
15218 /**
15219  * clutter_actor_get_effect:
15220  * @self: a #ClutterActor
15221  * @name: the name of the effect to retrieve
15222  *
15223  * Retrieves the #ClutterEffect with the given name in the list
15224  * of effects applied to @self
15225  *
15226  * Return value: (transfer none): a #ClutterEffect for the given
15227  *   name, or %NULL. The returned #ClutterEffect is owned by the
15228  *   actor and it should not be unreferenced directly
15229  *
15230  * Since: 1.4
15231  */
15232 ClutterEffect *
15233 clutter_actor_get_effect (ClutterActor *self,
15234                           const gchar  *name)
15235 {
15236   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15237   g_return_val_if_fail (name != NULL, NULL);
15238
15239   if (self->priv->effects == NULL)
15240     return NULL;
15241
15242   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15243 }
15244
15245 /**
15246  * clutter_actor_clear_effects:
15247  * @self: a #ClutterActor
15248  *
15249  * Clears the list of effects applied to @self
15250  *
15251  * Since: 1.4
15252  */
15253 void
15254 clutter_actor_clear_effects (ClutterActor *self)
15255 {
15256   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15257
15258   if (self->priv->effects == NULL)
15259     return;
15260
15261   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15262
15263   clutter_actor_queue_redraw (self);
15264 }
15265
15266 /**
15267  * clutter_actor_has_key_focus:
15268  * @self: a #ClutterActor
15269  *
15270  * Checks whether @self is the #ClutterActor that has key focus
15271  *
15272  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15273  *
15274  * Since: 1.4
15275  */
15276 gboolean
15277 clutter_actor_has_key_focus (ClutterActor *self)
15278 {
15279   ClutterActor *stage;
15280
15281   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15282
15283   stage = _clutter_actor_get_stage_internal (self);
15284   if (stage == NULL)
15285     return FALSE;
15286
15287   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15288 }
15289
15290 static gboolean
15291 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15292                                       ClutterPaintVolume *pv)
15293 {
15294   ClutterActorPrivate *priv = self->priv;
15295
15296   /* Actors are only expected to report a valid paint volume
15297    * while they have a valid allocation. */
15298   if (G_UNLIKELY (priv->needs_allocation))
15299     {
15300       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15301                     "Actor needs allocation",
15302                     _clutter_actor_get_debug_name (self));
15303       return FALSE;
15304     }
15305
15306   /* Check if there are any handlers connected to the paint
15307    * signal. If there are then all bets are off for what the paint
15308    * volume for this actor might possibly be!
15309    *
15310    * XXX: It's expected that this is going to end up being quite a
15311    * costly check to have to do here, but we haven't come up with
15312    * another solution that can reliably catch paint signal handlers at
15313    * the right time to either avoid artefacts due to invalid stage
15314    * clipping or due to incorrect culling.
15315    *
15316    * Previously we checked in clutter_actor_paint(), but at that time
15317    * we may already be using a stage clip that could be derived from
15318    * an invalid paint-volume. We used to try and handle that by
15319    * queuing a follow up, unclipped, redraw but still the previous
15320    * checking wasn't enough to catch invalid volumes involved in
15321    * culling (considering that containers may derive their volume from
15322    * children that haven't yet been painted)
15323    *
15324    * Longer term, improved solutions could be:
15325    * - Disallow painting in the paint signal, only allow using it
15326    *   for tracking when paints happen. We can add another API that
15327    *   allows monkey patching the paint of arbitrary actors but in a
15328    *   more controlled way and that also supports modifying the
15329    *   paint-volume.
15330    * - If we could be notified somehow when signal handlers are
15331    *   connected we wouldn't have to poll for handlers like this.
15332    */
15333   if (g_signal_has_handler_pending (self,
15334                                     actor_signals[PAINT],
15335                                     0,
15336                                     TRUE))
15337     {
15338       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15339                     "Actor has \"paint\" signal handlers",
15340                     _clutter_actor_get_debug_name (self));
15341       return FALSE;
15342     }
15343
15344   _clutter_paint_volume_init_static (pv, self);
15345
15346   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15347     {
15348       clutter_paint_volume_free (pv);
15349       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15350                     "Actor failed to report a volume",
15351                     _clutter_actor_get_debug_name (self));
15352       return FALSE;
15353     }
15354
15355   /* since effects can modify the paint volume, we allow them to actually
15356    * do this by making get_paint_volume() "context sensitive"
15357    */
15358   if (priv->effects != NULL)
15359     {
15360       if (priv->current_effect != NULL)
15361         {
15362           const GList *effects, *l;
15363
15364           /* if we are being called from within the paint sequence of
15365            * an actor, get the paint volume up to the current effect
15366            */
15367           effects = _clutter_meta_group_peek_metas (priv->effects);
15368           for (l = effects;
15369                l != NULL || (l != NULL && l->data != priv->current_effect);
15370                l = l->next)
15371             {
15372               if (!_clutter_effect_get_paint_volume (l->data, pv))
15373                 {
15374                   clutter_paint_volume_free (pv);
15375                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15376                                 "Effect (%s) failed to report a volume",
15377                                 _clutter_actor_get_debug_name (self),
15378                                 _clutter_actor_meta_get_debug_name (l->data));
15379                   return FALSE;
15380                 }
15381             }
15382         }
15383       else
15384         {
15385           const GList *effects, *l;
15386
15387           /* otherwise, get the cumulative volume */
15388           effects = _clutter_meta_group_peek_metas (priv->effects);
15389           for (l = effects; l != NULL; l = l->next)
15390             if (!_clutter_effect_get_paint_volume (l->data, pv))
15391               {
15392                 clutter_paint_volume_free (pv);
15393                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15394                               "Effect (%s) failed to report a volume",
15395                               _clutter_actor_get_debug_name (self),
15396                               _clutter_actor_meta_get_debug_name (l->data));
15397                 return FALSE;
15398               }
15399         }
15400     }
15401
15402   return TRUE;
15403 }
15404
15405 /* The public clutter_actor_get_paint_volume API returns a const
15406  * pointer since we return a pointer directly to the cached
15407  * PaintVolume associated with the actor and don't want the user to
15408  * inadvertently modify it, but for internal uses we sometimes need
15409  * access to the same PaintVolume but need to apply some book-keeping
15410  * modifications to it so we don't want a const pointer.
15411  */
15412 static ClutterPaintVolume *
15413 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15414 {
15415   ClutterActorPrivate *priv;
15416
15417   priv = self->priv;
15418
15419   if (priv->paint_volume_valid)
15420     clutter_paint_volume_free (&priv->paint_volume);
15421
15422   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15423     {
15424       priv->paint_volume_valid = TRUE;
15425       return &priv->paint_volume;
15426     }
15427   else
15428     {
15429       priv->paint_volume_valid = FALSE;
15430       return NULL;
15431     }
15432 }
15433
15434 /**
15435  * clutter_actor_get_paint_volume:
15436  * @self: a #ClutterActor
15437  *
15438  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15439  * when a paint volume can't be determined.
15440  *
15441  * The paint volume is defined as the 3D space occupied by an actor
15442  * when being painted.
15443  *
15444  * This function will call the <function>get_paint_volume()</function>
15445  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15446  * should not usually care about overriding the default implementation,
15447  * unless they are, for instance: painting outside their allocation, or
15448  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15449  * 3D depth).
15450  *
15451  * <note>2D actors overriding <function>get_paint_volume()</function>
15452  * ensure their volume has a depth of 0. (This will be true so long as
15453  * you don't call clutter_paint_volume_set_depth().)</note>
15454  *
15455  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15456  *   or %NULL if no volume could be determined. The returned pointer
15457  *   is not guaranteed to be valid across multiple frames; if you want
15458  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15459  *
15460  * Since: 1.6
15461  */
15462 const ClutterPaintVolume *
15463 clutter_actor_get_paint_volume (ClutterActor *self)
15464 {
15465   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15466
15467   return _clutter_actor_get_paint_volume_mutable (self);
15468 }
15469
15470 /**
15471  * clutter_actor_get_transformed_paint_volume:
15472  * @self: a #ClutterActor
15473  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15474  *    (or %NULL for the stage)
15475  *
15476  * Retrieves the 3D paint volume of an actor like
15477  * clutter_actor_get_paint_volume() does (Please refer to the
15478  * documentation of clutter_actor_get_paint_volume() for more
15479  * details.) and it additionally transforms the paint volume into the
15480  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15481  * is passed for @relative_to_ancestor)
15482  *
15483  * This can be used by containers that base their paint volume on
15484  * the volume of their children. Such containers can query the
15485  * transformed paint volume of all of its children and union them
15486  * together using clutter_paint_volume_union().
15487  *
15488  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15489  *   or %NULL if no volume could be determined. The returned pointer is
15490  *   not guaranteed to be valid across multiple frames; if you wish to
15491  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15492  *
15493  * Since: 1.6
15494  */
15495 const ClutterPaintVolume *
15496 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15497                                             ClutterActor *relative_to_ancestor)
15498 {
15499   const ClutterPaintVolume *volume;
15500   ClutterActor *stage;
15501   ClutterPaintVolume *transformed_volume;
15502
15503   stage = _clutter_actor_get_stage_internal (self);
15504   if (G_UNLIKELY (stage == NULL))
15505     return NULL;
15506
15507   if (relative_to_ancestor == NULL)
15508     relative_to_ancestor = stage;
15509
15510   volume = clutter_actor_get_paint_volume (self);
15511   if (volume == NULL)
15512     return NULL;
15513
15514   transformed_volume =
15515     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15516
15517   _clutter_paint_volume_copy_static (volume, transformed_volume);
15518
15519   _clutter_paint_volume_transform_relative (transformed_volume,
15520                                             relative_to_ancestor);
15521
15522   return transformed_volume;
15523 }
15524
15525 /**
15526  * clutter_actor_get_paint_box:
15527  * @self: a #ClutterActor
15528  * @box: (out): return location for a #ClutterActorBox
15529  *
15530  * Retrieves the paint volume of the passed #ClutterActor, and
15531  * transforms it into a 2D bounding box in stage coordinates.
15532  *
15533  * This function is useful to determine the on screen area occupied by
15534  * the actor. The box is only an approximation and may often be
15535  * considerably larger due to the optimizations used to calculate the
15536  * box. The box is never smaller though, so it can reliably be used
15537  * for culling.
15538  *
15539  * There are times when a 2D paint box can't be determined, e.g.
15540  * because the actor isn't yet parented under a stage or because
15541  * the actor is unable to determine a paint volume.
15542  *
15543  * Return value: %TRUE if a 2D paint box could be determined, else
15544  * %FALSE.
15545  *
15546  * Since: 1.6
15547  */
15548 gboolean
15549 clutter_actor_get_paint_box (ClutterActor    *self,
15550                              ClutterActorBox *box)
15551 {
15552   ClutterActor *stage;
15553   ClutterPaintVolume *pv;
15554
15555   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15556   g_return_val_if_fail (box != NULL, FALSE);
15557
15558   stage = _clutter_actor_get_stage_internal (self);
15559   if (G_UNLIKELY (!stage))
15560     return FALSE;
15561
15562   pv = _clutter_actor_get_paint_volume_mutable (self);
15563   if (G_UNLIKELY (!pv))
15564     return FALSE;
15565
15566   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15567
15568   return TRUE;
15569 }
15570
15571 /**
15572  * clutter_actor_has_overlaps:
15573  * @self: A #ClutterActor
15574  *
15575  * Asks the actor's implementation whether it may contain overlapping
15576  * primitives.
15577  *
15578  * For example; Clutter may use this to determine whether the painting
15579  * should be redirected to an offscreen buffer to correctly implement
15580  * the opacity property.
15581  *
15582  * Custom actors can override the default response by implementing the
15583  * #ClutterActor <function>has_overlaps</function> virtual function. See
15584  * clutter_actor_set_offscreen_redirect() for more information.
15585  *
15586  * Return value: %TRUE if the actor may have overlapping primitives, and
15587  *   %FALSE otherwise
15588  *
15589  * Since: 1.8
15590  */
15591 gboolean
15592 clutter_actor_has_overlaps (ClutterActor *self)
15593 {
15594   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15595
15596   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15597 }
15598
15599 /**
15600  * clutter_actor_has_effects:
15601  * @self: A #ClutterActor
15602  *
15603  * Returns whether the actor has any effects applied.
15604  *
15605  * Return value: %TRUE if the actor has any effects,
15606  *   %FALSE otherwise
15607  *
15608  * Since: 1.10
15609  */
15610 gboolean
15611 clutter_actor_has_effects (ClutterActor *self)
15612 {
15613   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15614
15615   if (self->priv->effects == NULL)
15616     return FALSE;
15617
15618   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15619 }
15620
15621 /**
15622  * clutter_actor_has_constraints:
15623  * @self: A #ClutterActor
15624  *
15625  * Returns whether the actor has any constraints applied.
15626  *
15627  * Return value: %TRUE if the actor has any constraints,
15628  *   %FALSE otherwise
15629  *
15630  * Since: 1.10
15631  */
15632 gboolean
15633 clutter_actor_has_constraints (ClutterActor *self)
15634 {
15635   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15636
15637   return self->priv->constraints != NULL;
15638 }
15639
15640 /**
15641  * clutter_actor_has_actions:
15642  * @self: A #ClutterActor
15643  *
15644  * Returns whether the actor has any actions applied.
15645  *
15646  * Return value: %TRUE if the actor has any actions,
15647  *   %FALSE otherwise
15648  *
15649  * Since: 1.10
15650  */
15651 gboolean
15652 clutter_actor_has_actions (ClutterActor *self)
15653 {
15654   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15655
15656   return self->priv->actions != NULL;
15657 }
15658
15659 /**
15660  * clutter_actor_get_n_children:
15661  * @self: a #ClutterActor
15662  *
15663  * Retrieves the number of children of @self.
15664  *
15665  * Return value: the number of children of an actor
15666  *
15667  * Since: 1.10
15668  */
15669 gint
15670 clutter_actor_get_n_children (ClutterActor *self)
15671 {
15672   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15673
15674   return self->priv->n_children;
15675 }
15676
15677 /**
15678  * clutter_actor_get_child_at_index:
15679  * @self: a #ClutterActor
15680  * @index_: the position in the list of children
15681  *
15682  * Retrieves the actor at the given @index_ inside the list of
15683  * children of @self.
15684  *
15685  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15686  *
15687  * Since: 1.10
15688  */
15689 ClutterActor *
15690 clutter_actor_get_child_at_index (ClutterActor *self,
15691                                   gint          index_)
15692 {
15693   ClutterActor *iter;
15694   int i;
15695
15696   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15697   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15698
15699   for (iter = self->priv->first_child, i = 0;
15700        iter != NULL && i < index_;
15701        iter = iter->priv->next_sibling, i += 1)
15702     ;
15703
15704   return iter;
15705 }
15706
15707 /*< private >
15708  * _clutter_actor_foreach_child:
15709  * @actor: The actor whos children you want to iterate
15710  * @callback: The function to call for each child
15711  * @user_data: Private data to pass to @callback
15712  *
15713  * Calls a given @callback once for each child of the specified @actor and
15714  * passing the @user_data pointer each time.
15715  *
15716  * Return value: returns %TRUE if all children were iterated, else
15717  *    %FALSE if a callback broke out of iteration early.
15718  */
15719 gboolean
15720 _clutter_actor_foreach_child (ClutterActor           *self,
15721                               ClutterForeachCallback  callback,
15722                               gpointer                user_data)
15723 {
15724   ClutterActorPrivate *priv = self->priv;
15725   ClutterActor *iter;
15726   gboolean cont;
15727
15728   for (cont = TRUE, iter = priv->first_child;
15729        cont && iter != NULL;
15730        iter = iter->priv->next_sibling)
15731     {
15732       cont = callback (iter, user_data);
15733     }
15734
15735   return cont;
15736 }
15737
15738 #if 0
15739 /* For debugging purposes this gives us a simple way to print out
15740  * the scenegraph e.g in gdb using:
15741  * [|
15742  *   _clutter_actor_traverse (stage,
15743  *                            0,
15744  *                            clutter_debug_print_actor_cb,
15745  *                            NULL,
15746  *                            NULL);
15747  * |]
15748  */
15749 static ClutterActorTraverseVisitFlags
15750 clutter_debug_print_actor_cb (ClutterActor *actor,
15751                               int depth,
15752                               void *user_data)
15753 {
15754   g_print ("%*s%s:%p\n",
15755            depth * 2, "",
15756            _clutter_actor_get_debug_name (actor),
15757            actor);
15758
15759   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15760 }
15761 #endif
15762
15763 static void
15764 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15765                                  ClutterTraverseCallback callback,
15766                                  gpointer                user_data)
15767 {
15768   GQueue *queue = g_queue_new ();
15769   ClutterActor dummy;
15770   int current_depth = 0;
15771
15772   g_queue_push_tail (queue, actor);
15773   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15774
15775   while ((actor = g_queue_pop_head (queue)))
15776     {
15777       ClutterActorTraverseVisitFlags flags;
15778
15779       if (actor == &dummy)
15780         {
15781           current_depth++;
15782           g_queue_push_tail (queue, &dummy);
15783           continue;
15784         }
15785
15786       flags = callback (actor, current_depth, user_data);
15787       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15788         break;
15789       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15790         {
15791           ClutterActor *iter;
15792
15793           for (iter = actor->priv->first_child;
15794                iter != NULL;
15795                iter = iter->priv->next_sibling)
15796             {
15797               g_queue_push_tail (queue, iter);
15798             }
15799         }
15800     }
15801
15802   g_queue_free (queue);
15803 }
15804
15805 static ClutterActorTraverseVisitFlags
15806 _clutter_actor_traverse_depth (ClutterActor           *actor,
15807                                ClutterTraverseCallback before_children_callback,
15808                                ClutterTraverseCallback after_children_callback,
15809                                int                     current_depth,
15810                                gpointer                user_data)
15811 {
15812   ClutterActorTraverseVisitFlags flags;
15813
15814   flags = before_children_callback (actor, current_depth, user_data);
15815   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15816     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15817
15818   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15819     {
15820       ClutterActor *iter;
15821
15822       for (iter = actor->priv->first_child;
15823            iter != NULL;
15824            iter = iter->priv->next_sibling)
15825         {
15826           flags = _clutter_actor_traverse_depth (iter,
15827                                                  before_children_callback,
15828                                                  after_children_callback,
15829                                                  current_depth + 1,
15830                                                  user_data);
15831
15832           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15833             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15834         }
15835     }
15836
15837   if (after_children_callback)
15838     return after_children_callback (actor, current_depth, user_data);
15839   else
15840     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15841 }
15842
15843 /* _clutter_actor_traverse:
15844  * @actor: The actor to start traversing the graph from
15845  * @flags: These flags may affect how the traversal is done
15846  * @before_children_callback: A function to call before visiting the
15847  *   children of the current actor.
15848  * @after_children_callback: A function to call after visiting the
15849  *   children of the current actor. (Ignored if
15850  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15851  * @user_data: The private data to pass to the callbacks
15852  *
15853  * Traverses the scenegraph starting at the specified @actor and
15854  * descending through all its children and its children's children.
15855  * For each actor traversed @before_children_callback and
15856  * @after_children_callback are called with the specified
15857  * @user_data, before and after visiting that actor's children.
15858  *
15859  * The callbacks can return flags that affect the ongoing traversal
15860  * such as by skipping over an actors children or bailing out of
15861  * any further traversing.
15862  */
15863 void
15864 _clutter_actor_traverse (ClutterActor              *actor,
15865                          ClutterActorTraverseFlags  flags,
15866                          ClutterTraverseCallback    before_children_callback,
15867                          ClutterTraverseCallback    after_children_callback,
15868                          gpointer                   user_data)
15869 {
15870   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15871     _clutter_actor_traverse_breadth (actor,
15872                                      before_children_callback,
15873                                      user_data);
15874   else /* DEPTH_FIRST */
15875     _clutter_actor_traverse_depth (actor,
15876                                    before_children_callback,
15877                                    after_children_callback,
15878                                    0, /* start depth */
15879                                    user_data);
15880 }
15881
15882 static void
15883 on_layout_manager_changed (ClutterLayoutManager *manager,
15884                            ClutterActor         *self)
15885 {
15886   clutter_actor_queue_relayout (self);
15887 }
15888
15889 /**
15890  * clutter_actor_set_layout_manager:
15891  * @self: a #ClutterActor
15892  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15893  *
15894  * Sets the #ClutterLayoutManager delegate object that will be used to
15895  * lay out the children of @self.
15896  *
15897  * The #ClutterActor will take a reference on the passed @manager which
15898  * will be released either when the layout manager is removed, or when
15899  * the actor is destroyed.
15900  *
15901  * Since: 1.10
15902  */
15903 void
15904 clutter_actor_set_layout_manager (ClutterActor         *self,
15905                                   ClutterLayoutManager *manager)
15906 {
15907   ClutterActorPrivate *priv;
15908
15909   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15910   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15911
15912   priv = self->priv;
15913
15914   if (priv->layout_manager != NULL)
15915     {
15916       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15917                                             G_CALLBACK (on_layout_manager_changed),
15918                                             self);
15919       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15920       g_object_unref (priv->layout_manager);
15921     }
15922
15923   priv->layout_manager = manager;
15924
15925   if (priv->layout_manager != NULL)
15926     {
15927       g_object_ref_sink (priv->layout_manager);
15928       clutter_layout_manager_set_container (priv->layout_manager,
15929                                             CLUTTER_CONTAINER (self));
15930       g_signal_connect (priv->layout_manager, "layout-changed",
15931                         G_CALLBACK (on_layout_manager_changed),
15932                         self);
15933     }
15934
15935   clutter_actor_queue_relayout (self);
15936
15937   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15938 }
15939
15940 /**
15941  * clutter_actor_get_layout_manager:
15942  * @self: a #ClutterActor
15943  *
15944  * Retrieves the #ClutterLayoutManager used by @self.
15945  *
15946  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15947  *   or %NULL
15948  *
15949  * Since: 1.10
15950  */
15951 ClutterLayoutManager *
15952 clutter_actor_get_layout_manager (ClutterActor *self)
15953 {
15954   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15955
15956   return self->priv->layout_manager;
15957 }
15958
15959 static const ClutterLayoutInfo default_layout_info = {
15960   0.f,                          /* fixed-x */
15961   0.f,                          /* fixed-y */
15962   { 0, 0, 0, 0 },               /* margin */
15963   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15964   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15965   0.f, 0.f,                     /* min_width, natural_width */
15966   0.f, 0.f,                     /* natual_width, natural_height */
15967 };
15968
15969 static void
15970 layout_info_free (gpointer data)
15971 {
15972   if (G_LIKELY (data != NULL))
15973     g_slice_free (ClutterLayoutInfo, data);
15974 }
15975
15976 /*< private >
15977  * _clutter_actor_get_layout_info:
15978  * @self: a #ClutterActor
15979  *
15980  * Retrieves a pointer to the ClutterLayoutInfo structure.
15981  *
15982  * If the actor does not have a ClutterLayoutInfo associated to it, one
15983  * will be created and initialized to the default values.
15984  *
15985  * This function should be used for setters.
15986  *
15987  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15988  * instead.
15989  *
15990  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15991  */
15992 ClutterLayoutInfo *
15993 _clutter_actor_get_layout_info (ClutterActor *self)
15994 {
15995   ClutterLayoutInfo *retval;
15996
15997   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15998   if (retval == NULL)
15999     {
16000       retval = g_slice_new (ClutterLayoutInfo);
16001
16002       *retval = default_layout_info;
16003
16004       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16005                                retval,
16006                                layout_info_free);
16007     }
16008
16009   return retval;
16010 }
16011
16012 /*< private >
16013  * _clutter_actor_get_layout_info_or_defaults:
16014  * @self: a #ClutterActor
16015  *
16016  * Retrieves the ClutterLayoutInfo structure associated to an actor.
16017  *
16018  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16019  * then the default structure will be returned.
16020  *
16021  * This function should only be used for getters.
16022  *
16023  * Return value: a const pointer to the ClutterLayoutInfo structure
16024  */
16025 const ClutterLayoutInfo *
16026 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16027 {
16028   const ClutterLayoutInfo *info;
16029
16030   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16031   if (info == NULL)
16032     return &default_layout_info;
16033
16034   return info;
16035 }
16036
16037 /**
16038  * clutter_actor_set_x_align:
16039  * @self: a #ClutterActor
16040  * @x_align: the horizontal alignment policy
16041  *
16042  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16043  * actor received extra horizontal space.
16044  *
16045  * See also the #ClutterActor:x-align property.
16046  *
16047  * Since: 1.10
16048  */
16049 void
16050 clutter_actor_set_x_align (ClutterActor      *self,
16051                            ClutterActorAlign  x_align)
16052 {
16053   ClutterLayoutInfo *info;
16054
16055   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16056
16057   info = _clutter_actor_get_layout_info (self);
16058
16059   if (info->x_align != x_align)
16060     {
16061       info->x_align = x_align;
16062
16063       clutter_actor_queue_relayout (self);
16064
16065       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16066     }
16067 }
16068
16069 /**
16070  * clutter_actor_get_x_align:
16071  * @self: a #ClutterActor
16072  *
16073  * Retrieves the horizontal alignment policy set using
16074  * clutter_actor_set_x_align().
16075  *
16076  * Return value: the horizontal alignment policy.
16077  *
16078  * Since: 1.10
16079  */
16080 ClutterActorAlign
16081 clutter_actor_get_x_align (ClutterActor *self)
16082 {
16083   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16084
16085   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16086 }
16087
16088 /**
16089  * clutter_actor_set_y_align:
16090  * @self: a #ClutterActor
16091  * @y_align: the vertical alignment policy
16092  *
16093  * Sets the vertical alignment policy of a #ClutterActor, in case the
16094  * actor received extra vertical space.
16095  *
16096  * See also the #ClutterActor:y-align property.
16097  *
16098  * Since: 1.10
16099  */
16100 void
16101 clutter_actor_set_y_align (ClutterActor      *self,
16102                            ClutterActorAlign  y_align)
16103 {
16104   ClutterLayoutInfo *info;
16105
16106   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16107
16108   info = _clutter_actor_get_layout_info (self);
16109
16110   if (info->y_align != y_align)
16111     {
16112       info->y_align = y_align;
16113
16114       clutter_actor_queue_relayout (self);
16115
16116       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16117     }
16118 }
16119
16120 /**
16121  * clutter_actor_get_y_align:
16122  * @self: a #ClutterActor
16123  *
16124  * Retrieves the vertical alignment policy set using
16125  * clutter_actor_set_y_align().
16126  *
16127  * Return value: the vertical alignment policy.
16128  *
16129  * Since: 1.10
16130  */
16131 ClutterActorAlign
16132 clutter_actor_get_y_align (ClutterActor *self)
16133 {
16134   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16135
16136   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16137 }
16138
16139
16140 /**
16141  * clutter_margin_new:
16142  *
16143  * Creates a new #ClutterMargin.
16144  *
16145  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16146  *   clutter_margin_free() to free the resources associated with it when
16147  *   done.
16148  *
16149  * Since: 1.10
16150  */
16151 ClutterMargin *
16152 clutter_margin_new (void)
16153 {
16154   return g_slice_new0 (ClutterMargin);
16155 }
16156
16157 /**
16158  * clutter_margin_copy:
16159  * @margin_: a #ClutterMargin
16160  *
16161  * Creates a new #ClutterMargin and copies the contents of @margin_ into
16162  * the newly created structure.
16163  *
16164  * Return value: (transfer full): a copy of the #ClutterMargin.
16165  *
16166  * Since: 1.10
16167  */
16168 ClutterMargin *
16169 clutter_margin_copy (const ClutterMargin *margin_)
16170 {
16171   if (G_LIKELY (margin_ != NULL))
16172     return g_slice_dup (ClutterMargin, margin_);
16173
16174   return NULL;
16175 }
16176
16177 /**
16178  * clutter_margin_free:
16179  * @margin_: a #ClutterMargin
16180  *
16181  * Frees the resources allocated by clutter_margin_new() and
16182  * clutter_margin_copy().
16183  *
16184  * Since: 1.10
16185  */
16186 void
16187 clutter_margin_free (ClutterMargin *margin_)
16188 {
16189   if (G_LIKELY (margin_ != NULL))
16190     g_slice_free (ClutterMargin, margin_);
16191 }
16192
16193 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16194                      clutter_margin_copy,
16195                      clutter_margin_free)
16196
16197 /**
16198  * clutter_actor_set_margin:
16199  * @self: a #ClutterActor
16200  * @margin: a #ClutterMargin
16201  *
16202  * Sets all the components of the margin of a #ClutterActor.
16203  *
16204  * Since: 1.10
16205  */
16206 void
16207 clutter_actor_set_margin (ClutterActor        *self,
16208                           const ClutterMargin *margin)
16209 {
16210   ClutterLayoutInfo *info;
16211   gboolean changed;
16212   GObject *obj;
16213
16214   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16215   g_return_if_fail (margin != NULL);
16216
16217   obj = G_OBJECT (self);
16218   changed = FALSE;
16219
16220   g_object_freeze_notify (obj);
16221
16222   info = _clutter_actor_get_layout_info (self);
16223
16224   if (info->margin.top != margin->top)
16225     {
16226       info->margin.top = margin->top;
16227       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16228       changed = TRUE;
16229     }
16230
16231   if (info->margin.right != margin->right)
16232     {
16233       info->margin.right = margin->right;
16234       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16235       changed = TRUE;
16236     }
16237
16238   if (info->margin.bottom != margin->bottom)
16239     {
16240       info->margin.bottom = margin->bottom;
16241       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16242       changed = TRUE;
16243     }
16244
16245   if (info->margin.left != margin->left)
16246     {
16247       info->margin.left = margin->left;
16248       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16249       changed = TRUE;
16250     }
16251
16252   if (changed)
16253     clutter_actor_queue_relayout (self);
16254
16255   g_object_thaw_notify (obj);
16256 }
16257
16258 /**
16259  * clutter_actor_get_margin:
16260  * @self: a #ClutterActor
16261  * @margin: (out caller-allocates): return location for a #ClutterMargin
16262  *
16263  * Retrieves all the components of the margin of a #ClutterActor.
16264  *
16265  * Since: 1.10
16266  */
16267 void
16268 clutter_actor_get_margin (ClutterActor  *self,
16269                           ClutterMargin *margin)
16270 {
16271   const ClutterLayoutInfo *info;
16272
16273   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16274   g_return_if_fail (margin != NULL);
16275
16276   info = _clutter_actor_get_layout_info_or_defaults (self);
16277
16278   *margin = info->margin;
16279 }
16280
16281 /**
16282  * clutter_actor_set_margin_top:
16283  * @self: a #ClutterActor
16284  * @margin: the top margin
16285  *
16286  * Sets the margin from the top of a #ClutterActor.
16287  *
16288  * Since: 1.10
16289  */
16290 void
16291 clutter_actor_set_margin_top (ClutterActor *self,
16292                               gfloat        margin)
16293 {
16294   ClutterLayoutInfo *info;
16295
16296   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16297   g_return_if_fail (margin >= 0.f);
16298
16299   info = _clutter_actor_get_layout_info (self);
16300
16301   if (info->margin.top == margin)
16302     return;
16303
16304   info->margin.top = margin;
16305
16306   clutter_actor_queue_relayout (self);
16307
16308   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16309 }
16310
16311 /**
16312  * clutter_actor_get_margin_top:
16313  * @self: a #ClutterActor
16314  *
16315  * Retrieves the top margin of a #ClutterActor.
16316  *
16317  * Return value: the top margin
16318  *
16319  * Since: 1.10
16320  */
16321 gfloat
16322 clutter_actor_get_margin_top (ClutterActor *self)
16323 {
16324   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16325
16326   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16327 }
16328
16329 /**
16330  * clutter_actor_set_margin_bottom:
16331  * @self: a #ClutterActor
16332  * @margin: the bottom margin
16333  *
16334  * Sets the margin from the bottom of a #ClutterActor.
16335  *
16336  * Since: 1.10
16337  */
16338 void
16339 clutter_actor_set_margin_bottom (ClutterActor *self,
16340                                  gfloat        margin)
16341 {
16342   ClutterLayoutInfo *info;
16343
16344   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16345   g_return_if_fail (margin >= 0.f);
16346
16347   info = _clutter_actor_get_layout_info (self);
16348
16349   if (info->margin.bottom == margin)
16350     return;
16351
16352   info->margin.bottom = margin;
16353
16354   clutter_actor_queue_relayout (self);
16355
16356   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16357 }
16358
16359 /**
16360  * clutter_actor_get_margin_bottom:
16361  * @self: a #ClutterActor
16362  *
16363  * Retrieves the bottom margin of a #ClutterActor.
16364  *
16365  * Return value: the bottom margin
16366  *
16367  * Since: 1.10
16368  */
16369 gfloat
16370 clutter_actor_get_margin_bottom (ClutterActor *self)
16371 {
16372   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16373
16374   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16375 }
16376
16377 /**
16378  * clutter_actor_set_margin_left:
16379  * @self: a #ClutterActor
16380  * @margin: the left margin
16381  *
16382  * Sets the margin from the left of a #ClutterActor.
16383  *
16384  * Since: 1.10
16385  */
16386 void
16387 clutter_actor_set_margin_left (ClutterActor *self,
16388                                gfloat        margin)
16389 {
16390   ClutterLayoutInfo *info;
16391
16392   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16393   g_return_if_fail (margin >= 0.f);
16394
16395   info = _clutter_actor_get_layout_info (self);
16396
16397   if (info->margin.left == margin)
16398     return;
16399
16400   info->margin.left = margin;
16401
16402   clutter_actor_queue_relayout (self);
16403
16404   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16405 }
16406
16407 /**
16408  * clutter_actor_get_margin_left:
16409  * @self: a #ClutterActor
16410  *
16411  * Retrieves the left margin of a #ClutterActor.
16412  *
16413  * Return value: the left margin
16414  *
16415  * Since: 1.10
16416  */
16417 gfloat
16418 clutter_actor_get_margin_left (ClutterActor *self)
16419 {
16420   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16421
16422   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16423 }
16424
16425 /**
16426  * clutter_actor_set_margin_right:
16427  * @self: a #ClutterActor
16428  * @margin: the right margin
16429  *
16430  * Sets the margin from the right of a #ClutterActor.
16431  *
16432  * Since: 1.10
16433  */
16434 void
16435 clutter_actor_set_margin_right (ClutterActor *self,
16436                                 gfloat        margin)
16437 {
16438   ClutterLayoutInfo *info;
16439
16440   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16441   g_return_if_fail (margin >= 0.f);
16442
16443   info = _clutter_actor_get_layout_info (self);
16444
16445   if (info->margin.right == margin)
16446     return;
16447
16448   info->margin.right = margin;
16449
16450   clutter_actor_queue_relayout (self);
16451
16452   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16453 }
16454
16455 /**
16456  * clutter_actor_get_margin_right:
16457  * @self: a #ClutterActor
16458  *
16459  * Retrieves the right margin of a #ClutterActor.
16460  *
16461  * Return value: the right margin
16462  *
16463  * Since: 1.10
16464  */
16465 gfloat
16466 clutter_actor_get_margin_right (ClutterActor *self)
16467 {
16468   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16469
16470   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16471 }
16472
16473 static inline void
16474 clutter_actor_set_background_color_internal (ClutterActor *self,
16475                                              const ClutterColor *color)
16476 {
16477   ClutterActorPrivate *priv = self->priv;
16478   GObject *obj;
16479
16480   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16481     return;
16482
16483   obj = G_OBJECT (self);
16484
16485   priv->bg_color = *color;
16486   priv->bg_color_set = TRUE;
16487
16488   clutter_actor_queue_redraw (self);
16489
16490   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16491   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16492 }
16493
16494 /**
16495  * clutter_actor_set_background_color:
16496  * @self: a #ClutterActor
16497  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16498  *  set color
16499  *
16500  * Sets the background color of a #ClutterActor.
16501  *
16502  * The background color will be used to cover the whole allocation of the
16503  * actor. The default background color of an actor is transparent.
16504  *
16505  * To check whether an actor has a background color, you can use the
16506  * #ClutterActor:background-color-set actor property.
16507  *
16508  * The #ClutterActor:background-color property is animatable.
16509  *
16510  * Since: 1.10
16511  */
16512 void
16513 clutter_actor_set_background_color (ClutterActor       *self,
16514                                     const ClutterColor *color)
16515 {
16516   ClutterActorPrivate *priv;
16517   GObject *obj;
16518   GParamSpec *bg_color_pspec;
16519
16520   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16521
16522   obj = G_OBJECT (self);
16523
16524   priv = self->priv;
16525
16526   if (color == NULL)
16527     {
16528       priv->bg_color_set = FALSE;
16529       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16530       clutter_actor_queue_redraw (self);
16531       return;
16532     }
16533
16534   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16535   if (clutter_actor_get_easing_duration (self) != 0)
16536     {
16537       ClutterTransition *transition;
16538
16539       transition = _clutter_actor_get_transition (self, bg_color_pspec);
16540       if (transition == NULL)
16541         {
16542           transition = _clutter_actor_create_transition (self, bg_color_pspec,
16543                                                          &priv->bg_color,
16544                                                          color);
16545           clutter_timeline_start (CLUTTER_TIMELINE (transition));
16546         }
16547       else
16548         _clutter_actor_update_transition (self, bg_color_pspec, color);
16549
16550       clutter_actor_queue_redraw (self);
16551     }
16552   else
16553     clutter_actor_set_background_color_internal (self, color);
16554 }
16555
16556 /**
16557  * clutter_actor_get_background_color:
16558  * @self: a #ClutterActor
16559  * @color: (out caller-allocates): return location for a #ClutterColor
16560  *
16561  * Retrieves the color set using clutter_actor_set_background_color().
16562  *
16563  * Since: 1.10
16564  */
16565 void
16566 clutter_actor_get_background_color (ClutterActor *self,
16567                                     ClutterColor *color)
16568 {
16569   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16570   g_return_if_fail (color != NULL);
16571
16572   *color = self->priv->bg_color;
16573 }
16574
16575 /**
16576  * clutter_actor_get_previous_sibling:
16577  * @self: a #ClutterActor
16578  *
16579  * Retrieves the sibling of @self that comes before it in the list
16580  * of children of @self's parent.
16581  *
16582  * The returned pointer is only valid until the scene graph changes; it
16583  * is not safe to modify the list of children of @self while iterating
16584  * it.
16585  *
16586  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16587  *
16588  * Since: 1.10
16589  */
16590 ClutterActor *
16591 clutter_actor_get_previous_sibling (ClutterActor *self)
16592 {
16593   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16594
16595   return self->priv->prev_sibling;
16596 }
16597
16598 /**
16599  * clutter_actor_get_next_sibling:
16600  * @self: a #ClutterActor
16601  *
16602  * Retrieves the sibling of @self that comes after it in the list
16603  * of children of @self's parent.
16604  *
16605  * The returned pointer is only valid until the scene graph changes; it
16606  * is not safe to modify the list of children of @self while iterating
16607  * it.
16608  *
16609  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16610  *
16611  * Since: 1.10
16612  */
16613 ClutterActor *
16614 clutter_actor_get_next_sibling (ClutterActor *self)
16615 {
16616   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16617
16618   return self->priv->next_sibling;
16619 }
16620
16621 /**
16622  * clutter_actor_get_first_child:
16623  * @self: a #ClutterActor
16624  *
16625  * Retrieves the first child of @self.
16626  *
16627  * The returned pointer is only valid until the scene graph changes; it
16628  * is not safe to modify the list of children of @self while iterating
16629  * it.
16630  *
16631  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16632  *
16633  * Since: 1.10
16634  */
16635 ClutterActor *
16636 clutter_actor_get_first_child (ClutterActor *self)
16637 {
16638   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16639
16640   return self->priv->first_child;
16641 }
16642
16643 /**
16644  * clutter_actor_get_last_child:
16645  * @self: a #ClutterActor
16646  *
16647  * Retrieves the last child of @self.
16648  *
16649  * The returned pointer is only valid until the scene graph changes; it
16650  * is not safe to modify the list of children of @self while iterating
16651  * it.
16652  *
16653  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16654  *
16655  * Since: 1.10
16656  */
16657 ClutterActor *
16658 clutter_actor_get_last_child (ClutterActor *self)
16659 {
16660   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16661
16662   return self->priv->last_child;
16663 }
16664
16665 /* easy way to have properly named fields instead of the dummy ones
16666  * we use in the public structure
16667  */
16668 typedef struct _RealActorIter
16669 {
16670   ClutterActor *root;           /* dummy1 */
16671   ClutterActor *current;        /* dummy2 */
16672   gpointer padding_1;           /* dummy3 */
16673   gint age;                     /* dummy4 */
16674   gpointer padding_2;           /* dummy5 */
16675 } RealActorIter;
16676
16677 /**
16678  * clutter_actor_iter_init:
16679  * @iter: a #ClutterActorIter
16680  * @root: a #ClutterActor
16681  *
16682  * Initializes a #ClutterActorIter, which can then be used to iterate
16683  * efficiently over a section of the scene graph, and associates it
16684  * with @root.
16685  *
16686  * Modifying the scene graph section that contains @root will invalidate
16687  * the iterator.
16688  *
16689  * |[
16690  *   ClutterActorIter iter;
16691  *   ClutterActor *child;
16692  *
16693  *   clutter_actor_iter_init (&iter, container);
16694  *   while (clutter_actor_iter_next (&iter, &child))
16695  *     {
16696  *       /&ast; do something with child &ast;/
16697  *     }
16698  * ]|
16699  *
16700  * Since: 1.10
16701  */
16702 void
16703 clutter_actor_iter_init (ClutterActorIter *iter,
16704                          ClutterActor     *root)
16705 {
16706   RealActorIter *ri = (RealActorIter *) iter;
16707
16708   g_return_if_fail (iter != NULL);
16709   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16710
16711   ri->root = root;
16712   ri->current = NULL;
16713   ri->age = root->priv->age;
16714 }
16715
16716 /**
16717  * clutter_actor_iter_next:
16718  * @iter: a #ClutterActorIter
16719  * @child: (out): return location for a #ClutterActor
16720  *
16721  * Advances the @iter and retrieves the next child of the root #ClutterActor
16722  * that was used to initialize the #ClutterActorIterator.
16723  *
16724  * If the iterator can advance, this function returns %TRUE and sets the
16725  * @child argument.
16726  *
16727  * If the iterator cannot advance, this function returns %FALSE, and
16728  * the contents of @child are undefined.
16729  *
16730  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16731  *
16732  * Since: 1.10
16733  */
16734 gboolean
16735 clutter_actor_iter_next (ClutterActorIter  *iter,
16736                          ClutterActor     **child)
16737 {
16738   RealActorIter *ri = (RealActorIter *) iter;
16739
16740   g_return_val_if_fail (iter != NULL, FALSE);
16741   g_return_val_if_fail (ri->root != NULL, FALSE);
16742 #ifndef G_DISABLE_ASSERT
16743   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16744 #endif
16745
16746   if (ri->current == NULL)
16747     ri->current = ri->root->priv->first_child;
16748   else
16749     ri->current = ri->current->priv->next_sibling;
16750
16751   if (child != NULL)
16752     *child = ri->current;
16753
16754   return ri->current != NULL;
16755 }
16756
16757 /**
16758  * clutter_actor_iter_prev:
16759  * @iter: a #ClutterActorIter
16760  * @child: (out): return location for a #ClutterActor
16761  *
16762  * Advances the @iter and retrieves the previous child of the root
16763  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16764  *
16765  * If the iterator can advance, this function returns %TRUE and sets the
16766  * @child argument.
16767  *
16768  * If the iterator cannot advance, this function returns %FALSE, and
16769  * the contents of @child are undefined.
16770  *
16771  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16772  *
16773  * Since: 1.10
16774  */
16775 gboolean
16776 clutter_actor_iter_prev (ClutterActorIter  *iter,
16777                          ClutterActor     **child)
16778 {
16779   RealActorIter *ri = (RealActorIter *) iter;
16780
16781   g_return_val_if_fail (iter != NULL, FALSE);
16782   g_return_val_if_fail (ri->root != NULL, FALSE);
16783 #ifndef G_DISABLE_ASSERT
16784   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16785 #endif
16786
16787   if (ri->current == NULL)
16788     ri->current = ri->root->priv->last_child;
16789   else
16790     ri->current = ri->current->priv->prev_sibling;
16791
16792   if (child != NULL)
16793     *child = ri->current;
16794
16795   return ri->current != NULL;
16796 }
16797
16798 /**
16799  * clutter_actor_iter_remove:
16800  * @iter: a #ClutterActorIter
16801  *
16802  * Safely removes the #ClutterActor currently pointer to by the iterator
16803  * from its parent.
16804  *
16805  * This function can only be called after clutter_actor_iter_next() or
16806  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16807  * than once for the same actor.
16808  *
16809  * This function will call clutter_actor_remove_child() internally.
16810  *
16811  * Since: 1.10
16812  */
16813 void
16814 clutter_actor_iter_remove (ClutterActorIter *iter)
16815 {
16816   RealActorIter *ri = (RealActorIter *) iter;
16817   ClutterActor *cur;
16818
16819   g_return_if_fail (iter != NULL);
16820   g_return_if_fail (ri->root != NULL);
16821 #ifndef G_DISABLE_ASSERT
16822   g_return_if_fail (ri->age == ri->root->priv->age);
16823 #endif
16824   g_return_if_fail (ri->current != NULL);
16825
16826   cur = ri->current;
16827
16828   if (cur != NULL)
16829     {
16830       ri->current = cur->priv->prev_sibling;
16831
16832       clutter_actor_remove_child_internal (ri->root, cur,
16833                                            REMOVE_CHILD_DEFAULT_FLAGS);
16834
16835       ri->age += 1;
16836     }
16837 }
16838
16839 /**
16840  * clutter_actor_iter_destroy:
16841  * @iter: a #ClutterActorIter
16842  *
16843  * Safely destroys the #ClutterActor currently pointer to by the iterator
16844  * from its parent.
16845  *
16846  * This function can only be called after clutter_actor_iter_next() or
16847  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16848  * than once for the same actor.
16849  *
16850  * This function will call clutter_actor_destroy() internally.
16851  *
16852  * Since: 1.10
16853  */
16854 void
16855 clutter_actor_iter_destroy (ClutterActorIter *iter)
16856 {
16857   RealActorIter *ri = (RealActorIter *) iter;
16858   ClutterActor *cur;
16859
16860   g_return_if_fail (iter != NULL);
16861   g_return_if_fail (ri->root != NULL);
16862 #ifndef G_DISABLE_ASSERT
16863   g_return_if_fail (ri->age == ri->root->priv->age);
16864 #endif
16865   g_return_if_fail (ri->current != NULL);
16866
16867   cur = ri->current;
16868
16869   if (cur != NULL)
16870     {
16871       ri->current = cur->priv->prev_sibling;
16872
16873       clutter_actor_destroy (cur);
16874
16875       ri->age += 1;
16876     }
16877 }
16878
16879 static const ClutterAnimationInfo default_animation_info = {
16880   NULL,         /* transitions */
16881   NULL,         /* states */
16882   NULL,         /* cur_state */
16883 };
16884
16885 static void
16886 clutter_animation_info_free (gpointer data)
16887 {
16888   if (data != NULL)
16889     {
16890       ClutterAnimationInfo *info = data;
16891
16892       if (info->transitions != NULL)
16893         g_hash_table_unref (info->transitions);
16894
16895       if (info->states != NULL)
16896         g_array_unref (info->states);
16897
16898       g_slice_free (ClutterAnimationInfo, info);
16899     }
16900 }
16901
16902 const ClutterAnimationInfo *
16903 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16904 {
16905   const ClutterAnimationInfo *res;
16906   GObject *obj = G_OBJECT (self);
16907
16908   res = g_object_get_qdata (obj, quark_actor_animation_info);
16909   if (res != NULL)
16910     return res;
16911
16912   return &default_animation_info;
16913 }
16914
16915 ClutterAnimationInfo *
16916 _clutter_actor_get_animation_info (ClutterActor *self)
16917 {
16918   GObject *obj = G_OBJECT (self);
16919   ClutterAnimationInfo *res;
16920
16921   res = g_object_get_qdata (obj, quark_actor_animation_info);
16922   if (res == NULL)
16923     {
16924       res = g_slice_new (ClutterAnimationInfo);
16925
16926       *res = default_animation_info;
16927
16928       g_object_set_qdata_full (obj, quark_actor_animation_info,
16929                                res,
16930                                clutter_animation_info_free);
16931     }
16932
16933   return res;
16934 }
16935
16936 ClutterTransition *
16937 _clutter_actor_get_transition (ClutterActor *actor,
16938                                GParamSpec   *pspec)
16939 {
16940   const ClutterAnimationInfo *info;
16941
16942   info = _clutter_actor_get_animation_info_or_defaults (actor);
16943
16944   if (info->transitions == NULL)
16945     return NULL;
16946
16947   return g_hash_table_lookup (info->transitions, pspec->name);
16948 }
16949
16950 typedef struct _TransitionClosure
16951 {
16952   ClutterActor *actor;
16953   ClutterTransition *transition;
16954   gchar *name;
16955   gulong completed_id;
16956 } TransitionClosure;
16957
16958 static void
16959 transition_closure_free (gpointer data)
16960 {
16961   if (G_LIKELY (data != NULL))
16962     {
16963       TransitionClosure *clos = data;
16964
16965       g_signal_handler_disconnect (clos->transition, clos->completed_id);
16966       g_free (clos->name);
16967
16968       g_slice_free (TransitionClosure, clos);
16969     }
16970 }
16971
16972 static void
16973 on_transition_completed (ClutterTransition *transition,
16974                          TransitionClosure *clos)
16975 {
16976   ClutterActor *actor = clos->actor;
16977   ClutterAnimationInfo *info;
16978
16979   info = _clutter_actor_get_animation_info (actor);
16980
16981   /* this will take care of cleaning clos for us */
16982   g_hash_table_remove (info->transitions, clos->name);
16983
16984   /* if it's the last transition then we clean up */
16985   if (g_hash_table_size (info->transitions) == 0)
16986     {
16987       g_hash_table_unref (info->transitions);
16988       info->transitions = NULL;
16989
16990       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
16991                     _clutter_actor_get_debug_name (actor));
16992
16993       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
16994     }
16995 }
16996
16997 void
16998 _clutter_actor_update_transition (ClutterActor *actor,
16999                                   GParamSpec   *pspec,
17000                                   ...)
17001 {
17002   TransitionClosure *clos;
17003   ClutterInterval *interval;
17004   const ClutterAnimationInfo *info;
17005   va_list var_args;
17006   GType ptype;
17007   GValue initial = G_VALUE_INIT;
17008   GValue final = G_VALUE_INIT;
17009   char *error = NULL;
17010
17011   info = _clutter_actor_get_animation_info_or_defaults (actor);
17012
17013   if (info->transitions == NULL)
17014     return;
17015
17016   clos = g_hash_table_lookup (info->transitions, pspec->name);
17017   if (clos == NULL)
17018     return;
17019
17020   va_start (var_args, pspec);
17021
17022   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17023
17024   g_value_init (&initial, ptype);
17025   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17026                                         pspec->name,
17027                                         &initial);
17028
17029   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17030   if (error != NULL)
17031     {
17032       g_critical ("%s: %s", G_STRLOC, error);
17033       g_free (error);
17034       goto out;
17035     }
17036
17037   interval = clutter_transition_get_interval (clos->transition);
17038   clutter_interval_set_initial_value (interval, &initial);
17039   clutter_interval_set_final_value (interval, &final);
17040
17041   clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
17042
17043 out:
17044   g_value_unset (&initial);
17045   g_value_unset (&final);
17046
17047   va_end (var_args);
17048 }
17049
17050 /*< private >*
17051  * _clutter_actor_create_transition:
17052  * @actor: a #ClutterActor
17053  * @pspec: the property used for the transition
17054  * @...: initial and final state
17055  *
17056  * Creates a #ClutterTransition for the property represented by @pspec.
17057  *
17058  * Return value: a #ClutterTransition
17059  */
17060 ClutterTransition *
17061 _clutter_actor_create_transition (ClutterActor *actor,
17062                                   GParamSpec   *pspec,
17063                                   ...)
17064 {
17065   ClutterAnimationInfo *info;
17066   ClutterTransition *res = NULL;
17067   gboolean call_restore = FALSE;
17068   TransitionClosure *clos;
17069   va_list var_args;
17070
17071   info = _clutter_actor_get_animation_info (actor);
17072
17073   if (info->states == NULL)
17074     {
17075       clutter_actor_save_easing_state (actor);
17076       call_restore = TRUE;
17077     }
17078
17079   if (info->transitions == NULL)
17080     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17081                                                NULL,
17082                                                transition_closure_free);
17083
17084   va_start (var_args, pspec);
17085
17086   clos = g_hash_table_lookup (info->transitions, pspec->name);
17087   if (clos == NULL)
17088     {
17089       ClutterInterval *interval;
17090       GValue initial = G_VALUE_INIT;
17091       GValue final = G_VALUE_INIT;
17092       GType ptype;
17093       char *error;
17094
17095       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17096
17097       G_VALUE_COLLECT_INIT (&initial, ptype,
17098                             var_args, 0,
17099                             &error);
17100       if (error != NULL)
17101         {
17102           g_critical ("%s: %s", G_STRLOC, error);
17103           g_free (error);
17104           goto out;
17105         }
17106
17107       G_VALUE_COLLECT_INIT (&final, ptype,
17108                             var_args, 0,
17109                             &error);
17110
17111       if (error != NULL)
17112         {
17113           g_critical ("%s: %s", G_STRLOC, error);
17114           g_value_unset (&initial);
17115           g_free (error);
17116           goto out;
17117         }
17118
17119       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17120
17121       g_value_unset (&initial);
17122       g_value_unset (&final);
17123
17124       res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
17125                                              pspec->name);
17126
17127       clutter_transition_set_interval (res, interval);
17128       clutter_transition_set_remove_on_complete (res, TRUE);
17129
17130       clutter_actor_add_transition (actor, pspec->name, res);
17131     }
17132   else
17133     res = clos->transition;
17134
17135 out:
17136   if (call_restore)
17137     clutter_actor_restore_easing_state (actor);
17138
17139   va_end (var_args);
17140
17141   return res;
17142 }
17143
17144 /**
17145  * clutter_actor_add_transition:
17146  * @self: a #ClutterActor
17147  * @name: the name of the transition to add
17148  * @transition: the #ClutterTransition to add
17149  *
17150  * Adds a @transition to the #ClutterActor's list of animations.
17151  *
17152  * The @name string is a per-actor unique identifier of the @transition: only
17153  * one #ClutterTransition can be associated to the specified @name.
17154  *
17155  * The @transition will be given the easing duration, mode, and delay
17156  * associated to the actor's current easing state; it is possible to modify
17157  * these values after calling clutter_actor_add_transition().
17158  *
17159  * This function is usually called implicitly when modifying an animatable
17160  * property.
17161  *
17162  * Since: 1.10
17163  */
17164 void
17165 clutter_actor_add_transition (ClutterActor      *self,
17166                               const char        *name,
17167                               ClutterTransition *transition)
17168 {
17169   ClutterTimeline *timeline;
17170   TransitionClosure *clos;
17171   ClutterAnimationInfo *info;
17172
17173   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17174   g_return_if_fail (name != NULL);
17175   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17176
17177   info = _clutter_actor_get_animation_info (self);
17178
17179   if (info->cur_state == NULL)
17180     {
17181       g_warning ("No easing state is defined for the actor '%s'; you "
17182                  "must call clutter_actor_save_easing_state() before "
17183                  "calling clutter_actor_add_transition().",
17184                  _clutter_actor_get_debug_name (self));
17185       return;
17186     }
17187
17188   if (info->transitions == NULL)
17189     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17190                                                NULL,
17191                                                transition_closure_free);
17192
17193   if (g_hash_table_lookup (info->transitions, name) != NULL)
17194     {
17195       g_warning ("A transition with name '%s' already exists for "
17196                  "the actor '%s'",
17197                  name,
17198                  _clutter_actor_get_debug_name (self));
17199       return;
17200     }
17201
17202   timeline = CLUTTER_TIMELINE (transition);
17203
17204   clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17205   clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17206   clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17207
17208   clos = g_slice_new (TransitionClosure);
17209   clos->actor = self;
17210   clos->transition = transition;
17211   clos->name = g_strdup (name);
17212   clos->completed_id = g_signal_connect (timeline, "completed",
17213                                          G_CALLBACK (on_transition_completed),
17214                                          clos);
17215
17216   g_hash_table_insert (info->transitions, clos->name, clos);
17217 }
17218
17219 /**
17220  * clutter_actor_remove_transition:
17221  * @self: a #ClutterActor
17222  * @name: the name of the transition to remove
17223  *
17224  * Removes the transition stored inside a #ClutterActor using @name
17225  * identifier.
17226  *
17227  * Since: 1.10
17228  */
17229 void
17230 clutter_actor_remove_transition (ClutterActor *self,
17231                                  const char   *name)
17232 {
17233   const ClutterAnimationInfo *info;
17234
17235   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17236   g_return_if_fail (name != NULL);
17237
17238   info = _clutter_actor_get_animation_info_or_defaults (self);
17239
17240   if (info->transitions == NULL)
17241     return;
17242
17243   g_hash_table_remove (info->transitions, name);
17244 }
17245
17246 /**
17247  * clutter_actor_remove_all_transitions:
17248  * @self: a #ClutterActor
17249  *
17250  * Removes all transitions associated to @self.
17251  *
17252  * Since: 1.10
17253  */
17254 void
17255 clutter_actor_remove_all_transitions (ClutterActor *self)
17256 {
17257   const ClutterAnimationInfo *info;
17258
17259   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17260
17261   info = _clutter_actor_get_animation_info_or_defaults (self);
17262   if (info->transitions == NULL)
17263     return;
17264
17265   g_hash_table_remove_all (info->transitions);
17266 }
17267
17268 /**
17269  * clutter_actor_set_easing_duration:
17270  * @self: a #ClutterActor
17271  * @msecs: the duration of the easing, or %NULL
17272  *
17273  * Sets the duration of the tweening for animatable properties
17274  * of @self for the current easing state.
17275  *
17276  * Since: 1.10
17277  */
17278 void
17279 clutter_actor_set_easing_duration (ClutterActor *self,
17280                                    guint         msecs)
17281 {
17282   ClutterAnimationInfo *info;
17283
17284   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17285
17286   info = _clutter_actor_get_animation_info (self);
17287
17288   if (info->cur_state == NULL)
17289     {
17290       g_warning ("You must call clutter_actor_save_easing_state() prior "
17291                  "to calling clutter_actor_set_easing_duration().");
17292       return;
17293     }
17294
17295   if (info->cur_state->easing_duration != msecs)
17296     info->cur_state->easing_duration = msecs;
17297 }
17298
17299 /**
17300  * clutter_actor_get_easing_duration:
17301  * @self: a #ClutterActor
17302  *
17303  * Retrieves the duration of the tweening for animatable
17304  * properties of @self for the current easing state.
17305  *
17306  * Return value: the duration of the tweening, in milliseconds
17307  *
17308  * Since: 1.10
17309  */
17310 guint
17311 clutter_actor_get_easing_duration (ClutterActor *self)
17312 {
17313   const ClutterAnimationInfo *info;
17314
17315   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17316
17317   info = _clutter_actor_get_animation_info_or_defaults (self);
17318
17319   if (info->cur_state != NULL)
17320     return info->cur_state->easing_duration;
17321
17322   return 0;
17323 }
17324
17325 /**
17326  * clutter_actor_set_easing_mode:
17327  * @self: a #ClutterActor
17328  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17329  *
17330  * Sets the easing mode for the tweening of animatable properties
17331  * of @self.
17332  *
17333  * Since: 1.10
17334  */
17335 void
17336 clutter_actor_set_easing_mode (ClutterActor         *self,
17337                                ClutterAnimationMode  mode)
17338 {
17339   ClutterAnimationInfo *info;
17340
17341   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17342   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17343   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17344
17345   info = _clutter_actor_get_animation_info (self);
17346
17347   if (info->cur_state == NULL)
17348     {
17349       g_warning ("You must call clutter_actor_save_easing_state() prior "
17350                  "to calling clutter_actor_set_easing_mode().");
17351       return;
17352     }
17353
17354   if (info->cur_state->easing_mode != mode)
17355     info->cur_state->easing_mode = mode;
17356 }
17357
17358 /**
17359  * clutter_actor_get_easing_mode:
17360  * @self: a #ClutterActor
17361  *
17362  * Retrieves the easing mode for the tweening of animatable properties
17363  * of @self for the current easing state.
17364  *
17365  * Return value: an easing mode
17366  *
17367  * Since: 1.10
17368  */
17369 ClutterAnimationMode
17370 clutter_actor_get_easing_mode (ClutterActor *self)
17371 {
17372   const ClutterAnimationInfo *info;
17373
17374   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17375
17376   info = _clutter_actor_get_animation_info_or_defaults (self);
17377
17378   if (info->cur_state != NULL)
17379     return info->cur_state->easing_mode;
17380
17381   return CLUTTER_EASE_OUT_CUBIC;
17382 }
17383
17384 /**
17385  * clutter_actor_set_easing_delay:
17386  * @self: a #ClutterActor
17387  * @msecs: the delay before the start of the tweening, in milliseconds
17388  *
17389  * Sets the delay that should be applied before tweening animatable
17390  * properties.
17391  *
17392  * Since: 1.10
17393  */
17394 void
17395 clutter_actor_set_easing_delay (ClutterActor *self,
17396                                 guint         msecs)
17397 {
17398   ClutterAnimationInfo *info;
17399
17400   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17401
17402   info = _clutter_actor_get_animation_info (self);
17403
17404   if (info->cur_state == NULL)
17405     {
17406       g_warning ("You must call clutter_actor_save_easing_state() prior "
17407                  "to calling clutter_actor_set_easing_delay().");
17408       return;
17409     }
17410
17411   if (info->cur_state->easing_delay != msecs)
17412     info->cur_state->easing_delay = msecs;
17413 }
17414
17415 /**
17416  * clutter_actor_get_easing_delay:
17417  * @self: a #ClutterActor
17418  *
17419  * Retrieves the delay that should be applied when tweening animatable
17420  * properties.
17421  *
17422  * Return value: a delay, in milliseconds
17423  *
17424  * Since: 1.10
17425  */
17426 guint
17427 clutter_actor_get_easing_delay (ClutterActor *self)
17428 {
17429   const ClutterAnimationInfo *info;
17430
17431   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17432
17433   info = _clutter_actor_get_animation_info_or_defaults (self);
17434
17435   if (info->cur_state != NULL)
17436     return info->cur_state->easing_delay;
17437
17438   return 0;
17439 }
17440
17441 /**
17442  * clutter_actor_get_transition:
17443  * @self: a #ClutterActor
17444  * @name: the name of the transition
17445  *
17446  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17447  * transition @name.
17448  *
17449  * Transitions created for animatable properties use the name of the
17450  * property itself, for instance the code below:
17451  *
17452  * |[
17453  *   clutter_actor_set_easing_duration (actor, 1000);
17454  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17455  *
17456  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17457  *   g_signal_connect (transition, "completed",
17458  *                     G_CALLBACK (on_transition_complete),
17459  *                     actor);
17460  * ]|
17461  *
17462  * will call the <function>on_transition_complete</function> callback when
17463  * the transition is complete.
17464  *
17465  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17466  *   was found to match the passed name; the returned instance is owned
17467  *   by Clutter and it should not be freed
17468  *
17469  * Since: 1.10
17470  */
17471 ClutterTransition *
17472 clutter_actor_get_transition (ClutterActor *self,
17473                               const char   *name)
17474 {
17475   TransitionClosure *clos;
17476   const ClutterAnimationInfo *info;
17477
17478   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17479   g_return_val_if_fail (name != NULL, NULL);
17480
17481   info = _clutter_actor_get_animation_info_or_defaults (self);
17482
17483   if (info->transitions == NULL)
17484     return NULL;
17485
17486   clos = g_hash_table_lookup (info->transitions, name);
17487   if (clos == NULL)
17488     return NULL;
17489
17490   return clos->transition;
17491 }
17492
17493 /**
17494  * clutter_actor_save_easing_state:
17495  * @self: a #ClutterActor
17496  *
17497  * Saves the current easing state for animatable properties, and creates
17498  * a new state with the default values for easing mode and duration.
17499  *
17500  * Since: 1.10
17501  */
17502 void
17503 clutter_actor_save_easing_state (ClutterActor *self)
17504 {
17505   ClutterAnimationInfo *info;
17506   AState new_state;
17507
17508   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17509
17510   info = _clutter_actor_get_animation_info (self);
17511
17512   if (info->states == NULL)
17513     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17514
17515   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17516   new_state.easing_duration = 250;
17517   new_state.easing_delay = 0;
17518
17519   g_array_append_val (info->states, new_state);
17520
17521   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17522 }
17523
17524 /**
17525  * clutter_actor_restore_easing_state:
17526  * @self: a #ClutterActor
17527  *
17528  * Restores the easing state as it was prior to a call to
17529  * clutter_actor_save_easing_state().
17530  *
17531  * Since: 1.10
17532  */
17533 void
17534 clutter_actor_restore_easing_state (ClutterActor *self)
17535 {
17536   ClutterAnimationInfo *info;
17537
17538   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17539
17540   info = _clutter_actor_get_animation_info (self);
17541
17542   if (info->states == NULL)
17543     {
17544       g_critical ("The function clutter_actor_restore_easing_state() has "
17545                   "called without a previous call to "
17546                   "clutter_actor_save_easing_state().");
17547       return;
17548     }
17549
17550   g_array_remove_index (info->states, info->states->len - 1);
17551
17552   if (info->states->len > 0)
17553     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17554   else
17555     {
17556       g_array_unref (info->states);
17557       info->states = NULL;
17558     }
17559 }
17560
17561 /**
17562  * clutter_actor_set_content:
17563  * @self: a #ClutterActor
17564  * @content: (allow-none): a #ClutterContent, or %NULL
17565  *
17566  * Sets the contents of a #ClutterActor.
17567  *
17568  * Since: 1.10
17569  */
17570 void
17571 clutter_actor_set_content (ClutterActor   *self,
17572                            ClutterContent *content)
17573 {
17574   ClutterActorPrivate *priv;
17575
17576   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17577   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17578
17579   priv = self->priv;
17580
17581   if (priv->content != NULL)
17582     {
17583       _clutter_content_detached (priv->content, self);
17584       g_object_unref (priv->content);
17585     }
17586
17587   priv->content = content;
17588
17589   if (priv->content != NULL)
17590     {
17591       g_object_ref (priv->content);
17592       _clutter_content_attached (priv->content, self);
17593     }
17594
17595   /* given that the content is always painted within the allocation,
17596    * we only need to queue a redraw here
17597    */
17598   clutter_actor_queue_redraw (self);
17599
17600   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17601
17602   /* if the content gravity is not resize-fill, and the new content has a
17603    * different preferred size than the previous one, then the content box
17604    * may have been changed. since we compute that lazily, we just notify
17605    * here, and let whomever watches :content-box do whatever they need to
17606    * do.
17607    */
17608   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17609     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17610 }
17611
17612 /**
17613  * clutter_actor_get_content:
17614  * @self: a #ClutterActor
17615  *
17616  * Retrieves the contents of @self.
17617  *
17618  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17619  *   or %NULL if none was set
17620  *
17621  * Since: 1.10
17622  */
17623 ClutterContent *
17624 clutter_actor_get_content (ClutterActor *self)
17625 {
17626   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17627
17628   return self->priv->content;
17629 }
17630
17631 /**
17632  * clutter_actor_set_content_gravity:
17633  * @self: a #ClutterActor
17634  * @gravity: the #ClutterContentGravity
17635  *
17636  * Sets the gravity of the #ClutterContent used by @self.
17637  *
17638  * See the description of the #ClutterActor:content-gravity property for
17639  * more information.
17640  *
17641  * Since: 1.10
17642  */
17643 void
17644 clutter_actor_set_content_gravity (ClutterActor *self,
17645                                    ClutterContentGravity  gravity)
17646 {
17647   ClutterActorPrivate *priv;
17648
17649   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17650
17651   priv = self->priv;
17652
17653   if (priv->content_gravity == gravity)
17654     return;
17655
17656   priv->content_gravity = gravity;
17657
17658   clutter_actor_queue_redraw (self);
17659
17660   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17661   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17662 }
17663
17664 /**
17665  * clutter_actor_get_content_gravity:
17666  * @self: a #ClutterActor
17667  *
17668  * Retrieves the content gravity as set using
17669  * clutter_actor_get_content_gravity().
17670  *
17671  * Return value: the content gravity
17672  *
17673  * Since: 1.10
17674  */
17675 ClutterContentGravity
17676 clutter_actor_get_content_gravity (ClutterActor *self)
17677 {
17678   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17679                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17680
17681   return self->priv->content_gravity;
17682 }
17683
17684 /**
17685  * clutter_actor_get_content_box:
17686  * @self: a #ClutterActor
17687  * @box: (out caller-allocates): the return location for the bounding
17688  *   box for the #ClutterContent
17689  *
17690  * Retrieves the bounding box for the #ClutterContent of @self.
17691  *
17692  * The bounding box is relative to the actor's allocation.
17693  *
17694  * If no #ClutterContent is set for @self, or if @self has not been
17695  * allocated yet, then the result is undefined.
17696  *
17697  * The content box is guaranteed to be, at most, as big as the allocation
17698  * of the #ClutterActor.
17699  *
17700  * If the #ClutterContent used by the actor has a preferred size, then
17701  * it is possible to modify the content box by using the
17702  * #ClutterActor:content-gravity property.
17703  *
17704  * Since: 1.10
17705  */
17706 void
17707 clutter_actor_get_content_box (ClutterActor    *self,
17708                                ClutterActorBox *box)
17709 {
17710   ClutterActorPrivate *priv;
17711   gfloat content_w, content_h;
17712   gfloat alloc_w, alloc_h;
17713
17714   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17715   g_return_if_fail (box != NULL);
17716
17717   priv = self->priv;
17718
17719   box->x1 = 0.f;
17720   box->y1 = 0.f;
17721   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17722   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17723
17724   if (priv->content == NULL)
17725     return;
17726
17727   /* no need to do any more work */
17728   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17729     return;
17730
17731   /* if the content does not have a preferred size then there is
17732    * no point in computing the content box
17733    */
17734   if (!clutter_content_get_preferred_size (priv->content,
17735                                            &content_w,
17736                                            &content_h))
17737     return;
17738
17739   alloc_w = box->x2;
17740   alloc_h = box->y2;
17741
17742   switch (priv->content_gravity)
17743     {
17744     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17745       box->x2 = box->x1 + MIN (content_w, alloc_w);
17746       box->y2 = box->y1 + MIN (content_h, alloc_h);
17747       break;
17748
17749     case CLUTTER_CONTENT_GRAVITY_TOP:
17750       if (alloc_w > content_w)
17751         {
17752           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17753           box->x2 = box->x1 + content_w;
17754         }
17755       box->y2 = box->y1 + MIN (content_h, alloc_h);
17756       break;
17757
17758     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17759       if (alloc_w > content_w)
17760         {
17761           box->x1 += (alloc_w - content_w);
17762           box->x2 = box->x1 + content_w;
17763         }
17764       box->y2 = box->y1 + MIN (content_h, alloc_h);
17765       break;
17766
17767     case CLUTTER_CONTENT_GRAVITY_LEFT:
17768       box->x2 = box->x1 + MIN (content_w, alloc_w);
17769       if (alloc_h > content_h)
17770         {
17771           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17772           box->y2 = box->y1 + content_h;
17773         }
17774       break;
17775
17776     case CLUTTER_CONTENT_GRAVITY_CENTER:
17777       if (alloc_w > content_w)
17778         {
17779           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17780           box->x2 = box->x1 + content_w;
17781         }
17782       if (alloc_h > content_h)
17783         {
17784           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17785           box->y2 = box->y1 + content_h;
17786         }
17787       break;
17788
17789     case CLUTTER_CONTENT_GRAVITY_RIGHT:
17790       if (alloc_w > content_w)
17791         {
17792           box->x1 += (alloc_w - content_w);
17793           box->x2 = box->x1 + content_w;
17794         }
17795       if (alloc_h > content_h)
17796         {
17797           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17798           box->y2 = box->y1 + content_h;
17799         }
17800       break;
17801
17802     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17803       box->x2 = box->x1 + MIN (content_w, alloc_w);
17804       if (alloc_h > content_h)
17805         {
17806           box->y1 += (alloc_h - content_h);
17807           box->y2 = box->y1 + content_h;
17808         }
17809       break;
17810
17811     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17812       if (alloc_w > content_w)
17813         {
17814           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17815           box->x2 = box->x1 + content_w;
17816         }
17817       if (alloc_h > content_h)
17818         {
17819           box->y1 += (alloc_h - content_h);
17820           box->y2 = box->y1 + content_h;
17821         }
17822       break;
17823
17824     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17825       if (alloc_w > content_w)
17826         {
17827           box->x1 += (alloc_w - content_w);
17828           box->x2 = box->x1 + content_w;
17829         }
17830       if (alloc_h > content_h)
17831         {
17832           box->y1 += (alloc_h - content_h);
17833           box->y2 = box->y1 + content_h;
17834         }
17835       break;
17836
17837     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17838       g_assert_not_reached ();
17839       break;
17840
17841     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17842       {
17843         double r_c = content_w / content_h;
17844         double r_a = alloc_w / alloc_h;
17845
17846         if (r_c >= 1.0)
17847           {
17848             if (r_a >= 1.0)
17849               {
17850                 box->x1 = 0.f;
17851                 box->x2 = alloc_w;
17852
17853                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17854                 box->y2 = box->y1 + (alloc_w * r_c);
17855               }
17856             else
17857               {
17858                 box->y1 = 0.f;
17859                 box->y2 = alloc_h;
17860
17861                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17862                 box->x2 = box->x1 + (alloc_h * r_c);
17863               }
17864           }
17865         else
17866           {
17867             if (r_a >= 1.0)
17868               {
17869                 box->y1 = 0.f;
17870                 box->y2 = alloc_h;
17871
17872                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17873                 box->x2 = box->x1 + (alloc_h * r_c);
17874               }
17875             else
17876               {
17877                 box->x1 = 0.f;
17878                 box->x2 = alloc_w;
17879
17880                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17881                 box->y2 = box->y1 + (alloc_w * r_c);
17882               }
17883           }
17884       }
17885       break;
17886     }
17887 }
17888
17889 /**
17890  * clutter_actor_set_content_scaling_filters:
17891  * @self: a #ClutterActor
17892  * @min_filter: the minification filter for the content
17893  * @mag_filter: the magnification filter for the content
17894  *
17895  * Sets the minification and magnification filter to be applied when
17896  * scaling the #ClutterActor:content of a #ClutterActor.
17897  *
17898  * The #ClutterActor:minification-filter will be used when reducing
17899  * the size of the content; the #ClutterActor:magnification-filter
17900  * will be used when increasing the size of the content.
17901  *
17902  * Since: 1.10
17903  */
17904 void
17905 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
17906                                            ClutterScalingFilter  min_filter,
17907                                            ClutterScalingFilter  mag_filter)
17908 {
17909   ClutterActorPrivate *priv;
17910   gboolean changed;
17911   GObject *obj;
17912
17913   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17914
17915   priv = self->priv;
17916   obj = G_OBJECT (self);
17917
17918   g_object_freeze_notify (obj);
17919
17920   changed = FALSE;
17921
17922   if (priv->min_filter != min_filter)
17923     {
17924       priv->min_filter = min_filter;
17925       changed = TRUE;
17926
17927       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
17928     }
17929
17930   if (priv->mag_filter != mag_filter)
17931     {
17932       priv->mag_filter = mag_filter;
17933       changed = TRUE;
17934
17935       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
17936     }
17937
17938   if (changed)
17939     clutter_actor_queue_redraw (self);
17940
17941   g_object_thaw_notify (obj);
17942 }
17943
17944 /**
17945  * clutter_actor_get_content_scaling_filters:
17946  * @self: a #ClutterActor
17947  * @min_filter: (out) (allow-none): return location for the minification
17948  *   filter, or %NULL
17949  * @mag_filter: (out) (allow-none): return location for the magnification
17950  *   filter, or %NULL
17951  *
17952  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
17953  *
17954  * Since: 1.10
17955  */
17956 void
17957 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
17958                                            ClutterScalingFilter *min_filter,
17959                                            ClutterScalingFilter *mag_filter)
17960 {
17961   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17962
17963   if (min_filter != NULL)
17964     *min_filter = self->priv->min_filter;
17965
17966   if (mag_filter != NULL)
17967     *mag_filter = self->priv->mag_filter;
17968 }