actor: Restore a lost queue_relayout()
[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: Base abstract class for all visual stage actors.
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="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
795   LAST_SIGNAL
796 };
797
798 static guint actor_signals[LAST_SIGNAL] = { 0, };
799
800 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
801 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
802 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
803 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
804
805 /* These setters are all static for now, maybe they should be in the
806  * public API, but they are perhaps obscure enough to leave only as
807  * properties
808  */
809 static void clutter_actor_set_min_width          (ClutterActor *self,
810                                                   gfloat        min_width);
811 static void clutter_actor_set_min_height         (ClutterActor *self,
812                                                   gfloat        min_height);
813 static void clutter_actor_set_natural_width      (ClutterActor *self,
814                                                   gfloat        natural_width);
815 static void clutter_actor_set_natural_height     (ClutterActor *self,
816                                                   gfloat        natural_height);
817 static void clutter_actor_set_min_width_set      (ClutterActor *self,
818                                                   gboolean      use_min_width);
819 static void clutter_actor_set_min_height_set     (ClutterActor *self,
820                                                   gboolean      use_min_height);
821 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
822                                                   gboolean  use_natural_width);
823 static void clutter_actor_set_natural_height_set (ClutterActor *self,
824                                                   gboolean  use_natural_height);
825 static void clutter_actor_update_map_state       (ClutterActor  *self,
826                                                   MapStateChange change);
827 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
828
829 /* Helper routines for managing anchor coords */
830 static void clutter_anchor_coord_get_units (ClutterActor      *self,
831                                             const AnchorCoord *coord,
832                                             gfloat            *x,
833                                             gfloat            *y,
834                                             gfloat            *z);
835 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
836                                             gfloat             x,
837                                             gfloat             y,
838                                             gfloat             z);
839
840 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
841 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
842                                                         ClutterGravity     gravity);
843
844 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
845
846 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
847
848 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
849                                                                ClutterActor *ancestor,
850                                                                CoglMatrix *matrix);
851
852 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
853
854 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
855
856 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
857                                                                 const ClutterColor *color);
858
859 static void on_layout_manager_changed (ClutterLayoutManager *manager,
860                                        ClutterActor         *self);
861
862 /* Helper macro which translates by the anchor coord, applies the
863    given transformation and then translates back */
864 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
865   gfloat _tx, _ty, _tz;                                                \
866   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
867   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
868   { _transform; }                                                      \
869   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
870
871 static GQuark quark_shader_data = 0;
872 static GQuark quark_actor_layout_info = 0;
873 static GQuark quark_actor_transform_info = 0;
874 static GQuark quark_actor_animation_info = 0;
875
876 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
877                          clutter_actor,
878                          G_TYPE_INITIALLY_UNOWNED,
879                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
880                                                 clutter_container_iface_init)
881                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
882                                                 clutter_scriptable_iface_init)
883                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
884                                                 clutter_animatable_iface_init)
885                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
886                                                 atk_implementor_iface_init));
887
888 /*< private >
889  * clutter_actor_get_debug_name:
890  * @actor: a #ClutterActor
891  *
892  * Retrieves a printable name of @actor for debugging messages
893  *
894  * Return value: a string with a printable name
895  */
896 const gchar *
897 _clutter_actor_get_debug_name (ClutterActor *actor)
898 {
899   return actor->priv->name != NULL ? actor->priv->name
900                                    : G_OBJECT_TYPE_NAME (actor);
901 }
902
903 #ifdef CLUTTER_ENABLE_DEBUG
904 /* XXX - this is for debugging only, remove once working (or leave
905  * in only in some debug mode). Should leave it for a little while
906  * until we're confident in the new map/realize/visible handling.
907  */
908 static inline void
909 clutter_actor_verify_map_state (ClutterActor *self)
910 {
911   ClutterActorPrivate *priv = self->priv;
912
913   if (CLUTTER_ACTOR_IS_REALIZED (self))
914     {
915       /* all bets are off during reparent when we're potentially realized,
916        * but should not be according to invariants
917        */
918       if (!CLUTTER_ACTOR_IN_REPARENT (self))
919         {
920           if (priv->parent == NULL)
921             {
922               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
923                 {
924                 }
925               else
926                 g_warning ("Realized non-toplevel actor '%s' should "
927                            "have a parent",
928                            _clutter_actor_get_debug_name (self));
929             }
930           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
931             {
932               g_warning ("Realized actor %s has an unrealized parent %s",
933                          _clutter_actor_get_debug_name (self),
934                          _clutter_actor_get_debug_name (priv->parent));
935             }
936         }
937     }
938
939   if (CLUTTER_ACTOR_IS_MAPPED (self))
940     {
941       if (!CLUTTER_ACTOR_IS_REALIZED (self))
942         g_warning ("Actor '%s' is mapped but not realized",
943                    _clutter_actor_get_debug_name (self));
944
945       /* remaining bets are off during reparent when we're potentially
946        * mapped, but should not be according to invariants
947        */
948       if (!CLUTTER_ACTOR_IN_REPARENT (self))
949         {
950           if (priv->parent == NULL)
951             {
952               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
953                 {
954                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
955                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
956                     {
957                       g_warning ("Toplevel actor '%s' is mapped "
958                                  "but not visible",
959                                  _clutter_actor_get_debug_name (self));
960                     }
961                 }
962               else
963                 {
964                   g_warning ("Mapped actor '%s' should have a parent",
965                              _clutter_actor_get_debug_name (self));
966                 }
967             }
968           else
969             {
970               ClutterActor *iter = self;
971
972               /* check for the enable_paint_unmapped flag on the actor
973                * and parents; if the flag is enabled at any point of this
974                * branch of the scene graph then all the later checks
975                * become pointless
976                */
977               while (iter != NULL)
978                 {
979                   if (iter->priv->enable_paint_unmapped)
980                     return;
981
982                   iter = iter->priv->parent;
983                 }
984
985               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
986                 {
987                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
988                              "is not visible",
989                              _clutter_actor_get_debug_name (self),
990                              _clutter_actor_get_debug_name (priv->parent));
991                 }
992
993               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
994                 {
995                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
996                              "is not realized",
997                              _clutter_actor_get_debug_name (self),
998                              _clutter_actor_get_debug_name (priv->parent));
999                 }
1000
1001               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1002                 {
1003                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1004                     g_warning ("Actor '%s' is mapped but its non-toplevel "
1005                                "parent '%s' is not mapped",
1006                                _clutter_actor_get_debug_name (self),
1007                                _clutter_actor_get_debug_name (priv->parent));
1008                 }
1009             }
1010         }
1011     }
1012 }
1013
1014 #endif /* CLUTTER_ENABLE_DEBUG */
1015
1016 static void
1017 clutter_actor_set_mapped (ClutterActor *self,
1018                           gboolean      mapped)
1019 {
1020   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1021     return;
1022
1023   if (mapped)
1024     {
1025       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1026       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1027     }
1028   else
1029     {
1030       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1031       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1032     }
1033 }
1034
1035 /* this function updates the mapped and realized states according to
1036  * invariants, in the appropriate order.
1037  */
1038 static void
1039 clutter_actor_update_map_state (ClutterActor  *self,
1040                                 MapStateChange change)
1041 {
1042   gboolean was_mapped;
1043
1044   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1045
1046   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1047     {
1048       /* the mapped flag on top-level actors must be set by the
1049        * per-backend implementation because it might be asynchronous.
1050        *
1051        * That is, the MAPPED flag on toplevels currently tracks the X
1052        * server mapped-ness of the window, while the expected behavior
1053        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1054        * This creates some weird complexity by breaking the invariant
1055        * that if we're visible and all ancestors shown then we are
1056        * also mapped - instead, we are mapped if all ancestors
1057        * _possibly excepting_ the stage are mapped. The stage
1058        * will map/unmap for example when it is minimized or
1059        * moved to another workspace.
1060        *
1061        * So, the only invariant on the stage is that if visible it
1062        * should be realized, and that it has to be visible to be
1063        * mapped.
1064        */
1065       if (CLUTTER_ACTOR_IS_VISIBLE (self))
1066         clutter_actor_realize (self);
1067
1068       switch (change)
1069         {
1070         case MAP_STATE_CHECK:
1071           break;
1072
1073         case MAP_STATE_MAKE_MAPPED:
1074           g_assert (!was_mapped);
1075           clutter_actor_set_mapped (self, TRUE);
1076           break;
1077
1078         case MAP_STATE_MAKE_UNMAPPED:
1079           g_assert (was_mapped);
1080           clutter_actor_set_mapped (self, FALSE);
1081           break;
1082
1083         case MAP_STATE_MAKE_UNREALIZED:
1084           /* we only use MAKE_UNREALIZED in unparent,
1085            * and unparenting a stage isn't possible.
1086            * If someone wants to just unrealize a stage
1087            * then clutter_actor_unrealize() doesn't
1088            * go through this codepath.
1089            */
1090           g_warning ("Trying to force unrealize stage is not allowed");
1091           break;
1092         }
1093
1094       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1095           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1096           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1097         {
1098           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1099                      "it is somehow still mapped",
1100                      _clutter_actor_get_debug_name (self));
1101         }
1102     }
1103   else
1104     {
1105       ClutterActorPrivate *priv = self->priv;
1106       ClutterActor *parent = priv->parent;
1107       gboolean should_be_mapped;
1108       gboolean may_be_realized;
1109       gboolean must_be_realized;
1110
1111       should_be_mapped = FALSE;
1112       may_be_realized = TRUE;
1113       must_be_realized = FALSE;
1114
1115       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1116         {
1117           may_be_realized = FALSE;
1118         }
1119       else
1120         {
1121           /* Maintain invariant that if parent is mapped, and we are
1122            * visible, then we are mapped ...  unless parent is a
1123            * stage, in which case we map regardless of parent's map
1124            * state but do require stage to be visible and realized.
1125            *
1126            * If parent is realized, that does not force us to be
1127            * realized; but if parent is unrealized, that does force
1128            * us to be unrealized.
1129            *
1130            * The reason we don't force children to realize with
1131            * parents is _clutter_actor_rerealize(); if we require that
1132            * a realized parent means children are realized, then to
1133            * unrealize an actor we would have to unrealize its
1134            * parents, which would end up meaning unrealizing and
1135            * hiding the entire stage. So we allow unrealizing a
1136            * child (as long as that child is not mapped) while that
1137            * child still has a realized parent.
1138            *
1139            * Also, if we unrealize from leaf nodes to root, and
1140            * realize from root to leaf, the invariants are never
1141            * violated if we allow children to be unrealized
1142            * while parents are realized.
1143            *
1144            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1145            * to force us to unmap, even though parent is still
1146            * mapped. This is because we're unmapping from leaf nodes
1147            * up to root nodes.
1148            */
1149           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1150               change != MAP_STATE_MAKE_UNMAPPED)
1151             {
1152               gboolean parent_is_visible_realized_toplevel;
1153
1154               parent_is_visible_realized_toplevel =
1155                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1156                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1157                  CLUTTER_ACTOR_IS_REALIZED (parent));
1158
1159               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1160                   parent_is_visible_realized_toplevel)
1161                 {
1162                   must_be_realized = TRUE;
1163                   should_be_mapped = TRUE;
1164                 }
1165             }
1166
1167           /* if the actor has been set to be painted even if unmapped
1168            * then we should map it and check for realization as well;
1169            * this is an override for the branch of the scene graph
1170            * which begins with this node
1171            */
1172           if (priv->enable_paint_unmapped)
1173             {
1174               if (priv->parent == NULL)
1175                 g_warning ("Attempting to map an unparented actor '%s'",
1176                            _clutter_actor_get_debug_name (self));
1177
1178               should_be_mapped = TRUE;
1179               must_be_realized = TRUE;
1180             }
1181
1182           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1183             may_be_realized = FALSE;
1184         }
1185
1186       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1187         {
1188           if (parent == NULL)
1189             g_warning ("Attempting to map a child that does not "
1190                        "meet the necessary invariants: the actor '%s' "
1191                        "has no parent",
1192                        _clutter_actor_get_debug_name (self));
1193           else
1194             g_warning ("Attempting to map a child that does not "
1195                        "meet the necessary invariants: the actor '%s' "
1196                        "is parented to an unmapped actor '%s'",
1197                        _clutter_actor_get_debug_name (self),
1198                        _clutter_actor_get_debug_name (priv->parent));
1199         }
1200
1201       /* If in reparent, we temporarily suspend unmap and unrealize.
1202        *
1203        * We want to go in the order "realize, map" and "unmap, unrealize"
1204        */
1205
1206       /* Unmap */
1207       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1208         clutter_actor_set_mapped (self, FALSE);
1209
1210       /* Realize */
1211       if (must_be_realized)
1212         clutter_actor_realize (self);
1213
1214       /* if we must be realized then we may be, presumably */
1215       g_assert (!(must_be_realized && !may_be_realized));
1216
1217       /* Unrealize */
1218       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1219         clutter_actor_unrealize_not_hiding (self);
1220
1221       /* Map */
1222       if (should_be_mapped)
1223         {
1224           if (!must_be_realized)
1225             g_warning ("Somehow we think actor '%s' should be mapped but "
1226                        "not realized, which isn't allowed",
1227                        _clutter_actor_get_debug_name (self));
1228
1229           /* realization is allowed to fail (though I don't know what
1230            * an app is supposed to do about that - shouldn't it just
1231            * be a g_error? anyway, we have to avoid mapping if this
1232            * happens)
1233            */
1234           if (CLUTTER_ACTOR_IS_REALIZED (self))
1235             clutter_actor_set_mapped (self, TRUE);
1236         }
1237     }
1238
1239 #ifdef CLUTTER_ENABLE_DEBUG
1240   /* check all invariants were kept */
1241   clutter_actor_verify_map_state (self);
1242 #endif
1243 }
1244
1245 static void
1246 clutter_actor_real_map (ClutterActor *self)
1247 {
1248   ClutterActorPrivate *priv = self->priv;
1249   ClutterActor *stage, *iter;
1250
1251   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1252
1253   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1254                 _clutter_actor_get_debug_name (self));
1255
1256   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1257
1258   stage = _clutter_actor_get_stage_internal (self);
1259   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1260
1261   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1262                 priv->pick_id,
1263                 _clutter_actor_get_debug_name (self));
1264
1265   /* notify on parent mapped before potentially mapping
1266    * children, so apps see a top-down notification.
1267    */
1268   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1269
1270   for (iter = self->priv->first_child;
1271        iter != NULL;
1272        iter = iter->priv->next_sibling)
1273     {
1274       clutter_actor_map (iter);
1275     }
1276 }
1277
1278 /**
1279  * clutter_actor_map:
1280  * @self: A #ClutterActor
1281  *
1282  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1283  * and realizes its children if they are visible. Does nothing if the
1284  * actor is not visible.
1285  *
1286  * Calling this function is strongly disencouraged: the default
1287  * implementation of #ClutterActorClass.map() will map all the children
1288  * of an actor when mapping its parent.
1289  *
1290  * When overriding map, it is mandatory to chain up to the parent
1291  * implementation.
1292  *
1293  * Since: 1.0
1294  */
1295 void
1296 clutter_actor_map (ClutterActor *self)
1297 {
1298   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1299
1300   if (CLUTTER_ACTOR_IS_MAPPED (self))
1301     return;
1302
1303   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1304     return;
1305
1306   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1307 }
1308
1309 static void
1310 clutter_actor_real_unmap (ClutterActor *self)
1311 {
1312   ClutterActorPrivate *priv = self->priv;
1313   ClutterActor *iter;
1314
1315   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1316
1317   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1318                 _clutter_actor_get_debug_name (self));
1319
1320   for (iter = self->priv->first_child;
1321        iter != NULL;
1322        iter = iter->priv->next_sibling)
1323     {
1324       clutter_actor_unmap (iter);
1325     }
1326
1327   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1328
1329   /* clear the contents of the last paint volume, so that hiding + moving +
1330    * showing will not result in the wrong area being repainted
1331    */
1332   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1333   priv->last_paint_volume_valid = TRUE;
1334
1335   /* notify on parent mapped after potentially unmapping
1336    * children, so apps see a bottom-up notification.
1337    */
1338   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1339
1340   /* relinquish keyboard focus if we were unmapped while owning it */
1341   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1342     {
1343       ClutterStage *stage;
1344
1345       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1346
1347       if (stage != NULL)
1348         _clutter_stage_release_pick_id (stage, priv->pick_id);
1349
1350       priv->pick_id = -1;
1351
1352       if (stage != NULL &&
1353           clutter_stage_get_key_focus (stage) == self)
1354         {
1355           clutter_stage_set_key_focus (stage, NULL);
1356         }
1357     }
1358 }
1359
1360 /**
1361  * clutter_actor_unmap:
1362  * @self: A #ClutterActor
1363  *
1364  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1365  * unmaps its children if they were mapped.
1366  *
1367  * Calling this function is not encouraged: the default #ClutterActor
1368  * implementation of #ClutterActorClass.unmap() will also unmap any
1369  * eventual children by default when their parent is unmapped.
1370  *
1371  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1372  * chain up to the parent implementation.
1373  *
1374  * <note>It is important to note that the implementation of the
1375  * #ClutterActorClass.unmap() virtual function may be called after
1376  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1377  * implementation, but it is guaranteed to be called before the
1378  * #GObjectClass.finalize() implementation.</note>
1379  *
1380  * Since: 1.0
1381  */
1382 void
1383 clutter_actor_unmap (ClutterActor *self)
1384 {
1385   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1386
1387   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1388     return;
1389
1390   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1391 }
1392
1393 static void
1394 clutter_actor_real_show (ClutterActor *self)
1395 {
1396   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1397     {
1398       ClutterActorPrivate *priv = self->priv;
1399
1400       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1401
1402       /* we notify on the "visible" flag in the clutter_actor_show()
1403        * wrapper so the entire show signal emission completes first
1404        * (?)
1405        */
1406       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1407
1408       /* we queue a relayout unless the actor is inside a
1409        * container that explicitly told us not to
1410        */
1411       if (priv->parent != NULL &&
1412           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1413         {
1414           /* While an actor is hidden the parent may not have
1415            * allocated/requested so we need to start from scratch
1416            * and avoid the short-circuiting in
1417            * clutter_actor_queue_relayout().
1418            */
1419           priv->needs_width_request  = FALSE;
1420           priv->needs_height_request = FALSE;
1421           priv->needs_allocation     = FALSE;
1422           clutter_actor_queue_relayout (self);
1423         }
1424     }
1425 }
1426
1427 static inline void
1428 set_show_on_set_parent (ClutterActor *self,
1429                         gboolean      set_show)
1430 {
1431   ClutterActorPrivate *priv = self->priv;
1432
1433   set_show = !!set_show;
1434
1435   if (priv->show_on_set_parent == set_show)
1436     return;
1437
1438   if (priv->parent == NULL)
1439     {
1440       priv->show_on_set_parent = set_show;
1441       g_object_notify_by_pspec (G_OBJECT (self),
1442                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1443     }
1444 }
1445
1446 /**
1447  * clutter_actor_show:
1448  * @self: A #ClutterActor
1449  *
1450  * Flags an actor to be displayed. An actor that isn't shown will not
1451  * be rendered on the stage.
1452  *
1453  * Actors are visible by default.
1454  *
1455  * If this function is called on an actor without a parent, the
1456  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1457  * effect.
1458  */
1459 void
1460 clutter_actor_show (ClutterActor *self)
1461 {
1462   ClutterActorPrivate *priv;
1463
1464   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1465
1466   /* simple optimization */
1467   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1468     {
1469       /* we still need to set the :show-on-set-parent property, in
1470        * case show() is called on an unparented actor
1471        */
1472       set_show_on_set_parent (self, TRUE);
1473       return;
1474     }
1475
1476 #ifdef CLUTTER_ENABLE_DEBUG
1477   clutter_actor_verify_map_state (self);
1478 #endif
1479
1480   priv = self->priv;
1481
1482   g_object_freeze_notify (G_OBJECT (self));
1483
1484   set_show_on_set_parent (self, TRUE);
1485
1486   g_signal_emit (self, actor_signals[SHOW], 0);
1487   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1488
1489   if (priv->parent != NULL)
1490     clutter_actor_queue_redraw (priv->parent);
1491
1492   g_object_thaw_notify (G_OBJECT (self));
1493 }
1494
1495 /**
1496  * clutter_actor_show_all:
1497  * @self: a #ClutterActor
1498  *
1499  * Calls clutter_actor_show() on all children of an actor (if any).
1500  *
1501  * Since: 0.2
1502  *
1503  * Deprecated: 1.10: Actors are visible by default
1504  */
1505 void
1506 clutter_actor_show_all (ClutterActor *self)
1507 {
1508   ClutterActorClass *klass;
1509
1510   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1511
1512   klass = CLUTTER_ACTOR_GET_CLASS (self);
1513   if (klass->show_all)
1514     klass->show_all (self);
1515 }
1516
1517 static void
1518 clutter_actor_real_hide (ClutterActor *self)
1519 {
1520   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1521     {
1522       ClutterActorPrivate *priv = self->priv;
1523
1524       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1525
1526       /* we notify on the "visible" flag in the clutter_actor_hide()
1527        * wrapper so the entire hide signal emission completes first
1528        * (?)
1529        */
1530       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1531
1532       /* we queue a relayout unless the actor is inside a
1533        * container that explicitly told us not to
1534        */
1535       if (priv->parent != NULL &&
1536           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1537         clutter_actor_queue_relayout (priv->parent);
1538     }
1539 }
1540
1541 /**
1542  * clutter_actor_hide:
1543  * @self: A #ClutterActor
1544  *
1545  * Flags an actor to be hidden. A hidden actor will not be
1546  * rendered on the stage.
1547  *
1548  * Actors are visible by default.
1549  *
1550  * If this function is called on an actor without a parent, the
1551  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1552  * as a side-effect.
1553  */
1554 void
1555 clutter_actor_hide (ClutterActor *self)
1556 {
1557   ClutterActorPrivate *priv;
1558
1559   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1560
1561   /* simple optimization */
1562   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1563     {
1564       /* we still need to set the :show-on-set-parent property, in
1565        * case hide() is called on an unparented actor
1566        */
1567       set_show_on_set_parent (self, FALSE);
1568       return;
1569     }
1570
1571 #ifdef CLUTTER_ENABLE_DEBUG
1572   clutter_actor_verify_map_state (self);
1573 #endif
1574
1575   priv = self->priv;
1576
1577   g_object_freeze_notify (G_OBJECT (self));
1578
1579   set_show_on_set_parent (self, FALSE);
1580
1581   g_signal_emit (self, actor_signals[HIDE], 0);
1582   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1583
1584   if (priv->parent != NULL)
1585     clutter_actor_queue_redraw (priv->parent);
1586
1587   g_object_thaw_notify (G_OBJECT (self));
1588 }
1589
1590 /**
1591  * clutter_actor_hide_all:
1592  * @self: a #ClutterActor
1593  *
1594  * Calls clutter_actor_hide() on all child actors (if any).
1595  *
1596  * Since: 0.2
1597  *
1598  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1599  *   prevent its children from being painted as well.
1600  */
1601 void
1602 clutter_actor_hide_all (ClutterActor *self)
1603 {
1604   ClutterActorClass *klass;
1605
1606   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1607
1608   klass = CLUTTER_ACTOR_GET_CLASS (self);
1609   if (klass->hide_all)
1610     klass->hide_all (self);
1611 }
1612
1613 /**
1614  * clutter_actor_realize:
1615  * @self: A #ClutterActor
1616  *
1617  * Realization informs the actor that it is attached to a stage. It
1618  * can use this to allocate resources if it wanted to delay allocation
1619  * until it would be rendered. However it is perfectly acceptable for
1620  * an actor to create resources before being realized because Clutter
1621  * only ever has a single rendering context so that actor is free to
1622  * be moved from one stage to another.
1623  *
1624  * This function does nothing if the actor is already realized.
1625  *
1626  * Because a realized actor must have realized parent actors, calling
1627  * clutter_actor_realize() will also realize all parents of the actor.
1628  *
1629  * This function does not realize child actors, except in the special
1630  * case that realizing the stage, when the stage is visible, will
1631  * suddenly map (and thus realize) the children of the stage.
1632  **/
1633 void
1634 clutter_actor_realize (ClutterActor *self)
1635 {
1636   ClutterActorPrivate *priv;
1637
1638   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1639
1640   priv = self->priv;
1641
1642 #ifdef CLUTTER_ENABLE_DEBUG
1643   clutter_actor_verify_map_state (self);
1644 #endif
1645
1646   if (CLUTTER_ACTOR_IS_REALIZED (self))
1647     return;
1648
1649   /* To be realized, our parent actors must be realized first.
1650    * This will only succeed if we're inside a toplevel.
1651    */
1652   if (priv->parent != NULL)
1653     clutter_actor_realize (priv->parent);
1654
1655   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1656     {
1657       /* toplevels can be realized at any time */
1658     }
1659   else
1660     {
1661       /* "Fail" the realization if parent is missing or unrealized;
1662        * this should really be a g_warning() not some kind of runtime
1663        * failure; how can an app possibly recover? Instead it's a bug
1664        * in the app and the app should get an explanatory warning so
1665        * someone can fix it. But for now it's too hard to fix this
1666        * because e.g. ClutterTexture needs reworking.
1667        */
1668       if (priv->parent == NULL ||
1669           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1670         return;
1671     }
1672
1673   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1674
1675   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1676   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1677
1678   g_signal_emit (self, actor_signals[REALIZE], 0);
1679
1680   /* Stage actor is allowed to unset the realized flag again in its
1681    * default signal handler, though that is a pathological situation.
1682    */
1683
1684   /* If realization "failed" we'll have to update child state. */
1685   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1686 }
1687
1688 static void
1689 clutter_actor_real_unrealize (ClutterActor *self)
1690 {
1691   /* we must be unmapped (implying our children are also unmapped) */
1692   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1693 }
1694
1695 /**
1696  * clutter_actor_unrealize:
1697  * @self: A #ClutterActor
1698  *
1699  * Unrealization informs the actor that it may be being destroyed or
1700  * moved to another stage. The actor may want to destroy any
1701  * underlying graphics resources at this point. However it is
1702  * perfectly acceptable for it to retain the resources until the actor
1703  * is destroyed because Clutter only ever uses a single rendering
1704  * context and all of the graphics resources are valid on any stage.
1705  *
1706  * Because mapped actors must be realized, actors may not be
1707  * unrealized if they are mapped. This function hides the actor to be
1708  * sure it isn't mapped, an application-visible side effect that you
1709  * may not be expecting.
1710  *
1711  * This function should not be called by application code.
1712  */
1713 void
1714 clutter_actor_unrealize (ClutterActor *self)
1715 {
1716   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1717   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1718
1719 /* This function should not really be in the public API, because
1720  * there isn't a good reason to call it. ClutterActor will already
1721  * unrealize things for you when it's important to do so.
1722  *
1723  * If you were using clutter_actor_unrealize() in a dispose
1724  * implementation, then don't, just chain up to ClutterActor's
1725  * dispose.
1726  *
1727  * If you were using clutter_actor_unrealize() to implement
1728  * unrealizing children of your container, then don't, ClutterActor
1729  * will already take care of that.
1730  *
1731  * If you were using clutter_actor_unrealize() to re-realize to
1732  * create your resources in a different way, then use
1733  * _clutter_actor_rerealize() (inside Clutter) or just call your
1734  * code that recreates your resources directly (outside Clutter).
1735  */
1736
1737 #ifdef CLUTTER_ENABLE_DEBUG
1738   clutter_actor_verify_map_state (self);
1739 #endif
1740
1741   clutter_actor_hide (self);
1742
1743   clutter_actor_unrealize_not_hiding (self);
1744 }
1745
1746 static ClutterActorTraverseVisitFlags
1747 unrealize_actor_before_children_cb (ClutterActor *self,
1748                                     int depth,
1749                                     void *user_data)
1750 {
1751   /* If an actor is already unrealized we know its children have also
1752    * already been unrealized... */
1753   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1754     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1755
1756   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1757
1758   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1759 }
1760
1761 static ClutterActorTraverseVisitFlags
1762 unrealize_actor_after_children_cb (ClutterActor *self,
1763                                    int depth,
1764                                    void *user_data)
1765 {
1766   /* We want to unset the realized flag only _after_
1767    * child actors are unrealized, to maintain invariants.
1768    */
1769   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1770   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1771   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1772 }
1773
1774 /*
1775  * clutter_actor_unrealize_not_hiding:
1776  * @self: A #ClutterActor
1777  *
1778  * Unrealization informs the actor that it may be being destroyed or
1779  * moved to another stage. The actor may want to destroy any
1780  * underlying graphics resources at this point. However it is
1781  * perfectly acceptable for it to retain the resources until the actor
1782  * is destroyed because Clutter only ever uses a single rendering
1783  * context and all of the graphics resources are valid on any stage.
1784  *
1785  * Because mapped actors must be realized, actors may not be
1786  * unrealized if they are mapped. You must hide the actor or one of
1787  * its parents before attempting to unrealize.
1788  *
1789  * This function is separate from clutter_actor_unrealize() because it
1790  * does not automatically hide the actor.
1791  * Actors need not be hidden to be unrealized, they just need to
1792  * be unmapped. In fact we don't want to mess up the application's
1793  * setting of the "visible" flag, so hiding is very undesirable.
1794  *
1795  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1796  * backward compatibility.
1797  */
1798 static void
1799 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1800 {
1801   _clutter_actor_traverse (self,
1802                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1803                            unrealize_actor_before_children_cb,
1804                            unrealize_actor_after_children_cb,
1805                            NULL);
1806 }
1807
1808 /*
1809  * _clutter_actor_rerealize:
1810  * @self: A #ClutterActor
1811  * @callback: Function to call while unrealized
1812  * @data: data for callback
1813  *
1814  * If an actor is already unrealized, this just calls the callback.
1815  *
1816  * If it is realized, it unrealizes temporarily, calls the callback,
1817  * and then re-realizes the actor.
1818  *
1819  * As a side effect, leaves all children of the actor unrealized if
1820  * the actor was realized but not showing.  This is because when we
1821  * unrealize the actor temporarily we must unrealize its children
1822  * (e.g. children of a stage can't be realized if stage window is
1823  * gone). And we aren't clever enough to save the realization state of
1824  * all children. In most cases this should not matter, because
1825  * the children will automatically realize when they next become mapped.
1826  */
1827 void
1828 _clutter_actor_rerealize (ClutterActor    *self,
1829                           ClutterCallback  callback,
1830                           void            *data)
1831 {
1832   gboolean was_mapped;
1833   gboolean was_showing;
1834   gboolean was_realized;
1835
1836   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1837
1838 #ifdef CLUTTER_ENABLE_DEBUG
1839   clutter_actor_verify_map_state (self);
1840 #endif
1841
1842   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1843   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1844   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1845
1846   /* Must be unmapped to unrealize. Note we only have to hide this
1847    * actor if it was mapped (if all parents were showing).  If actor
1848    * is merely visible (but not mapped), then that's fine, we can
1849    * leave it visible.
1850    */
1851   if (was_mapped)
1852     clutter_actor_hide (self);
1853
1854   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1855
1856   /* unrealize self and all children */
1857   clutter_actor_unrealize_not_hiding (self);
1858
1859   if (callback != NULL)
1860     {
1861       (* callback) (self, data);
1862     }
1863
1864   if (was_showing)
1865     clutter_actor_show (self); /* will realize only if mapping implies it */
1866   else if (was_realized)
1867     clutter_actor_realize (self); /* realize self and all parents */
1868 }
1869
1870 static void
1871 clutter_actor_real_pick (ClutterActor       *self,
1872                          const ClutterColor *color)
1873 {
1874   /* the default implementation is just to paint a rectangle
1875    * with the same size of the actor using the passed color
1876    */
1877   if (clutter_actor_should_pick_paint (self))
1878     {
1879       ClutterActorBox box = { 0, };
1880       float width, height;
1881
1882       clutter_actor_get_allocation_box (self, &box);
1883
1884       width = box.x2 - box.x1;
1885       height = box.y2 - box.y1;
1886
1887       cogl_set_source_color4ub (color->red,
1888                                 color->green,
1889                                 color->blue,
1890                                 color->alpha);
1891
1892       cogl_rectangle (0, 0, width, height);
1893     }
1894
1895   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1896    * with existing container classes that override the pick() virtual
1897    * and chain up to the default implementation - otherwise we'll end up
1898    * painting our children twice.
1899    *
1900    * this has to go away for 2.0; hopefully along the pick() itself.
1901    */
1902   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1903     {
1904       ClutterActor *iter;
1905
1906       for (iter = self->priv->first_child;
1907            iter != NULL;
1908            iter = iter->priv->next_sibling)
1909         clutter_actor_paint (iter);
1910     }
1911 }
1912
1913 /**
1914  * clutter_actor_should_pick_paint:
1915  * @self: A #ClutterActor
1916  *
1917  * Should be called inside the implementation of the
1918  * #ClutterActor::pick virtual function in order to check whether
1919  * the actor should paint itself in pick mode or not.
1920  *
1921  * This function should never be called directly by applications.
1922  *
1923  * Return value: %TRUE if the actor should paint its silhouette,
1924  *   %FALSE otherwise
1925  */
1926 gboolean
1927 clutter_actor_should_pick_paint (ClutterActor *self)
1928 {
1929   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1930
1931   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1932       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1933        CLUTTER_ACTOR_IS_REACTIVE (self)))
1934     return TRUE;
1935
1936   return FALSE;
1937 }
1938
1939 static void
1940 clutter_actor_real_get_preferred_width (ClutterActor *self,
1941                                         gfloat        for_height,
1942                                         gfloat       *min_width_p,
1943                                         gfloat       *natural_width_p)
1944 {
1945   ClutterActorPrivate *priv = self->priv;
1946
1947   if (priv->n_children != 0 &&
1948       priv->layout_manager != NULL)
1949     {
1950       ClutterContainer *container = CLUTTER_CONTAINER (self);
1951
1952       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1953                     "for the preferred width",
1954                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1955                     priv->layout_manager);
1956
1957       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1958                                                   container,
1959                                                   for_height,
1960                                                   min_width_p,
1961                                                   natural_width_p);
1962
1963       return;
1964     }
1965
1966   /* Default implementation is always 0x0, usually an actor
1967    * using this default is relying on someone to set the
1968    * request manually
1969    */
1970   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1971
1972   if (min_width_p)
1973     *min_width_p = 0;
1974
1975   if (natural_width_p)
1976     *natural_width_p = 0;
1977 }
1978
1979 static void
1980 clutter_actor_real_get_preferred_height (ClutterActor *self,
1981                                          gfloat        for_width,
1982                                          gfloat       *min_height_p,
1983                                          gfloat       *natural_height_p)
1984 {
1985   ClutterActorPrivate *priv = self->priv;
1986
1987   if (priv->n_children != 0 &&
1988       priv->layout_manager != NULL)
1989     {
1990       ClutterContainer *container = CLUTTER_CONTAINER (self);
1991
1992       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1993                     "for the preferred height",
1994                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1995                     priv->layout_manager);
1996
1997       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1998                                                    container,
1999                                                    for_width,
2000                                                    min_height_p,
2001                                                    natural_height_p);
2002
2003       return;
2004     }
2005   /* Default implementation is always 0x0, usually an actor
2006    * using this default is relying on someone to set the
2007    * request manually
2008    */
2009   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2010
2011   if (min_height_p)
2012     *min_height_p = 0;
2013
2014   if (natural_height_p)
2015     *natural_height_p = 0;
2016 }
2017
2018 static void
2019 clutter_actor_store_old_geometry (ClutterActor    *self,
2020                                   ClutterActorBox *box)
2021 {
2022   *box = self->priv->allocation;
2023 }
2024
2025 static inline void
2026 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2027                                           const ClutterActorBox *old)
2028 {
2029   ClutterActorPrivate *priv = self->priv;
2030   GObject *obj = G_OBJECT (self);
2031
2032   g_object_freeze_notify (obj);
2033
2034   /* to avoid excessive requisition or allocation cycles we
2035    * use the cached values.
2036    *
2037    * - if we don't have an allocation we assume that we need
2038    *   to notify anyway
2039    * - if we don't have a width or a height request we notify
2040    *   width and height
2041    * - if we have a valid allocation then we check the old
2042    *   bounding box with the current allocation and we notify
2043    *   the changes
2044    */
2045   if (priv->needs_allocation)
2046     {
2047       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2048       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2049       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2050       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2051     }
2052   else if (priv->needs_width_request || priv->needs_height_request)
2053     {
2054       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2055       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2056     }
2057   else
2058     {
2059       gfloat xu, yu;
2060       gfloat widthu, heightu;
2061
2062       xu = priv->allocation.x1;
2063       yu = priv->allocation.y1;
2064       widthu = priv->allocation.x2 - priv->allocation.x1;
2065       heightu = priv->allocation.y2 - priv->allocation.y1;
2066
2067       if (xu != old->x1)
2068         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2069
2070       if (yu != old->y1)
2071         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2072
2073       if (widthu != (old->x2 - old->x1))
2074         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2075
2076       if (heightu != (old->y2 - old->y1))
2077         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2078     }
2079
2080   g_object_thaw_notify (obj);
2081 }
2082
2083 /*< private >
2084  * clutter_actor_set_allocation_internal:
2085  * @self: a #ClutterActor
2086  * @box: a #ClutterActorBox
2087  * @flags: allocation flags
2088  *
2089  * Stores the allocation of @self.
2090  *
2091  * This function only performs basic storage and property notification.
2092  *
2093  * This function should be called by clutter_actor_set_allocation()
2094  * and by the default implementation of #ClutterActorClass.allocate().
2095  *
2096  * Return value: %TRUE if the allocation of the #ClutterActor has been
2097  *   changed, and %FALSE otherwise
2098  */
2099 static inline gboolean
2100 clutter_actor_set_allocation_internal (ClutterActor           *self,
2101                                        const ClutterActorBox  *box,
2102                                        ClutterAllocationFlags  flags)
2103 {
2104   ClutterActorPrivate *priv = self->priv;
2105   GObject *obj;
2106   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2107   gboolean flags_changed;
2108   gboolean retval;
2109   ClutterActorBox old_alloc = { 0, };
2110
2111   obj = G_OBJECT (self);
2112
2113   g_object_freeze_notify (obj);
2114
2115   clutter_actor_store_old_geometry (self, &old_alloc);
2116
2117   x1_changed = priv->allocation.x1 != box->x1;
2118   y1_changed = priv->allocation.y1 != box->y1;
2119   x2_changed = priv->allocation.x2 != box->x2;
2120   y2_changed = priv->allocation.y2 != box->y2;
2121
2122   flags_changed = priv->allocation_flags != flags;
2123
2124   priv->allocation = *box;
2125   priv->allocation_flags = flags;
2126
2127   /* allocation is authoritative */
2128   priv->needs_width_request = FALSE;
2129   priv->needs_height_request = FALSE;
2130   priv->needs_allocation = FALSE;
2131
2132   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
2133     {
2134       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2135                     _clutter_actor_get_debug_name (self));
2136
2137       priv->transform_valid = FALSE;
2138
2139       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2140
2141       /* if the allocation changes, so does the content box */
2142       if (priv->content != NULL)
2143         g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2144
2145       retval = TRUE;
2146     }
2147   else
2148     retval = FALSE;
2149
2150   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2151
2152   g_object_thaw_notify (obj);
2153
2154   return retval;
2155 }
2156
2157 static void clutter_actor_real_allocate (ClutterActor           *self,
2158                                          const ClutterActorBox  *box,
2159                                          ClutterAllocationFlags  flags);
2160
2161 static inline void
2162 clutter_actor_maybe_layout_children (ClutterActor           *self,
2163                                      const ClutterActorBox  *allocation,
2164                                      ClutterAllocationFlags  flags)
2165 {
2166   ClutterActorPrivate *priv = self->priv;
2167
2168   /* this is going to be a bit hard to follow, so let's put an explanation
2169    * here.
2170    *
2171    * we want ClutterActor to have a default layout manager if the actor was
2172    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2173    *
2174    * we also want any subclass of ClutterActor that does not override the
2175    * ::allocate() virtual function to delegate to a layout manager.
2176    *
2177    * finally, we want to allow people subclassing ClutterActor and overriding
2178    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2179    *
2180    * on the other hand, we want existing actor subclasses overriding the
2181    * ::allocate() virtual function and chaining up to the parent's
2182    * implementation to continue working without allocating their children
2183    * twice, or without entering an allocation loop.
2184    *
2185    * for the first two points, we check if the class of the actor is
2186    * overridding the ::allocate() virtual function; if it isn't, then we
2187    * follow through with checking whether we have children and a layout
2188    * manager, and eventually calling clutter_layout_manager_allocate().
2189    *
2190    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2191    * allocation flags that we got passed, and if it is present, we continue
2192    * with the check above.
2193    *
2194    * if neither of these two checks yields a positive result, we just
2195    * assume that the ::allocate() virtual function that resulted in this
2196    * function being called will also allocate the children of the actor.
2197    */
2198
2199   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2200     goto check_layout;
2201
2202   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2203     goto check_layout;
2204
2205   return;
2206
2207 check_layout:
2208   if (priv->n_children != 0 &&
2209       priv->layout_manager != NULL)
2210     {
2211       ClutterContainer *container = CLUTTER_CONTAINER (self);
2212       ClutterAllocationFlags children_flags;
2213       ClutterActorBox children_box;
2214
2215       /* normalize the box passed to the layout manager */
2216       children_box.x1 = children_box.y1 = 0.f;
2217       children_box.x2 = (allocation->x2 - allocation->x1);
2218       children_box.y2 = (allocation->y2 - allocation->y1);
2219
2220       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2221        * the actor's children, since it refers only to the current
2222        * actor's allocation.
2223        */
2224       children_flags = flags;
2225       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2226
2227       CLUTTER_NOTE (LAYOUT,
2228                     "Allocating %d children of %s "
2229                     "at { %.2f, %.2f - %.2f x %.2f } "
2230                     "using %s",
2231                     priv->n_children,
2232                     _clutter_actor_get_debug_name (self),
2233                     allocation->x1,
2234                     allocation->y1,
2235                     (allocation->x2 - allocation->x1),
2236                     (allocation->y2 - allocation->y1),
2237                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2238
2239       clutter_layout_manager_allocate (priv->layout_manager,
2240                                        container,
2241                                        &children_box,
2242                                        children_flags);
2243     }
2244 }
2245
2246 static void
2247 clutter_actor_real_allocate (ClutterActor           *self,
2248                              const ClutterActorBox  *box,
2249                              ClutterAllocationFlags  flags)
2250 {
2251   ClutterActorPrivate *priv = self->priv;
2252   gboolean changed;
2253
2254   g_object_freeze_notify (G_OBJECT (self));
2255
2256   changed = clutter_actor_set_allocation_internal (self, box, flags);
2257
2258   /* we allocate our children before we notify changes in our geometry,
2259    * so that people connecting to properties will be able to get valid
2260    * data out of the sub-tree of the scene graph that has this actor at
2261    * the root.
2262    */
2263   clutter_actor_maybe_layout_children (self, box, flags);
2264
2265   if (changed)
2266     {
2267       ClutterActorBox signal_box = priv->allocation;
2268       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2269
2270       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2271                      &signal_box,
2272                      signal_flags);
2273     }
2274
2275   g_object_thaw_notify (G_OBJECT (self));
2276 }
2277
2278 static void
2279 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2280                                     ClutterActor *origin)
2281 {
2282   /* no point in queuing a redraw on a destroyed actor */
2283   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2284     return;
2285
2286   /* NB: We can't bail out early here if the actor is hidden in case
2287    * the actor bas been cloned. In this case the clone will need to
2288    * receive the signal so it can queue its own redraw.
2289    */
2290
2291   /* calls klass->queue_redraw in default handler */
2292   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2293 }
2294
2295 static void
2296 clutter_actor_real_queue_redraw (ClutterActor *self,
2297                                  ClutterActor *origin)
2298 {
2299   ClutterActor *parent;
2300
2301   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2302                 _clutter_actor_get_debug_name (self),
2303                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2304                                : "same actor");
2305
2306   /* no point in queuing a redraw on a destroyed actor */
2307   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2308     return;
2309
2310   /* If the queue redraw is coming from a child then the actor has
2311      become dirty and any queued effect is no longer valid */
2312   if (self != origin)
2313     {
2314       self->priv->is_dirty = TRUE;
2315       self->priv->effect_to_redraw = NULL;
2316     }
2317
2318   /* If the actor isn't visible, we still had to emit the signal
2319    * to allow for a ClutterClone, but the appearance of the parent
2320    * won't change so we don't have to propagate up the hierarchy.
2321    */
2322   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2323     return;
2324
2325   /* Although we could determine here that a full stage redraw
2326    * has already been queued and immediately bail out, we actually
2327    * guarantee that we will propagate a queue-redraw signal to our
2328    * parent at least once so that it's possible to implement a
2329    * container that tracks which of its children have queued a
2330    * redraw.
2331    */
2332   if (self->priv->propagated_one_redraw)
2333     {
2334       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2335       if (stage != NULL &&
2336           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2337         return;
2338     }
2339
2340   self->priv->propagated_one_redraw = TRUE;
2341
2342   /* notify parents, if they are all visible eventually we'll
2343    * queue redraw on the stage, which queues the redraw idle.
2344    */
2345   parent = clutter_actor_get_parent (self);
2346   if (parent != NULL)
2347     {
2348       /* this will go up recursively */
2349       _clutter_actor_signal_queue_redraw (parent, origin);
2350     }
2351 }
2352
2353 static void
2354 clutter_actor_real_queue_relayout (ClutterActor *self)
2355 {
2356   ClutterActorPrivate *priv = self->priv;
2357
2358   /* no point in queueing a redraw on a destroyed actor */
2359   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2360     return;
2361
2362   priv->needs_width_request  = TRUE;
2363   priv->needs_height_request = TRUE;
2364   priv->needs_allocation     = TRUE;
2365
2366   /* reset the cached size requests */
2367   memset (priv->width_requests, 0,
2368           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2369   memset (priv->height_requests, 0,
2370           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2371
2372   /* We need to go all the way up the hierarchy */
2373   if (priv->parent != NULL)
2374     _clutter_actor_queue_only_relayout (priv->parent);
2375 }
2376
2377 /**
2378  * clutter_actor_apply_relative_transform_to_point:
2379  * @self: A #ClutterActor
2380  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2381  *   default #ClutterStage
2382  * @point: A point as #ClutterVertex
2383  * @vertex: (out caller-allocates): The translated #ClutterVertex
2384  *
2385  * Transforms @point in coordinates relative to the actor into
2386  * ancestor-relative coordinates using the relevant transform
2387  * stack (i.e. scale, rotation, etc).
2388  *
2389  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2390  * this case, the coordinates returned will be the coordinates on
2391  * the stage before the projection is applied. This is different from
2392  * the behaviour of clutter_actor_apply_transform_to_point().
2393  *
2394  * Since: 0.6
2395  */
2396 void
2397 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2398                                                  ClutterActor        *ancestor,
2399                                                  const ClutterVertex *point,
2400                                                  ClutterVertex       *vertex)
2401 {
2402   gfloat w;
2403   CoglMatrix matrix;
2404
2405   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2406   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2407   g_return_if_fail (point != NULL);
2408   g_return_if_fail (vertex != NULL);
2409
2410   *vertex = *point;
2411   w = 1.0;
2412
2413   if (ancestor == NULL)
2414     ancestor = _clutter_actor_get_stage_internal (self);
2415
2416   if (ancestor == NULL)
2417     {
2418       *vertex = *point;
2419       return;
2420     }
2421
2422   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2423   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2424 }
2425
2426 static gboolean
2427 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2428                                          const ClutterVertex *vertices_in,
2429                                          ClutterVertex *vertices_out,
2430                                          int n_vertices)
2431 {
2432   ClutterActor *stage;
2433   CoglMatrix modelview;
2434   CoglMatrix projection;
2435   float viewport[4];
2436
2437   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2438
2439   stage = _clutter_actor_get_stage_internal (self);
2440
2441   /* We really can't do anything meaningful in this case so don't try
2442    * to do any transform */
2443   if (stage == NULL)
2444     return FALSE;
2445
2446   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2447    * that gets us to stage coordinates, we want to go all the way to eye
2448    * coordinates */
2449   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2450
2451   /* Fetch the projection and viewport */
2452   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2453   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2454                                &viewport[0],
2455                                &viewport[1],
2456                                &viewport[2],
2457                                &viewport[3]);
2458
2459   _clutter_util_fully_transform_vertices (&modelview,
2460                                           &projection,
2461                                           viewport,
2462                                           vertices_in,
2463                                           vertices_out,
2464                                           n_vertices);
2465
2466   return TRUE;
2467 }
2468
2469 /**
2470  * clutter_actor_apply_transform_to_point:
2471  * @self: A #ClutterActor
2472  * @point: A point as #ClutterVertex
2473  * @vertex: (out caller-allocates): The translated #ClutterVertex
2474  *
2475  * Transforms @point in coordinates relative to the actor
2476  * into screen-relative coordinates with the current actor
2477  * transformation (i.e. scale, rotation, etc)
2478  *
2479  * Since: 0.4
2480  **/
2481 void
2482 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2483                                         const ClutterVertex *point,
2484                                         ClutterVertex       *vertex)
2485 {
2486   g_return_if_fail (point != NULL);
2487   g_return_if_fail (vertex != NULL);
2488   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2489 }
2490
2491 /*
2492  * _clutter_actor_get_relative_transformation_matrix:
2493  * @self: The actor whose coordinate space you want to transform from.
2494  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2495  *            or %NULL if you want to transform all the way to eye coordinates.
2496  * @matrix: A #CoglMatrix to store the transformation
2497  *
2498  * This gets a transformation @matrix that will transform coordinates from the
2499  * coordinate space of @self into the coordinate space of @ancestor.
2500  *
2501  * For example if you need a matrix that can transform the local actor
2502  * coordinates of @self into stage coordinates you would pass the actor's stage
2503  * pointer as the @ancestor.
2504  *
2505  * If you pass %NULL then the transformation will take you all the way through
2506  * to eye coordinates. This can be useful if you want to extract the entire
2507  * modelview transform that Clutter applies before applying the projection
2508  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2509  * using cogl_set_modelview_matrix() for example then you would want a matrix
2510  * that transforms into eye coordinates.
2511  *
2512  * <note><para>This function explicitly initializes the given @matrix. If you just
2513  * want clutter to multiply a relative transformation with an existing matrix
2514  * you can use clutter_actor_apply_relative_transformation_matrix()
2515  * instead.</para></note>
2516  *
2517  */
2518 /* XXX: We should consider caching the stage relative modelview along with
2519  * the actor itself */
2520 static void
2521 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2522                                                    ClutterActor *ancestor,
2523                                                    CoglMatrix *matrix)
2524 {
2525   cogl_matrix_init_identity (matrix);
2526
2527   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2528 }
2529
2530 /* Project the given @box into stage window coordinates, writing the
2531  * transformed vertices to @verts[]. */
2532 static gboolean
2533 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2534                                           const ClutterActorBox *box,
2535                                           ClutterVertex          verts[])
2536 {
2537   ClutterVertex box_vertices[4];
2538
2539   box_vertices[0].x = box->x1;
2540   box_vertices[0].y = box->y1;
2541   box_vertices[0].z = 0;
2542   box_vertices[1].x = box->x2;
2543   box_vertices[1].y = box->y1;
2544   box_vertices[1].z = 0;
2545   box_vertices[2].x = box->x1;
2546   box_vertices[2].y = box->y2;
2547   box_vertices[2].z = 0;
2548   box_vertices[3].x = box->x2;
2549   box_vertices[3].y = box->y2;
2550   box_vertices[3].z = 0;
2551
2552   return
2553     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2554 }
2555
2556 /**
2557  * clutter_actor_get_allocation_vertices:
2558  * @self: A #ClutterActor
2559  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2560  *   against, or %NULL to use the #ClutterStage
2561  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2562  *   location for an array of 4 #ClutterVertex in which to store the result
2563  *
2564  * Calculates the transformed coordinates of the four corners of the
2565  * actor in the plane of @ancestor. The returned vertices relate to
2566  * the #ClutterActorBox coordinates as follows:
2567  * <itemizedlist>
2568  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2569  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2570  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2571  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2572  * </itemizedlist>
2573  *
2574  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2575  * this case, the coordinates returned will be the coordinates on
2576  * the stage before the projection is applied. This is different from
2577  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2578  *
2579  * Since: 0.6
2580  */
2581 void
2582 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2583                                        ClutterActor  *ancestor,
2584                                        ClutterVertex  verts[])
2585 {
2586   ClutterActorPrivate *priv;
2587   ClutterActorBox box;
2588   ClutterVertex vertices[4];
2589   CoglMatrix modelview;
2590
2591   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2592   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2593
2594   if (ancestor == NULL)
2595     ancestor = _clutter_actor_get_stage_internal (self);
2596
2597   /* Fallback to a NOP transform if the actor isn't parented under a
2598    * stage. */
2599   if (ancestor == NULL)
2600     ancestor = self;
2601
2602   priv = self->priv;
2603
2604   /* if the actor needs to be allocated we force a relayout, so that
2605    * we will have valid values to use in the transformations */
2606   if (priv->needs_allocation)
2607     {
2608       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2609       if (stage)
2610         _clutter_stage_maybe_relayout (stage);
2611       else
2612         {
2613           box.x1 = box.y1 = 0;
2614           /* The result isn't really meaningful in this case but at
2615            * least try to do something *vaguely* reasonable... */
2616           clutter_actor_get_size (self, &box.x2, &box.y2);
2617         }
2618     }
2619
2620   clutter_actor_get_allocation_box (self, &box);
2621
2622   vertices[0].x = box.x1;
2623   vertices[0].y = box.y1;
2624   vertices[0].z = 0;
2625   vertices[1].x = box.x2;
2626   vertices[1].y = box.y1;
2627   vertices[1].z = 0;
2628   vertices[2].x = box.x1;
2629   vertices[2].y = box.y2;
2630   vertices[2].z = 0;
2631   vertices[3].x = box.x2;
2632   vertices[3].y = box.y2;
2633   vertices[3].z = 0;
2634
2635   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2636                                                      &modelview);
2637
2638   cogl_matrix_transform_points (&modelview,
2639                                 3,
2640                                 sizeof (ClutterVertex),
2641                                 vertices,
2642                                 sizeof (ClutterVertex),
2643                                 vertices,
2644                                 4);
2645 }
2646
2647 /**
2648  * clutter_actor_get_abs_allocation_vertices:
2649  * @self: A #ClutterActor
2650  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2651  *   of 4 #ClutterVertex where to store the result.
2652  *
2653  * Calculates the transformed screen coordinates of the four corners of
2654  * the actor; the returned vertices relate to the #ClutterActorBox
2655  * coordinates  as follows:
2656  * <itemizedlist>
2657  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2658  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2659  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2660  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2661  * </itemizedlist>
2662  *
2663  * Since: 0.4
2664  */
2665 void
2666 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2667                                            ClutterVertex  verts[])
2668 {
2669   ClutterActorPrivate *priv;
2670   ClutterActorBox actor_space_allocation;
2671
2672   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2673
2674   priv = self->priv;
2675
2676   /* if the actor needs to be allocated we force a relayout, so that
2677    * the actor allocation box will be valid for
2678    * _clutter_actor_transform_and_project_box()
2679    */
2680   if (priv->needs_allocation)
2681     {
2682       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2683       /* There's nothing meaningful we can do now */
2684       if (!stage)
2685         return;
2686
2687       _clutter_stage_maybe_relayout (stage);
2688     }
2689
2690   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2691    * own coordinate space... */
2692   actor_space_allocation.x1 = 0;
2693   actor_space_allocation.y1 = 0;
2694   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2695   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2696   _clutter_actor_transform_and_project_box (self,
2697                                             &actor_space_allocation,
2698                                             verts);
2699 }
2700
2701 static void
2702 clutter_actor_real_apply_transform (ClutterActor *self,
2703                                     CoglMatrix   *matrix)
2704 {
2705   ClutterActorPrivate *priv = self->priv;
2706
2707   if (!priv->transform_valid)
2708     {
2709       CoglMatrix *transform = &priv->transform;
2710       const ClutterTransformInfo *info;
2711
2712       info = _clutter_actor_get_transform_info_or_defaults (self);
2713
2714       cogl_matrix_init_identity (transform);
2715
2716       cogl_matrix_translate (transform,
2717                              priv->allocation.x1,
2718                              priv->allocation.y1,
2719                              0.0);
2720
2721       if (info->depth)
2722         cogl_matrix_translate (transform, 0, 0, info->depth);
2723
2724       /*
2725        * because the rotation involves translations, we must scale
2726        * before applying the rotations (if we apply the scale after
2727        * the rotations, the translations included in the rotation are
2728        * not scaled and so the entire object will move on the screen
2729        * as a result of rotating it).
2730        */
2731       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2732         {
2733           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2734                                         &info->scale_center,
2735                                         cogl_matrix_scale (transform,
2736                                                            info->scale_x,
2737                                                            info->scale_y,
2738                                                            1.0));
2739         }
2740
2741       if (info->rz_angle)
2742         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2743                                       &info->rz_center,
2744                                       cogl_matrix_rotate (transform,
2745                                                           info->rz_angle,
2746                                                           0, 0, 1.0));
2747
2748       if (info->ry_angle)
2749         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2750                                       &info->ry_center,
2751                                       cogl_matrix_rotate (transform,
2752                                                           info->ry_angle,
2753                                                           0, 1.0, 0));
2754
2755       if (info->rx_angle)
2756         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2757                                       &info->rx_center,
2758                                       cogl_matrix_rotate (transform,
2759                                                           info->rx_angle,
2760                                                           1.0, 0, 0));
2761
2762       if (!clutter_anchor_coord_is_zero (&info->anchor))
2763         {
2764           gfloat x, y, z;
2765
2766           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2767           cogl_matrix_translate (transform, -x, -y, -z);
2768         }
2769
2770       priv->transform_valid = TRUE;
2771     }
2772
2773   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2774 }
2775
2776 /* Applies the transforms associated with this actor to the given
2777  * matrix. */
2778 void
2779 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2780                                           CoglMatrix *matrix)
2781 {
2782   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2783 }
2784
2785 /*
2786  * clutter_actor_apply_relative_transformation_matrix:
2787  * @self: The actor whose coordinate space you want to transform from.
2788  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2789  *            or %NULL if you want to transform all the way to eye coordinates.
2790  * @matrix: A #CoglMatrix to apply the transformation too.
2791  *
2792  * This multiplies a transform with @matrix that will transform coordinates
2793  * from the coordinate space of @self into the coordinate space of @ancestor.
2794  *
2795  * For example if you need a matrix that can transform the local actor
2796  * coordinates of @self into stage coordinates you would pass the actor's stage
2797  * pointer as the @ancestor.
2798  *
2799  * If you pass %NULL then the transformation will take you all the way through
2800  * to eye coordinates. This can be useful if you want to extract the entire
2801  * modelview transform that Clutter applies before applying the projection
2802  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2803  * using cogl_set_modelview_matrix() for example then you would want a matrix
2804  * that transforms into eye coordinates.
2805  *
2806  * <note>This function doesn't initialize the given @matrix, it simply
2807  * multiplies the requested transformation matrix with the existing contents of
2808  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2809  * before calling this function, or you can use
2810  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2811  */
2812 void
2813 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2814                                                      ClutterActor *ancestor,
2815                                                      CoglMatrix *matrix)
2816 {
2817   ClutterActor *parent;
2818
2819   /* Note we terminate before ever calling stage->apply_transform()
2820    * since that would conceptually be relative to the underlying
2821    * window OpenGL coordinates so we'd need a special @ancestor
2822    * value to represent the fake parent of the stage. */
2823   if (self == ancestor)
2824     return;
2825
2826   parent = clutter_actor_get_parent (self);
2827
2828   if (parent != NULL)
2829     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2830                                                          matrix);
2831
2832   _clutter_actor_apply_modelview_transform (self, matrix);
2833 }
2834
2835 static void
2836 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2837                                        ClutterPaintVolume *pv,
2838                                        const char *label,
2839                                        const CoglColor *color)
2840 {
2841   static CoglPipeline *outline = NULL;
2842   CoglPrimitive *prim;
2843   ClutterVertex line_ends[12 * 2];
2844   int n_vertices;
2845   CoglContext *ctx =
2846     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2847   /* XXX: at some point we'll query this from the stage but we can't
2848    * do that until the osx backend uses Cogl natively. */
2849   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2850
2851   if (outline == NULL)
2852     outline = cogl_pipeline_new (ctx);
2853
2854   _clutter_paint_volume_complete (pv);
2855
2856   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2857
2858   /* Front face */
2859   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2860   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2861   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2862   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2863
2864   if (!pv->is_2d)
2865     {
2866       /* Back face */
2867       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2868       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2869       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2870       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2871
2872       /* Lines connecting front face to back face */
2873       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2874       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2875       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2876       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2877     }
2878
2879   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2880                                 n_vertices,
2881                                 (CoglVertexP3 *)line_ends);
2882
2883   cogl_pipeline_set_color (outline, color);
2884   cogl_framebuffer_draw_primitive (fb, outline, prim);
2885   cogl_object_unref (prim);
2886
2887   if (label)
2888     {
2889       PangoLayout *layout;
2890       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2891       pango_layout_set_text (layout, label, -1);
2892       cogl_pango_render_layout (layout,
2893                                 pv->vertices[0].x,
2894                                 pv->vertices[0].y,
2895                                 color,
2896                                 0);
2897       g_object_unref (layout);
2898     }
2899 }
2900
2901 static void
2902 _clutter_actor_draw_paint_volume (ClutterActor *self)
2903 {
2904   ClutterPaintVolume *pv;
2905   CoglColor color;
2906
2907   pv = _clutter_actor_get_paint_volume_mutable (self);
2908   if (!pv)
2909     {
2910       gfloat width, height;
2911       ClutterPaintVolume fake_pv;
2912
2913       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2914       _clutter_paint_volume_init_static (&fake_pv, stage);
2915
2916       clutter_actor_get_size (self, &width, &height);
2917       clutter_paint_volume_set_width (&fake_pv, width);
2918       clutter_paint_volume_set_height (&fake_pv, height);
2919
2920       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2921       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2922                                              _clutter_actor_get_debug_name (self),
2923                                              &color);
2924
2925       clutter_paint_volume_free (&fake_pv);
2926     }
2927   else
2928     {
2929       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2930       _clutter_actor_draw_paint_volume_full (self, pv,
2931                                              _clutter_actor_get_debug_name (self),
2932                                              &color);
2933     }
2934 }
2935
2936 static void
2937 _clutter_actor_paint_cull_result (ClutterActor *self,
2938                                   gboolean success,
2939                                   ClutterCullResult result)
2940 {
2941   ClutterPaintVolume *pv;
2942   CoglColor color;
2943
2944   if (success)
2945     {
2946       if (result == CLUTTER_CULL_RESULT_IN)
2947         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2948       else if (result == CLUTTER_CULL_RESULT_OUT)
2949         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2950       else
2951         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2952     }
2953   else
2954     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2955
2956   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2957     _clutter_actor_draw_paint_volume_full (self, pv,
2958                                            _clutter_actor_get_debug_name (self),
2959                                            &color);
2960   else
2961     {
2962       PangoLayout *layout;
2963       char *label =
2964         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2965       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2966       cogl_set_source_color (&color);
2967
2968       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2969       pango_layout_set_text (layout, label, -1);
2970       cogl_pango_render_layout (layout,
2971                                 0,
2972                                 0,
2973                                 &color,
2974                                 0);
2975       g_free (label);
2976       g_object_unref (layout);
2977     }
2978 }
2979
2980 static int clone_paint_level = 0;
2981
2982 void
2983 _clutter_actor_push_clone_paint (void)
2984 {
2985   clone_paint_level++;
2986 }
2987
2988 void
2989 _clutter_actor_pop_clone_paint (void)
2990 {
2991   clone_paint_level--;
2992 }
2993
2994 static gboolean
2995 in_clone_paint (void)
2996 {
2997   return clone_paint_level > 0;
2998 }
2999
3000 /* Returns TRUE if the actor can be ignored */
3001 /* FIXME: we should return a ClutterCullResult, and
3002  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3003  * means there's no point in trying to cull descendants of the current
3004  * node. */
3005 static gboolean
3006 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3007 {
3008   ClutterActorPrivate *priv = self->priv;
3009   ClutterActor *stage;
3010   const ClutterPlane *stage_clip;
3011
3012   if (!priv->last_paint_volume_valid)
3013     {
3014       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3015                     "->last_paint_volume_valid == FALSE",
3016                     _clutter_actor_get_debug_name (self));
3017       return FALSE;
3018     }
3019
3020   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3021     return FALSE;
3022
3023   stage = _clutter_actor_get_stage_internal (self);
3024   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3025   if (G_UNLIKELY (!stage_clip))
3026     {
3027       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3028                     "No stage clip set",
3029                     _clutter_actor_get_debug_name (self));
3030       return FALSE;
3031     }
3032
3033   if (cogl_get_draw_framebuffer () !=
3034       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3035     {
3036       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3037                     "Current framebuffer doesn't correspond to stage",
3038                     _clutter_actor_get_debug_name (self));
3039       return FALSE;
3040     }
3041
3042   *result_out =
3043     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3044   return TRUE;
3045 }
3046
3047 static void
3048 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3049 {
3050   ClutterActorPrivate *priv = self->priv;
3051   const ClutterPaintVolume *pv;
3052
3053   if (priv->last_paint_volume_valid)
3054     {
3055       clutter_paint_volume_free (&priv->last_paint_volume);
3056       priv->last_paint_volume_valid = FALSE;
3057     }
3058
3059   pv = clutter_actor_get_paint_volume (self);
3060   if (!pv)
3061     {
3062       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3063                     "Actor failed to report a paint volume",
3064                     _clutter_actor_get_debug_name (self));
3065       return;
3066     }
3067
3068   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3069
3070   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3071                                             NULL); /* eye coordinates */
3072
3073   priv->last_paint_volume_valid = TRUE;
3074 }
3075
3076 static inline gboolean
3077 actor_has_shader_data (ClutterActor *self)
3078 {
3079   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3080 }
3081
3082 guint32
3083 _clutter_actor_get_pick_id (ClutterActor *self)
3084 {
3085   if (self->priv->pick_id < 0)
3086     return 0;
3087
3088   return self->priv->pick_id;
3089 }
3090
3091 /* This is the same as clutter_actor_add_effect except that it doesn't
3092    queue a redraw and it doesn't notify on the effect property */
3093 static void
3094 _clutter_actor_add_effect_internal (ClutterActor  *self,
3095                                     ClutterEffect *effect)
3096 {
3097   ClutterActorPrivate *priv = self->priv;
3098
3099   if (priv->effects == NULL)
3100     {
3101       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3102       priv->effects->actor = self;
3103     }
3104
3105   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3106 }
3107
3108 /* This is the same as clutter_actor_remove_effect except that it doesn't
3109    queue a redraw and it doesn't notify on the effect property */
3110 static void
3111 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3112                                        ClutterEffect *effect)
3113 {
3114   ClutterActorPrivate *priv = self->priv;
3115
3116   if (priv->effects == NULL)
3117     return;
3118
3119   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3120 }
3121
3122 static gboolean
3123 needs_flatten_effect (ClutterActor *self)
3124 {
3125   ClutterActorPrivate *priv = self->priv;
3126
3127   if (G_UNLIKELY (clutter_paint_debug_flags &
3128                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3129     return FALSE;
3130
3131   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3132     return TRUE;
3133   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3134     {
3135       if (clutter_actor_get_paint_opacity (self) < 255 &&
3136           clutter_actor_has_overlaps (self))
3137         return TRUE;
3138     }
3139
3140   return FALSE;
3141 }
3142
3143 static void
3144 add_or_remove_flatten_effect (ClutterActor *self)
3145 {
3146   ClutterActorPrivate *priv = self->priv;
3147
3148   /* Add or remove the flatten effect depending on the
3149      offscreen-redirect property. */
3150   if (needs_flatten_effect (self))
3151     {
3152       if (priv->flatten_effect == NULL)
3153         {
3154           ClutterActorMeta *actor_meta;
3155           gint priority;
3156
3157           priv->flatten_effect = _clutter_flatten_effect_new ();
3158           /* Keep a reference to the effect so that we can queue
3159              redraws from it */
3160           g_object_ref_sink (priv->flatten_effect);
3161
3162           /* Set the priority of the effect to high so that it will
3163              always be applied to the actor first. It uses an internal
3164              priority so that it won't be visible to applications */
3165           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3166           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3167           _clutter_actor_meta_set_priority (actor_meta, priority);
3168
3169           /* This will add the effect without queueing a redraw */
3170           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3171         }
3172     }
3173   else
3174     {
3175       if (priv->flatten_effect != NULL)
3176         {
3177           /* Destroy the effect so that it will lose its fbo cache of
3178              the actor */
3179           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3180           g_object_unref (priv->flatten_effect);
3181           priv->flatten_effect = NULL;
3182         }
3183     }
3184 }
3185
3186 static void
3187 clutter_actor_real_paint (ClutterActor *actor)
3188 {
3189   ClutterActorPrivate *priv = actor->priv;
3190   ClutterActor *iter;
3191
3192   for (iter = priv->first_child;
3193        iter != NULL;
3194        iter = iter->priv->next_sibling)
3195     {
3196       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3197                     _clutter_actor_get_debug_name (iter),
3198                     _clutter_actor_get_debug_name (actor),
3199                     iter->priv->allocation.x1,
3200                     iter->priv->allocation.y1,
3201                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3202                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3203
3204       clutter_actor_paint (iter);
3205     }
3206 }
3207
3208 static gboolean
3209 clutter_actor_paint_node (ClutterActor     *actor,
3210                           ClutterPaintNode *root)
3211 {
3212   ClutterActorPrivate *priv = actor->priv;
3213
3214   if (root == NULL)
3215     return FALSE;
3216
3217   if (priv->bg_color_set &&
3218       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3219     {
3220       ClutterPaintNode *node;
3221       ClutterColor bg_color;
3222       ClutterActorBox box;
3223
3224       box.x1 = 0.f;
3225       box.y1 = 0.f;
3226       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3227       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3228
3229       bg_color = priv->bg_color;
3230       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3231                      * priv->bg_color.alpha
3232                      / 255;
3233
3234       node = clutter_color_node_new (&bg_color);
3235       clutter_paint_node_set_name (node, "backgroundColor");
3236       clutter_paint_node_add_rectangle (node, &box);
3237       clutter_paint_node_add_child (root, node);
3238       clutter_paint_node_unref (node);
3239     }
3240
3241   if (priv->content != NULL)
3242     _clutter_content_paint_content (priv->content, actor, root);
3243
3244   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3245     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3246
3247   if (clutter_paint_node_get_n_children (root) == 0)
3248     return FALSE;
3249
3250 #ifdef CLUTTER_ENABLE_DEBUG
3251   if (CLUTTER_HAS_DEBUG (PAINT))
3252     {
3253       /* dump the tree only if we have one */
3254       _clutter_paint_node_dump_tree (root);
3255     }
3256 #endif /* CLUTTER_ENABLE_DEBUG */
3257
3258   _clutter_paint_node_paint (root);
3259
3260 #if 0
3261   /* XXX: Uncomment this when we disable emitting the paint signal */
3262   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3263 #endif
3264
3265   return TRUE;
3266 }
3267
3268 /**
3269  * clutter_actor_paint:
3270  * @self: A #ClutterActor
3271  *
3272  * Renders the actor to display.
3273  *
3274  * This function should not be called directly by applications.
3275  * Call clutter_actor_queue_redraw() to queue paints, instead.
3276  *
3277  * This function is context-aware, and will either cause a
3278  * regular paint or a pick paint.
3279  *
3280  * This function will emit the #ClutterActor::paint signal or
3281  * the #ClutterActor::pick signal, depending on the context.
3282  *
3283  * This function does not paint the actor if the actor is set to 0,
3284  * unless it is performing a pick paint.
3285  */
3286 void
3287 clutter_actor_paint (ClutterActor *self)
3288 {
3289   ClutterActorPrivate *priv;
3290   ClutterPickMode pick_mode;
3291   gboolean clip_set = FALSE;
3292   gboolean shader_applied = FALSE;
3293
3294   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3295                           "Actor real-paint counter",
3296                           "Increments each time any actor is painted",
3297                           0 /* no application private data */);
3298   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3299                           "Actor pick-paint counter",
3300                           "Increments each time any actor is painted "
3301                           "for picking",
3302                           0 /* no application private data */);
3303
3304   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3305
3306   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3307     return;
3308
3309   priv = self->priv;
3310
3311   pick_mode = _clutter_context_get_pick_mode ();
3312
3313   if (pick_mode == CLUTTER_PICK_NONE)
3314     priv->propagated_one_redraw = FALSE;
3315
3316   /* It's an important optimization that we consider painting of
3317    * actors with 0 opacity to be a NOP... */
3318   if (pick_mode == CLUTTER_PICK_NONE &&
3319       /* ignore top-levels, since they might be transparent */
3320       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3321       /* Use the override opacity if its been set */
3322       ((priv->opacity_override >= 0) ?
3323        priv->opacity_override : priv->opacity) == 0)
3324     return;
3325
3326   /* if we aren't paintable (not in a toplevel with all
3327    * parents paintable) then do nothing.
3328    */
3329   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3330     return;
3331
3332   /* mark that we are in the paint process */
3333   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3334
3335   cogl_push_matrix();
3336
3337   if (priv->enable_model_view_transform)
3338     {
3339       CoglMatrix matrix;
3340
3341       /* XXX: It could be better to cache the modelview with the actor
3342        * instead of progressively building up the transformations on
3343        * the matrix stack every time we paint. */
3344       cogl_get_modelview_matrix (&matrix);
3345       _clutter_actor_apply_modelview_transform (self, &matrix);
3346
3347 #ifdef CLUTTER_ENABLE_DEBUG
3348       /* Catch when out-of-band transforms have been made by actors not as part
3349        * of an apply_transform vfunc... */
3350       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3351         {
3352           CoglMatrix expected_matrix;
3353
3354           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3355                                                              &expected_matrix);
3356
3357           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3358             {
3359               GString *buf = g_string_sized_new (1024);
3360               ClutterActor *parent;
3361
3362               parent = self;
3363               while (parent != NULL)
3364                 {
3365                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3366
3367                   if (parent->priv->parent != NULL)
3368                     g_string_append (buf, "->");
3369
3370                   parent = parent->priv->parent;
3371                 }
3372
3373               g_warning ("Unexpected transform found when painting actor "
3374                          "\"%s\". This will be caused by one of the actor's "
3375                          "ancestors (%s) using the Cogl API directly to transform "
3376                          "children instead of using ::apply_transform().",
3377                          _clutter_actor_get_debug_name (self),
3378                          buf->str);
3379
3380               g_string_free (buf, TRUE);
3381             }
3382         }
3383 #endif /* CLUTTER_ENABLE_DEBUG */
3384
3385       cogl_set_modelview_matrix (&matrix);
3386     }
3387
3388   if (priv->has_clip)
3389     {
3390       cogl_clip_push_rectangle (priv->clip.x,
3391                                 priv->clip.y,
3392                                 priv->clip.x + priv->clip.width,
3393                                 priv->clip.y + priv->clip.height);
3394       clip_set = TRUE;
3395     }
3396   else if (priv->clip_to_allocation)
3397     {
3398       gfloat width, height;
3399
3400       width  = priv->allocation.x2 - priv->allocation.x1;
3401       height = priv->allocation.y2 - priv->allocation.y1;
3402
3403       cogl_clip_push_rectangle (0, 0, width, height);
3404       clip_set = TRUE;
3405     }
3406
3407   if (pick_mode == CLUTTER_PICK_NONE)
3408     {
3409       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3410
3411       /* We check whether we need to add the flatten effect before
3412          each paint so that we can avoid having a mechanism for
3413          applications to notify when the value of the
3414          has_overlaps virtual changes. */
3415       add_or_remove_flatten_effect (self);
3416     }
3417   else
3418     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3419
3420   /* We save the current paint volume so that the next time the
3421    * actor queues a redraw we can constrain the redraw to just
3422    * cover the union of the new bounding box and the old.
3423    *
3424    * We also fetch the current paint volume to perform culling so
3425    * we can avoid painting actors outside the current clip region.
3426    *
3427    * If we are painting inside a clone, we should neither update
3428    * the paint volume or use it to cull painting, since the paint
3429    * box represents the location of the source actor on the
3430    * screen.
3431    *
3432    * XXX: We are starting to do a lot of vertex transforms on
3433    * the CPU in a typical paint, so at some point we should
3434    * audit these and consider caching some things.
3435    *
3436    * NB: We don't perform culling while picking at this point because
3437    * clutter-stage.c doesn't setup the clipping planes appropriately.
3438    *
3439    * NB: We don't want to update the last-paint-volume during picking
3440    * because the last-paint-volume is used to determine the old screen
3441    * space location of an actor that has moved so we can know the
3442    * minimal region to redraw to clear an old view of the actor. If we
3443    * update this during picking then by the time we come around to
3444    * paint then the last-paint-volume would likely represent the new
3445    * actor position not the old.
3446    */
3447   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3448     {
3449       gboolean success;
3450       /* annoyingly gcc warns if uninitialized even though
3451        * the initialization is redundant :-( */
3452       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3453
3454       if (G_LIKELY ((clutter_paint_debug_flags &
3455                      (CLUTTER_DEBUG_DISABLE_CULLING |
3456                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3457                     (CLUTTER_DEBUG_DISABLE_CULLING |
3458                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3459         _clutter_actor_update_last_paint_volume (self);
3460
3461       success = cull_actor (self, &result);
3462
3463       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3464         _clutter_actor_paint_cull_result (self, success, result);
3465       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3466         goto done;
3467     }
3468
3469   if (priv->effects == NULL)
3470     {
3471       if (pick_mode == CLUTTER_PICK_NONE &&
3472           actor_has_shader_data (self))
3473         {
3474           _clutter_actor_shader_pre_paint (self, FALSE);
3475           shader_applied = TRUE;
3476         }
3477
3478       priv->next_effect_to_paint = NULL;
3479     }
3480   else
3481     priv->next_effect_to_paint =
3482       _clutter_meta_group_peek_metas (priv->effects);
3483
3484   clutter_actor_continue_paint (self);
3485
3486   if (shader_applied)
3487     _clutter_actor_shader_post_paint (self);
3488
3489   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3490                   pick_mode == CLUTTER_PICK_NONE))
3491     _clutter_actor_draw_paint_volume (self);
3492
3493 done:
3494   /* If we make it here then the actor has run through a complete
3495      paint run including all the effects so it's no longer dirty */
3496   if (pick_mode == CLUTTER_PICK_NONE)
3497     priv->is_dirty = FALSE;
3498
3499   if (clip_set)
3500     cogl_clip_pop();
3501
3502   cogl_pop_matrix();
3503
3504   /* paint sequence complete */
3505   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3506 }
3507
3508 /**
3509  * clutter_actor_continue_paint:
3510  * @self: A #ClutterActor
3511  *
3512  * Run the next stage of the paint sequence. This function should only
3513  * be called within the implementation of the ‘run’ virtual of a
3514  * #ClutterEffect. It will cause the run method of the next effect to
3515  * be applied, or it will paint the actual actor if the current effect
3516  * is the last effect in the chain.
3517  *
3518  * Since: 1.8
3519  */
3520 void
3521 clutter_actor_continue_paint (ClutterActor *self)
3522 {
3523   ClutterActorPrivate *priv;
3524
3525   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3526   /* This should only be called from with in the ‘run’ implementation
3527      of a ClutterEffect */
3528   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3529
3530   priv = self->priv;
3531
3532   /* Skip any effects that are disabled */
3533   while (priv->next_effect_to_paint &&
3534          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3535     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3536
3537   /* If this has come from the last effect then we'll just paint the
3538      actual actor */
3539   if (priv->next_effect_to_paint == NULL)
3540     {
3541       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3542         {
3543           ClutterPaintNode *dummy;
3544           gboolean emit_paint = TRUE;
3545
3546           /* XXX - this will go away in 2.0, when we can get rid of this
3547            * stuff and switch to a pure retained render tree of PaintNodes
3548            * for the entire frame, starting from the Stage; the paint()
3549            * virtual function can then be called directly.
3550            */
3551           dummy = _clutter_dummy_node_new ();
3552           clutter_paint_node_set_name (dummy, "Root");
3553
3554           /* XXX - for 1.12, we use the return value of paint_node() to
3555            * set the emit_paint variable.
3556            */
3557           clutter_actor_paint_node (self, dummy);
3558           clutter_paint_node_unref (dummy);
3559
3560           if (emit_paint || CLUTTER_ACTOR_IS_TOPLEVEL (self))
3561             g_signal_emit (self, actor_signals[PAINT], 0);
3562           else
3563             {
3564               CLUTTER_NOTE (PAINT, "The actor '%s' painted using PaintNodes, "
3565                                    "skipping the emission of the paint signal.",
3566                                    _clutter_actor_get_debug_name (self));
3567             }
3568         }
3569       else
3570         {
3571           ClutterColor col = { 0, };
3572
3573           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3574
3575           /* Actor will then paint silhouette of itself in supplied
3576            * color.  See clutter_stage_get_actor_at_pos() for where
3577            * picking is enabled.
3578            */
3579           g_signal_emit (self, actor_signals[PICK], 0, &col);
3580         }
3581     }
3582   else
3583     {
3584       ClutterEffect *old_current_effect;
3585       ClutterEffectPaintFlags run_flags = 0;
3586
3587       /* Cache the current effect so that we can put it back before
3588          returning */
3589       old_current_effect = priv->current_effect;
3590
3591       priv->current_effect = priv->next_effect_to_paint->data;
3592       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3593
3594       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3595         {
3596           if (priv->is_dirty)
3597             {
3598               /* If there's an effect queued with this redraw then all
3599                  effects up to that one will be considered dirty. It
3600                  is expected the queued effect will paint the cached
3601                  image and not call clutter_actor_continue_paint again
3602                  (although it should work ok if it does) */
3603               if (priv->effect_to_redraw == NULL ||
3604                   priv->current_effect != priv->effect_to_redraw)
3605                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3606             }
3607
3608           _clutter_effect_paint (priv->current_effect, run_flags);
3609         }
3610       else
3611         {
3612           /* We can't determine when an actor has been modified since
3613              its last pick so lets just assume it has always been
3614              modified */
3615           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3616
3617           _clutter_effect_pick (priv->current_effect, run_flags);
3618         }
3619
3620       priv->current_effect = old_current_effect;
3621     }
3622 }
3623
3624 static ClutterActorTraverseVisitFlags
3625 invalidate_queue_redraw_entry (ClutterActor *self,
3626                                int           depth,
3627                                gpointer      user_data)
3628 {
3629   ClutterActorPrivate *priv = self->priv;
3630
3631   if (priv->queue_redraw_entry != NULL)
3632     {
3633       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3634       priv->queue_redraw_entry = NULL;
3635     }
3636
3637   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3638 }
3639
3640 static inline void
3641 remove_child (ClutterActor *self,
3642               ClutterActor *child)
3643 {
3644   ClutterActor *prev_sibling, *next_sibling;
3645
3646   prev_sibling = child->priv->prev_sibling;
3647   next_sibling = child->priv->next_sibling;
3648
3649   if (prev_sibling != NULL)
3650     prev_sibling->priv->next_sibling = next_sibling;
3651
3652   if (next_sibling != NULL)
3653     next_sibling->priv->prev_sibling = prev_sibling;
3654
3655   if (self->priv->first_child == child)
3656     self->priv->first_child = next_sibling;
3657
3658   if (self->priv->last_child == child)
3659     self->priv->last_child = prev_sibling;
3660
3661   child->priv->parent = NULL;
3662   child->priv->prev_sibling = NULL;
3663   child->priv->next_sibling = NULL;
3664 }
3665
3666 typedef enum {
3667   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3668   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3669   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3670   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3671   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3672   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3673
3674   /* default flags for public API */
3675   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3676                                     REMOVE_CHILD_EMIT_PARENT_SET |
3677                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3678                                     REMOVE_CHILD_CHECK_STATE |
3679                                     REMOVE_CHILD_FLUSH_QUEUE |
3680                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3681
3682   /* flags for legacy/deprecated API */
3683   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3684                                     REMOVE_CHILD_FLUSH_QUEUE |
3685                                     REMOVE_CHILD_EMIT_PARENT_SET |
3686                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3687 } ClutterActorRemoveChildFlags;
3688
3689 /*< private >
3690  * clutter_actor_remove_child_internal:
3691  * @self: a #ClutterActor
3692  * @child: the child of @self that has to be removed
3693  * @flags: control the removal operations
3694  *
3695  * Removes @child from the list of children of @self.
3696  */
3697 static void
3698 clutter_actor_remove_child_internal (ClutterActor                 *self,
3699                                      ClutterActor                 *child,
3700                                      ClutterActorRemoveChildFlags  flags)
3701 {
3702   ClutterActor *old_first, *old_last;
3703   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3704   gboolean flush_queue;
3705   gboolean notify_first_last;
3706   gboolean was_mapped;
3707
3708   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3709   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3710   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3711   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3712   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3713   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3714
3715   g_object_freeze_notify (G_OBJECT (self));
3716
3717   if (destroy_meta)
3718     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3719
3720   if (check_state)
3721     {
3722       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3723
3724       /* we need to unrealize *before* we set parent_actor to NULL,
3725        * because in an unrealize method actors are dissociating from the
3726        * stage, which means they need to be able to
3727        * clutter_actor_get_stage().
3728        *
3729        * yhis should unmap and unrealize, unless we're reparenting.
3730        */
3731       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3732     }
3733   else
3734     was_mapped = FALSE;
3735
3736   if (flush_queue)
3737     {
3738       /* We take this opportunity to invalidate any queue redraw entry
3739        * associated with the actor and descendants since we won't be able to
3740        * determine the appropriate stage after this.
3741        *
3742        * we do this after we updated the mapped state because actors might
3743        * end up queueing redraws inside their mapped/unmapped virtual
3744        * functions, and if we invalidate the redraw entry we could end up
3745        * with an inconsistent state and weird memory corruption. see
3746        * bugs:
3747        *
3748        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3749        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3750        */
3751       _clutter_actor_traverse (child,
3752                                0,
3753                                invalidate_queue_redraw_entry,
3754                                NULL,
3755                                NULL);
3756     }
3757
3758   old_first = self->priv->first_child;
3759   old_last = self->priv->last_child;
3760
3761   remove_child (self, child);
3762
3763   self->priv->n_children -= 1;
3764
3765   self->priv->age += 1;
3766
3767   /* clutter_actor_reparent() will emit ::parent-set for us */
3768   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3769     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3770
3771   /* if the child was mapped then we need to relayout ourselves to account
3772    * for the removed child
3773    */
3774   if (was_mapped)
3775     clutter_actor_queue_relayout (self);
3776
3777   /* we need to emit the signal before dropping the reference */
3778   if (emit_actor_removed)
3779     g_signal_emit_by_name (self, "actor-removed", child);
3780
3781   if (notify_first_last)
3782     {
3783       if (old_first != self->priv->first_child)
3784         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3785
3786       if (old_last != self->priv->last_child)
3787         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3788     }
3789
3790   g_object_thaw_notify (G_OBJECT (self));
3791
3792   /* remove the reference we acquired in clutter_actor_add_child() */
3793   g_object_unref (child);
3794 }
3795
3796 static const ClutterTransformInfo default_transform_info = {
3797   0.0, { 0, },          /* rotation-x */
3798   0.0, { 0, },          /* rotation-y */
3799   0.0, { 0, },          /* rotation-z */
3800
3801   1.0, 1.0, { 0, },     /* scale */
3802
3803   { 0, },               /* anchor */
3804
3805   0.0,                  /* depth */
3806 };
3807
3808 /*< private >
3809  * _clutter_actor_get_transform_info_or_defaults:
3810  * @self: a #ClutterActor
3811  *
3812  * Retrieves the ClutterTransformInfo structure associated to an actor.
3813  *
3814  * If the actor does not have a ClutterTransformInfo structure associated
3815  * to it, then the default structure will be returned.
3816  *
3817  * This function should only be used for getters.
3818  *
3819  * Return value: a const pointer to the ClutterTransformInfo structure
3820  */
3821 const ClutterTransformInfo *
3822 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3823 {
3824   ClutterTransformInfo *info;
3825
3826   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3827   if (info != NULL)
3828     return info;
3829
3830   return &default_transform_info;
3831 }
3832
3833 static void
3834 clutter_transform_info_free (gpointer data)
3835 {
3836   if (data != NULL)
3837     g_slice_free (ClutterTransformInfo, data);
3838 }
3839
3840 /*< private >
3841  * _clutter_actor_get_transform_info:
3842  * @self: a #ClutterActor
3843  *
3844  * Retrieves a pointer to the ClutterTransformInfo structure.
3845  *
3846  * If the actor does not have a ClutterTransformInfo associated to it, one
3847  * will be created and initialized to the default values.
3848  *
3849  * This function should be used for setters.
3850  *
3851  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3852  * instead.
3853  *
3854  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3855  *   structure
3856  */
3857 ClutterTransformInfo *
3858 _clutter_actor_get_transform_info (ClutterActor *self)
3859 {
3860   ClutterTransformInfo *info;
3861
3862   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3863   if (info == NULL)
3864     {
3865       info = g_slice_new (ClutterTransformInfo);
3866
3867       *info = default_transform_info;
3868
3869       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3870                                info,
3871                                clutter_transform_info_free);
3872     }
3873
3874   return info;
3875 }
3876
3877 /*< private >
3878  * clutter_actor_set_rotation_angle_internal:
3879  * @self: a #ClutterActor
3880  * @axis: the axis of the angle to change
3881  * @angle: the angle of rotation
3882  *
3883  * Sets the rotation angle on the given axis without affecting the
3884  * rotation center point.
3885  */
3886 static inline void
3887 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3888                                            ClutterRotateAxis  axis,
3889                                            gdouble            angle)
3890 {
3891   GObject *obj = G_OBJECT (self);
3892   ClutterTransformInfo *info;
3893
3894   info = _clutter_actor_get_transform_info (self);
3895
3896   g_object_freeze_notify (obj);
3897
3898   switch (axis)
3899     {
3900     case CLUTTER_X_AXIS:
3901       info->rx_angle = angle;
3902       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3903       break;
3904
3905     case CLUTTER_Y_AXIS:
3906       info->ry_angle = angle;
3907       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3908       break;
3909
3910     case CLUTTER_Z_AXIS:
3911       info->rz_angle = angle;
3912       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3913       break;
3914     }
3915
3916   self->priv->transform_valid = FALSE;
3917
3918   g_object_thaw_notify (obj);
3919
3920   clutter_actor_queue_redraw (self);
3921 }
3922
3923 static inline void
3924 clutter_actor_set_rotation_angle (ClutterActor      *self,
3925                                   ClutterRotateAxis  axis,
3926                                   gdouble            angle)
3927 {
3928   ClutterTransformInfo *info;
3929
3930   info = _clutter_actor_get_transform_info (self);
3931
3932   if (clutter_actor_get_easing_duration (self) != 0)
3933     {
3934       ClutterTransition *transition;
3935       GParamSpec *pspec = NULL;
3936       double *cur_angle_p = NULL;
3937
3938       switch (axis)
3939         {
3940         case CLUTTER_X_AXIS:
3941           cur_angle_p = &info->rx_angle;
3942           pspec = obj_props[PROP_ROTATION_ANGLE_X];
3943           break;
3944
3945         case CLUTTER_Y_AXIS:
3946           cur_angle_p = &info->ry_angle;
3947           pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3948           break;
3949
3950         case CLUTTER_Z_AXIS:
3951           cur_angle_p = &info->rz_angle;
3952           pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3953           break;
3954         }
3955
3956       g_assert (pspec != NULL);
3957       g_assert (cur_angle_p != NULL);
3958
3959       transition = _clutter_actor_get_transition (self, pspec);
3960       if (transition == NULL)
3961         {
3962           transition = _clutter_actor_create_transition (self, pspec,
3963                                                          *cur_angle_p,
3964                                                          angle);
3965           clutter_timeline_start (CLUTTER_TIMELINE (transition));
3966         }
3967       else
3968         _clutter_actor_update_transition (self, pspec, angle);
3969
3970       self->priv->transform_valid = FALSE;
3971       clutter_actor_queue_redraw (self);
3972     }
3973   else
3974     clutter_actor_set_rotation_angle_internal (self, axis, angle);
3975 }
3976
3977 /*< private >
3978  * clutter_actor_set_rotation_center_internal:
3979  * @self: a #ClutterActor
3980  * @axis: the axis of the center to change
3981  * @center: the coordinates of the rotation center
3982  *
3983  * Sets the rotation center on the given axis without affecting the
3984  * rotation angle.
3985  */
3986 static inline void
3987 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3988                                             ClutterRotateAxis    axis,
3989                                             const ClutterVertex *center)
3990 {
3991   GObject *obj = G_OBJECT (self);
3992   ClutterTransformInfo *info;
3993   ClutterVertex v = { 0, 0, 0 };
3994
3995   info = _clutter_actor_get_transform_info (self);
3996
3997   if (center != NULL)
3998     v = *center;
3999
4000   g_object_freeze_notify (obj);
4001
4002   switch (axis)
4003     {
4004     case CLUTTER_X_AXIS:
4005       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4006       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4007       break;
4008
4009     case CLUTTER_Y_AXIS:
4010       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4011       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4012       break;
4013
4014     case CLUTTER_Z_AXIS:
4015       /* if the previously set rotation center was fractional, then
4016        * setting explicit coordinates will have to notify the
4017        * :rotation-center-z-gravity property as well
4018        */
4019       if (info->rz_center.is_fractional)
4020         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4021
4022       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4023       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4024       break;
4025     }
4026
4027   self->priv->transform_valid = FALSE;
4028
4029   g_object_thaw_notify (obj);
4030
4031   clutter_actor_queue_redraw (self);
4032 }
4033
4034 static void
4035 clutter_actor_animate_scale_factor (ClutterActor *self,
4036                                     double        old_factor,
4037                                     double        new_factor,
4038                                     GParamSpec   *pspec)
4039 {
4040   ClutterTransition *transition;
4041
4042   transition = _clutter_actor_get_transition (self, pspec);
4043   if (transition == NULL)
4044     {
4045       transition = _clutter_actor_create_transition (self, pspec,
4046                                                      old_factor,
4047                                                      new_factor);
4048       clutter_timeline_start (CLUTTER_TIMELINE (transition));
4049     }
4050   else
4051     _clutter_actor_update_transition (self, pspec, new_factor);
4052
4053
4054   self->priv->transform_valid = FALSE;
4055   clutter_actor_queue_redraw (self);
4056 }
4057
4058 static void
4059 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4060                                          double factor,
4061                                          GParamSpec *pspec)
4062 {
4063   GObject *obj = G_OBJECT (self);
4064   ClutterTransformInfo *info;
4065
4066   info = _clutter_actor_get_transform_info (self);
4067
4068   if (pspec == obj_props[PROP_SCALE_X])
4069     info->scale_x = factor;
4070   else
4071     info->scale_y = factor;
4072
4073   self->priv->transform_valid = FALSE;
4074   clutter_actor_queue_redraw (self);
4075   g_object_notify_by_pspec (obj, pspec);
4076 }
4077
4078 static inline void
4079 clutter_actor_set_scale_factor (ClutterActor      *self,
4080                                 ClutterRotateAxis  axis,
4081                                 gdouble            factor)
4082 {
4083   GObject *obj = G_OBJECT (self);
4084   ClutterTransformInfo *info;
4085   GParamSpec *pspec;
4086
4087   info = _clutter_actor_get_transform_info (self);
4088
4089   g_object_freeze_notify (obj);
4090
4091   switch (axis)
4092     {
4093     case CLUTTER_X_AXIS:
4094       pspec = obj_props[PROP_SCALE_X];
4095
4096       if (clutter_actor_get_easing_duration (self) != 0)
4097         clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
4098       else
4099         clutter_actor_set_scale_factor_internal (self, factor, pspec);
4100       break;
4101
4102     case CLUTTER_Y_AXIS:
4103       pspec = obj_props[PROP_SCALE_Y];
4104
4105       if (clutter_actor_get_easing_duration (self) != 0)
4106         clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4107       else
4108         clutter_actor_set_scale_factor_internal (self, factor, pspec);
4109       break;
4110
4111     default:
4112       g_assert_not_reached ();
4113     }
4114
4115   g_object_thaw_notify (obj);
4116 }
4117
4118 static inline void
4119 clutter_actor_set_scale_center (ClutterActor      *self,
4120                                 ClutterRotateAxis  axis,
4121                                 gfloat             coord)
4122 {
4123   GObject *obj = G_OBJECT (self);
4124   ClutterTransformInfo *info;
4125   gfloat center_x, center_y;
4126
4127   info = _clutter_actor_get_transform_info (self);
4128
4129   g_object_freeze_notify (obj);
4130
4131   /* get the current scale center coordinates */
4132   clutter_anchor_coord_get_units (self, &info->scale_center,
4133                                   &center_x,
4134                                   &center_y,
4135                                   NULL);
4136
4137   /* we need to notify this too, because setting explicit coordinates will
4138    * change the gravity as a side effect
4139    */
4140   if (info->scale_center.is_fractional)
4141     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4142
4143   switch (axis)
4144     {
4145     case CLUTTER_X_AXIS:
4146       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4147       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4148       break;
4149
4150     case CLUTTER_Y_AXIS:
4151       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4152       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4153       break;
4154
4155     default:
4156       g_assert_not_reached ();
4157     }
4158
4159   self->priv->transform_valid = FALSE;
4160
4161   clutter_actor_queue_redraw (self);
4162
4163   g_object_thaw_notify (obj);
4164 }
4165
4166 static inline void
4167 clutter_actor_set_anchor_coord (ClutterActor      *self,
4168                                 ClutterRotateAxis  axis,
4169                                 gfloat             coord)
4170 {
4171   GObject *obj = G_OBJECT (self);
4172   ClutterTransformInfo *info;
4173   gfloat anchor_x, anchor_y;
4174
4175   info = _clutter_actor_get_transform_info (self);
4176
4177   g_object_freeze_notify (obj);
4178
4179   clutter_anchor_coord_get_units (self, &info->anchor,
4180                                   &anchor_x,
4181                                   &anchor_y,
4182                                   NULL);
4183
4184   if (info->anchor.is_fractional)
4185     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4186
4187   switch (axis)
4188     {
4189     case CLUTTER_X_AXIS:
4190       clutter_anchor_coord_set_units (&info->anchor,
4191                                       coord,
4192                                       anchor_y,
4193                                       0.0);
4194       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4195       break;
4196
4197     case CLUTTER_Y_AXIS:
4198       clutter_anchor_coord_set_units (&info->anchor,
4199                                       anchor_x,
4200                                       coord,
4201                                       0.0);
4202       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4203       break;
4204
4205     default:
4206       g_assert_not_reached ();
4207     }
4208
4209   self->priv->transform_valid = FALSE;
4210
4211   clutter_actor_queue_redraw (self);
4212
4213   g_object_thaw_notify (obj);
4214 }
4215
4216 static void
4217 clutter_actor_set_property (GObject      *object,
4218                             guint         prop_id,
4219                             const GValue *value,
4220                             GParamSpec   *pspec)
4221 {
4222   ClutterActor *actor = CLUTTER_ACTOR (object);
4223   ClutterActorPrivate *priv = actor->priv;
4224
4225   switch (prop_id)
4226     {
4227     case PROP_X:
4228       clutter_actor_set_x (actor, g_value_get_float (value));
4229       break;
4230
4231     case PROP_Y:
4232       clutter_actor_set_y (actor, g_value_get_float (value));
4233       break;
4234
4235     case PROP_WIDTH:
4236       clutter_actor_set_width (actor, g_value_get_float (value));
4237       break;
4238
4239     case PROP_HEIGHT:
4240       clutter_actor_set_height (actor, g_value_get_float (value));
4241       break;
4242
4243     case PROP_FIXED_X:
4244       clutter_actor_set_x (actor, g_value_get_float (value));
4245       break;
4246
4247     case PROP_FIXED_Y:
4248       clutter_actor_set_y (actor, g_value_get_float (value));
4249       break;
4250
4251     case PROP_FIXED_POSITION_SET:
4252       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4253       break;
4254
4255     case PROP_MIN_WIDTH:
4256       clutter_actor_set_min_width (actor, g_value_get_float (value));
4257       break;
4258
4259     case PROP_MIN_HEIGHT:
4260       clutter_actor_set_min_height (actor, g_value_get_float (value));
4261       break;
4262
4263     case PROP_NATURAL_WIDTH:
4264       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4265       break;
4266
4267     case PROP_NATURAL_HEIGHT:
4268       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4269       break;
4270
4271     case PROP_MIN_WIDTH_SET:
4272       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4273       break;
4274
4275     case PROP_MIN_HEIGHT_SET:
4276       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4277       break;
4278
4279     case PROP_NATURAL_WIDTH_SET:
4280       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4281       break;
4282
4283     case PROP_NATURAL_HEIGHT_SET:
4284       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4285       break;
4286
4287     case PROP_REQUEST_MODE:
4288       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4289       break;
4290
4291     case PROP_DEPTH:
4292       clutter_actor_set_depth (actor, g_value_get_float (value));
4293       break;
4294
4295     case PROP_OPACITY:
4296       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4297       break;
4298
4299     case PROP_OFFSCREEN_REDIRECT:
4300       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4301       break;
4302
4303     case PROP_NAME:
4304       clutter_actor_set_name (actor, g_value_get_string (value));
4305       break;
4306
4307     case PROP_VISIBLE:
4308       if (g_value_get_boolean (value) == TRUE)
4309         clutter_actor_show (actor);
4310       else
4311         clutter_actor_hide (actor);
4312       break;
4313
4314     case PROP_SCALE_X:
4315       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4316                                       g_value_get_double (value));
4317       break;
4318
4319     case PROP_SCALE_Y:
4320       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4321                                       g_value_get_double (value));
4322       break;
4323
4324     case PROP_SCALE_CENTER_X:
4325       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4326                                       g_value_get_float (value));
4327       break;
4328
4329     case PROP_SCALE_CENTER_Y:
4330       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4331                                       g_value_get_float (value));
4332       break;
4333
4334     case PROP_SCALE_GRAVITY:
4335       {
4336         const ClutterTransformInfo *info;
4337         ClutterGravity gravity;
4338
4339         info = _clutter_actor_get_transform_info_or_defaults (actor);
4340         gravity = g_value_get_enum (value);
4341
4342         clutter_actor_set_scale_with_gravity (actor,
4343                                               info->scale_x,
4344                                               info->scale_y,
4345                                               gravity);
4346       }
4347       break;
4348
4349     case PROP_CLIP:
4350       {
4351         const ClutterGeometry *geom = g_value_get_boxed (value);
4352
4353         clutter_actor_set_clip (actor,
4354                                 geom->x, geom->y,
4355                                 geom->width, geom->height);
4356       }
4357       break;
4358
4359     case PROP_CLIP_TO_ALLOCATION:
4360       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4361       break;
4362
4363     case PROP_REACTIVE:
4364       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4365       break;
4366
4367     case PROP_ROTATION_ANGLE_X:
4368       clutter_actor_set_rotation_angle (actor,
4369                                         CLUTTER_X_AXIS,
4370                                         g_value_get_double (value));
4371       break;
4372
4373     case PROP_ROTATION_ANGLE_Y:
4374       clutter_actor_set_rotation_angle (actor,
4375                                         CLUTTER_Y_AXIS,
4376                                         g_value_get_double (value));
4377       break;
4378
4379     case PROP_ROTATION_ANGLE_Z:
4380       clutter_actor_set_rotation_angle (actor,
4381                                         CLUTTER_Z_AXIS,
4382                                         g_value_get_double (value));
4383       break;
4384
4385     case PROP_ROTATION_CENTER_X:
4386       clutter_actor_set_rotation_center_internal (actor,
4387                                                   CLUTTER_X_AXIS,
4388                                                   g_value_get_boxed (value));
4389       break;
4390
4391     case PROP_ROTATION_CENTER_Y:
4392       clutter_actor_set_rotation_center_internal (actor,
4393                                                   CLUTTER_Y_AXIS,
4394                                                   g_value_get_boxed (value));
4395       break;
4396
4397     case PROP_ROTATION_CENTER_Z:
4398       clutter_actor_set_rotation_center_internal (actor,
4399                                                   CLUTTER_Z_AXIS,
4400                                                   g_value_get_boxed (value));
4401       break;
4402
4403     case PROP_ROTATION_CENTER_Z_GRAVITY:
4404       {
4405         const ClutterTransformInfo *info;
4406
4407         info = _clutter_actor_get_transform_info_or_defaults (actor);
4408         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4409                                                    g_value_get_enum (value));
4410       }
4411       break;
4412
4413     case PROP_ANCHOR_X:
4414       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4415                                       g_value_get_float (value));
4416       break;
4417
4418     case PROP_ANCHOR_Y:
4419       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4420                                       g_value_get_float (value));
4421       break;
4422
4423     case PROP_ANCHOR_GRAVITY:
4424       clutter_actor_set_anchor_point_from_gravity (actor,
4425                                                    g_value_get_enum (value));
4426       break;
4427
4428     case PROP_SHOW_ON_SET_PARENT:
4429       priv->show_on_set_parent = g_value_get_boolean (value);
4430       break;
4431
4432     case PROP_TEXT_DIRECTION:
4433       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4434       break;
4435
4436     case PROP_ACTIONS:
4437       clutter_actor_add_action (actor, g_value_get_object (value));
4438       break;
4439
4440     case PROP_CONSTRAINTS:
4441       clutter_actor_add_constraint (actor, g_value_get_object (value));
4442       break;
4443
4444     case PROP_EFFECT:
4445       clutter_actor_add_effect (actor, g_value_get_object (value));
4446       break;
4447
4448     case PROP_LAYOUT_MANAGER:
4449       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4450       break;
4451
4452     case PROP_X_ALIGN:
4453       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4454       break;
4455
4456     case PROP_Y_ALIGN:
4457       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4458       break;
4459
4460     case PROP_MARGIN_TOP:
4461       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4462       break;
4463
4464     case PROP_MARGIN_BOTTOM:
4465       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4466       break;
4467
4468     case PROP_MARGIN_LEFT:
4469       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4470       break;
4471
4472     case PROP_MARGIN_RIGHT:
4473       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4474       break;
4475
4476     case PROP_BACKGROUND_COLOR:
4477       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4478       break;
4479
4480     case PROP_CONTENT:
4481       clutter_actor_set_content (actor, g_value_get_object (value));
4482       break;
4483
4484     case PROP_CONTENT_GRAVITY:
4485       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4486       break;
4487
4488     case PROP_MINIFICATION_FILTER:
4489       clutter_actor_set_content_scaling_filters (actor,
4490                                                  g_value_get_enum (value),
4491                                                  actor->priv->mag_filter);
4492       break;
4493
4494     case PROP_MAGNIFICATION_FILTER:
4495       clutter_actor_set_content_scaling_filters (actor,
4496                                                  actor->priv->min_filter,
4497                                                  g_value_get_enum (value));
4498       break;
4499
4500     default:
4501       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4502       break;
4503     }
4504 }
4505
4506 static void
4507 clutter_actor_get_property (GObject    *object,
4508                             guint       prop_id,
4509                             GValue     *value,
4510                             GParamSpec *pspec)
4511 {
4512   ClutterActor *actor = CLUTTER_ACTOR (object);
4513   ClutterActorPrivate *priv = actor->priv;
4514
4515   switch (prop_id)
4516     {
4517     case PROP_X:
4518       g_value_set_float (value, clutter_actor_get_x (actor));
4519       break;
4520
4521     case PROP_Y:
4522       g_value_set_float (value, clutter_actor_get_y (actor));
4523       break;
4524
4525     case PROP_WIDTH:
4526       g_value_set_float (value, clutter_actor_get_width (actor));
4527       break;
4528
4529     case PROP_HEIGHT:
4530       g_value_set_float (value, clutter_actor_get_height (actor));
4531       break;
4532
4533     case PROP_FIXED_X:
4534       {
4535         const ClutterLayoutInfo *info;
4536
4537         info = _clutter_actor_get_layout_info_or_defaults (actor);
4538         g_value_set_float (value, info->fixed_x);
4539       }
4540       break;
4541
4542     case PROP_FIXED_Y:
4543       {
4544         const ClutterLayoutInfo *info;
4545
4546         info = _clutter_actor_get_layout_info_or_defaults (actor);
4547         g_value_set_float (value, info->fixed_y);
4548       }
4549       break;
4550
4551     case PROP_FIXED_POSITION_SET:
4552       g_value_set_boolean (value, priv->position_set);
4553       break;
4554
4555     case PROP_MIN_WIDTH:
4556       {
4557         const ClutterLayoutInfo *info;
4558
4559         info = _clutter_actor_get_layout_info_or_defaults (actor);
4560         g_value_set_float (value, info->min_width);
4561       }
4562       break;
4563
4564     case PROP_MIN_HEIGHT:
4565       {
4566         const ClutterLayoutInfo *info;
4567
4568         info = _clutter_actor_get_layout_info_or_defaults (actor);
4569         g_value_set_float (value, info->min_height);
4570       }
4571       break;
4572
4573     case PROP_NATURAL_WIDTH:
4574       {
4575         const ClutterLayoutInfo *info;
4576
4577         info = _clutter_actor_get_layout_info_or_defaults (actor);
4578         g_value_set_float (value, info->natural_width);
4579       }
4580       break;
4581
4582     case PROP_NATURAL_HEIGHT:
4583       {
4584         const ClutterLayoutInfo *info;
4585
4586         info = _clutter_actor_get_layout_info_or_defaults (actor);
4587         g_value_set_float (value, info->natural_height);
4588       }
4589       break;
4590
4591     case PROP_MIN_WIDTH_SET:
4592       g_value_set_boolean (value, priv->min_width_set);
4593       break;
4594
4595     case PROP_MIN_HEIGHT_SET:
4596       g_value_set_boolean (value, priv->min_height_set);
4597       break;
4598
4599     case PROP_NATURAL_WIDTH_SET:
4600       g_value_set_boolean (value, priv->natural_width_set);
4601       break;
4602
4603     case PROP_NATURAL_HEIGHT_SET:
4604       g_value_set_boolean (value, priv->natural_height_set);
4605       break;
4606
4607     case PROP_REQUEST_MODE:
4608       g_value_set_enum (value, priv->request_mode);
4609       break;
4610
4611     case PROP_ALLOCATION:
4612       g_value_set_boxed (value, &priv->allocation);
4613       break;
4614
4615     case PROP_DEPTH:
4616       g_value_set_float (value, clutter_actor_get_depth (actor));
4617       break;
4618
4619     case PROP_OPACITY:
4620       g_value_set_uint (value, priv->opacity);
4621       break;
4622
4623     case PROP_OFFSCREEN_REDIRECT:
4624       g_value_set_enum (value, priv->offscreen_redirect);
4625       break;
4626
4627     case PROP_NAME:
4628       g_value_set_string (value, priv->name);
4629       break;
4630
4631     case PROP_VISIBLE:
4632       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4633       break;
4634
4635     case PROP_MAPPED:
4636       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4637       break;
4638
4639     case PROP_REALIZED:
4640       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4641       break;
4642
4643     case PROP_HAS_CLIP:
4644       g_value_set_boolean (value, priv->has_clip);
4645       break;
4646
4647     case PROP_CLIP:
4648       {
4649         ClutterGeometry clip;
4650
4651         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4652         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4653         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4654         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4655
4656         g_value_set_boxed (value, &clip);
4657       }
4658       break;
4659
4660     case PROP_CLIP_TO_ALLOCATION:
4661       g_value_set_boolean (value, priv->clip_to_allocation);
4662       break;
4663
4664     case PROP_SCALE_X:
4665       {
4666         const ClutterTransformInfo *info;
4667
4668         info = _clutter_actor_get_transform_info_or_defaults (actor);
4669         g_value_set_double (value, info->scale_x);
4670       }
4671       break;
4672
4673     case PROP_SCALE_Y:
4674       {
4675         const ClutterTransformInfo *info;
4676
4677         info = _clutter_actor_get_transform_info_or_defaults (actor);
4678         g_value_set_double (value, info->scale_y);
4679       }
4680       break;
4681
4682     case PROP_SCALE_CENTER_X:
4683       {
4684         gfloat center;
4685
4686         clutter_actor_get_scale_center (actor, &center, NULL);
4687
4688         g_value_set_float (value, center);
4689       }
4690       break;
4691
4692     case PROP_SCALE_CENTER_Y:
4693       {
4694         gfloat center;
4695
4696         clutter_actor_get_scale_center (actor, NULL, &center);
4697
4698         g_value_set_float (value, center);
4699       }
4700       break;
4701
4702     case PROP_SCALE_GRAVITY:
4703       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4704       break;
4705
4706     case PROP_REACTIVE:
4707       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4708       break;
4709
4710     case PROP_ROTATION_ANGLE_X:
4711       {
4712         const ClutterTransformInfo *info;
4713
4714         info = _clutter_actor_get_transform_info_or_defaults (actor);
4715         g_value_set_double (value, info->rx_angle);
4716       }
4717       break;
4718
4719     case PROP_ROTATION_ANGLE_Y:
4720       {
4721         const ClutterTransformInfo *info;
4722
4723         info = _clutter_actor_get_transform_info_or_defaults (actor);
4724         g_value_set_double (value, info->ry_angle);
4725       }
4726       break;
4727
4728     case PROP_ROTATION_ANGLE_Z:
4729       {
4730         const ClutterTransformInfo *info;
4731
4732         info = _clutter_actor_get_transform_info_or_defaults (actor);
4733         g_value_set_double (value, info->rz_angle);
4734       }
4735       break;
4736
4737     case PROP_ROTATION_CENTER_X:
4738       {
4739         ClutterVertex center;
4740
4741         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4742                                     &center.x,
4743                                     &center.y,
4744                                     &center.z);
4745
4746         g_value_set_boxed (value, &center);
4747       }
4748       break;
4749
4750     case PROP_ROTATION_CENTER_Y:
4751       {
4752         ClutterVertex center;
4753
4754         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4755                                     &center.x,
4756                                     &center.y,
4757                                     &center.z);
4758
4759         g_value_set_boxed (value, &center);
4760       }
4761       break;
4762
4763     case PROP_ROTATION_CENTER_Z:
4764       {
4765         ClutterVertex center;
4766
4767         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4768                                     &center.x,
4769                                     &center.y,
4770                                     &center.z);
4771
4772         g_value_set_boxed (value, &center);
4773       }
4774       break;
4775
4776     case PROP_ROTATION_CENTER_Z_GRAVITY:
4777       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4778       break;
4779
4780     case PROP_ANCHOR_X:
4781       {
4782         const ClutterTransformInfo *info;
4783         gfloat anchor_x;
4784
4785         info = _clutter_actor_get_transform_info_or_defaults (actor);
4786         clutter_anchor_coord_get_units (actor, &info->anchor,
4787                                         &anchor_x,
4788                                         NULL,
4789                                         NULL);
4790         g_value_set_float (value, anchor_x);
4791       }
4792       break;
4793
4794     case PROP_ANCHOR_Y:
4795       {
4796         const ClutterTransformInfo *info;
4797         gfloat anchor_y;
4798
4799         info = _clutter_actor_get_transform_info_or_defaults (actor);
4800         clutter_anchor_coord_get_units (actor, &info->anchor,
4801                                         NULL,
4802                                         &anchor_y,
4803                                         NULL);
4804         g_value_set_float (value, anchor_y);
4805       }
4806       break;
4807
4808     case PROP_ANCHOR_GRAVITY:
4809       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4810       break;
4811
4812     case PROP_SHOW_ON_SET_PARENT:
4813       g_value_set_boolean (value, priv->show_on_set_parent);
4814       break;
4815
4816     case PROP_TEXT_DIRECTION:
4817       g_value_set_enum (value, priv->text_direction);
4818       break;
4819
4820     case PROP_HAS_POINTER:
4821       g_value_set_boolean (value, priv->has_pointer);
4822       break;
4823
4824     case PROP_LAYOUT_MANAGER:
4825       g_value_set_object (value, priv->layout_manager);
4826       break;
4827
4828     case PROP_X_ALIGN:
4829       {
4830         const ClutterLayoutInfo *info;
4831
4832         info = _clutter_actor_get_layout_info_or_defaults (actor);
4833         g_value_set_enum (value, info->x_align);
4834       }
4835       break;
4836
4837     case PROP_Y_ALIGN:
4838       {
4839         const ClutterLayoutInfo *info;
4840
4841         info = _clutter_actor_get_layout_info_or_defaults (actor);
4842         g_value_set_enum (value, info->y_align);
4843       }
4844       break;
4845
4846     case PROP_MARGIN_TOP:
4847       {
4848         const ClutterLayoutInfo *info;
4849
4850         info = _clutter_actor_get_layout_info_or_defaults (actor);
4851         g_value_set_float (value, info->margin.top);
4852       }
4853       break;
4854
4855     case PROP_MARGIN_BOTTOM:
4856       {
4857         const ClutterLayoutInfo *info;
4858
4859         info = _clutter_actor_get_layout_info_or_defaults (actor);
4860         g_value_set_float (value, info->margin.bottom);
4861       }
4862       break;
4863
4864     case PROP_MARGIN_LEFT:
4865       {
4866         const ClutterLayoutInfo *info;
4867
4868         info = _clutter_actor_get_layout_info_or_defaults (actor);
4869         g_value_set_float (value, info->margin.left);
4870       }
4871       break;
4872
4873     case PROP_MARGIN_RIGHT:
4874       {
4875         const ClutterLayoutInfo *info;
4876
4877         info = _clutter_actor_get_layout_info_or_defaults (actor);
4878         g_value_set_float (value, info->margin.right);
4879       }
4880       break;
4881
4882     case PROP_BACKGROUND_COLOR_SET:
4883       g_value_set_boolean (value, priv->bg_color_set);
4884       break;
4885
4886     case PROP_BACKGROUND_COLOR:
4887       g_value_set_boxed (value, &priv->bg_color);
4888       break;
4889
4890     case PROP_FIRST_CHILD:
4891       g_value_set_object (value, priv->first_child);
4892       break;
4893
4894     case PROP_LAST_CHILD:
4895       g_value_set_object (value, priv->last_child);
4896       break;
4897
4898     case PROP_CONTENT:
4899       g_value_set_object (value, priv->content);
4900       break;
4901
4902     case PROP_CONTENT_GRAVITY:
4903       g_value_set_enum (value, priv->content_gravity);
4904       break;
4905
4906     case PROP_CONTENT_BOX:
4907       {
4908         ClutterActorBox box = { 0, };
4909
4910         clutter_actor_get_content_box (actor, &box);
4911         g_value_set_boxed (value, &box);
4912       }
4913       break;
4914
4915     case PROP_MINIFICATION_FILTER:
4916       g_value_set_enum (value, priv->min_filter);
4917       break;
4918
4919     case PROP_MAGNIFICATION_FILTER:
4920       g_value_set_enum (value, priv->mag_filter);
4921       break;
4922
4923     default:
4924       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4925       break;
4926     }
4927 }
4928
4929 static void
4930 clutter_actor_dispose (GObject *object)
4931 {
4932   ClutterActor *self = CLUTTER_ACTOR (object);
4933   ClutterActorPrivate *priv = self->priv;
4934
4935   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4936                 priv->id,
4937                 g_type_name (G_OBJECT_TYPE (self)),
4938                 object->ref_count);
4939
4940   g_signal_emit (self, actor_signals[DESTROY], 0);
4941
4942   /* avoid recursing when called from clutter_actor_destroy() */
4943   if (priv->parent != NULL)
4944     {
4945       ClutterActor *parent = priv->parent;
4946
4947       /* go through the Container implementation unless this
4948        * is an internal child and has been marked as such.
4949        *
4950        * removing the actor from its parent will reset the
4951        * realized and mapped states.
4952        */
4953       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4954         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4955       else
4956         clutter_actor_remove_child_internal (parent, self,
4957                                              REMOVE_CHILD_LEGACY_FLAGS);
4958     }
4959
4960   /* parent must be gone at this point */
4961   g_assert (priv->parent == NULL);
4962
4963   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4964     {
4965       /* can't be mapped or realized with no parent */
4966       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4967       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4968     }
4969
4970   g_clear_object (&priv->pango_context);
4971   g_clear_object (&priv->actions);
4972   g_clear_object (&priv->constraints);
4973   g_clear_object (&priv->effects);
4974   g_clear_object (&priv->flatten_effect);
4975
4976   if (priv->layout_manager != NULL)
4977     {
4978       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4979       g_clear_object (&priv->layout_manager);
4980     }
4981
4982   if (priv->content != NULL)
4983     {
4984       _clutter_content_detached (priv->content, self);
4985       g_clear_object (&priv->content);
4986     }
4987
4988   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4989 }
4990
4991 static void
4992 clutter_actor_finalize (GObject *object)
4993 {
4994   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4995
4996   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4997                 priv->name != NULL ? priv->name : "<none>",
4998                 priv->id,
4999                 g_type_name (G_OBJECT_TYPE (object)));
5000
5001   _clutter_context_release_id (priv->id);
5002
5003   g_free (priv->name);
5004
5005   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5006 }
5007
5008
5009 /**
5010  * clutter_actor_get_accessible:
5011  * @self: a #ClutterActor
5012  *
5013  * Returns the accessible object that describes the actor to an
5014  * assistive technology.
5015  *
5016  * If no class-specific #AtkObject implementation is available for the
5017  * actor instance in question, it will inherit an #AtkObject
5018  * implementation from the first ancestor class for which such an
5019  * implementation is defined.
5020  *
5021  * The documentation of the <ulink
5022  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5023  * library contains more information about accessible objects and
5024  * their uses.
5025  *
5026  * Returns: (transfer none): the #AtkObject associated with @actor
5027  */
5028 AtkObject *
5029 clutter_actor_get_accessible (ClutterActor *self)
5030 {
5031   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5032
5033   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5034 }
5035
5036 static AtkObject *
5037 clutter_actor_real_get_accessible (ClutterActor *actor)
5038 {
5039   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5040 }
5041
5042 static AtkObject *
5043 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5044 {
5045   AtkObject *accessible;
5046
5047   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5048   if (accessible != NULL)
5049     g_object_ref (accessible);
5050
5051   return accessible;
5052 }
5053
5054 static void
5055 atk_implementor_iface_init (AtkImplementorIface *iface)
5056 {
5057   iface->ref_accessible = _clutter_actor_ref_accessible;
5058 }
5059
5060 static gboolean
5061 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5062                                            ClutterPaintVolume *volume)
5063 {
5064   ClutterActorPrivate *priv = self->priv;
5065   gboolean res = FALSE;
5066
5067   /* we start from the allocation */
5068   clutter_paint_volume_set_width (volume,
5069                                   priv->allocation.x2 - priv->allocation.x1);
5070   clutter_paint_volume_set_height (volume,
5071                                    priv->allocation.y2 - priv->allocation.y1);
5072
5073   /* if the actor has a clip set then we have a pretty definite
5074    * size for the paint volume: the actor cannot possibly paint
5075    * outside the clip region.
5076    */
5077   if (priv->clip_to_allocation)
5078     {
5079       /* the allocation has already been set, so we just flip the
5080        * return value
5081        */
5082       res = TRUE;
5083     }
5084   else
5085     {
5086       ClutterActor *child;
5087
5088       if (priv->has_clip &&
5089           priv->clip.width >= 0 &&
5090           priv->clip.height >= 0)
5091         {
5092           ClutterVertex origin;
5093
5094           origin.x = priv->clip.x;
5095           origin.y = priv->clip.y;
5096           origin.z = 0;
5097
5098           clutter_paint_volume_set_origin (volume, &origin);
5099           clutter_paint_volume_set_width (volume, priv->clip.width);
5100           clutter_paint_volume_set_height (volume, priv->clip.height);
5101
5102           res = TRUE;
5103         }
5104
5105       /* if we don't have children we just bail out here... */
5106       if (priv->n_children == 0)
5107         return res;
5108
5109       /* ...but if we have children then we ask for their paint volume in
5110        * our coordinates. if any of our children replies that it doesn't
5111        * have a paint volume, we bail out
5112        */
5113       for (child = priv->first_child;
5114            child != NULL;
5115            child = child->priv->next_sibling)
5116         {
5117           const ClutterPaintVolume *child_volume;
5118
5119           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5120           if (child_volume == NULL)
5121             {
5122               res = FALSE;
5123               break;
5124             }
5125
5126           clutter_paint_volume_union (volume, child_volume);
5127           res = TRUE;
5128         }
5129     }
5130
5131   return res;
5132
5133 }
5134
5135 static gboolean
5136 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5137                                      ClutterPaintVolume *volume)
5138 {
5139   ClutterActorClass *klass;
5140   gboolean res;
5141
5142   klass = CLUTTER_ACTOR_GET_CLASS (self);
5143
5144   /* XXX - this thoroughly sucks, but we don't want to penalize users
5145    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5146    * redraw. This should go away in 2.0.
5147    */
5148   if (klass->paint == clutter_actor_real_paint &&
5149       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5150     {
5151       res = TRUE;
5152     }
5153   else
5154     {
5155       /* this is the default return value: we cannot know if a class
5156        * is going to paint outside its allocation, so we take the
5157        * conservative approach.
5158        */
5159       res = FALSE;
5160     }
5161
5162   if (clutter_actor_update_default_paint_volume (self, volume))
5163     return res;
5164
5165   return FALSE;
5166 }
5167
5168 /**
5169  * clutter_actor_get_default_paint_volume:
5170  * @self: a #ClutterActor
5171  *
5172  * Retrieves the default paint volume for @self.
5173  *
5174  * This function provides the same #ClutterPaintVolume that would be
5175  * computed by the default implementation inside #ClutterActor of the
5176  * #ClutterActorClass.get_paint_volume() virtual function.
5177  *
5178  * This function should only be used by #ClutterActor subclasses that
5179  * cannot chain up to the parent implementation when computing their
5180  * paint volume.
5181  *
5182  * Return value: (transfer none): a pointer to the default
5183  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5184  *   the actor could not compute a valid paint volume. The returned value
5185  *   is not guaranteed to be stable across multiple frames, so if you
5186  *   want to retain it, you will need to copy it using
5187  *   clutter_paint_volume_copy().
5188  *
5189  * Since: 1.10
5190  */
5191 const ClutterPaintVolume *
5192 clutter_actor_get_default_paint_volume (ClutterActor *self)
5193 {
5194   ClutterPaintVolume volume;
5195   ClutterPaintVolume *res;
5196
5197   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5198
5199   res = NULL;
5200   _clutter_paint_volume_init_static (&volume, self);
5201   if (clutter_actor_update_default_paint_volume (self, &volume))
5202     {
5203       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5204
5205       if (stage != NULL)
5206         {
5207           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5208           _clutter_paint_volume_copy_static (&volume, res);
5209         }
5210     }
5211
5212   clutter_paint_volume_free (&volume);
5213
5214   return res;
5215 }
5216
5217 static gboolean
5218 clutter_actor_real_has_overlaps (ClutterActor *self)
5219 {
5220   /* By default we'll assume that all actors need an offscreen redirect to get
5221    * the correct opacity. Actors such as ClutterTexture that would never need
5222    * an offscreen redirect can override this to return FALSE. */
5223   return TRUE;
5224 }
5225
5226 static void
5227 clutter_actor_real_destroy (ClutterActor *actor)
5228 {
5229   ClutterActorIter iter;
5230
5231   clutter_actor_iter_init (&iter, actor);
5232   while (clutter_actor_iter_next (&iter, NULL))
5233     clutter_actor_iter_destroy (&iter);
5234 }
5235
5236 static GObject *
5237 clutter_actor_constructor (GType gtype,
5238                            guint n_props,
5239                            GObjectConstructParam *props)
5240 {
5241   GObjectClass *gobject_class;
5242   ClutterActor *self;
5243   GObject *retval;
5244
5245   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5246   retval = gobject_class->constructor (gtype, n_props, props);
5247   self = CLUTTER_ACTOR (retval);
5248
5249   if (self->priv->layout_manager == NULL)
5250     {
5251       ClutterLayoutManager *default_layout;
5252
5253       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5254
5255       default_layout = clutter_fixed_layout_new ();
5256       clutter_actor_set_layout_manager (self, default_layout);
5257     }
5258
5259   return retval;
5260 }
5261
5262 static void
5263 clutter_actor_class_init (ClutterActorClass *klass)
5264 {
5265   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5266
5267   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5268   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5269   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5270   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5271
5272   object_class->constructor = clutter_actor_constructor;
5273   object_class->set_property = clutter_actor_set_property;
5274   object_class->get_property = clutter_actor_get_property;
5275   object_class->dispose = clutter_actor_dispose;
5276   object_class->finalize = clutter_actor_finalize;
5277
5278   klass->show = clutter_actor_real_show;
5279   klass->show_all = clutter_actor_show;
5280   klass->hide = clutter_actor_real_hide;
5281   klass->hide_all = clutter_actor_hide;
5282   klass->map = clutter_actor_real_map;
5283   klass->unmap = clutter_actor_real_unmap;
5284   klass->unrealize = clutter_actor_real_unrealize;
5285   klass->pick = clutter_actor_real_pick;
5286   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5287   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5288   klass->allocate = clutter_actor_real_allocate;
5289   klass->queue_redraw = clutter_actor_real_queue_redraw;
5290   klass->queue_relayout = clutter_actor_real_queue_relayout;
5291   klass->apply_transform = clutter_actor_real_apply_transform;
5292   klass->get_accessible = clutter_actor_real_get_accessible;
5293   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5294   klass->has_overlaps = clutter_actor_real_has_overlaps;
5295   klass->paint = clutter_actor_real_paint;
5296   klass->destroy = clutter_actor_real_destroy;
5297
5298   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5299
5300   /**
5301    * ClutterActor:x:
5302    *
5303    * X coordinate of the actor in pixels. If written, forces a fixed
5304    * position for the actor. If read, returns the fixed position if any,
5305    * otherwise the allocation if available, otherwise 0.
5306    *
5307    * The #ClutterActor:x property is animatable.
5308    */
5309   obj_props[PROP_X] =
5310     g_param_spec_float ("x",
5311                         P_("X coordinate"),
5312                         P_("X coordinate of the actor"),
5313                         -G_MAXFLOAT, G_MAXFLOAT,
5314                         0.0,
5315                         G_PARAM_READWRITE |
5316                         G_PARAM_STATIC_STRINGS |
5317                         CLUTTER_PARAM_ANIMATABLE);
5318
5319   /**
5320    * ClutterActor:y:
5321    *
5322    * Y coordinate of the actor in pixels. If written, forces a fixed
5323    * position for the actor.  If read, returns the fixed position if
5324    * any, otherwise the allocation if available, otherwise 0.
5325    *
5326    * The #ClutterActor:y property is animatable.
5327    */
5328   obj_props[PROP_Y] =
5329     g_param_spec_float ("y",
5330                         P_("Y coordinate"),
5331                         P_("Y coordinate of the actor"),
5332                         -G_MAXFLOAT, G_MAXFLOAT,
5333                         0.0,
5334                         G_PARAM_READWRITE |
5335                         G_PARAM_STATIC_STRINGS |
5336                         CLUTTER_PARAM_ANIMATABLE);
5337
5338   /**
5339    * ClutterActor:width:
5340    *
5341    * Width of the actor (in pixels). If written, forces the minimum and
5342    * natural size request of the actor to the given width. If read, returns
5343    * the allocated width if available, otherwise the width request.
5344    *
5345    * The #ClutterActor:width property is animatable.
5346    */
5347   obj_props[PROP_WIDTH] =
5348     g_param_spec_float ("width",
5349                         P_("Width"),
5350                         P_("Width of the actor"),
5351                         0.0, G_MAXFLOAT,
5352                         0.0,
5353                         G_PARAM_READWRITE |
5354                         G_PARAM_STATIC_STRINGS |
5355                         CLUTTER_PARAM_ANIMATABLE);
5356
5357   /**
5358    * ClutterActor:height:
5359    *
5360    * Height of the actor (in pixels).  If written, forces the minimum and
5361    * natural size request of the actor to the given height. If read, returns
5362    * the allocated height if available, otherwise the height request.
5363    *
5364    * The #ClutterActor:height property is animatable.
5365    */
5366   obj_props[PROP_HEIGHT] =
5367     g_param_spec_float ("height",
5368                         P_("Height"),
5369                         P_("Height of the actor"),
5370                         0.0, G_MAXFLOAT,
5371                         0.0,
5372                         G_PARAM_READWRITE |
5373                         G_PARAM_STATIC_STRINGS |
5374                         CLUTTER_PARAM_ANIMATABLE);
5375
5376   /**
5377    * ClutterActor:fixed-x:
5378    *
5379    * The fixed X position of the actor in pixels.
5380    *
5381    * Writing this property sets #ClutterActor:fixed-position-set
5382    * property as well, as a side effect
5383    *
5384    * Since: 0.8
5385    */
5386   obj_props[PROP_FIXED_X] =
5387     g_param_spec_float ("fixed-x",
5388                         P_("Fixed X"),
5389                         P_("Forced X position of the actor"),
5390                         -G_MAXFLOAT, G_MAXFLOAT,
5391                         0.0,
5392                         CLUTTER_PARAM_READWRITE);
5393
5394   /**
5395    * ClutterActor:fixed-y:
5396    *
5397    * The fixed Y position of the actor in pixels.
5398    *
5399    * Writing this property sets the #ClutterActor:fixed-position-set
5400    * property as well, as a side effect
5401    *
5402    * Since: 0.8
5403    */
5404   obj_props[PROP_FIXED_Y] =
5405     g_param_spec_float ("fixed-y",
5406                         P_("Fixed Y"),
5407                         P_("Forced Y position of the actor"),
5408                         -G_MAXFLOAT, G_MAXFLOAT,
5409                         0,
5410                         CLUTTER_PARAM_READWRITE);
5411
5412   /**
5413    * ClutterActor:fixed-position-set:
5414    *
5415    * This flag controls whether the #ClutterActor:fixed-x and
5416    * #ClutterActor:fixed-y properties are used
5417    *
5418    * Since: 0.8
5419    */
5420   obj_props[PROP_FIXED_POSITION_SET] =
5421     g_param_spec_boolean ("fixed-position-set",
5422                           P_("Fixed position set"),
5423                           P_("Whether to use fixed positioning for the actor"),
5424                           FALSE,
5425                           CLUTTER_PARAM_READWRITE);
5426
5427   /**
5428    * ClutterActor:min-width:
5429    *
5430    * A forced minimum width request for the actor, in pixels
5431    *
5432    * Writing this property sets the #ClutterActor:min-width-set property
5433    * as well, as a side effect.
5434    *
5435    *This property overrides the usual width request of the actor.
5436    *
5437    * Since: 0.8
5438    */
5439   obj_props[PROP_MIN_WIDTH] =
5440     g_param_spec_float ("min-width",
5441                         P_("Min Width"),
5442                         P_("Forced minimum width request for the actor"),
5443                         0.0, G_MAXFLOAT,
5444                         0.0,
5445                         CLUTTER_PARAM_READWRITE);
5446
5447   /**
5448    * ClutterActor:min-height:
5449    *
5450    * A forced minimum height request for the actor, in pixels
5451    *
5452    * Writing this property sets the #ClutterActor:min-height-set property
5453    * as well, as a side effect. This property overrides the usual height
5454    * request of the actor.
5455    *
5456    * Since: 0.8
5457    */
5458   obj_props[PROP_MIN_HEIGHT] =
5459     g_param_spec_float ("min-height",
5460                         P_("Min Height"),
5461                         P_("Forced minimum height request for the actor"),
5462                         0.0, G_MAXFLOAT,
5463                         0.0,
5464                         CLUTTER_PARAM_READWRITE);
5465
5466   /**
5467    * ClutterActor:natural-width:
5468    *
5469    * A forced natural width request for the actor, in pixels
5470    *
5471    * Writing this property sets the #ClutterActor:natural-width-set
5472    * property as well, as a side effect. This property overrides the
5473    * usual width request of the actor
5474    *
5475    * Since: 0.8
5476    */
5477   obj_props[PROP_NATURAL_WIDTH] =
5478     g_param_spec_float ("natural-width",
5479                         P_("Natural Width"),
5480                         P_("Forced natural width request for the actor"),
5481                         0.0, G_MAXFLOAT,
5482                         0.0,
5483                         CLUTTER_PARAM_READWRITE);
5484
5485   /**
5486    * ClutterActor:natural-height:
5487    *
5488    * A forced natural height request for the actor, in pixels
5489    *
5490    * Writing this property sets the #ClutterActor:natural-height-set
5491    * property as well, as a side effect. This property overrides the
5492    * usual height request of the actor
5493    *
5494    * Since: 0.8
5495    */
5496   obj_props[PROP_NATURAL_HEIGHT] =
5497     g_param_spec_float ("natural-height",
5498                         P_("Natural Height"),
5499                         P_("Forced natural height request for the actor"),
5500                         0.0, G_MAXFLOAT,
5501                         0.0,
5502                         CLUTTER_PARAM_READWRITE);
5503
5504   /**
5505    * ClutterActor:min-width-set:
5506    *
5507    * This flag controls whether the #ClutterActor:min-width property
5508    * is used
5509    *
5510    * Since: 0.8
5511    */
5512   obj_props[PROP_MIN_WIDTH_SET] =
5513     g_param_spec_boolean ("min-width-set",
5514                           P_("Minimum width set"),
5515                           P_("Whether to use the min-width property"),
5516                           FALSE,
5517                           CLUTTER_PARAM_READWRITE);
5518
5519   /**
5520    * ClutterActor:min-height-set:
5521    *
5522    * This flag controls whether the #ClutterActor:min-height property
5523    * is used
5524    *
5525    * Since: 0.8
5526    */
5527   obj_props[PROP_MIN_HEIGHT_SET] =
5528     g_param_spec_boolean ("min-height-set",
5529                           P_("Minimum height set"),
5530                           P_("Whether to use the min-height property"),
5531                           FALSE,
5532                           CLUTTER_PARAM_READWRITE);
5533
5534   /**
5535    * ClutterActor:natural-width-set:
5536    *
5537    * This flag controls whether the #ClutterActor:natural-width property
5538    * is used
5539    *
5540    * Since: 0.8
5541    */
5542   obj_props[PROP_NATURAL_WIDTH_SET] =
5543     g_param_spec_boolean ("natural-width-set",
5544                           P_("Natural width set"),
5545                           P_("Whether to use the natural-width property"),
5546                           FALSE,
5547                           CLUTTER_PARAM_READWRITE);
5548
5549   /**
5550    * ClutterActor:natural-height-set:
5551    *
5552    * This flag controls whether the #ClutterActor:natural-height property
5553    * is used
5554    *
5555    * Since: 0.8
5556    */
5557   obj_props[PROP_NATURAL_HEIGHT_SET] =
5558     g_param_spec_boolean ("natural-height-set",
5559                           P_("Natural height set"),
5560                           P_("Whether to use the natural-height property"),
5561                           FALSE,
5562                           CLUTTER_PARAM_READWRITE);
5563
5564   /**
5565    * ClutterActor:allocation:
5566    *
5567    * The allocation for the actor, in pixels
5568    *
5569    * This is property is read-only, but you might monitor it to know when an
5570    * actor moves or resizes
5571    *
5572    * Since: 0.8
5573    */
5574   obj_props[PROP_ALLOCATION] =
5575     g_param_spec_boxed ("allocation",
5576                         P_("Allocation"),
5577                         P_("The actor's allocation"),
5578                         CLUTTER_TYPE_ACTOR_BOX,
5579                         CLUTTER_PARAM_READABLE);
5580
5581   /**
5582    * ClutterActor:request-mode:
5583    *
5584    * Request mode for the #ClutterActor. The request mode determines the
5585    * type of geometry management used by the actor, either height for width
5586    * (the default) or width for height.
5587    *
5588    * For actors implementing height for width, the parent container should get
5589    * the preferred width first, and then the preferred height for that width.
5590    *
5591    * For actors implementing width for height, the parent container should get
5592    * the preferred height first, and then the preferred width for that height.
5593    *
5594    * For instance:
5595    *
5596    * |[
5597    *   ClutterRequestMode mode;
5598    *   gfloat natural_width, min_width;
5599    *   gfloat natural_height, min_height;
5600    *
5601    *   mode = clutter_actor_get_request_mode (child);
5602    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5603    *     {
5604    *       clutter_actor_get_preferred_width (child, -1,
5605    *                                          &amp;min_width,
5606    *                                          &amp;natural_width);
5607    *       clutter_actor_get_preferred_height (child, natural_width,
5608    *                                           &amp;min_height,
5609    *                                           &amp;natural_height);
5610    *     }
5611    *   else
5612    *     {
5613    *       clutter_actor_get_preferred_height (child, -1,
5614    *                                           &amp;min_height,
5615    *                                           &amp;natural_height);
5616    *       clutter_actor_get_preferred_width (child, natural_height,
5617    *                                          &amp;min_width,
5618    *                                          &amp;natural_width);
5619    *     }
5620    * ]|
5621    *
5622    * will retrieve the minimum and natural width and height depending on the
5623    * preferred request mode of the #ClutterActor "child".
5624    *
5625    * The clutter_actor_get_preferred_size() function will implement this
5626    * check for you.
5627    *
5628    * Since: 0.8
5629    */
5630   obj_props[PROP_REQUEST_MODE] =
5631     g_param_spec_enum ("request-mode",
5632                        P_("Request Mode"),
5633                        P_("The actor's request mode"),
5634                        CLUTTER_TYPE_REQUEST_MODE,
5635                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5636                        CLUTTER_PARAM_READWRITE);
5637
5638   /**
5639    * ClutterActor:depth:
5640    *
5641    * The position of the actor on the Z axis.
5642    *
5643    * The #ClutterActor:depth property is relative to the parent's
5644    * modelview matrix.
5645    *
5646    * The #ClutterActor:depth property is animatable.
5647    *
5648    * Since: 0.6
5649    */
5650   obj_props[PROP_DEPTH] =
5651     g_param_spec_float ("depth",
5652                         P_("Depth"),
5653                         P_("Position on the Z axis"),
5654                         -G_MAXFLOAT, G_MAXFLOAT,
5655                         0.0,
5656                         G_PARAM_READWRITE |
5657                         G_PARAM_STATIC_STRINGS |
5658                         CLUTTER_PARAM_ANIMATABLE);
5659
5660   /**
5661    * ClutterActor:opacity:
5662    *
5663    * Opacity of an actor, between 0 (fully transparent) and
5664    * 255 (fully opaque)
5665    *
5666    * The #ClutterActor:opacity property is animatable.
5667    */
5668   obj_props[PROP_OPACITY] =
5669     g_param_spec_uint ("opacity",
5670                        P_("Opacity"),
5671                        P_("Opacity of an actor"),
5672                        0, 255,
5673                        255,
5674                        G_PARAM_READWRITE |
5675                        G_PARAM_STATIC_STRINGS |
5676                        CLUTTER_PARAM_ANIMATABLE);
5677
5678   /**
5679    * ClutterActor:offscreen-redirect:
5680    *
5681    * Determines the conditions in which the actor will be redirected
5682    * to an offscreen framebuffer while being painted. For example this
5683    * can be used to cache an actor in a framebuffer or for improved
5684    * handling of transparent actors. See
5685    * clutter_actor_set_offscreen_redirect() for details.
5686    *
5687    * Since: 1.8
5688    */
5689   obj_props[PROP_OFFSCREEN_REDIRECT] =
5690     g_param_spec_flags ("offscreen-redirect",
5691                         P_("Offscreen redirect"),
5692                         P_("Flags controlling when to flatten the actor into a single image"),
5693                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5694                         0,
5695                         CLUTTER_PARAM_READWRITE);
5696
5697   /**
5698    * ClutterActor:visible:
5699    *
5700    * Whether the actor is set to be visible or not
5701    *
5702    * See also #ClutterActor:mapped
5703    */
5704   obj_props[PROP_VISIBLE] =
5705     g_param_spec_boolean ("visible",
5706                           P_("Visible"),
5707                           P_("Whether the actor is visible or not"),
5708                           FALSE,
5709                           CLUTTER_PARAM_READWRITE);
5710
5711   /**
5712    * ClutterActor:mapped:
5713    *
5714    * Whether the actor is mapped (will be painted when the stage
5715    * to which it belongs is mapped)
5716    *
5717    * Since: 1.0
5718    */
5719   obj_props[PROP_MAPPED] =
5720     g_param_spec_boolean ("mapped",
5721                           P_("Mapped"),
5722                           P_("Whether the actor will be painted"),
5723                           FALSE,
5724                           CLUTTER_PARAM_READABLE);
5725
5726   /**
5727    * ClutterActor:realized:
5728    *
5729    * Whether the actor has been realized
5730    *
5731    * Since: 1.0
5732    */
5733   obj_props[PROP_REALIZED] =
5734     g_param_spec_boolean ("realized",
5735                           P_("Realized"),
5736                           P_("Whether the actor has been realized"),
5737                           FALSE,
5738                           CLUTTER_PARAM_READABLE);
5739
5740   /**
5741    * ClutterActor:reactive:
5742    *
5743    * Whether the actor is reactive to events or not
5744    *
5745    * Only reactive actors will emit event-related signals
5746    *
5747    * Since: 0.6
5748    */
5749   obj_props[PROP_REACTIVE] =
5750     g_param_spec_boolean ("reactive",
5751                           P_("Reactive"),
5752                           P_("Whether the actor is reactive to events"),
5753                           FALSE,
5754                           CLUTTER_PARAM_READWRITE);
5755
5756   /**
5757    * ClutterActor:has-clip:
5758    *
5759    * Whether the actor has the #ClutterActor:clip property set or not
5760    */
5761   obj_props[PROP_HAS_CLIP] =
5762     g_param_spec_boolean ("has-clip",
5763                           P_("Has Clip"),
5764                           P_("Whether the actor has a clip set"),
5765                           FALSE,
5766                           CLUTTER_PARAM_READABLE);
5767
5768   /**
5769    * ClutterActor:clip:
5770    *
5771    * The clip region for the actor, in actor-relative coordinates
5772    *
5773    * Every part of the actor outside the clip region will not be
5774    * painted
5775    */
5776   obj_props[PROP_CLIP] =
5777     g_param_spec_boxed ("clip",
5778                         P_("Clip"),
5779                         P_("The clip region for the actor"),
5780                         CLUTTER_TYPE_GEOMETRY,
5781                         CLUTTER_PARAM_READWRITE);
5782
5783   /**
5784    * ClutterActor:name:
5785    *
5786    * The name of the actor
5787    *
5788    * Since: 0.2
5789    */
5790   obj_props[PROP_NAME] =
5791     g_param_spec_string ("name",
5792                          P_("Name"),
5793                          P_("Name of the actor"),
5794                          NULL,
5795                          CLUTTER_PARAM_READWRITE);
5796
5797   /**
5798    * ClutterActor:scale-x:
5799    *
5800    * The horizontal scale of the actor.
5801    *
5802    * The #ClutterActor:scale-x property is animatable.
5803    *
5804    * Since: 0.6
5805    */
5806   obj_props[PROP_SCALE_X] =
5807     g_param_spec_double ("scale-x",
5808                          P_("Scale X"),
5809                          P_("Scale factor on the X axis"),
5810                          0.0, G_MAXDOUBLE,
5811                          1.0,
5812                          G_PARAM_READWRITE |
5813                          G_PARAM_STATIC_STRINGS |
5814                          CLUTTER_PARAM_ANIMATABLE);
5815
5816   /**
5817    * ClutterActor:scale-y:
5818    *
5819    * The vertical scale of the actor.
5820    *
5821    * The #ClutterActor:scale-y property is animatable.
5822    *
5823    * Since: 0.6
5824    */
5825   obj_props[PROP_SCALE_Y] =
5826     g_param_spec_double ("scale-y",
5827                          P_("Scale Y"),
5828                          P_("Scale factor on the Y axis"),
5829                          0.0, G_MAXDOUBLE,
5830                          1.0,
5831                          G_PARAM_READWRITE |
5832                          G_PARAM_STATIC_STRINGS |
5833                          CLUTTER_PARAM_ANIMATABLE);
5834
5835   /**
5836    * ClutterActor:scale-center-x:
5837    *
5838    * The horizontal center point for scaling
5839    *
5840    * Since: 1.0
5841    */
5842   obj_props[PROP_SCALE_CENTER_X] =
5843     g_param_spec_float ("scale-center-x",
5844                         P_("Scale Center X"),
5845                         P_("Horizontal scale center"),
5846                         -G_MAXFLOAT, G_MAXFLOAT,
5847                         0.0,
5848                         CLUTTER_PARAM_READWRITE);
5849
5850   /**
5851    * ClutterActor:scale-center-y:
5852    *
5853    * The vertical center point for scaling
5854    *
5855    * Since: 1.0
5856    */
5857   obj_props[PROP_SCALE_CENTER_Y] =
5858     g_param_spec_float ("scale-center-y",
5859                         P_("Scale Center Y"),
5860                         P_("Vertical scale center"),
5861                         -G_MAXFLOAT, G_MAXFLOAT,
5862                         0.0,
5863                         CLUTTER_PARAM_READWRITE);
5864
5865   /**
5866    * ClutterActor:scale-gravity:
5867    *
5868    * The center point for scaling expressed as a #ClutterGravity
5869    *
5870    * Since: 1.0
5871    */
5872   obj_props[PROP_SCALE_GRAVITY] =
5873     g_param_spec_enum ("scale-gravity",
5874                        P_("Scale Gravity"),
5875                        P_("The center of scaling"),
5876                        CLUTTER_TYPE_GRAVITY,
5877                        CLUTTER_GRAVITY_NONE,
5878                        CLUTTER_PARAM_READWRITE);
5879
5880   /**
5881    * ClutterActor:rotation-angle-x:
5882    *
5883    * The rotation angle on the X axis.
5884    *
5885    * The #ClutterActor:rotation-angle-x property is animatable.
5886    *
5887    * Since: 0.6
5888    */
5889   obj_props[PROP_ROTATION_ANGLE_X] =
5890     g_param_spec_double ("rotation-angle-x",
5891                          P_("Rotation Angle X"),
5892                          P_("The rotation angle on the X axis"),
5893                          -G_MAXDOUBLE, G_MAXDOUBLE,
5894                          0.0,
5895                          G_PARAM_READWRITE |
5896                          G_PARAM_STATIC_STRINGS |
5897                          CLUTTER_PARAM_ANIMATABLE);
5898
5899   /**
5900    * ClutterActor:rotation-angle-y:
5901    *
5902    * The rotation angle on the Y axis
5903    *
5904    * The #ClutterActor:rotation-angle-y property is animatable.
5905    *
5906    * Since: 0.6
5907    */
5908   obj_props[PROP_ROTATION_ANGLE_Y] =
5909     g_param_spec_double ("rotation-angle-y",
5910                          P_("Rotation Angle Y"),
5911                          P_("The rotation angle on the Y axis"),
5912                          -G_MAXDOUBLE, G_MAXDOUBLE,
5913                          0.0,
5914                          G_PARAM_READWRITE |
5915                          G_PARAM_STATIC_STRINGS |
5916                          CLUTTER_PARAM_ANIMATABLE);
5917
5918   /**
5919    * ClutterActor:rotation-angle-z:
5920    *
5921    * The rotation angle on the Z axis
5922    *
5923    * The #ClutterActor:rotation-angle-z property is animatable.
5924    *
5925    * Since: 0.6
5926    */
5927   obj_props[PROP_ROTATION_ANGLE_Z] =
5928     g_param_spec_double ("rotation-angle-z",
5929                          P_("Rotation Angle Z"),
5930                          P_("The rotation angle on the Z axis"),
5931                          -G_MAXDOUBLE, G_MAXDOUBLE,
5932                          0.0,
5933                          G_PARAM_READWRITE |
5934                          G_PARAM_STATIC_STRINGS |
5935                          CLUTTER_PARAM_ANIMATABLE);
5936
5937   /**
5938    * ClutterActor:rotation-center-x:
5939    *
5940    * The rotation center on the X axis.
5941    *
5942    * Since: 0.6
5943    */
5944   obj_props[PROP_ROTATION_CENTER_X] =
5945     g_param_spec_boxed ("rotation-center-x",
5946                         P_("Rotation Center X"),
5947                         P_("The rotation center on the X axis"),
5948                         CLUTTER_TYPE_VERTEX,
5949                         CLUTTER_PARAM_READWRITE);
5950
5951   /**
5952    * ClutterActor:rotation-center-y:
5953    *
5954    * The rotation center on the Y axis.
5955    *
5956    * Since: 0.6
5957    */
5958   obj_props[PROP_ROTATION_CENTER_Y] =
5959     g_param_spec_boxed ("rotation-center-y",
5960                         P_("Rotation Center Y"),
5961                         P_("The rotation center on the Y axis"),
5962                         CLUTTER_TYPE_VERTEX,
5963                         CLUTTER_PARAM_READWRITE);
5964
5965   /**
5966    * ClutterActor:rotation-center-z:
5967    *
5968    * The rotation center on the Z axis.
5969    *
5970    * Since: 0.6
5971    */
5972   obj_props[PROP_ROTATION_CENTER_Z] =
5973     g_param_spec_boxed ("rotation-center-z",
5974                         P_("Rotation Center Z"),
5975                         P_("The rotation center on the Z axis"),
5976                         CLUTTER_TYPE_VERTEX,
5977                         CLUTTER_PARAM_READWRITE);
5978
5979   /**
5980    * ClutterActor:rotation-center-z-gravity:
5981    *
5982    * The rotation center on the Z axis expressed as a #ClutterGravity.
5983    *
5984    * Since: 1.0
5985    */
5986   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5987     g_param_spec_enum ("rotation-center-z-gravity",
5988                        P_("Rotation Center Z Gravity"),
5989                        P_("Center point for rotation around the Z axis"),
5990                        CLUTTER_TYPE_GRAVITY,
5991                        CLUTTER_GRAVITY_NONE,
5992                        CLUTTER_PARAM_READWRITE);
5993
5994   /**
5995    * ClutterActor:anchor-x:
5996    *
5997    * The X coordinate of an actor's anchor point, relative to
5998    * the actor coordinate space, in pixels
5999    *
6000    * Since: 0.8
6001    */
6002   obj_props[PROP_ANCHOR_X] =
6003     g_param_spec_float ("anchor-x",
6004                         P_("Anchor X"),
6005                         P_("X coordinate of the anchor point"),
6006                         -G_MAXFLOAT, G_MAXFLOAT,
6007                         0,
6008                         CLUTTER_PARAM_READWRITE);
6009
6010   /**
6011    * ClutterActor:anchor-y:
6012    *
6013    * The Y coordinate of an actor's anchor point, relative to
6014    * the actor coordinate space, in pixels
6015    *
6016    * Since: 0.8
6017    */
6018   obj_props[PROP_ANCHOR_Y] =
6019     g_param_spec_float ("anchor-y",
6020                         P_("Anchor Y"),
6021                         P_("Y coordinate of the anchor point"),
6022                         -G_MAXFLOAT, G_MAXFLOAT,
6023                         0,
6024                         CLUTTER_PARAM_READWRITE);
6025
6026   /**
6027    * ClutterActor:anchor-gravity:
6028    *
6029    * The anchor point expressed as a #ClutterGravity
6030    *
6031    * Since: 1.0
6032    */
6033   obj_props[PROP_ANCHOR_GRAVITY] =
6034     g_param_spec_enum ("anchor-gravity",
6035                        P_("Anchor Gravity"),
6036                        P_("The anchor point as a ClutterGravity"),
6037                        CLUTTER_TYPE_GRAVITY,
6038                        CLUTTER_GRAVITY_NONE,
6039                        CLUTTER_PARAM_READWRITE);
6040
6041   /**
6042    * ClutterActor:show-on-set-parent:
6043    *
6044    * If %TRUE, the actor is automatically shown when parented.
6045    *
6046    * Calling clutter_actor_hide() on an actor which has not been
6047    * parented will set this property to %FALSE as a side effect.
6048    *
6049    * Since: 0.8
6050    */
6051   obj_props[PROP_SHOW_ON_SET_PARENT] =
6052     g_param_spec_boolean ("show-on-set-parent",
6053                           P_("Show on set parent"),
6054                           P_("Whether the actor is shown when parented"),
6055                           TRUE,
6056                           CLUTTER_PARAM_READWRITE);
6057
6058   /**
6059    * ClutterActor:clip-to-allocation:
6060    *
6061    * Whether the clip region should track the allocated area
6062    * of the actor.
6063    *
6064    * This property is ignored if a clip area has been explicitly
6065    * set using clutter_actor_set_clip().
6066    *
6067    * Since: 1.0
6068    */
6069   obj_props[PROP_CLIP_TO_ALLOCATION] =
6070     g_param_spec_boolean ("clip-to-allocation",
6071                           P_("Clip to Allocation"),
6072                           P_("Sets the clip region to track the actor's allocation"),
6073                           FALSE,
6074                           CLUTTER_PARAM_READWRITE);
6075
6076   /**
6077    * ClutterActor:text-direction:
6078    *
6079    * The direction of the text inside a #ClutterActor.
6080    *
6081    * Since: 1.0
6082    */
6083   obj_props[PROP_TEXT_DIRECTION] =
6084     g_param_spec_enum ("text-direction",
6085                        P_("Text Direction"),
6086                        P_("Direction of the text"),
6087                        CLUTTER_TYPE_TEXT_DIRECTION,
6088                        CLUTTER_TEXT_DIRECTION_LTR,
6089                        CLUTTER_PARAM_READWRITE);
6090
6091   /**
6092    * ClutterActor:has-pointer:
6093    *
6094    * Whether the actor contains the pointer of a #ClutterInputDevice
6095    * or not.
6096    *
6097    * Since: 1.2
6098    */
6099   obj_props[PROP_HAS_POINTER] =
6100     g_param_spec_boolean ("has-pointer",
6101                           P_("Has Pointer"),
6102                           P_("Whether the actor contains the pointer of an input device"),
6103                           FALSE,
6104                           CLUTTER_PARAM_READABLE);
6105
6106   /**
6107    * ClutterActor:actions:
6108    *
6109    * Adds a #ClutterAction to the actor
6110    *
6111    * Since: 1.4
6112    */
6113   obj_props[PROP_ACTIONS] =
6114     g_param_spec_object ("actions",
6115                          P_("Actions"),
6116                          P_("Adds an action to the actor"),
6117                          CLUTTER_TYPE_ACTION,
6118                          CLUTTER_PARAM_WRITABLE);
6119
6120   /**
6121    * ClutterActor:constraints:
6122    *
6123    * Adds a #ClutterConstraint to the actor
6124    *
6125    * Since: 1.4
6126    */
6127   obj_props[PROP_CONSTRAINTS] =
6128     g_param_spec_object ("constraints",
6129                          P_("Constraints"),
6130                          P_("Adds a constraint to the actor"),
6131                          CLUTTER_TYPE_CONSTRAINT,
6132                          CLUTTER_PARAM_WRITABLE);
6133
6134   /**
6135    * ClutterActor:effect:
6136    *
6137    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6138    *
6139    * Since: 1.4
6140    */
6141   obj_props[PROP_EFFECT] =
6142     g_param_spec_object ("effect",
6143                          P_("Effect"),
6144                          P_("Add an effect to be applied on the actor"),
6145                          CLUTTER_TYPE_EFFECT,
6146                          CLUTTER_PARAM_WRITABLE);
6147
6148   /**
6149    * ClutterActor:layout-manager:
6150    *
6151    * A delegate object for controlling the layout of the children of
6152    * an actor.
6153    *
6154    * Since: 1.10
6155    */
6156   obj_props[PROP_LAYOUT_MANAGER] =
6157     g_param_spec_object ("layout-manager",
6158                          P_("Layout Manager"),
6159                          P_("The object controlling the layout of an actor's children"),
6160                          CLUTTER_TYPE_LAYOUT_MANAGER,
6161                          CLUTTER_PARAM_READWRITE);
6162
6163
6164   /**
6165    * ClutterActor:x-align:
6166    *
6167    * The alignment of an actor on the X axis, if the actor has been given
6168    * extra space for its allocation.
6169    *
6170    * Since: 1.10
6171    */
6172   obj_props[PROP_X_ALIGN] =
6173     g_param_spec_enum ("x-align",
6174                        P_("X Alignment"),
6175                        P_("The alignment of the actor on the X axis within its allocation"),
6176                        CLUTTER_TYPE_ACTOR_ALIGN,
6177                        CLUTTER_ACTOR_ALIGN_FILL,
6178                        CLUTTER_PARAM_READWRITE);
6179
6180   /**
6181    * ClutterActor:y-align:
6182    *
6183    * The alignment of an actor on the Y axis, if the actor has been given
6184    * extra space for its allocation.
6185    *
6186    * Since: 1.10
6187    */
6188   obj_props[PROP_Y_ALIGN] =
6189     g_param_spec_enum ("y-align",
6190                        P_("Y Alignment"),
6191                        P_("The alignment of the actor on the Y axis within its allocation"),
6192                        CLUTTER_TYPE_ACTOR_ALIGN,
6193                        CLUTTER_ACTOR_ALIGN_FILL,
6194                        CLUTTER_PARAM_READWRITE);
6195
6196   /**
6197    * ClutterActor:margin-top:
6198    *
6199    * The margin (in pixels) from the top of the actor.
6200    *
6201    * This property adds a margin to the actor's preferred size; the margin
6202    * will be automatically taken into account when allocating the actor.
6203    *
6204    * Since: 1.10
6205    */
6206   obj_props[PROP_MARGIN_TOP] =
6207     g_param_spec_float ("margin-top",
6208                         P_("Margin Top"),
6209                         P_("Extra space at the top"),
6210                         0.0, G_MAXFLOAT,
6211                         0.0,
6212                         CLUTTER_PARAM_READWRITE);
6213
6214   /**
6215    * ClutterActor:margin-bottom:
6216    *
6217    * The margin (in pixels) from the bottom of the actor.
6218    *
6219    * This property adds a margin to the actor's preferred size; the margin
6220    * will be automatically taken into account when allocating the actor.
6221    *
6222    * Since: 1.10
6223    */
6224   obj_props[PROP_MARGIN_BOTTOM] =
6225     g_param_spec_float ("margin-bottom",
6226                         P_("Margin Bottom"),
6227                         P_("Extra space at the bottom"),
6228                         0.0, G_MAXFLOAT,
6229                         0.0,
6230                         CLUTTER_PARAM_READWRITE);
6231
6232   /**
6233    * ClutterActor:margin-left:
6234    *
6235    * The margin (in pixels) from the left of the actor.
6236    *
6237    * This property adds a margin to the actor's preferred size; the margin
6238    * will be automatically taken into account when allocating the actor.
6239    *
6240    * Since: 1.10
6241    */
6242   obj_props[PROP_MARGIN_LEFT] =
6243     g_param_spec_float ("margin-left",
6244                         P_("Margin Left"),
6245                         P_("Extra space at the left"),
6246                         0.0, G_MAXFLOAT,
6247                         0.0,
6248                         CLUTTER_PARAM_READWRITE);
6249
6250   /**
6251    * ClutterActor:margin-right:
6252    *
6253    * The margin (in pixels) from the right of the actor.
6254    *
6255    * This property adds a margin to the actor's preferred size; the margin
6256    * will be automatically taken into account when allocating the actor.
6257    *
6258    * Since: 1.10
6259    */
6260   obj_props[PROP_MARGIN_RIGHT] =
6261     g_param_spec_float ("margin-right",
6262                         P_("Margin Right"),
6263                         P_("Extra space at the right"),
6264                         0.0, G_MAXFLOAT,
6265                         0.0,
6266                         CLUTTER_PARAM_READWRITE);
6267
6268   /**
6269    * ClutterActor:background-color-set:
6270    *
6271    * Whether the #ClutterActor:background-color property has been set.
6272    *
6273    * Since: 1.10
6274    */
6275   obj_props[PROP_BACKGROUND_COLOR_SET] =
6276     g_param_spec_boolean ("background-color-set",
6277                           P_("Background Color Set"),
6278                           P_("Whether the background color is set"),
6279                           FALSE,
6280                           CLUTTER_PARAM_READABLE);
6281
6282   /**
6283    * ClutterActor:background-color:
6284    *
6285    * Paints a solid fill of the actor's allocation using the specified
6286    * color.
6287    *
6288    * The #ClutterActor:background-color property is animatable.
6289    *
6290    * Since: 1.10
6291    */
6292   obj_props[PROP_BACKGROUND_COLOR] =
6293     clutter_param_spec_color ("background-color",
6294                               P_("Background color"),
6295                               P_("The actor's background color"),
6296                               CLUTTER_COLOR_Transparent,
6297                               G_PARAM_READWRITE |
6298                               G_PARAM_STATIC_STRINGS |
6299                               CLUTTER_PARAM_ANIMATABLE);
6300
6301   /**
6302    * ClutterActor:first-child:
6303    *
6304    * The actor's first child.
6305    *
6306    * Since: 1.10
6307    */
6308   obj_props[PROP_FIRST_CHILD] =
6309     g_param_spec_object ("first-child",
6310                          P_("First Child"),
6311                          P_("The actor's first child"),
6312                          CLUTTER_TYPE_ACTOR,
6313                          CLUTTER_PARAM_READABLE);
6314
6315   /**
6316    * ClutterActor:last-child:
6317    *
6318    * The actor's last child.
6319    *
6320    * Since: 1.10
6321    */
6322   obj_props[PROP_LAST_CHILD] =
6323     g_param_spec_object ("last-child",
6324                          P_("Last Child"),
6325                          P_("The actor's last child"),
6326                          CLUTTER_TYPE_ACTOR,
6327                          CLUTTER_PARAM_READABLE);
6328
6329   /**
6330    * ClutterActor:content:
6331    *
6332    * The #ClutterContent implementation that controls the content
6333    * of the actor.
6334    *
6335    * Since: 1.10
6336    */
6337   obj_props[PROP_CONTENT] =
6338     g_param_spec_object ("content",
6339                          P_("Content"),
6340                          P_("Delegate object for painting the actor's content"),
6341                          CLUTTER_TYPE_CONTENT,
6342                          CLUTTER_PARAM_READWRITE);
6343
6344   /**
6345    * ClutterActor:content-gravity:
6346    *
6347    * The alignment that should be honoured by the #ClutterContent
6348    * set with the #ClutterActor:content property.
6349    *
6350    * Changing the value of this property will change the bounding box of
6351    * the content; you can use the #ClutterActor:content-box property to
6352    * get the position and size of the content within the actor's
6353    * allocation.
6354    *
6355    * This property is meaningful only for #ClutterContent implementations
6356    * that have a preferred size, and if the preferred size is smaller than
6357    * the actor's allocation.
6358    *
6359    * Since: 1.10
6360    */
6361   obj_props[PROP_CONTENT_GRAVITY] =
6362     g_param_spec_enum ("content-gravity",
6363                        P_("Content Gravity"),
6364                        P_("Alignment of the actor's content"),
6365                        CLUTTER_TYPE_CONTENT_GRAVITY,
6366                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6367                        CLUTTER_PARAM_READWRITE);
6368
6369   /**
6370    * ClutterActor:content-box:
6371    *
6372    * The bounding box for the #ClutterContent used by the actor.
6373    *
6374    * The value of this property is controlled by the #ClutterActor:allocation
6375    * and #ClutterActor:content-gravity properties of #ClutterActor.
6376    *
6377    * The bounding box for the content is guaranteed to never exceed the
6378    * allocation's of the actor.
6379    *
6380    * Since: 1.10
6381    */
6382   obj_props[PROP_CONTENT_BOX] =
6383     g_param_spec_boxed ("content-box",
6384                         P_("Content Box"),
6385                         P_("The bounding box of the actor's content"),
6386                         CLUTTER_TYPE_ACTOR_BOX,
6387                         CLUTTER_PARAM_READABLE);
6388
6389   obj_props[PROP_MINIFICATION_FILTER] =
6390     g_param_spec_enum ("minification-filter",
6391                        P_("Minification Filter"),
6392                        P_("The filter used when reducing the size of the content"),
6393                        CLUTTER_TYPE_SCALING_FILTER,
6394                        CLUTTER_SCALING_FILTER_LINEAR,
6395                        CLUTTER_PARAM_READWRITE);
6396
6397   obj_props[PROP_MAGNIFICATION_FILTER] =
6398     g_param_spec_enum ("magnification-filter",
6399                        P_("Magnification Filter"),
6400                        P_("The filter used when increasing the size of the content"),
6401                        CLUTTER_TYPE_SCALING_FILTER,
6402                        CLUTTER_SCALING_FILTER_LINEAR,
6403                        CLUTTER_PARAM_READWRITE);
6404
6405   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6406
6407   /**
6408    * ClutterActor::destroy:
6409    * @actor: the #ClutterActor which emitted the signal
6410    *
6411    * The ::destroy signal notifies that all references held on the
6412    * actor which emitted it should be released.
6413    *
6414    * The ::destroy signal should be used by all holders of a reference
6415    * on @actor.
6416    *
6417    * This signal might result in the finalization of the #ClutterActor
6418    * if all references are released.
6419    *
6420    * Composite actors and actors implementing the #ClutterContainer
6421    * interface should override the default implementation of the
6422    * class handler of this signal and call clutter_actor_destroy() on
6423    * their children. When overriding the default class handler, it is
6424    * required to chain up to the parent's implementation.
6425    *
6426    * Since: 0.2
6427    */
6428   actor_signals[DESTROY] =
6429     g_signal_new (I_("destroy"),
6430                   G_TYPE_FROM_CLASS (object_class),
6431                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6432                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6433                   NULL, NULL,
6434                   _clutter_marshal_VOID__VOID,
6435                   G_TYPE_NONE, 0);
6436   /**
6437    * ClutterActor::show:
6438    * @actor: the object which received the signal
6439    *
6440    * The ::show signal is emitted when an actor is visible and
6441    * rendered on the stage.
6442    *
6443    * Since: 0.2
6444    */
6445   actor_signals[SHOW] =
6446     g_signal_new (I_("show"),
6447                   G_TYPE_FROM_CLASS (object_class),
6448                   G_SIGNAL_RUN_FIRST,
6449                   G_STRUCT_OFFSET (ClutterActorClass, show),
6450                   NULL, NULL,
6451                   _clutter_marshal_VOID__VOID,
6452                   G_TYPE_NONE, 0);
6453   /**
6454    * ClutterActor::hide:
6455    * @actor: the object which received the signal
6456    *
6457    * The ::hide signal is emitted when an actor is no longer rendered
6458    * on the stage.
6459    *
6460    * Since: 0.2
6461    */
6462   actor_signals[HIDE] =
6463     g_signal_new (I_("hide"),
6464                   G_TYPE_FROM_CLASS (object_class),
6465                   G_SIGNAL_RUN_FIRST,
6466                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6467                   NULL, NULL,
6468                   _clutter_marshal_VOID__VOID,
6469                   G_TYPE_NONE, 0);
6470   /**
6471    * ClutterActor::parent-set:
6472    * @actor: the object which received the signal
6473    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6474    *
6475    * This signal is emitted when the parent of the actor changes.
6476    *
6477    * Since: 0.2
6478    */
6479   actor_signals[PARENT_SET] =
6480     g_signal_new (I_("parent-set"),
6481                   G_TYPE_FROM_CLASS (object_class),
6482                   G_SIGNAL_RUN_LAST,
6483                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6484                   NULL, NULL,
6485                   _clutter_marshal_VOID__OBJECT,
6486                   G_TYPE_NONE, 1,
6487                   CLUTTER_TYPE_ACTOR);
6488
6489   /**
6490    * ClutterActor::queue-redraw:
6491    * @actor: the actor we're bubbling the redraw request through
6492    * @origin: the actor which initiated the redraw request
6493    *
6494    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6495    * is called on @origin.
6496    *
6497    * The default implementation for #ClutterActor chains up to the
6498    * parent actor and queues a redraw on the parent, thus "bubbling"
6499    * the redraw queue up through the actor graph. The default
6500    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6501    * in a main loop idle handler.
6502    *
6503    * Note that the @origin actor may be the stage, or a container; it
6504    * does not have to be a leaf node in the actor graph.
6505    *
6506    * Toolkits embedding a #ClutterStage which require a redraw and
6507    * relayout cycle can stop the emission of this signal using the
6508    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6509    * themselves, like:
6510    *
6511    * |[
6512    *   static void
6513    *   on_redraw_complete (gpointer data)
6514    *   {
6515    *     ClutterStage *stage = data;
6516    *
6517    *     /&ast; execute the Clutter drawing pipeline &ast;/
6518    *     clutter_stage_ensure_redraw (stage);
6519    *   }
6520    *
6521    *   static void
6522    *   on_stage_queue_redraw (ClutterStage *stage)
6523    *   {
6524    *     /&ast; this prevents the default handler to run &ast;/
6525    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6526    *
6527    *     /&ast; queue a redraw with the host toolkit and call
6528    *      &ast; a function when the redraw has been completed
6529    *      &ast;/
6530    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6531    *   }
6532    * ]|
6533    *
6534    * <note><para>This signal is emitted before the Clutter paint
6535    * pipeline is executed. If you want to know when the pipeline has
6536    * been completed you should connect to the ::paint signal on the
6537    * Stage with g_signal_connect_after().</para></note>
6538    *
6539    * Since: 1.0
6540    */
6541   actor_signals[QUEUE_REDRAW] =
6542     g_signal_new (I_("queue-redraw"),
6543                   G_TYPE_FROM_CLASS (object_class),
6544                   G_SIGNAL_RUN_LAST |
6545                   G_SIGNAL_NO_HOOKS,
6546                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6547                   NULL, NULL,
6548                   _clutter_marshal_VOID__OBJECT,
6549                   G_TYPE_NONE, 1,
6550                   CLUTTER_TYPE_ACTOR);
6551
6552   /**
6553    * ClutterActor::queue-relayout
6554    * @actor: the actor being queued for relayout
6555    *
6556    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6557    * is called on an actor.
6558    *
6559    * The default implementation for #ClutterActor chains up to the
6560    * parent actor and queues a relayout on the parent, thus "bubbling"
6561    * the relayout queue up through the actor graph.
6562    *
6563    * The main purpose of this signal is to allow relayout to be propagated
6564    * properly in the procense of #ClutterClone actors. Applications will
6565    * not normally need to connect to this signal.
6566    *
6567    * Since: 1.2
6568    */
6569   actor_signals[QUEUE_RELAYOUT] =
6570     g_signal_new (I_("queue-relayout"),
6571                   G_TYPE_FROM_CLASS (object_class),
6572                   G_SIGNAL_RUN_LAST |
6573                   G_SIGNAL_NO_HOOKS,
6574                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6575                   NULL, NULL,
6576                   _clutter_marshal_VOID__VOID,
6577                   G_TYPE_NONE, 0);
6578
6579   /**
6580    * ClutterActor::event:
6581    * @actor: the actor which received the event
6582    * @event: a #ClutterEvent
6583    *
6584    * The ::event signal is emitted each time an event is received
6585    * by the @actor. This signal will be emitted on every actor,
6586    * following the hierarchy chain, until it reaches the top-level
6587    * container (the #ClutterStage).
6588    *
6589    * Return value: %TRUE if the event has been handled by the actor,
6590    *   or %FALSE to continue the emission.
6591    *
6592    * Since: 0.6
6593    */
6594   actor_signals[EVENT] =
6595     g_signal_new (I_("event"),
6596                   G_TYPE_FROM_CLASS (object_class),
6597                   G_SIGNAL_RUN_LAST,
6598                   G_STRUCT_OFFSET (ClutterActorClass, event),
6599                   _clutter_boolean_handled_accumulator, NULL,
6600                   _clutter_marshal_BOOLEAN__BOXED,
6601                   G_TYPE_BOOLEAN, 1,
6602                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6603   /**
6604    * ClutterActor::button-press-event:
6605    * @actor: the actor which received the event
6606    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6607    *
6608    * The ::button-press-event signal is emitted each time a mouse button
6609    * is pressed on @actor.
6610    *
6611    * Return value: %TRUE if the event has been handled by the actor,
6612    *   or %FALSE to continue the emission.
6613    *
6614    * Since: 0.6
6615    */
6616   actor_signals[BUTTON_PRESS_EVENT] =
6617     g_signal_new (I_("button-press-event"),
6618                   G_TYPE_FROM_CLASS (object_class),
6619                   G_SIGNAL_RUN_LAST,
6620                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6621                   _clutter_boolean_handled_accumulator, NULL,
6622                   _clutter_marshal_BOOLEAN__BOXED,
6623                   G_TYPE_BOOLEAN, 1,
6624                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6625   /**
6626    * ClutterActor::button-release-event:
6627    * @actor: the actor which received the event
6628    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6629    *
6630    * The ::button-release-event signal is emitted each time a mouse button
6631    * is released on @actor.
6632    *
6633    * Return value: %TRUE if the event has been handled by the actor,
6634    *   or %FALSE to continue the emission.
6635    *
6636    * Since: 0.6
6637    */
6638   actor_signals[BUTTON_RELEASE_EVENT] =
6639     g_signal_new (I_("button-release-event"),
6640                   G_TYPE_FROM_CLASS (object_class),
6641                   G_SIGNAL_RUN_LAST,
6642                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6643                   _clutter_boolean_handled_accumulator, NULL,
6644                   _clutter_marshal_BOOLEAN__BOXED,
6645                   G_TYPE_BOOLEAN, 1,
6646                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6647   /**
6648    * ClutterActor::scroll-event:
6649    * @actor: the actor which received the event
6650    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6651    *
6652    * The ::scroll-event signal is emitted each time the mouse is
6653    * scrolled on @actor
6654    *
6655    * Return value: %TRUE if the event has been handled by the actor,
6656    *   or %FALSE to continue the emission.
6657    *
6658    * Since: 0.6
6659    */
6660   actor_signals[SCROLL_EVENT] =
6661     g_signal_new (I_("scroll-event"),
6662                   G_TYPE_FROM_CLASS (object_class),
6663                   G_SIGNAL_RUN_LAST,
6664                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6665                   _clutter_boolean_handled_accumulator, NULL,
6666                   _clutter_marshal_BOOLEAN__BOXED,
6667                   G_TYPE_BOOLEAN, 1,
6668                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6669   /**
6670    * ClutterActor::key-press-event:
6671    * @actor: the actor which received the event
6672    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6673    *
6674    * The ::key-press-event signal is emitted each time a keyboard button
6675    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6676    *
6677    * Return value: %TRUE if the event has been handled by the actor,
6678    *   or %FALSE to continue the emission.
6679    *
6680    * Since: 0.6
6681    */
6682   actor_signals[KEY_PRESS_EVENT] =
6683     g_signal_new (I_("key-press-event"),
6684                   G_TYPE_FROM_CLASS (object_class),
6685                   G_SIGNAL_RUN_LAST,
6686                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6687                   _clutter_boolean_handled_accumulator, NULL,
6688                   _clutter_marshal_BOOLEAN__BOXED,
6689                   G_TYPE_BOOLEAN, 1,
6690                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6691   /**
6692    * ClutterActor::key-release-event:
6693    * @actor: the actor which received the event
6694    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6695    *
6696    * The ::key-release-event signal is emitted each time a keyboard button
6697    * is released while @actor has key focus (see
6698    * clutter_stage_set_key_focus()).
6699    *
6700    * Return value: %TRUE if the event has been handled by the actor,
6701    *   or %FALSE to continue the emission.
6702    *
6703    * Since: 0.6
6704    */
6705   actor_signals[KEY_RELEASE_EVENT] =
6706     g_signal_new (I_("key-release-event"),
6707                   G_TYPE_FROM_CLASS (object_class),
6708                   G_SIGNAL_RUN_LAST,
6709                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6710                   _clutter_boolean_handled_accumulator, NULL,
6711                   _clutter_marshal_BOOLEAN__BOXED,
6712                   G_TYPE_BOOLEAN, 1,
6713                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6714   /**
6715    * ClutterActor::motion-event:
6716    * @actor: the actor which received the event
6717    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6718    *
6719    * The ::motion-event signal is emitted each time the mouse pointer is
6720    * moved over @actor.
6721    *
6722    * Return value: %TRUE if the event has been handled by the actor,
6723    *   or %FALSE to continue the emission.
6724    *
6725    * Since: 0.6
6726    */
6727   actor_signals[MOTION_EVENT] =
6728     g_signal_new (I_("motion-event"),
6729                   G_TYPE_FROM_CLASS (object_class),
6730                   G_SIGNAL_RUN_LAST,
6731                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6732                   _clutter_boolean_handled_accumulator, NULL,
6733                   _clutter_marshal_BOOLEAN__BOXED,
6734                   G_TYPE_BOOLEAN, 1,
6735                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6736
6737   /**
6738    * ClutterActor::key-focus-in:
6739    * @actor: the actor which now has key focus
6740    *
6741    * The ::key-focus-in signal is emitted when @actor receives key focus.
6742    *
6743    * Since: 0.6
6744    */
6745   actor_signals[KEY_FOCUS_IN] =
6746     g_signal_new (I_("key-focus-in"),
6747                   G_TYPE_FROM_CLASS (object_class),
6748                   G_SIGNAL_RUN_LAST,
6749                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6750                   NULL, NULL,
6751                   _clutter_marshal_VOID__VOID,
6752                   G_TYPE_NONE, 0);
6753
6754   /**
6755    * ClutterActor::key-focus-out:
6756    * @actor: the actor which now has key focus
6757    *
6758    * The ::key-focus-out signal is emitted when @actor loses key focus.
6759    *
6760    * Since: 0.6
6761    */
6762   actor_signals[KEY_FOCUS_OUT] =
6763     g_signal_new (I_("key-focus-out"),
6764                   G_TYPE_FROM_CLASS (object_class),
6765                   G_SIGNAL_RUN_LAST,
6766                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6767                   NULL, NULL,
6768                   _clutter_marshal_VOID__VOID,
6769                   G_TYPE_NONE, 0);
6770
6771   /**
6772    * ClutterActor::enter-event:
6773    * @actor: the actor which the pointer has entered.
6774    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6775    *
6776    * The ::enter-event signal is emitted when the pointer enters the @actor
6777    *
6778    * Return value: %TRUE if the event has been handled by the actor,
6779    *   or %FALSE to continue the emission.
6780    *
6781    * Since: 0.6
6782    */
6783   actor_signals[ENTER_EVENT] =
6784     g_signal_new (I_("enter-event"),
6785                   G_TYPE_FROM_CLASS (object_class),
6786                   G_SIGNAL_RUN_LAST,
6787                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6788                   _clutter_boolean_handled_accumulator, NULL,
6789                   _clutter_marshal_BOOLEAN__BOXED,
6790                   G_TYPE_BOOLEAN, 1,
6791                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6792
6793   /**
6794    * ClutterActor::leave-event:
6795    * @actor: the actor which the pointer has left
6796    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6797    *
6798    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6799    *
6800    * Return value: %TRUE if the event has been handled by the actor,
6801    *   or %FALSE to continue the emission.
6802    *
6803    * Since: 0.6
6804    */
6805   actor_signals[LEAVE_EVENT] =
6806     g_signal_new (I_("leave-event"),
6807                   G_TYPE_FROM_CLASS (object_class),
6808                   G_SIGNAL_RUN_LAST,
6809                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6810                   _clutter_boolean_handled_accumulator, NULL,
6811                   _clutter_marshal_BOOLEAN__BOXED,
6812                   G_TYPE_BOOLEAN, 1,
6813                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6814
6815   /**
6816    * ClutterActor::captured-event:
6817    * @actor: the actor which received the signal
6818    * @event: a #ClutterEvent
6819    *
6820    * The ::captured-event signal is emitted when an event is captured
6821    * by Clutter. This signal will be emitted starting from the top-level
6822    * container (the #ClutterStage) to the actor which received the event
6823    * going down the hierarchy. This signal can be used to intercept every
6824    * event before the specialized events (like
6825    * ClutterActor::button-press-event or ::key-released-event) are
6826    * emitted.
6827    *
6828    * Return value: %TRUE if the event has been handled by the actor,
6829    *   or %FALSE to continue the emission.
6830    *
6831    * Since: 0.6
6832    */
6833   actor_signals[CAPTURED_EVENT] =
6834     g_signal_new (I_("captured-event"),
6835                   G_TYPE_FROM_CLASS (object_class),
6836                   G_SIGNAL_RUN_LAST,
6837                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6838                   _clutter_boolean_handled_accumulator, NULL,
6839                   _clutter_marshal_BOOLEAN__BOXED,
6840                   G_TYPE_BOOLEAN, 1,
6841                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6842
6843   /**
6844    * ClutterActor::paint:
6845    * @actor: the #ClutterActor that received the signal
6846    *
6847    * The ::paint signal is emitted each time an actor is being painted.
6848    *
6849    * Subclasses of #ClutterActor should override the class signal handler
6850    * and paint themselves in that function.
6851    *
6852    * It is possible to connect a handler to the ::paint signal in order
6853    * to set up some custom aspect of a paint.
6854    *
6855    * Since: 0.8
6856    */
6857   actor_signals[PAINT] =
6858     g_signal_new (I_("paint"),
6859                   G_TYPE_FROM_CLASS (object_class),
6860                   G_SIGNAL_RUN_LAST |
6861                   G_SIGNAL_NO_HOOKS,
6862                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6863                   NULL, NULL,
6864                   _clutter_marshal_VOID__VOID,
6865                   G_TYPE_NONE, 0);
6866   /**
6867    * ClutterActor::realize:
6868    * @actor: the #ClutterActor that received the signal
6869    *
6870    * The ::realize signal is emitted each time an actor is being
6871    * realized.
6872    *
6873    * Since: 0.8
6874    */
6875   actor_signals[REALIZE] =
6876     g_signal_new (I_("realize"),
6877                   G_TYPE_FROM_CLASS (object_class),
6878                   G_SIGNAL_RUN_LAST,
6879                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6880                   NULL, NULL,
6881                   _clutter_marshal_VOID__VOID,
6882                   G_TYPE_NONE, 0);
6883   /**
6884    * ClutterActor::unrealize:
6885    * @actor: the #ClutterActor that received the signal
6886    *
6887    * The ::unrealize signal is emitted each time an actor is being
6888    * unrealized.
6889    *
6890    * Since: 0.8
6891    */
6892   actor_signals[UNREALIZE] =
6893     g_signal_new (I_("unrealize"),
6894                   G_TYPE_FROM_CLASS (object_class),
6895                   G_SIGNAL_RUN_LAST,
6896                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6897                   NULL, NULL,
6898                   _clutter_marshal_VOID__VOID,
6899                   G_TYPE_NONE, 0);
6900
6901   /**
6902    * ClutterActor::pick:
6903    * @actor: the #ClutterActor that received the signal
6904    * @color: the #ClutterColor to be used when picking
6905    *
6906    * The ::pick signal is emitted each time an actor is being painted
6907    * in "pick mode". The pick mode is used to identify the actor during
6908    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6909    * The actor should paint its shape using the passed @pick_color.
6910    *
6911    * Subclasses of #ClutterActor should override the class signal handler
6912    * and paint themselves in that function.
6913    *
6914    * It is possible to connect a handler to the ::pick signal in order
6915    * to set up some custom aspect of a paint in pick mode.
6916    *
6917    * Since: 1.0
6918    */
6919   actor_signals[PICK] =
6920     g_signal_new (I_("pick"),
6921                   G_TYPE_FROM_CLASS (object_class),
6922                   G_SIGNAL_RUN_LAST,
6923                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6924                   NULL, NULL,
6925                   _clutter_marshal_VOID__BOXED,
6926                   G_TYPE_NONE, 1,
6927                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6928
6929   /**
6930    * ClutterActor::allocation-changed:
6931    * @actor: the #ClutterActor that emitted the signal
6932    * @box: a #ClutterActorBox with the new allocation
6933    * @flags: #ClutterAllocationFlags for the allocation
6934    *
6935    * The ::allocation-changed signal is emitted when the
6936    * #ClutterActor:allocation property changes. Usually, application
6937    * code should just use the notifications for the :allocation property
6938    * but if you want to track the allocation flags as well, for instance
6939    * to know whether the absolute origin of @actor changed, then you might
6940    * want use this signal instead.
6941    *
6942    * Since: 1.0
6943    */
6944   actor_signals[ALLOCATION_CHANGED] =
6945     g_signal_new (I_("allocation-changed"),
6946                   G_TYPE_FROM_CLASS (object_class),
6947                   G_SIGNAL_RUN_LAST,
6948                   0,
6949                   NULL, NULL,
6950                   _clutter_marshal_VOID__BOXED_FLAGS,
6951                   G_TYPE_NONE, 2,
6952                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6953                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6954 }
6955
6956 static void
6957 clutter_actor_init (ClutterActor *self)
6958 {
6959   ClutterActorPrivate *priv;
6960
6961   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6962
6963   priv->id = _clutter_context_acquire_id (self);
6964   priv->pick_id = -1;
6965
6966   priv->opacity = 0xff;
6967   priv->show_on_set_parent = TRUE;
6968
6969   priv->needs_width_request = TRUE;
6970   priv->needs_height_request = TRUE;
6971   priv->needs_allocation = TRUE;
6972
6973   priv->cached_width_age = 1;
6974   priv->cached_height_age = 1;
6975
6976   priv->opacity_override = -1;
6977   priv->enable_model_view_transform = TRUE;
6978
6979   /* Initialize an empty paint volume to start with */
6980   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6981   priv->last_paint_volume_valid = TRUE;
6982
6983   priv->transform_valid = FALSE;
6984
6985   /* the default is to stretch the content, to match the
6986    * current behaviour of basically all actors. also, it's
6987    * the easiest thing to compute.
6988    */
6989   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
6990   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
6991   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
6992 }
6993
6994 /**
6995  * clutter_actor_new:
6996  *
6997  * Creates a new #ClutterActor.
6998  *
6999  * A newly created actor has a floating reference, which will be sunk
7000  * when it is added to another actor.
7001  *
7002  * Return value: (transfer full): the newly created #ClutterActor
7003  *
7004  * Since: 1.10
7005  */
7006 ClutterActor *
7007 clutter_actor_new (void)
7008 {
7009   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7010 }
7011
7012 /**
7013  * clutter_actor_destroy:
7014  * @self: a #ClutterActor
7015  *
7016  * Destroys an actor.  When an actor is destroyed, it will break any
7017  * references it holds to other objects.  If the actor is inside a
7018  * container, the actor will be removed.
7019  *
7020  * When you destroy a container, its children will be destroyed as well.
7021  *
7022  * Note: you cannot destroy the #ClutterStage returned by
7023  * clutter_stage_get_default().
7024  */
7025 void
7026 clutter_actor_destroy (ClutterActor *self)
7027 {
7028   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7029
7030   g_object_ref (self);
7031
7032   /* avoid recursion while destroying */
7033   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7034     {
7035       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7036
7037       g_object_run_dispose (G_OBJECT (self));
7038
7039       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7040     }
7041
7042   g_object_unref (self);
7043 }
7044
7045 void
7046 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7047                                     ClutterPaintVolume *clip)
7048 {
7049   ClutterActorPrivate *priv = self->priv;
7050   ClutterPaintVolume *pv;
7051   gboolean clipped;
7052
7053   /* Remove queue entry early in the process, otherwise a new
7054      queue_redraw() during signal handling could put back this
7055      object in the stage redraw list (but the entry is freed as
7056      soon as we return from this function, causing a segfault
7057      later)
7058   */
7059   priv->queue_redraw_entry = NULL;
7060
7061   /* If we've been explicitly passed a clip volume then there's
7062    * nothing more to calculate, but otherwise the only thing we know
7063    * is that the change is constrained to the given actor.
7064    *
7065    * The idea is that if we know the paint volume for where the actor
7066    * was last drawn (in eye coordinates) and we also have the paint
7067    * volume for where it will be drawn next (in actor coordinates)
7068    * then if we queue a redraw for both these volumes that will cover
7069    * everything that needs to be redrawn to clear the old view and
7070    * show the latest view of the actor.
7071    *
7072    * Don't clip this redraw if we don't know what position we had for
7073    * the previous redraw since we don't know where to set the clip so
7074    * it will clear the actor as it is currently.
7075    */
7076   if (clip)
7077     {
7078       _clutter_actor_set_queue_redraw_clip (self, clip);
7079       clipped = TRUE;
7080     }
7081   else if (G_LIKELY (priv->last_paint_volume_valid))
7082     {
7083       pv = _clutter_actor_get_paint_volume_mutable (self);
7084       if (pv)
7085         {
7086           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7087
7088           /* make sure we redraw the actors old position... */
7089           _clutter_actor_set_queue_redraw_clip (stage,
7090                                                 &priv->last_paint_volume);
7091           _clutter_actor_signal_queue_redraw (stage, stage);
7092           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7093
7094           /* XXX: Ideally the redraw signal would take a clip volume
7095            * argument, but that would be an ABI break. Until we can
7096            * break the ABI we pass the argument out-of-band
7097            */
7098
7099           /* setup the clip for the actors new position... */
7100           _clutter_actor_set_queue_redraw_clip (self, pv);
7101           clipped = TRUE;
7102         }
7103       else
7104         clipped = FALSE;
7105     }
7106   else
7107     clipped = FALSE;
7108
7109   _clutter_actor_signal_queue_redraw (self, self);
7110
7111   /* Just in case anyone is manually firing redraw signals without
7112    * using the public queue_redraw() API we are careful to ensure that
7113    * our out-of-band clip member is cleared before returning...
7114    *
7115    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7116    */
7117   if (G_LIKELY (clipped))
7118     _clutter_actor_set_queue_redraw_clip (self, NULL);
7119 }
7120
7121 static void
7122 _clutter_actor_get_allocation_clip (ClutterActor *self,
7123                                     ClutterActorBox *clip)
7124 {
7125   ClutterActorBox allocation;
7126
7127   /* XXX: we don't care if we get an out of date allocation here
7128    * because clutter_actor_queue_redraw_with_clip knows to ignore
7129    * the clip if the actor's allocation is invalid.
7130    *
7131    * This is noted because clutter_actor_get_allocation_box does some
7132    * unnecessary work to support buggy code with a comment suggesting
7133    * that it could be changed later which would be good for this use
7134    * case!
7135    */
7136   clutter_actor_get_allocation_box (self, &allocation);
7137
7138   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7139    * actor's own coordinate space but the allocation is in parent
7140    * coordinates */
7141   clip->x1 = 0;
7142   clip->y1 = 0;
7143   clip->x2 = allocation.x2 - allocation.x1;
7144   clip->y2 = allocation.y2 - allocation.y1;
7145 }
7146
7147 void
7148 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7149                                   ClutterRedrawFlags  flags,
7150                                   ClutterPaintVolume *volume,
7151                                   ClutterEffect      *effect)
7152 {
7153   ClutterActorPrivate *priv = self->priv;
7154   ClutterPaintVolume allocation_pv;
7155   ClutterPaintVolume *pv;
7156   gboolean should_free_pv;
7157   ClutterActor *stage;
7158
7159   /* Here's an outline of the actor queue redraw mechanism:
7160    *
7161    * The process starts in one of the following two functions which
7162    * are wrappers for this function:
7163    * clutter_actor_queue_redraw
7164    * _clutter_actor_queue_redraw_with_clip
7165    *
7166    * additionally, an effect can queue a redraw by wrapping this
7167    * function in clutter_effect_queue_rerun
7168    *
7169    * This functions queues an entry in a list associated with the
7170    * stage which is a list of actors that queued a redraw while
7171    * updating the timelines, performing layouting and processing other
7172    * mainloop sources before the next paint starts.
7173    *
7174    * We aim to minimize the processing done at this point because
7175    * there is a good chance other events will happen while updating
7176    * the scenegraph that would invalidate any expensive work we might
7177    * otherwise try to do here. For example we don't try and resolve
7178    * the screen space bounding box of an actor at this stage so as to
7179    * minimize how much of the screen redraw because it's possible
7180    * something else will happen which will force a full redraw anyway.
7181    *
7182    * When all updates are complete and we come to paint the stage then
7183    * we iterate this list and actually emit the "queue-redraw" signals
7184    * for each of the listed actors which will bubble up to the stage
7185    * for each actor and at that point we will transform the actors
7186    * paint volume into screen coordinates to determine the clip region
7187    * for what needs to be redrawn in the next paint.
7188    *
7189    * Besides minimizing redundant work another reason for this
7190    * deferred design is that it's more likely we will be able to
7191    * determine the paint volume of an actor once we've finished
7192    * updating the scenegraph because its allocation should be up to
7193    * date. NB: If we can't determine an actors paint volume then we
7194    * can't automatically queue a clipped redraw which can make a big
7195    * difference to performance.
7196    *
7197    * So the control flow goes like this:
7198    * One of clutter_actor_queue_redraw,
7199    *        _clutter_actor_queue_redraw_with_clip
7200    *     or clutter_effect_queue_rerun
7201    *
7202    * then control moves to:
7203    *   _clutter_stage_queue_actor_redraw
7204    *
7205    * later during _clutter_stage_do_update, once relayouting is done
7206    * and the scenegraph has been updated we will call:
7207    * _clutter_stage_finish_queue_redraws
7208    *
7209    * _clutter_stage_finish_queue_redraws will call
7210    * _clutter_actor_finish_queue_redraw for each listed actor.
7211    * Note: actors *are* allowed to queue further redraws during this
7212    * process (considering clone actors or texture_new_from_actor which
7213    * respond to their source queueing a redraw by queuing a redraw
7214    * themselves). We repeat the process until the list is empty.
7215    *
7216    * This will result in the "queue-redraw" signal being fired for
7217    * each actor which will pass control to the default signal handler:
7218    * clutter_actor_real_queue_redraw
7219    *
7220    * This will bubble up to the stages handler:
7221    * clutter_stage_real_queue_redraw
7222    *
7223    * clutter_stage_real_queue_redraw will transform the actors paint
7224    * volume into screen space and add it as a clip region for the next
7225    * paint.
7226    */
7227
7228   /* ignore queueing a redraw for actors being destroyed */
7229   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7230     return;
7231
7232   stage = _clutter_actor_get_stage_internal (self);
7233
7234   /* Ignore queueing a redraw for actors not descended from a stage */
7235   if (stage == NULL)
7236     return;
7237
7238   /* ignore queueing a redraw on stages that are being destroyed */
7239   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7240     return;
7241
7242   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7243     {
7244       ClutterActorBox allocation_clip;
7245       ClutterVertex origin;
7246
7247       /* If the actor doesn't have a valid allocation then we will
7248        * queue a full stage redraw. */
7249       if (priv->needs_allocation)
7250         {
7251           /* NB: NULL denotes an undefined clip which will result in a
7252            * full redraw... */
7253           _clutter_actor_set_queue_redraw_clip (self, NULL);
7254           _clutter_actor_signal_queue_redraw (self, self);
7255           return;
7256         }
7257
7258       _clutter_paint_volume_init_static (&allocation_pv, self);
7259       pv = &allocation_pv;
7260
7261       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7262
7263       origin.x = allocation_clip.x1;
7264       origin.y = allocation_clip.y1;
7265       origin.z = 0;
7266       clutter_paint_volume_set_origin (pv, &origin);
7267       clutter_paint_volume_set_width (pv,
7268                                       allocation_clip.x2 - allocation_clip.x1);
7269       clutter_paint_volume_set_height (pv,
7270                                        allocation_clip.y2 -
7271                                        allocation_clip.y1);
7272       should_free_pv = TRUE;
7273     }
7274   else
7275     {
7276       pv = volume;
7277       should_free_pv = FALSE;
7278     }
7279
7280   self->priv->queue_redraw_entry =
7281     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7282                                        priv->queue_redraw_entry,
7283                                        self,
7284                                        pv);
7285
7286   if (should_free_pv)
7287     clutter_paint_volume_free (pv);
7288
7289   /* If this is the first redraw queued then we can directly use the
7290      effect parameter */
7291   if (!priv->is_dirty)
7292     priv->effect_to_redraw = effect;
7293   /* Otherwise we need to merge it with the existing effect parameter */
7294   else if (effect != NULL)
7295     {
7296       /* If there's already an effect then we need to use whichever is
7297          later in the chain of actors. Otherwise a full redraw has
7298          already been queued on the actor so we need to ignore the
7299          effect parameter */
7300       if (priv->effect_to_redraw != NULL)
7301         {
7302           if (priv->effects == NULL)
7303             g_warning ("Redraw queued with an effect that is "
7304                        "not applied to the actor");
7305           else
7306             {
7307               const GList *l;
7308
7309               for (l = _clutter_meta_group_peek_metas (priv->effects);
7310                    l != NULL;
7311                    l = l->next)
7312                 {
7313                   if (l->data == priv->effect_to_redraw ||
7314                       l->data == effect)
7315                     priv->effect_to_redraw = l->data;
7316                 }
7317             }
7318         }
7319     }
7320   else
7321     {
7322       /* If no effect is specified then we need to redraw the whole
7323          actor */
7324       priv->effect_to_redraw = NULL;
7325     }
7326
7327   priv->is_dirty = TRUE;
7328 }
7329
7330 /**
7331  * clutter_actor_queue_redraw:
7332  * @self: A #ClutterActor
7333  *
7334  * Queues up a redraw of an actor and any children. The redraw occurs
7335  * once the main loop becomes idle (after the current batch of events
7336  * has been processed, roughly).
7337  *
7338  * Applications rarely need to call this, as redraws are handled
7339  * automatically by modification functions.
7340  *
7341  * This function will not do anything if @self is not visible, or
7342  * if the actor is inside an invisible part of the scenegraph.
7343  *
7344  * Also be aware that painting is a NOP for actors with an opacity of
7345  * 0
7346  *
7347  * When you are implementing a custom actor you must queue a redraw
7348  * whenever some private state changes that will affect painting or
7349  * picking of your actor.
7350  */
7351 void
7352 clutter_actor_queue_redraw (ClutterActor *self)
7353 {
7354   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7355
7356   _clutter_actor_queue_redraw_full (self,
7357                                     0, /* flags */
7358                                     NULL, /* clip volume */
7359                                     NULL /* effect */);
7360 }
7361
7362 /*< private >
7363  * _clutter_actor_queue_redraw_with_clip:
7364  * @self: A #ClutterActor
7365  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7366  *   this queue redraw.
7367  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7368  *   redrawn or %NULL if you are just using a @flag to state your
7369  *   desired clipping.
7370  *
7371  * Queues up a clipped redraw of an actor and any children. The redraw
7372  * occurs once the main loop becomes idle (after the current batch of
7373  * events has been processed, roughly).
7374  *
7375  * If no flags are given the clip volume is defined by @volume
7376  * specified in actor coordinates and tells Clutter that only content
7377  * within this volume has been changed so Clutter can optionally
7378  * optimize the redraw.
7379  *
7380  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7381  * should be %NULL and this tells Clutter to use the actor's current
7382  * allocation as a clip box. This flag can only be used for 2D actors,
7383  * because any actor with depth may be projected outside its
7384  * allocation.
7385  *
7386  * Applications rarely need to call this, as redraws are handled
7387  * automatically by modification functions.
7388  *
7389  * This function will not do anything if @self is not visible, or if
7390  * the actor is inside an invisible part of the scenegraph.
7391  *
7392  * Also be aware that painting is a NOP for actors with an opacity of
7393  * 0
7394  *
7395  * When you are implementing a custom actor you must queue a redraw
7396  * whenever some private state changes that will affect painting or
7397  * picking of your actor.
7398  */
7399 void
7400 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7401                                        ClutterRedrawFlags  flags,
7402                                        ClutterPaintVolume *volume)
7403 {
7404   _clutter_actor_queue_redraw_full (self,
7405                                     flags, /* flags */
7406                                     volume, /* clip volume */
7407                                     NULL /* effect */);
7408 }
7409
7410 static void
7411 _clutter_actor_queue_only_relayout (ClutterActor *self)
7412 {
7413   ClutterActorPrivate *priv = self->priv;
7414
7415   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7416     return;
7417
7418   if (priv->needs_width_request &&
7419       priv->needs_height_request &&
7420       priv->needs_allocation)
7421     return; /* save some cpu cycles */
7422
7423 #if CLUTTER_ENABLE_DEBUG
7424   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7425     {
7426       g_warning ("The actor '%s' is currently inside an allocation "
7427                  "cycle; calling clutter_actor_queue_relayout() is "
7428                  "not recommended",
7429                  _clutter_actor_get_debug_name (self));
7430     }
7431 #endif /* CLUTTER_ENABLE_DEBUG */
7432
7433   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7434 }
7435
7436 /**
7437  * clutter_actor_queue_redraw_with_clip:
7438  * @self: a #ClutterActor
7439  * @clip: (allow-none): a rectangular clip region, or %NULL
7440  *
7441  * Queues a redraw on @self limited to a specific, actor-relative
7442  * rectangular area.
7443  *
7444  * If @clip is %NULL this function is equivalent to
7445  * clutter_actor_queue_redraw().
7446  *
7447  * Since: 1.10
7448  */
7449 void
7450 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7451                                       const cairo_rectangle_int_t *clip)
7452 {
7453   ClutterPaintVolume volume;
7454   ClutterVertex origin;
7455
7456   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7457
7458   if (clip == NULL)
7459     {
7460       clutter_actor_queue_redraw (self);
7461       return;
7462     }
7463
7464   _clutter_paint_volume_init_static (&volume, self);
7465
7466   origin.x = clip->x;
7467   origin.y = clip->y;
7468   origin.z = 0.0f;
7469
7470   clutter_paint_volume_set_origin (&volume, &origin);
7471   clutter_paint_volume_set_width (&volume, clip->width);
7472   clutter_paint_volume_set_height (&volume, clip->height);
7473
7474   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7475
7476   clutter_paint_volume_free (&volume);
7477 }
7478
7479 /**
7480  * clutter_actor_queue_relayout:
7481  * @self: A #ClutterActor
7482  *
7483  * Indicates that the actor's size request or other layout-affecting
7484  * properties may have changed. This function is used inside #ClutterActor
7485  * subclass implementations, not by applications directly.
7486  *
7487  * Queueing a new layout automatically queues a redraw as well.
7488  *
7489  * Since: 0.8
7490  */
7491 void
7492 clutter_actor_queue_relayout (ClutterActor *self)
7493 {
7494   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7495
7496   _clutter_actor_queue_only_relayout (self);
7497   clutter_actor_queue_redraw (self);
7498 }
7499
7500 /**
7501  * clutter_actor_get_preferred_size:
7502  * @self: a #ClutterActor
7503  * @min_width_p: (out) (allow-none): return location for the minimum
7504  *   width, or %NULL
7505  * @min_height_p: (out) (allow-none): return location for the minimum
7506  *   height, or %NULL
7507  * @natural_width_p: (out) (allow-none): return location for the natural
7508  *   width, or %NULL
7509  * @natural_height_p: (out) (allow-none): return location for the natural
7510  *   height, or %NULL
7511  *
7512  * Computes the preferred minimum and natural size of an actor, taking into
7513  * account the actor's geometry management (either height-for-width
7514  * or width-for-height).
7515  *
7516  * The width and height used to compute the preferred height and preferred
7517  * width are the actor's natural ones.
7518  *
7519  * If you need to control the height for the preferred width, or the width for
7520  * the preferred height, you should use clutter_actor_get_preferred_width()
7521  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7522  * geometry management using the #ClutterActor:request-mode property.
7523  *
7524  * Since: 0.8
7525  */
7526 void
7527 clutter_actor_get_preferred_size (ClutterActor *self,
7528                                   gfloat       *min_width_p,
7529                                   gfloat       *min_height_p,
7530                                   gfloat       *natural_width_p,
7531                                   gfloat       *natural_height_p)
7532 {
7533   ClutterActorPrivate *priv;
7534   gfloat min_width, min_height;
7535   gfloat natural_width, natural_height;
7536
7537   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7538
7539   priv = self->priv;
7540
7541   min_width = min_height = 0;
7542   natural_width = natural_height = 0;
7543
7544   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7545     {
7546       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7547       clutter_actor_get_preferred_width (self, -1,
7548                                          &min_width,
7549                                          &natural_width);
7550       clutter_actor_get_preferred_height (self, natural_width,
7551                                           &min_height,
7552                                           &natural_height);
7553     }
7554   else
7555     {
7556       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7557       clutter_actor_get_preferred_height (self, -1,
7558                                           &min_height,
7559                                           &natural_height);
7560       clutter_actor_get_preferred_width (self, natural_height,
7561                                          &min_width,
7562                                          &natural_width);
7563     }
7564
7565   if (min_width_p)
7566     *min_width_p = min_width;
7567
7568   if (min_height_p)
7569     *min_height_p = min_height;
7570
7571   if (natural_width_p)
7572     *natural_width_p = natural_width;
7573
7574   if (natural_height_p)
7575     *natural_height_p = natural_height;
7576 }
7577
7578 /*< private >
7579  * effective_align:
7580  * @align: a #ClutterActorAlign
7581  * @direction: a #ClutterTextDirection
7582  *
7583  * Retrieves the correct alignment depending on the text direction
7584  *
7585  * Return value: the effective alignment
7586  */
7587 static ClutterActorAlign
7588 effective_align (ClutterActorAlign    align,
7589                  ClutterTextDirection direction)
7590 {
7591   ClutterActorAlign res;
7592
7593   switch (align)
7594     {
7595     case CLUTTER_ACTOR_ALIGN_START:
7596       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7597           ? CLUTTER_ACTOR_ALIGN_END
7598           : CLUTTER_ACTOR_ALIGN_START;
7599       break;
7600
7601     case CLUTTER_ACTOR_ALIGN_END:
7602       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7603           ? CLUTTER_ACTOR_ALIGN_START
7604           : CLUTTER_ACTOR_ALIGN_END;
7605       break;
7606
7607     default:
7608       res = align;
7609       break;
7610     }
7611
7612   return res;
7613 }
7614
7615 static inline void
7616 adjust_for_margin (float  margin_start,
7617                    float  margin_end,
7618                    float *minimum_size,
7619                    float *natural_size,
7620                    float *allocated_start,
7621                    float *allocated_end)
7622 {
7623   *minimum_size -= (margin_start + margin_end);
7624   *natural_size -= (margin_start + margin_end);
7625   *allocated_start += margin_start;
7626   *allocated_end -= margin_end;
7627 }
7628
7629 static inline void
7630 adjust_for_alignment (ClutterActorAlign  alignment,
7631                       float              natural_size,
7632                       float             *allocated_start,
7633                       float             *allocated_end)
7634 {
7635   float allocated_size = *allocated_end - *allocated_start;
7636
7637   switch (alignment)
7638     {
7639     case CLUTTER_ACTOR_ALIGN_FILL:
7640       /* do nothing */
7641       break;
7642
7643     case CLUTTER_ACTOR_ALIGN_START:
7644       /* keep start */
7645       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7646       break;
7647
7648     case CLUTTER_ACTOR_ALIGN_END:
7649       if (allocated_size > natural_size)
7650         {
7651           *allocated_start += (allocated_size - natural_size);
7652           *allocated_end = *allocated_start + natural_size;
7653         }
7654       break;
7655
7656     case CLUTTER_ACTOR_ALIGN_CENTER:
7657       if (allocated_size > natural_size)
7658         {
7659           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7660           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7661         }
7662       break;
7663     }
7664 }
7665
7666 /*< private >
7667  * clutter_actor_adjust_width:
7668  * @self: a #ClutterActor
7669  * @minimum_width: (inout): the actor's preferred minimum width, which
7670  *   will be adjusted depending on the margin
7671  * @natural_width: (inout): the actor's preferred natural width, which
7672  *   will be adjusted depending on the margin
7673  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7674  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7675  *
7676  * Adjusts the preferred and allocated position and size of an actor,
7677  * depending on the margin and alignment properties.
7678  */
7679 static void
7680 clutter_actor_adjust_width (ClutterActor *self,
7681                             gfloat       *minimum_width,
7682                             gfloat       *natural_width,
7683                             gfloat       *adjusted_x1,
7684                             gfloat       *adjusted_x2)
7685 {
7686   ClutterTextDirection text_dir;
7687   const ClutterLayoutInfo *info;
7688
7689   info = _clutter_actor_get_layout_info_or_defaults (self);
7690   text_dir = clutter_actor_get_text_direction (self);
7691
7692   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7693
7694   /* this will tweak natural_width to remove the margin, so that
7695    * adjust_for_alignment() will use the correct size
7696    */
7697   adjust_for_margin (info->margin.left, info->margin.right,
7698                      minimum_width, natural_width,
7699                      adjusted_x1, adjusted_x2);
7700
7701   adjust_for_alignment (effective_align (info->x_align, text_dir),
7702                         *natural_width,
7703                         adjusted_x1, adjusted_x2);
7704 }
7705
7706 /*< private >
7707  * clutter_actor_adjust_height:
7708  * @self: a #ClutterActor
7709  * @minimum_height: (inout): the actor's preferred minimum height, which
7710  *   will be adjusted depending on the margin
7711  * @natural_height: (inout): the actor's preferred natural height, which
7712  *   will be adjusted depending on the margin
7713  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7714  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7715  *
7716  * Adjusts the preferred and allocated position and size of an actor,
7717  * depending on the margin and alignment properties.
7718  */
7719 static void
7720 clutter_actor_adjust_height (ClutterActor *self,
7721                              gfloat       *minimum_height,
7722                              gfloat       *natural_height,
7723                              gfloat       *adjusted_y1,
7724                              gfloat       *adjusted_y2)
7725 {
7726   const ClutterLayoutInfo *info;
7727
7728   info = _clutter_actor_get_layout_info_or_defaults (self);
7729
7730   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7731
7732   /* this will tweak natural_height to remove the margin, so that
7733    * adjust_for_alignment() will use the correct size
7734    */
7735   adjust_for_margin (info->margin.top, info->margin.bottom,
7736                      minimum_height, natural_height,
7737                      adjusted_y1,
7738                      adjusted_y2);
7739
7740   /* we don't use effective_align() here, because text direction
7741    * only affects the horizontal axis
7742    */
7743   adjust_for_alignment (info->y_align,
7744                         *natural_height,
7745                         adjusted_y1,
7746                         adjusted_y2);
7747
7748 }
7749
7750 /* looks for a cached size request for this for_size. If not
7751  * found, returns the oldest entry so it can be overwritten */
7752 static gboolean
7753 _clutter_actor_get_cached_size_request (gfloat         for_size,
7754                                         SizeRequest   *cached_size_requests,
7755                                         SizeRequest  **result)
7756 {
7757   guint i;
7758
7759   *result = &cached_size_requests[0];
7760
7761   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7762     {
7763       SizeRequest *sr;
7764
7765       sr = &cached_size_requests[i];
7766
7767       if (sr->age > 0 &&
7768           sr->for_size == for_size)
7769         {
7770           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7771           *result = sr;
7772           return TRUE;
7773         }
7774       else if (sr->age < (*result)->age)
7775         {
7776           *result = sr;
7777         }
7778     }
7779
7780   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7781
7782   return FALSE;
7783 }
7784
7785 /**
7786  * clutter_actor_get_preferred_width:
7787  * @self: A #ClutterActor
7788  * @for_height: available height when computing the preferred width,
7789  *   or a negative value to indicate that no height is defined
7790  * @min_width_p: (out) (allow-none): return location for minimum width,
7791  *   or %NULL
7792  * @natural_width_p: (out) (allow-none): return location for the natural
7793  *   width, or %NULL
7794  *
7795  * Computes the requested minimum and natural widths for an actor,
7796  * optionally depending on the specified height, or if they are
7797  * already computed, returns the cached values.
7798  *
7799  * An actor may not get its request - depending on the layout
7800  * manager that's in effect.
7801  *
7802  * A request should not incorporate the actor's scale or anchor point;
7803  * those transformations do not affect layout, only rendering.
7804  *
7805  * Since: 0.8
7806  */
7807 void
7808 clutter_actor_get_preferred_width (ClutterActor *self,
7809                                    gfloat        for_height,
7810                                    gfloat       *min_width_p,
7811                                    gfloat       *natural_width_p)
7812 {
7813   float request_min_width, request_natural_width;
7814   SizeRequest *cached_size_request;
7815   const ClutterLayoutInfo *info;
7816   ClutterActorPrivate *priv;
7817   gboolean found_in_cache;
7818
7819   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7820
7821   priv = self->priv;
7822
7823   info = _clutter_actor_get_layout_info_or_defaults (self);
7824
7825   /* we shortcircuit the case of a fixed size set using set_width() */
7826   if (priv->min_width_set && priv->natural_width_set)
7827     {
7828       if (min_width_p != NULL)
7829         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7830
7831       if (natural_width_p != NULL)
7832         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7833
7834       return;
7835     }
7836
7837   /* the remaining cases are:
7838    *
7839    *   - either min_width or natural_width have been set
7840    *   - neither min_width or natural_width have been set
7841    *
7842    * in both cases, we go through the cache (and through the actor in case
7843    * of cache misses) and determine the authoritative value depending on
7844    * the *_set flags.
7845    */
7846
7847   if (!priv->needs_width_request)
7848     {
7849       found_in_cache =
7850         _clutter_actor_get_cached_size_request (for_height,
7851                                                 priv->width_requests,
7852                                                 &cached_size_request);
7853     }
7854   else
7855     {
7856       /* if the actor needs a width request we use the first slot */
7857       found_in_cache = FALSE;
7858       cached_size_request = &priv->width_requests[0];
7859     }
7860
7861   if (!found_in_cache)
7862     {
7863       gfloat minimum_width, natural_width;
7864       ClutterActorClass *klass;
7865
7866       minimum_width = natural_width = 0;
7867
7868       /* adjust for the margin */
7869       if (for_height >= 0)
7870         {
7871           for_height -= (info->margin.top + info->margin.bottom);
7872           if (for_height < 0)
7873             for_height = 0;
7874         }
7875
7876       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7877
7878       klass = CLUTTER_ACTOR_GET_CLASS (self);
7879       klass->get_preferred_width (self, for_height,
7880                                   &minimum_width,
7881                                   &natural_width);
7882
7883       /* adjust for the margin */
7884       minimum_width += (info->margin.left + info->margin.right);
7885       natural_width += (info->margin.left + info->margin.right);
7886
7887       /* Due to accumulated float errors, it's better not to warn
7888        * on this, but just fix it.
7889        */
7890       if (natural_width < minimum_width)
7891         natural_width = minimum_width;
7892
7893       cached_size_request->min_size = minimum_width;
7894       cached_size_request->natural_size = natural_width;
7895       cached_size_request->for_size = for_height;
7896       cached_size_request->age = priv->cached_width_age;
7897
7898       priv->cached_width_age += 1;
7899       priv->needs_width_request = FALSE;
7900     }
7901
7902   if (!priv->min_width_set)
7903     request_min_width = cached_size_request->min_size;
7904   else
7905     request_min_width = info->min_width;
7906
7907   if (!priv->natural_width_set)
7908     request_natural_width = cached_size_request->natural_size;
7909   else
7910     request_natural_width = info->natural_width;
7911
7912   if (min_width_p)
7913     *min_width_p = request_min_width;
7914
7915   if (natural_width_p)
7916     *natural_width_p = request_natural_width;
7917 }
7918
7919 /**
7920  * clutter_actor_get_preferred_height:
7921  * @self: A #ClutterActor
7922  * @for_width: available width to assume in computing desired height,
7923  *   or a negative value to indicate that no width is defined
7924  * @min_height_p: (out) (allow-none): return location for minimum height,
7925  *   or %NULL
7926  * @natural_height_p: (out) (allow-none): return location for natural
7927  *   height, or %NULL
7928  *
7929  * Computes the requested minimum and natural heights for an actor,
7930  * or if they are already computed, returns the cached values.
7931  *
7932  * An actor may not get its request - depending on the layout
7933  * manager that's in effect.
7934  *
7935  * A request should not incorporate the actor's scale or anchor point;
7936  * those transformations do not affect layout, only rendering.
7937  *
7938  * Since: 0.8
7939  */
7940 void
7941 clutter_actor_get_preferred_height (ClutterActor *self,
7942                                     gfloat        for_width,
7943                                     gfloat       *min_height_p,
7944                                     gfloat       *natural_height_p)
7945 {
7946   float request_min_height, request_natural_height;
7947   SizeRequest *cached_size_request;
7948   const ClutterLayoutInfo *info;
7949   ClutterActorPrivate *priv;
7950   gboolean found_in_cache;
7951
7952   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7953
7954   priv = self->priv;
7955
7956   info = _clutter_actor_get_layout_info_or_defaults (self);
7957
7958   /* we shortcircuit the case of a fixed size set using set_height() */
7959   if (priv->min_height_set && priv->natural_height_set)
7960     {
7961       if (min_height_p != NULL)
7962         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7963
7964       if (natural_height_p != NULL)
7965         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7966
7967       return;
7968     }
7969
7970   /* the remaining cases are:
7971    *
7972    *   - either min_height or natural_height have been set
7973    *   - neither min_height or natural_height have been set
7974    *
7975    * in both cases, we go through the cache (and through the actor in case
7976    * of cache misses) and determine the authoritative value depending on
7977    * the *_set flags.
7978    */
7979
7980   if (!priv->needs_height_request)
7981     {
7982       found_in_cache =
7983         _clutter_actor_get_cached_size_request (for_width,
7984                                                 priv->height_requests,
7985                                                 &cached_size_request);
7986     }
7987   else
7988     {
7989       found_in_cache = FALSE;
7990       cached_size_request = &priv->height_requests[0];
7991     }
7992
7993   if (!found_in_cache)
7994     {
7995       gfloat minimum_height, natural_height;
7996       ClutterActorClass *klass;
7997
7998       minimum_height = natural_height = 0;
7999
8000       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8001
8002       /* adjust for margin */
8003       if (for_width >= 0)
8004         {
8005           for_width -= (info->margin.left + info->margin.right);
8006           if (for_width < 0)
8007             for_width = 0;
8008         }
8009
8010       klass = CLUTTER_ACTOR_GET_CLASS (self);
8011       klass->get_preferred_height (self, for_width,
8012                                    &minimum_height,
8013                                    &natural_height);
8014
8015       /* adjust for margin */
8016       minimum_height += (info->margin.top + info->margin.bottom);
8017       natural_height += (info->margin.top + info->margin.bottom);
8018
8019       /* Due to accumulated float errors, it's better not to warn
8020        * on this, but just fix it.
8021        */
8022       if (natural_height < minimum_height)
8023         natural_height = minimum_height;
8024
8025       cached_size_request->min_size = minimum_height;
8026       cached_size_request->natural_size = natural_height;
8027       cached_size_request->for_size = for_width;
8028       cached_size_request->age = priv->cached_height_age;
8029
8030       priv->cached_height_age += 1;
8031       priv->needs_height_request = FALSE;
8032     }
8033
8034   if (!priv->min_height_set)
8035     request_min_height = cached_size_request->min_size;
8036   else
8037     request_min_height = info->min_height;
8038
8039   if (!priv->natural_height_set)
8040     request_natural_height = cached_size_request->natural_size;
8041   else
8042     request_natural_height = info->natural_height;
8043
8044   if (min_height_p)
8045     *min_height_p = request_min_height;
8046
8047   if (natural_height_p)
8048     *natural_height_p = request_natural_height;
8049 }
8050
8051 /**
8052  * clutter_actor_get_allocation_box:
8053  * @self: A #ClutterActor
8054  * @box: (out): the function fills this in with the actor's allocation
8055  *
8056  * Gets the layout box an actor has been assigned. The allocation can
8057  * only be assumed valid inside a paint() method; anywhere else, it
8058  * may be out-of-date.
8059  *
8060  * An allocation does not incorporate the actor's scale or anchor point;
8061  * those transformations do not affect layout, only rendering.
8062  *
8063  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8064  * of functions inside the implementation of the get_preferred_width()
8065  * or get_preferred_height() virtual functions.</note>
8066  *
8067  * Since: 0.8
8068  */
8069 void
8070 clutter_actor_get_allocation_box (ClutterActor    *self,
8071                                   ClutterActorBox *box)
8072 {
8073   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8074
8075   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8076    * which limits calling get_allocation to inside paint() basically; or
8077    * we can 2) force a layout, which could be expensive if someone calls
8078    * get_allocation somewhere silly; or we can 3) just return the latest
8079    * value, allowing it to be out-of-date, and assume people know what
8080    * they are doing.
8081    *
8082    * The least-surprises approach that keeps existing code working is
8083    * likely to be 2). People can end up doing some inefficient things,
8084    * though, and in general code that requires 2) is probably broken.
8085    */
8086
8087   /* this implements 2) */
8088   if (G_UNLIKELY (self->priv->needs_allocation))
8089     {
8090       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8091
8092       /* do not queue a relayout on an unparented actor */
8093       if (stage)
8094         _clutter_stage_maybe_relayout (stage);
8095     }
8096
8097   /* commenting out the code above and just keeping this assigment
8098    * implements 3)
8099    */
8100   *box = self->priv->allocation;
8101 }
8102
8103 /**
8104  * clutter_actor_get_allocation_geometry:
8105  * @self: A #ClutterActor
8106  * @geom: (out): allocation geometry in pixels
8107  *
8108  * Gets the layout box an actor has been assigned.  The allocation can
8109  * only be assumed valid inside a paint() method; anywhere else, it
8110  * may be out-of-date.
8111  *
8112  * An allocation does not incorporate the actor's scale or anchor point;
8113  * those transformations do not affect layout, only rendering.
8114  *
8115  * The returned rectangle is in pixels.
8116  *
8117  * Since: 0.8
8118  */
8119 void
8120 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8121                                        ClutterGeometry *geom)
8122 {
8123   ClutterActorBox box;
8124
8125   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8126   g_return_if_fail (geom != NULL);
8127
8128   clutter_actor_get_allocation_box (self, &box);
8129
8130   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8131   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8132   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8133   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8134 }
8135
8136 static void
8137 clutter_actor_update_constraints (ClutterActor    *self,
8138                                   ClutterActorBox *allocation)
8139 {
8140   ClutterActorPrivate *priv = self->priv;
8141   const GList *constraints, *l;
8142
8143   if (priv->constraints == NULL)
8144     return;
8145
8146   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8147   for (l = constraints; l != NULL; l = l->next)
8148     {
8149       ClutterConstraint *constraint = l->data;
8150       ClutterActorMeta *meta = l->data;
8151
8152       if (clutter_actor_meta_get_enabled (meta))
8153         {
8154           _clutter_constraint_update_allocation (constraint,
8155                                                  self,
8156                                                  allocation);
8157         }
8158     }
8159 }
8160
8161 /*< private >
8162  * clutter_actor_adjust_allocation:
8163  * @self: a #ClutterActor
8164  * @allocation: (inout): the allocation to adjust
8165  *
8166  * Adjusts the passed allocation box taking into account the actor's
8167  * layout information, like alignment, expansion, and margin.
8168  */
8169 static void
8170 clutter_actor_adjust_allocation (ClutterActor    *self,
8171                                  ClutterActorBox *allocation)
8172 {
8173   ClutterActorBox adj_allocation;
8174   float alloc_width, alloc_height;
8175   float min_width, min_height;
8176   float nat_width, nat_height;
8177   ClutterRequestMode req_mode;
8178
8179   adj_allocation = *allocation;
8180
8181   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8182
8183   /* we want to hit the cache, so we use the public API */
8184   req_mode = clutter_actor_get_request_mode (self);
8185
8186   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8187     {
8188       clutter_actor_get_preferred_width (self, -1,
8189                                          &min_width,
8190                                          &nat_width);
8191       clutter_actor_get_preferred_height (self, alloc_width,
8192                                           &min_height,
8193                                           &nat_height);
8194     }
8195   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8196     {
8197       clutter_actor_get_preferred_height (self, -1,
8198                                           &min_height,
8199                                           &nat_height);
8200       clutter_actor_get_preferred_height (self, alloc_height,
8201                                           &min_width,
8202                                           &nat_width);
8203     }
8204
8205 #ifdef CLUTTER_ENABLE_DEBUG
8206   /* warn about underallocations */
8207   if (_clutter_diagnostic_enabled () &&
8208       (floorf (min_width - alloc_width) > 0 ||
8209        floorf (min_height - alloc_height) > 0))
8210     {
8211       ClutterActor *parent = clutter_actor_get_parent (self);
8212
8213       /* the only actors that are allowed to be underallocated are the Stage,
8214        * as it doesn't have an implicit size, and Actors that specifically
8215        * told us that they want to opt-out from layout control mechanisms
8216        * through the NO_LAYOUT escape hatch.
8217        */
8218       if (parent != NULL &&
8219           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8220         {
8221           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8222                      "of %.2f x %.2f from its parent actor '%s', but its "
8223                      "requested minimum size is of %.2f x %.2f",
8224                      _clutter_actor_get_debug_name (self),
8225                      alloc_width, alloc_height,
8226                      _clutter_actor_get_debug_name (parent),
8227                      min_width, min_height);
8228         }
8229     }
8230 #endif
8231
8232   clutter_actor_adjust_width (self,
8233                               &min_width,
8234                               &nat_width,
8235                               &adj_allocation.x1,
8236                               &adj_allocation.x2);
8237
8238   clutter_actor_adjust_height (self,
8239                                &min_height,
8240                                &nat_height,
8241                                &adj_allocation.y1,
8242                                &adj_allocation.y2);
8243
8244   /* we maintain the invariant that an allocation cannot be adjusted
8245    * to be outside the parent-given box
8246    */
8247   if (adj_allocation.x1 < allocation->x1 ||
8248       adj_allocation.y1 < allocation->y1 ||
8249       adj_allocation.x2 > allocation->x2 ||
8250       adj_allocation.y2 > allocation->y2)
8251     {
8252       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8253                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8254                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8255                  _clutter_actor_get_debug_name (self),
8256                  adj_allocation.x1, adj_allocation.y1,
8257                  adj_allocation.x2 - adj_allocation.x1,
8258                  adj_allocation.y2 - adj_allocation.y1,
8259                  allocation->x1, allocation->y1,
8260                  allocation->x2 - allocation->x1,
8261                  allocation->y2 - allocation->y1);
8262       return;
8263     }
8264
8265   *allocation = adj_allocation;
8266 }
8267
8268 /**
8269  * clutter_actor_allocate:
8270  * @self: A #ClutterActor
8271  * @box: new allocation of the actor, in parent-relative coordinates
8272  * @flags: flags that control the allocation
8273  *
8274  * Called by the parent of an actor to assign the actor its size.
8275  * Should never be called by applications (except when implementing
8276  * a container or layout manager).
8277  *
8278  * Actors can know from their allocation box whether they have moved
8279  * with respect to their parent actor. The @flags parameter describes
8280  * additional information about the allocation, for instance whether
8281  * the parent has moved with respect to the stage, for example because
8282  * a grandparent's origin has moved.
8283  *
8284  * Since: 0.8
8285  */
8286 void
8287 clutter_actor_allocate (ClutterActor           *self,
8288                         const ClutterActorBox  *box,
8289                         ClutterAllocationFlags  flags)
8290 {
8291   ClutterActorPrivate *priv;
8292   ClutterActorClass *klass;
8293   ClutterActorBox old_allocation, real_allocation;
8294   gboolean origin_changed, child_moved, size_changed;
8295   gboolean stage_allocation_changed;
8296
8297   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8298   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8299     {
8300       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8301                  "which isn't a descendent of the stage!\n",
8302                  self, _clutter_actor_get_debug_name (self));
8303       return;
8304     }
8305
8306   priv = self->priv;
8307
8308   old_allocation = priv->allocation;
8309   real_allocation = *box;
8310
8311   /* constraints are allowed to modify the allocation only here; we do
8312    * this prior to all the other checks so that we can bail out if the
8313    * allocation did not change
8314    */
8315   clutter_actor_update_constraints (self, &real_allocation);
8316
8317   /* adjust the allocation depending on the align/margin properties */
8318   clutter_actor_adjust_allocation (self, &real_allocation);
8319
8320   if (real_allocation.x2 < real_allocation.x1 ||
8321       real_allocation.y2 < real_allocation.y1)
8322     {
8323       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8324                  _clutter_actor_get_debug_name (self),
8325                  real_allocation.x2 - real_allocation.x1,
8326                  real_allocation.y2 - real_allocation.y1);
8327     }
8328
8329   /* we allow 0-sized actors, but not negative-sized ones */
8330   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8331   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8332
8333   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8334
8335   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8336                  real_allocation.y1 != old_allocation.y1);
8337
8338   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8339                   real_allocation.y2 != old_allocation.y2);
8340
8341   if (origin_changed || child_moved || size_changed)
8342     stage_allocation_changed = TRUE;
8343   else
8344     stage_allocation_changed = FALSE;
8345
8346   /* If we get an allocation "out of the blue"
8347    * (we did not queue relayout), then we want to
8348    * ignore it. But if we have needs_allocation set,
8349    * we want to guarantee that allocate() virtual
8350    * method is always called, i.e. that queue_relayout()
8351    * always results in an allocate() invocation on
8352    * an actor.
8353    *
8354    * The optimization here is to avoid re-allocating
8355    * actors that did not queue relayout and were
8356    * not moved.
8357    */
8358   if (!priv->needs_allocation && !stage_allocation_changed)
8359     {
8360       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8361       return;
8362     }
8363
8364   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8365    * clutter_actor_allocate(), it indicates whether the parent has its
8366    * absolute origin moved; when passed in to ClutterActor::allocate()
8367    * virtual method though, it indicates whether the child has its
8368    * absolute origin moved.  So we set it when child_moved is TRUE
8369    */
8370   if (child_moved)
8371     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8372
8373   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8374
8375   klass = CLUTTER_ACTOR_GET_CLASS (self);
8376   klass->allocate (self, &real_allocation, flags);
8377
8378   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8379
8380   if (stage_allocation_changed)
8381     clutter_actor_queue_redraw (self);
8382 }
8383
8384 /**
8385  * clutter_actor_set_allocation:
8386  * @self: a #ClutterActor
8387  * @box: a #ClutterActorBox
8388  * @flags: allocation flags
8389  *
8390  * Stores the allocation of @self as defined by @box.
8391  *
8392  * This function can only be called from within the implementation of
8393  * the #ClutterActorClass.allocate() virtual function.
8394  *
8395  * The allocation should have been adjusted to take into account constraints,
8396  * alignment, and margin properties. If you are implementing a #ClutterActor
8397  * subclass that provides its own layout management policy for its children
8398  * instead of using a #ClutterLayoutManager delegate, you should not call
8399  * this function on the children of @self; instead, you should call
8400  * clutter_actor_allocate(), which will adjust the allocation box for
8401  * you.
8402  *
8403  * This function should only be used by subclasses of #ClutterActor
8404  * that wish to store their allocation but cannot chain up to the
8405  * parent's implementation; the default implementation of the
8406  * #ClutterActorClass.allocate() virtual function will call this
8407  * function.
8408  *
8409  * It is important to note that, while chaining up was the recommended
8410  * behaviour for #ClutterActor subclasses prior to the introduction of
8411  * this function, it is recommended to call clutter_actor_set_allocation()
8412  * instead.
8413  *
8414  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8415  * to handle the allocation of its children, this function will call
8416  * the clutter_layout_manager_allocate() function only if the
8417  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8418  * expected that the subclass will call clutter_layout_manager_allocate()
8419  * by itself. For instance, the following code:
8420  *
8421  * |[
8422  * static void
8423  * my_actor_allocate (ClutterActor *actor,
8424  *                    const ClutterActorBox *allocation,
8425  *                    ClutterAllocationFlags flags)
8426  * {
8427  *   ClutterActorBox new_alloc;
8428  *   ClutterAllocationFlags new_flags;
8429  *
8430  *   adjust_allocation (allocation, &amp;new_alloc);
8431  *
8432  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8433  *
8434  *   /&ast; this will use the layout manager set on the actor &ast;/
8435  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8436  * }
8437  * ]|
8438  *
8439  * is equivalent to this:
8440  *
8441  * |[
8442  * static void
8443  * my_actor_allocate (ClutterActor *actor,
8444  *                    const ClutterActorBox *allocation,
8445  *                    ClutterAllocationFlags flags)
8446  * {
8447  *   ClutterLayoutManager *layout;
8448  *   ClutterActorBox new_alloc;
8449  *
8450  *   adjust_allocation (allocation, &amp;new_alloc);
8451  *
8452  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8453  *
8454  *   layout = clutter_actor_get_layout_manager (actor);
8455  *   clutter_layout_manager_allocate (layout,
8456  *                                    CLUTTER_CONTAINER (actor),
8457  *                                    &amp;new_alloc,
8458  *                                    flags);
8459  * }
8460  * ]|
8461  *
8462  * Since: 1.10
8463  */
8464 void
8465 clutter_actor_set_allocation (ClutterActor           *self,
8466                               const ClutterActorBox  *box,
8467                               ClutterAllocationFlags  flags)
8468 {
8469   ClutterActorPrivate *priv;
8470   gboolean changed;
8471
8472   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8473   g_return_if_fail (box != NULL);
8474
8475   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8476     {
8477       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8478                   "can only be called from within the implementation of "
8479                   "the ClutterActor::allocate() virtual function.");
8480       return;
8481     }
8482
8483   priv = self->priv;
8484
8485   g_object_freeze_notify (G_OBJECT (self));
8486
8487   changed = clutter_actor_set_allocation_internal (self, box, flags);
8488
8489   /* we allocate our children before we notify changes in our geometry,
8490    * so that people connecting to properties will be able to get valid
8491    * data out of the sub-tree of the scene graph that has this actor at
8492    * the root.
8493    */
8494   clutter_actor_maybe_layout_children (self, box, flags);
8495
8496   if (changed)
8497     {
8498       ClutterActorBox signal_box = priv->allocation;
8499       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8500
8501       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8502                      &signal_box,
8503                      signal_flags);
8504     }
8505
8506   g_object_thaw_notify (G_OBJECT (self));
8507 }
8508
8509 /**
8510  * clutter_actor_set_geometry:
8511  * @self: A #ClutterActor
8512  * @geometry: A #ClutterGeometry
8513  *
8514  * Sets the actor's fixed position and forces its minimum and natural
8515  * size, in pixels. This means the untransformed actor will have the
8516  * given geometry. This is the same as calling clutter_actor_set_position()
8517  * and clutter_actor_set_size().
8518  *
8519  * Deprecated: 1.10: Use clutter_actor_set_position() and
8520  *   clutter_actor_set_size() instead.
8521  */
8522 void
8523 clutter_actor_set_geometry (ClutterActor          *self,
8524                             const ClutterGeometry *geometry)
8525 {
8526   g_object_freeze_notify (G_OBJECT (self));
8527
8528   clutter_actor_set_position (self, geometry->x, geometry->y);
8529   clutter_actor_set_size (self, geometry->width, geometry->height);
8530
8531   g_object_thaw_notify (G_OBJECT (self));
8532 }
8533
8534 /**
8535  * clutter_actor_get_geometry:
8536  * @self: A #ClutterActor
8537  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8538  *
8539  * Gets the size and position of an actor relative to its parent
8540  * actor. This is the same as calling clutter_actor_get_position() and
8541  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8542  * requested size and position if the actor's allocation is invalid.
8543  *
8544  * Deprecated: 1.10: Use clutter_actor_get_position() and
8545  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8546  *   instead.
8547  */
8548 void
8549 clutter_actor_get_geometry (ClutterActor    *self,
8550                             ClutterGeometry *geometry)
8551 {
8552   gfloat x, y, width, height;
8553
8554   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8555   g_return_if_fail (geometry != NULL);
8556
8557   clutter_actor_get_position (self, &x, &y);
8558   clutter_actor_get_size (self, &width, &height);
8559
8560   geometry->x = (int) x;
8561   geometry->y = (int) y;
8562   geometry->width = (int) width;
8563   geometry->height = (int) height;
8564 }
8565
8566 /**
8567  * clutter_actor_set_position:
8568  * @self: A #ClutterActor
8569  * @x: New left position of actor in pixels.
8570  * @y: New top position of actor in pixels.
8571  *
8572  * Sets the actor's fixed position in pixels relative to any parent
8573  * actor.
8574  *
8575  * If a layout manager is in use, this position will override the
8576  * layout manager and force a fixed position.
8577  */
8578 void
8579 clutter_actor_set_position (ClutterActor *self,
8580                             gfloat        x,
8581                             gfloat        y)
8582 {
8583   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8584
8585   g_object_freeze_notify (G_OBJECT (self));
8586
8587   clutter_actor_set_x (self, x);
8588   clutter_actor_set_y (self, y);
8589
8590   g_object_thaw_notify (G_OBJECT (self));
8591 }
8592
8593 /**
8594  * clutter_actor_get_fixed_position_set:
8595  * @self: A #ClutterActor
8596  *
8597  * Checks whether an actor has a fixed position set (and will thus be
8598  * unaffected by any layout manager).
8599  *
8600  * Return value: %TRUE if the fixed position is set on the actor
8601  *
8602  * Since: 0.8
8603  */
8604 gboolean
8605 clutter_actor_get_fixed_position_set (ClutterActor *self)
8606 {
8607   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8608
8609   return self->priv->position_set;
8610 }
8611
8612 /**
8613  * clutter_actor_set_fixed_position_set:
8614  * @self: A #ClutterActor
8615  * @is_set: whether to use fixed position
8616  *
8617  * Sets whether an actor has a fixed position set (and will thus be
8618  * unaffected by any layout manager).
8619  *
8620  * Since: 0.8
8621  */
8622 void
8623 clutter_actor_set_fixed_position_set (ClutterActor *self,
8624                                       gboolean      is_set)
8625 {
8626   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8627
8628   if (self->priv->position_set == (is_set != FALSE))
8629     return;
8630
8631   self->priv->position_set = is_set != FALSE;
8632   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8633
8634   clutter_actor_queue_relayout (self);
8635 }
8636
8637 /**
8638  * clutter_actor_move_by:
8639  * @self: A #ClutterActor
8640  * @dx: Distance to move Actor on X axis.
8641  * @dy: Distance to move Actor on Y axis.
8642  *
8643  * Moves an actor by the specified distance relative to its current
8644  * position in pixels.
8645  *
8646  * This function modifies the fixed position of an actor and thus removes
8647  * it from any layout management. Another way to move an actor is with an
8648  * anchor point, see clutter_actor_set_anchor_point().
8649  *
8650  * Since: 0.2
8651  */
8652 void
8653 clutter_actor_move_by (ClutterActor *self,
8654                        gfloat        dx,
8655                        gfloat        dy)
8656 {
8657   const ClutterLayoutInfo *info;
8658   gfloat x, y;
8659
8660   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8661
8662   info = _clutter_actor_get_layout_info_or_defaults (self);
8663   x = info->fixed_x;
8664   y = info->fixed_y;
8665
8666   clutter_actor_set_position (self, x + dx, y + dy);
8667 }
8668
8669 static void
8670 clutter_actor_set_min_width (ClutterActor *self,
8671                              gfloat        min_width)
8672 {
8673   ClutterActorPrivate *priv = self->priv;
8674   ClutterActorBox old = { 0, };
8675   ClutterLayoutInfo *info;
8676
8677   /* if we are setting the size on a top-level actor and the
8678    * backend only supports static top-levels (e.g. framebuffers)
8679    * then we ignore the passed value and we override it with
8680    * the stage implementation's preferred size.
8681    */
8682   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8683       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8684     return;
8685
8686   info = _clutter_actor_get_layout_info (self);
8687
8688   if (priv->min_width_set && min_width == info->min_width)
8689     return;
8690
8691   g_object_freeze_notify (G_OBJECT (self));
8692
8693   clutter_actor_store_old_geometry (self, &old);
8694
8695   info->min_width = min_width;
8696   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8697   clutter_actor_set_min_width_set (self, TRUE);
8698
8699   clutter_actor_notify_if_geometry_changed (self, &old);
8700
8701   g_object_thaw_notify (G_OBJECT (self));
8702
8703   clutter_actor_queue_relayout (self);
8704 }
8705
8706 static void
8707 clutter_actor_set_min_height (ClutterActor *self,
8708                               gfloat        min_height)
8709
8710 {
8711   ClutterActorPrivate *priv = self->priv;
8712   ClutterActorBox old = { 0, };
8713   ClutterLayoutInfo *info;
8714
8715   /* if we are setting the size on a top-level actor and the
8716    * backend only supports static top-levels (e.g. framebuffers)
8717    * then we ignore the passed value and we override it with
8718    * the stage implementation's preferred size.
8719    */
8720   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8721       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8722     return;
8723
8724   info = _clutter_actor_get_layout_info (self);
8725
8726   if (priv->min_height_set && min_height == info->min_height)
8727     return;
8728
8729   g_object_freeze_notify (G_OBJECT (self));
8730
8731   clutter_actor_store_old_geometry (self, &old);
8732
8733   info->min_height = min_height;
8734   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8735   clutter_actor_set_min_height_set (self, TRUE);
8736
8737   clutter_actor_notify_if_geometry_changed (self, &old);
8738
8739   g_object_thaw_notify (G_OBJECT (self));
8740
8741   clutter_actor_queue_relayout (self);
8742 }
8743
8744 static void
8745 clutter_actor_set_natural_width (ClutterActor *self,
8746                                  gfloat        natural_width)
8747 {
8748   ClutterActorPrivate *priv = self->priv;
8749   ClutterActorBox old = { 0, };
8750   ClutterLayoutInfo *info;
8751
8752   /* if we are setting the size on a top-level actor and the
8753    * backend only supports static top-levels (e.g. framebuffers)
8754    * then we ignore the passed value and we override it with
8755    * the stage implementation's preferred size.
8756    */
8757   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8758       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8759     return;
8760
8761   info = _clutter_actor_get_layout_info (self);
8762
8763   if (priv->natural_width_set && natural_width == info->natural_width)
8764     return;
8765
8766   g_object_freeze_notify (G_OBJECT (self));
8767
8768   clutter_actor_store_old_geometry (self, &old);
8769
8770   info->natural_width = natural_width;
8771   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8772   clutter_actor_set_natural_width_set (self, TRUE);
8773
8774   clutter_actor_notify_if_geometry_changed (self, &old);
8775
8776   g_object_thaw_notify (G_OBJECT (self));
8777
8778   clutter_actor_queue_relayout (self);
8779 }
8780
8781 static void
8782 clutter_actor_set_natural_height (ClutterActor *self,
8783                                   gfloat        natural_height)
8784 {
8785   ClutterActorPrivate *priv = self->priv;
8786   ClutterActorBox old = { 0, };
8787   ClutterLayoutInfo *info;
8788
8789   /* if we are setting the size on a top-level actor and the
8790    * backend only supports static top-levels (e.g. framebuffers)
8791    * then we ignore the passed value and we override it with
8792    * the stage implementation's preferred size.
8793    */
8794   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8795       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8796     return;
8797
8798   info = _clutter_actor_get_layout_info (self);
8799
8800   if (priv->natural_height_set && natural_height == info->natural_height)
8801     return;
8802
8803   g_object_freeze_notify (G_OBJECT (self));
8804
8805   clutter_actor_store_old_geometry (self, &old);
8806
8807   info->natural_height = natural_height;
8808   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8809   clutter_actor_set_natural_height_set (self, TRUE);
8810
8811   clutter_actor_notify_if_geometry_changed (self, &old);
8812
8813   g_object_thaw_notify (G_OBJECT (self));
8814
8815   clutter_actor_queue_relayout (self);
8816 }
8817
8818 static void
8819 clutter_actor_set_min_width_set (ClutterActor *self,
8820                                  gboolean      use_min_width)
8821 {
8822   ClutterActorPrivate *priv = self->priv;
8823   ClutterActorBox old = { 0, };
8824
8825   if (priv->min_width_set == (use_min_width != FALSE))
8826     return;
8827
8828   clutter_actor_store_old_geometry (self, &old);
8829
8830   priv->min_width_set = use_min_width != FALSE;
8831   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8832
8833   clutter_actor_notify_if_geometry_changed (self, &old);
8834
8835   clutter_actor_queue_relayout (self);
8836 }
8837
8838 static void
8839 clutter_actor_set_min_height_set (ClutterActor *self,
8840                                   gboolean      use_min_height)
8841 {
8842   ClutterActorPrivate *priv = self->priv;
8843   ClutterActorBox old = { 0, };
8844
8845   if (priv->min_height_set == (use_min_height != FALSE))
8846     return;
8847
8848   clutter_actor_store_old_geometry (self, &old);
8849
8850   priv->min_height_set = use_min_height != FALSE;
8851   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8852
8853   clutter_actor_notify_if_geometry_changed (self, &old);
8854
8855   clutter_actor_queue_relayout (self);
8856 }
8857
8858 static void
8859 clutter_actor_set_natural_width_set (ClutterActor *self,
8860                                      gboolean      use_natural_width)
8861 {
8862   ClutterActorPrivate *priv = self->priv;
8863   ClutterActorBox old = { 0, };
8864
8865   if (priv->natural_width_set == (use_natural_width != FALSE))
8866     return;
8867
8868   clutter_actor_store_old_geometry (self, &old);
8869
8870   priv->natural_width_set = use_natural_width != FALSE;
8871   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8872
8873   clutter_actor_notify_if_geometry_changed (self, &old);
8874
8875   clutter_actor_queue_relayout (self);
8876 }
8877
8878 static void
8879 clutter_actor_set_natural_height_set (ClutterActor *self,
8880                                       gboolean      use_natural_height)
8881 {
8882   ClutterActorPrivate *priv = self->priv;
8883   ClutterActorBox old = { 0, };
8884
8885   if (priv->natural_height_set == (use_natural_height != FALSE))
8886     return;
8887
8888   clutter_actor_store_old_geometry (self, &old);
8889
8890   priv->natural_height_set = use_natural_height != FALSE;
8891   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8892
8893   clutter_actor_notify_if_geometry_changed (self, &old);
8894
8895   clutter_actor_queue_relayout (self);
8896 }
8897
8898 /**
8899  * clutter_actor_set_request_mode:
8900  * @self: a #ClutterActor
8901  * @mode: the request mode
8902  *
8903  * Sets the geometry request mode of @self.
8904  *
8905  * The @mode determines the order for invoking
8906  * clutter_actor_get_preferred_width() and
8907  * clutter_actor_get_preferred_height()
8908  *
8909  * Since: 1.2
8910  */
8911 void
8912 clutter_actor_set_request_mode (ClutterActor       *self,
8913                                 ClutterRequestMode  mode)
8914 {
8915   ClutterActorPrivate *priv;
8916
8917   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8918
8919   priv = self->priv;
8920
8921   if (priv->request_mode == mode)
8922     return;
8923
8924   priv->request_mode = mode;
8925
8926   priv->needs_width_request = TRUE;
8927   priv->needs_height_request = TRUE;
8928
8929   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8930
8931   clutter_actor_queue_relayout (self);
8932 }
8933
8934 /**
8935  * clutter_actor_get_request_mode:
8936  * @self: a #ClutterActor
8937  *
8938  * Retrieves the geometry request mode of @self
8939  *
8940  * Return value: the request mode for the actor
8941  *
8942  * Since: 1.2
8943  */
8944 ClutterRequestMode
8945 clutter_actor_get_request_mode (ClutterActor *self)
8946 {
8947   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8948                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8949
8950   return self->priv->request_mode;
8951 }
8952
8953 /* variant of set_width() without checks and without notification
8954  * freeze+thaw, for internal usage only
8955  */
8956 static inline void
8957 clutter_actor_set_width_internal (ClutterActor *self,
8958                                   gfloat        width)
8959 {
8960   if (width >= 0)
8961     {
8962       /* the Stage will use the :min-width to control the minimum
8963        * width to be resized to, so we should not be setting it
8964        * along with the :natural-width
8965        */
8966       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8967         clutter_actor_set_min_width (self, width);
8968
8969       clutter_actor_set_natural_width (self, width);
8970     }
8971   else
8972     {
8973       /* we only unset the :natural-width for the Stage */
8974       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8975         clutter_actor_set_min_width_set (self, FALSE);
8976
8977       clutter_actor_set_natural_width_set (self, FALSE);
8978     }
8979 }
8980
8981 /* variant of set_height() without checks and without notification
8982  * freeze+thaw, for internal usage only
8983  */
8984 static inline void
8985 clutter_actor_set_height_internal (ClutterActor *self,
8986                                    gfloat        height)
8987 {
8988   if (height >= 0)
8989     {
8990       /* see the comment above in set_width_internal() */
8991       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8992         clutter_actor_set_min_height (self, height);
8993
8994       clutter_actor_set_natural_height (self, height);
8995     }
8996   else
8997     {
8998       /* see the comment above in set_width_internal() */
8999       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9000         clutter_actor_set_min_height_set (self, FALSE);
9001
9002       clutter_actor_set_natural_height_set (self, FALSE);
9003     }
9004 }
9005
9006 /**
9007  * clutter_actor_set_size:
9008  * @self: A #ClutterActor
9009  * @width: New width of actor in pixels, or -1
9010  * @height: New height of actor in pixels, or -1
9011  *
9012  * Sets the actor's size request in pixels. This overrides any
9013  * "normal" size request the actor would have. For example
9014  * a text actor might normally request the size of the text;
9015  * this function would force a specific size instead.
9016  *
9017  * If @width and/or @height are -1 the actor will use its
9018  * "normal" size request instead of overriding it, i.e.
9019  * you can "unset" the size with -1.
9020  *
9021  * This function sets or unsets both the minimum and natural size.
9022  */
9023 void
9024 clutter_actor_set_size (ClutterActor *self,
9025                         gfloat        width,
9026                         gfloat        height)
9027 {
9028   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9029
9030   g_object_freeze_notify (G_OBJECT (self));
9031
9032   clutter_actor_set_width (self, width);
9033   clutter_actor_set_height (self, height);
9034
9035   g_object_thaw_notify (G_OBJECT (self));
9036 }
9037
9038 /**
9039  * clutter_actor_get_size:
9040  * @self: A #ClutterActor
9041  * @width: (out) (allow-none): return location for the width, or %NULL.
9042  * @height: (out) (allow-none): return location for the height, or %NULL.
9043  *
9044  * This function tries to "do what you mean" and return
9045  * the size an actor will have. If the actor has a valid
9046  * allocation, the allocation will be returned; otherwise,
9047  * the actors natural size request will be returned.
9048  *
9049  * If you care whether you get the request vs. the allocation, you
9050  * should probably call a different function like
9051  * clutter_actor_get_allocation_box() or
9052  * clutter_actor_get_preferred_width().
9053  *
9054  * Since: 0.2
9055  */
9056 void
9057 clutter_actor_get_size (ClutterActor *self,
9058                         gfloat       *width,
9059                         gfloat       *height)
9060 {
9061   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9062
9063   if (width)
9064     *width = clutter_actor_get_width (self);
9065
9066   if (height)
9067     *height = clutter_actor_get_height (self);
9068 }
9069
9070 /**
9071  * clutter_actor_get_position:
9072  * @self: a #ClutterActor
9073  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9074  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9075  *
9076  * This function tries to "do what you mean" and tell you where the
9077  * actor is, prior to any transformations. Retrieves the fixed
9078  * position of an actor in pixels, if one has been set; otherwise, if
9079  * the allocation is valid, returns the actor's allocated position;
9080  * otherwise, returns 0,0.
9081  *
9082  * The returned position is in pixels.
9083  *
9084  * Since: 0.6
9085  */
9086 void
9087 clutter_actor_get_position (ClutterActor *self,
9088                             gfloat       *x,
9089                             gfloat       *y)
9090 {
9091   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9092
9093   if (x)
9094     *x = clutter_actor_get_x (self);
9095
9096   if (y)
9097     *y = clutter_actor_get_y (self);
9098 }
9099
9100 /**
9101  * clutter_actor_get_transformed_position:
9102  * @self: A #ClutterActor
9103  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9104  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9105  *
9106  * Gets the absolute position of an actor, in pixels relative to the stage.
9107  *
9108  * Since: 0.8
9109  */
9110 void
9111 clutter_actor_get_transformed_position (ClutterActor *self,
9112                                         gfloat       *x,
9113                                         gfloat       *y)
9114 {
9115   ClutterVertex v1;
9116   ClutterVertex v2;
9117
9118   v1.x = v1.y = v1.z = 0;
9119   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9120
9121   if (x)
9122     *x = v2.x;
9123
9124   if (y)
9125     *y = v2.y;
9126 }
9127
9128 /**
9129  * clutter_actor_get_transformed_size:
9130  * @self: A #ClutterActor
9131  * @width: (out) (allow-none): return location for the width, or %NULL
9132  * @height: (out) (allow-none): return location for the height, or %NULL
9133  *
9134  * Gets the absolute size of an actor in pixels, taking into account the
9135  * scaling factors.
9136  *
9137  * If the actor has a valid allocation, the allocated size will be used.
9138  * If the actor has not a valid allocation then the preferred size will
9139  * be transformed and returned.
9140  *
9141  * If you want the transformed allocation, see
9142  * clutter_actor_get_abs_allocation_vertices() instead.
9143  *
9144  * <note>When the actor (or one of its ancestors) is rotated around the
9145  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9146  * as a generic quadrangle; in that case this function returns the size
9147  * of the smallest rectangle that encapsulates the entire quad. Please
9148  * note that in this case no assumptions can be made about the relative
9149  * position of this envelope to the absolute position of the actor, as
9150  * returned by clutter_actor_get_transformed_position(); if you need this
9151  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9152  * to get the coords of the actual quadrangle.</note>
9153  *
9154  * Since: 0.8
9155  */
9156 void
9157 clutter_actor_get_transformed_size (ClutterActor *self,
9158                                     gfloat       *width,
9159                                     gfloat       *height)
9160 {
9161   ClutterActorPrivate *priv;
9162   ClutterVertex v[4];
9163   gfloat x_min, x_max, y_min, y_max;
9164   gint i;
9165
9166   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9167
9168   priv = self->priv;
9169
9170   /* if the actor hasn't been allocated yet, get the preferred
9171    * size and transform that
9172    */
9173   if (priv->needs_allocation)
9174     {
9175       gfloat natural_width, natural_height;
9176       ClutterActorBox box;
9177
9178       /* Make a fake allocation to transform.
9179        *
9180        * NB: _clutter_actor_transform_and_project_box expects a box in
9181        * the actor's coordinate space... */
9182
9183       box.x1 = 0;
9184       box.y1 = 0;
9185
9186       natural_width = natural_height = 0;
9187       clutter_actor_get_preferred_size (self, NULL, NULL,
9188                                         &natural_width,
9189                                         &natural_height);
9190
9191       box.x2 = natural_width;
9192       box.y2 = natural_height;
9193
9194       _clutter_actor_transform_and_project_box (self, &box, v);
9195     }
9196   else
9197     clutter_actor_get_abs_allocation_vertices (self, v);
9198
9199   x_min = x_max = v[0].x;
9200   y_min = y_max = v[0].y;
9201
9202   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9203     {
9204       if (v[i].x < x_min)
9205         x_min = v[i].x;
9206
9207       if (v[i].x > x_max)
9208         x_max = v[i].x;
9209
9210       if (v[i].y < y_min)
9211         y_min = v[i].y;
9212
9213       if (v[i].y > y_max)
9214         y_max = v[i].y;
9215     }
9216
9217   if (width)
9218     *width  = x_max - x_min;
9219
9220   if (height)
9221     *height = y_max - y_min;
9222 }
9223
9224 /**
9225  * clutter_actor_get_width:
9226  * @self: A #ClutterActor
9227  *
9228  * Retrieves the width of a #ClutterActor.
9229  *
9230  * If the actor has a valid allocation, this function will return the
9231  * width of the allocated area given to the actor.
9232  *
9233  * If the actor does not have a valid allocation, this function will
9234  * return the actor's natural width, that is the preferred width of
9235  * the actor.
9236  *
9237  * If you care whether you get the preferred width or the width that
9238  * has been assigned to the actor, you should probably call a different
9239  * function like clutter_actor_get_allocation_box() to retrieve the
9240  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9241  * preferred width.
9242  *
9243  * If an actor has a fixed width, for instance a width that has been
9244  * assigned using clutter_actor_set_width(), the width returned will
9245  * be the same value.
9246  *
9247  * Return value: the width of the actor, in pixels
9248  */
9249 gfloat
9250 clutter_actor_get_width (ClutterActor *self)
9251 {
9252   ClutterActorPrivate *priv;
9253
9254   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9255
9256   priv = self->priv;
9257
9258   if (priv->needs_allocation)
9259     {
9260       gfloat natural_width = 0;
9261
9262       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9263         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9264       else
9265         {
9266           gfloat natural_height = 0;
9267
9268           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9269           clutter_actor_get_preferred_width (self, natural_height,
9270                                              NULL,
9271                                              &natural_width);
9272         }
9273
9274       return natural_width;
9275     }
9276   else
9277     return priv->allocation.x2 - priv->allocation.x1;
9278 }
9279
9280 /**
9281  * clutter_actor_get_height:
9282  * @self: A #ClutterActor
9283  *
9284  * Retrieves the height of a #ClutterActor.
9285  *
9286  * If the actor has a valid allocation, this function will return the
9287  * height of the allocated area given to the actor.
9288  *
9289  * If the actor does not have a valid allocation, this function will
9290  * return the actor's natural height, that is the preferred height of
9291  * the actor.
9292  *
9293  * If you care whether you get the preferred height or the height that
9294  * has been assigned to the actor, you should probably call a different
9295  * function like clutter_actor_get_allocation_box() to retrieve the
9296  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9297  * preferred height.
9298  *
9299  * If an actor has a fixed height, for instance a height that has been
9300  * assigned using clutter_actor_set_height(), the height returned will
9301  * be the same value.
9302  *
9303  * Return value: the height of the actor, in pixels
9304  */
9305 gfloat
9306 clutter_actor_get_height (ClutterActor *self)
9307 {
9308   ClutterActorPrivate *priv;
9309
9310   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9311
9312   priv = self->priv;
9313
9314   if (priv->needs_allocation)
9315     {
9316       gfloat natural_height = 0;
9317
9318       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9319         {
9320           gfloat natural_width = 0;
9321
9322           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9323           clutter_actor_get_preferred_height (self, natural_width,
9324                                               NULL, &natural_height);
9325         }
9326       else
9327         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9328
9329       return natural_height;
9330     }
9331   else
9332     return priv->allocation.y2 - priv->allocation.y1;
9333 }
9334
9335 /**
9336  * clutter_actor_set_width:
9337  * @self: A #ClutterActor
9338  * @width: Requested new width for the actor, in pixels, or -1
9339  *
9340  * Forces a width on an actor, causing the actor's preferred width
9341  * and height (if any) to be ignored.
9342  *
9343  * If @width is -1 the actor will use its preferred width request
9344  * instead of overriding it, i.e. you can "unset" the width with -1.
9345  *
9346  * This function sets both the minimum and natural size of the actor.
9347  *
9348  * since: 0.2
9349  */
9350 void
9351 clutter_actor_set_width (ClutterActor *self,
9352                          gfloat        width)
9353 {
9354   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9355
9356   if (clutter_actor_get_easing_duration (self) != 0)
9357     {
9358       ClutterTransition *transition;
9359
9360       transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9361       if (transition == NULL)
9362         {
9363           float old_width = clutter_actor_get_width (self);
9364
9365           transition = _clutter_actor_create_transition (self,
9366                                                          obj_props[PROP_WIDTH],
9367                                                          old_width,
9368                                                          width);
9369           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9370         }
9371       else
9372         _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9373
9374       clutter_actor_queue_relayout (self);
9375     }
9376   else
9377     {
9378       g_object_freeze_notify (G_OBJECT (self));
9379
9380       clutter_actor_set_width_internal (self, width);
9381
9382       g_object_thaw_notify (G_OBJECT (self));
9383     }
9384 }
9385
9386 /**
9387  * clutter_actor_set_height:
9388  * @self: A #ClutterActor
9389  * @height: Requested new height for the actor, in pixels, or -1
9390  *
9391  * Forces a height on an actor, causing the actor's preferred width
9392  * and height (if any) to be ignored.
9393  *
9394  * If @height is -1 the actor will use its preferred height instead of
9395  * overriding it, i.e. you can "unset" the height with -1.
9396  *
9397  * This function sets both the minimum and natural size of the actor.
9398  *
9399  * since: 0.2
9400  */
9401 void
9402 clutter_actor_set_height (ClutterActor *self,
9403                           gfloat        height)
9404 {
9405   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9406
9407   if (clutter_actor_get_easing_duration (self) != 0)
9408     {
9409       ClutterTransition *transition;
9410
9411       transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9412       if (transition ==  NULL)
9413         {
9414           float old_height = clutter_actor_get_height (self);
9415
9416           transition = _clutter_actor_create_transition (self,
9417                                                          obj_props[PROP_HEIGHT],
9418                                                          old_height,
9419                                                          height);
9420           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9421         }
9422       else
9423         _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9424
9425       clutter_actor_queue_relayout (self);
9426     }
9427   else
9428     {
9429       g_object_freeze_notify (G_OBJECT (self));
9430
9431       clutter_actor_set_height_internal (self, height);
9432
9433       g_object_thaw_notify (G_OBJECT (self));
9434     }
9435 }
9436
9437 static inline void
9438 clutter_actor_set_x_internal (ClutterActor *self,
9439                               float         x)
9440 {
9441   ClutterActorPrivate *priv = self->priv;
9442   ClutterLayoutInfo *linfo;
9443   ClutterActorBox old = { 0, };
9444
9445   linfo = _clutter_actor_get_layout_info (self);
9446
9447   if (priv->position_set && linfo->fixed_x == x)
9448     return;
9449
9450   clutter_actor_store_old_geometry (self, &old);
9451
9452   linfo->fixed_x = x;
9453   clutter_actor_set_fixed_position_set (self, TRUE);
9454
9455   clutter_actor_notify_if_geometry_changed (self, &old);
9456
9457   clutter_actor_queue_relayout (self);
9458 }
9459
9460 static inline void
9461 clutter_actor_set_y_internal (ClutterActor *self,
9462                               float         y)
9463 {
9464   ClutterActorPrivate *priv = self->priv;
9465   ClutterLayoutInfo *linfo;
9466   ClutterActorBox old = { 0, };
9467
9468   linfo = _clutter_actor_get_layout_info (self);
9469
9470   if (priv->position_set && linfo->fixed_y == y)
9471     return;
9472
9473   clutter_actor_store_old_geometry (self, &old);
9474
9475   linfo->fixed_y = y;
9476   clutter_actor_set_fixed_position_set (self, TRUE);
9477
9478   clutter_actor_notify_if_geometry_changed (self, &old);
9479
9480   clutter_actor_queue_relayout (self);
9481 }
9482
9483 /**
9484  * clutter_actor_set_x:
9485  * @self: a #ClutterActor
9486  * @x: the actor's position on the X axis
9487  *
9488  * Sets the actor's X coordinate, relative to its parent, in pixels.
9489  *
9490  * Overrides any layout manager and forces a fixed position for
9491  * the actor.
9492  *
9493  * The #ClutterActor:x property is animatable.
9494  *
9495  * Since: 0.6
9496  */
9497 void
9498 clutter_actor_set_x (ClutterActor *self,
9499                      gfloat        x)
9500 {
9501   const ClutterLayoutInfo *linfo;
9502
9503   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9504
9505   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9506
9507   if (clutter_actor_get_easing_duration (self) != 0)
9508     {
9509       ClutterTransition *transition;
9510
9511       transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9512       if (transition == NULL)
9513         {
9514           transition = _clutter_actor_create_transition (self,
9515                                                          obj_props[PROP_X],
9516                                                          linfo->fixed_x,
9517                                                          x);
9518
9519           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9520         }
9521       else
9522         _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9523
9524       clutter_actor_queue_relayout (self);
9525     }
9526   else
9527     clutter_actor_set_x_internal (self, x);
9528 }
9529
9530 /**
9531  * clutter_actor_set_y:
9532  * @self: a #ClutterActor
9533  * @y: the actor's position on the Y axis
9534  *
9535  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9536  *
9537  * Overrides any layout manager and forces a fixed position for
9538  * the actor.
9539  *
9540  * The #ClutterActor:y property is animatable.
9541  *
9542  * Since: 0.6
9543  */
9544 void
9545 clutter_actor_set_y (ClutterActor *self,
9546                      gfloat        y)
9547 {
9548   const ClutterLayoutInfo *linfo;
9549
9550   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9551
9552   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9553
9554   if (clutter_actor_get_easing_duration (self) != 0)
9555     {
9556       ClutterTransition *transition;
9557
9558       transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9559       if (transition == NULL)
9560         {
9561           transition = _clutter_actor_create_transition (self,
9562                                                          obj_props[PROP_Y],
9563                                                          linfo->fixed_y,
9564                                                          y);
9565
9566           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9567         }
9568       else
9569         _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9570
9571       clutter_actor_queue_relayout (self);
9572     }
9573   else
9574     clutter_actor_set_y_internal (self, y);
9575
9576   clutter_actor_queue_relayout (self);
9577 }
9578
9579 /**
9580  * clutter_actor_get_x:
9581  * @self: A #ClutterActor
9582  *
9583  * Retrieves the X coordinate of a #ClutterActor.
9584  *
9585  * This function tries to "do what you mean", by returning the
9586  * correct value depending on the actor's state.
9587  *
9588  * If the actor has a valid allocation, this function will return
9589  * the X coordinate of the origin of the allocation box.
9590  *
9591  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9592  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9593  * function will return that coordinate.
9594  *
9595  * If both the allocation and a fixed position are missing, this function
9596  * will return 0.
9597  *
9598  * Return value: the X coordinate, in pixels, ignoring any
9599  *   transformation (i.e. scaling, rotation)
9600  */
9601 gfloat
9602 clutter_actor_get_x (ClutterActor *self)
9603 {
9604   ClutterActorPrivate *priv;
9605
9606   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9607
9608   priv = self->priv;
9609
9610   if (priv->needs_allocation)
9611     {
9612       if (priv->position_set)
9613         {
9614           const ClutterLayoutInfo *info;
9615
9616           info = _clutter_actor_get_layout_info_or_defaults (self);
9617
9618           return info->fixed_x;
9619         }
9620       else
9621         return 0;
9622     }
9623   else
9624     return priv->allocation.x1;
9625 }
9626
9627 /**
9628  * clutter_actor_get_y:
9629  * @self: A #ClutterActor
9630  *
9631  * Retrieves the Y coordinate of a #ClutterActor.
9632  *
9633  * This function tries to "do what you mean", by returning the
9634  * correct value depending on the actor's state.
9635  *
9636  * If the actor has a valid allocation, this function will return
9637  * the Y coordinate of the origin of the allocation box.
9638  *
9639  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9640  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9641  * function will return that coordinate.
9642  *
9643  * If both the allocation and a fixed position are missing, this function
9644  * will return 0.
9645  *
9646  * Return value: the Y coordinate, in pixels, ignoring any
9647  *   transformation (i.e. scaling, rotation)
9648  */
9649 gfloat
9650 clutter_actor_get_y (ClutterActor *self)
9651 {
9652   ClutterActorPrivate *priv;
9653
9654   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9655
9656   priv = self->priv;
9657
9658   if (priv->needs_allocation)
9659     {
9660       if (priv->position_set)
9661         {
9662           const ClutterLayoutInfo *info;
9663
9664           info = _clutter_actor_get_layout_info_or_defaults (self);
9665
9666           return info->fixed_y;
9667         }
9668       else
9669         return 0;
9670     }
9671   else
9672     return priv->allocation.y1;
9673 }
9674
9675 /**
9676  * clutter_actor_set_scale:
9677  * @self: A #ClutterActor
9678  * @scale_x: double factor to scale actor by horizontally.
9679  * @scale_y: double factor to scale actor by vertically.
9680  *
9681  * Scales an actor with the given factors. The scaling is relative to
9682  * the scale center and the anchor point. The scale center is
9683  * unchanged by this function and defaults to 0,0.
9684  *
9685  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9686  * animatable.
9687  *
9688  * Since: 0.2
9689  */
9690 void
9691 clutter_actor_set_scale (ClutterActor *self,
9692                          gdouble       scale_x,
9693                          gdouble       scale_y)
9694 {
9695   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9696
9697   g_object_freeze_notify (G_OBJECT (self));
9698
9699   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9700   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9701
9702   g_object_thaw_notify (G_OBJECT (self));
9703 }
9704
9705 /**
9706  * clutter_actor_set_scale_full:
9707  * @self: A #ClutterActor
9708  * @scale_x: double factor to scale actor by horizontally.
9709  * @scale_y: double factor to scale actor by vertically.
9710  * @center_x: X coordinate of the center of the scale.
9711  * @center_y: Y coordinate of the center of the scale
9712  *
9713  * Scales an actor with the given factors around the given center
9714  * point. The center point is specified in pixels relative to the
9715  * anchor point (usually the top left corner of the actor).
9716  *
9717  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9718  * are animatable.
9719  *
9720  * Since: 1.0
9721  */
9722 void
9723 clutter_actor_set_scale_full (ClutterActor *self,
9724                               gdouble       scale_x,
9725                               gdouble       scale_y,
9726                               gfloat        center_x,
9727                               gfloat        center_y)
9728 {
9729   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9730
9731   g_object_freeze_notify (G_OBJECT (self));
9732
9733   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9734   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9735   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9736   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9737
9738   g_object_thaw_notify (G_OBJECT (self));
9739 }
9740
9741 /**
9742  * clutter_actor_set_scale_with_gravity:
9743  * @self: A #ClutterActor
9744  * @scale_x: double factor to scale actor by horizontally.
9745  * @scale_y: double factor to scale actor by vertically.
9746  * @gravity: the location of the scale center expressed as a compass
9747  * direction.
9748  *
9749  * Scales an actor with the given factors around the given
9750  * center point. The center point is specified as one of the compass
9751  * directions in #ClutterGravity. For example, setting it to north
9752  * will cause the top of the actor to remain unchanged and the rest of
9753  * the actor to expand left, right and downwards.
9754  *
9755  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9756  * animatable.
9757  *
9758  * Since: 1.0
9759  */
9760 void
9761 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9762                                       gdouble         scale_x,
9763                                       gdouble         scale_y,
9764                                       ClutterGravity  gravity)
9765 {
9766   ClutterTransformInfo *info;
9767   GObject *obj;
9768
9769   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9770
9771   obj = G_OBJECT (self);
9772
9773   g_object_freeze_notify (obj);
9774
9775   info = _clutter_actor_get_transform_info (self);
9776   info->scale_x = scale_x;
9777   info->scale_y = scale_y;
9778
9779   if (gravity == CLUTTER_GRAVITY_NONE)
9780     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9781   else
9782     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9783
9784   self->priv->transform_valid = FALSE;
9785
9786   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9787   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9788   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9789   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9790   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9791
9792   clutter_actor_queue_redraw (self);
9793
9794   g_object_thaw_notify (obj);
9795 }
9796
9797 /**
9798  * clutter_actor_get_scale:
9799  * @self: A #ClutterActor
9800  * @scale_x: (out) (allow-none): Location to store horizonal
9801  *   scale factor, or %NULL.
9802  * @scale_y: (out) (allow-none): Location to store vertical
9803  *   scale factor, or %NULL.
9804  *
9805  * Retrieves an actors scale factors.
9806  *
9807  * Since: 0.2
9808  */
9809 void
9810 clutter_actor_get_scale (ClutterActor *self,
9811                          gdouble      *scale_x,
9812                          gdouble      *scale_y)
9813 {
9814   const ClutterTransformInfo *info;
9815
9816   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9817
9818   info = _clutter_actor_get_transform_info_or_defaults (self);
9819
9820   if (scale_x)
9821     *scale_x = info->scale_x;
9822
9823   if (scale_y)
9824     *scale_y = info->scale_y;
9825 }
9826
9827 /**
9828  * clutter_actor_get_scale_center:
9829  * @self: A #ClutterActor
9830  * @center_x: (out) (allow-none): Location to store the X position
9831  *   of the scale center, or %NULL.
9832  * @center_y: (out) (allow-none): Location to store the Y position
9833  *   of the scale center, or %NULL.
9834  *
9835  * Retrieves the scale center coordinate in pixels relative to the top
9836  * left corner of the actor. If the scale center was specified using a
9837  * #ClutterGravity this will calculate the pixel offset using the
9838  * current size of the actor.
9839  *
9840  * Since: 1.0
9841  */
9842 void
9843 clutter_actor_get_scale_center (ClutterActor *self,
9844                                 gfloat       *center_x,
9845                                 gfloat       *center_y)
9846 {
9847   const ClutterTransformInfo *info;
9848
9849   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9850
9851   info = _clutter_actor_get_transform_info_or_defaults (self);
9852
9853   clutter_anchor_coord_get_units (self, &info->scale_center,
9854                                   center_x,
9855                                   center_y,
9856                                   NULL);
9857 }
9858
9859 /**
9860  * clutter_actor_get_scale_gravity:
9861  * @self: A #ClutterActor
9862  *
9863  * Retrieves the scale center as a compass direction. If the scale
9864  * center was specified in pixels or units this will return
9865  * %CLUTTER_GRAVITY_NONE.
9866  *
9867  * Return value: the scale gravity
9868  *
9869  * Since: 1.0
9870  */
9871 ClutterGravity
9872 clutter_actor_get_scale_gravity (ClutterActor *self)
9873 {
9874   const ClutterTransformInfo *info;
9875
9876   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9877
9878   info = _clutter_actor_get_transform_info_or_defaults (self);
9879
9880   return clutter_anchor_coord_get_gravity (&info->scale_center);
9881 }
9882
9883 static inline void
9884 clutter_actor_set_opacity_internal (ClutterActor *self,
9885                                     guint8        opacity)
9886 {
9887   ClutterActorPrivate *priv = self->priv;
9888
9889   if (priv->opacity != opacity)
9890     {
9891       priv->opacity = opacity;
9892
9893       /* Queue a redraw from the flatten effect so that it can use
9894          its cached image if available instead of having to redraw the
9895          actual actor. If it doesn't end up using the FBO then the
9896          effect is still able to continue the paint anyway. If there
9897          is no flatten effect yet then this is equivalent to queueing
9898          a full redraw */
9899       _clutter_actor_queue_redraw_full (self,
9900                                         0, /* flags */
9901                                         NULL, /* clip */
9902                                         priv->flatten_effect);
9903
9904       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9905     }
9906 }
9907
9908 /**
9909  * clutter_actor_set_opacity:
9910  * @self: A #ClutterActor
9911  * @opacity: New opacity value for the actor.
9912  *
9913  * Sets the actor's opacity, with zero being completely transparent and
9914  * 255 (0xff) being fully opaque.
9915  *
9916  * The #ClutterActor:opacity property is animatable.
9917  */
9918 void
9919 clutter_actor_set_opacity (ClutterActor *self,
9920                            guint8        opacity)
9921 {
9922   ClutterActorPrivate *priv;
9923
9924   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9925
9926   priv = self->priv;
9927
9928   if (clutter_actor_get_easing_duration (self) != 0)
9929     {
9930       ClutterTransition *transition;
9931
9932       transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9933       if (transition == NULL)
9934         {
9935           transition = _clutter_actor_create_transition (self,
9936                                                          obj_props[PROP_OPACITY],
9937                                                          priv->opacity,
9938                                                          opacity);
9939           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9940         }
9941       else
9942         _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9943
9944       clutter_actor_queue_redraw (self);
9945     }
9946   else
9947     clutter_actor_set_opacity_internal (self, opacity);
9948 }
9949
9950 /*
9951  * clutter_actor_get_paint_opacity_internal:
9952  * @self: a #ClutterActor
9953  *
9954  * Retrieves the absolute opacity of the actor, as it appears on the stage
9955  *
9956  * This function does not do type checks
9957  *
9958  * Return value: the absolute opacity of the actor
9959  */
9960 static guint8
9961 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9962 {
9963   ClutterActorPrivate *priv = self->priv;
9964   ClutterActor *parent;
9965
9966   /* override the top-level opacity to always be 255; even in
9967    * case of ClutterStage:use-alpha being TRUE we want the rest
9968    * of the scene to be painted
9969    */
9970   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9971     return 255;
9972
9973   if (priv->opacity_override >= 0)
9974     return priv->opacity_override;
9975
9976   parent = priv->parent;
9977
9978   /* Factor in the actual actors opacity with parents */
9979   if (parent != NULL)
9980     {
9981       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9982
9983       if (opacity != 0xff)
9984         return (opacity * priv->opacity) / 0xff;
9985     }
9986
9987   return priv->opacity;
9988
9989 }
9990
9991 /**
9992  * clutter_actor_get_paint_opacity:
9993  * @self: A #ClutterActor
9994  *
9995  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9996  *
9997  * This function traverses the hierarchy chain and composites the opacity of
9998  * the actor with that of its parents.
9999  *
10000  * This function is intended for subclasses to use in the paint virtual
10001  * function, to paint themselves with the correct opacity.
10002  *
10003  * Return value: The actor opacity value.
10004  *
10005  * Since: 0.8
10006  */
10007 guint8
10008 clutter_actor_get_paint_opacity (ClutterActor *self)
10009 {
10010   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10011
10012   return clutter_actor_get_paint_opacity_internal (self);
10013 }
10014
10015 /**
10016  * clutter_actor_get_opacity:
10017  * @self: a #ClutterActor
10018  *
10019  * Retrieves the opacity value of an actor, as set by
10020  * clutter_actor_set_opacity().
10021  *
10022  * For retrieving the absolute opacity of the actor inside a paint
10023  * virtual function, see clutter_actor_get_paint_opacity().
10024  *
10025  * Return value: the opacity of the actor
10026  */
10027 guint8
10028 clutter_actor_get_opacity (ClutterActor *self)
10029 {
10030   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10031
10032   return self->priv->opacity;
10033 }
10034
10035 /**
10036  * clutter_actor_set_offscreen_redirect:
10037  * @self: A #ClutterActor
10038  * @redirect: New offscreen redirect flags for the actor.
10039  *
10040  * Defines the circumstances where the actor should be redirected into
10041  * an offscreen image. The offscreen image is used to flatten the
10042  * actor into a single image while painting for two main reasons.
10043  * Firstly, when the actor is painted a second time without any of its
10044  * contents changing it can simply repaint the cached image without
10045  * descending further down the actor hierarchy. Secondly, it will make
10046  * the opacity look correct even if there are overlapping primitives
10047  * in the actor.
10048  *
10049  * Caching the actor could in some cases be a performance win and in
10050  * some cases be a performance lose so it is important to determine
10051  * which value is right for an actor before modifying this value. For
10052  * example, there is never any reason to flatten an actor that is just
10053  * a single texture (such as a #ClutterTexture) because it is
10054  * effectively already cached in an image so the offscreen would be
10055  * redundant. Also if the actor contains primitives that are far apart
10056  * with a large transparent area in the middle (such as a large
10057  * CluterGroup with a small actor in the top left and a small actor in
10058  * the bottom right) then the cached image will contain the entire
10059  * image of the large area and the paint will waste time blending all
10060  * of the transparent pixels in the middle.
10061  *
10062  * The default method of implementing opacity on a container simply
10063  * forwards on the opacity to all of the children. If the children are
10064  * overlapping then it will appear as if they are two separate glassy
10065  * objects and there will be a break in the color where they
10066  * overlap. By redirecting to an offscreen buffer it will be as if the
10067  * two opaque objects are combined into one and then made transparent
10068  * which is usually what is expected.
10069  *
10070  * The image below demonstrates the difference between redirecting and
10071  * not. The image shows two Clutter groups, each containing a red and
10072  * a green rectangle which overlap. The opacity on the group is set to
10073  * 128 (which is 50%). When the offscreen redirect is not used, the
10074  * red rectangle can be seen through the blue rectangle as if the two
10075  * rectangles were separately transparent. When the redirect is used
10076  * the group as a whole is transparent instead so the red rectangle is
10077  * not visible where they overlap.
10078  *
10079  * <figure id="offscreen-redirect">
10080  *   <title>Sample of using an offscreen redirect for transparency</title>
10081  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10082  * </figure>
10083  *
10084  * The default value for this property is 0, so we effectively will
10085  * never redirect an actor offscreen by default. This means that there
10086  * are times that transparent actors may look glassy as described
10087  * above. The reason this is the default is because there is a
10088  * performance trade off between quality and performance here. In many
10089  * cases the default form of glassy opacity looks good enough, but if
10090  * it's not you will need to set the
10091  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10092  * redirection for opacity.
10093  *
10094  * Custom actors that don't contain any overlapping primitives are
10095  * recommended to override the has_overlaps() virtual to return %FALSE
10096  * for maximum efficiency.
10097  *
10098  * Since: 1.8
10099  */
10100 void
10101 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10102                                       ClutterOffscreenRedirect redirect)
10103 {
10104   ClutterActorPrivate *priv;
10105
10106   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10107
10108   priv = self->priv;
10109
10110   if (priv->offscreen_redirect != redirect)
10111     {
10112       priv->offscreen_redirect = redirect;
10113
10114       /* Queue a redraw from the effect so that it can use its cached
10115          image if available instead of having to redraw the actual
10116          actor. If it doesn't end up using the FBO then the effect is
10117          still able to continue the paint anyway. If there is no
10118          effect then this is equivalent to queuing a full redraw */
10119       _clutter_actor_queue_redraw_full (self,
10120                                         0, /* flags */
10121                                         NULL, /* clip */
10122                                         priv->flatten_effect);
10123
10124       g_object_notify_by_pspec (G_OBJECT (self),
10125                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10126     }
10127 }
10128
10129 /**
10130  * clutter_actor_get_offscreen_redirect:
10131  * @self: a #ClutterActor
10132  *
10133  * Retrieves whether to redirect the actor to an offscreen buffer, as
10134  * set by clutter_actor_set_offscreen_redirect().
10135  *
10136  * Return value: the value of the offscreen-redirect property of the actor
10137  *
10138  * Since: 1.8
10139  */
10140 ClutterOffscreenRedirect
10141 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10142 {
10143   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10144
10145   return self->priv->offscreen_redirect;
10146 }
10147
10148 /**
10149  * clutter_actor_set_name:
10150  * @self: A #ClutterActor
10151  * @name: Textual tag to apply to actor
10152  *
10153  * Sets the given name to @self. The name can be used to identify
10154  * a #ClutterActor.
10155  */
10156 void
10157 clutter_actor_set_name (ClutterActor *self,
10158                         const gchar  *name)
10159 {
10160   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10161
10162   g_free (self->priv->name);
10163   self->priv->name = g_strdup (name);
10164
10165   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10166 }
10167
10168 /**
10169  * clutter_actor_get_name:
10170  * @self: A #ClutterActor
10171  *
10172  * Retrieves the name of @self.
10173  *
10174  * Return value: the name of the actor, or %NULL. The returned string is
10175  *   owned by the actor and should not be modified or freed.
10176  */
10177 const gchar *
10178 clutter_actor_get_name (ClutterActor *self)
10179 {
10180   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10181
10182   return self->priv->name;
10183 }
10184
10185 /**
10186  * clutter_actor_get_gid:
10187  * @self: A #ClutterActor
10188  *
10189  * Retrieves the unique id for @self.
10190  *
10191  * Return value: Globally unique value for this object instance.
10192  *
10193  * Since: 0.6
10194  *
10195  * Deprecated: 1.8: The id is not used any longer.
10196  */
10197 guint32
10198 clutter_actor_get_gid (ClutterActor *self)
10199 {
10200   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10201
10202   return self->priv->id;
10203 }
10204
10205 static inline void
10206 clutter_actor_set_depth_internal (ClutterActor *self,
10207                                   float         depth)
10208 {
10209   ClutterTransformInfo *info;
10210
10211   info = _clutter_actor_get_transform_info (self);
10212
10213   if (info->depth != depth)
10214     {
10215       /* Sets Z value - XXX 2.0: should we invert? */
10216       info->depth = depth;
10217
10218       self->priv->transform_valid = FALSE;
10219
10220       /* FIXME - remove this crap; sadly, there are still containers
10221        * in Clutter that depend on this utter brain damage
10222        */
10223       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10224
10225       clutter_actor_queue_redraw (self);
10226
10227       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10228     }
10229 }
10230
10231 /**
10232  * clutter_actor_set_depth:
10233  * @self: a #ClutterActor
10234  * @depth: Z co-ord
10235  *
10236  * Sets the Z coordinate of @self to @depth.
10237  *
10238  * The unit used by @depth is dependant on the perspective setup. See
10239  * also clutter_stage_set_perspective().
10240  */
10241 void
10242 clutter_actor_set_depth (ClutterActor *self,
10243                          gfloat        depth)
10244 {
10245   const ClutterTransformInfo *tinfo;
10246
10247   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10248
10249   tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10250
10251   if (clutter_actor_get_easing_duration (self) != 0)
10252     {
10253       ClutterTransition *transition;
10254
10255       transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10256       if (transition == NULL)
10257         {
10258           transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10259                                                          tinfo->depth,
10260                                                          depth);
10261           clutter_timeline_start (CLUTTER_TIMELINE (transition));
10262         }
10263       else
10264         _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10265
10266       clutter_actor_queue_redraw (self);
10267     }
10268   else
10269     clutter_actor_set_depth_internal (self, depth);
10270 }
10271
10272 /**
10273  * clutter_actor_get_depth:
10274  * @self: a #ClutterActor
10275  *
10276  * Retrieves the depth of @self.
10277  *
10278  * Return value: the depth of the actor
10279  */
10280 gfloat
10281 clutter_actor_get_depth (ClutterActor *self)
10282 {
10283   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10284
10285   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10286 }
10287
10288 /**
10289  * clutter_actor_set_rotation:
10290  * @self: a #ClutterActor
10291  * @axis: the axis of rotation
10292  * @angle: the angle of rotation
10293  * @x: X coordinate of the rotation center
10294  * @y: Y coordinate of the rotation center
10295  * @z: Z coordinate of the rotation center
10296  *
10297  * Sets the rotation angle of @self around the given axis.
10298  *
10299  * The rotation center coordinates used depend on the value of @axis:
10300  * <itemizedlist>
10301  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10302  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10303  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10304  * </itemizedlist>
10305  *
10306  * The rotation coordinates are relative to the anchor point of the
10307  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10308  * point is set, the upper left corner is assumed as the origin.
10309  *
10310  * Since: 0.8
10311  */
10312 void
10313 clutter_actor_set_rotation (ClutterActor      *self,
10314                             ClutterRotateAxis  axis,
10315                             gdouble            angle,
10316                             gfloat             x,
10317                             gfloat             y,
10318                             gfloat             z)
10319 {
10320   ClutterVertex v;
10321
10322   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10323
10324   v.x = x;
10325   v.y = y;
10326   v.z = z;
10327
10328   g_object_freeze_notify (G_OBJECT (self));
10329
10330   clutter_actor_set_rotation_angle (self, axis, angle);
10331   clutter_actor_set_rotation_center_internal (self, axis, &v);
10332
10333   g_object_thaw_notify (G_OBJECT (self));
10334 }
10335
10336 /**
10337  * clutter_actor_set_z_rotation_from_gravity:
10338  * @self: a #ClutterActor
10339  * @angle: the angle of rotation
10340  * @gravity: the center point of the rotation
10341  *
10342  * Sets the rotation angle of @self around the Z axis using the center
10343  * point specified as a compass point. For example to rotate such that
10344  * the center of the actor remains static you can use
10345  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10346  * will move accordingly.
10347  *
10348  * Since: 1.0
10349  */
10350 void
10351 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10352                                            gdouble         angle,
10353                                            ClutterGravity  gravity)
10354 {
10355   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10356
10357   if (gravity == CLUTTER_GRAVITY_NONE)
10358     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10359   else
10360     {
10361       GObject *obj = G_OBJECT (self);
10362       ClutterTransformInfo *info;
10363
10364       info = _clutter_actor_get_transform_info (self);
10365
10366       g_object_freeze_notify (obj);
10367
10368       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10369
10370       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10371       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10372       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10373
10374       g_object_thaw_notify (obj);
10375     }
10376 }
10377
10378 /**
10379  * clutter_actor_get_rotation:
10380  * @self: a #ClutterActor
10381  * @axis: the axis of rotation
10382  * @x: (out): return value for the X coordinate of the center of rotation
10383  * @y: (out): return value for the Y coordinate of the center of rotation
10384  * @z: (out): return value for the Z coordinate of the center of rotation
10385  *
10386  * Retrieves the angle and center of rotation on the given axis,
10387  * set using clutter_actor_set_rotation().
10388  *
10389  * Return value: the angle of rotation
10390  *
10391  * Since: 0.8
10392  */
10393 gdouble
10394 clutter_actor_get_rotation (ClutterActor      *self,
10395                             ClutterRotateAxis  axis,
10396                             gfloat            *x,
10397                             gfloat            *y,
10398                             gfloat            *z)
10399 {
10400   const ClutterTransformInfo *info;
10401   const AnchorCoord *anchor_coord;
10402   gdouble retval = 0;
10403
10404   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10405
10406   info = _clutter_actor_get_transform_info_or_defaults (self);
10407
10408   switch (axis)
10409     {
10410     case CLUTTER_X_AXIS:
10411       anchor_coord = &info->rx_center;
10412       retval = info->rx_angle;
10413       break;
10414
10415     case CLUTTER_Y_AXIS:
10416       anchor_coord = &info->ry_center;
10417       retval = info->ry_angle;
10418       break;
10419
10420     case CLUTTER_Z_AXIS:
10421       anchor_coord = &info->rz_center;
10422       retval = info->rz_angle;
10423       break;
10424
10425     default:
10426       anchor_coord = NULL;
10427       retval = 0.0;
10428       break;
10429     }
10430
10431   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10432
10433   return retval;
10434 }
10435
10436 /**
10437  * clutter_actor_get_z_rotation_gravity:
10438  * @self: A #ClutterActor
10439  *
10440  * Retrieves the center for the rotation around the Z axis as a
10441  * compass direction. If the center was specified in pixels or units
10442  * this will return %CLUTTER_GRAVITY_NONE.
10443  *
10444  * Return value: the Z rotation center
10445  *
10446  * Since: 1.0
10447  */
10448 ClutterGravity
10449 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10450 {
10451   const ClutterTransformInfo *info;
10452
10453   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10454
10455   info = _clutter_actor_get_transform_info_or_defaults (self);
10456
10457   return clutter_anchor_coord_get_gravity (&info->rz_center);
10458 }
10459
10460 /**
10461  * clutter_actor_set_clip:
10462  * @self: A #ClutterActor
10463  * @xoff: X offset of the clip rectangle
10464  * @yoff: Y offset of the clip rectangle
10465  * @width: Width of the clip rectangle
10466  * @height: Height of the clip rectangle
10467  *
10468  * Sets clip area for @self. The clip area is always computed from the
10469  * upper left corner of the actor, even if the anchor point is set
10470  * otherwise.
10471  *
10472  * Since: 0.6
10473  */
10474 void
10475 clutter_actor_set_clip (ClutterActor *self,
10476                         gfloat        xoff,
10477                         gfloat        yoff,
10478                         gfloat        width,
10479                         gfloat        height)
10480 {
10481   ClutterActorPrivate *priv;
10482
10483   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10484
10485   priv = self->priv;
10486
10487   if (priv->has_clip &&
10488       priv->clip.x == xoff &&
10489       priv->clip.y == yoff &&
10490       priv->clip.width == width &&
10491       priv->clip.height == height)
10492     return;
10493
10494   priv->clip.x = xoff;
10495   priv->clip.y = yoff;
10496   priv->clip.width = width;
10497   priv->clip.height = height;
10498
10499   priv->has_clip = TRUE;
10500
10501   clutter_actor_queue_redraw (self);
10502
10503   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10504   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10505 }
10506
10507 /**
10508  * clutter_actor_remove_clip:
10509  * @self: A #ClutterActor
10510  *
10511  * Removes clip area from @self.
10512  */
10513 void
10514 clutter_actor_remove_clip (ClutterActor *self)
10515 {
10516   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10517
10518   if (!self->priv->has_clip)
10519     return;
10520
10521   self->priv->has_clip = FALSE;
10522
10523   clutter_actor_queue_redraw (self);
10524
10525   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10526 }
10527
10528 /**
10529  * clutter_actor_has_clip:
10530  * @self: a #ClutterActor
10531  *
10532  * Determines whether the actor has a clip area set or not.
10533  *
10534  * Return value: %TRUE if the actor has a clip area set.
10535  *
10536  * Since: 0.1.1
10537  */
10538 gboolean
10539 clutter_actor_has_clip (ClutterActor *self)
10540 {
10541   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10542
10543   return self->priv->has_clip;
10544 }
10545
10546 /**
10547  * clutter_actor_get_clip:
10548  * @self: a #ClutterActor
10549  * @xoff: (out) (allow-none): return location for the X offset of
10550  *   the clip rectangle, or %NULL
10551  * @yoff: (out) (allow-none): return location for the Y offset of
10552  *   the clip rectangle, or %NULL
10553  * @width: (out) (allow-none): return location for the width of
10554  *   the clip rectangle, or %NULL
10555  * @height: (out) (allow-none): return location for the height of
10556  *   the clip rectangle, or %NULL
10557  *
10558  * Gets the clip area for @self, if any is set
10559  *
10560  * Since: 0.6
10561  */
10562 void
10563 clutter_actor_get_clip (ClutterActor *self,
10564                         gfloat       *xoff,
10565                         gfloat       *yoff,
10566                         gfloat       *width,
10567                         gfloat       *height)
10568 {
10569   ClutterActorPrivate *priv;
10570
10571   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10572
10573   priv = self->priv;
10574
10575   if (!priv->has_clip)
10576     return;
10577
10578   if (xoff != NULL)
10579     *xoff = priv->clip.x;
10580
10581   if (yoff != NULL)
10582     *yoff = priv->clip.y;
10583
10584   if (width != NULL)
10585     *width = priv->clip.width;
10586
10587   if (height != NULL)
10588     *height = priv->clip.height;
10589 }
10590
10591 /**
10592  * clutter_actor_get_children:
10593  * @self: a #ClutterActor
10594  *
10595  * Retrieves the list of children of @self.
10596  *
10597  * Return value: (transfer container) (element-type ClutterActor): A newly
10598  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10599  *   done.
10600  *
10601  * Since: 1.10
10602  */
10603 GList *
10604 clutter_actor_get_children (ClutterActor *self)
10605 {
10606   ClutterActor *iter;
10607   GList *res;
10608
10609   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10610
10611   /* we walk the list backward so that we can use prepend(),
10612    * which is O(1)
10613    */
10614   for (iter = self->priv->last_child, res = NULL;
10615        iter != NULL;
10616        iter = iter->priv->prev_sibling)
10617     {
10618       res = g_list_prepend (res, iter);
10619     }
10620
10621   return res;
10622 }
10623
10624 /*< private >
10625  * insert_child_at_depth:
10626  * @self: a #ClutterActor
10627  * @child: a #ClutterActor
10628  *
10629  * Inserts @child inside the list of children held by @self, using
10630  * the depth as the insertion criteria.
10631  *
10632  * This sadly makes the insertion not O(1), but we can keep the
10633  * list sorted so that the painters algorithm we use for painting
10634  * the children will work correctly.
10635  */
10636 static void
10637 insert_child_at_depth (ClutterActor *self,
10638                        ClutterActor *child,
10639                        gpointer      dummy G_GNUC_UNUSED)
10640 {
10641   ClutterActor *iter;
10642   float child_depth;
10643
10644   child->priv->parent = self;
10645
10646   child_depth =
10647     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10648
10649   /* special-case the first child */
10650   if (self->priv->n_children == 0)
10651     {
10652       self->priv->first_child = child;
10653       self->priv->last_child = child;
10654
10655       child->priv->next_sibling = NULL;
10656       child->priv->prev_sibling = NULL;
10657
10658       return;
10659     }
10660
10661   /* Find the right place to insert the child so that it will still be
10662      sorted and the child will be after all of the actors at the same
10663      dept */
10664   for (iter = self->priv->first_child;
10665        iter != NULL;
10666        iter = iter->priv->next_sibling)
10667     {
10668       float iter_depth;
10669
10670       iter_depth =
10671         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10672
10673       if (iter_depth > child_depth)
10674         break;
10675     }
10676
10677   if (iter != NULL)
10678     {
10679       ClutterActor *tmp = iter->priv->prev_sibling;
10680
10681       if (tmp != NULL)
10682         tmp->priv->next_sibling = child;
10683
10684       /* Insert the node before the found one */
10685       child->priv->prev_sibling = iter->priv->prev_sibling;
10686       child->priv->next_sibling = iter;
10687       iter->priv->prev_sibling = child;
10688     }
10689   else
10690     {
10691       ClutterActor *tmp = self->priv->last_child;
10692
10693       if (tmp != NULL)
10694         tmp->priv->next_sibling = child;
10695
10696       /* insert the node at the end of the list */
10697       child->priv->prev_sibling = self->priv->last_child;
10698       child->priv->next_sibling = NULL;
10699     }
10700
10701   if (child->priv->prev_sibling == NULL)
10702     self->priv->first_child = child;
10703
10704   if (child->priv->next_sibling == NULL)
10705     self->priv->last_child = child;
10706 }
10707
10708 static void
10709 insert_child_at_index (ClutterActor *self,
10710                        ClutterActor *child,
10711                        gpointer      data_)
10712 {
10713   gint index_ = GPOINTER_TO_INT (data_);
10714
10715   child->priv->parent = self;
10716
10717   if (index_ == 0)
10718     {
10719       ClutterActor *tmp = self->priv->first_child;
10720
10721       if (tmp != NULL)
10722         tmp->priv->prev_sibling = child;
10723
10724       child->priv->prev_sibling = NULL;
10725       child->priv->next_sibling = tmp;
10726     }
10727   else if (index_ < 0 || index_ >= self->priv->n_children)
10728     {
10729       ClutterActor *tmp = self->priv->last_child;
10730
10731       if (tmp != NULL)
10732         tmp->priv->next_sibling = child;
10733
10734       child->priv->prev_sibling = tmp;
10735       child->priv->next_sibling = NULL;
10736     }
10737   else
10738     {
10739       ClutterActor *iter;
10740       int i;
10741
10742       for (iter = self->priv->first_child, i = 0;
10743            iter != NULL;
10744            iter = iter->priv->next_sibling, i += 1)
10745         {
10746           if (index_ == i)
10747             {
10748               ClutterActor *tmp = iter->priv->prev_sibling;
10749
10750               child->priv->prev_sibling = tmp;
10751               child->priv->next_sibling = iter;
10752
10753               iter->priv->prev_sibling = child;
10754
10755               if (tmp != NULL)
10756                 tmp->priv->next_sibling = child;
10757
10758               break;
10759             }
10760         }
10761     }
10762
10763   if (child->priv->prev_sibling == NULL)
10764     self->priv->first_child = child;
10765
10766   if (child->priv->next_sibling == NULL)
10767     self->priv->last_child = child;
10768 }
10769
10770 static void
10771 insert_child_above (ClutterActor *self,
10772                     ClutterActor *child,
10773                     gpointer      data)
10774 {
10775   ClutterActor *sibling = data;
10776
10777   child->priv->parent = self;
10778
10779   if (sibling == NULL)
10780     sibling = self->priv->last_child;
10781
10782   child->priv->prev_sibling = sibling;
10783
10784   if (sibling != NULL)
10785     {
10786       ClutterActor *tmp = sibling->priv->next_sibling;
10787
10788       child->priv->next_sibling = tmp;
10789
10790       if (tmp != NULL)
10791         tmp->priv->prev_sibling = child;
10792
10793       sibling->priv->next_sibling = child;
10794     }
10795   else
10796     child->priv->next_sibling = NULL;
10797
10798   if (child->priv->prev_sibling == NULL)
10799     self->priv->first_child = child;
10800
10801   if (child->priv->next_sibling == NULL)
10802     self->priv->last_child = child;
10803 }
10804
10805 static void
10806 insert_child_below (ClutterActor *self,
10807                     ClutterActor *child,
10808                     gpointer      data)
10809 {
10810   ClutterActor *sibling = data;
10811
10812   child->priv->parent = self;
10813
10814   if (sibling == NULL)
10815     sibling = self->priv->first_child;
10816
10817   child->priv->next_sibling = sibling;
10818
10819   if (sibling != NULL)
10820     {
10821       ClutterActor *tmp = sibling->priv->prev_sibling;
10822
10823       child->priv->prev_sibling = tmp;
10824
10825       if (tmp != NULL)
10826         tmp->priv->next_sibling = child;
10827
10828       sibling->priv->prev_sibling = child;
10829     }
10830   else
10831     child->priv->prev_sibling = NULL;
10832
10833   if (child->priv->prev_sibling == NULL)
10834     self->priv->first_child = child;
10835
10836   if (child->priv->next_sibling == NULL)
10837     self->priv->last_child = child;
10838 }
10839
10840 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10841                                            ClutterActor *child,
10842                                            gpointer      data);
10843
10844 typedef enum {
10845   ADD_CHILD_CREATE_META       = 1 << 0,
10846   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10847   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10848   ADD_CHILD_CHECK_STATE       = 1 << 3,
10849   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10850
10851   /* default flags for public API */
10852   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10853                                ADD_CHILD_EMIT_PARENT_SET |
10854                                ADD_CHILD_EMIT_ACTOR_ADDED |
10855                                ADD_CHILD_CHECK_STATE |
10856                                ADD_CHILD_NOTIFY_FIRST_LAST,
10857
10858   /* flags for legacy/deprecated API */
10859   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10860                                ADD_CHILD_CHECK_STATE |
10861                                ADD_CHILD_NOTIFY_FIRST_LAST
10862 } ClutterActorAddChildFlags;
10863
10864 /*< private >
10865  * clutter_actor_add_child_internal:
10866  * @self: a #ClutterActor
10867  * @child: a #ClutterActor
10868  * @flags: control flags for actions
10869  * @add_func: delegate function
10870  * @data: (closure): data to pass to @add_func
10871  *
10872  * Adds @child to the list of children of @self.
10873  *
10874  * The actual insertion inside the list is delegated to @add_func: this
10875  * function will just set up the state, perform basic checks, and emit
10876  * signals.
10877  *
10878  * The @flags argument is used to perform additional operations.
10879  */
10880 static inline void
10881 clutter_actor_add_child_internal (ClutterActor              *self,
10882                                   ClutterActor              *child,
10883                                   ClutterActorAddChildFlags  flags,
10884                                   ClutterActorAddChildFunc   add_func,
10885                                   gpointer                   data)
10886 {
10887   ClutterTextDirection text_dir;
10888   gboolean create_meta;
10889   gboolean emit_parent_set, emit_actor_added;
10890   gboolean check_state;
10891   gboolean notify_first_last;
10892   ClutterActor *old_first_child, *old_last_child;
10893
10894   if (child->priv->parent != NULL)
10895     {
10896       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10897                  "use clutter_actor_remove_child() first.",
10898                  _clutter_actor_get_debug_name (child),
10899                  _clutter_actor_get_debug_name (child->priv->parent));
10900       return;
10901     }
10902
10903   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10904     {
10905       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10906                  "a child of another actor.",
10907                  _clutter_actor_get_debug_name (child));
10908       return;
10909     }
10910
10911 #if 0
10912   /* XXX - this check disallows calling methods that change the stacking
10913    * order within the destruction sequence, by triggering a critical
10914    * warning first, and leaving the actor in an undefined state, which
10915    * then ends up being caught by an assertion.
10916    *
10917    * the reproducible sequence is:
10918    *
10919    *   - actor gets destroyed;
10920    *   - another actor, linked to the first, will try to change the
10921    *     stacking order of the first actor;
10922    *   - changing the stacking order is a composite operation composed
10923    *     by the following steps:
10924    *     1. ref() the child;
10925    *     2. remove_child_internal(), which removes the reference;
10926    *     3. add_child_internal(), which adds a reference;
10927    *   - the state of the actor is not changed between (2) and (3), as
10928    *     it could be an expensive recomputation;
10929    *   - if (3) bails out, then the actor is in an undefined state, but
10930    *     still alive;
10931    *   - the destruction sequence terminates, but the actor is unparented
10932    *     while its state indicates being parented instead.
10933    *   - assertion failure.
10934    *
10935    * the obvious fix would be to decompose each set_child_*_sibling()
10936    * method into proper remove_child()/add_child(), with state validation;
10937    * this may cause excessive work, though, and trigger a cascade of other
10938    * bugs in code that assumes that a change in the stacking order is an
10939    * atomic operation.
10940    *
10941    * another potential fix is to just remove this check here, and let
10942    * code doing stacking order changes inside the destruction sequence
10943    * of an actor continue doing the work.
10944    *
10945    * the third fix is to silently bail out early from every
10946    * set_child_*_sibling() and set_child_at_index() method, and avoid
10947    * doing work.
10948    *
10949    * I have a preference for the second solution, since it involves the
10950    * least amount of work, and the least amount of code duplication.
10951    *
10952    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10953    */
10954   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10955     {
10956       g_warning ("The actor '%s' is currently being destroyed, and "
10957                  "cannot be added as a child of another actor.",
10958                  _clutter_actor_get_debug_name (child));
10959       return;
10960     }
10961 #endif
10962
10963   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10964   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10965   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10966   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10967   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10968
10969   old_first_child = self->priv->first_child;
10970   old_last_child = self->priv->last_child;
10971
10972   g_object_freeze_notify (G_OBJECT (self));
10973
10974   if (create_meta)
10975     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10976
10977   g_object_ref_sink (child);
10978   child->priv->parent = NULL;
10979   child->priv->next_sibling = NULL;
10980   child->priv->prev_sibling = NULL;
10981
10982   /* delegate the actual insertion */
10983   add_func (self, child, data);
10984
10985   g_assert (child->priv->parent == self);
10986
10987   self->priv->n_children += 1;
10988
10989   self->priv->age += 1;
10990
10991   /* if push_internal() has been called then we automatically set
10992    * the flag on the actor
10993    */
10994   if (self->priv->internal_child)
10995     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10996
10997   /* clutter_actor_reparent() will emit ::parent-set for us */
10998   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10999     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11000
11001   if (check_state)
11002     {
11003       /* If parent is mapped or realized, we need to also be mapped or
11004        * realized once we're inside the parent.
11005        */
11006       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11007
11008       /* propagate the parent's text direction to the child */
11009       text_dir = clutter_actor_get_text_direction (self);
11010       clutter_actor_set_text_direction (child, text_dir);
11011     }
11012
11013   if (child->priv->show_on_set_parent)
11014     clutter_actor_show (child);
11015
11016   if (CLUTTER_ACTOR_IS_MAPPED (child))
11017     clutter_actor_queue_redraw (child);
11018
11019   /* maintain the invariant that if an actor needs layout,
11020    * its parents do as well
11021    */
11022   if (child->priv->needs_width_request ||
11023       child->priv->needs_height_request ||
11024       child->priv->needs_allocation)
11025     {
11026       /* we work around the short-circuiting we do
11027        * in clutter_actor_queue_relayout() since we
11028        * want to force a relayout
11029        */
11030       child->priv->needs_width_request = TRUE;
11031       child->priv->needs_height_request = TRUE;
11032       child->priv->needs_allocation = TRUE;
11033
11034       clutter_actor_queue_relayout (child->priv->parent);
11035     }
11036
11037   if (emit_actor_added)
11038     g_signal_emit_by_name (self, "actor-added", child);
11039
11040   if (notify_first_last)
11041     {
11042       if (old_first_child != self->priv->first_child)
11043         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11044
11045       if (old_last_child != self->priv->last_child)
11046         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11047     }
11048
11049   g_object_thaw_notify (G_OBJECT (self));
11050 }
11051
11052 /**
11053  * clutter_actor_add_child:
11054  * @self: a #ClutterActor
11055  * @child: a #ClutterActor
11056  *
11057  * Adds @child to the children of @self.
11058  *
11059  * This function will acquire a reference on @child that will only
11060  * be released when calling clutter_actor_remove_child().
11061  *
11062  * This function will take into consideration the #ClutterActor:depth
11063  * of @child, and will keep the list of children sorted.
11064  *
11065  * This function will emit the #ClutterContainer::actor-added signal
11066  * on @self.
11067  *
11068  * Since: 1.10
11069  */
11070 void
11071 clutter_actor_add_child (ClutterActor *self,
11072                          ClutterActor *child)
11073 {
11074   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11075   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11076   g_return_if_fail (self != child);
11077   g_return_if_fail (child->priv->parent == NULL);
11078
11079   clutter_actor_add_child_internal (self, child,
11080                                     ADD_CHILD_DEFAULT_FLAGS,
11081                                     insert_child_at_depth,
11082                                     NULL);
11083 }
11084
11085 /**
11086  * clutter_actor_insert_child_at_index:
11087  * @self: a #ClutterActor
11088  * @child: a #ClutterActor
11089  * @index_: the index
11090  *
11091  * Inserts @child into the list of children of @self, using the
11092  * given @index_. If @index_ is greater than the number of children
11093  * in @self, or is less than 0, then the new child is added at the end.
11094  *
11095  * This function will acquire a reference on @child that will only
11096  * be released when calling clutter_actor_remove_child().
11097  *
11098  * This function will not take into consideration the #ClutterActor:depth
11099  * of @child.
11100  *
11101  * This function will emit the #ClutterContainer::actor-added signal
11102  * on @self.
11103  *
11104  * Since: 1.10
11105  */
11106 void
11107 clutter_actor_insert_child_at_index (ClutterActor *self,
11108                                      ClutterActor *child,
11109                                      gint          index_)
11110 {
11111   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11112   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11113   g_return_if_fail (self != child);
11114   g_return_if_fail (child->priv->parent == NULL);
11115
11116   clutter_actor_add_child_internal (self, child,
11117                                     ADD_CHILD_DEFAULT_FLAGS,
11118                                     insert_child_at_index,
11119                                     GINT_TO_POINTER (index_));
11120 }
11121
11122 /**
11123  * clutter_actor_insert_child_above:
11124  * @self: a #ClutterActor
11125  * @child: a #ClutterActor
11126  * @sibling: (allow-none): a child of @self, or %NULL
11127  *
11128  * Inserts @child into the list of children of @self, above another
11129  * child of @self or, if @sibling is %NULL, above all the children
11130  * of @self.
11131  *
11132  * This function will acquire a reference on @child that will only
11133  * be released when calling clutter_actor_remove_child().
11134  *
11135  * This function will not take into consideration the #ClutterActor:depth
11136  * of @child.
11137  *
11138  * This function will emit the #ClutterContainer::actor-added signal
11139  * on @self.
11140  *
11141  * Since: 1.10
11142  */
11143 void
11144 clutter_actor_insert_child_above (ClutterActor *self,
11145                                   ClutterActor *child,
11146                                   ClutterActor *sibling)
11147 {
11148   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11149   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11150   g_return_if_fail (self != child);
11151   g_return_if_fail (child != sibling);
11152   g_return_if_fail (child->priv->parent == NULL);
11153   g_return_if_fail (sibling == NULL ||
11154                     (CLUTTER_IS_ACTOR (sibling) &&
11155                      sibling->priv->parent == self));
11156
11157   clutter_actor_add_child_internal (self, child,
11158                                     ADD_CHILD_DEFAULT_FLAGS,
11159                                     insert_child_above,
11160                                     sibling);
11161 }
11162
11163 /**
11164  * clutter_actor_insert_child_below:
11165  * @self: a #ClutterActor
11166  * @child: a #ClutterActor
11167  * @sibling: (allow-none): a child of @self, or %NULL
11168  *
11169  * Inserts @child into the list of children of @self, below another
11170  * child of @self or, if @sibling is %NULL, below all the children
11171  * of @self.
11172  *
11173  * This function will acquire a reference on @child that will only
11174  * be released when calling clutter_actor_remove_child().
11175  *
11176  * This function will not take into consideration the #ClutterActor:depth
11177  * of @child.
11178  *
11179  * This function will emit the #ClutterContainer::actor-added signal
11180  * on @self.
11181  *
11182  * Since: 1.10
11183  */
11184 void
11185 clutter_actor_insert_child_below (ClutterActor *self,
11186                                   ClutterActor *child,
11187                                   ClutterActor *sibling)
11188 {
11189   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11190   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11191   g_return_if_fail (self != child);
11192   g_return_if_fail (child != sibling);
11193   g_return_if_fail (child->priv->parent == NULL);
11194   g_return_if_fail (sibling == NULL ||
11195                     (CLUTTER_IS_ACTOR (sibling) &&
11196                      sibling->priv->parent == self));
11197
11198   clutter_actor_add_child_internal (self, child,
11199                                     ADD_CHILD_DEFAULT_FLAGS,
11200                                     insert_child_below,
11201                                     sibling);
11202 }
11203
11204 /**
11205  * clutter_actor_set_parent:
11206  * @self: A #ClutterActor
11207  * @parent: A new #ClutterActor parent
11208  *
11209  * Sets the parent of @self to @parent.
11210  *
11211  * This function will result in @parent acquiring a reference on @self,
11212  * eventually by sinking its floating reference first. The reference
11213  * will be released by clutter_actor_unparent().
11214  *
11215  * This function should only be called by legacy #ClutterActor<!-- -->s
11216  * implementing the #ClutterContainer interface.
11217  *
11218  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11219  */
11220 void
11221 clutter_actor_set_parent (ClutterActor *self,
11222                           ClutterActor *parent)
11223 {
11224   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11225   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11226   g_return_if_fail (self != parent);
11227   g_return_if_fail (self->priv->parent == NULL);
11228
11229   /* as this function will be called inside ClutterContainer::add
11230    * implementations or when building up a composite actor, we have
11231    * to preserve the old behaviour, and not create child meta or
11232    * emit the ::actor-added signal, to avoid recursion or double
11233    * emissions
11234    */
11235   clutter_actor_add_child_internal (parent, self,
11236                                     ADD_CHILD_LEGACY_FLAGS,
11237                                     insert_child_at_depth,
11238                                     NULL);
11239 }
11240
11241 /**
11242  * clutter_actor_get_parent:
11243  * @self: A #ClutterActor
11244  *
11245  * Retrieves the parent of @self.
11246  *
11247  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11248  *  if no parent is set
11249  */
11250 ClutterActor *
11251 clutter_actor_get_parent (ClutterActor *self)
11252 {
11253   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11254
11255   return self->priv->parent;
11256 }
11257
11258 /**
11259  * clutter_actor_get_paint_visibility:
11260  * @self: A #ClutterActor
11261  *
11262  * Retrieves the 'paint' visibility of an actor recursively checking for non
11263  * visible parents.
11264  *
11265  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11266  *
11267  * Return Value: %TRUE if the actor is visibile and will be painted.
11268  *
11269  * Since: 0.8.4
11270  */
11271 gboolean
11272 clutter_actor_get_paint_visibility (ClutterActor *actor)
11273 {
11274   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11275
11276   return CLUTTER_ACTOR_IS_MAPPED (actor);
11277 }
11278
11279 /**
11280  * clutter_actor_remove_child:
11281  * @self: a #ClutterActor
11282  * @child: a #ClutterActor
11283  *
11284  * Removes @child from the children of @self.
11285  *
11286  * This function will release the reference added by
11287  * clutter_actor_add_child(), so if you want to keep using @child
11288  * you will have to acquire a referenced on it before calling this
11289  * function.
11290  *
11291  * This function will emit the #ClutterContainer::actor-removed
11292  * signal on @self.
11293  *
11294  * Since: 1.10
11295  */
11296 void
11297 clutter_actor_remove_child (ClutterActor *self,
11298                             ClutterActor *child)
11299 {
11300   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11301   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11302   g_return_if_fail (self != child);
11303   g_return_if_fail (child->priv->parent != NULL);
11304   g_return_if_fail (child->priv->parent == self);
11305
11306   clutter_actor_remove_child_internal (self, child,
11307                                        REMOVE_CHILD_DEFAULT_FLAGS);
11308 }
11309
11310 /**
11311  * clutter_actor_remove_all_children:
11312  * @self: a #ClutterActor
11313  *
11314  * Removes all children of @self.
11315  *
11316  * This function releases the reference added by inserting a child actor
11317  * in the list of children of @self.
11318  *
11319  * If the reference count of a child drops to zero, the child will be
11320  * destroyed. If you want to ensure the destruction of all the children
11321  * of @self, use clutter_actor_destroy_all_children().
11322  *
11323  * Since: 1.10
11324  */
11325 void
11326 clutter_actor_remove_all_children (ClutterActor *self)
11327 {
11328   ClutterActorIter iter;
11329
11330   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11331
11332   if (self->priv->n_children == 0)
11333     return;
11334
11335   g_object_freeze_notify (G_OBJECT (self));
11336
11337   clutter_actor_iter_init (&iter, self);
11338   while (clutter_actor_iter_next (&iter, NULL))
11339     clutter_actor_iter_remove (&iter);
11340
11341   g_object_thaw_notify (G_OBJECT (self));
11342
11343   /* sanity check */
11344   g_assert (self->priv->first_child == NULL);
11345   g_assert (self->priv->last_child == NULL);
11346   g_assert (self->priv->n_children == 0);
11347 }
11348
11349 /**
11350  * clutter_actor_destroy_all_children:
11351  * @self: a #ClutterActor
11352  *
11353  * Destroys all children of @self.
11354  *
11355  * This function releases the reference added by inserting a child
11356  * actor in the list of children of @self, and ensures that the
11357  * #ClutterActor::destroy signal is emitted on each child of the
11358  * actor.
11359  *
11360  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11361  * when its reference count drops to 0; the default handler of the
11362  * #ClutterActor::destroy signal will destroy all the children of an
11363  * actor. This function ensures that all children are destroyed, instead
11364  * of just removed from @self, unlike clutter_actor_remove_all_children()
11365  * which will merely release the reference and remove each child.
11366  *
11367  * Unless you acquired an additional reference on each child of @self
11368  * prior to calling clutter_actor_remove_all_children() and want to reuse
11369  * the actors, you should use clutter_actor_destroy_all_children() in
11370  * order to make sure that children are destroyed and signal handlers
11371  * are disconnected even in cases where circular references prevent this
11372  * from automatically happening through reference counting alone.
11373  *
11374  * Since: 1.10
11375  */
11376 void
11377 clutter_actor_destroy_all_children (ClutterActor *self)
11378 {
11379   ClutterActorIter iter;
11380
11381   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11382
11383   if (self->priv->n_children == 0)
11384     return;
11385
11386   g_object_freeze_notify (G_OBJECT (self));
11387
11388   clutter_actor_iter_init (&iter, self);
11389   while (clutter_actor_iter_next (&iter, NULL))
11390     clutter_actor_iter_destroy (&iter);
11391
11392   g_object_thaw_notify (G_OBJECT (self));
11393
11394   /* sanity check */
11395   g_assert (self->priv->first_child == NULL);
11396   g_assert (self->priv->last_child == NULL);
11397   g_assert (self->priv->n_children == 0);
11398 }
11399
11400 typedef struct _InsertBetweenData {
11401   ClutterActor *prev_sibling;
11402   ClutterActor *next_sibling;
11403 } InsertBetweenData;
11404
11405 static void
11406 insert_child_between (ClutterActor *self,
11407                       ClutterActor *child,
11408                       gpointer      data_)
11409 {
11410   InsertBetweenData *data = data_;
11411   ClutterActor *prev_sibling = data->prev_sibling;
11412   ClutterActor *next_sibling = data->next_sibling;
11413
11414   child->priv->parent = self;
11415   child->priv->prev_sibling = prev_sibling;
11416   child->priv->next_sibling = next_sibling;
11417
11418   if (prev_sibling != NULL)
11419     prev_sibling->priv->next_sibling = child;
11420
11421   if (next_sibling != NULL)
11422     next_sibling->priv->prev_sibling = child;
11423
11424   if (child->priv->prev_sibling == NULL)
11425     self->priv->first_child = child;
11426
11427   if (child->priv->next_sibling == NULL)
11428     self->priv->last_child = child;
11429 }
11430
11431 /**
11432  * clutter_actor_replace_child:
11433  * @self: a #ClutterActor
11434  * @old_child: the child of @self to replace
11435  * @new_child: the #ClutterActor to replace @old_child
11436  *
11437  * Replaces @old_child with @new_child in the list of children of @self.
11438  *
11439  * Since: 1.10
11440  */
11441 void
11442 clutter_actor_replace_child (ClutterActor *self,
11443                              ClutterActor *old_child,
11444                              ClutterActor *new_child)
11445 {
11446   ClutterActor *prev_sibling, *next_sibling;
11447   InsertBetweenData clos;
11448
11449   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11450   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11451   g_return_if_fail (old_child->priv->parent == self);
11452   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11453   g_return_if_fail (old_child != new_child);
11454   g_return_if_fail (new_child != self);
11455   g_return_if_fail (new_child->priv->parent == NULL);
11456
11457   prev_sibling = old_child->priv->prev_sibling;
11458   next_sibling = old_child->priv->next_sibling;
11459   clutter_actor_remove_child_internal (self, old_child,
11460                                        REMOVE_CHILD_DEFAULT_FLAGS);
11461
11462   clos.prev_sibling = prev_sibling;
11463   clos.next_sibling = next_sibling;
11464   clutter_actor_add_child_internal (self, new_child,
11465                                     ADD_CHILD_DEFAULT_FLAGS,
11466                                     insert_child_between,
11467                                     &clos);
11468 }
11469
11470 /**
11471  * clutter_actor_unparent:
11472  * @self: a #ClutterActor
11473  *
11474  * Removes the parent of @self.
11475  *
11476  * This will cause the parent of @self to release the reference
11477  * acquired when calling clutter_actor_set_parent(), so if you
11478  * want to keep @self you will have to acquire a reference of
11479  * your own, through g_object_ref().
11480  *
11481  * This function should only be called by legacy #ClutterActor<!-- -->s
11482  * implementing the #ClutterContainer interface.
11483  *
11484  * Since: 0.1.1
11485  *
11486  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11487  */
11488 void
11489 clutter_actor_unparent (ClutterActor *self)
11490 {
11491   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11492
11493   if (self->priv->parent == NULL)
11494     return;
11495
11496   clutter_actor_remove_child_internal (self->priv->parent, self,
11497                                        REMOVE_CHILD_LEGACY_FLAGS);
11498 }
11499
11500 /**
11501  * clutter_actor_reparent:
11502  * @self: a #ClutterActor
11503  * @new_parent: the new #ClutterActor parent
11504  *
11505  * Resets the parent actor of @self.
11506  *
11507  * This function is logically equivalent to calling clutter_actor_unparent()
11508  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11509  * ensures the child is not finalized when unparented, and emits the
11510  * #ClutterActor::parent-set signal only once.
11511  *
11512  * In reality, calling this function is less useful than it sounds, as some
11513  * application code may rely on changes in the intermediate state between
11514  * removal and addition of the actor from its old parent to the @new_parent.
11515  * Thus, it is strongly encouraged to avoid using this function in application
11516  * code.
11517  *
11518  * Since: 0.2
11519  *
11520  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11521  *   clutter_actor_add_child() instead; remember to take a reference on
11522  *   the actor being removed before calling clutter_actor_remove_child()
11523  *   to avoid the reference count dropping to zero and the actor being
11524  *   destroyed.
11525  */
11526 void
11527 clutter_actor_reparent (ClutterActor *self,
11528                         ClutterActor *new_parent)
11529 {
11530   ClutterActorPrivate *priv;
11531
11532   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11533   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11534   g_return_if_fail (self != new_parent);
11535
11536   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11537     {
11538       g_warning ("Cannot set a parent on a toplevel actor");
11539       return;
11540     }
11541
11542   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11543     {
11544       g_warning ("Cannot set a parent currently being destroyed");
11545       return;
11546     }
11547
11548   priv = self->priv;
11549
11550   if (priv->parent != new_parent)
11551     {
11552       ClutterActor *old_parent;
11553
11554       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11555
11556       old_parent = priv->parent;
11557
11558       g_object_ref (self);
11559
11560       if (old_parent != NULL)
11561         {
11562          /* go through the Container implementation if this is a regular
11563           * child and not an internal one
11564           */
11565          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11566            {
11567              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11568
11569              /* this will have to call unparent() */
11570              clutter_container_remove_actor (parent, self);
11571            }
11572          else
11573            clutter_actor_remove_child_internal (old_parent, self,
11574                                                 REMOVE_CHILD_LEGACY_FLAGS);
11575         }
11576
11577       /* Note, will call set_parent() */
11578       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11579         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11580       else
11581         clutter_actor_add_child_internal (new_parent, self,
11582                                           ADD_CHILD_LEGACY_FLAGS,
11583                                           insert_child_at_depth,
11584                                           NULL);
11585
11586       /* we emit the ::parent-set signal once */
11587       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11588
11589       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11590
11591       /* the IN_REPARENT flag suspends state updates */
11592       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11593
11594       g_object_unref (self);
11595    }
11596 }
11597
11598 /**
11599  * clutter_actor_contains:
11600  * @self: A #ClutterActor
11601  * @descendant: A #ClutterActor, possibly contained in @self
11602  *
11603  * Determines if @descendant is contained inside @self (either as an
11604  * immediate child, or as a deeper descendant). If @self and
11605  * @descendant point to the same actor then it will also return %TRUE.
11606  *
11607  * Return value: whether @descendent is contained within @self
11608  *
11609  * Since: 1.4
11610  */
11611 gboolean
11612 clutter_actor_contains (ClutterActor *self,
11613                         ClutterActor *descendant)
11614 {
11615   ClutterActor *actor;
11616
11617   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11618   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11619
11620   for (actor = descendant; actor; actor = actor->priv->parent)
11621     if (actor == self)
11622       return TRUE;
11623
11624   return FALSE;
11625 }
11626
11627 /**
11628  * clutter_actor_set_child_above_sibling:
11629  * @self: a #ClutterActor
11630  * @child: a #ClutterActor child of @self
11631  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11632  *
11633  * Sets @child to be above @sibling in the list of children of @self.
11634  *
11635  * If @sibling is %NULL, @child will be the new last child of @self.
11636  *
11637  * This function is logically equivalent to removing @child and using
11638  * clutter_actor_insert_child_above(), but it will not emit signals
11639  * or change state on @child.
11640  *
11641  * Since: 1.10
11642  */
11643 void
11644 clutter_actor_set_child_above_sibling (ClutterActor *self,
11645                                        ClutterActor *child,
11646                                        ClutterActor *sibling)
11647 {
11648   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11649   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11650   g_return_if_fail (child->priv->parent == self);
11651   g_return_if_fail (child != sibling);
11652   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11653
11654   if (sibling != NULL)
11655     g_return_if_fail (sibling->priv->parent == self);
11656
11657   /* we don't want to change the state of child, or emit signals, or
11658    * regenerate ChildMeta instances here, but we still want to follow
11659    * the correct sequence of steps encoded in remove_child() and
11660    * add_child(), so that correctness is ensured, and we only go
11661    * through one known code path.
11662    */
11663   g_object_ref (child);
11664   clutter_actor_remove_child_internal (self, child, 0);
11665   clutter_actor_add_child_internal (self, child,
11666                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11667                                     insert_child_above,
11668                                     sibling);
11669
11670   clutter_actor_queue_relayout (self);
11671 }
11672
11673 /**
11674  * clutter_actor_set_child_below_sibling:
11675  * @self: a #ClutterActor
11676  * @child: a #ClutterActor child of @self
11677  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11678  *
11679  * Sets @child to be below @sibling in the list of children of @self.
11680  *
11681  * If @sibling is %NULL, @child will be the new first child of @self.
11682  *
11683  * This function is logically equivalent to removing @self and using
11684  * clutter_actor_insert_child_below(), but it will not emit signals
11685  * or change state on @child.
11686  *
11687  * Since: 1.10
11688  */
11689 void
11690 clutter_actor_set_child_below_sibling (ClutterActor *self,
11691                                        ClutterActor *child,
11692                                        ClutterActor *sibling)
11693 {
11694   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11695   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11696   g_return_if_fail (child->priv->parent == self);
11697   g_return_if_fail (child != sibling);
11698   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11699
11700   if (sibling != NULL)
11701     g_return_if_fail (sibling->priv->parent == self);
11702
11703   /* see the comment in set_child_above_sibling() */
11704   g_object_ref (child);
11705   clutter_actor_remove_child_internal (self, child, 0);
11706   clutter_actor_add_child_internal (self, child,
11707                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11708                                     insert_child_below,
11709                                     sibling);
11710
11711   clutter_actor_queue_relayout (self);
11712 }
11713
11714 /**
11715  * clutter_actor_set_child_at_index:
11716  * @self: a #ClutterActor
11717  * @child: a #ClutterActor child of @self
11718  * @index_: the new index for @child
11719  *
11720  * Changes the index of @child in the list of children of @self.
11721  *
11722  * This function is logically equivalent to removing @child and
11723  * calling clutter_actor_insert_child_at_index(), but it will not
11724  * emit signals or change state on @child.
11725  *
11726  * Since: 1.10
11727  */
11728 void
11729 clutter_actor_set_child_at_index (ClutterActor *self,
11730                                   ClutterActor *child,
11731                                   gint          index_)
11732 {
11733   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11734   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11735   g_return_if_fail (child->priv->parent == self);
11736   g_return_if_fail (index_ <= self->priv->n_children);
11737
11738   g_object_ref (child);
11739   clutter_actor_remove_child_internal (self, child, 0);
11740   clutter_actor_add_child_internal (self, child,
11741                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11742                                     insert_child_at_index,
11743                                     GINT_TO_POINTER (index_));
11744
11745   clutter_actor_queue_relayout (self);
11746 }
11747
11748 /**
11749  * clutter_actor_raise:
11750  * @self: A #ClutterActor
11751  * @below: (allow-none): A #ClutterActor to raise above.
11752  *
11753  * Puts @self above @below.
11754  *
11755  * Both actors must have the same parent, and the parent must implement
11756  * the #ClutterContainer interface
11757  *
11758  * This function calls clutter_container_raise_child() internally.
11759  *
11760  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11761  */
11762 void
11763 clutter_actor_raise (ClutterActor *self,
11764                      ClutterActor *below)
11765 {
11766   ClutterActor *parent;
11767
11768   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11769
11770   parent = clutter_actor_get_parent (self);
11771   if (parent == NULL)
11772     {
11773       g_warning ("%s: Actor '%s' is not inside a container",
11774                  G_STRFUNC,
11775                  _clutter_actor_get_debug_name (self));
11776       return;
11777     }
11778
11779   if (below != NULL)
11780     {
11781       if (parent != clutter_actor_get_parent (below))
11782         {
11783           g_warning ("%s Actor '%s' is not in the same container as "
11784                      "actor '%s'",
11785                      G_STRFUNC,
11786                      _clutter_actor_get_debug_name (self),
11787                      _clutter_actor_get_debug_name (below));
11788           return;
11789         }
11790     }
11791
11792   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11793 }
11794
11795 /**
11796  * clutter_actor_lower:
11797  * @self: A #ClutterActor
11798  * @above: (allow-none): A #ClutterActor to lower below
11799  *
11800  * Puts @self below @above.
11801  *
11802  * Both actors must have the same parent, and the parent must implement
11803  * the #ClutterContainer interface.
11804  *
11805  * This function calls clutter_container_lower_child() internally.
11806  *
11807  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11808  */
11809 void
11810 clutter_actor_lower (ClutterActor *self,
11811                      ClutterActor *above)
11812 {
11813   ClutterActor *parent;
11814
11815   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11816
11817   parent = clutter_actor_get_parent (self);
11818   if (parent == NULL)
11819     {
11820       g_warning ("%s: Actor of type %s is not inside a container",
11821                  G_STRFUNC,
11822                  _clutter_actor_get_debug_name (self));
11823       return;
11824     }
11825
11826   if (above)
11827     {
11828       if (parent != clutter_actor_get_parent (above))
11829         {
11830           g_warning ("%s: Actor '%s' is not in the same container as "
11831                      "actor '%s'",
11832                      G_STRFUNC,
11833                      _clutter_actor_get_debug_name (self),
11834                      _clutter_actor_get_debug_name (above));
11835           return;
11836         }
11837     }
11838
11839   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11840 }
11841
11842 /**
11843  * clutter_actor_raise_top:
11844  * @self: A #ClutterActor
11845  *
11846  * Raises @self to the top.
11847  *
11848  * This function calls clutter_actor_raise() internally.
11849  *
11850  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11851  *   a %NULL sibling, instead.
11852  */
11853 void
11854 clutter_actor_raise_top (ClutterActor *self)
11855 {
11856   clutter_actor_raise (self, NULL);
11857 }
11858
11859 /**
11860  * clutter_actor_lower_bottom:
11861  * @self: A #ClutterActor
11862  *
11863  * Lowers @self to the bottom.
11864  *
11865  * This function calls clutter_actor_lower() internally.
11866  *
11867  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11868  *   a %NULL sibling, instead.
11869  */
11870 void
11871 clutter_actor_lower_bottom (ClutterActor *self)
11872 {
11873   clutter_actor_lower (self, NULL);
11874 }
11875
11876 /*
11877  * Event handling
11878  */
11879
11880 /**
11881  * clutter_actor_event:
11882  * @actor: a #ClutterActor
11883  * @event: a #ClutterEvent
11884  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11885  *
11886  * This function is used to emit an event on the main stage.
11887  * You should rarely need to use this function, except for
11888  * synthetising events.
11889  *
11890  * Return value: the return value from the signal emission: %TRUE
11891  *   if the actor handled the event, or %FALSE if the event was
11892  *   not handled
11893  *
11894  * Since: 0.6
11895  */
11896 gboolean
11897 clutter_actor_event (ClutterActor *actor,
11898                      ClutterEvent *event,
11899                      gboolean      capture)
11900 {
11901   gboolean retval = FALSE;
11902   gint signal_num = -1;
11903
11904   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11905   g_return_val_if_fail (event != NULL, FALSE);
11906
11907   g_object_ref (actor);
11908
11909   if (capture)
11910     {
11911       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11912                      event,
11913                      &retval);
11914       goto out;
11915     }
11916
11917   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11918
11919   if (!retval)
11920     {
11921       switch (event->type)
11922         {
11923         case CLUTTER_NOTHING:
11924           break;
11925         case CLUTTER_BUTTON_PRESS:
11926           signal_num = BUTTON_PRESS_EVENT;
11927           break;
11928         case CLUTTER_BUTTON_RELEASE:
11929           signal_num = BUTTON_RELEASE_EVENT;
11930           break;
11931         case CLUTTER_SCROLL:
11932           signal_num = SCROLL_EVENT;
11933           break;
11934         case CLUTTER_KEY_PRESS:
11935           signal_num = KEY_PRESS_EVENT;
11936           break;
11937         case CLUTTER_KEY_RELEASE:
11938           signal_num = KEY_RELEASE_EVENT;
11939           break;
11940         case CLUTTER_MOTION:
11941           signal_num = MOTION_EVENT;
11942           break;
11943         case CLUTTER_ENTER:
11944           signal_num = ENTER_EVENT;
11945           break;
11946         case CLUTTER_LEAVE:
11947           signal_num = LEAVE_EVENT;
11948           break;
11949         case CLUTTER_DELETE:
11950         case CLUTTER_DESTROY_NOTIFY:
11951         case CLUTTER_CLIENT_MESSAGE:
11952         default:
11953           signal_num = -1;
11954           break;
11955         }
11956
11957       if (signal_num != -1)
11958         g_signal_emit (actor, actor_signals[signal_num], 0,
11959                        event, &retval);
11960     }
11961
11962 out:
11963   g_object_unref (actor);
11964
11965   return retval;
11966 }
11967
11968 /**
11969  * clutter_actor_set_reactive:
11970  * @actor: a #ClutterActor
11971  * @reactive: whether the actor should be reactive to events
11972  *
11973  * Sets @actor as reactive. Reactive actors will receive events.
11974  *
11975  * Since: 0.6
11976  */
11977 void
11978 clutter_actor_set_reactive (ClutterActor *actor,
11979                             gboolean      reactive)
11980 {
11981   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11982
11983   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11984     return;
11985
11986   if (reactive)
11987     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11988   else
11989     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11990
11991   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11992 }
11993
11994 /**
11995  * clutter_actor_get_reactive:
11996  * @actor: a #ClutterActor
11997  *
11998  * Checks whether @actor is marked as reactive.
11999  *
12000  * Return value: %TRUE if the actor is reactive
12001  *
12002  * Since: 0.6
12003  */
12004 gboolean
12005 clutter_actor_get_reactive (ClutterActor *actor)
12006 {
12007   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12008
12009   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12010 }
12011
12012 /**
12013  * clutter_actor_get_anchor_point:
12014  * @self: a #ClutterActor
12015  * @anchor_x: (out): return location for the X coordinate of the anchor point
12016  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12017  *
12018  * Gets the current anchor point of the @actor in pixels.
12019  *
12020  * Since: 0.6
12021  */
12022 void
12023 clutter_actor_get_anchor_point (ClutterActor *self,
12024                                 gfloat       *anchor_x,
12025                                 gfloat       *anchor_y)
12026 {
12027   const ClutterTransformInfo *info;
12028
12029   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12030
12031   info = _clutter_actor_get_transform_info_or_defaults (self);
12032   clutter_anchor_coord_get_units (self, &info->anchor,
12033                                   anchor_x,
12034                                   anchor_y,
12035                                   NULL);
12036 }
12037
12038 /**
12039  * clutter_actor_set_anchor_point:
12040  * @self: a #ClutterActor
12041  * @anchor_x: X coordinate of the anchor point
12042  * @anchor_y: Y coordinate of the anchor point
12043  *
12044  * Sets an anchor point for @self. The anchor point is a point in the
12045  * coordinate space of an actor to which the actor position within its
12046  * parent is relative; the default is (0, 0), i.e. the top-left corner
12047  * of the actor.
12048  *
12049  * Since: 0.6
12050  */
12051 void
12052 clutter_actor_set_anchor_point (ClutterActor *self,
12053                                 gfloat        anchor_x,
12054                                 gfloat        anchor_y)
12055 {
12056   ClutterTransformInfo *info;
12057   ClutterActorPrivate *priv;
12058   gboolean changed = FALSE;
12059   gfloat old_anchor_x, old_anchor_y;
12060   GObject *obj;
12061
12062   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12063
12064   obj = G_OBJECT (self);
12065   priv = self->priv;
12066   info = _clutter_actor_get_transform_info (self);
12067
12068   g_object_freeze_notify (obj);
12069
12070   clutter_anchor_coord_get_units (self, &info->anchor,
12071                                   &old_anchor_x,
12072                                   &old_anchor_y,
12073                                   NULL);
12074
12075   if (info->anchor.is_fractional)
12076     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12077
12078   if (old_anchor_x != anchor_x)
12079     {
12080       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12081       changed = TRUE;
12082     }
12083
12084   if (old_anchor_y != anchor_y)
12085     {
12086       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12087       changed = TRUE;
12088     }
12089
12090   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12091
12092   if (changed)
12093     {
12094       priv->transform_valid = FALSE;
12095       clutter_actor_queue_redraw (self);
12096     }
12097
12098   g_object_thaw_notify (obj);
12099 }
12100
12101 /**
12102  * clutter_actor_get_anchor_point_gravity:
12103  * @self: a #ClutterActor
12104  *
12105  * Retrieves the anchor position expressed as a #ClutterGravity. If
12106  * the anchor point was specified using pixels or units this will
12107  * return %CLUTTER_GRAVITY_NONE.
12108  *
12109  * Return value: the #ClutterGravity used by the anchor point
12110  *
12111  * Since: 1.0
12112  */
12113 ClutterGravity
12114 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12115 {
12116   const ClutterTransformInfo *info;
12117
12118   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12119
12120   info = _clutter_actor_get_transform_info_or_defaults (self);
12121
12122   return clutter_anchor_coord_get_gravity (&info->anchor);
12123 }
12124
12125 /**
12126  * clutter_actor_move_anchor_point:
12127  * @self: a #ClutterActor
12128  * @anchor_x: X coordinate of the anchor point
12129  * @anchor_y: Y coordinate of the anchor point
12130  *
12131  * Sets an anchor point for the actor, and adjusts the actor postion so that
12132  * the relative position of the actor toward its parent remains the same.
12133  *
12134  * Since: 0.6
12135  */
12136 void
12137 clutter_actor_move_anchor_point (ClutterActor *self,
12138                                  gfloat        anchor_x,
12139                                  gfloat        anchor_y)
12140 {
12141   gfloat old_anchor_x, old_anchor_y;
12142   const ClutterTransformInfo *info;
12143
12144   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12145
12146   info = _clutter_actor_get_transform_info (self);
12147   clutter_anchor_coord_get_units (self, &info->anchor,
12148                                   &old_anchor_x,
12149                                   &old_anchor_y,
12150                                   NULL);
12151
12152   g_object_freeze_notify (G_OBJECT (self));
12153
12154   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12155
12156   if (self->priv->position_set)
12157     clutter_actor_move_by (self,
12158                            anchor_x - old_anchor_x,
12159                            anchor_y - old_anchor_y);
12160
12161   g_object_thaw_notify (G_OBJECT (self));
12162 }
12163
12164 /**
12165  * clutter_actor_move_anchor_point_from_gravity:
12166  * @self: a #ClutterActor
12167  * @gravity: #ClutterGravity.
12168  *
12169  * Sets an anchor point on the actor based on the given gravity, adjusting the
12170  * actor postion so that its relative position within its parent remains
12171  * unchanged.
12172  *
12173  * Since version 1.0 the anchor point will be stored as a gravity so
12174  * that if the actor changes size then the anchor point will move. For
12175  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12176  * and later double the size of the actor, the anchor point will move
12177  * to the bottom right.
12178  *
12179  * Since: 0.6
12180  */
12181 void
12182 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12183                                               ClutterGravity  gravity)
12184 {
12185   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12186   const ClutterTransformInfo *info;
12187   ClutterActorPrivate *priv;
12188
12189   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12190
12191   priv = self->priv;
12192   info = _clutter_actor_get_transform_info (self);
12193
12194   g_object_freeze_notify (G_OBJECT (self));
12195
12196   clutter_anchor_coord_get_units (self, &info->anchor,
12197                                   &old_anchor_x,
12198                                   &old_anchor_y,
12199                                   NULL);
12200   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12201   clutter_anchor_coord_get_units (self, &info->anchor,
12202                                   &new_anchor_x,
12203                                   &new_anchor_y,
12204                                   NULL);
12205
12206   if (priv->position_set)
12207     clutter_actor_move_by (self,
12208                            new_anchor_x - old_anchor_x,
12209                            new_anchor_y - old_anchor_y);
12210
12211   g_object_thaw_notify (G_OBJECT (self));
12212 }
12213
12214 /**
12215  * clutter_actor_set_anchor_point_from_gravity:
12216  * @self: a #ClutterActor
12217  * @gravity: #ClutterGravity.
12218  *
12219  * Sets an anchor point on the actor, based on the given gravity (this is a
12220  * convenience function wrapping clutter_actor_set_anchor_point()).
12221  *
12222  * Since version 1.0 the anchor point will be stored as a gravity so
12223  * that if the actor changes size then the anchor point will move. For
12224  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12225  * and later double the size of the actor, the anchor point will move
12226  * to the bottom right.
12227  *
12228  * Since: 0.6
12229  */
12230 void
12231 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12232                                              ClutterGravity  gravity)
12233 {
12234   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12235
12236   if (gravity == CLUTTER_GRAVITY_NONE)
12237     clutter_actor_set_anchor_point (self, 0, 0);
12238   else
12239     {
12240       GObject *obj = G_OBJECT (self);
12241       ClutterTransformInfo *info;
12242
12243       g_object_freeze_notify (obj);
12244
12245       info = _clutter_actor_get_transform_info (self);
12246       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12247
12248       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12249       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12250       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12251
12252       self->priv->transform_valid = FALSE;
12253
12254       clutter_actor_queue_redraw (self);
12255
12256       g_object_thaw_notify (obj);
12257     }
12258 }
12259
12260 static void
12261 clutter_container_iface_init (ClutterContainerIface *iface)
12262 {
12263   /* we don't override anything, as ClutterContainer already has a default
12264    * implementation that we can use, and which calls into our own API.
12265    */
12266 }
12267
12268 typedef enum
12269 {
12270   PARSE_X,
12271   PARSE_Y,
12272   PARSE_WIDTH,
12273   PARSE_HEIGHT,
12274   PARSE_ANCHOR_X,
12275   PARSE_ANCHOR_Y
12276 } ParseDimension;
12277
12278 static gfloat
12279 parse_units (ClutterActor   *self,
12280              ParseDimension  dimension,
12281              JsonNode       *node)
12282 {
12283   GValue value = { 0, };
12284   gfloat retval = 0;
12285
12286   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12287     return 0;
12288
12289   json_node_get_value (node, &value);
12290
12291   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12292     {
12293       retval = (gfloat) g_value_get_int64 (&value);
12294     }
12295   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12296     {
12297       retval = g_value_get_double (&value);
12298     }
12299   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12300     {
12301       ClutterUnits units;
12302       gboolean res;
12303
12304       res = clutter_units_from_string (&units, g_value_get_string (&value));
12305       if (res)
12306         retval = clutter_units_to_pixels (&units);
12307       else
12308         {
12309           g_warning ("Invalid value '%s': integers, strings or floating point "
12310                      "values can be used for the x, y, width and height "
12311                      "properties. Valid modifiers for strings are 'px', 'mm', "
12312                      "'pt' and 'em'.",
12313                      g_value_get_string (&value));
12314           retval = 0;
12315         }
12316     }
12317   else
12318     {
12319       g_warning ("Invalid value of type '%s': integers, strings of floating "
12320                  "point values can be used for the x, y, width, height "
12321                  "anchor-x and anchor-y properties.",
12322                  g_type_name (G_VALUE_TYPE (&value)));
12323     }
12324
12325   g_value_unset (&value);
12326
12327   return retval;
12328 }
12329
12330 typedef struct {
12331   ClutterRotateAxis axis;
12332
12333   gdouble angle;
12334
12335   gfloat center_x;
12336   gfloat center_y;
12337   gfloat center_z;
12338 } RotationInfo;
12339
12340 static inline gboolean
12341 parse_rotation_array (ClutterActor *actor,
12342                       JsonArray    *array,
12343                       RotationInfo *info)
12344 {
12345   JsonNode *element;
12346
12347   if (json_array_get_length (array) != 2)
12348     return FALSE;
12349
12350   /* angle */
12351   element = json_array_get_element (array, 0);
12352   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12353     info->angle = json_node_get_double (element);
12354   else
12355     return FALSE;
12356
12357   /* center */
12358   element = json_array_get_element (array, 1);
12359   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12360     {
12361       JsonArray *center = json_node_get_array (element);
12362
12363       if (json_array_get_length (center) != 2)
12364         return FALSE;
12365
12366       switch (info->axis)
12367         {
12368         case CLUTTER_X_AXIS:
12369           info->center_y = parse_units (actor, PARSE_Y,
12370                                         json_array_get_element (center, 0));
12371           info->center_z = parse_units (actor, PARSE_Y,
12372                                         json_array_get_element (center, 1));
12373           return TRUE;
12374
12375         case CLUTTER_Y_AXIS:
12376           info->center_x = parse_units (actor, PARSE_X,
12377                                         json_array_get_element (center, 0));
12378           info->center_z = parse_units (actor, PARSE_X,
12379                                         json_array_get_element (center, 1));
12380           return TRUE;
12381
12382         case CLUTTER_Z_AXIS:
12383           info->center_x = parse_units (actor, PARSE_X,
12384                                         json_array_get_element (center, 0));
12385           info->center_y = parse_units (actor, PARSE_Y,
12386                                         json_array_get_element (center, 1));
12387           return TRUE;
12388         }
12389     }
12390
12391   return FALSE;
12392 }
12393
12394 static gboolean
12395 parse_rotation (ClutterActor *actor,
12396                 JsonNode     *node,
12397                 RotationInfo *info)
12398 {
12399   JsonArray *array;
12400   guint len, i;
12401   gboolean retval = FALSE;
12402
12403   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12404     {
12405       g_warning ("Invalid node of type '%s' found, expecting an array",
12406                  json_node_type_name (node));
12407       return FALSE;
12408     }
12409
12410   array = json_node_get_array (node);
12411   len = json_array_get_length (array);
12412
12413   for (i = 0; i < len; i++)
12414     {
12415       JsonNode *element = json_array_get_element (array, i);
12416       JsonObject *object;
12417       JsonNode *member;
12418
12419       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12420         {
12421           g_warning ("Invalid node of type '%s' found, expecting an object",
12422                      json_node_type_name (element));
12423           return FALSE;
12424         }
12425
12426       object = json_node_get_object (element);
12427
12428       if (json_object_has_member (object, "x-axis"))
12429         {
12430           member = json_object_get_member (object, "x-axis");
12431
12432           info->axis = CLUTTER_X_AXIS;
12433
12434           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12435             {
12436               info->angle = json_node_get_double (member);
12437               retval = TRUE;
12438             }
12439           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12440             retval = parse_rotation_array (actor,
12441                                            json_node_get_array (member),
12442                                            info);
12443           else
12444             retval = FALSE;
12445         }
12446       else if (json_object_has_member (object, "y-axis"))
12447         {
12448           member = json_object_get_member (object, "y-axis");
12449
12450           info->axis = CLUTTER_Y_AXIS;
12451
12452           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12453             {
12454               info->angle = json_node_get_double (member);
12455               retval = TRUE;
12456             }
12457           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12458             retval = parse_rotation_array (actor,
12459                                            json_node_get_array (member),
12460                                            info);
12461           else
12462             retval = FALSE;
12463         }
12464       else if (json_object_has_member (object, "z-axis"))
12465         {
12466           member = json_object_get_member (object, "z-axis");
12467
12468           info->axis = CLUTTER_Z_AXIS;
12469
12470           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12471             {
12472               info->angle = json_node_get_double (member);
12473               retval = TRUE;
12474             }
12475           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12476             retval = parse_rotation_array (actor,
12477                                            json_node_get_array (member),
12478                                            info);
12479           else
12480             retval = FALSE;
12481         }
12482     }
12483
12484   return retval;
12485 }
12486
12487 static GSList *
12488 parse_actor_metas (ClutterScript *script,
12489                    ClutterActor  *actor,
12490                    JsonNode      *node)
12491 {
12492   GList *elements, *l;
12493   GSList *retval = NULL;
12494
12495   if (!JSON_NODE_HOLDS_ARRAY (node))
12496     return NULL;
12497
12498   elements = json_array_get_elements (json_node_get_array (node));
12499
12500   for (l = elements; l != NULL; l = l->next)
12501     {
12502       JsonNode *element = l->data;
12503       const gchar *id_ = _clutter_script_get_id_from_node (element);
12504       GObject *meta;
12505
12506       if (id_ == NULL || *id_ == '\0')
12507         continue;
12508
12509       meta = clutter_script_get_object (script, id_);
12510       if (meta == NULL)
12511         continue;
12512
12513       retval = g_slist_prepend (retval, meta);
12514     }
12515
12516   g_list_free (elements);
12517
12518   return g_slist_reverse (retval);
12519 }
12520
12521 static GSList *
12522 parse_behaviours (ClutterScript *script,
12523                   ClutterActor  *actor,
12524                   JsonNode      *node)
12525 {
12526   GList *elements, *l;
12527   GSList *retval = NULL;
12528
12529   if (!JSON_NODE_HOLDS_ARRAY (node))
12530     return NULL;
12531
12532   elements = json_array_get_elements (json_node_get_array (node));
12533
12534   for (l = elements; l != NULL; l = l->next)
12535     {
12536       JsonNode *element = l->data;
12537       const gchar *id_ = _clutter_script_get_id_from_node (element);
12538       GObject *behaviour;
12539
12540       if (id_ == NULL || *id_ == '\0')
12541         continue;
12542
12543       behaviour = clutter_script_get_object (script, id_);
12544       if (behaviour == NULL)
12545         continue;
12546
12547       retval = g_slist_prepend (retval, behaviour);
12548     }
12549
12550   g_list_free (elements);
12551
12552   return g_slist_reverse (retval);
12553 }
12554
12555 static gboolean
12556 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12557                                  ClutterScript     *script,
12558                                  GValue            *value,
12559                                  const gchar       *name,
12560                                  JsonNode          *node)
12561 {
12562   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12563   gboolean retval = FALSE;
12564
12565   if ((name[0] == 'x' && name[1] == '\0') ||
12566       (name[0] == 'y' && name[1] == '\0') ||
12567       (strcmp (name, "width") == 0) ||
12568       (strcmp (name, "height") == 0) ||
12569       (strcmp (name, "anchor_x") == 0) ||
12570       (strcmp (name, "anchor_y") == 0))
12571     {
12572       ParseDimension dimension;
12573       gfloat units;
12574
12575       if (name[0] == 'x')
12576         dimension = PARSE_X;
12577       else if (name[0] == 'y')
12578         dimension = PARSE_Y;
12579       else if (name[0] == 'w')
12580         dimension = PARSE_WIDTH;
12581       else if (name[0] == 'h')
12582         dimension = PARSE_HEIGHT;
12583       else if (name[0] == 'a' && name[7] == 'x')
12584         dimension = PARSE_ANCHOR_X;
12585       else if (name[0] == 'a' && name[7] == 'y')
12586         dimension = PARSE_ANCHOR_Y;
12587       else
12588         return FALSE;
12589
12590       units = parse_units (actor, dimension, node);
12591
12592       /* convert back to pixels: all properties are pixel-based */
12593       g_value_init (value, G_TYPE_FLOAT);
12594       g_value_set_float (value, units);
12595
12596       retval = TRUE;
12597     }
12598   else if (strcmp (name, "rotation") == 0)
12599     {
12600       RotationInfo *info;
12601
12602       info = g_slice_new0 (RotationInfo);
12603       retval = parse_rotation (actor, node, info);
12604
12605       if (retval)
12606         {
12607           g_value_init (value, G_TYPE_POINTER);
12608           g_value_set_pointer (value, info);
12609         }
12610       else
12611         g_slice_free (RotationInfo, info);
12612     }
12613   else if (strcmp (name, "behaviours") == 0)
12614     {
12615       GSList *l;
12616
12617 #ifdef CLUTTER_ENABLE_DEBUG
12618       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12619         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12620                                      "and it should not be used in newly "
12621                                      "written ClutterScript definitions.");
12622 #endif
12623
12624       l = parse_behaviours (script, actor, node);
12625
12626       g_value_init (value, G_TYPE_POINTER);
12627       g_value_set_pointer (value, l);
12628
12629       retval = TRUE;
12630     }
12631   else if (strcmp (name, "actions") == 0 ||
12632            strcmp (name, "constraints") == 0 ||
12633            strcmp (name, "effects") == 0)
12634     {
12635       GSList *l;
12636
12637       l = parse_actor_metas (script, actor, node);
12638
12639       g_value_init (value, G_TYPE_POINTER);
12640       g_value_set_pointer (value, l);
12641
12642       retval = TRUE;
12643     }
12644
12645   return retval;
12646 }
12647
12648 static void
12649 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12650                                    ClutterScript     *script,
12651                                    const gchar       *name,
12652                                    const GValue      *value)
12653 {
12654   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12655
12656 #ifdef CLUTTER_ENABLE_DEBUG
12657   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12658     {
12659       gchar *tmp = g_strdup_value_contents (value);
12660
12661       CLUTTER_NOTE (SCRIPT,
12662                     "in ClutterActor::set_custom_property('%s') = %s",
12663                     name,
12664                     tmp);
12665
12666       g_free (tmp);
12667     }
12668 #endif /* CLUTTER_ENABLE_DEBUG */
12669
12670   if (strcmp (name, "rotation") == 0)
12671     {
12672       RotationInfo *info;
12673
12674       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12675         return;
12676
12677       info = g_value_get_pointer (value);
12678
12679       clutter_actor_set_rotation (actor,
12680                                   info->axis, info->angle,
12681                                   info->center_x,
12682                                   info->center_y,
12683                                   info->center_z);
12684
12685       g_slice_free (RotationInfo, info);
12686
12687       return;
12688     }
12689
12690   if (strcmp (name, "behaviours") == 0)
12691     {
12692       GSList *behaviours, *l;
12693
12694       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12695         return;
12696
12697       behaviours = g_value_get_pointer (value);
12698       for (l = behaviours; l != NULL; l = l->next)
12699         {
12700           ClutterBehaviour *behaviour = l->data;
12701
12702           clutter_behaviour_apply (behaviour, actor);
12703         }
12704
12705       g_slist_free (behaviours);
12706
12707       return;
12708     }
12709
12710   if (strcmp (name, "actions") == 0 ||
12711       strcmp (name, "constraints") == 0 ||
12712       strcmp (name, "effects") == 0)
12713     {
12714       GSList *metas, *l;
12715
12716       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12717         return;
12718
12719       metas = g_value_get_pointer (value);
12720       for (l = metas; l != NULL; l = l->next)
12721         {
12722           if (name[0] == 'a')
12723             clutter_actor_add_action (actor, l->data);
12724
12725           if (name[0] == 'c')
12726             clutter_actor_add_constraint (actor, l->data);
12727
12728           if (name[0] == 'e')
12729             clutter_actor_add_effect (actor, l->data);
12730         }
12731
12732       g_slist_free (metas);
12733
12734       return;
12735     }
12736
12737   g_object_set_property (G_OBJECT (scriptable), name, value);
12738 }
12739
12740 static void
12741 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12742 {
12743   iface->parse_custom_node = clutter_actor_parse_custom_node;
12744   iface->set_custom_property = clutter_actor_set_custom_property;
12745 }
12746
12747 static ClutterActorMeta *
12748 get_meta_from_animation_property (ClutterActor  *actor,
12749                                   const gchar   *name,
12750                                   gchar        **name_p)
12751 {
12752   ClutterActorPrivate *priv = actor->priv;
12753   ClutterActorMeta *meta = NULL;
12754   gchar **tokens;
12755
12756   /* if this is not a special property, fall through */
12757   if (name[0] != '@')
12758     return NULL;
12759
12760   /* detect the properties named using the following spec:
12761    *
12762    *   @<section>.<meta-name>.<property-name>
12763    *
12764    * where <section> can be one of the following:
12765    *
12766    *   - actions
12767    *   - constraints
12768    *   - effects
12769    *
12770    * and <meta-name> is the name set on a specific ActorMeta
12771    */
12772
12773   tokens = g_strsplit (name + 1, ".", -1);
12774   if (tokens == NULL || g_strv_length (tokens) != 3)
12775     {
12776       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12777                     name + 1);
12778       g_strfreev (tokens);
12779       return NULL;
12780     }
12781
12782   if (strcmp (tokens[0], "actions") == 0)
12783     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12784
12785   if (strcmp (tokens[0], "constraints") == 0)
12786     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12787
12788   if (strcmp (tokens[0], "effects") == 0)
12789     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12790
12791   if (name_p != NULL)
12792     *name_p = g_strdup (tokens[2]);
12793
12794   CLUTTER_NOTE (ANIMATION,
12795                 "Looking for property '%s' of object '%s' in section '%s'",
12796                 tokens[2],
12797                 tokens[1],
12798                 tokens[0]);
12799
12800   g_strfreev (tokens);
12801
12802   return meta;
12803 }
12804
12805 static GParamSpec *
12806 clutter_actor_find_property (ClutterAnimatable *animatable,
12807                              const gchar       *property_name)
12808 {
12809   ClutterActorMeta *meta = NULL;
12810   GObjectClass *klass = NULL;
12811   GParamSpec *pspec = NULL;
12812   gchar *p_name = NULL;
12813
12814   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12815                                            property_name,
12816                                            &p_name);
12817
12818   if (meta != NULL)
12819     {
12820       klass = G_OBJECT_GET_CLASS (meta);
12821
12822       pspec = g_object_class_find_property (klass, p_name);
12823     }
12824   else
12825     {
12826       klass = G_OBJECT_GET_CLASS (animatable);
12827
12828       pspec = g_object_class_find_property (klass, property_name);
12829     }
12830
12831   g_free (p_name);
12832
12833   return pspec;
12834 }
12835
12836 static void
12837 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12838                                  const gchar       *property_name,
12839                                  GValue            *initial)
12840 {
12841   ClutterActorMeta *meta = NULL;
12842   gchar *p_name = NULL;
12843
12844   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12845                                            property_name,
12846                                            &p_name);
12847
12848   if (meta != NULL)
12849     g_object_get_property (G_OBJECT (meta), p_name, initial);
12850   else
12851     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12852
12853   g_free (p_name);
12854 }
12855
12856 /*
12857  * clutter_actor_set_animatable_property:
12858  * @actor: a #ClutterActor
12859  * @prop_id: the paramspec id
12860  * @value: the value to set
12861  * @pspec: the paramspec
12862  *
12863  * Sets values of animatable properties.
12864  *
12865  * This is a variant of clutter_actor_set_property() that gets called
12866  * by the #ClutterAnimatable implementation of #ClutterActor for the
12867  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12868  * #GParamSpec.
12869  *
12870  * Unlike the implementation of #GObjectClass.set_property(), this
12871  * function will not update the interval if a transition involving an
12872  * animatable property is in progress - this avoids cycles with the
12873  * transition API calling the public API.
12874  */
12875 static void
12876 clutter_actor_set_animatable_property (ClutterActor *actor,
12877                                        guint         prop_id,
12878                                        const GValue *value,
12879                                        GParamSpec   *pspec)
12880 {
12881   switch (prop_id)
12882     {
12883     case PROP_X:
12884       clutter_actor_set_x_internal (actor, g_value_get_float (value));
12885       break;
12886
12887     case PROP_Y:
12888       clutter_actor_set_y_internal (actor, g_value_get_float (value));
12889       break;
12890
12891     case PROP_WIDTH:
12892       clutter_actor_set_width_internal (actor, g_value_get_float (value));
12893       break;
12894
12895     case PROP_HEIGHT:
12896       clutter_actor_set_height_internal (actor, g_value_get_float (value));
12897       break;
12898
12899     case PROP_DEPTH:
12900       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12901       break;
12902
12903     case PROP_OPACITY:
12904       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12905       break;
12906
12907     case PROP_BACKGROUND_COLOR:
12908       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12909       break;
12910
12911     case PROP_SCALE_X:
12912       clutter_actor_set_scale_factor_internal (actor,
12913                                                g_value_get_double (value),
12914                                                pspec);
12915       break;
12916
12917     case PROP_SCALE_Y:
12918       clutter_actor_set_scale_factor_internal (actor,
12919                                                g_value_get_double (value),
12920                                                pspec);
12921       break;
12922
12923     case PROP_ROTATION_ANGLE_X:
12924       clutter_actor_set_rotation_angle_internal (actor,
12925                                                  CLUTTER_X_AXIS,
12926                                                  g_value_get_double (value));
12927       break;
12928
12929     case PROP_ROTATION_ANGLE_Y:
12930       clutter_actor_set_rotation_angle_internal (actor,
12931                                                  CLUTTER_Y_AXIS,
12932                                                  g_value_get_double (value));
12933       break;
12934
12935     case PROP_ROTATION_ANGLE_Z:
12936       clutter_actor_set_rotation_angle_internal (actor,
12937                                                  CLUTTER_Z_AXIS,
12938                                                  g_value_get_double (value));
12939       break;
12940
12941     default:
12942       g_object_set_property (G_OBJECT (actor), pspec->name, value);
12943       break;
12944     }
12945 }
12946
12947 static void
12948 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12949                                const gchar       *property_name,
12950                                const GValue      *final)
12951 {
12952   ClutterActor *actor = CLUTTER_ACTOR (animatable);
12953   ClutterActorMeta *meta = NULL;
12954   gchar *p_name = NULL;
12955
12956   meta = get_meta_from_animation_property (actor,
12957                                            property_name,
12958                                            &p_name);
12959   if (meta != NULL)
12960     g_object_set_property (G_OBJECT (meta), p_name, final);
12961   else
12962     {
12963       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12964       GParamSpec *pspec;
12965
12966       pspec = g_object_class_find_property (obj_class, property_name);
12967
12968       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12969         {
12970           /* XXX - I'm going to the special hell for this */
12971           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12972         }
12973       else
12974         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
12975     }
12976
12977   g_free (p_name);
12978 }
12979
12980 static void
12981 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12982 {
12983   iface->find_property = clutter_actor_find_property;
12984   iface->get_initial_state = clutter_actor_get_initial_state;
12985   iface->set_final_state = clutter_actor_set_final_state;
12986 }
12987
12988 /**
12989  * clutter_actor_transform_stage_point:
12990  * @self: A #ClutterActor
12991  * @x: (in): x screen coordinate of the point to unproject
12992  * @y: (in): y screen coordinate of the point to unproject
12993  * @x_out: (out): return location for the unprojected x coordinance
12994  * @y_out: (out): return location for the unprojected y coordinance
12995  *
12996  * This function translates screen coordinates (@x, @y) to
12997  * coordinates relative to the actor. For example, it can be used to translate
12998  * screen events from global screen coordinates into actor-local coordinates.
12999  *
13000  * The conversion can fail, notably if the transform stack results in the
13001  * actor being projected on the screen as a mere line.
13002  *
13003  * The conversion should not be expected to be pixel-perfect due to the
13004  * nature of the operation. In general the error grows when the skewing
13005  * of the actor rectangle on screen increases.
13006  *
13007  * <note><para>This function can be computationally intensive.</para></note>
13008  *
13009  * <note><para>This function only works when the allocation is up-to-date,
13010  * i.e. inside of paint().</para></note>
13011  *
13012  * Return value: %TRUE if conversion was successful.
13013  *
13014  * Since: 0.6
13015  */
13016 gboolean
13017 clutter_actor_transform_stage_point (ClutterActor *self,
13018                                      gfloat        x,
13019                                      gfloat        y,
13020                                      gfloat       *x_out,
13021                                      gfloat       *y_out)
13022 {
13023   ClutterVertex v[4];
13024   float ST[3][3];
13025   float RQ[3][3];
13026   int du, dv, xi, yi;
13027   float px, py;
13028   float xf, yf, wf, det;
13029   ClutterActorPrivate *priv;
13030
13031   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13032
13033   priv = self->priv;
13034
13035   /* This implementation is based on the quad -> quad projection algorithm
13036    * described by Paul Heckbert in:
13037    *
13038    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13039    *
13040    * and the sample implementation at:
13041    *
13042    *   http://www.cs.cmu.edu/~ph/src/texfund/
13043    *
13044    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13045    * quad to rectangle only, which significantly simplifies things; the
13046    * function calls have been unrolled, and most of the math is done in fixed
13047    * point.
13048    */
13049
13050   clutter_actor_get_abs_allocation_vertices (self, v);
13051
13052   /* Keeping these as ints simplifies the multiplication (no significant
13053    * loss of precision here).
13054    */
13055   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13056   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13057
13058   if (!du || !dv)
13059     return FALSE;
13060
13061 #define UX2FP(x)        (x)
13062 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13063
13064   /* First, find mapping from unit uv square to xy quadrilateral; this
13065    * equivalent to the pmap_square_quad() functions in the sample
13066    * implementation, which we can simplify, since our target is always
13067    * a rectangle.
13068    */
13069   px = v[0].x - v[1].x + v[3].x - v[2].x;
13070   py = v[0].y - v[1].y + v[3].y - v[2].y;
13071
13072   if (!px && !py)
13073     {
13074       /* affine transform */
13075       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13076       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13077       RQ[2][0] = UX2FP (v[0].x);
13078       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13079       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13080       RQ[2][1] = UX2FP (v[0].y);
13081       RQ[0][2] = 0;
13082       RQ[1][2] = 0;
13083       RQ[2][2] = 1.0;
13084     }
13085   else
13086     {
13087       /* projective transform */
13088       double dx1, dx2, dy1, dy2, del;
13089
13090       dx1 = UX2FP (v[1].x - v[3].x);
13091       dx2 = UX2FP (v[2].x - v[3].x);
13092       dy1 = UX2FP (v[1].y - v[3].y);
13093       dy2 = UX2FP (v[2].y - v[3].y);
13094
13095       del = DET2FP (dx1, dx2, dy1, dy2);
13096       if (!del)
13097         return FALSE;
13098
13099       /*
13100        * The division here needs to be done in floating point for
13101        * precisions reasons.
13102        */
13103       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13104       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13105       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13106       RQ[2][2] = 1.0;
13107       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13108       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13109       RQ[2][0] = UX2FP (v[0].x);
13110       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13111       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13112       RQ[2][1] = UX2FP (v[0].y);
13113     }
13114
13115   /*
13116    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13117    * square. Since our rectangle is based at 0,0 we only need to scale.
13118    */
13119   RQ[0][0] /= du;
13120   RQ[1][0] /= dv;
13121   RQ[0][1] /= du;
13122   RQ[1][1] /= dv;
13123   RQ[0][2] /= du;
13124   RQ[1][2] /= dv;
13125
13126   /*
13127    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13128    * inverse of that.
13129    */
13130   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13131   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13132   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13133   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13134   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13135   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13136   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13137   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13138   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13139
13140   /*
13141    * Check the resulting matrix is OK.
13142    */
13143   det = (RQ[0][0] * ST[0][0])
13144       + (RQ[0][1] * ST[0][1])
13145       + (RQ[0][2] * ST[0][2]);
13146   if (!det)
13147     return FALSE;
13148
13149   /*
13150    * Now transform our point with the ST matrix; the notional w
13151    * coordinate is 1, hence the last part is simply added.
13152    */
13153   xi = (int) x;
13154   yi = (int) y;
13155
13156   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13157   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13158   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13159
13160   if (x_out)
13161     *x_out = xf / wf;
13162
13163   if (y_out)
13164     *y_out = yf / wf;
13165
13166 #undef UX2FP
13167 #undef DET2FP
13168
13169   return TRUE;
13170 }
13171
13172 /*
13173  * ClutterGeometry
13174  */
13175
13176 static ClutterGeometry*
13177 clutter_geometry_copy (const ClutterGeometry *geometry)
13178 {
13179   return g_slice_dup (ClutterGeometry, geometry);
13180 }
13181
13182 static void
13183 clutter_geometry_free (ClutterGeometry *geometry)
13184 {
13185   if (G_LIKELY (geometry != NULL))
13186     g_slice_free (ClutterGeometry, geometry);
13187 }
13188
13189 /**
13190  * clutter_geometry_union:
13191  * @geometry_a: a #ClutterGeometry
13192  * @geometry_b: another #ClutterGeometry
13193  * @result: (out): location to store the result
13194  *
13195  * Find the union of two rectangles represented as #ClutterGeometry.
13196  *
13197  * Since: 1.4
13198  */
13199 void
13200 clutter_geometry_union (const ClutterGeometry *geometry_a,
13201                         const ClutterGeometry *geometry_b,
13202                         ClutterGeometry       *result)
13203 {
13204   /* We don't try to handle rectangles that can't be represented
13205    * as a signed integer box */
13206   gint x_1 = MIN (geometry_a->x, geometry_b->x);
13207   gint y_1 = MIN (geometry_a->y, geometry_b->y);
13208   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13209                   geometry_b->x + (gint)geometry_b->width);
13210   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13211                   geometry_b->y + (gint)geometry_b->height);
13212   result->x = x_1;
13213   result->y = y_1;
13214   result->width = x_2 - x_1;
13215   result->height = y_2 - y_1;
13216 }
13217
13218 /**
13219  * clutter_geometry_intersects:
13220  * @geometry0: The first geometry to test
13221  * @geometry1: The second geometry to test
13222  *
13223  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13224  * they do else %FALSE.
13225  *
13226  * Return value: %TRUE of @geometry0 and geometry1 intersect else
13227  * %FALSE.
13228  *
13229  * Since: 1.4
13230  */
13231 gboolean
13232 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13233                              const ClutterGeometry *geometry1)
13234 {
13235   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13236       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13237       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13238       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13239     return FALSE;
13240   else
13241     return TRUE;
13242 }
13243
13244 static gboolean
13245 clutter_geometry_progress (const GValue *a,
13246                            const GValue *b,
13247                            gdouble       progress,
13248                            GValue       *retval)
13249 {
13250   const ClutterGeometry *a_geom = g_value_get_boxed (a);
13251   const ClutterGeometry *b_geom = g_value_get_boxed (b);
13252   ClutterGeometry res = { 0, };
13253   gint a_width = a_geom->width;
13254   gint b_width = b_geom->width;
13255   gint a_height = a_geom->height;
13256   gint b_height = b_geom->height;
13257
13258   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13259   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13260
13261   res.width = a_width + (b_width - a_width) * progress;
13262   res.height = a_height + (b_height - a_height) * progress;
13263
13264   g_value_set_boxed (retval, &res);
13265
13266   return TRUE;
13267 }
13268
13269 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13270                                clutter_geometry_copy,
13271                                clutter_geometry_free,
13272                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13273
13274 /*
13275  * ClutterVertices
13276  */
13277
13278 /**
13279  * clutter_vertex_new:
13280  * @x: X coordinate
13281  * @y: Y coordinate
13282  * @z: Z coordinate
13283  *
13284  * Creates a new #ClutterVertex for the point in 3D space
13285  * identified by the 3 coordinates @x, @y, @z
13286  *
13287  * Return value: the newly allocate #ClutterVertex. Use
13288  *   clutter_vertex_free() to free the resources
13289  *
13290  * Since: 1.0
13291  */
13292 ClutterVertex *
13293 clutter_vertex_new (gfloat x,
13294                     gfloat y,
13295                     gfloat z)
13296 {
13297   ClutterVertex *vertex;
13298
13299   vertex = g_slice_new (ClutterVertex);
13300   vertex->x = x;
13301   vertex->y = y;
13302   vertex->z = z;
13303
13304   return vertex;
13305 }
13306
13307 /**
13308  * clutter_vertex_copy:
13309  * @vertex: a #ClutterVertex
13310  *
13311  * Copies @vertex
13312  *
13313  * Return value: a newly allocated copy of #ClutterVertex. Use
13314  *   clutter_vertex_free() to free the allocated resources
13315  *
13316  * Since: 1.0
13317  */
13318 ClutterVertex *
13319 clutter_vertex_copy (const ClutterVertex *vertex)
13320 {
13321   if (G_LIKELY (vertex != NULL))
13322     return g_slice_dup (ClutterVertex, vertex);
13323
13324   return NULL;
13325 }
13326
13327 /**
13328  * clutter_vertex_free:
13329  * @vertex: a #ClutterVertex
13330  *
13331  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13332  *
13333  * Since: 1.0
13334  */
13335 void
13336 clutter_vertex_free (ClutterVertex *vertex)
13337 {
13338   if (G_UNLIKELY (vertex != NULL))
13339     g_slice_free (ClutterVertex, vertex);
13340 }
13341
13342 /**
13343  * clutter_vertex_equal:
13344  * @vertex_a: a #ClutterVertex
13345  * @vertex_b: a #ClutterVertex
13346  *
13347  * Compares @vertex_a and @vertex_b for equality
13348  *
13349  * Return value: %TRUE if the passed #ClutterVertex are equal
13350  *
13351  * Since: 1.0
13352  */
13353 gboolean
13354 clutter_vertex_equal (const ClutterVertex *vertex_a,
13355                       const ClutterVertex *vertex_b)
13356 {
13357   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13358
13359   if (vertex_a == vertex_b)
13360     return TRUE;
13361
13362   return vertex_a->x == vertex_b->x &&
13363          vertex_a->y == vertex_b->y &&
13364          vertex_a->z == vertex_b->z;
13365 }
13366
13367 static gboolean
13368 clutter_vertex_progress (const GValue *a,
13369                          const GValue *b,
13370                          gdouble       progress,
13371                          GValue       *retval)
13372 {
13373   const ClutterVertex *av = g_value_get_boxed (a);
13374   const ClutterVertex *bv = g_value_get_boxed (b);
13375   ClutterVertex res = { 0, };
13376
13377   res.x = av->x + (bv->x - av->x) * progress;
13378   res.y = av->y + (bv->y - av->y) * progress;
13379   res.z = av->z + (bv->z - av->z) * progress;
13380
13381   g_value_set_boxed (retval, &res);
13382
13383   return TRUE;
13384 }
13385
13386 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13387                                clutter_vertex_copy,
13388                                clutter_vertex_free,
13389                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13390
13391 /**
13392  * clutter_actor_is_rotated:
13393  * @self: a #ClutterActor
13394  *
13395  * Checks whether any rotation is applied to the actor.
13396  *
13397  * Return value: %TRUE if the actor is rotated.
13398  *
13399  * Since: 0.6
13400  */
13401 gboolean
13402 clutter_actor_is_rotated (ClutterActor *self)
13403 {
13404   const ClutterTransformInfo *info;
13405
13406   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13407
13408   info = _clutter_actor_get_transform_info_or_defaults (self);
13409
13410   if (info->rx_angle || info->ry_angle || info->rz_angle)
13411     return TRUE;
13412
13413   return FALSE;
13414 }
13415
13416 /**
13417  * clutter_actor_is_scaled:
13418  * @self: a #ClutterActor
13419  *
13420  * Checks whether the actor is scaled in either dimension.
13421  *
13422  * Return value: %TRUE if the actor is scaled.
13423  *
13424  * Since: 0.6
13425  */
13426 gboolean
13427 clutter_actor_is_scaled (ClutterActor *self)
13428 {
13429   const ClutterTransformInfo *info;
13430
13431   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13432
13433   info = _clutter_actor_get_transform_info_or_defaults (self);
13434
13435   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13436     return TRUE;
13437
13438   return FALSE;
13439 }
13440
13441 ClutterActor *
13442 _clutter_actor_get_stage_internal (ClutterActor *actor)
13443 {
13444   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13445     actor = actor->priv->parent;
13446
13447   return actor;
13448 }
13449
13450 /**
13451  * clutter_actor_get_stage:
13452  * @actor: a #ClutterActor
13453  *
13454  * Retrieves the #ClutterStage where @actor is contained.
13455  *
13456  * Return value: (transfer none) (type Clutter.Stage): the stage
13457  *   containing the actor, or %NULL
13458  *
13459  * Since: 0.8
13460  */
13461 ClutterActor *
13462 clutter_actor_get_stage (ClutterActor *actor)
13463 {
13464   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13465
13466   return _clutter_actor_get_stage_internal (actor);
13467 }
13468
13469 /**
13470  * clutter_actor_allocate_available_size:
13471  * @self: a #ClutterActor
13472  * @x: the actor's X coordinate
13473  * @y: the actor's Y coordinate
13474  * @available_width: the maximum available width, or -1 to use the
13475  *   actor's natural width
13476  * @available_height: the maximum available height, or -1 to use the
13477  *   actor's natural height
13478  * @flags: flags controlling the allocation
13479  *
13480  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13481  * preferred size, but limiting it to the maximum available width
13482  * and height provided.
13483  *
13484  * This function will do the right thing when dealing with the
13485  * actor's request mode.
13486  *
13487  * The implementation of this function is equivalent to:
13488  *
13489  * |[
13490  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13491  *     {
13492  *       clutter_actor_get_preferred_width (self, available_height,
13493  *                                          &amp;min_width,
13494  *                                          &amp;natural_width);
13495  *       width = CLAMP (natural_width, min_width, available_width);
13496  *
13497  *       clutter_actor_get_preferred_height (self, width,
13498  *                                           &amp;min_height,
13499  *                                           &amp;natural_height);
13500  *       height = CLAMP (natural_height, min_height, available_height);
13501  *     }
13502  *   else
13503  *     {
13504  *       clutter_actor_get_preferred_height (self, available_width,
13505  *                                           &amp;min_height,
13506  *                                           &amp;natural_height);
13507  *       height = CLAMP (natural_height, min_height, available_height);
13508  *
13509  *       clutter_actor_get_preferred_width (self, height,
13510  *                                          &amp;min_width,
13511  *                                          &amp;natural_width);
13512  *       width = CLAMP (natural_width, min_width, available_width);
13513  *     }
13514  *
13515  *   box.x1 = x; box.y1 = y;
13516  *   box.x2 = box.x1 + available_width;
13517  *   box.y2 = box.y1 + available_height;
13518  *   clutter_actor_allocate (self, &amp;box, flags);
13519  * ]|
13520  *
13521  * This function can be used by fluid layout managers to allocate
13522  * an actor's preferred size without making it bigger than the area
13523  * available for the container.
13524  *
13525  * Since: 1.0
13526  */
13527 void
13528 clutter_actor_allocate_available_size (ClutterActor           *self,
13529                                        gfloat                  x,
13530                                        gfloat                  y,
13531                                        gfloat                  available_width,
13532                                        gfloat                  available_height,
13533                                        ClutterAllocationFlags  flags)
13534 {
13535   ClutterActorPrivate *priv;
13536   gfloat width, height;
13537   gfloat min_width, min_height;
13538   gfloat natural_width, natural_height;
13539   ClutterActorBox box;
13540
13541   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13542
13543   priv = self->priv;
13544
13545   width = height = 0.0;
13546
13547   switch (priv->request_mode)
13548     {
13549     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13550       clutter_actor_get_preferred_width (self, available_height,
13551                                          &min_width,
13552                                          &natural_width);
13553       width  = CLAMP (natural_width, min_width, available_width);
13554
13555       clutter_actor_get_preferred_height (self, width,
13556                                           &min_height,
13557                                           &natural_height);
13558       height = CLAMP (natural_height, min_height, available_height);
13559       break;
13560
13561     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13562       clutter_actor_get_preferred_height (self, available_width,
13563                                           &min_height,
13564                                           &natural_height);
13565       height = CLAMP (natural_height, min_height, available_height);
13566
13567       clutter_actor_get_preferred_width (self, height,
13568                                          &min_width,
13569                                          &natural_width);
13570       width  = CLAMP (natural_width, min_width, available_width);
13571       break;
13572     }
13573
13574
13575   box.x1 = x;
13576   box.y1 = y;
13577   box.x2 = box.x1 + width;
13578   box.y2 = box.y1 + height;
13579   clutter_actor_allocate (self, &box, flags);
13580 }
13581
13582 /**
13583  * clutter_actor_allocate_preferred_size:
13584  * @self: a #ClutterActor
13585  * @flags: flags controlling the allocation
13586  *
13587  * Allocates the natural size of @self.
13588  *
13589  * This function is a utility call for #ClutterActor implementations
13590  * that allocates the actor's preferred natural size. It can be used
13591  * by fixed layout managers (like #ClutterGroup or so called
13592  * 'composite actors') inside the ClutterActor::allocate
13593  * implementation to give each child exactly how much space it
13594  * requires.
13595  *
13596  * This function is not meant to be used by applications. It is also
13597  * not meant to be used outside the implementation of the
13598  * ClutterActor::allocate virtual function.
13599  *
13600  * Since: 0.8
13601  */
13602 void
13603 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13604                                        ClutterAllocationFlags  flags)
13605 {
13606   gfloat actor_x, actor_y;
13607   gfloat natural_width, natural_height;
13608   ClutterActorBox actor_box;
13609
13610   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13611
13612   actor_x = clutter_actor_get_x (self);
13613   actor_y = clutter_actor_get_y (self);
13614
13615   clutter_actor_get_preferred_size (self,
13616                                     NULL, NULL,
13617                                     &natural_width,
13618                                     &natural_height);
13619
13620   actor_box.x1 = actor_x;
13621   actor_box.y1 = actor_y;
13622   actor_box.x2 = actor_box.x1 + natural_width;
13623   actor_box.y2 = actor_box.y1 + natural_height;
13624
13625   clutter_actor_allocate (self, &actor_box, flags);
13626 }
13627
13628 /**
13629  * clutter_actor_allocate_align_fill:
13630  * @self: a #ClutterActor
13631  * @box: a #ClutterActorBox, containing the available width and height
13632  * @x_align: the horizontal alignment, between 0 and 1
13633  * @y_align: the vertical alignment, between 0 and 1
13634  * @x_fill: whether the actor should fill horizontally
13635  * @y_fill: whether the actor should fill vertically
13636  * @flags: allocation flags to be passed to clutter_actor_allocate()
13637  *
13638  * Allocates @self by taking into consideration the available allocation
13639  * area; an alignment factor on either axis; and whether the actor should
13640  * fill the allocation on either axis.
13641  *
13642  * The @box should contain the available allocation width and height;
13643  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13644  * allocation will be offset by their value.
13645  *
13646  * This function takes into consideration the geometry request specified by
13647  * the #ClutterActor:request-mode property, and the text direction.
13648  *
13649  * This function is useful for fluid layout managers, like #ClutterBinLayout
13650  * or #ClutterTableLayout
13651  *
13652  * Since: 1.4
13653  */
13654 void
13655 clutter_actor_allocate_align_fill (ClutterActor           *self,
13656                                    const ClutterActorBox  *box,
13657                                    gdouble                 x_align,
13658                                    gdouble                 y_align,
13659                                    gboolean                x_fill,
13660                                    gboolean                y_fill,
13661                                    ClutterAllocationFlags  flags)
13662 {
13663   ClutterActorPrivate *priv;
13664   ClutterActorBox allocation = { 0, };
13665   gfloat x_offset, y_offset;
13666   gfloat available_width, available_height;
13667   gfloat child_width, child_height;
13668
13669   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13670   g_return_if_fail (box != NULL);
13671   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13672   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13673
13674   priv = self->priv;
13675
13676   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13677   clutter_actor_box_get_size (box, &available_width, &available_height);
13678
13679   if (available_width < 0)
13680     available_width = 0;
13681
13682   if (available_height < 0)
13683     available_height = 0;
13684
13685   if (x_fill)
13686     {
13687       allocation.x1 = x_offset;
13688       allocation.x2 = allocation.x1 + available_width;
13689     }
13690
13691   if (y_fill)
13692     {
13693       allocation.y1 = y_offset;
13694       allocation.y2 = allocation.y1 + available_height;
13695     }
13696
13697   /* if we are filling horizontally and vertically then we're done */
13698   if (x_fill && y_fill)
13699     goto out;
13700
13701   child_width = child_height = 0.0f;
13702
13703   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13704     {
13705       gfloat min_width, natural_width;
13706       gfloat min_height, natural_height;
13707
13708       clutter_actor_get_preferred_width (self, available_height,
13709                                          &min_width,
13710                                          &natural_width);
13711
13712       child_width = CLAMP (natural_width, min_width, available_width);
13713
13714       if (!y_fill)
13715         {
13716           clutter_actor_get_preferred_height (self, child_width,
13717                                               &min_height,
13718                                               &natural_height);
13719
13720           child_height = CLAMP (natural_height, min_height, available_height);
13721         }
13722     }
13723   else
13724     {
13725       gfloat min_width, natural_width;
13726       gfloat min_height, natural_height;
13727
13728       clutter_actor_get_preferred_height (self, available_width,
13729                                           &min_height,
13730                                           &natural_height);
13731
13732       child_height = CLAMP (natural_height, min_height, available_height);
13733
13734       if (!x_fill)
13735         {
13736           clutter_actor_get_preferred_width (self, child_height,
13737                                              &min_width,
13738                                              &natural_width);
13739
13740           child_width = CLAMP (natural_width, min_width, available_width);
13741         }
13742     }
13743
13744   /* invert the horizontal alignment for RTL languages */
13745   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13746     x_align = 1.0 - x_align;
13747
13748   if (!x_fill)
13749     {
13750       allocation.x1 = x_offset
13751                     + ((available_width - child_width) * x_align);
13752       allocation.x2 = allocation.x1 + child_width;
13753     }
13754
13755   if (!y_fill)
13756     {
13757       allocation.y1 = y_offset
13758                     + ((available_height - child_height) * y_align);
13759       allocation.y2 = allocation.y1 + child_height;
13760     }
13761
13762 out:
13763   clutter_actor_box_clamp_to_pixel (&allocation);
13764   clutter_actor_allocate (self, &allocation, flags);
13765 }
13766
13767 /**
13768  * clutter_actor_grab_key_focus:
13769  * @self: a #ClutterActor
13770  *
13771  * Sets the key focus of the #ClutterStage including @self
13772  * to this #ClutterActor.
13773  *
13774  * Since: 1.0
13775  */
13776 void
13777 clutter_actor_grab_key_focus (ClutterActor *self)
13778 {
13779   ClutterActor *stage;
13780
13781   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13782
13783   stage = _clutter_actor_get_stage_internal (self);
13784   if (stage != NULL)
13785     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13786 }
13787
13788 /**
13789  * clutter_actor_get_pango_context:
13790  * @self: a #ClutterActor
13791  *
13792  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13793  * is already configured using the appropriate font map, resolution
13794  * and font options.
13795  *
13796  * Unlike clutter_actor_create_pango_context(), this context is owend
13797  * by the #ClutterActor and it will be updated each time the options
13798  * stored by the #ClutterBackend change.
13799  *
13800  * You can use the returned #PangoContext to create a #PangoLayout
13801  * and render text using cogl_pango_render_layout() to reuse the
13802  * glyphs cache also used by Clutter.
13803  *
13804  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13805  *   The returned #PangoContext is owned by the actor and should not be
13806  *   unreferenced by the application code
13807  *
13808  * Since: 1.0
13809  */
13810 PangoContext *
13811 clutter_actor_get_pango_context (ClutterActor *self)
13812 {
13813   ClutterActorPrivate *priv;
13814
13815   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13816
13817   priv = self->priv;
13818
13819   if (priv->pango_context != NULL)
13820     return priv->pango_context;
13821
13822   priv->pango_context = _clutter_context_get_pango_context ();
13823   g_object_ref (priv->pango_context);
13824
13825   return priv->pango_context;
13826 }
13827
13828 /**
13829  * clutter_actor_create_pango_context:
13830  * @self: a #ClutterActor
13831  *
13832  * Creates a #PangoContext for the given actor. The #PangoContext
13833  * is already configured using the appropriate font map, resolution
13834  * and font options.
13835  *
13836  * See also clutter_actor_get_pango_context().
13837  *
13838  * Return value: (transfer full): the newly created #PangoContext.
13839  *   Use g_object_unref() on the returned value to deallocate its
13840  *   resources
13841  *
13842  * Since: 1.0
13843  */
13844 PangoContext *
13845 clutter_actor_create_pango_context (ClutterActor *self)
13846 {
13847   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13848
13849   return _clutter_context_create_pango_context ();
13850 }
13851
13852 /**
13853  * clutter_actor_create_pango_layout:
13854  * @self: a #ClutterActor
13855  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13856  *
13857  * Creates a new #PangoLayout from the same #PangoContext used
13858  * by the #ClutterActor. The #PangoLayout is already configured
13859  * with the font map, resolution and font options, and the
13860  * given @text.
13861  *
13862  * If you want to keep around a #PangoLayout created by this
13863  * function you will have to connect to the #ClutterBackend::font-changed
13864  * and #ClutterBackend::resolution-changed signals, and call
13865  * pango_layout_context_changed() in response to them.
13866  *
13867  * Return value: (transfer full): the newly created #PangoLayout.
13868  *   Use g_object_unref() when done
13869  *
13870  * Since: 1.0
13871  */
13872 PangoLayout *
13873 clutter_actor_create_pango_layout (ClutterActor *self,
13874                                    const gchar  *text)
13875 {
13876   PangoContext *context;
13877   PangoLayout *layout;
13878
13879   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13880
13881   context = clutter_actor_get_pango_context (self);
13882   layout = pango_layout_new (context);
13883
13884   if (text)
13885     pango_layout_set_text (layout, text, -1);
13886
13887   return layout;
13888 }
13889
13890 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13891  * ClutterOffscreenEffect.
13892  */
13893 void
13894 _clutter_actor_set_opacity_override (ClutterActor *self,
13895                                      gint          opacity)
13896 {
13897   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13898
13899   self->priv->opacity_override = opacity;
13900 }
13901
13902 gint
13903 _clutter_actor_get_opacity_override (ClutterActor *self)
13904 {
13905   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13906
13907   return self->priv->opacity_override;
13908 }
13909
13910 /* Allows you to disable applying the actors model view transform during
13911  * a paint. Used by ClutterClone. */
13912 void
13913 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13914                                                 gboolean      enable)
13915 {
13916   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13917
13918   self->priv->enable_model_view_transform = enable;
13919 }
13920
13921 void
13922 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13923                                           gboolean      enable)
13924 {
13925   ClutterActorPrivate *priv;
13926
13927   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13928
13929   priv = self->priv;
13930
13931   priv->enable_paint_unmapped = enable;
13932
13933   if (priv->enable_paint_unmapped)
13934     {
13935       /* Make sure that the parents of the widget are realized first;
13936        * otherwise checks in clutter_actor_update_map_state() will
13937        * fail.
13938        */
13939       clutter_actor_realize (self);
13940
13941       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13942     }
13943   else
13944     {
13945       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13946     }
13947 }
13948
13949 static void
13950 clutter_anchor_coord_get_units (ClutterActor      *self,
13951                                 const AnchorCoord *coord,
13952                                 gfloat            *x,
13953                                 gfloat            *y,
13954                                 gfloat            *z)
13955 {
13956   if (coord->is_fractional)
13957     {
13958       gfloat actor_width, actor_height;
13959
13960       clutter_actor_get_size (self, &actor_width, &actor_height);
13961
13962       if (x)
13963         *x = actor_width * coord->v.fraction.x;
13964
13965       if (y)
13966         *y = actor_height * coord->v.fraction.y;
13967
13968       if (z)
13969         *z = 0;
13970     }
13971   else
13972     {
13973       if (x)
13974         *x = coord->v.units.x;
13975
13976       if (y)
13977         *y = coord->v.units.y;
13978
13979       if (z)
13980         *z = coord->v.units.z;
13981     }
13982 }
13983
13984 static void
13985 clutter_anchor_coord_set_units (AnchorCoord *coord,
13986                                 gfloat       x,
13987                                 gfloat       y,
13988                                 gfloat       z)
13989 {
13990   coord->is_fractional = FALSE;
13991   coord->v.units.x = x;
13992   coord->v.units.y = y;
13993   coord->v.units.z = z;
13994 }
13995
13996 static ClutterGravity
13997 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13998 {
13999   if (coord->is_fractional)
14000     {
14001       if (coord->v.fraction.x == 0.0)
14002         {
14003           if (coord->v.fraction.y == 0.0)
14004             return CLUTTER_GRAVITY_NORTH_WEST;
14005           else if (coord->v.fraction.y == 0.5)
14006             return CLUTTER_GRAVITY_WEST;
14007           else if (coord->v.fraction.y == 1.0)
14008             return CLUTTER_GRAVITY_SOUTH_WEST;
14009           else
14010             return CLUTTER_GRAVITY_NONE;
14011         }
14012       else if (coord->v.fraction.x == 0.5)
14013         {
14014           if (coord->v.fraction.y == 0.0)
14015             return CLUTTER_GRAVITY_NORTH;
14016           else if (coord->v.fraction.y == 0.5)
14017             return CLUTTER_GRAVITY_CENTER;
14018           else if (coord->v.fraction.y == 1.0)
14019             return CLUTTER_GRAVITY_SOUTH;
14020           else
14021             return CLUTTER_GRAVITY_NONE;
14022         }
14023       else if (coord->v.fraction.x == 1.0)
14024         {
14025           if (coord->v.fraction.y == 0.0)
14026             return CLUTTER_GRAVITY_NORTH_EAST;
14027           else if (coord->v.fraction.y == 0.5)
14028             return CLUTTER_GRAVITY_EAST;
14029           else if (coord->v.fraction.y == 1.0)
14030             return CLUTTER_GRAVITY_SOUTH_EAST;
14031           else
14032             return CLUTTER_GRAVITY_NONE;
14033         }
14034       else
14035         return CLUTTER_GRAVITY_NONE;
14036     }
14037   else
14038     return CLUTTER_GRAVITY_NONE;
14039 }
14040
14041 static void
14042 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14043                                   ClutterGravity  gravity)
14044 {
14045   switch (gravity)
14046     {
14047     case CLUTTER_GRAVITY_NORTH:
14048       coord->v.fraction.x = 0.5;
14049       coord->v.fraction.y = 0.0;
14050       break;
14051
14052     case CLUTTER_GRAVITY_NORTH_EAST:
14053       coord->v.fraction.x = 1.0;
14054       coord->v.fraction.y = 0.0;
14055       break;
14056
14057     case CLUTTER_GRAVITY_EAST:
14058       coord->v.fraction.x = 1.0;
14059       coord->v.fraction.y = 0.5;
14060       break;
14061
14062     case CLUTTER_GRAVITY_SOUTH_EAST:
14063       coord->v.fraction.x = 1.0;
14064       coord->v.fraction.y = 1.0;
14065       break;
14066
14067     case CLUTTER_GRAVITY_SOUTH:
14068       coord->v.fraction.x = 0.5;
14069       coord->v.fraction.y = 1.0;
14070       break;
14071
14072     case CLUTTER_GRAVITY_SOUTH_WEST:
14073       coord->v.fraction.x = 0.0;
14074       coord->v.fraction.y = 1.0;
14075       break;
14076
14077     case CLUTTER_GRAVITY_WEST:
14078       coord->v.fraction.x = 0.0;
14079       coord->v.fraction.y = 0.5;
14080       break;
14081
14082     case CLUTTER_GRAVITY_NORTH_WEST:
14083       coord->v.fraction.x = 0.0;
14084       coord->v.fraction.y = 0.0;
14085       break;
14086
14087     case CLUTTER_GRAVITY_CENTER:
14088       coord->v.fraction.x = 0.5;
14089       coord->v.fraction.y = 0.5;
14090       break;
14091
14092     default:
14093       coord->v.fraction.x = 0.0;
14094       coord->v.fraction.y = 0.0;
14095       break;
14096     }
14097
14098   coord->is_fractional = TRUE;
14099 }
14100
14101 static gboolean
14102 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14103 {
14104   if (coord->is_fractional)
14105     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14106   else
14107     return (coord->v.units.x == 0.0
14108             && coord->v.units.y == 0.0
14109             && coord->v.units.z == 0.0);
14110 }
14111
14112 /**
14113  * clutter_actor_get_flags:
14114  * @self: a #ClutterActor
14115  *
14116  * Retrieves the flags set on @self
14117  *
14118  * Return value: a bitwise or of #ClutterActorFlags or 0
14119  *
14120  * Since: 1.0
14121  */
14122 ClutterActorFlags
14123 clutter_actor_get_flags (ClutterActor *self)
14124 {
14125   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14126
14127   return self->flags;
14128 }
14129
14130 /**
14131  * clutter_actor_set_flags:
14132  * @self: a #ClutterActor
14133  * @flags: the flags to set
14134  *
14135  * Sets @flags on @self
14136  *
14137  * This function will emit notifications for the changed properties
14138  *
14139  * Since: 1.0
14140  */
14141 void
14142 clutter_actor_set_flags (ClutterActor      *self,
14143                          ClutterActorFlags  flags)
14144 {
14145   ClutterActorFlags old_flags;
14146   GObject *obj;
14147   gboolean was_reactive_set, reactive_set;
14148   gboolean was_realized_set, realized_set;
14149   gboolean was_mapped_set, mapped_set;
14150   gboolean was_visible_set, visible_set;
14151
14152   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14153
14154   if (self->flags == flags)
14155     return;
14156
14157   obj = G_OBJECT (self);
14158   g_object_ref (obj);
14159   g_object_freeze_notify (obj);
14160
14161   old_flags = self->flags;
14162
14163   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14164   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14165   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14166   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14167
14168   self->flags |= flags;
14169
14170   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14171   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14172   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14173   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14174
14175   if (reactive_set != was_reactive_set)
14176     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14177
14178   if (realized_set != was_realized_set)
14179     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14180
14181   if (mapped_set != was_mapped_set)
14182     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14183
14184   if (visible_set != was_visible_set)
14185     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14186
14187   g_object_thaw_notify (obj);
14188   g_object_unref (obj);
14189 }
14190
14191 /**
14192  * clutter_actor_unset_flags:
14193  * @self: a #ClutterActor
14194  * @flags: the flags to unset
14195  *
14196  * Unsets @flags on @self
14197  *
14198  * This function will emit notifications for the changed properties
14199  *
14200  * Since: 1.0
14201  */
14202 void
14203 clutter_actor_unset_flags (ClutterActor      *self,
14204                            ClutterActorFlags  flags)
14205 {
14206   ClutterActorFlags old_flags;
14207   GObject *obj;
14208   gboolean was_reactive_set, reactive_set;
14209   gboolean was_realized_set, realized_set;
14210   gboolean was_mapped_set, mapped_set;
14211   gboolean was_visible_set, visible_set;
14212
14213   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14214
14215   obj = G_OBJECT (self);
14216   g_object_freeze_notify (obj);
14217
14218   old_flags = self->flags;
14219
14220   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14221   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14222   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14223   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14224
14225   self->flags &= ~flags;
14226
14227   if (self->flags == old_flags)
14228     return;
14229
14230   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14231   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14232   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14233   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14234
14235   if (reactive_set != was_reactive_set)
14236     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14237
14238   if (realized_set != was_realized_set)
14239     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14240
14241   if (mapped_set != was_mapped_set)
14242     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14243
14244   if (visible_set != was_visible_set)
14245     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14246
14247   g_object_thaw_notify (obj);
14248 }
14249
14250 /**
14251  * clutter_actor_get_transformation_matrix:
14252  * @self: a #ClutterActor
14253  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14254  *
14255  * Retrieves the transformations applied to @self relative to its
14256  * parent.
14257  *
14258  * Since: 1.0
14259  */
14260 void
14261 clutter_actor_get_transformation_matrix (ClutterActor *self,
14262                                          CoglMatrix   *matrix)
14263 {
14264   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14265
14266   cogl_matrix_init_identity (matrix);
14267
14268   _clutter_actor_apply_modelview_transform (self, matrix);
14269 }
14270
14271 void
14272 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14273                                    gboolean      is_in_clone_paint)
14274 {
14275   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14276   self->priv->in_clone_paint = is_in_clone_paint;
14277 }
14278
14279 /**
14280  * clutter_actor_is_in_clone_paint:
14281  * @self: a #ClutterActor
14282  *
14283  * Checks whether @self is being currently painted by a #ClutterClone
14284  *
14285  * This function is useful only inside the ::paint virtual function
14286  * implementations or within handlers for the #ClutterActor::paint
14287  * signal
14288  *
14289  * This function should not be used by applications
14290  *
14291  * Return value: %TRUE if the #ClutterActor is currently being painted
14292  *   by a #ClutterClone, and %FALSE otherwise
14293  *
14294  * Since: 1.0
14295  */
14296 gboolean
14297 clutter_actor_is_in_clone_paint (ClutterActor *self)
14298 {
14299   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14300
14301   return self->priv->in_clone_paint;
14302 }
14303
14304 static gboolean
14305 set_direction_recursive (ClutterActor *actor,
14306                          gpointer      user_data)
14307 {
14308   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14309
14310   clutter_actor_set_text_direction (actor, text_dir);
14311
14312   return TRUE;
14313 }
14314
14315 /**
14316  * clutter_actor_set_text_direction:
14317  * @self: a #ClutterActor
14318  * @text_dir: the text direction for @self
14319  *
14320  * Sets the #ClutterTextDirection for an actor
14321  *
14322  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14323  *
14324  * If @self implements #ClutterContainer then this function will recurse
14325  * inside all the children of @self (including the internal ones).
14326  *
14327  * Composite actors not implementing #ClutterContainer, or actors requiring
14328  * special handling when the text direction changes, should connect to
14329  * the #GObject::notify signal for the #ClutterActor:text-direction property
14330  *
14331  * Since: 1.2
14332  */
14333 void
14334 clutter_actor_set_text_direction (ClutterActor         *self,
14335                                   ClutterTextDirection  text_dir)
14336 {
14337   ClutterActorPrivate *priv;
14338
14339   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14340   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14341
14342   priv = self->priv;
14343
14344   if (priv->text_direction != text_dir)
14345     {
14346       priv->text_direction = text_dir;
14347
14348       /* we need to emit the notify::text-direction first, so that
14349        * the sub-classes can catch that and do specific handling of
14350        * the text direction; see clutter_text_direction_changed_cb()
14351        * inside clutter-text.c
14352        */
14353       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14354
14355       _clutter_actor_foreach_child (self, set_direction_recursive,
14356                                     GINT_TO_POINTER (text_dir));
14357
14358       clutter_actor_queue_relayout (self);
14359     }
14360 }
14361
14362 void
14363 _clutter_actor_set_has_pointer (ClutterActor *self,
14364                                 gboolean      has_pointer)
14365 {
14366   ClutterActorPrivate *priv = self->priv;
14367
14368   if (priv->has_pointer != has_pointer)
14369     {
14370       priv->has_pointer = has_pointer;
14371
14372       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14373     }
14374 }
14375
14376 /**
14377  * clutter_actor_get_text_direction:
14378  * @self: a #ClutterActor
14379  *
14380  * Retrieves the value set using clutter_actor_set_text_direction()
14381  *
14382  * If no text direction has been previously set, the default text
14383  * direction, as returned by clutter_get_default_text_direction(), will
14384  * be returned instead
14385  *
14386  * Return value: the #ClutterTextDirection for the actor
14387  *
14388  * Since: 1.2
14389  */
14390 ClutterTextDirection
14391 clutter_actor_get_text_direction (ClutterActor *self)
14392 {
14393   ClutterActorPrivate *priv;
14394
14395   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14396                         CLUTTER_TEXT_DIRECTION_LTR);
14397
14398   priv = self->priv;
14399
14400   /* if no direction has been set yet use the default */
14401   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14402     priv->text_direction = clutter_get_default_text_direction ();
14403
14404   return priv->text_direction;
14405 }
14406
14407 /**
14408  * clutter_actor_push_internal:
14409  * @self: a #ClutterActor
14410  *
14411  * Should be used by actors implementing the #ClutterContainer and with
14412  * internal children added through clutter_actor_set_parent(), for instance:
14413  *
14414  * |[
14415  *   static void
14416  *   my_actor_init (MyActor *self)
14417  *   {
14418  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14419  *
14420  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14421  *
14422  *     /&ast; calling clutter_actor_set_parent() now will result in
14423  *      &ast; the internal flag being set on a child of MyActor
14424  *      &ast;/
14425  *
14426  *     /&ast; internal child - a background texture &ast;/
14427  *     self->priv->background_tex = clutter_texture_new ();
14428  *     clutter_actor_set_parent (self->priv->background_tex,
14429  *                               CLUTTER_ACTOR (self));
14430  *
14431  *     /&ast; internal child - a label &ast;/
14432  *     self->priv->label = clutter_text_new ();
14433  *     clutter_actor_set_parent (self->priv->label,
14434  *                               CLUTTER_ACTOR (self));
14435  *
14436  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14437  *
14438  *     /&ast; calling clutter_actor_set_parent() now will not result in
14439  *      &ast; the internal flag being set on a child of MyActor
14440  *      &ast;/
14441  *   }
14442  * ]|
14443  *
14444  * This function will be used by Clutter to toggle an "internal child"
14445  * flag whenever clutter_actor_set_parent() is called; internal children
14446  * are handled differently by Clutter, specifically when destroying their
14447  * parent.
14448  *
14449  * Call clutter_actor_pop_internal() when you finished adding internal
14450  * children.
14451  *
14452  * Nested calls to clutter_actor_push_internal() are allowed, but each
14453  * one must by followed by a clutter_actor_pop_internal() call.
14454  *
14455  * Since: 1.2
14456  *
14457  * Deprecated: 1.10: All children of an actor are accessible through
14458  *   the #ClutterActor API, and #ClutterActor implements the
14459  *   #ClutterContainer interface, so this function is only useful
14460  *   for legacy containers overriding the default implementation.
14461  */
14462 void
14463 clutter_actor_push_internal (ClutterActor *self)
14464 {
14465   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14466
14467   self->priv->internal_child += 1;
14468 }
14469
14470 /**
14471  * clutter_actor_pop_internal:
14472  * @self: a #ClutterActor
14473  *
14474  * Disables the effects of clutter_actor_push_internal().
14475  *
14476  * Since: 1.2
14477  *
14478  * Deprecated: 1.10: All children of an actor are accessible through
14479  *   the #ClutterActor API. This function is only useful for legacy
14480  *   containers overriding the default implementation of the
14481  *   #ClutterContainer interface.
14482  */
14483 void
14484 clutter_actor_pop_internal (ClutterActor *self)
14485 {
14486   ClutterActorPrivate *priv;
14487
14488   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14489
14490   priv = self->priv;
14491
14492   if (priv->internal_child == 0)
14493     {
14494       g_warning ("Mismatched %s: you need to call "
14495                  "clutter_actor_push_composite() at least once before "
14496                  "calling this function", G_STRFUNC);
14497       return;
14498     }
14499
14500   priv->internal_child -= 1;
14501 }
14502
14503 /**
14504  * clutter_actor_has_pointer:
14505  * @self: a #ClutterActor
14506  *
14507  * Checks whether an actor contains the pointer of a
14508  * #ClutterInputDevice
14509  *
14510  * Return value: %TRUE if the actor contains the pointer, and
14511  *   %FALSE otherwise
14512  *
14513  * Since: 1.2
14514  */
14515 gboolean
14516 clutter_actor_has_pointer (ClutterActor *self)
14517 {
14518   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14519
14520   return self->priv->has_pointer;
14521 }
14522
14523 /* XXX: This is a workaround for not being able to break the ABI of
14524  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14525  * clutter_actor_queue_clipped_redraw() for details.
14526  */
14527 ClutterPaintVolume *
14528 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14529 {
14530   return g_object_get_data (G_OBJECT (self),
14531                             "-clutter-actor-queue-redraw-clip");
14532 }
14533
14534 void
14535 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14536                                       ClutterPaintVolume *clip)
14537 {
14538   g_object_set_data (G_OBJECT (self),
14539                      "-clutter-actor-queue-redraw-clip",
14540                      clip);
14541 }
14542
14543 /**
14544  * clutter_actor_has_allocation:
14545  * @self: a #ClutterActor
14546  *
14547  * Checks if the actor has an up-to-date allocation assigned to
14548  * it. This means that the actor should have an allocation: it's
14549  * visible and has a parent. It also means that there is no
14550  * outstanding relayout request in progress for the actor or its
14551  * children (There might be other outstanding layout requests in
14552  * progress that will cause the actor to get a new allocation
14553  * when the stage is laid out, however).
14554  *
14555  * If this function returns %FALSE, then the actor will normally
14556  * be allocated before it is next drawn on the screen.
14557  *
14558  * Return value: %TRUE if the actor has an up-to-date allocation
14559  *
14560  * Since: 1.4
14561  */
14562 gboolean
14563 clutter_actor_has_allocation (ClutterActor *self)
14564 {
14565   ClutterActorPrivate *priv;
14566
14567   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14568
14569   priv = self->priv;
14570
14571   return priv->parent != NULL &&
14572          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14573          !priv->needs_allocation;
14574 }
14575
14576 /**
14577  * clutter_actor_add_action:
14578  * @self: a #ClutterActor
14579  * @action: a #ClutterAction
14580  *
14581  * Adds @action to the list of actions applied to @self
14582  *
14583  * A #ClutterAction can only belong to one actor at a time
14584  *
14585  * The #ClutterActor will hold a reference on @action until either
14586  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14587  * is called
14588  *
14589  * Since: 1.4
14590  */
14591 void
14592 clutter_actor_add_action (ClutterActor  *self,
14593                           ClutterAction *action)
14594 {
14595   ClutterActorPrivate *priv;
14596
14597   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14598   g_return_if_fail (CLUTTER_IS_ACTION (action));
14599
14600   priv = self->priv;
14601
14602   if (priv->actions == NULL)
14603     {
14604       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14605       priv->actions->actor = self;
14606     }
14607
14608   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14609
14610   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14611 }
14612
14613 /**
14614  * clutter_actor_add_action_with_name:
14615  * @self: a #ClutterActor
14616  * @name: the name to set on the action
14617  * @action: a #ClutterAction
14618  *
14619  * A convenience function for setting the name of a #ClutterAction
14620  * while adding it to the list of actions applied to @self
14621  *
14622  * This function is the logical equivalent of:
14623  *
14624  * |[
14625  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14626  *   clutter_actor_add_action (self, action);
14627  * ]|
14628  *
14629  * Since: 1.4
14630  */
14631 void
14632 clutter_actor_add_action_with_name (ClutterActor  *self,
14633                                     const gchar   *name,
14634                                     ClutterAction *action)
14635 {
14636   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14637   g_return_if_fail (name != NULL);
14638   g_return_if_fail (CLUTTER_IS_ACTION (action));
14639
14640   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14641   clutter_actor_add_action (self, action);
14642 }
14643
14644 /**
14645  * clutter_actor_remove_action:
14646  * @self: a #ClutterActor
14647  * @action: a #ClutterAction
14648  *
14649  * Removes @action from the list of actions applied to @self
14650  *
14651  * The reference held by @self on the #ClutterAction will be released
14652  *
14653  * Since: 1.4
14654  */
14655 void
14656 clutter_actor_remove_action (ClutterActor  *self,
14657                              ClutterAction *action)
14658 {
14659   ClutterActorPrivate *priv;
14660
14661   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14662   g_return_if_fail (CLUTTER_IS_ACTION (action));
14663
14664   priv = self->priv;
14665
14666   if (priv->actions == NULL)
14667     return;
14668
14669   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14670
14671   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14672 }
14673
14674 /**
14675  * clutter_actor_remove_action_by_name:
14676  * @self: a #ClutterActor
14677  * @name: the name of the action to remove
14678  *
14679  * Removes the #ClutterAction with the given name from the list
14680  * of actions applied to @self
14681  *
14682  * Since: 1.4
14683  */
14684 void
14685 clutter_actor_remove_action_by_name (ClutterActor *self,
14686                                      const gchar  *name)
14687 {
14688   ClutterActorPrivate *priv;
14689   ClutterActorMeta *meta;
14690
14691   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14692   g_return_if_fail (name != NULL);
14693
14694   priv = self->priv;
14695
14696   if (priv->actions == NULL)
14697     return;
14698
14699   meta = _clutter_meta_group_get_meta (priv->actions, name);
14700   if (meta == NULL)
14701     return;
14702
14703   _clutter_meta_group_remove_meta (priv->actions, meta);
14704
14705   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14706 }
14707
14708 /**
14709  * clutter_actor_get_actions:
14710  * @self: a #ClutterActor
14711  *
14712  * Retrieves the list of actions applied to @self
14713  *
14714  * Return value: (transfer container) (element-type Clutter.Action): a copy
14715  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14716  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14717  *   allocated by the returned #GList
14718  *
14719  * Since: 1.4
14720  */
14721 GList *
14722 clutter_actor_get_actions (ClutterActor *self)
14723 {
14724   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14725
14726   if (self->priv->actions == NULL)
14727     return NULL;
14728
14729   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14730 }
14731
14732 /**
14733  * clutter_actor_get_action:
14734  * @self: a #ClutterActor
14735  * @name: the name of the action to retrieve
14736  *
14737  * Retrieves the #ClutterAction with the given name in the list
14738  * of actions applied to @self
14739  *
14740  * Return value: (transfer none): a #ClutterAction for the given
14741  *   name, or %NULL. The returned #ClutterAction is owned by the
14742  *   actor and it should not be unreferenced directly
14743  *
14744  * Since: 1.4
14745  */
14746 ClutterAction *
14747 clutter_actor_get_action (ClutterActor *self,
14748                           const gchar  *name)
14749 {
14750   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14751   g_return_val_if_fail (name != NULL, NULL);
14752
14753   if (self->priv->actions == NULL)
14754     return NULL;
14755
14756   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14757 }
14758
14759 /**
14760  * clutter_actor_clear_actions:
14761  * @self: a #ClutterActor
14762  *
14763  * Clears the list of actions applied to @self
14764  *
14765  * Since: 1.4
14766  */
14767 void
14768 clutter_actor_clear_actions (ClutterActor *self)
14769 {
14770   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14771
14772   if (self->priv->actions == NULL)
14773     return;
14774
14775   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14776 }
14777
14778 /**
14779  * clutter_actor_add_constraint:
14780  * @self: a #ClutterActor
14781  * @constraint: a #ClutterConstraint
14782  *
14783  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14784  * to @self
14785  *
14786  * The #ClutterActor will hold a reference on the @constraint until
14787  * either clutter_actor_remove_constraint() or
14788  * clutter_actor_clear_constraints() is called.
14789  *
14790  * Since: 1.4
14791  */
14792 void
14793 clutter_actor_add_constraint (ClutterActor      *self,
14794                               ClutterConstraint *constraint)
14795 {
14796   ClutterActorPrivate *priv;
14797
14798   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14799   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14800
14801   priv = self->priv;
14802
14803   if (priv->constraints == NULL)
14804     {
14805       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14806       priv->constraints->actor = self;
14807     }
14808
14809   _clutter_meta_group_add_meta (priv->constraints,
14810                                 CLUTTER_ACTOR_META (constraint));
14811   clutter_actor_queue_relayout (self);
14812
14813   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14814 }
14815
14816 /**
14817  * clutter_actor_add_constraint_with_name:
14818  * @self: a #ClutterActor
14819  * @name: the name to set on the constraint
14820  * @constraint: a #ClutterConstraint
14821  *
14822  * A convenience function for setting the name of a #ClutterConstraint
14823  * while adding it to the list of constraints applied to @self
14824  *
14825  * This function is the logical equivalent of:
14826  *
14827  * |[
14828  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14829  *   clutter_actor_add_constraint (self, constraint);
14830  * ]|
14831  *
14832  * Since: 1.4
14833  */
14834 void
14835 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14836                                         const gchar       *name,
14837                                         ClutterConstraint *constraint)
14838 {
14839   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14840   g_return_if_fail (name != NULL);
14841   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14842
14843   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14844   clutter_actor_add_constraint (self, constraint);
14845 }
14846
14847 /**
14848  * clutter_actor_remove_constraint:
14849  * @self: a #ClutterActor
14850  * @constraint: a #ClutterConstraint
14851  *
14852  * Removes @constraint from the list of constraints applied to @self
14853  *
14854  * The reference held by @self on the #ClutterConstraint will be released
14855  *
14856  * Since: 1.4
14857  */
14858 void
14859 clutter_actor_remove_constraint (ClutterActor      *self,
14860                                  ClutterConstraint *constraint)
14861 {
14862   ClutterActorPrivate *priv;
14863
14864   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14865   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14866
14867   priv = self->priv;
14868
14869   if (priv->constraints == NULL)
14870     return;
14871
14872   _clutter_meta_group_remove_meta (priv->constraints,
14873                                    CLUTTER_ACTOR_META (constraint));
14874   clutter_actor_queue_relayout (self);
14875
14876   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14877 }
14878
14879 /**
14880  * clutter_actor_remove_constraint_by_name:
14881  * @self: a #ClutterActor
14882  * @name: the name of the constraint to remove
14883  *
14884  * Removes the #ClutterConstraint with the given name from the list
14885  * of constraints applied to @self
14886  *
14887  * Since: 1.4
14888  */
14889 void
14890 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14891                                          const gchar  *name)
14892 {
14893   ClutterActorPrivate *priv;
14894   ClutterActorMeta *meta;
14895
14896   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14897   g_return_if_fail (name != NULL);
14898
14899   priv = self->priv;
14900
14901   if (priv->constraints == NULL)
14902     return;
14903
14904   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14905   if (meta == NULL)
14906     return;
14907
14908   _clutter_meta_group_remove_meta (priv->constraints, meta);
14909   clutter_actor_queue_relayout (self);
14910 }
14911
14912 /**
14913  * clutter_actor_get_constraints:
14914  * @self: a #ClutterActor
14915  *
14916  * Retrieves the list of constraints applied to @self
14917  *
14918  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14919  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14920  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14921  *   allocated by the returned #GList
14922  *
14923  * Since: 1.4
14924  */
14925 GList *
14926 clutter_actor_get_constraints (ClutterActor *self)
14927 {
14928   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14929
14930   if (self->priv->constraints == NULL)
14931     return NULL;
14932
14933   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14934 }
14935
14936 /**
14937  * clutter_actor_get_constraint:
14938  * @self: a #ClutterActor
14939  * @name: the name of the constraint to retrieve
14940  *
14941  * Retrieves the #ClutterConstraint with the given name in the list
14942  * of constraints applied to @self
14943  *
14944  * Return value: (transfer none): a #ClutterConstraint for the given
14945  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14946  *   actor and it should not be unreferenced directly
14947  *
14948  * Since: 1.4
14949  */
14950 ClutterConstraint *
14951 clutter_actor_get_constraint (ClutterActor *self,
14952                               const gchar  *name)
14953 {
14954   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14955   g_return_val_if_fail (name != NULL, NULL);
14956
14957   if (self->priv->constraints == NULL)
14958     return NULL;
14959
14960   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14961 }
14962
14963 /**
14964  * clutter_actor_clear_constraints:
14965  * @self: a #ClutterActor
14966  *
14967  * Clears the list of constraints applied to @self
14968  *
14969  * Since: 1.4
14970  */
14971 void
14972 clutter_actor_clear_constraints (ClutterActor *self)
14973 {
14974   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14975
14976   if (self->priv->constraints == NULL)
14977     return;
14978
14979   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14980
14981   clutter_actor_queue_relayout (self);
14982 }
14983
14984 /**
14985  * clutter_actor_set_clip_to_allocation:
14986  * @self: a #ClutterActor
14987  * @clip_set: %TRUE to apply a clip tracking the allocation
14988  *
14989  * Sets whether @self should be clipped to the same size as its
14990  * allocation
14991  *
14992  * Since: 1.4
14993  */
14994 void
14995 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14996                                       gboolean      clip_set)
14997 {
14998   ClutterActorPrivate *priv;
14999
15000   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15001
15002   clip_set = !!clip_set;
15003
15004   priv = self->priv;
15005
15006   if (priv->clip_to_allocation != clip_set)
15007     {
15008       priv->clip_to_allocation = clip_set;
15009
15010       clutter_actor_queue_redraw (self);
15011
15012       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15013     }
15014 }
15015
15016 /**
15017  * clutter_actor_get_clip_to_allocation:
15018  * @self: a #ClutterActor
15019  *
15020  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15021  *
15022  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15023  *
15024  * Since: 1.4
15025  */
15026 gboolean
15027 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15028 {
15029   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15030
15031   return self->priv->clip_to_allocation;
15032 }
15033
15034 /**
15035  * clutter_actor_add_effect:
15036  * @self: a #ClutterActor
15037  * @effect: a #ClutterEffect
15038  *
15039  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15040  *
15041  * The #ClutterActor will hold a reference on the @effect until either
15042  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15043  * called.
15044  *
15045  * Since: 1.4
15046  */
15047 void
15048 clutter_actor_add_effect (ClutterActor  *self,
15049                           ClutterEffect *effect)
15050 {
15051   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15052   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15053
15054   _clutter_actor_add_effect_internal (self, effect);
15055
15056   clutter_actor_queue_redraw (self);
15057
15058   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15059 }
15060
15061 /**
15062  * clutter_actor_add_effect_with_name:
15063  * @self: a #ClutterActor
15064  * @name: the name to set on the effect
15065  * @effect: a #ClutterEffect
15066  *
15067  * A convenience function for setting the name of a #ClutterEffect
15068  * while adding it to the list of effectss applied to @self
15069  *
15070  * This function is the logical equivalent of:
15071  *
15072  * |[
15073  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15074  *   clutter_actor_add_effect (self, effect);
15075  * ]|
15076  *
15077  * Since: 1.4
15078  */
15079 void
15080 clutter_actor_add_effect_with_name (ClutterActor  *self,
15081                                     const gchar   *name,
15082                                     ClutterEffect *effect)
15083 {
15084   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15085   g_return_if_fail (name != NULL);
15086   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15087
15088   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15089   clutter_actor_add_effect (self, effect);
15090 }
15091
15092 /**
15093  * clutter_actor_remove_effect:
15094  * @self: a #ClutterActor
15095  * @effect: a #ClutterEffect
15096  *
15097  * Removes @effect from the list of effects applied to @self
15098  *
15099  * The reference held by @self on the #ClutterEffect will be released
15100  *
15101  * Since: 1.4
15102  */
15103 void
15104 clutter_actor_remove_effect (ClutterActor  *self,
15105                              ClutterEffect *effect)
15106 {
15107   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15108   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15109
15110   _clutter_actor_remove_effect_internal (self, effect);
15111
15112   clutter_actor_queue_redraw (self);
15113
15114   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15115 }
15116
15117 /**
15118  * clutter_actor_remove_effect_by_name:
15119  * @self: a #ClutterActor
15120  * @name: the name of the effect to remove
15121  *
15122  * Removes the #ClutterEffect with the given name from the list
15123  * of effects applied to @self
15124  *
15125  * Since: 1.4
15126  */
15127 void
15128 clutter_actor_remove_effect_by_name (ClutterActor *self,
15129                                      const gchar  *name)
15130 {
15131   ClutterActorPrivate *priv;
15132   ClutterActorMeta *meta;
15133
15134   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15135   g_return_if_fail (name != NULL);
15136
15137   priv = self->priv;
15138
15139   if (priv->effects == NULL)
15140     return;
15141
15142   meta = _clutter_meta_group_get_meta (priv->effects, name);
15143   if (meta == NULL)
15144     return;
15145
15146   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15147 }
15148
15149 /**
15150  * clutter_actor_get_effects:
15151  * @self: a #ClutterActor
15152  *
15153  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15154  *
15155  * Return value: (transfer container) (element-type Clutter.Effect): a list
15156  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15157  *   list are owned by Clutter and they should not be freed. You should
15158  *   free the returned list using g_list_free() when done
15159  *
15160  * Since: 1.4
15161  */
15162 GList *
15163 clutter_actor_get_effects (ClutterActor *self)
15164 {
15165   ClutterActorPrivate *priv;
15166
15167   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15168
15169   priv = self->priv;
15170
15171   if (priv->effects == NULL)
15172     return NULL;
15173
15174   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15175 }
15176
15177 /**
15178  * clutter_actor_get_effect:
15179  * @self: a #ClutterActor
15180  * @name: the name of the effect to retrieve
15181  *
15182  * Retrieves the #ClutterEffect with the given name in the list
15183  * of effects applied to @self
15184  *
15185  * Return value: (transfer none): a #ClutterEffect for the given
15186  *   name, or %NULL. The returned #ClutterEffect is owned by the
15187  *   actor and it should not be unreferenced directly
15188  *
15189  * Since: 1.4
15190  */
15191 ClutterEffect *
15192 clutter_actor_get_effect (ClutterActor *self,
15193                           const gchar  *name)
15194 {
15195   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15196   g_return_val_if_fail (name != NULL, NULL);
15197
15198   if (self->priv->effects == NULL)
15199     return NULL;
15200
15201   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15202 }
15203
15204 /**
15205  * clutter_actor_clear_effects:
15206  * @self: a #ClutterActor
15207  *
15208  * Clears the list of effects applied to @self
15209  *
15210  * Since: 1.4
15211  */
15212 void
15213 clutter_actor_clear_effects (ClutterActor *self)
15214 {
15215   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15216
15217   if (self->priv->effects == NULL)
15218     return;
15219
15220   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15221
15222   clutter_actor_queue_redraw (self);
15223 }
15224
15225 /**
15226  * clutter_actor_has_key_focus:
15227  * @self: a #ClutterActor
15228  *
15229  * Checks whether @self is the #ClutterActor that has key focus
15230  *
15231  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15232  *
15233  * Since: 1.4
15234  */
15235 gboolean
15236 clutter_actor_has_key_focus (ClutterActor *self)
15237 {
15238   ClutterActor *stage;
15239
15240   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15241
15242   stage = _clutter_actor_get_stage_internal (self);
15243   if (stage == NULL)
15244     return FALSE;
15245
15246   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15247 }
15248
15249 static gboolean
15250 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15251                                       ClutterPaintVolume *pv)
15252 {
15253   ClutterActorPrivate *priv = self->priv;
15254
15255   /* Actors are only expected to report a valid paint volume
15256    * while they have a valid allocation. */
15257   if (G_UNLIKELY (priv->needs_allocation))
15258     {
15259       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15260                     "Actor needs allocation",
15261                     _clutter_actor_get_debug_name (self));
15262       return FALSE;
15263     }
15264
15265   /* Check if there are any handlers connected to the paint
15266    * signal. If there are then all bets are off for what the paint
15267    * volume for this actor might possibly be!
15268    *
15269    * XXX: It's expected that this is going to end up being quite a
15270    * costly check to have to do here, but we haven't come up with
15271    * another solution that can reliably catch paint signal handlers at
15272    * the right time to either avoid artefacts due to invalid stage
15273    * clipping or due to incorrect culling.
15274    *
15275    * Previously we checked in clutter_actor_paint(), but at that time
15276    * we may already be using a stage clip that could be derived from
15277    * an invalid paint-volume. We used to try and handle that by
15278    * queuing a follow up, unclipped, redraw but still the previous
15279    * checking wasn't enough to catch invalid volumes involved in
15280    * culling (considering that containers may derive their volume from
15281    * children that haven't yet been painted)
15282    *
15283    * Longer term, improved solutions could be:
15284    * - Disallow painting in the paint signal, only allow using it
15285    *   for tracking when paints happen. We can add another API that
15286    *   allows monkey patching the paint of arbitrary actors but in a
15287    *   more controlled way and that also supports modifying the
15288    *   paint-volume.
15289    * - If we could be notified somehow when signal handlers are
15290    *   connected we wouldn't have to poll for handlers like this.
15291    */
15292   if (g_signal_has_handler_pending (self,
15293                                     actor_signals[PAINT],
15294                                     0,
15295                                     TRUE))
15296     {
15297       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15298                     "Actor has \"paint\" signal handlers",
15299                     _clutter_actor_get_debug_name (self));
15300       return FALSE;
15301     }
15302
15303   _clutter_paint_volume_init_static (pv, self);
15304
15305   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15306     {
15307       clutter_paint_volume_free (pv);
15308       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15309                     "Actor failed to report a volume",
15310                     _clutter_actor_get_debug_name (self));
15311       return FALSE;
15312     }
15313
15314   /* since effects can modify the paint volume, we allow them to actually
15315    * do this by making get_paint_volume() "context sensitive"
15316    */
15317   if (priv->effects != NULL)
15318     {
15319       if (priv->current_effect != NULL)
15320         {
15321           const GList *effects, *l;
15322
15323           /* if we are being called from within the paint sequence of
15324            * an actor, get the paint volume up to the current effect
15325            */
15326           effects = _clutter_meta_group_peek_metas (priv->effects);
15327           for (l = effects;
15328                l != NULL || (l != NULL && l->data != priv->current_effect);
15329                l = l->next)
15330             {
15331               if (!_clutter_effect_get_paint_volume (l->data, pv))
15332                 {
15333                   clutter_paint_volume_free (pv);
15334                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15335                                 "Effect (%s) failed to report a volume",
15336                                 _clutter_actor_get_debug_name (self),
15337                                 _clutter_actor_meta_get_debug_name (l->data));
15338                   return FALSE;
15339                 }
15340             }
15341         }
15342       else
15343         {
15344           const GList *effects, *l;
15345
15346           /* otherwise, get the cumulative volume */
15347           effects = _clutter_meta_group_peek_metas (priv->effects);
15348           for (l = effects; l != NULL; l = l->next)
15349             if (!_clutter_effect_get_paint_volume (l->data, pv))
15350               {
15351                 clutter_paint_volume_free (pv);
15352                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15353                               "Effect (%s) failed to report a volume",
15354                               _clutter_actor_get_debug_name (self),
15355                               _clutter_actor_meta_get_debug_name (l->data));
15356                 return FALSE;
15357               }
15358         }
15359     }
15360
15361   return TRUE;
15362 }
15363
15364 /* The public clutter_actor_get_paint_volume API returns a const
15365  * pointer since we return a pointer directly to the cached
15366  * PaintVolume associated with the actor and don't want the user to
15367  * inadvertently modify it, but for internal uses we sometimes need
15368  * access to the same PaintVolume but need to apply some book-keeping
15369  * modifications to it so we don't want a const pointer.
15370  */
15371 static ClutterPaintVolume *
15372 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15373 {
15374   ClutterActorPrivate *priv;
15375
15376   priv = self->priv;
15377
15378   if (priv->paint_volume_valid)
15379     clutter_paint_volume_free (&priv->paint_volume);
15380
15381   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15382     {
15383       priv->paint_volume_valid = TRUE;
15384       return &priv->paint_volume;
15385     }
15386   else
15387     {
15388       priv->paint_volume_valid = FALSE;
15389       return NULL;
15390     }
15391 }
15392
15393 /**
15394  * clutter_actor_get_paint_volume:
15395  * @self: a #ClutterActor
15396  *
15397  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15398  * when a paint volume can't be determined.
15399  *
15400  * The paint volume is defined as the 3D space occupied by an actor
15401  * when being painted.
15402  *
15403  * This function will call the <function>get_paint_volume()</function>
15404  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15405  * should not usually care about overriding the default implementation,
15406  * unless they are, for instance: painting outside their allocation, or
15407  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15408  * 3D depth).
15409  *
15410  * <note>2D actors overriding <function>get_paint_volume()</function>
15411  * ensure their volume has a depth of 0. (This will be true so long as
15412  * you don't call clutter_paint_volume_set_depth().)</note>
15413  *
15414  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15415  *   or %NULL if no volume could be determined. The returned pointer
15416  *   is not guaranteed to be valid across multiple frames; if you want
15417  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15418  *
15419  * Since: 1.6
15420  */
15421 const ClutterPaintVolume *
15422 clutter_actor_get_paint_volume (ClutterActor *self)
15423 {
15424   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15425
15426   return _clutter_actor_get_paint_volume_mutable (self);
15427 }
15428
15429 /**
15430  * clutter_actor_get_transformed_paint_volume:
15431  * @self: a #ClutterActor
15432  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15433  *    (or %NULL for the stage)
15434  *
15435  * Retrieves the 3D paint volume of an actor like
15436  * clutter_actor_get_paint_volume() does (Please refer to the
15437  * documentation of clutter_actor_get_paint_volume() for more
15438  * details.) and it additionally transforms the paint volume into the
15439  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15440  * is passed for @relative_to_ancestor)
15441  *
15442  * This can be used by containers that base their paint volume on
15443  * the volume of their children. Such containers can query the
15444  * transformed paint volume of all of its children and union them
15445  * together using clutter_paint_volume_union().
15446  *
15447  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15448  *   or %NULL if no volume could be determined. The returned pointer is
15449  *   not guaranteed to be valid across multiple frames; if you wish to
15450  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15451  *
15452  * Since: 1.6
15453  */
15454 const ClutterPaintVolume *
15455 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15456                                             ClutterActor *relative_to_ancestor)
15457 {
15458   const ClutterPaintVolume *volume;
15459   ClutterActor *stage;
15460   ClutterPaintVolume *transformed_volume;
15461
15462   stage = _clutter_actor_get_stage_internal (self);
15463   if (G_UNLIKELY (stage == NULL))
15464     return NULL;
15465
15466   if (relative_to_ancestor == NULL)
15467     relative_to_ancestor = stage;
15468
15469   volume = clutter_actor_get_paint_volume (self);
15470   if (volume == NULL)
15471     return NULL;
15472
15473   transformed_volume =
15474     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15475
15476   _clutter_paint_volume_copy_static (volume, transformed_volume);
15477
15478   _clutter_paint_volume_transform_relative (transformed_volume,
15479                                             relative_to_ancestor);
15480
15481   return transformed_volume;
15482 }
15483
15484 /**
15485  * clutter_actor_get_paint_box:
15486  * @self: a #ClutterActor
15487  * @box: (out): return location for a #ClutterActorBox
15488  *
15489  * Retrieves the paint volume of the passed #ClutterActor, and
15490  * transforms it into a 2D bounding box in stage coordinates.
15491  *
15492  * This function is useful to determine the on screen area occupied by
15493  * the actor. The box is only an approximation and may often be
15494  * considerably larger due to the optimizations used to calculate the
15495  * box. The box is never smaller though, so it can reliably be used
15496  * for culling.
15497  *
15498  * There are times when a 2D paint box can't be determined, e.g.
15499  * because the actor isn't yet parented under a stage or because
15500  * the actor is unable to determine a paint volume.
15501  *
15502  * Return value: %TRUE if a 2D paint box could be determined, else
15503  * %FALSE.
15504  *
15505  * Since: 1.6
15506  */
15507 gboolean
15508 clutter_actor_get_paint_box (ClutterActor    *self,
15509                              ClutterActorBox *box)
15510 {
15511   ClutterActor *stage;
15512   ClutterPaintVolume *pv;
15513
15514   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15515   g_return_val_if_fail (box != NULL, FALSE);
15516
15517   stage = _clutter_actor_get_stage_internal (self);
15518   if (G_UNLIKELY (!stage))
15519     return FALSE;
15520
15521   pv = _clutter_actor_get_paint_volume_mutable (self);
15522   if (G_UNLIKELY (!pv))
15523     return FALSE;
15524
15525   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15526
15527   return TRUE;
15528 }
15529
15530 /**
15531  * clutter_actor_has_overlaps:
15532  * @self: A #ClutterActor
15533  *
15534  * Asks the actor's implementation whether it may contain overlapping
15535  * primitives.
15536  *
15537  * For example; Clutter may use this to determine whether the painting
15538  * should be redirected to an offscreen buffer to correctly implement
15539  * the opacity property.
15540  *
15541  * Custom actors can override the default response by implementing the
15542  * #ClutterActor <function>has_overlaps</function> virtual function. See
15543  * clutter_actor_set_offscreen_redirect() for more information.
15544  *
15545  * Return value: %TRUE if the actor may have overlapping primitives, and
15546  *   %FALSE otherwise
15547  *
15548  * Since: 1.8
15549  */
15550 gboolean
15551 clutter_actor_has_overlaps (ClutterActor *self)
15552 {
15553   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15554
15555   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15556 }
15557
15558 /**
15559  * clutter_actor_has_effects:
15560  * @self: A #ClutterActor
15561  *
15562  * Returns whether the actor has any effects applied.
15563  *
15564  * Return value: %TRUE if the actor has any effects,
15565  *   %FALSE otherwise
15566  *
15567  * Since: 1.10
15568  */
15569 gboolean
15570 clutter_actor_has_effects (ClutterActor *self)
15571 {
15572   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15573
15574   if (self->priv->effects == NULL)
15575     return FALSE;
15576
15577   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15578 }
15579
15580 /**
15581  * clutter_actor_has_constraints:
15582  * @self: A #ClutterActor
15583  *
15584  * Returns whether the actor has any constraints applied.
15585  *
15586  * Return value: %TRUE if the actor has any constraints,
15587  *   %FALSE otherwise
15588  *
15589  * Since: 1.10
15590  */
15591 gboolean
15592 clutter_actor_has_constraints (ClutterActor *self)
15593 {
15594   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15595
15596   return self->priv->constraints != NULL;
15597 }
15598
15599 /**
15600  * clutter_actor_has_actions:
15601  * @self: A #ClutterActor
15602  *
15603  * Returns whether the actor has any actions applied.
15604  *
15605  * Return value: %TRUE if the actor has any actions,
15606  *   %FALSE otherwise
15607  *
15608  * Since: 1.10
15609  */
15610 gboolean
15611 clutter_actor_has_actions (ClutterActor *self)
15612 {
15613   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15614
15615   return self->priv->actions != NULL;
15616 }
15617
15618 /**
15619  * clutter_actor_get_n_children:
15620  * @self: a #ClutterActor
15621  *
15622  * Retrieves the number of children of @self.
15623  *
15624  * Return value: the number of children of an actor
15625  *
15626  * Since: 1.10
15627  */
15628 gint
15629 clutter_actor_get_n_children (ClutterActor *self)
15630 {
15631   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15632
15633   return self->priv->n_children;
15634 }
15635
15636 /**
15637  * clutter_actor_get_child_at_index:
15638  * @self: a #ClutterActor
15639  * @index_: the position in the list of children
15640  *
15641  * Retrieves the actor at the given @index_ inside the list of
15642  * children of @self.
15643  *
15644  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15645  *
15646  * Since: 1.10
15647  */
15648 ClutterActor *
15649 clutter_actor_get_child_at_index (ClutterActor *self,
15650                                   gint          index_)
15651 {
15652   ClutterActor *iter;
15653   int i;
15654
15655   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15656   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15657
15658   for (iter = self->priv->first_child, i = 0;
15659        iter != NULL && i < index_;
15660        iter = iter->priv->next_sibling, i += 1)
15661     ;
15662
15663   return iter;
15664 }
15665
15666 /*< private >
15667  * _clutter_actor_foreach_child:
15668  * @actor: The actor whos children you want to iterate
15669  * @callback: The function to call for each child
15670  * @user_data: Private data to pass to @callback
15671  *
15672  * Calls a given @callback once for each child of the specified @actor and
15673  * passing the @user_data pointer each time.
15674  *
15675  * Return value: returns %TRUE if all children were iterated, else
15676  *    %FALSE if a callback broke out of iteration early.
15677  */
15678 gboolean
15679 _clutter_actor_foreach_child (ClutterActor           *self,
15680                               ClutterForeachCallback  callback,
15681                               gpointer                user_data)
15682 {
15683   ClutterActorPrivate *priv = self->priv;
15684   ClutterActor *iter;
15685   gboolean cont;
15686
15687   for (cont = TRUE, iter = priv->first_child;
15688        cont && iter != NULL;
15689        iter = iter->priv->next_sibling)
15690     {
15691       cont = callback (iter, user_data);
15692     }
15693
15694   return cont;
15695 }
15696
15697 #if 0
15698 /* For debugging purposes this gives us a simple way to print out
15699  * the scenegraph e.g in gdb using:
15700  * [|
15701  *   _clutter_actor_traverse (stage,
15702  *                            0,
15703  *                            clutter_debug_print_actor_cb,
15704  *                            NULL,
15705  *                            NULL);
15706  * |]
15707  */
15708 static ClutterActorTraverseVisitFlags
15709 clutter_debug_print_actor_cb (ClutterActor *actor,
15710                               int depth,
15711                               void *user_data)
15712 {
15713   g_print ("%*s%s:%p\n",
15714            depth * 2, "",
15715            _clutter_actor_get_debug_name (actor),
15716            actor);
15717
15718   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15719 }
15720 #endif
15721
15722 static void
15723 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15724                                  ClutterTraverseCallback callback,
15725                                  gpointer                user_data)
15726 {
15727   GQueue *queue = g_queue_new ();
15728   ClutterActor dummy;
15729   int current_depth = 0;
15730
15731   g_queue_push_tail (queue, actor);
15732   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15733
15734   while ((actor = g_queue_pop_head (queue)))
15735     {
15736       ClutterActorTraverseVisitFlags flags;
15737
15738       if (actor == &dummy)
15739         {
15740           current_depth++;
15741           g_queue_push_tail (queue, &dummy);
15742           continue;
15743         }
15744
15745       flags = callback (actor, current_depth, user_data);
15746       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15747         break;
15748       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15749         {
15750           ClutterActor *iter;
15751
15752           for (iter = actor->priv->first_child;
15753                iter != NULL;
15754                iter = iter->priv->next_sibling)
15755             {
15756               g_queue_push_tail (queue, iter);
15757             }
15758         }
15759     }
15760
15761   g_queue_free (queue);
15762 }
15763
15764 static ClutterActorTraverseVisitFlags
15765 _clutter_actor_traverse_depth (ClutterActor           *actor,
15766                                ClutterTraverseCallback before_children_callback,
15767                                ClutterTraverseCallback after_children_callback,
15768                                int                     current_depth,
15769                                gpointer                user_data)
15770 {
15771   ClutterActorTraverseVisitFlags flags;
15772
15773   flags = before_children_callback (actor, current_depth, user_data);
15774   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15775     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15776
15777   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15778     {
15779       ClutterActor *iter;
15780
15781       for (iter = actor->priv->first_child;
15782            iter != NULL;
15783            iter = iter->priv->next_sibling)
15784         {
15785           flags = _clutter_actor_traverse_depth (iter,
15786                                                  before_children_callback,
15787                                                  after_children_callback,
15788                                                  current_depth + 1,
15789                                                  user_data);
15790
15791           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15792             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15793         }
15794     }
15795
15796   if (after_children_callback)
15797     return after_children_callback (actor, current_depth, user_data);
15798   else
15799     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15800 }
15801
15802 /* _clutter_actor_traverse:
15803  * @actor: The actor to start traversing the graph from
15804  * @flags: These flags may affect how the traversal is done
15805  * @before_children_callback: A function to call before visiting the
15806  *   children of the current actor.
15807  * @after_children_callback: A function to call after visiting the
15808  *   children of the current actor. (Ignored if
15809  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15810  * @user_data: The private data to pass to the callbacks
15811  *
15812  * Traverses the scenegraph starting at the specified @actor and
15813  * descending through all its children and its children's children.
15814  * For each actor traversed @before_children_callback and
15815  * @after_children_callback are called with the specified
15816  * @user_data, before and after visiting that actor's children.
15817  *
15818  * The callbacks can return flags that affect the ongoing traversal
15819  * such as by skipping over an actors children or bailing out of
15820  * any further traversing.
15821  */
15822 void
15823 _clutter_actor_traverse (ClutterActor              *actor,
15824                          ClutterActorTraverseFlags  flags,
15825                          ClutterTraverseCallback    before_children_callback,
15826                          ClutterTraverseCallback    after_children_callback,
15827                          gpointer                   user_data)
15828 {
15829   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15830     _clutter_actor_traverse_breadth (actor,
15831                                      before_children_callback,
15832                                      user_data);
15833   else /* DEPTH_FIRST */
15834     _clutter_actor_traverse_depth (actor,
15835                                    before_children_callback,
15836                                    after_children_callback,
15837                                    0, /* start depth */
15838                                    user_data);
15839 }
15840
15841 static void
15842 on_layout_manager_changed (ClutterLayoutManager *manager,
15843                            ClutterActor         *self)
15844 {
15845   clutter_actor_queue_relayout (self);
15846 }
15847
15848 /**
15849  * clutter_actor_set_layout_manager:
15850  * @self: a #ClutterActor
15851  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15852  *
15853  * Sets the #ClutterLayoutManager delegate object that will be used to
15854  * lay out the children of @self.
15855  *
15856  * The #ClutterActor will take a reference on the passed @manager which
15857  * will be released either when the layout manager is removed, or when
15858  * the actor is destroyed.
15859  *
15860  * Since: 1.10
15861  */
15862 void
15863 clutter_actor_set_layout_manager (ClutterActor         *self,
15864                                   ClutterLayoutManager *manager)
15865 {
15866   ClutterActorPrivate *priv;
15867
15868   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15869   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15870
15871   priv = self->priv;
15872
15873   if (priv->layout_manager != NULL)
15874     {
15875       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15876                                             G_CALLBACK (on_layout_manager_changed),
15877                                             self);
15878       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15879       g_object_unref (priv->layout_manager);
15880     }
15881
15882   priv->layout_manager = manager;
15883
15884   if (priv->layout_manager != NULL)
15885     {
15886       g_object_ref_sink (priv->layout_manager);
15887       clutter_layout_manager_set_container (priv->layout_manager,
15888                                             CLUTTER_CONTAINER (self));
15889       g_signal_connect (priv->layout_manager, "layout-changed",
15890                         G_CALLBACK (on_layout_manager_changed),
15891                         self);
15892     }
15893
15894   clutter_actor_queue_relayout (self);
15895
15896   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15897 }
15898
15899 /**
15900  * clutter_actor_get_layout_manager:
15901  * @self: a #ClutterActor
15902  *
15903  * Retrieves the #ClutterLayoutManager used by @self.
15904  *
15905  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15906  *   or %NULL
15907  *
15908  * Since: 1.10
15909  */
15910 ClutterLayoutManager *
15911 clutter_actor_get_layout_manager (ClutterActor *self)
15912 {
15913   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15914
15915   return self->priv->layout_manager;
15916 }
15917
15918 static const ClutterLayoutInfo default_layout_info = {
15919   0.f,                          /* fixed-x */
15920   0.f,                          /* fixed-y */
15921   { 0, 0, 0, 0 },               /* margin */
15922   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15923   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15924   0.f, 0.f,                     /* min_width, natural_width */
15925   0.f, 0.f,                     /* natual_width, natural_height */
15926 };
15927
15928 static void
15929 layout_info_free (gpointer data)
15930 {
15931   if (G_LIKELY (data != NULL))
15932     g_slice_free (ClutterLayoutInfo, data);
15933 }
15934
15935 /*< private >
15936  * _clutter_actor_get_layout_info:
15937  * @self: a #ClutterActor
15938  *
15939  * Retrieves a pointer to the ClutterLayoutInfo structure.
15940  *
15941  * If the actor does not have a ClutterLayoutInfo associated to it, one
15942  * will be created and initialized to the default values.
15943  *
15944  * This function should be used for setters.
15945  *
15946  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15947  * instead.
15948  *
15949  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15950  */
15951 ClutterLayoutInfo *
15952 _clutter_actor_get_layout_info (ClutterActor *self)
15953 {
15954   ClutterLayoutInfo *retval;
15955
15956   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15957   if (retval == NULL)
15958     {
15959       retval = g_slice_new (ClutterLayoutInfo);
15960
15961       *retval = default_layout_info;
15962
15963       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15964                                retval,
15965                                layout_info_free);
15966     }
15967
15968   return retval;
15969 }
15970
15971 /*< private >
15972  * _clutter_actor_get_layout_info_or_defaults:
15973  * @self: a #ClutterActor
15974  *
15975  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15976  *
15977  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15978  * then the default structure will be returned.
15979  *
15980  * This function should only be used for getters.
15981  *
15982  * Return value: a const pointer to the ClutterLayoutInfo structure
15983  */
15984 const ClutterLayoutInfo *
15985 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15986 {
15987   const ClutterLayoutInfo *info;
15988
15989   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15990   if (info == NULL)
15991     return &default_layout_info;
15992
15993   return info;
15994 }
15995
15996 /**
15997  * clutter_actor_set_x_align:
15998  * @self: a #ClutterActor
15999  * @x_align: the horizontal alignment policy
16000  *
16001  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16002  * actor received extra horizontal space.
16003  *
16004  * See also the #ClutterActor:x-align property.
16005  *
16006  * Since: 1.10
16007  */
16008 void
16009 clutter_actor_set_x_align (ClutterActor      *self,
16010                            ClutterActorAlign  x_align)
16011 {
16012   ClutterLayoutInfo *info;
16013
16014   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16015
16016   info = _clutter_actor_get_layout_info (self);
16017
16018   if (info->x_align != x_align)
16019     {
16020       info->x_align = x_align;
16021
16022       clutter_actor_queue_relayout (self);
16023
16024       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16025     }
16026 }
16027
16028 /**
16029  * clutter_actor_get_x_align:
16030  * @self: a #ClutterActor
16031  *
16032  * Retrieves the horizontal alignment policy set using
16033  * clutter_actor_set_x_align().
16034  *
16035  * Return value: the horizontal alignment policy.
16036  *
16037  * Since: 1.10
16038  */
16039 ClutterActorAlign
16040 clutter_actor_get_x_align (ClutterActor *self)
16041 {
16042   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16043
16044   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16045 }
16046
16047 /**
16048  * clutter_actor_set_y_align:
16049  * @self: a #ClutterActor
16050  * @y_align: the vertical alignment policy
16051  *
16052  * Sets the vertical alignment policy of a #ClutterActor, in case the
16053  * actor received extra vertical space.
16054  *
16055  * See also the #ClutterActor:y-align property.
16056  *
16057  * Since: 1.10
16058  */
16059 void
16060 clutter_actor_set_y_align (ClutterActor      *self,
16061                            ClutterActorAlign  y_align)
16062 {
16063   ClutterLayoutInfo *info;
16064
16065   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16066
16067   info = _clutter_actor_get_layout_info (self);
16068
16069   if (info->y_align != y_align)
16070     {
16071       info->y_align = y_align;
16072
16073       clutter_actor_queue_relayout (self);
16074
16075       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16076     }
16077 }
16078
16079 /**
16080  * clutter_actor_get_y_align:
16081  * @self: a #ClutterActor
16082  *
16083  * Retrieves the vertical alignment policy set using
16084  * clutter_actor_set_y_align().
16085  *
16086  * Return value: the vertical alignment policy.
16087  *
16088  * Since: 1.10
16089  */
16090 ClutterActorAlign
16091 clutter_actor_get_y_align (ClutterActor *self)
16092 {
16093   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16094
16095   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16096 }
16097
16098
16099 /**
16100  * clutter_margin_new:
16101  *
16102  * Creates a new #ClutterMargin.
16103  *
16104  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16105  *   clutter_margin_free() to free the resources associated with it when
16106  *   done.
16107  *
16108  * Since: 1.10
16109  */
16110 ClutterMargin *
16111 clutter_margin_new (void)
16112 {
16113   return g_slice_new0 (ClutterMargin);
16114 }
16115
16116 /**
16117  * clutter_margin_copy:
16118  * @margin_: a #ClutterMargin
16119  *
16120  * Creates a new #ClutterMargin and copies the contents of @margin_ into
16121  * the newly created structure.
16122  *
16123  * Return value: (transfer full): a copy of the #ClutterMargin.
16124  *
16125  * Since: 1.10
16126  */
16127 ClutterMargin *
16128 clutter_margin_copy (const ClutterMargin *margin_)
16129 {
16130   if (G_LIKELY (margin_ != NULL))
16131     return g_slice_dup (ClutterMargin, margin_);
16132
16133   return NULL;
16134 }
16135
16136 /**
16137  * clutter_margin_free:
16138  * @margin_: a #ClutterMargin
16139  *
16140  * Frees the resources allocated by clutter_margin_new() and
16141  * clutter_margin_copy().
16142  *
16143  * Since: 1.10
16144  */
16145 void
16146 clutter_margin_free (ClutterMargin *margin_)
16147 {
16148   if (G_LIKELY (margin_ != NULL))
16149     g_slice_free (ClutterMargin, margin_);
16150 }
16151
16152 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16153                      clutter_margin_copy,
16154                      clutter_margin_free)
16155
16156 /**
16157  * clutter_actor_set_margin:
16158  * @self: a #ClutterActor
16159  * @margin: a #ClutterMargin
16160  *
16161  * Sets all the components of the margin of a #ClutterActor.
16162  *
16163  * Since: 1.10
16164  */
16165 void
16166 clutter_actor_set_margin (ClutterActor        *self,
16167                           const ClutterMargin *margin)
16168 {
16169   ClutterLayoutInfo *info;
16170   gboolean changed;
16171   GObject *obj;
16172
16173   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16174   g_return_if_fail (margin != NULL);
16175
16176   obj = G_OBJECT (self);
16177   changed = FALSE;
16178
16179   g_object_freeze_notify (obj);
16180
16181   info = _clutter_actor_get_layout_info (self);
16182
16183   if (info->margin.top != margin->top)
16184     {
16185       info->margin.top = margin->top;
16186       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16187       changed = TRUE;
16188     }
16189
16190   if (info->margin.right != margin->right)
16191     {
16192       info->margin.right = margin->right;
16193       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16194       changed = TRUE;
16195     }
16196
16197   if (info->margin.bottom != margin->bottom)
16198     {
16199       info->margin.bottom = margin->bottom;
16200       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16201       changed = TRUE;
16202     }
16203
16204   if (info->margin.left != margin->left)
16205     {
16206       info->margin.left = margin->left;
16207       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16208       changed = TRUE;
16209     }
16210
16211   if (changed)
16212     clutter_actor_queue_relayout (self);
16213
16214   g_object_thaw_notify (obj);
16215 }
16216
16217 /**
16218  * clutter_actor_get_margin:
16219  * @self: a #ClutterActor
16220  * @margin: (out caller-allocates): return location for a #ClutterMargin
16221  *
16222  * Retrieves all the components of the margin of a #ClutterActor.
16223  *
16224  * Since: 1.10
16225  */
16226 void
16227 clutter_actor_get_margin (ClutterActor  *self,
16228                           ClutterMargin *margin)
16229 {
16230   const ClutterLayoutInfo *info;
16231
16232   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16233   g_return_if_fail (margin != NULL);
16234
16235   info = _clutter_actor_get_layout_info_or_defaults (self);
16236
16237   *margin = info->margin;
16238 }
16239
16240 /**
16241  * clutter_actor_set_margin_top:
16242  * @self: a #ClutterActor
16243  * @margin: the top margin
16244  *
16245  * Sets the margin from the top of a #ClutterActor.
16246  *
16247  * Since: 1.10
16248  */
16249 void
16250 clutter_actor_set_margin_top (ClutterActor *self,
16251                               gfloat        margin)
16252 {
16253   ClutterLayoutInfo *info;
16254
16255   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16256   g_return_if_fail (margin >= 0.f);
16257
16258   info = _clutter_actor_get_layout_info (self);
16259
16260   if (info->margin.top == margin)
16261     return;
16262
16263   info->margin.top = margin;
16264
16265   clutter_actor_queue_relayout (self);
16266
16267   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16268 }
16269
16270 /**
16271  * clutter_actor_get_margin_top:
16272  * @self: a #ClutterActor
16273  *
16274  * Retrieves the top margin of a #ClutterActor.
16275  *
16276  * Return value: the top margin
16277  *
16278  * Since: 1.10
16279  */
16280 gfloat
16281 clutter_actor_get_margin_top (ClutterActor *self)
16282 {
16283   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16284
16285   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16286 }
16287
16288 /**
16289  * clutter_actor_set_margin_bottom:
16290  * @self: a #ClutterActor
16291  * @margin: the bottom margin
16292  *
16293  * Sets the margin from the bottom of a #ClutterActor.
16294  *
16295  * Since: 1.10
16296  */
16297 void
16298 clutter_actor_set_margin_bottom (ClutterActor *self,
16299                                  gfloat        margin)
16300 {
16301   ClutterLayoutInfo *info;
16302
16303   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16304   g_return_if_fail (margin >= 0.f);
16305
16306   info = _clutter_actor_get_layout_info (self);
16307
16308   if (info->margin.bottom == margin)
16309     return;
16310
16311   info->margin.bottom = margin;
16312
16313   clutter_actor_queue_relayout (self);
16314
16315   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16316 }
16317
16318 /**
16319  * clutter_actor_get_margin_bottom:
16320  * @self: a #ClutterActor
16321  *
16322  * Retrieves the bottom margin of a #ClutterActor.
16323  *
16324  * Return value: the bottom margin
16325  *
16326  * Since: 1.10
16327  */
16328 gfloat
16329 clutter_actor_get_margin_bottom (ClutterActor *self)
16330 {
16331   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16332
16333   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16334 }
16335
16336 /**
16337  * clutter_actor_set_margin_left:
16338  * @self: a #ClutterActor
16339  * @margin: the left margin
16340  *
16341  * Sets the margin from the left of a #ClutterActor.
16342  *
16343  * Since: 1.10
16344  */
16345 void
16346 clutter_actor_set_margin_left (ClutterActor *self,
16347                                gfloat        margin)
16348 {
16349   ClutterLayoutInfo *info;
16350
16351   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16352   g_return_if_fail (margin >= 0.f);
16353
16354   info = _clutter_actor_get_layout_info (self);
16355
16356   if (info->margin.left == margin)
16357     return;
16358
16359   info->margin.left = margin;
16360
16361   clutter_actor_queue_relayout (self);
16362
16363   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16364 }
16365
16366 /**
16367  * clutter_actor_get_margin_left:
16368  * @self: a #ClutterActor
16369  *
16370  * Retrieves the left margin of a #ClutterActor.
16371  *
16372  * Return value: the left margin
16373  *
16374  * Since: 1.10
16375  */
16376 gfloat
16377 clutter_actor_get_margin_left (ClutterActor *self)
16378 {
16379   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16380
16381   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16382 }
16383
16384 /**
16385  * clutter_actor_set_margin_right:
16386  * @self: a #ClutterActor
16387  * @margin: the right margin
16388  *
16389  * Sets the margin from the right of a #ClutterActor.
16390  *
16391  * Since: 1.10
16392  */
16393 void
16394 clutter_actor_set_margin_right (ClutterActor *self,
16395                                 gfloat        margin)
16396 {
16397   ClutterLayoutInfo *info;
16398
16399   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16400   g_return_if_fail (margin >= 0.f);
16401
16402   info = _clutter_actor_get_layout_info (self);
16403
16404   if (info->margin.right == margin)
16405     return;
16406
16407   info->margin.right = margin;
16408
16409   clutter_actor_queue_relayout (self);
16410
16411   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16412 }
16413
16414 /**
16415  * clutter_actor_get_margin_right:
16416  * @self: a #ClutterActor
16417  *
16418  * Retrieves the right margin of a #ClutterActor.
16419  *
16420  * Return value: the right margin
16421  *
16422  * Since: 1.10
16423  */
16424 gfloat
16425 clutter_actor_get_margin_right (ClutterActor *self)
16426 {
16427   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16428
16429   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16430 }
16431
16432 static inline void
16433 clutter_actor_set_background_color_internal (ClutterActor *self,
16434                                              const ClutterColor *color)
16435 {
16436   ClutterActorPrivate *priv = self->priv;
16437   GObject *obj;
16438
16439   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16440     return;
16441
16442   obj = G_OBJECT (self);
16443
16444   priv->bg_color = *color;
16445   priv->bg_color_set = TRUE;
16446
16447   clutter_actor_queue_redraw (self);
16448
16449   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16450   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16451 }
16452
16453 /**
16454  * clutter_actor_set_background_color:
16455  * @self: a #ClutterActor
16456  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16457  *  set color
16458  *
16459  * Sets the background color of a #ClutterActor.
16460  *
16461  * The background color will be used to cover the whole allocation of the
16462  * actor. The default background color of an actor is transparent.
16463  *
16464  * To check whether an actor has a background color, you can use the
16465  * #ClutterActor:background-color-set actor property.
16466  *
16467  * The #ClutterActor:background-color property is animatable.
16468  *
16469  * Since: 1.10
16470  */
16471 void
16472 clutter_actor_set_background_color (ClutterActor       *self,
16473                                     const ClutterColor *color)
16474 {
16475   ClutterActorPrivate *priv;
16476   GObject *obj;
16477   GParamSpec *bg_color_pspec;
16478
16479   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16480
16481   obj = G_OBJECT (self);
16482
16483   priv = self->priv;
16484
16485   if (color == NULL)
16486     {
16487       priv->bg_color_set = FALSE;
16488       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16489       clutter_actor_queue_redraw (self);
16490       return;
16491     }
16492
16493   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16494   if (clutter_actor_get_easing_duration (self) != 0)
16495     {
16496       ClutterTransition *transition;
16497
16498       transition = _clutter_actor_get_transition (self, bg_color_pspec);
16499       if (transition == NULL)
16500         {
16501           transition = _clutter_actor_create_transition (self, bg_color_pspec,
16502                                                          &priv->bg_color,
16503                                                          color);
16504           clutter_timeline_start (CLUTTER_TIMELINE (transition));
16505         }
16506       else
16507         _clutter_actor_update_transition (self, bg_color_pspec, color);
16508
16509       clutter_actor_queue_redraw (self);
16510     }
16511   else
16512     clutter_actor_set_background_color_internal (self, color);
16513 }
16514
16515 /**
16516  * clutter_actor_get_background_color:
16517  * @self: a #ClutterActor
16518  * @color: (out caller-allocates): return location for a #ClutterColor
16519  *
16520  * Retrieves the color set using clutter_actor_set_background_color().
16521  *
16522  * Since: 1.10
16523  */
16524 void
16525 clutter_actor_get_background_color (ClutterActor *self,
16526                                     ClutterColor *color)
16527 {
16528   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16529   g_return_if_fail (color != NULL);
16530
16531   *color = self->priv->bg_color;
16532 }
16533
16534 /**
16535  * clutter_actor_get_previous_sibling:
16536  * @self: a #ClutterActor
16537  *
16538  * Retrieves the sibling of @self that comes before it in the list
16539  * of children of @self's parent.
16540  *
16541  * The returned pointer is only valid until the scene graph changes; it
16542  * is not safe to modify the list of children of @self while iterating
16543  * it.
16544  *
16545  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16546  *
16547  * Since: 1.10
16548  */
16549 ClutterActor *
16550 clutter_actor_get_previous_sibling (ClutterActor *self)
16551 {
16552   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16553
16554   return self->priv->prev_sibling;
16555 }
16556
16557 /**
16558  * clutter_actor_get_next_sibling:
16559  * @self: a #ClutterActor
16560  *
16561  * Retrieves the sibling of @self that comes after it in the list
16562  * of children of @self's parent.
16563  *
16564  * The returned pointer is only valid until the scene graph changes; it
16565  * is not safe to modify the list of children of @self while iterating
16566  * it.
16567  *
16568  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16569  *
16570  * Since: 1.10
16571  */
16572 ClutterActor *
16573 clutter_actor_get_next_sibling (ClutterActor *self)
16574 {
16575   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16576
16577   return self->priv->next_sibling;
16578 }
16579
16580 /**
16581  * clutter_actor_get_first_child:
16582  * @self: a #ClutterActor
16583  *
16584  * Retrieves the first child of @self.
16585  *
16586  * The returned pointer is only valid until the scene graph changes; it
16587  * is not safe to modify the list of children of @self while iterating
16588  * it.
16589  *
16590  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16591  *
16592  * Since: 1.10
16593  */
16594 ClutterActor *
16595 clutter_actor_get_first_child (ClutterActor *self)
16596 {
16597   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16598
16599   return self->priv->first_child;
16600 }
16601
16602 /**
16603  * clutter_actor_get_last_child:
16604  * @self: a #ClutterActor
16605  *
16606  * Retrieves the last child of @self.
16607  *
16608  * The returned pointer is only valid until the scene graph changes; it
16609  * is not safe to modify the list of children of @self while iterating
16610  * it.
16611  *
16612  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16613  *
16614  * Since: 1.10
16615  */
16616 ClutterActor *
16617 clutter_actor_get_last_child (ClutterActor *self)
16618 {
16619   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16620
16621   return self->priv->last_child;
16622 }
16623
16624 /* easy way to have properly named fields instead of the dummy ones
16625  * we use in the public structure
16626  */
16627 typedef struct _RealActorIter
16628 {
16629   ClutterActor *root;           /* dummy1 */
16630   ClutterActor *current;        /* dummy2 */
16631   gpointer padding_1;           /* dummy3 */
16632   gint age;                     /* dummy4 */
16633   gpointer padding_2;           /* dummy5 */
16634 } RealActorIter;
16635
16636 /**
16637  * clutter_actor_iter_init:
16638  * @iter: a #ClutterActorIter
16639  * @root: a #ClutterActor
16640  *
16641  * Initializes a #ClutterActorIter, which can then be used to iterate
16642  * efficiently over a section of the scene graph, and associates it
16643  * with @root.
16644  *
16645  * Modifying the scene graph section that contains @root will invalidate
16646  * the iterator.
16647  *
16648  * |[
16649  *   ClutterActorIter iter;
16650  *   ClutterActor *child;
16651  *
16652  *   clutter_actor_iter_init (&iter, container);
16653  *   while (clutter_actor_iter_next (&iter, &child))
16654  *     {
16655  *       /&ast; do something with child &ast;/
16656  *     }
16657  * ]|
16658  *
16659  * Since: 1.10
16660  */
16661 void
16662 clutter_actor_iter_init (ClutterActorIter *iter,
16663                          ClutterActor     *root)
16664 {
16665   RealActorIter *ri = (RealActorIter *) iter;
16666
16667   g_return_if_fail (iter != NULL);
16668   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16669
16670   ri->root = root;
16671   ri->current = NULL;
16672   ri->age = root->priv->age;
16673 }
16674
16675 /**
16676  * clutter_actor_iter_next:
16677  * @iter: a #ClutterActorIter
16678  * @child: (out): return location for a #ClutterActor
16679  *
16680  * Advances the @iter and retrieves the next child of the root #ClutterActor
16681  * that was used to initialize the #ClutterActorIterator.
16682  *
16683  * If the iterator can advance, this function returns %TRUE and sets the
16684  * @child argument.
16685  *
16686  * If the iterator cannot advance, this function returns %FALSE, and
16687  * the contents of @child are undefined.
16688  *
16689  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16690  *
16691  * Since: 1.10
16692  */
16693 gboolean
16694 clutter_actor_iter_next (ClutterActorIter  *iter,
16695                          ClutterActor     **child)
16696 {
16697   RealActorIter *ri = (RealActorIter *) iter;
16698
16699   g_return_val_if_fail (iter != NULL, FALSE);
16700   g_return_val_if_fail (ri->root != NULL, FALSE);
16701 #ifndef G_DISABLE_ASSERT
16702   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16703 #endif
16704
16705   if (ri->current == NULL)
16706     ri->current = ri->root->priv->first_child;
16707   else
16708     ri->current = ri->current->priv->next_sibling;
16709
16710   if (child != NULL)
16711     *child = ri->current;
16712
16713   return ri->current != NULL;
16714 }
16715
16716 /**
16717  * clutter_actor_iter_prev:
16718  * @iter: a #ClutterActorIter
16719  * @child: (out): return location for a #ClutterActor
16720  *
16721  * Advances the @iter and retrieves the previous child of the root
16722  * #ClutterActor 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_prev (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->last_child;
16748   else
16749     ri->current = ri->current->priv->prev_sibling;
16750
16751   if (child != NULL)
16752     *child = ri->current;
16753
16754   return ri->current != NULL;
16755 }
16756
16757 /**
16758  * clutter_actor_iter_remove:
16759  * @iter: a #ClutterActorIter
16760  *
16761  * Safely removes the #ClutterActor currently pointer to by the iterator
16762  * from its parent.
16763  *
16764  * This function can only be called after clutter_actor_iter_next() or
16765  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16766  * than once for the same actor.
16767  *
16768  * This function will call clutter_actor_remove_child() internally.
16769  *
16770  * Since: 1.10
16771  */
16772 void
16773 clutter_actor_iter_remove (ClutterActorIter *iter)
16774 {
16775   RealActorIter *ri = (RealActorIter *) iter;
16776   ClutterActor *cur;
16777
16778   g_return_if_fail (iter != NULL);
16779   g_return_if_fail (ri->root != NULL);
16780 #ifndef G_DISABLE_ASSERT
16781   g_return_if_fail (ri->age == ri->root->priv->age);
16782 #endif
16783   g_return_if_fail (ri->current != NULL);
16784
16785   cur = ri->current;
16786
16787   if (cur != NULL)
16788     {
16789       ri->current = cur->priv->prev_sibling;
16790
16791       clutter_actor_remove_child_internal (ri->root, cur,
16792                                            REMOVE_CHILD_DEFAULT_FLAGS);
16793
16794       ri->age += 1;
16795     }
16796 }
16797
16798 /**
16799  * clutter_actor_iter_destroy:
16800  * @iter: a #ClutterActorIter
16801  *
16802  * Safely destroys 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_destroy() internally.
16810  *
16811  * Since: 1.10
16812  */
16813 void
16814 clutter_actor_iter_destroy (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_destroy (cur);
16833
16834       ri->age += 1;
16835     }
16836 }
16837
16838 static const ClutterAnimationInfo default_animation_info = {
16839   NULL,         /* transitions */
16840   NULL,         /* states */
16841   NULL,         /* cur_state */
16842 };
16843
16844 static void
16845 clutter_animation_info_free (gpointer data)
16846 {
16847   if (data != NULL)
16848     {
16849       ClutterAnimationInfo *info = data;
16850
16851       if (info->transitions != NULL)
16852         g_hash_table_unref (info->transitions);
16853
16854       if (info->states != NULL)
16855         g_array_unref (info->states);
16856
16857       g_slice_free (ClutterAnimationInfo, info);
16858     }
16859 }
16860
16861 const ClutterAnimationInfo *
16862 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16863 {
16864   const ClutterAnimationInfo *res;
16865   GObject *obj = G_OBJECT (self);
16866
16867   res = g_object_get_qdata (obj, quark_actor_animation_info);
16868   if (res != NULL)
16869     return res;
16870
16871   return &default_animation_info;
16872 }
16873
16874 ClutterAnimationInfo *
16875 _clutter_actor_get_animation_info (ClutterActor *self)
16876 {
16877   GObject *obj = G_OBJECT (self);
16878   ClutterAnimationInfo *res;
16879
16880   res = g_object_get_qdata (obj, quark_actor_animation_info);
16881   if (res == NULL)
16882     {
16883       res = g_slice_new (ClutterAnimationInfo);
16884
16885       *res = default_animation_info;
16886
16887       g_object_set_qdata_full (obj, quark_actor_animation_info,
16888                                res,
16889                                clutter_animation_info_free);
16890     }
16891
16892   return res;
16893 }
16894
16895 ClutterTransition *
16896 _clutter_actor_get_transition (ClutterActor *actor,
16897                                GParamSpec   *pspec)
16898 {
16899   const ClutterAnimationInfo *info;
16900
16901   info = _clutter_actor_get_animation_info_or_defaults (actor);
16902
16903   if (info->transitions == NULL)
16904     return NULL;
16905
16906   return g_hash_table_lookup (info->transitions, pspec->name);
16907 }
16908
16909 typedef struct _TransitionClosure
16910 {
16911   ClutterActor *actor;
16912   ClutterTransition *transition;
16913   gchar *name;
16914   gulong completed_id;
16915 } TransitionClosure;
16916
16917 static void
16918 transition_closure_free (gpointer data)
16919 {
16920   if (G_LIKELY (data != NULL))
16921     {
16922       TransitionClosure *clos = data;
16923
16924       g_signal_handler_disconnect (clos->transition, clos->completed_id);
16925       g_free (clos->name);
16926
16927       g_slice_free (TransitionClosure, clos);
16928     }
16929 }
16930
16931 static void
16932 on_transition_completed (ClutterTransition *transition,
16933                          TransitionClosure *clos)
16934 {
16935   ClutterAnimationInfo *info;
16936
16937   info = _clutter_actor_get_animation_info (clos->actor);
16938
16939   /* this will take care of cleaning clos for us */
16940   g_hash_table_remove (info->transitions, clos->name);
16941 }
16942
16943 void
16944 _clutter_actor_update_transition (ClutterActor *actor,
16945                                   GParamSpec   *pspec,
16946                                   ...)
16947 {
16948   TransitionClosure *clos;
16949   ClutterInterval *interval;
16950   const ClutterAnimationInfo *info;
16951   va_list var_args;
16952   GType ptype;
16953   GValue initial = G_VALUE_INIT;
16954   GValue final = G_VALUE_INIT;
16955   char *error = NULL;
16956
16957   info = _clutter_actor_get_animation_info_or_defaults (actor);
16958
16959   if (info->transitions == NULL)
16960     return;
16961
16962   clos = g_hash_table_lookup (info->transitions, pspec->name);
16963   if (clos == NULL)
16964     return;
16965
16966   va_start (var_args, pspec);
16967
16968   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16969
16970   g_value_init (&initial, ptype);
16971   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
16972                                         pspec->name,
16973                                         &initial);
16974
16975   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
16976   if (error != NULL)
16977     {
16978       g_critical ("%s: %s", G_STRLOC, error);
16979       g_free (error);
16980       goto out;
16981     }
16982
16983   interval = clutter_transition_get_interval (clos->transition);
16984   clutter_interval_set_initial_value (interval, &initial);
16985   clutter_interval_set_final_value (interval, &final);
16986
16987   clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
16988
16989 out:
16990   g_value_unset (&initial);
16991   g_value_unset (&final);
16992
16993   va_end (var_args);
16994 }
16995
16996 /*< private >*
16997  * _clutter_actor_create_transition:
16998  * @actor: a #ClutterActor
16999  * @pspec: the property used for the transition
17000  * @...: initial and final state
17001  *
17002  * Creates a #ClutterTransition for the property represented by @pspec.
17003  *
17004  * Return value: a #ClutterTransition
17005  */
17006 ClutterTransition *
17007 _clutter_actor_create_transition (ClutterActor *actor,
17008                                   GParamSpec   *pspec,
17009                                   ...)
17010 {
17011   ClutterAnimationInfo *info;
17012   ClutterTransition *res = NULL;
17013   gboolean call_restore = FALSE;
17014   TransitionClosure *clos;
17015   va_list var_args;
17016
17017   info = _clutter_actor_get_animation_info (actor);
17018
17019   if (info->states == NULL)
17020     {
17021       clutter_actor_save_easing_state (actor);
17022       call_restore = TRUE;
17023     }
17024
17025   if (info->transitions == NULL)
17026     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17027                                                NULL,
17028                                                transition_closure_free);
17029
17030   va_start (var_args, pspec);
17031
17032   clos = g_hash_table_lookup (info->transitions, pspec->name);
17033   if (clos == NULL)
17034     {
17035       ClutterInterval *interval;
17036       GValue initial = G_VALUE_INIT;
17037       GValue final = G_VALUE_INIT;
17038       GType ptype;
17039       char *error;
17040
17041       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17042
17043       G_VALUE_COLLECT_INIT (&initial, ptype,
17044                             var_args, 0,
17045                             &error);
17046       if (error != NULL)
17047         {
17048           g_critical ("%s: %s", G_STRLOC, error);
17049           g_free (error);
17050           goto out;
17051         }
17052
17053       G_VALUE_COLLECT_INIT (&final, ptype,
17054                             var_args, 0,
17055                             &error);
17056
17057       if (error != NULL)
17058         {
17059           g_critical ("%s: %s", G_STRLOC, error);
17060           g_value_unset (&initial);
17061           g_free (error);
17062           goto out;
17063         }
17064
17065       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17066
17067       g_value_unset (&initial);
17068       g_value_unset (&final);
17069
17070       res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
17071                                              pspec->name);
17072
17073       clutter_transition_set_interval (res, interval);
17074       clutter_transition_set_remove_on_complete (res, TRUE);
17075
17076       clutter_actor_add_transition (actor, pspec->name, res);
17077     }
17078   else
17079     res = clos->transition;
17080
17081 out:
17082   if (call_restore)
17083     clutter_actor_restore_easing_state (actor);
17084
17085   va_end (var_args);
17086
17087   return res;
17088 }
17089
17090 /**
17091  * clutter_actor_add_transition:
17092  * @self: a #ClutterActor
17093  * @name: the name of the transition to add
17094  * @transition: the #ClutterTransition to add
17095  *
17096  * Adds a @transition to the #ClutterActor's list of animations.
17097  *
17098  * The @name string is a per-actor unique identifier of the @transition: only
17099  * one #ClutterTransition can be associated to the specified @name.
17100  *
17101  * The @transition will be given the easing duration, mode, and delay
17102  * associated to the actor's current easing state; it is possible to modify
17103  * these values after calling clutter_actor_add_transition().
17104  *
17105  * This function is usually called implicitly when modifying an animatable
17106  * property.
17107  *
17108  * Since: 1.10
17109  */
17110 void
17111 clutter_actor_add_transition (ClutterActor      *self,
17112                               const char        *name,
17113                               ClutterTransition *transition)
17114 {
17115   ClutterTimeline *timeline;
17116   TransitionClosure *clos;
17117   ClutterAnimationInfo *info;
17118
17119   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17120   g_return_if_fail (name != NULL);
17121   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17122
17123   info = _clutter_actor_get_animation_info (self);
17124
17125   if (info->cur_state == NULL)
17126     {
17127       g_warning ("No easing state is defined for the actor '%s'; you "
17128                  "must call clutter_actor_save_easing_state() before "
17129                  "calling clutter_actor_add_transition().",
17130                  _clutter_actor_get_debug_name (self));
17131       return;
17132     }
17133
17134   if (info->transitions == NULL)
17135     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17136                                                NULL,
17137                                                transition_closure_free);
17138
17139   if (g_hash_table_lookup (info->transitions, name) != NULL)
17140     {
17141       g_warning ("A transition with name '%s' already exists for "
17142                  "the actor '%s'",
17143                  name,
17144                  _clutter_actor_get_debug_name (self));
17145       return;
17146     }
17147
17148   timeline = CLUTTER_TIMELINE (transition);
17149
17150   clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17151   clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17152   clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17153
17154   clos = g_slice_new (TransitionClosure);
17155   clos->actor = self;
17156   clos->transition = transition;
17157   clos->name = g_strdup (name);
17158   clos->completed_id = g_signal_connect (timeline, "completed",
17159                                          G_CALLBACK (on_transition_completed),
17160                                          clos);
17161
17162   g_hash_table_insert (info->transitions, clos->name, clos);
17163 }
17164
17165 /**
17166  * clutter_actor_remove_transition:
17167  * @self: a #ClutterActor
17168  * @name: the name of the transition to remove
17169  *
17170  * Removes the transition stored inside a #ClutterActor using @name
17171  * identifier.
17172  *
17173  * Since: 1.10
17174  */
17175 void
17176 clutter_actor_remove_transition (ClutterActor *self,
17177                                  const char   *name)
17178 {
17179   const ClutterAnimationInfo *info;
17180
17181   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17182   g_return_if_fail (name != NULL);
17183
17184   info = _clutter_actor_get_animation_info_or_defaults (self);
17185
17186   if (info->transitions == NULL)
17187     return;
17188
17189   g_hash_table_remove (info->transitions, name);
17190 }
17191
17192 /**
17193  * clutter_actor_remove_all_transitions:
17194  * @self: a #ClutterActor
17195  *
17196  * Removes all transitions associated to @self.
17197  *
17198  * Since: 1.10
17199  */
17200 void
17201 clutter_actor_remove_all_transitions (ClutterActor *self)
17202 {
17203   const ClutterAnimationInfo *info;
17204
17205   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17206
17207   info = _clutter_actor_get_animation_info_or_defaults (self);
17208   if (info->transitions == NULL)
17209     return;
17210
17211   g_hash_table_remove_all (info->transitions);
17212 }
17213
17214 /**
17215  * clutter_actor_set_easing_duration:
17216  * @self: a #ClutterActor
17217  * @msecs: the duration of the easing, or %NULL
17218  *
17219  * Sets the duration of the tweening for animatable properties
17220  * of @self for the current easing state.
17221  *
17222  * Calling this function will implicitly call
17223  * clutter_actor_save_easing_state() if no previous call to
17224  * that function was made.
17225  *
17226  * Since: 1.10
17227  */
17228 void
17229 clutter_actor_set_easing_duration (ClutterActor *self,
17230                                    guint         msecs)
17231 {
17232   ClutterAnimationInfo *info;
17233
17234   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17235
17236   info = _clutter_actor_get_animation_info (self);
17237
17238   if (info->states == NULL)
17239     clutter_actor_save_easing_state (self);
17240
17241   if (info->cur_state->easing_duration != msecs)
17242     info->cur_state->easing_duration = msecs;
17243 }
17244
17245 /**
17246  * clutter_actor_get_easing_duration:
17247  * @self: a #ClutterActor
17248  *
17249  * Retrieves the duration of the tweening for animatable
17250  * properties of @self for the current easing state.
17251  *
17252  * Return value: the duration of the tweening, in milliseconds
17253  *
17254  * Since: 1.10
17255  */
17256 guint
17257 clutter_actor_get_easing_duration (ClutterActor *self)
17258 {
17259   const ClutterAnimationInfo *info;
17260
17261   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17262
17263   info = _clutter_actor_get_animation_info_or_defaults (self);
17264
17265   if (info->cur_state != NULL)
17266     return info->cur_state->easing_duration;
17267
17268   return 0;
17269 }
17270
17271 /**
17272  * clutter_actor_set_easing_mode:
17273  * @self: a #ClutterActor
17274  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17275  *
17276  * Sets the easing mode for the tweening of animatable properties
17277  * of @self.
17278  *
17279  * Calling this function will implicitly call
17280  * clutter_actor_save_easing_state() if no previous calls to
17281  * that function were made.
17282  *
17283  * Since: 1.10
17284  */
17285 void
17286 clutter_actor_set_easing_mode (ClutterActor         *self,
17287                                ClutterAnimationMode  mode)
17288 {
17289   ClutterAnimationInfo *info;
17290
17291   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17292   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17293   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17294
17295   info = _clutter_actor_get_animation_info (self);
17296
17297   if (info->states == NULL)
17298     clutter_actor_save_easing_state (self);
17299
17300   if (info->cur_state->easing_mode != mode)
17301     info->cur_state->easing_mode = mode;
17302 }
17303
17304 /**
17305  * clutter_actor_get_easing_mode:
17306  * @self: a #ClutterActor
17307  *
17308  * Retrieves the easing mode for the tweening of animatable properties
17309  * of @self for the current easing state.
17310  *
17311  * Return value: an easing mode
17312  *
17313  * Since: 1.10
17314  */
17315 ClutterAnimationMode
17316 clutter_actor_get_easing_mode (ClutterActor *self)
17317 {
17318   const ClutterAnimationInfo *info;
17319
17320   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17321
17322   info = _clutter_actor_get_animation_info_or_defaults (self);
17323
17324   if (info->cur_state != NULL)
17325     return info->cur_state->easing_mode;
17326
17327   return CLUTTER_EASE_OUT_CUBIC;
17328 }
17329
17330 /**
17331  * clutter_actor_set_easing_delay:
17332  * @self: a #ClutterActor
17333  * @msecs: the delay before the start of the tweening, in milliseconds
17334  *
17335  * Sets the delay that should be applied before tweening animatable
17336  * properties.
17337  *
17338  * Calling this function will implicitly call
17339  * clutter_actor_save_easing_state() if no previous calls to
17340  * that function were made.
17341  *
17342  * Since: 1.10
17343  */
17344 void
17345 clutter_actor_set_easing_delay (ClutterActor *self,
17346                                 guint         msecs)
17347 {
17348   ClutterAnimationInfo *info;
17349
17350   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17351
17352   info = _clutter_actor_get_animation_info (self);
17353
17354   if (info->states == NULL)
17355     clutter_actor_save_easing_state (self);
17356
17357   if (info->cur_state->easing_delay != msecs)
17358     info->cur_state->easing_delay = msecs;
17359 }
17360
17361 /**
17362  * clutter_actor_get_easing_delay:
17363  * @self: a #ClutterActor
17364  *
17365  * Retrieves the delay that should be applied when tweening animatable
17366  * properties.
17367  *
17368  * Return value: a delay, in milliseconds
17369  *
17370  * Since: 1.10
17371  */
17372 guint
17373 clutter_actor_get_easing_delay (ClutterActor *self)
17374 {
17375   const ClutterAnimationInfo *info;
17376
17377   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17378
17379   info = _clutter_actor_get_animation_info_or_defaults (self);
17380
17381   if (info->cur_state != NULL)
17382     return info->cur_state->easing_delay;
17383
17384   return 0;
17385 }
17386
17387 /**
17388  * clutter_actor_get_transition:
17389  * @self: a #ClutterActor
17390  * @name: the name of the transition
17391  *
17392  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17393  * transition @name.
17394  *
17395  * Transitions created for animatable properties use the name of the
17396  * property itself, for instance the code below:
17397  *
17398  * |[
17399  *   clutter_actor_set_easing_duration (actor, 1000);
17400  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17401  *
17402  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17403  *   g_signal_connect (transition, "completed",
17404  *                     G_CALLBACK (on_transition_complete),
17405  *                     actor);
17406  * ]|
17407  *
17408  * will call the <function>on_transition_complete</function> callback when
17409  * the transition is complete.
17410  *
17411  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17412  *   was found to match the passed name; the returned instance is owned
17413  *   by Clutter and it should not be freed
17414  *
17415  * Since: 1.10
17416  */
17417 ClutterTransition *
17418 clutter_actor_get_transition (ClutterActor *self,
17419                               const char   *name)
17420 {
17421   TransitionClosure *clos;
17422   const ClutterAnimationInfo *info;
17423
17424   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17425   g_return_val_if_fail (name != NULL, NULL);
17426
17427   info = _clutter_actor_get_animation_info_or_defaults (self);
17428
17429   if (info->transitions == NULL)
17430     return NULL;
17431
17432   clos = g_hash_table_lookup (info->transitions, name);
17433   if (clos == NULL)
17434     return NULL;
17435
17436   return clos->transition;
17437 }
17438
17439 /**
17440  * clutter_actor_save_easing_state:
17441  * @self: a #ClutterActor
17442  *
17443  * Saves the current easing state for animatable properties, and creates
17444  * a new state with the default values for easing mode and duration.
17445  *
17446  * Since: 1.10
17447  */
17448 void
17449 clutter_actor_save_easing_state (ClutterActor *self)
17450 {
17451   ClutterAnimationInfo *info;
17452   AState new_state;
17453
17454   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17455
17456   info = _clutter_actor_get_animation_info (self);
17457
17458   if (info->states == NULL)
17459     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17460
17461   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17462   new_state.easing_duration = 250;
17463   new_state.easing_delay = 0;
17464
17465   g_array_append_val (info->states, new_state);
17466
17467   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17468 }
17469
17470 /**
17471  * clutter_actor_restore_easing_state:
17472  * @self: a #ClutterActor
17473  *
17474  * Restores the easing state as it was prior to a call to
17475  * clutter_actor_save_easing_state().
17476  *
17477  * Since: 1.10
17478  */
17479 void
17480 clutter_actor_restore_easing_state (ClutterActor *self)
17481 {
17482   ClutterAnimationInfo *info;
17483
17484   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17485
17486   info = _clutter_actor_get_animation_info (self);
17487
17488   if (info->states == NULL)
17489     {
17490       g_critical ("The function clutter_actor_restore_easing_state() has "
17491                   "called without a previous call to "
17492                   "clutter_actor_save_easing_state().");
17493       return;
17494     }
17495
17496   g_array_remove_index (info->states, info->states->len - 1);
17497   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17498 }
17499
17500 /**
17501  * clutter_actor_set_content:
17502  * @self: a #ClutterActor
17503  * @content: (allow-none): a #ClutterContent, or %NULL
17504  *
17505  * Sets the contents of a #ClutterActor.
17506  *
17507  * Since: 1.10
17508  */
17509 void
17510 clutter_actor_set_content (ClutterActor   *self,
17511                            ClutterContent *content)
17512 {
17513   ClutterActorPrivate *priv;
17514
17515   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17516   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17517
17518   priv = self->priv;
17519
17520   if (priv->content != NULL)
17521     {
17522       _clutter_content_detached (priv->content, self);
17523       g_object_unref (priv->content);
17524     }
17525
17526   priv->content = content;
17527
17528   if (priv->content != NULL)
17529     {
17530       g_object_ref (priv->content);
17531       _clutter_content_attached (priv->content, self);
17532     }
17533
17534   /* given that the content is always painted within the allocation,
17535    * we only need to queue a redraw here
17536    */
17537   clutter_actor_queue_redraw (self);
17538
17539   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17540
17541   /* if the content gravity is not resize-fill, and the new content has a
17542    * different preferred size than the previous one, then the content box
17543    * may have been changed. since we compute that lazily, we just notify
17544    * here, and let whomever watches :content-box do whatever they need to
17545    * do.
17546    */
17547   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17548     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17549 }
17550
17551 /**
17552  * clutter_actor_get_content:
17553  * @self: a #ClutterActor
17554  *
17555  * Retrieves the contents of @self.
17556  *
17557  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17558  *   or %NULL if none was set
17559  *
17560  * Since: 1.10
17561  */
17562 ClutterContent *
17563 clutter_actor_get_content (ClutterActor *self)
17564 {
17565   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17566
17567   return self->priv->content;
17568 }
17569
17570 /**
17571  * clutter_actor_set_content_gravity:
17572  * @self: a #ClutterActor
17573  * @gravity: the #ClutterContentGravity
17574  *
17575  * Sets the gravity of the #ClutterContent used by @self.
17576  *
17577  * See the description of the #ClutterActor:content-gravity property for
17578  * more information.
17579  *
17580  * Since: 1.10
17581  */
17582 void
17583 clutter_actor_set_content_gravity (ClutterActor *self,
17584                                    ClutterContentGravity  gravity)
17585 {
17586   ClutterActorPrivate *priv;
17587
17588   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17589
17590   priv = self->priv;
17591
17592   if (priv->content_gravity == gravity)
17593     return;
17594
17595   priv->content_gravity = gravity;
17596
17597   clutter_actor_queue_redraw (self);
17598
17599   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17600   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17601 }
17602
17603 /**
17604  * clutter_actor_get_content_gravity:
17605  * @self: a #ClutterActor
17606  *
17607  * Retrieves the content gravity as set using
17608  * clutter_actor_get_content_gravity().
17609  *
17610  * Return value: the content gravity
17611  *
17612  * Since: 1.10
17613  */
17614 ClutterContentGravity
17615 clutter_actor_get_content_gravity (ClutterActor *self)
17616 {
17617   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17618                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17619
17620   return self->priv->content_gravity;
17621 }
17622
17623 /**
17624  * clutter_actor_get_content_box:
17625  * @self: a #ClutterActor
17626  * @box: (out caller-allocates): the return location for the bounding
17627  *   box for the #ClutterContent
17628  *
17629  * Retrieves the bounding box for the #ClutterContent of @self.
17630  *
17631  * The bounding box is relative to the actor's allocation.
17632  *
17633  * If no #ClutterContent is set for @self, or if @self has not been
17634  * allocated yet, then the result is undefined.
17635  *
17636  * The content box is guaranteed to be, at most, as big as the allocation
17637  * of the #ClutterActor.
17638  *
17639  * If the #ClutterContent used by the actor has a preferred size, then
17640  * it is possible to modify the content box by using the
17641  * #ClutterActor:content-gravity property.
17642  *
17643  * Since: 1.10
17644  */
17645 void
17646 clutter_actor_get_content_box (ClutterActor    *self,
17647                                ClutterActorBox *box)
17648 {
17649   ClutterActorPrivate *priv;
17650   gfloat content_w, content_h;
17651   gfloat alloc_w, alloc_h;
17652
17653   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17654   g_return_if_fail (box != NULL);
17655
17656   priv = self->priv;
17657
17658   if (!clutter_actor_has_allocation (self))
17659     return;
17660
17661   box->x1 = 0.f;
17662   box->y1 = 0.f;
17663   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17664   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17665
17666   if (priv->content == NULL)
17667     return;
17668
17669   /* no need to do any more work */
17670   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17671     return;
17672
17673   /* if the content does not have a preferred size then there is
17674    * no point in computing the content box
17675    */
17676   if (!clutter_content_get_preferred_size (priv->content,
17677                                            &content_w,
17678                                            &content_h))
17679     return;
17680
17681   alloc_w = box->x2;
17682   alloc_h = box->y2;
17683
17684   switch (priv->content_gravity)
17685     {
17686     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17687       box->x2 = box->x1 + MIN (content_w, alloc_w);
17688       box->y2 = box->y1 + MIN (content_h, alloc_h);
17689       break;
17690
17691     case CLUTTER_CONTENT_GRAVITY_TOP:
17692       if (alloc_w > content_w)
17693         {
17694           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17695           box->x2 = box->x1 + content_w;
17696         }
17697       box->y2 = box->y1 + MIN (content_h, alloc_h);
17698       break;
17699
17700     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17701       if (alloc_w > content_w)
17702         {
17703           box->x1 += (alloc_w - content_w);
17704           box->x2 = box->x1 + content_w;
17705         }
17706       box->y2 = box->y1 + MIN (content_h, alloc_h);
17707       break;
17708
17709     case CLUTTER_CONTENT_GRAVITY_LEFT:
17710       box->x2 = box->x1 + MIN (content_w, alloc_w);
17711       if (alloc_h > content_h)
17712         {
17713           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17714           box->y2 = box->y1 + content_h;
17715         }
17716       break;
17717
17718     case CLUTTER_CONTENT_GRAVITY_CENTER:
17719       if (alloc_w > content_w)
17720         {
17721           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17722           box->x2 = box->x1 + content_w;
17723         }
17724       if (alloc_h > content_h)
17725         {
17726           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17727           box->y2 = box->y1 + content_h;
17728         }
17729       break;
17730
17731     case CLUTTER_CONTENT_GRAVITY_RIGHT:
17732       if (alloc_w > content_w)
17733         {
17734           box->x1 += (alloc_w - content_w);
17735           box->x2 = box->x1 + content_w;
17736         }
17737       if (alloc_h > content_h)
17738         {
17739           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17740           box->y2 = box->y1 + content_h;
17741         }
17742       break;
17743
17744     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17745       box->x2 = box->x1 + MIN (content_w, alloc_w);
17746       if (alloc_h > content_h)
17747         {
17748           box->y1 += (alloc_h - content_h);
17749           box->y2 = box->y1 + content_h;
17750         }
17751       break;
17752
17753     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17754       if (alloc_w > content_w)
17755         {
17756           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17757           box->x2 = box->x1 + content_w;
17758         }
17759       if (alloc_h > content_h)
17760         {
17761           box->y1 += (alloc_h - content_h);
17762           box->y2 = box->y1 + content_h;
17763         }
17764       break;
17765
17766     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17767       if (alloc_w > content_w)
17768         {
17769           box->x1 += (alloc_w - content_w);
17770           box->x2 = box->x1 + content_w;
17771         }
17772       if (alloc_h > content_h)
17773         {
17774           box->y1 += (alloc_h - content_h);
17775           box->y2 = box->y1 + content_h;
17776         }
17777       break;
17778
17779     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17780       g_assert_not_reached ();
17781       break;
17782
17783     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17784       {
17785         double r_c = content_w / content_h;
17786         double r_a = alloc_w / alloc_h;
17787
17788         if (r_c >= 1.0)
17789           {
17790             if (r_a >= 1.0)
17791               {
17792                 box->x1 = 0.f;
17793                 box->x2 = alloc_w;
17794
17795                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17796                 box->y2 = box->y1 + (alloc_w * r_c);
17797               }
17798             else
17799               {
17800                 box->y1 = 0.f;
17801                 box->y2 = alloc_h;
17802
17803                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17804                 box->x2 = box->x1 + (alloc_h * r_c);
17805               }
17806           }
17807         else
17808           {
17809             if (r_a >= 1.0)
17810               {
17811                 box->y1 = 0.f;
17812                 box->y2 = alloc_h;
17813
17814                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17815                 box->x2 = box->x1 + (alloc_h * r_c);
17816               }
17817             else
17818               {
17819                 box->x1 = 0.f;
17820                 box->x2 = alloc_w;
17821
17822                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17823                 box->y2 = box->y1 + (alloc_w * r_c);
17824               }
17825           }
17826       }
17827       break;
17828     }
17829 }
17830
17831 /**
17832  * clutter_actor_set_content_scaling_filters:
17833  * @self: a #ClutterActor
17834  * @min_filter: the minification filter for the content
17835  * @mag_filter: the magnification filter for the content
17836  *
17837  * Sets the minification and magnification filter to be applied when
17838  * scaling the #ClutterActor:content of a #ClutterActor.
17839  *
17840  * The #ClutterActor:minification-filter will be used when reducing
17841  * the size of the content; the #ClutterActor:magnification-filter
17842  * will be used when increasing the size of the content.
17843  *
17844  * Since: 1.10
17845  */
17846 void
17847 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
17848                                            ClutterScalingFilter  min_filter,
17849                                            ClutterScalingFilter  mag_filter)
17850 {
17851   ClutterActorPrivate *priv;
17852   gboolean changed;
17853   GObject *obj;
17854
17855   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17856
17857   priv = self->priv;
17858   obj = G_OBJECT (self);
17859
17860   g_object_freeze_notify (obj);
17861
17862   changed = FALSE;
17863
17864   if (priv->min_filter != min_filter)
17865     {
17866       priv->min_filter = min_filter;
17867       changed = TRUE;
17868
17869       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
17870     }
17871
17872   if (priv->mag_filter != mag_filter)
17873     {
17874       priv->mag_filter = mag_filter;
17875       changed = TRUE;
17876
17877       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
17878     }
17879
17880   if (changed)
17881     clutter_actor_queue_redraw (self);
17882
17883   g_object_thaw_notify (obj);
17884 }
17885
17886 /**
17887  * clutter_actor_get_content_scaling_filters:
17888  * @self: a #ClutterActor
17889  * @min_filter: (out) (allow-none): return location for the minification
17890  *   filter, or %NULL
17891  * @mag_filter: (out) (allow-none): return location for the magnification
17892  *   filter, or %NULL
17893  *
17894  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
17895  *
17896  * Since: 1.10
17897  */
17898 void
17899 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
17900                                            ClutterScalingFilter *min_filter,
17901                                            ClutterScalingFilter *mag_filter)
17902 {
17903   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17904
17905   if (min_filter != NULL)
17906     *min_filter = self->priv->min_filter;
17907
17908   if (mag_filter != NULL)
17909     *mag_filter = self->priv->mag_filter;
17910 }