actor: Unconditionally emit ::paint
[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_BILINEAR,
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
9481 /**
9482  * clutter_actor_set_x:
9483  * @self: a #ClutterActor
9484  * @x: the actor's position on the X axis
9485  *
9486  * Sets the actor's X coordinate, relative to its parent, in pixels.
9487  *
9488  * Overrides any layout manager and forces a fixed position for
9489  * the actor.
9490  *
9491  * The #ClutterActor:x property is animatable.
9492  *
9493  * Since: 0.6
9494  */
9495 void
9496 clutter_actor_set_x (ClutterActor *self,
9497                      gfloat        x)
9498 {
9499   const ClutterLayoutInfo *linfo;
9500
9501   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9502
9503   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9504
9505   if (clutter_actor_get_easing_duration (self) != 0)
9506     {
9507       ClutterTransition *transition;
9508
9509       transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9510       if (transition == NULL)
9511         {
9512           transition = _clutter_actor_create_transition (self,
9513                                                          obj_props[PROP_X],
9514                                                          linfo->fixed_x,
9515                                                          x);
9516
9517           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9518         }
9519       else
9520         _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9521
9522       clutter_actor_queue_relayout (self);
9523     }
9524   else
9525     clutter_actor_set_x_internal (self, x);
9526 }
9527
9528 /**
9529  * clutter_actor_set_y:
9530  * @self: a #ClutterActor
9531  * @y: the actor's position on the Y axis
9532  *
9533  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9534  *
9535  * Overrides any layout manager and forces a fixed position for
9536  * the actor.
9537  *
9538  * The #ClutterActor:y property is animatable.
9539  *
9540  * Since: 0.6
9541  */
9542 void
9543 clutter_actor_set_y (ClutterActor *self,
9544                      gfloat        y)
9545 {
9546   const ClutterLayoutInfo *linfo;
9547
9548   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9549
9550   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9551
9552   if (clutter_actor_get_easing_duration (self) != 0)
9553     {
9554       ClutterTransition *transition;
9555
9556       transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9557       if (transition == NULL)
9558         {
9559           transition = _clutter_actor_create_transition (self,
9560                                                          obj_props[PROP_Y],
9561                                                          linfo->fixed_y,
9562                                                          y);
9563
9564           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9565         }
9566       else
9567         _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9568
9569       clutter_actor_queue_relayout (self);
9570     }
9571   else
9572     clutter_actor_set_y_internal (self, y);
9573
9574   clutter_actor_queue_relayout (self);
9575 }
9576
9577 /**
9578  * clutter_actor_get_x:
9579  * @self: A #ClutterActor
9580  *
9581  * Retrieves the X coordinate of a #ClutterActor.
9582  *
9583  * This function tries to "do what you mean", by returning the
9584  * correct value depending on the actor's state.
9585  *
9586  * If the actor has a valid allocation, this function will return
9587  * the X coordinate of the origin of the allocation box.
9588  *
9589  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9590  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9591  * function will return that coordinate.
9592  *
9593  * If both the allocation and a fixed position are missing, this function
9594  * will return 0.
9595  *
9596  * Return value: the X coordinate, in pixels, ignoring any
9597  *   transformation (i.e. scaling, rotation)
9598  */
9599 gfloat
9600 clutter_actor_get_x (ClutterActor *self)
9601 {
9602   ClutterActorPrivate *priv;
9603
9604   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9605
9606   priv = self->priv;
9607
9608   if (priv->needs_allocation)
9609     {
9610       if (priv->position_set)
9611         {
9612           const ClutterLayoutInfo *info;
9613
9614           info = _clutter_actor_get_layout_info_or_defaults (self);
9615
9616           return info->fixed_x;
9617         }
9618       else
9619         return 0;
9620     }
9621   else
9622     return priv->allocation.x1;
9623 }
9624
9625 /**
9626  * clutter_actor_get_y:
9627  * @self: A #ClutterActor
9628  *
9629  * Retrieves the Y coordinate of a #ClutterActor.
9630  *
9631  * This function tries to "do what you mean", by returning the
9632  * correct value depending on the actor's state.
9633  *
9634  * If the actor has a valid allocation, this function will return
9635  * the Y coordinate of the origin of the allocation box.
9636  *
9637  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9638  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9639  * function will return that coordinate.
9640  *
9641  * If both the allocation and a fixed position are missing, this function
9642  * will return 0.
9643  *
9644  * Return value: the Y coordinate, in pixels, ignoring any
9645  *   transformation (i.e. scaling, rotation)
9646  */
9647 gfloat
9648 clutter_actor_get_y (ClutterActor *self)
9649 {
9650   ClutterActorPrivate *priv;
9651
9652   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9653
9654   priv = self->priv;
9655
9656   if (priv->needs_allocation)
9657     {
9658       if (priv->position_set)
9659         {
9660           const ClutterLayoutInfo *info;
9661
9662           info = _clutter_actor_get_layout_info_or_defaults (self);
9663
9664           return info->fixed_y;
9665         }
9666       else
9667         return 0;
9668     }
9669   else
9670     return priv->allocation.y1;
9671 }
9672
9673 /**
9674  * clutter_actor_set_scale:
9675  * @self: A #ClutterActor
9676  * @scale_x: double factor to scale actor by horizontally.
9677  * @scale_y: double factor to scale actor by vertically.
9678  *
9679  * Scales an actor with the given factors. The scaling is relative to
9680  * the scale center and the anchor point. The scale center is
9681  * unchanged by this function and defaults to 0,0.
9682  *
9683  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9684  * animatable.
9685  *
9686  * Since: 0.2
9687  */
9688 void
9689 clutter_actor_set_scale (ClutterActor *self,
9690                          gdouble       scale_x,
9691                          gdouble       scale_y)
9692 {
9693   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9694
9695   g_object_freeze_notify (G_OBJECT (self));
9696
9697   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9698   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9699
9700   g_object_thaw_notify (G_OBJECT (self));
9701 }
9702
9703 /**
9704  * clutter_actor_set_scale_full:
9705  * @self: A #ClutterActor
9706  * @scale_x: double factor to scale actor by horizontally.
9707  * @scale_y: double factor to scale actor by vertically.
9708  * @center_x: X coordinate of the center of the scale.
9709  * @center_y: Y coordinate of the center of the scale
9710  *
9711  * Scales an actor with the given factors around the given center
9712  * point. The center point is specified in pixels relative to the
9713  * anchor point (usually the top left corner of the actor).
9714  *
9715  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9716  * are animatable.
9717  *
9718  * Since: 1.0
9719  */
9720 void
9721 clutter_actor_set_scale_full (ClutterActor *self,
9722                               gdouble       scale_x,
9723                               gdouble       scale_y,
9724                               gfloat        center_x,
9725                               gfloat        center_y)
9726 {
9727   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9728
9729   g_object_freeze_notify (G_OBJECT (self));
9730
9731   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9732   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9733   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9734   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9735
9736   g_object_thaw_notify (G_OBJECT (self));
9737 }
9738
9739 /**
9740  * clutter_actor_set_scale_with_gravity:
9741  * @self: A #ClutterActor
9742  * @scale_x: double factor to scale actor by horizontally.
9743  * @scale_y: double factor to scale actor by vertically.
9744  * @gravity: the location of the scale center expressed as a compass
9745  * direction.
9746  *
9747  * Scales an actor with the given factors around the given
9748  * center point. The center point is specified as one of the compass
9749  * directions in #ClutterGravity. For example, setting it to north
9750  * will cause the top of the actor to remain unchanged and the rest of
9751  * the actor to expand left, right and downwards.
9752  *
9753  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9754  * animatable.
9755  *
9756  * Since: 1.0
9757  */
9758 void
9759 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9760                                       gdouble         scale_x,
9761                                       gdouble         scale_y,
9762                                       ClutterGravity  gravity)
9763 {
9764   ClutterTransformInfo *info;
9765   GObject *obj;
9766
9767   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9768
9769   obj = G_OBJECT (self);
9770
9771   g_object_freeze_notify (obj);
9772
9773   info = _clutter_actor_get_transform_info (self);
9774   info->scale_x = scale_x;
9775   info->scale_y = scale_y;
9776
9777   if (gravity == CLUTTER_GRAVITY_NONE)
9778     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9779   else
9780     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9781
9782   self->priv->transform_valid = FALSE;
9783
9784   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9785   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9786   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9787   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9788   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9789
9790   clutter_actor_queue_redraw (self);
9791
9792   g_object_thaw_notify (obj);
9793 }
9794
9795 /**
9796  * clutter_actor_get_scale:
9797  * @self: A #ClutterActor
9798  * @scale_x: (out) (allow-none): Location to store horizonal
9799  *   scale factor, or %NULL.
9800  * @scale_y: (out) (allow-none): Location to store vertical
9801  *   scale factor, or %NULL.
9802  *
9803  * Retrieves an actors scale factors.
9804  *
9805  * Since: 0.2
9806  */
9807 void
9808 clutter_actor_get_scale (ClutterActor *self,
9809                          gdouble      *scale_x,
9810                          gdouble      *scale_y)
9811 {
9812   const ClutterTransformInfo *info;
9813
9814   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9815
9816   info = _clutter_actor_get_transform_info_or_defaults (self);
9817
9818   if (scale_x)
9819     *scale_x = info->scale_x;
9820
9821   if (scale_y)
9822     *scale_y = info->scale_y;
9823 }
9824
9825 /**
9826  * clutter_actor_get_scale_center:
9827  * @self: A #ClutterActor
9828  * @center_x: (out) (allow-none): Location to store the X position
9829  *   of the scale center, or %NULL.
9830  * @center_y: (out) (allow-none): Location to store the Y position
9831  *   of the scale center, or %NULL.
9832  *
9833  * Retrieves the scale center coordinate in pixels relative to the top
9834  * left corner of the actor. If the scale center was specified using a
9835  * #ClutterGravity this will calculate the pixel offset using the
9836  * current size of the actor.
9837  *
9838  * Since: 1.0
9839  */
9840 void
9841 clutter_actor_get_scale_center (ClutterActor *self,
9842                                 gfloat       *center_x,
9843                                 gfloat       *center_y)
9844 {
9845   const ClutterTransformInfo *info;
9846
9847   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9848
9849   info = _clutter_actor_get_transform_info_or_defaults (self);
9850
9851   clutter_anchor_coord_get_units (self, &info->scale_center,
9852                                   center_x,
9853                                   center_y,
9854                                   NULL);
9855 }
9856
9857 /**
9858  * clutter_actor_get_scale_gravity:
9859  * @self: A #ClutterActor
9860  *
9861  * Retrieves the scale center as a compass direction. If the scale
9862  * center was specified in pixels or units this will return
9863  * %CLUTTER_GRAVITY_NONE.
9864  *
9865  * Return value: the scale gravity
9866  *
9867  * Since: 1.0
9868  */
9869 ClutterGravity
9870 clutter_actor_get_scale_gravity (ClutterActor *self)
9871 {
9872   const ClutterTransformInfo *info;
9873
9874   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9875
9876   info = _clutter_actor_get_transform_info_or_defaults (self);
9877
9878   return clutter_anchor_coord_get_gravity (&info->scale_center);
9879 }
9880
9881 static inline void
9882 clutter_actor_set_opacity_internal (ClutterActor *self,
9883                                     guint8        opacity)
9884 {
9885   ClutterActorPrivate *priv = self->priv;
9886
9887   if (priv->opacity != opacity)
9888     {
9889       priv->opacity = opacity;
9890
9891       /* Queue a redraw from the flatten effect so that it can use
9892          its cached image if available instead of having to redraw the
9893          actual actor. If it doesn't end up using the FBO then the
9894          effect is still able to continue the paint anyway. If there
9895          is no flatten effect yet then this is equivalent to queueing
9896          a full redraw */
9897       _clutter_actor_queue_redraw_full (self,
9898                                         0, /* flags */
9899                                         NULL, /* clip */
9900                                         priv->flatten_effect);
9901
9902       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9903     }
9904 }
9905
9906 /**
9907  * clutter_actor_set_opacity:
9908  * @self: A #ClutterActor
9909  * @opacity: New opacity value for the actor.
9910  *
9911  * Sets the actor's opacity, with zero being completely transparent and
9912  * 255 (0xff) being fully opaque.
9913  *
9914  * The #ClutterActor:opacity property is animatable.
9915  */
9916 void
9917 clutter_actor_set_opacity (ClutterActor *self,
9918                            guint8        opacity)
9919 {
9920   ClutterActorPrivate *priv;
9921
9922   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9923
9924   priv = self->priv;
9925
9926   if (clutter_actor_get_easing_duration (self) != 0)
9927     {
9928       ClutterTransition *transition;
9929
9930       transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9931       if (transition == NULL)
9932         {
9933           transition = _clutter_actor_create_transition (self,
9934                                                          obj_props[PROP_OPACITY],
9935                                                          priv->opacity,
9936                                                          opacity);
9937           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9938         }
9939       else
9940         _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9941
9942       clutter_actor_queue_redraw (self);
9943     }
9944   else
9945     clutter_actor_set_opacity_internal (self, opacity);
9946 }
9947
9948 /*
9949  * clutter_actor_get_paint_opacity_internal:
9950  * @self: a #ClutterActor
9951  *
9952  * Retrieves the absolute opacity of the actor, as it appears on the stage
9953  *
9954  * This function does not do type checks
9955  *
9956  * Return value: the absolute opacity of the actor
9957  */
9958 static guint8
9959 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9960 {
9961   ClutterActorPrivate *priv = self->priv;
9962   ClutterActor *parent;
9963
9964   /* override the top-level opacity to always be 255; even in
9965    * case of ClutterStage:use-alpha being TRUE we want the rest
9966    * of the scene to be painted
9967    */
9968   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9969     return 255;
9970
9971   if (priv->opacity_override >= 0)
9972     return priv->opacity_override;
9973
9974   parent = priv->parent;
9975
9976   /* Factor in the actual actors opacity with parents */
9977   if (parent != NULL)
9978     {
9979       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9980
9981       if (opacity != 0xff)
9982         return (opacity * priv->opacity) / 0xff;
9983     }
9984
9985   return priv->opacity;
9986
9987 }
9988
9989 /**
9990  * clutter_actor_get_paint_opacity:
9991  * @self: A #ClutterActor
9992  *
9993  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9994  *
9995  * This function traverses the hierarchy chain and composites the opacity of
9996  * the actor with that of its parents.
9997  *
9998  * This function is intended for subclasses to use in the paint virtual
9999  * function, to paint themselves with the correct opacity.
10000  *
10001  * Return value: The actor opacity value.
10002  *
10003  * Since: 0.8
10004  */
10005 guint8
10006 clutter_actor_get_paint_opacity (ClutterActor *self)
10007 {
10008   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10009
10010   return clutter_actor_get_paint_opacity_internal (self);
10011 }
10012
10013 /**
10014  * clutter_actor_get_opacity:
10015  * @self: a #ClutterActor
10016  *
10017  * Retrieves the opacity value of an actor, as set by
10018  * clutter_actor_set_opacity().
10019  *
10020  * For retrieving the absolute opacity of the actor inside a paint
10021  * virtual function, see clutter_actor_get_paint_opacity().
10022  *
10023  * Return value: the opacity of the actor
10024  */
10025 guint8
10026 clutter_actor_get_opacity (ClutterActor *self)
10027 {
10028   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10029
10030   return self->priv->opacity;
10031 }
10032
10033 /**
10034  * clutter_actor_set_offscreen_redirect:
10035  * @self: A #ClutterActor
10036  * @redirect: New offscreen redirect flags for the actor.
10037  *
10038  * Defines the circumstances where the actor should be redirected into
10039  * an offscreen image. The offscreen image is used to flatten the
10040  * actor into a single image while painting for two main reasons.
10041  * Firstly, when the actor is painted a second time without any of its
10042  * contents changing it can simply repaint the cached image without
10043  * descending further down the actor hierarchy. Secondly, it will make
10044  * the opacity look correct even if there are overlapping primitives
10045  * in the actor.
10046  *
10047  * Caching the actor could in some cases be a performance win and in
10048  * some cases be a performance lose so it is important to determine
10049  * which value is right for an actor before modifying this value. For
10050  * example, there is never any reason to flatten an actor that is just
10051  * a single texture (such as a #ClutterTexture) because it is
10052  * effectively already cached in an image so the offscreen would be
10053  * redundant. Also if the actor contains primitives that are far apart
10054  * with a large transparent area in the middle (such as a large
10055  * CluterGroup with a small actor in the top left and a small actor in
10056  * the bottom right) then the cached image will contain the entire
10057  * image of the large area and the paint will waste time blending all
10058  * of the transparent pixels in the middle.
10059  *
10060  * The default method of implementing opacity on a container simply
10061  * forwards on the opacity to all of the children. If the children are
10062  * overlapping then it will appear as if they are two separate glassy
10063  * objects and there will be a break in the color where they
10064  * overlap. By redirecting to an offscreen buffer it will be as if the
10065  * two opaque objects are combined into one and then made transparent
10066  * which is usually what is expected.
10067  *
10068  * The image below demonstrates the difference between redirecting and
10069  * not. The image shows two Clutter groups, each containing a red and
10070  * a green rectangle which overlap. The opacity on the group is set to
10071  * 128 (which is 50%). When the offscreen redirect is not used, the
10072  * red rectangle can be seen through the blue rectangle as if the two
10073  * rectangles were separately transparent. When the redirect is used
10074  * the group as a whole is transparent instead so the red rectangle is
10075  * not visible where they overlap.
10076  *
10077  * <figure id="offscreen-redirect">
10078  *   <title>Sample of using an offscreen redirect for transparency</title>
10079  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10080  * </figure>
10081  *
10082  * The default value for this property is 0, so we effectively will
10083  * never redirect an actor offscreen by default. This means that there
10084  * are times that transparent actors may look glassy as described
10085  * above. The reason this is the default is because there is a
10086  * performance trade off between quality and performance here. In many
10087  * cases the default form of glassy opacity looks good enough, but if
10088  * it's not you will need to set the
10089  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10090  * redirection for opacity.
10091  *
10092  * Custom actors that don't contain any overlapping primitives are
10093  * recommended to override the has_overlaps() virtual to return %FALSE
10094  * for maximum efficiency.
10095  *
10096  * Since: 1.8
10097  */
10098 void
10099 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10100                                       ClutterOffscreenRedirect redirect)
10101 {
10102   ClutterActorPrivate *priv;
10103
10104   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10105
10106   priv = self->priv;
10107
10108   if (priv->offscreen_redirect != redirect)
10109     {
10110       priv->offscreen_redirect = redirect;
10111
10112       /* Queue a redraw from the effect so that it can use its cached
10113          image if available instead of having to redraw the actual
10114          actor. If it doesn't end up using the FBO then the effect is
10115          still able to continue the paint anyway. If there is no
10116          effect then this is equivalent to queuing a full redraw */
10117       _clutter_actor_queue_redraw_full (self,
10118                                         0, /* flags */
10119                                         NULL, /* clip */
10120                                         priv->flatten_effect);
10121
10122       g_object_notify_by_pspec (G_OBJECT (self),
10123                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10124     }
10125 }
10126
10127 /**
10128  * clutter_actor_get_offscreen_redirect:
10129  * @self: a #ClutterActor
10130  *
10131  * Retrieves whether to redirect the actor to an offscreen buffer, as
10132  * set by clutter_actor_set_offscreen_redirect().
10133  *
10134  * Return value: the value of the offscreen-redirect property of the actor
10135  *
10136  * Since: 1.8
10137  */
10138 ClutterOffscreenRedirect
10139 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10140 {
10141   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10142
10143   return self->priv->offscreen_redirect;
10144 }
10145
10146 /**
10147  * clutter_actor_set_name:
10148  * @self: A #ClutterActor
10149  * @name: Textual tag to apply to actor
10150  *
10151  * Sets the given name to @self. The name can be used to identify
10152  * a #ClutterActor.
10153  */
10154 void
10155 clutter_actor_set_name (ClutterActor *self,
10156                         const gchar  *name)
10157 {
10158   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10159
10160   g_free (self->priv->name);
10161   self->priv->name = g_strdup (name);
10162
10163   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10164 }
10165
10166 /**
10167  * clutter_actor_get_name:
10168  * @self: A #ClutterActor
10169  *
10170  * Retrieves the name of @self.
10171  *
10172  * Return value: the name of the actor, or %NULL. The returned string is
10173  *   owned by the actor and should not be modified or freed.
10174  */
10175 const gchar *
10176 clutter_actor_get_name (ClutterActor *self)
10177 {
10178   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10179
10180   return self->priv->name;
10181 }
10182
10183 /**
10184  * clutter_actor_get_gid:
10185  * @self: A #ClutterActor
10186  *
10187  * Retrieves the unique id for @self.
10188  *
10189  * Return value: Globally unique value for this object instance.
10190  *
10191  * Since: 0.6
10192  *
10193  * Deprecated: 1.8: The id is not used any longer.
10194  */
10195 guint32
10196 clutter_actor_get_gid (ClutterActor *self)
10197 {
10198   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10199
10200   return self->priv->id;
10201 }
10202
10203 static inline void
10204 clutter_actor_set_depth_internal (ClutterActor *self,
10205                                   float         depth)
10206 {
10207   ClutterTransformInfo *info;
10208
10209   info = _clutter_actor_get_transform_info (self);
10210
10211   if (info->depth != depth)
10212     {
10213       /* Sets Z value - XXX 2.0: should we invert? */
10214       info->depth = depth;
10215
10216       self->priv->transform_valid = FALSE;
10217
10218       /* FIXME - remove this crap; sadly, there are still containers
10219        * in Clutter that depend on this utter brain damage
10220        */
10221       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10222
10223       clutter_actor_queue_redraw (self);
10224
10225       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10226     }
10227 }
10228
10229 /**
10230  * clutter_actor_set_depth:
10231  * @self: a #ClutterActor
10232  * @depth: Z co-ord
10233  *
10234  * Sets the Z coordinate of @self to @depth.
10235  *
10236  * The unit used by @depth is dependant on the perspective setup. See
10237  * also clutter_stage_set_perspective().
10238  */
10239 void
10240 clutter_actor_set_depth (ClutterActor *self,
10241                          gfloat        depth)
10242 {
10243   const ClutterTransformInfo *tinfo;
10244
10245   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10246
10247   tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10248
10249   if (clutter_actor_get_easing_duration (self) != 0)
10250     {
10251       ClutterTransition *transition;
10252
10253       transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10254       if (transition == NULL)
10255         {
10256           transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10257                                                          tinfo->depth,
10258                                                          depth);
10259           clutter_timeline_start (CLUTTER_TIMELINE (transition));
10260         }
10261       else
10262         _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10263
10264       clutter_actor_queue_redraw (self);
10265     }
10266   else
10267     clutter_actor_set_depth_internal (self, depth);
10268 }
10269
10270 /**
10271  * clutter_actor_get_depth:
10272  * @self: a #ClutterActor
10273  *
10274  * Retrieves the depth of @self.
10275  *
10276  * Return value: the depth of the actor
10277  */
10278 gfloat
10279 clutter_actor_get_depth (ClutterActor *self)
10280 {
10281   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10282
10283   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10284 }
10285
10286 /**
10287  * clutter_actor_set_rotation:
10288  * @self: a #ClutterActor
10289  * @axis: the axis of rotation
10290  * @angle: the angle of rotation
10291  * @x: X coordinate of the rotation center
10292  * @y: Y coordinate of the rotation center
10293  * @z: Z coordinate of the rotation center
10294  *
10295  * Sets the rotation angle of @self around the given axis.
10296  *
10297  * The rotation center coordinates used depend on the value of @axis:
10298  * <itemizedlist>
10299  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10300  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10301  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10302  * </itemizedlist>
10303  *
10304  * The rotation coordinates are relative to the anchor point of the
10305  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10306  * point is set, the upper left corner is assumed as the origin.
10307  *
10308  * Since: 0.8
10309  */
10310 void
10311 clutter_actor_set_rotation (ClutterActor      *self,
10312                             ClutterRotateAxis  axis,
10313                             gdouble            angle,
10314                             gfloat             x,
10315                             gfloat             y,
10316                             gfloat             z)
10317 {
10318   ClutterVertex v;
10319
10320   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10321
10322   v.x = x;
10323   v.y = y;
10324   v.z = z;
10325
10326   g_object_freeze_notify (G_OBJECT (self));
10327
10328   clutter_actor_set_rotation_angle (self, axis, angle);
10329   clutter_actor_set_rotation_center_internal (self, axis, &v);
10330
10331   g_object_thaw_notify (G_OBJECT (self));
10332 }
10333
10334 /**
10335  * clutter_actor_set_z_rotation_from_gravity:
10336  * @self: a #ClutterActor
10337  * @angle: the angle of rotation
10338  * @gravity: the center point of the rotation
10339  *
10340  * Sets the rotation angle of @self around the Z axis using the center
10341  * point specified as a compass point. For example to rotate such that
10342  * the center of the actor remains static you can use
10343  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10344  * will move accordingly.
10345  *
10346  * Since: 1.0
10347  */
10348 void
10349 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10350                                            gdouble         angle,
10351                                            ClutterGravity  gravity)
10352 {
10353   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10354
10355   if (gravity == CLUTTER_GRAVITY_NONE)
10356     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10357   else
10358     {
10359       GObject *obj = G_OBJECT (self);
10360       ClutterTransformInfo *info;
10361
10362       info = _clutter_actor_get_transform_info (self);
10363
10364       g_object_freeze_notify (obj);
10365
10366       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10367
10368       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10369       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10370       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10371
10372       g_object_thaw_notify (obj);
10373     }
10374 }
10375
10376 /**
10377  * clutter_actor_get_rotation:
10378  * @self: a #ClutterActor
10379  * @axis: the axis of rotation
10380  * @x: (out): return value for the X coordinate of the center of rotation
10381  * @y: (out): return value for the Y coordinate of the center of rotation
10382  * @z: (out): return value for the Z coordinate of the center of rotation
10383  *
10384  * Retrieves the angle and center of rotation on the given axis,
10385  * set using clutter_actor_set_rotation().
10386  *
10387  * Return value: the angle of rotation
10388  *
10389  * Since: 0.8
10390  */
10391 gdouble
10392 clutter_actor_get_rotation (ClutterActor      *self,
10393                             ClutterRotateAxis  axis,
10394                             gfloat            *x,
10395                             gfloat            *y,
10396                             gfloat            *z)
10397 {
10398   const ClutterTransformInfo *info;
10399   const AnchorCoord *anchor_coord;
10400   gdouble retval = 0;
10401
10402   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10403
10404   info = _clutter_actor_get_transform_info_or_defaults (self);
10405
10406   switch (axis)
10407     {
10408     case CLUTTER_X_AXIS:
10409       anchor_coord = &info->rx_center;
10410       retval = info->rx_angle;
10411       break;
10412
10413     case CLUTTER_Y_AXIS:
10414       anchor_coord = &info->ry_center;
10415       retval = info->ry_angle;
10416       break;
10417
10418     case CLUTTER_Z_AXIS:
10419       anchor_coord = &info->rz_center;
10420       retval = info->rz_angle;
10421       break;
10422
10423     default:
10424       anchor_coord = NULL;
10425       retval = 0.0;
10426       break;
10427     }
10428
10429   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10430
10431   return retval;
10432 }
10433
10434 /**
10435  * clutter_actor_get_z_rotation_gravity:
10436  * @self: A #ClutterActor
10437  *
10438  * Retrieves the center for the rotation around the Z axis as a
10439  * compass direction. If the center was specified in pixels or units
10440  * this will return %CLUTTER_GRAVITY_NONE.
10441  *
10442  * Return value: the Z rotation center
10443  *
10444  * Since: 1.0
10445  */
10446 ClutterGravity
10447 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10448 {
10449   const ClutterTransformInfo *info;
10450
10451   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10452
10453   info = _clutter_actor_get_transform_info_or_defaults (self);
10454
10455   return clutter_anchor_coord_get_gravity (&info->rz_center);
10456 }
10457
10458 /**
10459  * clutter_actor_set_clip:
10460  * @self: A #ClutterActor
10461  * @xoff: X offset of the clip rectangle
10462  * @yoff: Y offset of the clip rectangle
10463  * @width: Width of the clip rectangle
10464  * @height: Height of the clip rectangle
10465  *
10466  * Sets clip area for @self. The clip area is always computed from the
10467  * upper left corner of the actor, even if the anchor point is set
10468  * otherwise.
10469  *
10470  * Since: 0.6
10471  */
10472 void
10473 clutter_actor_set_clip (ClutterActor *self,
10474                         gfloat        xoff,
10475                         gfloat        yoff,
10476                         gfloat        width,
10477                         gfloat        height)
10478 {
10479   ClutterActorPrivate *priv;
10480
10481   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10482
10483   priv = self->priv;
10484
10485   if (priv->has_clip &&
10486       priv->clip.x == xoff &&
10487       priv->clip.y == yoff &&
10488       priv->clip.width == width &&
10489       priv->clip.height == height)
10490     return;
10491
10492   priv->clip.x = xoff;
10493   priv->clip.y = yoff;
10494   priv->clip.width = width;
10495   priv->clip.height = height;
10496
10497   priv->has_clip = TRUE;
10498
10499   clutter_actor_queue_redraw (self);
10500
10501   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10502   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10503 }
10504
10505 /**
10506  * clutter_actor_remove_clip:
10507  * @self: A #ClutterActor
10508  *
10509  * Removes clip area from @self.
10510  */
10511 void
10512 clutter_actor_remove_clip (ClutterActor *self)
10513 {
10514   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10515
10516   if (!self->priv->has_clip)
10517     return;
10518
10519   self->priv->has_clip = FALSE;
10520
10521   clutter_actor_queue_redraw (self);
10522
10523   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10524 }
10525
10526 /**
10527  * clutter_actor_has_clip:
10528  * @self: a #ClutterActor
10529  *
10530  * Determines whether the actor has a clip area set or not.
10531  *
10532  * Return value: %TRUE if the actor has a clip area set.
10533  *
10534  * Since: 0.1.1
10535  */
10536 gboolean
10537 clutter_actor_has_clip (ClutterActor *self)
10538 {
10539   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10540
10541   return self->priv->has_clip;
10542 }
10543
10544 /**
10545  * clutter_actor_get_clip:
10546  * @self: a #ClutterActor
10547  * @xoff: (out) (allow-none): return location for the X offset of
10548  *   the clip rectangle, or %NULL
10549  * @yoff: (out) (allow-none): return location for the Y offset of
10550  *   the clip rectangle, or %NULL
10551  * @width: (out) (allow-none): return location for the width of
10552  *   the clip rectangle, or %NULL
10553  * @height: (out) (allow-none): return location for the height of
10554  *   the clip rectangle, or %NULL
10555  *
10556  * Gets the clip area for @self, if any is set
10557  *
10558  * Since: 0.6
10559  */
10560 void
10561 clutter_actor_get_clip (ClutterActor *self,
10562                         gfloat       *xoff,
10563                         gfloat       *yoff,
10564                         gfloat       *width,
10565                         gfloat       *height)
10566 {
10567   ClutterActorPrivate *priv;
10568
10569   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10570
10571   priv = self->priv;
10572
10573   if (!priv->has_clip)
10574     return;
10575
10576   if (xoff != NULL)
10577     *xoff = priv->clip.x;
10578
10579   if (yoff != NULL)
10580     *yoff = priv->clip.y;
10581
10582   if (width != NULL)
10583     *width = priv->clip.width;
10584
10585   if (height != NULL)
10586     *height = priv->clip.height;
10587 }
10588
10589 /**
10590  * clutter_actor_get_children:
10591  * @self: a #ClutterActor
10592  *
10593  * Retrieves the list of children of @self.
10594  *
10595  * Return value: (transfer container) (element-type ClutterActor): A newly
10596  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10597  *   done.
10598  *
10599  * Since: 1.10
10600  */
10601 GList *
10602 clutter_actor_get_children (ClutterActor *self)
10603 {
10604   ClutterActor *iter;
10605   GList *res;
10606
10607   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10608
10609   /* we walk the list backward so that we can use prepend(),
10610    * which is O(1)
10611    */
10612   for (iter = self->priv->last_child, res = NULL;
10613        iter != NULL;
10614        iter = iter->priv->prev_sibling)
10615     {
10616       res = g_list_prepend (res, iter);
10617     }
10618
10619   return res;
10620 }
10621
10622 /*< private >
10623  * insert_child_at_depth:
10624  * @self: a #ClutterActor
10625  * @child: a #ClutterActor
10626  *
10627  * Inserts @child inside the list of children held by @self, using
10628  * the depth as the insertion criteria.
10629  *
10630  * This sadly makes the insertion not O(1), but we can keep the
10631  * list sorted so that the painters algorithm we use for painting
10632  * the children will work correctly.
10633  */
10634 static void
10635 insert_child_at_depth (ClutterActor *self,
10636                        ClutterActor *child,
10637                        gpointer      dummy G_GNUC_UNUSED)
10638 {
10639   ClutterActor *iter;
10640   float child_depth;
10641
10642   child->priv->parent = self;
10643
10644   child_depth =
10645     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10646
10647   /* special-case the first child */
10648   if (self->priv->n_children == 0)
10649     {
10650       self->priv->first_child = child;
10651       self->priv->last_child = child;
10652
10653       child->priv->next_sibling = NULL;
10654       child->priv->prev_sibling = NULL;
10655
10656       return;
10657     }
10658
10659   /* Find the right place to insert the child so that it will still be
10660      sorted and the child will be after all of the actors at the same
10661      dept */
10662   for (iter = self->priv->first_child;
10663        iter != NULL;
10664        iter = iter->priv->next_sibling)
10665     {
10666       float iter_depth;
10667
10668       iter_depth =
10669         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10670
10671       if (iter_depth > child_depth)
10672         break;
10673     }
10674
10675   if (iter != NULL)
10676     {
10677       ClutterActor *tmp = iter->priv->prev_sibling;
10678
10679       if (tmp != NULL)
10680         tmp->priv->next_sibling = child;
10681
10682       /* Insert the node before the found one */
10683       child->priv->prev_sibling = iter->priv->prev_sibling;
10684       child->priv->next_sibling = iter;
10685       iter->priv->prev_sibling = child;
10686     }
10687   else
10688     {
10689       ClutterActor *tmp = self->priv->last_child;
10690
10691       if (tmp != NULL)
10692         tmp->priv->next_sibling = child;
10693
10694       /* insert the node at the end of the list */
10695       child->priv->prev_sibling = self->priv->last_child;
10696       child->priv->next_sibling = NULL;
10697     }
10698
10699   if (child->priv->prev_sibling == NULL)
10700     self->priv->first_child = child;
10701
10702   if (child->priv->next_sibling == NULL)
10703     self->priv->last_child = child;
10704 }
10705
10706 static void
10707 insert_child_at_index (ClutterActor *self,
10708                        ClutterActor *child,
10709                        gpointer      data_)
10710 {
10711   gint index_ = GPOINTER_TO_INT (data_);
10712
10713   child->priv->parent = self;
10714
10715   if (index_ == 0)
10716     {
10717       ClutterActor *tmp = self->priv->first_child;
10718
10719       if (tmp != NULL)
10720         tmp->priv->prev_sibling = child;
10721
10722       child->priv->prev_sibling = NULL;
10723       child->priv->next_sibling = tmp;
10724     }
10725   else if (index_ < 0 || index_ >= self->priv->n_children)
10726     {
10727       ClutterActor *tmp = self->priv->last_child;
10728
10729       if (tmp != NULL)
10730         tmp->priv->next_sibling = child;
10731
10732       child->priv->prev_sibling = tmp;
10733       child->priv->next_sibling = NULL;
10734     }
10735   else
10736     {
10737       ClutterActor *iter;
10738       int i;
10739
10740       for (iter = self->priv->first_child, i = 0;
10741            iter != NULL;
10742            iter = iter->priv->next_sibling, i += 1)
10743         {
10744           if (index_ == i)
10745             {
10746               ClutterActor *tmp = iter->priv->prev_sibling;
10747
10748               child->priv->prev_sibling = tmp;
10749               child->priv->next_sibling = iter;
10750
10751               iter->priv->prev_sibling = child;
10752
10753               if (tmp != NULL)
10754                 tmp->priv->next_sibling = child;
10755
10756               break;
10757             }
10758         }
10759     }
10760
10761   if (child->priv->prev_sibling == NULL)
10762     self->priv->first_child = child;
10763
10764   if (child->priv->next_sibling == NULL)
10765     self->priv->last_child = child;
10766 }
10767
10768 static void
10769 insert_child_above (ClutterActor *self,
10770                     ClutterActor *child,
10771                     gpointer      data)
10772 {
10773   ClutterActor *sibling = data;
10774
10775   child->priv->parent = self;
10776
10777   if (sibling == NULL)
10778     sibling = self->priv->last_child;
10779
10780   child->priv->prev_sibling = sibling;
10781
10782   if (sibling != NULL)
10783     {
10784       ClutterActor *tmp = sibling->priv->next_sibling;
10785
10786       child->priv->next_sibling = tmp;
10787
10788       if (tmp != NULL)
10789         tmp->priv->prev_sibling = child;
10790
10791       sibling->priv->next_sibling = child;
10792     }
10793   else
10794     child->priv->next_sibling = NULL;
10795
10796   if (child->priv->prev_sibling == NULL)
10797     self->priv->first_child = child;
10798
10799   if (child->priv->next_sibling == NULL)
10800     self->priv->last_child = child;
10801 }
10802
10803 static void
10804 insert_child_below (ClutterActor *self,
10805                     ClutterActor *child,
10806                     gpointer      data)
10807 {
10808   ClutterActor *sibling = data;
10809
10810   child->priv->parent = self;
10811
10812   if (sibling == NULL)
10813     sibling = self->priv->first_child;
10814
10815   child->priv->next_sibling = sibling;
10816
10817   if (sibling != NULL)
10818     {
10819       ClutterActor *tmp = sibling->priv->prev_sibling;
10820
10821       child->priv->prev_sibling = tmp;
10822
10823       if (tmp != NULL)
10824         tmp->priv->next_sibling = child;
10825
10826       sibling->priv->prev_sibling = child;
10827     }
10828   else
10829     child->priv->prev_sibling = NULL;
10830
10831   if (child->priv->prev_sibling == NULL)
10832     self->priv->first_child = child;
10833
10834   if (child->priv->next_sibling == NULL)
10835     self->priv->last_child = child;
10836 }
10837
10838 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10839                                            ClutterActor *child,
10840                                            gpointer      data);
10841
10842 typedef enum {
10843   ADD_CHILD_CREATE_META       = 1 << 0,
10844   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10845   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10846   ADD_CHILD_CHECK_STATE       = 1 << 3,
10847   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10848
10849   /* default flags for public API */
10850   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10851                                ADD_CHILD_EMIT_PARENT_SET |
10852                                ADD_CHILD_EMIT_ACTOR_ADDED |
10853                                ADD_CHILD_CHECK_STATE |
10854                                ADD_CHILD_NOTIFY_FIRST_LAST,
10855
10856   /* flags for legacy/deprecated API */
10857   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10858                                ADD_CHILD_CHECK_STATE |
10859                                ADD_CHILD_NOTIFY_FIRST_LAST
10860 } ClutterActorAddChildFlags;
10861
10862 /*< private >
10863  * clutter_actor_add_child_internal:
10864  * @self: a #ClutterActor
10865  * @child: a #ClutterActor
10866  * @flags: control flags for actions
10867  * @add_func: delegate function
10868  * @data: (closure): data to pass to @add_func
10869  *
10870  * Adds @child to the list of children of @self.
10871  *
10872  * The actual insertion inside the list is delegated to @add_func: this
10873  * function will just set up the state, perform basic checks, and emit
10874  * signals.
10875  *
10876  * The @flags argument is used to perform additional operations.
10877  */
10878 static inline void
10879 clutter_actor_add_child_internal (ClutterActor              *self,
10880                                   ClutterActor              *child,
10881                                   ClutterActorAddChildFlags  flags,
10882                                   ClutterActorAddChildFunc   add_func,
10883                                   gpointer                   data)
10884 {
10885   ClutterTextDirection text_dir;
10886   gboolean create_meta;
10887   gboolean emit_parent_set, emit_actor_added;
10888   gboolean check_state;
10889   gboolean notify_first_last;
10890   ClutterActor *old_first_child, *old_last_child;
10891
10892   if (child->priv->parent != NULL)
10893     {
10894       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10895                  "use clutter_actor_remove_child() first.",
10896                  _clutter_actor_get_debug_name (child),
10897                  _clutter_actor_get_debug_name (child->priv->parent));
10898       return;
10899     }
10900
10901   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10902     {
10903       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10904                  "a child of another actor.",
10905                  _clutter_actor_get_debug_name (child));
10906       return;
10907     }
10908
10909 #if 0
10910   /* XXX - this check disallows calling methods that change the stacking
10911    * order within the destruction sequence, by triggering a critical
10912    * warning first, and leaving the actor in an undefined state, which
10913    * then ends up being caught by an assertion.
10914    *
10915    * the reproducible sequence is:
10916    *
10917    *   - actor gets destroyed;
10918    *   - another actor, linked to the first, will try to change the
10919    *     stacking order of the first actor;
10920    *   - changing the stacking order is a composite operation composed
10921    *     by the following steps:
10922    *     1. ref() the child;
10923    *     2. remove_child_internal(), which removes the reference;
10924    *     3. add_child_internal(), which adds a reference;
10925    *   - the state of the actor is not changed between (2) and (3), as
10926    *     it could be an expensive recomputation;
10927    *   - if (3) bails out, then the actor is in an undefined state, but
10928    *     still alive;
10929    *   - the destruction sequence terminates, but the actor is unparented
10930    *     while its state indicates being parented instead.
10931    *   - assertion failure.
10932    *
10933    * the obvious fix would be to decompose each set_child_*_sibling()
10934    * method into proper remove_child()/add_child(), with state validation;
10935    * this may cause excessive work, though, and trigger a cascade of other
10936    * bugs in code that assumes that a change in the stacking order is an
10937    * atomic operation.
10938    *
10939    * another potential fix is to just remove this check here, and let
10940    * code doing stacking order changes inside the destruction sequence
10941    * of an actor continue doing the work.
10942    *
10943    * the third fix is to silently bail out early from every
10944    * set_child_*_sibling() and set_child_at_index() method, and avoid
10945    * doing work.
10946    *
10947    * I have a preference for the second solution, since it involves the
10948    * least amount of work, and the least amount of code duplication.
10949    *
10950    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10951    */
10952   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10953     {
10954       g_warning ("The actor '%s' is currently being destroyed, and "
10955                  "cannot be added as a child of another actor.",
10956                  _clutter_actor_get_debug_name (child));
10957       return;
10958     }
10959 #endif
10960
10961   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10962   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10963   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10964   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10965   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10966
10967   old_first_child = self->priv->first_child;
10968   old_last_child = self->priv->last_child;
10969
10970   g_object_freeze_notify (G_OBJECT (self));
10971
10972   if (create_meta)
10973     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10974
10975   g_object_ref_sink (child);
10976   child->priv->parent = NULL;
10977   child->priv->next_sibling = NULL;
10978   child->priv->prev_sibling = NULL;
10979
10980   /* delegate the actual insertion */
10981   add_func (self, child, data);
10982
10983   g_assert (child->priv->parent == self);
10984
10985   self->priv->n_children += 1;
10986
10987   self->priv->age += 1;
10988
10989   /* if push_internal() has been called then we automatically set
10990    * the flag on the actor
10991    */
10992   if (self->priv->internal_child)
10993     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10994
10995   /* clutter_actor_reparent() will emit ::parent-set for us */
10996   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10997     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10998
10999   if (check_state)
11000     {
11001       /* If parent is mapped or realized, we need to also be mapped or
11002        * realized once we're inside the parent.
11003        */
11004       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11005
11006       /* propagate the parent's text direction to the child */
11007       text_dir = clutter_actor_get_text_direction (self);
11008       clutter_actor_set_text_direction (child, text_dir);
11009     }
11010
11011   if (child->priv->show_on_set_parent)
11012     clutter_actor_show (child);
11013
11014   if (CLUTTER_ACTOR_IS_MAPPED (child))
11015     clutter_actor_queue_redraw (child);
11016
11017   /* maintain the invariant that if an actor needs layout,
11018    * its parents do as well
11019    */
11020   if (child->priv->needs_width_request ||
11021       child->priv->needs_height_request ||
11022       child->priv->needs_allocation)
11023     {
11024       /* we work around the short-circuiting we do
11025        * in clutter_actor_queue_relayout() since we
11026        * want to force a relayout
11027        */
11028       child->priv->needs_width_request = TRUE;
11029       child->priv->needs_height_request = TRUE;
11030       child->priv->needs_allocation = TRUE;
11031
11032       clutter_actor_queue_relayout (child->priv->parent);
11033     }
11034
11035   if (emit_actor_added)
11036     g_signal_emit_by_name (self, "actor-added", child);
11037
11038   if (notify_first_last)
11039     {
11040       if (old_first_child != self->priv->first_child)
11041         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11042
11043       if (old_last_child != self->priv->last_child)
11044         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11045     }
11046
11047   g_object_thaw_notify (G_OBJECT (self));
11048 }
11049
11050 /**
11051  * clutter_actor_add_child:
11052  * @self: a #ClutterActor
11053  * @child: a #ClutterActor
11054  *
11055  * Adds @child to the children of @self.
11056  *
11057  * This function will acquire a reference on @child that will only
11058  * be released when calling clutter_actor_remove_child().
11059  *
11060  * This function will take into consideration the #ClutterActor:depth
11061  * of @child, and will keep the list of children sorted.
11062  *
11063  * This function will emit the #ClutterContainer::actor-added signal
11064  * on @self.
11065  *
11066  * Since: 1.10
11067  */
11068 void
11069 clutter_actor_add_child (ClutterActor *self,
11070                          ClutterActor *child)
11071 {
11072   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11073   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11074   g_return_if_fail (self != child);
11075   g_return_if_fail (child->priv->parent == NULL);
11076
11077   clutter_actor_add_child_internal (self, child,
11078                                     ADD_CHILD_DEFAULT_FLAGS,
11079                                     insert_child_at_depth,
11080                                     NULL);
11081 }
11082
11083 /**
11084  * clutter_actor_insert_child_at_index:
11085  * @self: a #ClutterActor
11086  * @child: a #ClutterActor
11087  * @index_: the index
11088  *
11089  * Inserts @child into the list of children of @self, using the
11090  * given @index_. If @index_ is greater than the number of children
11091  * in @self, or is less than 0, then the new child is added at the end.
11092  *
11093  * This function will acquire a reference on @child that will only
11094  * be released when calling clutter_actor_remove_child().
11095  *
11096  * This function will not take into consideration the #ClutterActor:depth
11097  * of @child.
11098  *
11099  * This function will emit the #ClutterContainer::actor-added signal
11100  * on @self.
11101  *
11102  * Since: 1.10
11103  */
11104 void
11105 clutter_actor_insert_child_at_index (ClutterActor *self,
11106                                      ClutterActor *child,
11107                                      gint          index_)
11108 {
11109   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11110   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11111   g_return_if_fail (self != child);
11112   g_return_if_fail (child->priv->parent == NULL);
11113
11114   clutter_actor_add_child_internal (self, child,
11115                                     ADD_CHILD_DEFAULT_FLAGS,
11116                                     insert_child_at_index,
11117                                     GINT_TO_POINTER (index_));
11118 }
11119
11120 /**
11121  * clutter_actor_insert_child_above:
11122  * @self: a #ClutterActor
11123  * @child: a #ClutterActor
11124  * @sibling: (allow-none): a child of @self, or %NULL
11125  *
11126  * Inserts @child into the list of children of @self, above another
11127  * child of @self or, if @sibling is %NULL, above all the children
11128  * of @self.
11129  *
11130  * This function will acquire a reference on @child that will only
11131  * be released when calling clutter_actor_remove_child().
11132  *
11133  * This function will not take into consideration the #ClutterActor:depth
11134  * of @child.
11135  *
11136  * This function will emit the #ClutterContainer::actor-added signal
11137  * on @self.
11138  *
11139  * Since: 1.10
11140  */
11141 void
11142 clutter_actor_insert_child_above (ClutterActor *self,
11143                                   ClutterActor *child,
11144                                   ClutterActor *sibling)
11145 {
11146   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11147   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11148   g_return_if_fail (self != child);
11149   g_return_if_fail (child != sibling);
11150   g_return_if_fail (child->priv->parent == NULL);
11151   g_return_if_fail (sibling == NULL ||
11152                     (CLUTTER_IS_ACTOR (sibling) &&
11153                      sibling->priv->parent == self));
11154
11155   clutter_actor_add_child_internal (self, child,
11156                                     ADD_CHILD_DEFAULT_FLAGS,
11157                                     insert_child_above,
11158                                     sibling);
11159 }
11160
11161 /**
11162  * clutter_actor_insert_child_below:
11163  * @self: a #ClutterActor
11164  * @child: a #ClutterActor
11165  * @sibling: (allow-none): a child of @self, or %NULL
11166  *
11167  * Inserts @child into the list of children of @self, below another
11168  * child of @self or, if @sibling is %NULL, below all the children
11169  * of @self.
11170  *
11171  * This function will acquire a reference on @child that will only
11172  * be released when calling clutter_actor_remove_child().
11173  *
11174  * This function will not take into consideration the #ClutterActor:depth
11175  * of @child.
11176  *
11177  * This function will emit the #ClutterContainer::actor-added signal
11178  * on @self.
11179  *
11180  * Since: 1.10
11181  */
11182 void
11183 clutter_actor_insert_child_below (ClutterActor *self,
11184                                   ClutterActor *child,
11185                                   ClutterActor *sibling)
11186 {
11187   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11188   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11189   g_return_if_fail (self != child);
11190   g_return_if_fail (child != sibling);
11191   g_return_if_fail (child->priv->parent == NULL);
11192   g_return_if_fail (sibling == NULL ||
11193                     (CLUTTER_IS_ACTOR (sibling) &&
11194                      sibling->priv->parent == self));
11195
11196   clutter_actor_add_child_internal (self, child,
11197                                     ADD_CHILD_DEFAULT_FLAGS,
11198                                     insert_child_below,
11199                                     sibling);
11200 }
11201
11202 /**
11203  * clutter_actor_set_parent:
11204  * @self: A #ClutterActor
11205  * @parent: A new #ClutterActor parent
11206  *
11207  * Sets the parent of @self to @parent.
11208  *
11209  * This function will result in @parent acquiring a reference on @self,
11210  * eventually by sinking its floating reference first. The reference
11211  * will be released by clutter_actor_unparent().
11212  *
11213  * This function should only be called by legacy #ClutterActor<!-- -->s
11214  * implementing the #ClutterContainer interface.
11215  *
11216  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11217  */
11218 void
11219 clutter_actor_set_parent (ClutterActor *self,
11220                           ClutterActor *parent)
11221 {
11222   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11223   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11224   g_return_if_fail (self != parent);
11225   g_return_if_fail (self->priv->parent == NULL);
11226
11227   /* as this function will be called inside ClutterContainer::add
11228    * implementations or when building up a composite actor, we have
11229    * to preserve the old behaviour, and not create child meta or
11230    * emit the ::actor-added signal, to avoid recursion or double
11231    * emissions
11232    */
11233   clutter_actor_add_child_internal (parent, self,
11234                                     ADD_CHILD_LEGACY_FLAGS,
11235                                     insert_child_at_depth,
11236                                     NULL);
11237 }
11238
11239 /**
11240  * clutter_actor_get_parent:
11241  * @self: A #ClutterActor
11242  *
11243  * Retrieves the parent of @self.
11244  *
11245  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11246  *  if no parent is set
11247  */
11248 ClutterActor *
11249 clutter_actor_get_parent (ClutterActor *self)
11250 {
11251   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11252
11253   return self->priv->parent;
11254 }
11255
11256 /**
11257  * clutter_actor_get_paint_visibility:
11258  * @self: A #ClutterActor
11259  *
11260  * Retrieves the 'paint' visibility of an actor recursively checking for non
11261  * visible parents.
11262  *
11263  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11264  *
11265  * Return Value: %TRUE if the actor is visibile and will be painted.
11266  *
11267  * Since: 0.8.4
11268  */
11269 gboolean
11270 clutter_actor_get_paint_visibility (ClutterActor *actor)
11271 {
11272   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11273
11274   return CLUTTER_ACTOR_IS_MAPPED (actor);
11275 }
11276
11277 /**
11278  * clutter_actor_remove_child:
11279  * @self: a #ClutterActor
11280  * @child: a #ClutterActor
11281  *
11282  * Removes @child from the children of @self.
11283  *
11284  * This function will release the reference added by
11285  * clutter_actor_add_child(), so if you want to keep using @child
11286  * you will have to acquire a referenced on it before calling this
11287  * function.
11288  *
11289  * This function will emit the #ClutterContainer::actor-removed
11290  * signal on @self.
11291  *
11292  * Since: 1.10
11293  */
11294 void
11295 clutter_actor_remove_child (ClutterActor *self,
11296                             ClutterActor *child)
11297 {
11298   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11299   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11300   g_return_if_fail (self != child);
11301   g_return_if_fail (child->priv->parent != NULL);
11302   g_return_if_fail (child->priv->parent == self);
11303
11304   clutter_actor_remove_child_internal (self, child,
11305                                        REMOVE_CHILD_DEFAULT_FLAGS);
11306 }
11307
11308 /**
11309  * clutter_actor_remove_all_children:
11310  * @self: a #ClutterActor
11311  *
11312  * Removes all children of @self.
11313  *
11314  * This function releases the reference added by inserting a child actor
11315  * in the list of children of @self.
11316  *
11317  * If the reference count of a child drops to zero, the child will be
11318  * destroyed. If you want to ensure the destruction of all the children
11319  * of @self, use clutter_actor_destroy_all_children().
11320  *
11321  * Since: 1.10
11322  */
11323 void
11324 clutter_actor_remove_all_children (ClutterActor *self)
11325 {
11326   ClutterActorIter iter;
11327
11328   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11329
11330   if (self->priv->n_children == 0)
11331     return;
11332
11333   g_object_freeze_notify (G_OBJECT (self));
11334
11335   clutter_actor_iter_init (&iter, self);
11336   while (clutter_actor_iter_next (&iter, NULL))
11337     clutter_actor_iter_remove (&iter);
11338
11339   g_object_thaw_notify (G_OBJECT (self));
11340
11341   /* sanity check */
11342   g_assert (self->priv->first_child == NULL);
11343   g_assert (self->priv->last_child == NULL);
11344   g_assert (self->priv->n_children == 0);
11345 }
11346
11347 /**
11348  * clutter_actor_destroy_all_children:
11349  * @self: a #ClutterActor
11350  *
11351  * Destroys all children of @self.
11352  *
11353  * This function releases the reference added by inserting a child
11354  * actor in the list of children of @self, and ensures that the
11355  * #ClutterActor::destroy signal is emitted on each child of the
11356  * actor.
11357  *
11358  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11359  * when its reference count drops to 0; the default handler of the
11360  * #ClutterActor::destroy signal will destroy all the children of an
11361  * actor. This function ensures that all children are destroyed, instead
11362  * of just removed from @self, unlike clutter_actor_remove_all_children()
11363  * which will merely release the reference and remove each child.
11364  *
11365  * Unless you acquired an additional reference on each child of @self
11366  * prior to calling clutter_actor_remove_all_children() and want to reuse
11367  * the actors, you should use clutter_actor_destroy_all_children() in
11368  * order to make sure that children are destroyed and signal handlers
11369  * are disconnected even in cases where circular references prevent this
11370  * from automatically happening through reference counting alone.
11371  *
11372  * Since: 1.10
11373  */
11374 void
11375 clutter_actor_destroy_all_children (ClutterActor *self)
11376 {
11377   ClutterActorIter iter;
11378
11379   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11380
11381   if (self->priv->n_children == 0)
11382     return;
11383
11384   g_object_freeze_notify (G_OBJECT (self));
11385
11386   clutter_actor_iter_init (&iter, self);
11387   while (clutter_actor_iter_next (&iter, NULL))
11388     clutter_actor_iter_destroy (&iter);
11389
11390   g_object_thaw_notify (G_OBJECT (self));
11391
11392   /* sanity check */
11393   g_assert (self->priv->first_child == NULL);
11394   g_assert (self->priv->last_child == NULL);
11395   g_assert (self->priv->n_children == 0);
11396 }
11397
11398 typedef struct _InsertBetweenData {
11399   ClutterActor *prev_sibling;
11400   ClutterActor *next_sibling;
11401 } InsertBetweenData;
11402
11403 static void
11404 insert_child_between (ClutterActor *self,
11405                       ClutterActor *child,
11406                       gpointer      data_)
11407 {
11408   InsertBetweenData *data = data_;
11409   ClutterActor *prev_sibling = data->prev_sibling;
11410   ClutterActor *next_sibling = data->next_sibling;
11411
11412   child->priv->parent = self;
11413   child->priv->prev_sibling = prev_sibling;
11414   child->priv->next_sibling = next_sibling;
11415
11416   if (prev_sibling != NULL)
11417     prev_sibling->priv->next_sibling = child;
11418
11419   if (next_sibling != NULL)
11420     next_sibling->priv->prev_sibling = child;
11421
11422   if (child->priv->prev_sibling == NULL)
11423     self->priv->first_child = child;
11424
11425   if (child->priv->next_sibling == NULL)
11426     self->priv->last_child = child;
11427 }
11428
11429 /**
11430  * clutter_actor_replace_child:
11431  * @self: a #ClutterActor
11432  * @old_child: the child of @self to replace
11433  * @new_child: the #ClutterActor to replace @old_child
11434  *
11435  * Replaces @old_child with @new_child in the list of children of @self.
11436  *
11437  * Since: 1.10
11438  */
11439 void
11440 clutter_actor_replace_child (ClutterActor *self,
11441                              ClutterActor *old_child,
11442                              ClutterActor *new_child)
11443 {
11444   ClutterActor *prev_sibling, *next_sibling;
11445   InsertBetweenData clos;
11446
11447   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11448   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11449   g_return_if_fail (old_child->priv->parent == self);
11450   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11451   g_return_if_fail (old_child != new_child);
11452   g_return_if_fail (new_child != self);
11453   g_return_if_fail (new_child->priv->parent == NULL);
11454
11455   prev_sibling = old_child->priv->prev_sibling;
11456   next_sibling = old_child->priv->next_sibling;
11457   clutter_actor_remove_child_internal (self, old_child,
11458                                        REMOVE_CHILD_DEFAULT_FLAGS);
11459
11460   clos.prev_sibling = prev_sibling;
11461   clos.next_sibling = next_sibling;
11462   clutter_actor_add_child_internal (self, new_child,
11463                                     ADD_CHILD_DEFAULT_FLAGS,
11464                                     insert_child_between,
11465                                     &clos);
11466 }
11467
11468 /**
11469  * clutter_actor_unparent:
11470  * @self: a #ClutterActor
11471  *
11472  * Removes the parent of @self.
11473  *
11474  * This will cause the parent of @self to release the reference
11475  * acquired when calling clutter_actor_set_parent(), so if you
11476  * want to keep @self you will have to acquire a reference of
11477  * your own, through g_object_ref().
11478  *
11479  * This function should only be called by legacy #ClutterActor<!-- -->s
11480  * implementing the #ClutterContainer interface.
11481  *
11482  * Since: 0.1.1
11483  *
11484  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11485  */
11486 void
11487 clutter_actor_unparent (ClutterActor *self)
11488 {
11489   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11490
11491   if (self->priv->parent == NULL)
11492     return;
11493
11494   clutter_actor_remove_child_internal (self->priv->parent, self,
11495                                        REMOVE_CHILD_LEGACY_FLAGS);
11496 }
11497
11498 /**
11499  * clutter_actor_reparent:
11500  * @self: a #ClutterActor
11501  * @new_parent: the new #ClutterActor parent
11502  *
11503  * Resets the parent actor of @self.
11504  *
11505  * This function is logically equivalent to calling clutter_actor_unparent()
11506  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11507  * ensures the child is not finalized when unparented, and emits the
11508  * #ClutterActor::parent-set signal only once.
11509  *
11510  * In reality, calling this function is less useful than it sounds, as some
11511  * application code may rely on changes in the intermediate state between
11512  * removal and addition of the actor from its old parent to the @new_parent.
11513  * Thus, it is strongly encouraged to avoid using this function in application
11514  * code.
11515  *
11516  * Since: 0.2
11517  *
11518  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11519  *   clutter_actor_add_child() instead; remember to take a reference on
11520  *   the actor being removed before calling clutter_actor_remove_child()
11521  *   to avoid the reference count dropping to zero and the actor being
11522  *   destroyed.
11523  */
11524 void
11525 clutter_actor_reparent (ClutterActor *self,
11526                         ClutterActor *new_parent)
11527 {
11528   ClutterActorPrivate *priv;
11529
11530   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11531   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11532   g_return_if_fail (self != new_parent);
11533
11534   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11535     {
11536       g_warning ("Cannot set a parent on a toplevel actor");
11537       return;
11538     }
11539
11540   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11541     {
11542       g_warning ("Cannot set a parent currently being destroyed");
11543       return;
11544     }
11545
11546   priv = self->priv;
11547
11548   if (priv->parent != new_parent)
11549     {
11550       ClutterActor *old_parent;
11551
11552       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11553
11554       old_parent = priv->parent;
11555
11556       g_object_ref (self);
11557
11558       if (old_parent != NULL)
11559         {
11560          /* go through the Container implementation if this is a regular
11561           * child and not an internal one
11562           */
11563          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11564            {
11565              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11566
11567              /* this will have to call unparent() */
11568              clutter_container_remove_actor (parent, self);
11569            }
11570          else
11571            clutter_actor_remove_child_internal (old_parent, self,
11572                                                 REMOVE_CHILD_LEGACY_FLAGS);
11573         }
11574
11575       /* Note, will call set_parent() */
11576       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11577         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11578       else
11579         clutter_actor_add_child_internal (new_parent, self,
11580                                           ADD_CHILD_LEGACY_FLAGS,
11581                                           insert_child_at_depth,
11582                                           NULL);
11583
11584       /* we emit the ::parent-set signal once */
11585       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11586
11587       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11588
11589       /* the IN_REPARENT flag suspends state updates */
11590       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11591
11592       g_object_unref (self);
11593    }
11594 }
11595
11596 /**
11597  * clutter_actor_contains:
11598  * @self: A #ClutterActor
11599  * @descendant: A #ClutterActor, possibly contained in @self
11600  *
11601  * Determines if @descendant is contained inside @self (either as an
11602  * immediate child, or as a deeper descendant). If @self and
11603  * @descendant point to the same actor then it will also return %TRUE.
11604  *
11605  * Return value: whether @descendent is contained within @self
11606  *
11607  * Since: 1.4
11608  */
11609 gboolean
11610 clutter_actor_contains (ClutterActor *self,
11611                         ClutterActor *descendant)
11612 {
11613   ClutterActor *actor;
11614
11615   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11616   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11617
11618   for (actor = descendant; actor; actor = actor->priv->parent)
11619     if (actor == self)
11620       return TRUE;
11621
11622   return FALSE;
11623 }
11624
11625 /**
11626  * clutter_actor_set_child_above_sibling:
11627  * @self: a #ClutterActor
11628  * @child: a #ClutterActor child of @self
11629  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11630  *
11631  * Sets @child to be above @sibling in the list of children of @self.
11632  *
11633  * If @sibling is %NULL, @child will be the new last child of @self.
11634  *
11635  * This function is logically equivalent to removing @child and using
11636  * clutter_actor_insert_child_above(), but it will not emit signals
11637  * or change state on @child.
11638  *
11639  * Since: 1.10
11640  */
11641 void
11642 clutter_actor_set_child_above_sibling (ClutterActor *self,
11643                                        ClutterActor *child,
11644                                        ClutterActor *sibling)
11645 {
11646   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11647   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11648   g_return_if_fail (child->priv->parent == self);
11649   g_return_if_fail (child != sibling);
11650   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11651
11652   if (sibling != NULL)
11653     g_return_if_fail (sibling->priv->parent == self);
11654
11655   /* we don't want to change the state of child, or emit signals, or
11656    * regenerate ChildMeta instances here, but we still want to follow
11657    * the correct sequence of steps encoded in remove_child() and
11658    * add_child(), so that correctness is ensured, and we only go
11659    * through one known code path.
11660    */
11661   g_object_ref (child);
11662   clutter_actor_remove_child_internal (self, child, 0);
11663   clutter_actor_add_child_internal (self, child,
11664                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11665                                     insert_child_above,
11666                                     sibling);
11667
11668   clutter_actor_queue_relayout (self);
11669 }
11670
11671 /**
11672  * clutter_actor_set_child_below_sibling:
11673  * @self: a #ClutterActor
11674  * @child: a #ClutterActor child of @self
11675  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11676  *
11677  * Sets @child to be below @sibling in the list of children of @self.
11678  *
11679  * If @sibling is %NULL, @child will be the new first child of @self.
11680  *
11681  * This function is logically equivalent to removing @self and using
11682  * clutter_actor_insert_child_below(), but it will not emit signals
11683  * or change state on @child.
11684  *
11685  * Since: 1.10
11686  */
11687 void
11688 clutter_actor_set_child_below_sibling (ClutterActor *self,
11689                                        ClutterActor *child,
11690                                        ClutterActor *sibling)
11691 {
11692   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11693   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11694   g_return_if_fail (child->priv->parent == self);
11695   g_return_if_fail (child != sibling);
11696   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11697
11698   if (sibling != NULL)
11699     g_return_if_fail (sibling->priv->parent == self);
11700
11701   /* see the comment in set_child_above_sibling() */
11702   g_object_ref (child);
11703   clutter_actor_remove_child_internal (self, child, 0);
11704   clutter_actor_add_child_internal (self, child,
11705                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11706                                     insert_child_below,
11707                                     sibling);
11708
11709   clutter_actor_queue_relayout (self);
11710 }
11711
11712 /**
11713  * clutter_actor_set_child_at_index:
11714  * @self: a #ClutterActor
11715  * @child: a #ClutterActor child of @self
11716  * @index_: the new index for @child
11717  *
11718  * Changes the index of @child in the list of children of @self.
11719  *
11720  * This function is logically equivalent to removing @child and
11721  * calling clutter_actor_insert_child_at_index(), but it will not
11722  * emit signals or change state on @child.
11723  *
11724  * Since: 1.10
11725  */
11726 void
11727 clutter_actor_set_child_at_index (ClutterActor *self,
11728                                   ClutterActor *child,
11729                                   gint          index_)
11730 {
11731   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11732   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11733   g_return_if_fail (child->priv->parent == self);
11734   g_return_if_fail (index_ <= self->priv->n_children);
11735
11736   g_object_ref (child);
11737   clutter_actor_remove_child_internal (self, child, 0);
11738   clutter_actor_add_child_internal (self, child,
11739                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11740                                     insert_child_at_index,
11741                                     GINT_TO_POINTER (index_));
11742
11743   clutter_actor_queue_relayout (self);
11744 }
11745
11746 /**
11747  * clutter_actor_raise:
11748  * @self: A #ClutterActor
11749  * @below: (allow-none): A #ClutterActor to raise above.
11750  *
11751  * Puts @self above @below.
11752  *
11753  * Both actors must have the same parent, and the parent must implement
11754  * the #ClutterContainer interface
11755  *
11756  * This function calls clutter_container_raise_child() internally.
11757  *
11758  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11759  */
11760 void
11761 clutter_actor_raise (ClutterActor *self,
11762                      ClutterActor *below)
11763 {
11764   ClutterActor *parent;
11765
11766   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11767
11768   parent = clutter_actor_get_parent (self);
11769   if (parent == NULL)
11770     {
11771       g_warning ("%s: Actor '%s' is not inside a container",
11772                  G_STRFUNC,
11773                  _clutter_actor_get_debug_name (self));
11774       return;
11775     }
11776
11777   if (below != NULL)
11778     {
11779       if (parent != clutter_actor_get_parent (below))
11780         {
11781           g_warning ("%s Actor '%s' is not in the same container as "
11782                      "actor '%s'",
11783                      G_STRFUNC,
11784                      _clutter_actor_get_debug_name (self),
11785                      _clutter_actor_get_debug_name (below));
11786           return;
11787         }
11788     }
11789
11790   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11791 }
11792
11793 /**
11794  * clutter_actor_lower:
11795  * @self: A #ClutterActor
11796  * @above: (allow-none): A #ClutterActor to lower below
11797  *
11798  * Puts @self below @above.
11799  *
11800  * Both actors must have the same parent, and the parent must implement
11801  * the #ClutterContainer interface.
11802  *
11803  * This function calls clutter_container_lower_child() internally.
11804  *
11805  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11806  */
11807 void
11808 clutter_actor_lower (ClutterActor *self,
11809                      ClutterActor *above)
11810 {
11811   ClutterActor *parent;
11812
11813   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11814
11815   parent = clutter_actor_get_parent (self);
11816   if (parent == NULL)
11817     {
11818       g_warning ("%s: Actor of type %s is not inside a container",
11819                  G_STRFUNC,
11820                  _clutter_actor_get_debug_name (self));
11821       return;
11822     }
11823
11824   if (above)
11825     {
11826       if (parent != clutter_actor_get_parent (above))
11827         {
11828           g_warning ("%s: Actor '%s' is not in the same container as "
11829                      "actor '%s'",
11830                      G_STRFUNC,
11831                      _clutter_actor_get_debug_name (self),
11832                      _clutter_actor_get_debug_name (above));
11833           return;
11834         }
11835     }
11836
11837   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11838 }
11839
11840 /**
11841  * clutter_actor_raise_top:
11842  * @self: A #ClutterActor
11843  *
11844  * Raises @self to the top.
11845  *
11846  * This function calls clutter_actor_raise() internally.
11847  *
11848  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11849  *   a %NULL sibling, instead.
11850  */
11851 void
11852 clutter_actor_raise_top (ClutterActor *self)
11853 {
11854   clutter_actor_raise (self, NULL);
11855 }
11856
11857 /**
11858  * clutter_actor_lower_bottom:
11859  * @self: A #ClutterActor
11860  *
11861  * Lowers @self to the bottom.
11862  *
11863  * This function calls clutter_actor_lower() internally.
11864  *
11865  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11866  *   a %NULL sibling, instead.
11867  */
11868 void
11869 clutter_actor_lower_bottom (ClutterActor *self)
11870 {
11871   clutter_actor_lower (self, NULL);
11872 }
11873
11874 /*
11875  * Event handling
11876  */
11877
11878 /**
11879  * clutter_actor_event:
11880  * @actor: a #ClutterActor
11881  * @event: a #ClutterEvent
11882  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11883  *
11884  * This function is used to emit an event on the main stage.
11885  * You should rarely need to use this function, except for
11886  * synthetising events.
11887  *
11888  * Return value: the return value from the signal emission: %TRUE
11889  *   if the actor handled the event, or %FALSE if the event was
11890  *   not handled
11891  *
11892  * Since: 0.6
11893  */
11894 gboolean
11895 clutter_actor_event (ClutterActor *actor,
11896                      ClutterEvent *event,
11897                      gboolean      capture)
11898 {
11899   gboolean retval = FALSE;
11900   gint signal_num = -1;
11901
11902   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11903   g_return_val_if_fail (event != NULL, FALSE);
11904
11905   g_object_ref (actor);
11906
11907   if (capture)
11908     {
11909       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11910                      event,
11911                      &retval);
11912       goto out;
11913     }
11914
11915   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11916
11917   if (!retval)
11918     {
11919       switch (event->type)
11920         {
11921         case CLUTTER_NOTHING:
11922           break;
11923         case CLUTTER_BUTTON_PRESS:
11924           signal_num = BUTTON_PRESS_EVENT;
11925           break;
11926         case CLUTTER_BUTTON_RELEASE:
11927           signal_num = BUTTON_RELEASE_EVENT;
11928           break;
11929         case CLUTTER_SCROLL:
11930           signal_num = SCROLL_EVENT;
11931           break;
11932         case CLUTTER_KEY_PRESS:
11933           signal_num = KEY_PRESS_EVENT;
11934           break;
11935         case CLUTTER_KEY_RELEASE:
11936           signal_num = KEY_RELEASE_EVENT;
11937           break;
11938         case CLUTTER_MOTION:
11939           signal_num = MOTION_EVENT;
11940           break;
11941         case CLUTTER_ENTER:
11942           signal_num = ENTER_EVENT;
11943           break;
11944         case CLUTTER_LEAVE:
11945           signal_num = LEAVE_EVENT;
11946           break;
11947         case CLUTTER_DELETE:
11948         case CLUTTER_DESTROY_NOTIFY:
11949         case CLUTTER_CLIENT_MESSAGE:
11950         default:
11951           signal_num = -1;
11952           break;
11953         }
11954
11955       if (signal_num != -1)
11956         g_signal_emit (actor, actor_signals[signal_num], 0,
11957                        event, &retval);
11958     }
11959
11960 out:
11961   g_object_unref (actor);
11962
11963   return retval;
11964 }
11965
11966 /**
11967  * clutter_actor_set_reactive:
11968  * @actor: a #ClutterActor
11969  * @reactive: whether the actor should be reactive to events
11970  *
11971  * Sets @actor as reactive. Reactive actors will receive events.
11972  *
11973  * Since: 0.6
11974  */
11975 void
11976 clutter_actor_set_reactive (ClutterActor *actor,
11977                             gboolean      reactive)
11978 {
11979   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11980
11981   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11982     return;
11983
11984   if (reactive)
11985     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11986   else
11987     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11988
11989   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11990 }
11991
11992 /**
11993  * clutter_actor_get_reactive:
11994  * @actor: a #ClutterActor
11995  *
11996  * Checks whether @actor is marked as reactive.
11997  *
11998  * Return value: %TRUE if the actor is reactive
11999  *
12000  * Since: 0.6
12001  */
12002 gboolean
12003 clutter_actor_get_reactive (ClutterActor *actor)
12004 {
12005   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12006
12007   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12008 }
12009
12010 /**
12011  * clutter_actor_get_anchor_point:
12012  * @self: a #ClutterActor
12013  * @anchor_x: (out): return location for the X coordinate of the anchor point
12014  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12015  *
12016  * Gets the current anchor point of the @actor in pixels.
12017  *
12018  * Since: 0.6
12019  */
12020 void
12021 clutter_actor_get_anchor_point (ClutterActor *self,
12022                                 gfloat       *anchor_x,
12023                                 gfloat       *anchor_y)
12024 {
12025   const ClutterTransformInfo *info;
12026
12027   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12028
12029   info = _clutter_actor_get_transform_info_or_defaults (self);
12030   clutter_anchor_coord_get_units (self, &info->anchor,
12031                                   anchor_x,
12032                                   anchor_y,
12033                                   NULL);
12034 }
12035
12036 /**
12037  * clutter_actor_set_anchor_point:
12038  * @self: a #ClutterActor
12039  * @anchor_x: X coordinate of the anchor point
12040  * @anchor_y: Y coordinate of the anchor point
12041  *
12042  * Sets an anchor point for @self. The anchor point is a point in the
12043  * coordinate space of an actor to which the actor position within its
12044  * parent is relative; the default is (0, 0), i.e. the top-left corner
12045  * of the actor.
12046  *
12047  * Since: 0.6
12048  */
12049 void
12050 clutter_actor_set_anchor_point (ClutterActor *self,
12051                                 gfloat        anchor_x,
12052                                 gfloat        anchor_y)
12053 {
12054   ClutterTransformInfo *info;
12055   ClutterActorPrivate *priv;
12056   gboolean changed = FALSE;
12057   gfloat old_anchor_x, old_anchor_y;
12058   GObject *obj;
12059
12060   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12061
12062   obj = G_OBJECT (self);
12063   priv = self->priv;
12064   info = _clutter_actor_get_transform_info (self);
12065
12066   g_object_freeze_notify (obj);
12067
12068   clutter_anchor_coord_get_units (self, &info->anchor,
12069                                   &old_anchor_x,
12070                                   &old_anchor_y,
12071                                   NULL);
12072
12073   if (info->anchor.is_fractional)
12074     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12075
12076   if (old_anchor_x != anchor_x)
12077     {
12078       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12079       changed = TRUE;
12080     }
12081
12082   if (old_anchor_y != anchor_y)
12083     {
12084       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12085       changed = TRUE;
12086     }
12087
12088   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12089
12090   if (changed)
12091     {
12092       priv->transform_valid = FALSE;
12093       clutter_actor_queue_redraw (self);
12094     }
12095
12096   g_object_thaw_notify (obj);
12097 }
12098
12099 /**
12100  * clutter_actor_get_anchor_point_gravity:
12101  * @self: a #ClutterActor
12102  *
12103  * Retrieves the anchor position expressed as a #ClutterGravity. If
12104  * the anchor point was specified using pixels or units this will
12105  * return %CLUTTER_GRAVITY_NONE.
12106  *
12107  * Return value: the #ClutterGravity used by the anchor point
12108  *
12109  * Since: 1.0
12110  */
12111 ClutterGravity
12112 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12113 {
12114   const ClutterTransformInfo *info;
12115
12116   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12117
12118   info = _clutter_actor_get_transform_info_or_defaults (self);
12119
12120   return clutter_anchor_coord_get_gravity (&info->anchor);
12121 }
12122
12123 /**
12124  * clutter_actor_move_anchor_point:
12125  * @self: a #ClutterActor
12126  * @anchor_x: X coordinate of the anchor point
12127  * @anchor_y: Y coordinate of the anchor point
12128  *
12129  * Sets an anchor point for the actor, and adjusts the actor postion so that
12130  * the relative position of the actor toward its parent remains the same.
12131  *
12132  * Since: 0.6
12133  */
12134 void
12135 clutter_actor_move_anchor_point (ClutterActor *self,
12136                                  gfloat        anchor_x,
12137                                  gfloat        anchor_y)
12138 {
12139   gfloat old_anchor_x, old_anchor_y;
12140   const ClutterTransformInfo *info;
12141
12142   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12143
12144   info = _clutter_actor_get_transform_info (self);
12145   clutter_anchor_coord_get_units (self, &info->anchor,
12146                                   &old_anchor_x,
12147                                   &old_anchor_y,
12148                                   NULL);
12149
12150   g_object_freeze_notify (G_OBJECT (self));
12151
12152   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12153
12154   if (self->priv->position_set)
12155     clutter_actor_move_by (self,
12156                            anchor_x - old_anchor_x,
12157                            anchor_y - old_anchor_y);
12158
12159   g_object_thaw_notify (G_OBJECT (self));
12160 }
12161
12162 /**
12163  * clutter_actor_move_anchor_point_from_gravity:
12164  * @self: a #ClutterActor
12165  * @gravity: #ClutterGravity.
12166  *
12167  * Sets an anchor point on the actor based on the given gravity, adjusting the
12168  * actor postion so that its relative position within its parent remains
12169  * unchanged.
12170  *
12171  * Since version 1.0 the anchor point will be stored as a gravity so
12172  * that if the actor changes size then the anchor point will move. For
12173  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12174  * and later double the size of the actor, the anchor point will move
12175  * to the bottom right.
12176  *
12177  * Since: 0.6
12178  */
12179 void
12180 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12181                                               ClutterGravity  gravity)
12182 {
12183   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12184   const ClutterTransformInfo *info;
12185   ClutterActorPrivate *priv;
12186
12187   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12188
12189   priv = self->priv;
12190   info = _clutter_actor_get_transform_info (self);
12191
12192   g_object_freeze_notify (G_OBJECT (self));
12193
12194   clutter_anchor_coord_get_units (self, &info->anchor,
12195                                   &old_anchor_x,
12196                                   &old_anchor_y,
12197                                   NULL);
12198   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12199   clutter_anchor_coord_get_units (self, &info->anchor,
12200                                   &new_anchor_x,
12201                                   &new_anchor_y,
12202                                   NULL);
12203
12204   if (priv->position_set)
12205     clutter_actor_move_by (self,
12206                            new_anchor_x - old_anchor_x,
12207                            new_anchor_y - old_anchor_y);
12208
12209   g_object_thaw_notify (G_OBJECT (self));
12210 }
12211
12212 /**
12213  * clutter_actor_set_anchor_point_from_gravity:
12214  * @self: a #ClutterActor
12215  * @gravity: #ClutterGravity.
12216  *
12217  * Sets an anchor point on the actor, based on the given gravity (this is a
12218  * convenience function wrapping clutter_actor_set_anchor_point()).
12219  *
12220  * Since version 1.0 the anchor point will be stored as a gravity so
12221  * that if the actor changes size then the anchor point will move. For
12222  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12223  * and later double the size of the actor, the anchor point will move
12224  * to the bottom right.
12225  *
12226  * Since: 0.6
12227  */
12228 void
12229 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12230                                              ClutterGravity  gravity)
12231 {
12232   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12233
12234   if (gravity == CLUTTER_GRAVITY_NONE)
12235     clutter_actor_set_anchor_point (self, 0, 0);
12236   else
12237     {
12238       GObject *obj = G_OBJECT (self);
12239       ClutterTransformInfo *info;
12240
12241       g_object_freeze_notify (obj);
12242
12243       info = _clutter_actor_get_transform_info (self);
12244       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12245
12246       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12247       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12248       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12249
12250       self->priv->transform_valid = FALSE;
12251
12252       clutter_actor_queue_redraw (self);
12253
12254       g_object_thaw_notify (obj);
12255     }
12256 }
12257
12258 static void
12259 clutter_container_iface_init (ClutterContainerIface *iface)
12260 {
12261   /* we don't override anything, as ClutterContainer already has a default
12262    * implementation that we can use, and which calls into our own API.
12263    */
12264 }
12265
12266 typedef enum
12267 {
12268   PARSE_X,
12269   PARSE_Y,
12270   PARSE_WIDTH,
12271   PARSE_HEIGHT,
12272   PARSE_ANCHOR_X,
12273   PARSE_ANCHOR_Y
12274 } ParseDimension;
12275
12276 static gfloat
12277 parse_units (ClutterActor   *self,
12278              ParseDimension  dimension,
12279              JsonNode       *node)
12280 {
12281   GValue value = { 0, };
12282   gfloat retval = 0;
12283
12284   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12285     return 0;
12286
12287   json_node_get_value (node, &value);
12288
12289   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12290     {
12291       retval = (gfloat) g_value_get_int64 (&value);
12292     }
12293   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12294     {
12295       retval = g_value_get_double (&value);
12296     }
12297   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12298     {
12299       ClutterUnits units;
12300       gboolean res;
12301
12302       res = clutter_units_from_string (&units, g_value_get_string (&value));
12303       if (res)
12304         retval = clutter_units_to_pixels (&units);
12305       else
12306         {
12307           g_warning ("Invalid value '%s': integers, strings or floating point "
12308                      "values can be used for the x, y, width and height "
12309                      "properties. Valid modifiers for strings are 'px', 'mm', "
12310                      "'pt' and 'em'.",
12311                      g_value_get_string (&value));
12312           retval = 0;
12313         }
12314     }
12315   else
12316     {
12317       g_warning ("Invalid value of type '%s': integers, strings of floating "
12318                  "point values can be used for the x, y, width, height "
12319                  "anchor-x and anchor-y properties.",
12320                  g_type_name (G_VALUE_TYPE (&value)));
12321     }
12322
12323   g_value_unset (&value);
12324
12325   return retval;
12326 }
12327
12328 typedef struct {
12329   ClutterRotateAxis axis;
12330
12331   gdouble angle;
12332
12333   gfloat center_x;
12334   gfloat center_y;
12335   gfloat center_z;
12336 } RotationInfo;
12337
12338 static inline gboolean
12339 parse_rotation_array (ClutterActor *actor,
12340                       JsonArray    *array,
12341                       RotationInfo *info)
12342 {
12343   JsonNode *element;
12344
12345   if (json_array_get_length (array) != 2)
12346     return FALSE;
12347
12348   /* angle */
12349   element = json_array_get_element (array, 0);
12350   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12351     info->angle = json_node_get_double (element);
12352   else
12353     return FALSE;
12354
12355   /* center */
12356   element = json_array_get_element (array, 1);
12357   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12358     {
12359       JsonArray *center = json_node_get_array (element);
12360
12361       if (json_array_get_length (center) != 2)
12362         return FALSE;
12363
12364       switch (info->axis)
12365         {
12366         case CLUTTER_X_AXIS:
12367           info->center_y = parse_units (actor, PARSE_Y,
12368                                         json_array_get_element (center, 0));
12369           info->center_z = parse_units (actor, PARSE_Y,
12370                                         json_array_get_element (center, 1));
12371           return TRUE;
12372
12373         case CLUTTER_Y_AXIS:
12374           info->center_x = parse_units (actor, PARSE_X,
12375                                         json_array_get_element (center, 0));
12376           info->center_z = parse_units (actor, PARSE_X,
12377                                         json_array_get_element (center, 1));
12378           return TRUE;
12379
12380         case CLUTTER_Z_AXIS:
12381           info->center_x = parse_units (actor, PARSE_X,
12382                                         json_array_get_element (center, 0));
12383           info->center_y = parse_units (actor, PARSE_Y,
12384                                         json_array_get_element (center, 1));
12385           return TRUE;
12386         }
12387     }
12388
12389   return FALSE;
12390 }
12391
12392 static gboolean
12393 parse_rotation (ClutterActor *actor,
12394                 JsonNode     *node,
12395                 RotationInfo *info)
12396 {
12397   JsonArray *array;
12398   guint len, i;
12399   gboolean retval = FALSE;
12400
12401   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12402     {
12403       g_warning ("Invalid node of type '%s' found, expecting an array",
12404                  json_node_type_name (node));
12405       return FALSE;
12406     }
12407
12408   array = json_node_get_array (node);
12409   len = json_array_get_length (array);
12410
12411   for (i = 0; i < len; i++)
12412     {
12413       JsonNode *element = json_array_get_element (array, i);
12414       JsonObject *object;
12415       JsonNode *member;
12416
12417       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12418         {
12419           g_warning ("Invalid node of type '%s' found, expecting an object",
12420                      json_node_type_name (element));
12421           return FALSE;
12422         }
12423
12424       object = json_node_get_object (element);
12425
12426       if (json_object_has_member (object, "x-axis"))
12427         {
12428           member = json_object_get_member (object, "x-axis");
12429
12430           info->axis = CLUTTER_X_AXIS;
12431
12432           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12433             {
12434               info->angle = json_node_get_double (member);
12435               retval = TRUE;
12436             }
12437           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12438             retval = parse_rotation_array (actor,
12439                                            json_node_get_array (member),
12440                                            info);
12441           else
12442             retval = FALSE;
12443         }
12444       else if (json_object_has_member (object, "y-axis"))
12445         {
12446           member = json_object_get_member (object, "y-axis");
12447
12448           info->axis = CLUTTER_Y_AXIS;
12449
12450           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12451             {
12452               info->angle = json_node_get_double (member);
12453               retval = TRUE;
12454             }
12455           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12456             retval = parse_rotation_array (actor,
12457                                            json_node_get_array (member),
12458                                            info);
12459           else
12460             retval = FALSE;
12461         }
12462       else if (json_object_has_member (object, "z-axis"))
12463         {
12464           member = json_object_get_member (object, "z-axis");
12465
12466           info->axis = CLUTTER_Z_AXIS;
12467
12468           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12469             {
12470               info->angle = json_node_get_double (member);
12471               retval = TRUE;
12472             }
12473           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12474             retval = parse_rotation_array (actor,
12475                                            json_node_get_array (member),
12476                                            info);
12477           else
12478             retval = FALSE;
12479         }
12480     }
12481
12482   return retval;
12483 }
12484
12485 static GSList *
12486 parse_actor_metas (ClutterScript *script,
12487                    ClutterActor  *actor,
12488                    JsonNode      *node)
12489 {
12490   GList *elements, *l;
12491   GSList *retval = NULL;
12492
12493   if (!JSON_NODE_HOLDS_ARRAY (node))
12494     return NULL;
12495
12496   elements = json_array_get_elements (json_node_get_array (node));
12497
12498   for (l = elements; l != NULL; l = l->next)
12499     {
12500       JsonNode *element = l->data;
12501       const gchar *id_ = _clutter_script_get_id_from_node (element);
12502       GObject *meta;
12503
12504       if (id_ == NULL || *id_ == '\0')
12505         continue;
12506
12507       meta = clutter_script_get_object (script, id_);
12508       if (meta == NULL)
12509         continue;
12510
12511       retval = g_slist_prepend (retval, meta);
12512     }
12513
12514   g_list_free (elements);
12515
12516   return g_slist_reverse (retval);
12517 }
12518
12519 static GSList *
12520 parse_behaviours (ClutterScript *script,
12521                   ClutterActor  *actor,
12522                   JsonNode      *node)
12523 {
12524   GList *elements, *l;
12525   GSList *retval = NULL;
12526
12527   if (!JSON_NODE_HOLDS_ARRAY (node))
12528     return NULL;
12529
12530   elements = json_array_get_elements (json_node_get_array (node));
12531
12532   for (l = elements; l != NULL; l = l->next)
12533     {
12534       JsonNode *element = l->data;
12535       const gchar *id_ = _clutter_script_get_id_from_node (element);
12536       GObject *behaviour;
12537
12538       if (id_ == NULL || *id_ == '\0')
12539         continue;
12540
12541       behaviour = clutter_script_get_object (script, id_);
12542       if (behaviour == NULL)
12543         continue;
12544
12545       retval = g_slist_prepend (retval, behaviour);
12546     }
12547
12548   g_list_free (elements);
12549
12550   return g_slist_reverse (retval);
12551 }
12552
12553 static gboolean
12554 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12555                                  ClutterScript     *script,
12556                                  GValue            *value,
12557                                  const gchar       *name,
12558                                  JsonNode          *node)
12559 {
12560   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12561   gboolean retval = FALSE;
12562
12563   if ((name[0] == 'x' && name[1] == '\0') ||
12564       (name[0] == 'y' && name[1] == '\0') ||
12565       (strcmp (name, "width") == 0) ||
12566       (strcmp (name, "height") == 0) ||
12567       (strcmp (name, "anchor_x") == 0) ||
12568       (strcmp (name, "anchor_y") == 0))
12569     {
12570       ParseDimension dimension;
12571       gfloat units;
12572
12573       if (name[0] == 'x')
12574         dimension = PARSE_X;
12575       else if (name[0] == 'y')
12576         dimension = PARSE_Y;
12577       else if (name[0] == 'w')
12578         dimension = PARSE_WIDTH;
12579       else if (name[0] == 'h')
12580         dimension = PARSE_HEIGHT;
12581       else if (name[0] == 'a' && name[7] == 'x')
12582         dimension = PARSE_ANCHOR_X;
12583       else if (name[0] == 'a' && name[7] == 'y')
12584         dimension = PARSE_ANCHOR_Y;
12585       else
12586         return FALSE;
12587
12588       units = parse_units (actor, dimension, node);
12589
12590       /* convert back to pixels: all properties are pixel-based */
12591       g_value_init (value, G_TYPE_FLOAT);
12592       g_value_set_float (value, units);
12593
12594       retval = TRUE;
12595     }
12596   else if (strcmp (name, "rotation") == 0)
12597     {
12598       RotationInfo *info;
12599
12600       info = g_slice_new0 (RotationInfo);
12601       retval = parse_rotation (actor, node, info);
12602
12603       if (retval)
12604         {
12605           g_value_init (value, G_TYPE_POINTER);
12606           g_value_set_pointer (value, info);
12607         }
12608       else
12609         g_slice_free (RotationInfo, info);
12610     }
12611   else if (strcmp (name, "behaviours") == 0)
12612     {
12613       GSList *l;
12614
12615 #ifdef CLUTTER_ENABLE_DEBUG
12616       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12617         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12618                                      "and it should not be used in newly "
12619                                      "written ClutterScript definitions.");
12620 #endif
12621
12622       l = parse_behaviours (script, actor, node);
12623
12624       g_value_init (value, G_TYPE_POINTER);
12625       g_value_set_pointer (value, l);
12626
12627       retval = TRUE;
12628     }
12629   else if (strcmp (name, "actions") == 0 ||
12630            strcmp (name, "constraints") == 0 ||
12631            strcmp (name, "effects") == 0)
12632     {
12633       GSList *l;
12634
12635       l = parse_actor_metas (script, actor, node);
12636
12637       g_value_init (value, G_TYPE_POINTER);
12638       g_value_set_pointer (value, l);
12639
12640       retval = TRUE;
12641     }
12642
12643   return retval;
12644 }
12645
12646 static void
12647 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12648                                    ClutterScript     *script,
12649                                    const gchar       *name,
12650                                    const GValue      *value)
12651 {
12652   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12653
12654 #ifdef CLUTTER_ENABLE_DEBUG
12655   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12656     {
12657       gchar *tmp = g_strdup_value_contents (value);
12658
12659       CLUTTER_NOTE (SCRIPT,
12660                     "in ClutterActor::set_custom_property('%s') = %s",
12661                     name,
12662                     tmp);
12663
12664       g_free (tmp);
12665     }
12666 #endif /* CLUTTER_ENABLE_DEBUG */
12667
12668   if (strcmp (name, "rotation") == 0)
12669     {
12670       RotationInfo *info;
12671
12672       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12673         return;
12674
12675       info = g_value_get_pointer (value);
12676
12677       clutter_actor_set_rotation (actor,
12678                                   info->axis, info->angle,
12679                                   info->center_x,
12680                                   info->center_y,
12681                                   info->center_z);
12682
12683       g_slice_free (RotationInfo, info);
12684
12685       return;
12686     }
12687
12688   if (strcmp (name, "behaviours") == 0)
12689     {
12690       GSList *behaviours, *l;
12691
12692       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12693         return;
12694
12695       behaviours = g_value_get_pointer (value);
12696       for (l = behaviours; l != NULL; l = l->next)
12697         {
12698           ClutterBehaviour *behaviour = l->data;
12699
12700           clutter_behaviour_apply (behaviour, actor);
12701         }
12702
12703       g_slist_free (behaviours);
12704
12705       return;
12706     }
12707
12708   if (strcmp (name, "actions") == 0 ||
12709       strcmp (name, "constraints") == 0 ||
12710       strcmp (name, "effects") == 0)
12711     {
12712       GSList *metas, *l;
12713
12714       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12715         return;
12716
12717       metas = g_value_get_pointer (value);
12718       for (l = metas; l != NULL; l = l->next)
12719         {
12720           if (name[0] == 'a')
12721             clutter_actor_add_action (actor, l->data);
12722
12723           if (name[0] == 'c')
12724             clutter_actor_add_constraint (actor, l->data);
12725
12726           if (name[0] == 'e')
12727             clutter_actor_add_effect (actor, l->data);
12728         }
12729
12730       g_slist_free (metas);
12731
12732       return;
12733     }
12734
12735   g_object_set_property (G_OBJECT (scriptable), name, value);
12736 }
12737
12738 static void
12739 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12740 {
12741   iface->parse_custom_node = clutter_actor_parse_custom_node;
12742   iface->set_custom_property = clutter_actor_set_custom_property;
12743 }
12744
12745 static ClutterActorMeta *
12746 get_meta_from_animation_property (ClutterActor  *actor,
12747                                   const gchar   *name,
12748                                   gchar        **name_p)
12749 {
12750   ClutterActorPrivate *priv = actor->priv;
12751   ClutterActorMeta *meta = NULL;
12752   gchar **tokens;
12753
12754   /* if this is not a special property, fall through */
12755   if (name[0] != '@')
12756     return NULL;
12757
12758   /* detect the properties named using the following spec:
12759    *
12760    *   @<section>.<meta-name>.<property-name>
12761    *
12762    * where <section> can be one of the following:
12763    *
12764    *   - actions
12765    *   - constraints
12766    *   - effects
12767    *
12768    * and <meta-name> is the name set on a specific ActorMeta
12769    */
12770
12771   tokens = g_strsplit (name + 1, ".", -1);
12772   if (tokens == NULL || g_strv_length (tokens) != 3)
12773     {
12774       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12775                     name + 1);
12776       g_strfreev (tokens);
12777       return NULL;
12778     }
12779
12780   if (strcmp (tokens[0], "actions") == 0)
12781     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12782
12783   if (strcmp (tokens[0], "constraints") == 0)
12784     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12785
12786   if (strcmp (tokens[0], "effects") == 0)
12787     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12788
12789   if (name_p != NULL)
12790     *name_p = g_strdup (tokens[2]);
12791
12792   CLUTTER_NOTE (ANIMATION,
12793                 "Looking for property '%s' of object '%s' in section '%s'",
12794                 tokens[2],
12795                 tokens[1],
12796                 tokens[0]);
12797
12798   g_strfreev (tokens);
12799
12800   return meta;
12801 }
12802
12803 static GParamSpec *
12804 clutter_actor_find_property (ClutterAnimatable *animatable,
12805                              const gchar       *property_name)
12806 {
12807   ClutterActorMeta *meta = NULL;
12808   GObjectClass *klass = NULL;
12809   GParamSpec *pspec = NULL;
12810   gchar *p_name = NULL;
12811
12812   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12813                                            property_name,
12814                                            &p_name);
12815
12816   if (meta != NULL)
12817     {
12818       klass = G_OBJECT_GET_CLASS (meta);
12819
12820       pspec = g_object_class_find_property (klass, p_name);
12821     }
12822   else
12823     {
12824       klass = G_OBJECT_GET_CLASS (animatable);
12825
12826       pspec = g_object_class_find_property (klass, property_name);
12827     }
12828
12829   g_free (p_name);
12830
12831   return pspec;
12832 }
12833
12834 static void
12835 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12836                                  const gchar       *property_name,
12837                                  GValue            *initial)
12838 {
12839   ClutterActorMeta *meta = NULL;
12840   gchar *p_name = NULL;
12841
12842   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12843                                            property_name,
12844                                            &p_name);
12845
12846   if (meta != NULL)
12847     g_object_get_property (G_OBJECT (meta), p_name, initial);
12848   else
12849     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12850
12851   g_free (p_name);
12852 }
12853
12854 /*
12855  * clutter_actor_set_animatable_property:
12856  * @actor: a #ClutterActor
12857  * @prop_id: the paramspec id
12858  * @value: the value to set
12859  * @pspec: the paramspec
12860  *
12861  * Sets values of animatable properties.
12862  *
12863  * This is a variant of clutter_actor_set_property() that gets called
12864  * by the #ClutterAnimatable implementation of #ClutterActor for the
12865  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12866  * #GParamSpec.
12867  *
12868  * Unlike the implementation of #GObjectClass.set_property(), this
12869  * function will not update the interval if a transition involving an
12870  * animatable property is in progress - this avoids cycles with the
12871  * transition API calling the public API.
12872  */
12873 static void
12874 clutter_actor_set_animatable_property (ClutterActor *actor,
12875                                        guint         prop_id,
12876                                        const GValue *value,
12877                                        GParamSpec   *pspec)
12878 {
12879   switch (prop_id)
12880     {
12881     case PROP_X:
12882       clutter_actor_set_x_internal (actor, g_value_get_float (value));
12883       break;
12884
12885     case PROP_Y:
12886       clutter_actor_set_y_internal (actor, g_value_get_float (value));
12887       break;
12888
12889     case PROP_WIDTH:
12890       clutter_actor_set_width_internal (actor, g_value_get_float (value));
12891       break;
12892
12893     case PROP_HEIGHT:
12894       clutter_actor_set_height_internal (actor, g_value_get_float (value));
12895       break;
12896
12897     case PROP_DEPTH:
12898       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12899       break;
12900
12901     case PROP_OPACITY:
12902       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12903       break;
12904
12905     case PROP_BACKGROUND_COLOR:
12906       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12907       break;
12908
12909     case PROP_SCALE_X:
12910       clutter_actor_set_scale_factor_internal (actor,
12911                                                g_value_get_double (value),
12912                                                pspec);
12913       break;
12914
12915     case PROP_SCALE_Y:
12916       clutter_actor_set_scale_factor_internal (actor,
12917                                                g_value_get_double (value),
12918                                                pspec);
12919       break;
12920
12921     case PROP_ROTATION_ANGLE_X:
12922       clutter_actor_set_rotation_angle_internal (actor,
12923                                                  CLUTTER_X_AXIS,
12924                                                  g_value_get_double (value));
12925       break;
12926
12927     case PROP_ROTATION_ANGLE_Y:
12928       clutter_actor_set_rotation_angle_internal (actor,
12929                                                  CLUTTER_Y_AXIS,
12930                                                  g_value_get_double (value));
12931       break;
12932
12933     case PROP_ROTATION_ANGLE_Z:
12934       clutter_actor_set_rotation_angle_internal (actor,
12935                                                  CLUTTER_Z_AXIS,
12936                                                  g_value_get_double (value));
12937       break;
12938
12939     default:
12940       g_object_set_property (G_OBJECT (actor), pspec->name, value);
12941       break;
12942     }
12943 }
12944
12945 static void
12946 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12947                                const gchar       *property_name,
12948                                const GValue      *final)
12949 {
12950   ClutterActor *actor = CLUTTER_ACTOR (animatable);
12951   ClutterActorMeta *meta = NULL;
12952   gchar *p_name = NULL;
12953
12954   meta = get_meta_from_animation_property (actor,
12955                                            property_name,
12956                                            &p_name);
12957   if (meta != NULL)
12958     g_object_set_property (G_OBJECT (meta), p_name, final);
12959   else
12960     {
12961       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12962       GParamSpec *pspec;
12963
12964       pspec = g_object_class_find_property (obj_class, property_name);
12965
12966       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12967         {
12968           /* XXX - I'm going to the special hell for this */
12969           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12970         }
12971       else
12972         g_object_set_property (G_OBJECT (animatable), property_name, final);
12973     }
12974
12975   g_free (p_name);
12976 }
12977
12978 static void
12979 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12980 {
12981   iface->find_property = clutter_actor_find_property;
12982   iface->get_initial_state = clutter_actor_get_initial_state;
12983   iface->set_final_state = clutter_actor_set_final_state;
12984 }
12985
12986 /**
12987  * clutter_actor_transform_stage_point:
12988  * @self: A #ClutterActor
12989  * @x: (in): x screen coordinate of the point to unproject
12990  * @y: (in): y screen coordinate of the point to unproject
12991  * @x_out: (out): return location for the unprojected x coordinance
12992  * @y_out: (out): return location for the unprojected y coordinance
12993  *
12994  * This function translates screen coordinates (@x, @y) to
12995  * coordinates relative to the actor. For example, it can be used to translate
12996  * screen events from global screen coordinates into actor-local coordinates.
12997  *
12998  * The conversion can fail, notably if the transform stack results in the
12999  * actor being projected on the screen as a mere line.
13000  *
13001  * The conversion should not be expected to be pixel-perfect due to the
13002  * nature of the operation. In general the error grows when the skewing
13003  * of the actor rectangle on screen increases.
13004  *
13005  * <note><para>This function can be computationally intensive.</para></note>
13006  *
13007  * <note><para>This function only works when the allocation is up-to-date,
13008  * i.e. inside of paint().</para></note>
13009  *
13010  * Return value: %TRUE if conversion was successful.
13011  *
13012  * Since: 0.6
13013  */
13014 gboolean
13015 clutter_actor_transform_stage_point (ClutterActor *self,
13016                                      gfloat        x,
13017                                      gfloat        y,
13018                                      gfloat       *x_out,
13019                                      gfloat       *y_out)
13020 {
13021   ClutterVertex v[4];
13022   float ST[3][3];
13023   float RQ[3][3];
13024   int du, dv, xi, yi;
13025   float px, py;
13026   float xf, yf, wf, det;
13027   ClutterActorPrivate *priv;
13028
13029   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13030
13031   priv = self->priv;
13032
13033   /* This implementation is based on the quad -> quad projection algorithm
13034    * described by Paul Heckbert in:
13035    *
13036    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13037    *
13038    * and the sample implementation at:
13039    *
13040    *   http://www.cs.cmu.edu/~ph/src/texfund/
13041    *
13042    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13043    * quad to rectangle only, which significantly simplifies things; the
13044    * function calls have been unrolled, and most of the math is done in fixed
13045    * point.
13046    */
13047
13048   clutter_actor_get_abs_allocation_vertices (self, v);
13049
13050   /* Keeping these as ints simplifies the multiplication (no significant
13051    * loss of precision here).
13052    */
13053   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13054   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13055
13056   if (!du || !dv)
13057     return FALSE;
13058
13059 #define UX2FP(x)        (x)
13060 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13061
13062   /* First, find mapping from unit uv square to xy quadrilateral; this
13063    * equivalent to the pmap_square_quad() functions in the sample
13064    * implementation, which we can simplify, since our target is always
13065    * a rectangle.
13066    */
13067   px = v[0].x - v[1].x + v[3].x - v[2].x;
13068   py = v[0].y - v[1].y + v[3].y - v[2].y;
13069
13070   if (!px && !py)
13071     {
13072       /* affine transform */
13073       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13074       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13075       RQ[2][0] = UX2FP (v[0].x);
13076       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13077       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13078       RQ[2][1] = UX2FP (v[0].y);
13079       RQ[0][2] = 0;
13080       RQ[1][2] = 0;
13081       RQ[2][2] = 1.0;
13082     }
13083   else
13084     {
13085       /* projective transform */
13086       double dx1, dx2, dy1, dy2, del;
13087
13088       dx1 = UX2FP (v[1].x - v[3].x);
13089       dx2 = UX2FP (v[2].x - v[3].x);
13090       dy1 = UX2FP (v[1].y - v[3].y);
13091       dy2 = UX2FP (v[2].y - v[3].y);
13092
13093       del = DET2FP (dx1, dx2, dy1, dy2);
13094       if (!del)
13095         return FALSE;
13096
13097       /*
13098        * The division here needs to be done in floating point for
13099        * precisions reasons.
13100        */
13101       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13102       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13103       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13104       RQ[2][2] = 1.0;
13105       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13106       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13107       RQ[2][0] = UX2FP (v[0].x);
13108       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13109       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13110       RQ[2][1] = UX2FP (v[0].y);
13111     }
13112
13113   /*
13114    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13115    * square. Since our rectangle is based at 0,0 we only need to scale.
13116    */
13117   RQ[0][0] /= du;
13118   RQ[1][0] /= dv;
13119   RQ[0][1] /= du;
13120   RQ[1][1] /= dv;
13121   RQ[0][2] /= du;
13122   RQ[1][2] /= dv;
13123
13124   /*
13125    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13126    * inverse of that.
13127    */
13128   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13129   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13130   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13131   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13132   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13133   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13134   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13135   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13136   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13137
13138   /*
13139    * Check the resulting matrix is OK.
13140    */
13141   det = (RQ[0][0] * ST[0][0])
13142       + (RQ[0][1] * ST[0][1])
13143       + (RQ[0][2] * ST[0][2]);
13144   if (!det)
13145     return FALSE;
13146
13147   /*
13148    * Now transform our point with the ST matrix; the notional w
13149    * coordinate is 1, hence the last part is simply added.
13150    */
13151   xi = (int) x;
13152   yi = (int) y;
13153
13154   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13155   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13156   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13157
13158   if (x_out)
13159     *x_out = xf / wf;
13160
13161   if (y_out)
13162     *y_out = yf / wf;
13163
13164 #undef UX2FP
13165 #undef DET2FP
13166
13167   return TRUE;
13168 }
13169
13170 /*
13171  * ClutterGeometry
13172  */
13173
13174 static ClutterGeometry*
13175 clutter_geometry_copy (const ClutterGeometry *geometry)
13176 {
13177   return g_slice_dup (ClutterGeometry, geometry);
13178 }
13179
13180 static void
13181 clutter_geometry_free (ClutterGeometry *geometry)
13182 {
13183   if (G_LIKELY (geometry != NULL))
13184     g_slice_free (ClutterGeometry, geometry);
13185 }
13186
13187 /**
13188  * clutter_geometry_union:
13189  * @geometry_a: a #ClutterGeometry
13190  * @geometry_b: another #ClutterGeometry
13191  * @result: (out): location to store the result
13192  *
13193  * Find the union of two rectangles represented as #ClutterGeometry.
13194  *
13195  * Since: 1.4
13196  */
13197 void
13198 clutter_geometry_union (const ClutterGeometry *geometry_a,
13199                         const ClutterGeometry *geometry_b,
13200                         ClutterGeometry       *result)
13201 {
13202   /* We don't try to handle rectangles that can't be represented
13203    * as a signed integer box */
13204   gint x_1 = MIN (geometry_a->x, geometry_b->x);
13205   gint y_1 = MIN (geometry_a->y, geometry_b->y);
13206   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13207                   geometry_b->x + (gint)geometry_b->width);
13208   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13209                   geometry_b->y + (gint)geometry_b->height);
13210   result->x = x_1;
13211   result->y = y_1;
13212   result->width = x_2 - x_1;
13213   result->height = y_2 - y_1;
13214 }
13215
13216 /**
13217  * clutter_geometry_intersects:
13218  * @geometry0: The first geometry to test
13219  * @geometry1: The second geometry to test
13220  *
13221  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13222  * they do else %FALSE.
13223  *
13224  * Return value: %TRUE of @geometry0 and geometry1 intersect else
13225  * %FALSE.
13226  *
13227  * Since: 1.4
13228  */
13229 gboolean
13230 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13231                              const ClutterGeometry *geometry1)
13232 {
13233   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13234       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13235       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13236       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13237     return FALSE;
13238   else
13239     return TRUE;
13240 }
13241
13242 static gboolean
13243 clutter_geometry_progress (const GValue *a,
13244                            const GValue *b,
13245                            gdouble       progress,
13246                            GValue       *retval)
13247 {
13248   const ClutterGeometry *a_geom = g_value_get_boxed (a);
13249   const ClutterGeometry *b_geom = g_value_get_boxed (b);
13250   ClutterGeometry res = { 0, };
13251   gint a_width = a_geom->width;
13252   gint b_width = b_geom->width;
13253   gint a_height = a_geom->height;
13254   gint b_height = b_geom->height;
13255
13256   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13257   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13258
13259   res.width = a_width + (b_width - a_width) * progress;
13260   res.height = a_height + (b_height - a_height) * progress;
13261
13262   g_value_set_boxed (retval, &res);
13263
13264   return TRUE;
13265 }
13266
13267 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13268                                clutter_geometry_copy,
13269                                clutter_geometry_free,
13270                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13271
13272 /*
13273  * ClutterVertices
13274  */
13275
13276 /**
13277  * clutter_vertex_new:
13278  * @x: X coordinate
13279  * @y: Y coordinate
13280  * @z: Z coordinate
13281  *
13282  * Creates a new #ClutterVertex for the point in 3D space
13283  * identified by the 3 coordinates @x, @y, @z
13284  *
13285  * Return value: the newly allocate #ClutterVertex. Use
13286  *   clutter_vertex_free() to free the resources
13287  *
13288  * Since: 1.0
13289  */
13290 ClutterVertex *
13291 clutter_vertex_new (gfloat x,
13292                     gfloat y,
13293                     gfloat z)
13294 {
13295   ClutterVertex *vertex;
13296
13297   vertex = g_slice_new (ClutterVertex);
13298   vertex->x = x;
13299   vertex->y = y;
13300   vertex->z = z;
13301
13302   return vertex;
13303 }
13304
13305 /**
13306  * clutter_vertex_copy:
13307  * @vertex: a #ClutterVertex
13308  *
13309  * Copies @vertex
13310  *
13311  * Return value: a newly allocated copy of #ClutterVertex. Use
13312  *   clutter_vertex_free() to free the allocated resources
13313  *
13314  * Since: 1.0
13315  */
13316 ClutterVertex *
13317 clutter_vertex_copy (const ClutterVertex *vertex)
13318 {
13319   if (G_LIKELY (vertex != NULL))
13320     return g_slice_dup (ClutterVertex, vertex);
13321
13322   return NULL;
13323 }
13324
13325 /**
13326  * clutter_vertex_free:
13327  * @vertex: a #ClutterVertex
13328  *
13329  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13330  *
13331  * Since: 1.0
13332  */
13333 void
13334 clutter_vertex_free (ClutterVertex *vertex)
13335 {
13336   if (G_UNLIKELY (vertex != NULL))
13337     g_slice_free (ClutterVertex, vertex);
13338 }
13339
13340 /**
13341  * clutter_vertex_equal:
13342  * @vertex_a: a #ClutterVertex
13343  * @vertex_b: a #ClutterVertex
13344  *
13345  * Compares @vertex_a and @vertex_b for equality
13346  *
13347  * Return value: %TRUE if the passed #ClutterVertex are equal
13348  *
13349  * Since: 1.0
13350  */
13351 gboolean
13352 clutter_vertex_equal (const ClutterVertex *vertex_a,
13353                       const ClutterVertex *vertex_b)
13354 {
13355   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13356
13357   if (vertex_a == vertex_b)
13358     return TRUE;
13359
13360   return vertex_a->x == vertex_b->x &&
13361          vertex_a->y == vertex_b->y &&
13362          vertex_a->z == vertex_b->z;
13363 }
13364
13365 static gboolean
13366 clutter_vertex_progress (const GValue *a,
13367                          const GValue *b,
13368                          gdouble       progress,
13369                          GValue       *retval)
13370 {
13371   const ClutterVertex *av = g_value_get_boxed (a);
13372   const ClutterVertex *bv = g_value_get_boxed (b);
13373   ClutterVertex res = { 0, };
13374
13375   res.x = av->x + (bv->x - av->x) * progress;
13376   res.y = av->y + (bv->y - av->y) * progress;
13377   res.z = av->z + (bv->z - av->z) * progress;
13378
13379   g_value_set_boxed (retval, &res);
13380
13381   return TRUE;
13382 }
13383
13384 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13385                                clutter_vertex_copy,
13386                                clutter_vertex_free,
13387                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13388
13389 /**
13390  * clutter_actor_is_rotated:
13391  * @self: a #ClutterActor
13392  *
13393  * Checks whether any rotation is applied to the actor.
13394  *
13395  * Return value: %TRUE if the actor is rotated.
13396  *
13397  * Since: 0.6
13398  */
13399 gboolean
13400 clutter_actor_is_rotated (ClutterActor *self)
13401 {
13402   const ClutterTransformInfo *info;
13403
13404   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13405
13406   info = _clutter_actor_get_transform_info_or_defaults (self);
13407
13408   if (info->rx_angle || info->ry_angle || info->rz_angle)
13409     return TRUE;
13410
13411   return FALSE;
13412 }
13413
13414 /**
13415  * clutter_actor_is_scaled:
13416  * @self: a #ClutterActor
13417  *
13418  * Checks whether the actor is scaled in either dimension.
13419  *
13420  * Return value: %TRUE if the actor is scaled.
13421  *
13422  * Since: 0.6
13423  */
13424 gboolean
13425 clutter_actor_is_scaled (ClutterActor *self)
13426 {
13427   const ClutterTransformInfo *info;
13428
13429   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13430
13431   info = _clutter_actor_get_transform_info_or_defaults (self);
13432
13433   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13434     return TRUE;
13435
13436   return FALSE;
13437 }
13438
13439 ClutterActor *
13440 _clutter_actor_get_stage_internal (ClutterActor *actor)
13441 {
13442   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13443     actor = actor->priv->parent;
13444
13445   return actor;
13446 }
13447
13448 /**
13449  * clutter_actor_get_stage:
13450  * @actor: a #ClutterActor
13451  *
13452  * Retrieves the #ClutterStage where @actor is contained.
13453  *
13454  * Return value: (transfer none) (type Clutter.Stage): the stage
13455  *   containing the actor, or %NULL
13456  *
13457  * Since: 0.8
13458  */
13459 ClutterActor *
13460 clutter_actor_get_stage (ClutterActor *actor)
13461 {
13462   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13463
13464   return _clutter_actor_get_stage_internal (actor);
13465 }
13466
13467 /**
13468  * clutter_actor_allocate_available_size:
13469  * @self: a #ClutterActor
13470  * @x: the actor's X coordinate
13471  * @y: the actor's Y coordinate
13472  * @available_width: the maximum available width, or -1 to use the
13473  *   actor's natural width
13474  * @available_height: the maximum available height, or -1 to use the
13475  *   actor's natural height
13476  * @flags: flags controlling the allocation
13477  *
13478  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13479  * preferred size, but limiting it to the maximum available width
13480  * and height provided.
13481  *
13482  * This function will do the right thing when dealing with the
13483  * actor's request mode.
13484  *
13485  * The implementation of this function is equivalent to:
13486  *
13487  * |[
13488  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13489  *     {
13490  *       clutter_actor_get_preferred_width (self, available_height,
13491  *                                          &amp;min_width,
13492  *                                          &amp;natural_width);
13493  *       width = CLAMP (natural_width, min_width, available_width);
13494  *
13495  *       clutter_actor_get_preferred_height (self, width,
13496  *                                           &amp;min_height,
13497  *                                           &amp;natural_height);
13498  *       height = CLAMP (natural_height, min_height, available_height);
13499  *     }
13500  *   else
13501  *     {
13502  *       clutter_actor_get_preferred_height (self, available_width,
13503  *                                           &amp;min_height,
13504  *                                           &amp;natural_height);
13505  *       height = CLAMP (natural_height, min_height, available_height);
13506  *
13507  *       clutter_actor_get_preferred_width (self, height,
13508  *                                          &amp;min_width,
13509  *                                          &amp;natural_width);
13510  *       width = CLAMP (natural_width, min_width, available_width);
13511  *     }
13512  *
13513  *   box.x1 = x; box.y1 = y;
13514  *   box.x2 = box.x1 + available_width;
13515  *   box.y2 = box.y1 + available_height;
13516  *   clutter_actor_allocate (self, &amp;box, flags);
13517  * ]|
13518  *
13519  * This function can be used by fluid layout managers to allocate
13520  * an actor's preferred size without making it bigger than the area
13521  * available for the container.
13522  *
13523  * Since: 1.0
13524  */
13525 void
13526 clutter_actor_allocate_available_size (ClutterActor           *self,
13527                                        gfloat                  x,
13528                                        gfloat                  y,
13529                                        gfloat                  available_width,
13530                                        gfloat                  available_height,
13531                                        ClutterAllocationFlags  flags)
13532 {
13533   ClutterActorPrivate *priv;
13534   gfloat width, height;
13535   gfloat min_width, min_height;
13536   gfloat natural_width, natural_height;
13537   ClutterActorBox box;
13538
13539   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13540
13541   priv = self->priv;
13542
13543   width = height = 0.0;
13544
13545   switch (priv->request_mode)
13546     {
13547     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13548       clutter_actor_get_preferred_width (self, available_height,
13549                                          &min_width,
13550                                          &natural_width);
13551       width  = CLAMP (natural_width, min_width, available_width);
13552
13553       clutter_actor_get_preferred_height (self, width,
13554                                           &min_height,
13555                                           &natural_height);
13556       height = CLAMP (natural_height, min_height, available_height);
13557       break;
13558
13559     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13560       clutter_actor_get_preferred_height (self, available_width,
13561                                           &min_height,
13562                                           &natural_height);
13563       height = CLAMP (natural_height, min_height, available_height);
13564
13565       clutter_actor_get_preferred_width (self, height,
13566                                          &min_width,
13567                                          &natural_width);
13568       width  = CLAMP (natural_width, min_width, available_width);
13569       break;
13570     }
13571
13572
13573   box.x1 = x;
13574   box.y1 = y;
13575   box.x2 = box.x1 + width;
13576   box.y2 = box.y1 + height;
13577   clutter_actor_allocate (self, &box, flags);
13578 }
13579
13580 /**
13581  * clutter_actor_allocate_preferred_size:
13582  * @self: a #ClutterActor
13583  * @flags: flags controlling the allocation
13584  *
13585  * Allocates the natural size of @self.
13586  *
13587  * This function is a utility call for #ClutterActor implementations
13588  * that allocates the actor's preferred natural size. It can be used
13589  * by fixed layout managers (like #ClutterGroup or so called
13590  * 'composite actors') inside the ClutterActor::allocate
13591  * implementation to give each child exactly how much space it
13592  * requires.
13593  *
13594  * This function is not meant to be used by applications. It is also
13595  * not meant to be used outside the implementation of the
13596  * ClutterActor::allocate virtual function.
13597  *
13598  * Since: 0.8
13599  */
13600 void
13601 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13602                                        ClutterAllocationFlags  flags)
13603 {
13604   gfloat actor_x, actor_y;
13605   gfloat natural_width, natural_height;
13606   ClutterActorBox actor_box;
13607
13608   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13609
13610   actor_x = clutter_actor_get_x (self);
13611   actor_y = clutter_actor_get_y (self);
13612
13613   clutter_actor_get_preferred_size (self,
13614                                     NULL, NULL,
13615                                     &natural_width,
13616                                     &natural_height);
13617
13618   actor_box.x1 = actor_x;
13619   actor_box.y1 = actor_y;
13620   actor_box.x2 = actor_box.x1 + natural_width;
13621   actor_box.y2 = actor_box.y1 + natural_height;
13622
13623   clutter_actor_allocate (self, &actor_box, flags);
13624 }
13625
13626 /**
13627  * clutter_actor_allocate_align_fill:
13628  * @self: a #ClutterActor
13629  * @box: a #ClutterActorBox, containing the available width and height
13630  * @x_align: the horizontal alignment, between 0 and 1
13631  * @y_align: the vertical alignment, between 0 and 1
13632  * @x_fill: whether the actor should fill horizontally
13633  * @y_fill: whether the actor should fill vertically
13634  * @flags: allocation flags to be passed to clutter_actor_allocate()
13635  *
13636  * Allocates @self by taking into consideration the available allocation
13637  * area; an alignment factor on either axis; and whether the actor should
13638  * fill the allocation on either axis.
13639  *
13640  * The @box should contain the available allocation width and height;
13641  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13642  * allocation will be offset by their value.
13643  *
13644  * This function takes into consideration the geometry request specified by
13645  * the #ClutterActor:request-mode property, and the text direction.
13646  *
13647  * This function is useful for fluid layout managers, like #ClutterBinLayout
13648  * or #ClutterTableLayout
13649  *
13650  * Since: 1.4
13651  */
13652 void
13653 clutter_actor_allocate_align_fill (ClutterActor           *self,
13654                                    const ClutterActorBox  *box,
13655                                    gdouble                 x_align,
13656                                    gdouble                 y_align,
13657                                    gboolean                x_fill,
13658                                    gboolean                y_fill,
13659                                    ClutterAllocationFlags  flags)
13660 {
13661   ClutterActorPrivate *priv;
13662   ClutterActorBox allocation = { 0, };
13663   gfloat x_offset, y_offset;
13664   gfloat available_width, available_height;
13665   gfloat child_width, child_height;
13666
13667   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13668   g_return_if_fail (box != NULL);
13669   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13670   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13671
13672   priv = self->priv;
13673
13674   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13675   clutter_actor_box_get_size (box, &available_width, &available_height);
13676
13677   if (available_width < 0)
13678     available_width = 0;
13679
13680   if (available_height < 0)
13681     available_height = 0;
13682
13683   if (x_fill)
13684     {
13685       allocation.x1 = x_offset;
13686       allocation.x2 = allocation.x1 + available_width;
13687     }
13688
13689   if (y_fill)
13690     {
13691       allocation.y1 = y_offset;
13692       allocation.y2 = allocation.y1 + available_height;
13693     }
13694
13695   /* if we are filling horizontally and vertically then we're done */
13696   if (x_fill && y_fill)
13697     goto out;
13698
13699   child_width = child_height = 0.0f;
13700
13701   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13702     {
13703       gfloat min_width, natural_width;
13704       gfloat min_height, natural_height;
13705
13706       clutter_actor_get_preferred_width (self, available_height,
13707                                          &min_width,
13708                                          &natural_width);
13709
13710       child_width = CLAMP (natural_width, min_width, available_width);
13711
13712       if (!y_fill)
13713         {
13714           clutter_actor_get_preferred_height (self, child_width,
13715                                               &min_height,
13716                                               &natural_height);
13717
13718           child_height = CLAMP (natural_height, min_height, available_height);
13719         }
13720     }
13721   else
13722     {
13723       gfloat min_width, natural_width;
13724       gfloat min_height, natural_height;
13725
13726       clutter_actor_get_preferred_height (self, available_width,
13727                                           &min_height,
13728                                           &natural_height);
13729
13730       child_height = CLAMP (natural_height, min_height, available_height);
13731
13732       if (!x_fill)
13733         {
13734           clutter_actor_get_preferred_width (self, child_height,
13735                                              &min_width,
13736                                              &natural_width);
13737
13738           child_width = CLAMP (natural_width, min_width, available_width);
13739         }
13740     }
13741
13742   /* invert the horizontal alignment for RTL languages */
13743   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13744     x_align = 1.0 - x_align;
13745
13746   if (!x_fill)
13747     {
13748       allocation.x1 = x_offset
13749                     + ((available_width - child_width) * x_align);
13750       allocation.x2 = allocation.x1 + child_width;
13751     }
13752
13753   if (!y_fill)
13754     {
13755       allocation.y1 = y_offset
13756                     + ((available_height - child_height) * y_align);
13757       allocation.y2 = allocation.y1 + child_height;
13758     }
13759
13760 out:
13761   clutter_actor_box_clamp_to_pixel (&allocation);
13762   clutter_actor_allocate (self, &allocation, flags);
13763 }
13764
13765 /**
13766  * clutter_actor_grab_key_focus:
13767  * @self: a #ClutterActor
13768  *
13769  * Sets the key focus of the #ClutterStage including @self
13770  * to this #ClutterActor.
13771  *
13772  * Since: 1.0
13773  */
13774 void
13775 clutter_actor_grab_key_focus (ClutterActor *self)
13776 {
13777   ClutterActor *stage;
13778
13779   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13780
13781   stage = _clutter_actor_get_stage_internal (self);
13782   if (stage != NULL)
13783     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13784 }
13785
13786 /**
13787  * clutter_actor_get_pango_context:
13788  * @self: a #ClutterActor
13789  *
13790  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13791  * is already configured using the appropriate font map, resolution
13792  * and font options.
13793  *
13794  * Unlike clutter_actor_create_pango_context(), this context is owend
13795  * by the #ClutterActor and it will be updated each time the options
13796  * stored by the #ClutterBackend change.
13797  *
13798  * You can use the returned #PangoContext to create a #PangoLayout
13799  * and render text using cogl_pango_render_layout() to reuse the
13800  * glyphs cache also used by Clutter.
13801  *
13802  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13803  *   The returned #PangoContext is owned by the actor and should not be
13804  *   unreferenced by the application code
13805  *
13806  * Since: 1.0
13807  */
13808 PangoContext *
13809 clutter_actor_get_pango_context (ClutterActor *self)
13810 {
13811   ClutterActorPrivate *priv;
13812
13813   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13814
13815   priv = self->priv;
13816
13817   if (priv->pango_context != NULL)
13818     return priv->pango_context;
13819
13820   priv->pango_context = _clutter_context_get_pango_context ();
13821   g_object_ref (priv->pango_context);
13822
13823   return priv->pango_context;
13824 }
13825
13826 /**
13827  * clutter_actor_create_pango_context:
13828  * @self: a #ClutterActor
13829  *
13830  * Creates a #PangoContext for the given actor. The #PangoContext
13831  * is already configured using the appropriate font map, resolution
13832  * and font options.
13833  *
13834  * See also clutter_actor_get_pango_context().
13835  *
13836  * Return value: (transfer full): the newly created #PangoContext.
13837  *   Use g_object_unref() on the returned value to deallocate its
13838  *   resources
13839  *
13840  * Since: 1.0
13841  */
13842 PangoContext *
13843 clutter_actor_create_pango_context (ClutterActor *self)
13844 {
13845   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13846
13847   return _clutter_context_create_pango_context ();
13848 }
13849
13850 /**
13851  * clutter_actor_create_pango_layout:
13852  * @self: a #ClutterActor
13853  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13854  *
13855  * Creates a new #PangoLayout from the same #PangoContext used
13856  * by the #ClutterActor. The #PangoLayout is already configured
13857  * with the font map, resolution and font options, and the
13858  * given @text.
13859  *
13860  * If you want to keep around a #PangoLayout created by this
13861  * function you will have to connect to the #ClutterBackend::font-changed
13862  * and #ClutterBackend::resolution-changed signals, and call
13863  * pango_layout_context_changed() in response to them.
13864  *
13865  * Return value: (transfer full): the newly created #PangoLayout.
13866  *   Use g_object_unref() when done
13867  *
13868  * Since: 1.0
13869  */
13870 PangoLayout *
13871 clutter_actor_create_pango_layout (ClutterActor *self,
13872                                    const gchar  *text)
13873 {
13874   PangoContext *context;
13875   PangoLayout *layout;
13876
13877   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13878
13879   context = clutter_actor_get_pango_context (self);
13880   layout = pango_layout_new (context);
13881
13882   if (text)
13883     pango_layout_set_text (layout, text, -1);
13884
13885   return layout;
13886 }
13887
13888 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13889  * ClutterOffscreenEffect.
13890  */
13891 void
13892 _clutter_actor_set_opacity_override (ClutterActor *self,
13893                                      gint          opacity)
13894 {
13895   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13896
13897   self->priv->opacity_override = opacity;
13898 }
13899
13900 gint
13901 _clutter_actor_get_opacity_override (ClutterActor *self)
13902 {
13903   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13904
13905   return self->priv->opacity_override;
13906 }
13907
13908 /* Allows you to disable applying the actors model view transform during
13909  * a paint. Used by ClutterClone. */
13910 void
13911 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13912                                                 gboolean      enable)
13913 {
13914   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13915
13916   self->priv->enable_model_view_transform = enable;
13917 }
13918
13919 void
13920 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13921                                           gboolean      enable)
13922 {
13923   ClutterActorPrivate *priv;
13924
13925   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13926
13927   priv = self->priv;
13928
13929   priv->enable_paint_unmapped = enable;
13930
13931   if (priv->enable_paint_unmapped)
13932     {
13933       /* Make sure that the parents of the widget are realized first;
13934        * otherwise checks in clutter_actor_update_map_state() will
13935        * fail.
13936        */
13937       clutter_actor_realize (self);
13938
13939       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13940     }
13941   else
13942     {
13943       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13944     }
13945 }
13946
13947 static void
13948 clutter_anchor_coord_get_units (ClutterActor      *self,
13949                                 const AnchorCoord *coord,
13950                                 gfloat            *x,
13951                                 gfloat            *y,
13952                                 gfloat            *z)
13953 {
13954   if (coord->is_fractional)
13955     {
13956       gfloat actor_width, actor_height;
13957
13958       clutter_actor_get_size (self, &actor_width, &actor_height);
13959
13960       if (x)
13961         *x = actor_width * coord->v.fraction.x;
13962
13963       if (y)
13964         *y = actor_height * coord->v.fraction.y;
13965
13966       if (z)
13967         *z = 0;
13968     }
13969   else
13970     {
13971       if (x)
13972         *x = coord->v.units.x;
13973
13974       if (y)
13975         *y = coord->v.units.y;
13976
13977       if (z)
13978         *z = coord->v.units.z;
13979     }
13980 }
13981
13982 static void
13983 clutter_anchor_coord_set_units (AnchorCoord *coord,
13984                                 gfloat       x,
13985                                 gfloat       y,
13986                                 gfloat       z)
13987 {
13988   coord->is_fractional = FALSE;
13989   coord->v.units.x = x;
13990   coord->v.units.y = y;
13991   coord->v.units.z = z;
13992 }
13993
13994 static ClutterGravity
13995 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13996 {
13997   if (coord->is_fractional)
13998     {
13999       if (coord->v.fraction.x == 0.0)
14000         {
14001           if (coord->v.fraction.y == 0.0)
14002             return CLUTTER_GRAVITY_NORTH_WEST;
14003           else if (coord->v.fraction.y == 0.5)
14004             return CLUTTER_GRAVITY_WEST;
14005           else if (coord->v.fraction.y == 1.0)
14006             return CLUTTER_GRAVITY_SOUTH_WEST;
14007           else
14008             return CLUTTER_GRAVITY_NONE;
14009         }
14010       else if (coord->v.fraction.x == 0.5)
14011         {
14012           if (coord->v.fraction.y == 0.0)
14013             return CLUTTER_GRAVITY_NORTH;
14014           else if (coord->v.fraction.y == 0.5)
14015             return CLUTTER_GRAVITY_CENTER;
14016           else if (coord->v.fraction.y == 1.0)
14017             return CLUTTER_GRAVITY_SOUTH;
14018           else
14019             return CLUTTER_GRAVITY_NONE;
14020         }
14021       else if (coord->v.fraction.x == 1.0)
14022         {
14023           if (coord->v.fraction.y == 0.0)
14024             return CLUTTER_GRAVITY_NORTH_EAST;
14025           else if (coord->v.fraction.y == 0.5)
14026             return CLUTTER_GRAVITY_EAST;
14027           else if (coord->v.fraction.y == 1.0)
14028             return CLUTTER_GRAVITY_SOUTH_EAST;
14029           else
14030             return CLUTTER_GRAVITY_NONE;
14031         }
14032       else
14033         return CLUTTER_GRAVITY_NONE;
14034     }
14035   else
14036     return CLUTTER_GRAVITY_NONE;
14037 }
14038
14039 static void
14040 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14041                                   ClutterGravity  gravity)
14042 {
14043   switch (gravity)
14044     {
14045     case CLUTTER_GRAVITY_NORTH:
14046       coord->v.fraction.x = 0.5;
14047       coord->v.fraction.y = 0.0;
14048       break;
14049
14050     case CLUTTER_GRAVITY_NORTH_EAST:
14051       coord->v.fraction.x = 1.0;
14052       coord->v.fraction.y = 0.0;
14053       break;
14054
14055     case CLUTTER_GRAVITY_EAST:
14056       coord->v.fraction.x = 1.0;
14057       coord->v.fraction.y = 0.5;
14058       break;
14059
14060     case CLUTTER_GRAVITY_SOUTH_EAST:
14061       coord->v.fraction.x = 1.0;
14062       coord->v.fraction.y = 1.0;
14063       break;
14064
14065     case CLUTTER_GRAVITY_SOUTH:
14066       coord->v.fraction.x = 0.5;
14067       coord->v.fraction.y = 1.0;
14068       break;
14069
14070     case CLUTTER_GRAVITY_SOUTH_WEST:
14071       coord->v.fraction.x = 0.0;
14072       coord->v.fraction.y = 1.0;
14073       break;
14074
14075     case CLUTTER_GRAVITY_WEST:
14076       coord->v.fraction.x = 0.0;
14077       coord->v.fraction.y = 0.5;
14078       break;
14079
14080     case CLUTTER_GRAVITY_NORTH_WEST:
14081       coord->v.fraction.x = 0.0;
14082       coord->v.fraction.y = 0.0;
14083       break;
14084
14085     case CLUTTER_GRAVITY_CENTER:
14086       coord->v.fraction.x = 0.5;
14087       coord->v.fraction.y = 0.5;
14088       break;
14089
14090     default:
14091       coord->v.fraction.x = 0.0;
14092       coord->v.fraction.y = 0.0;
14093       break;
14094     }
14095
14096   coord->is_fractional = TRUE;
14097 }
14098
14099 static gboolean
14100 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14101 {
14102   if (coord->is_fractional)
14103     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14104   else
14105     return (coord->v.units.x == 0.0
14106             && coord->v.units.y == 0.0
14107             && coord->v.units.z == 0.0);
14108 }
14109
14110 /**
14111  * clutter_actor_get_flags:
14112  * @self: a #ClutterActor
14113  *
14114  * Retrieves the flags set on @self
14115  *
14116  * Return value: a bitwise or of #ClutterActorFlags or 0
14117  *
14118  * Since: 1.0
14119  */
14120 ClutterActorFlags
14121 clutter_actor_get_flags (ClutterActor *self)
14122 {
14123   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14124
14125   return self->flags;
14126 }
14127
14128 /**
14129  * clutter_actor_set_flags:
14130  * @self: a #ClutterActor
14131  * @flags: the flags to set
14132  *
14133  * Sets @flags on @self
14134  *
14135  * This function will emit notifications for the changed properties
14136  *
14137  * Since: 1.0
14138  */
14139 void
14140 clutter_actor_set_flags (ClutterActor      *self,
14141                          ClutterActorFlags  flags)
14142 {
14143   ClutterActorFlags old_flags;
14144   GObject *obj;
14145   gboolean was_reactive_set, reactive_set;
14146   gboolean was_realized_set, realized_set;
14147   gboolean was_mapped_set, mapped_set;
14148   gboolean was_visible_set, visible_set;
14149
14150   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14151
14152   if (self->flags == flags)
14153     return;
14154
14155   obj = G_OBJECT (self);
14156   g_object_ref (obj);
14157   g_object_freeze_notify (obj);
14158
14159   old_flags = self->flags;
14160
14161   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14162   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14163   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14164   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14165
14166   self->flags |= flags;
14167
14168   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14169   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14170   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14171   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14172
14173   if (reactive_set != was_reactive_set)
14174     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14175
14176   if (realized_set != was_realized_set)
14177     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14178
14179   if (mapped_set != was_mapped_set)
14180     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14181
14182   if (visible_set != was_visible_set)
14183     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14184
14185   g_object_thaw_notify (obj);
14186   g_object_unref (obj);
14187 }
14188
14189 /**
14190  * clutter_actor_unset_flags:
14191  * @self: a #ClutterActor
14192  * @flags: the flags to unset
14193  *
14194  * Unsets @flags on @self
14195  *
14196  * This function will emit notifications for the changed properties
14197  *
14198  * Since: 1.0
14199  */
14200 void
14201 clutter_actor_unset_flags (ClutterActor      *self,
14202                            ClutterActorFlags  flags)
14203 {
14204   ClutterActorFlags old_flags;
14205   GObject *obj;
14206   gboolean was_reactive_set, reactive_set;
14207   gboolean was_realized_set, realized_set;
14208   gboolean was_mapped_set, mapped_set;
14209   gboolean was_visible_set, visible_set;
14210
14211   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14212
14213   obj = G_OBJECT (self);
14214   g_object_freeze_notify (obj);
14215
14216   old_flags = self->flags;
14217
14218   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14219   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14220   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14221   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14222
14223   self->flags &= ~flags;
14224
14225   if (self->flags == old_flags)
14226     return;
14227
14228   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14229   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14230   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14231   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14232
14233   if (reactive_set != was_reactive_set)
14234     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14235
14236   if (realized_set != was_realized_set)
14237     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14238
14239   if (mapped_set != was_mapped_set)
14240     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14241
14242   if (visible_set != was_visible_set)
14243     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14244
14245   g_object_thaw_notify (obj);
14246 }
14247
14248 /**
14249  * clutter_actor_get_transformation_matrix:
14250  * @self: a #ClutterActor
14251  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14252  *
14253  * Retrieves the transformations applied to @self relative to its
14254  * parent.
14255  *
14256  * Since: 1.0
14257  */
14258 void
14259 clutter_actor_get_transformation_matrix (ClutterActor *self,
14260                                          CoglMatrix   *matrix)
14261 {
14262   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14263
14264   cogl_matrix_init_identity (matrix);
14265
14266   _clutter_actor_apply_modelview_transform (self, matrix);
14267 }
14268
14269 void
14270 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14271                                    gboolean      is_in_clone_paint)
14272 {
14273   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14274   self->priv->in_clone_paint = is_in_clone_paint;
14275 }
14276
14277 /**
14278  * clutter_actor_is_in_clone_paint:
14279  * @self: a #ClutterActor
14280  *
14281  * Checks whether @self is being currently painted by a #ClutterClone
14282  *
14283  * This function is useful only inside the ::paint virtual function
14284  * implementations or within handlers for the #ClutterActor::paint
14285  * signal
14286  *
14287  * This function should not be used by applications
14288  *
14289  * Return value: %TRUE if the #ClutterActor is currently being painted
14290  *   by a #ClutterClone, and %FALSE otherwise
14291  *
14292  * Since: 1.0
14293  */
14294 gboolean
14295 clutter_actor_is_in_clone_paint (ClutterActor *self)
14296 {
14297   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14298
14299   return self->priv->in_clone_paint;
14300 }
14301
14302 static gboolean
14303 set_direction_recursive (ClutterActor *actor,
14304                          gpointer      user_data)
14305 {
14306   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14307
14308   clutter_actor_set_text_direction (actor, text_dir);
14309
14310   return TRUE;
14311 }
14312
14313 /**
14314  * clutter_actor_set_text_direction:
14315  * @self: a #ClutterActor
14316  * @text_dir: the text direction for @self
14317  *
14318  * Sets the #ClutterTextDirection for an actor
14319  *
14320  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14321  *
14322  * If @self implements #ClutterContainer then this function will recurse
14323  * inside all the children of @self (including the internal ones).
14324  *
14325  * Composite actors not implementing #ClutterContainer, or actors requiring
14326  * special handling when the text direction changes, should connect to
14327  * the #GObject::notify signal for the #ClutterActor:text-direction property
14328  *
14329  * Since: 1.2
14330  */
14331 void
14332 clutter_actor_set_text_direction (ClutterActor         *self,
14333                                   ClutterTextDirection  text_dir)
14334 {
14335   ClutterActorPrivate *priv;
14336
14337   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14338   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14339
14340   priv = self->priv;
14341
14342   if (priv->text_direction != text_dir)
14343     {
14344       priv->text_direction = text_dir;
14345
14346       /* we need to emit the notify::text-direction first, so that
14347        * the sub-classes can catch that and do specific handling of
14348        * the text direction; see clutter_text_direction_changed_cb()
14349        * inside clutter-text.c
14350        */
14351       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14352
14353       _clutter_actor_foreach_child (self, set_direction_recursive,
14354                                     GINT_TO_POINTER (text_dir));
14355
14356       clutter_actor_queue_relayout (self);
14357     }
14358 }
14359
14360 void
14361 _clutter_actor_set_has_pointer (ClutterActor *self,
14362                                 gboolean      has_pointer)
14363 {
14364   ClutterActorPrivate *priv = self->priv;
14365
14366   if (priv->has_pointer != has_pointer)
14367     {
14368       priv->has_pointer = has_pointer;
14369
14370       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14371     }
14372 }
14373
14374 /**
14375  * clutter_actor_get_text_direction:
14376  * @self: a #ClutterActor
14377  *
14378  * Retrieves the value set using clutter_actor_set_text_direction()
14379  *
14380  * If no text direction has been previously set, the default text
14381  * direction, as returned by clutter_get_default_text_direction(), will
14382  * be returned instead
14383  *
14384  * Return value: the #ClutterTextDirection for the actor
14385  *
14386  * Since: 1.2
14387  */
14388 ClutterTextDirection
14389 clutter_actor_get_text_direction (ClutterActor *self)
14390 {
14391   ClutterActorPrivate *priv;
14392
14393   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14394                         CLUTTER_TEXT_DIRECTION_LTR);
14395
14396   priv = self->priv;
14397
14398   /* if no direction has been set yet use the default */
14399   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14400     priv->text_direction = clutter_get_default_text_direction ();
14401
14402   return priv->text_direction;
14403 }
14404
14405 /**
14406  * clutter_actor_push_internal:
14407  * @self: a #ClutterActor
14408  *
14409  * Should be used by actors implementing the #ClutterContainer and with
14410  * internal children added through clutter_actor_set_parent(), for instance:
14411  *
14412  * |[
14413  *   static void
14414  *   my_actor_init (MyActor *self)
14415  *   {
14416  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14417  *
14418  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14419  *
14420  *     /&ast; calling clutter_actor_set_parent() now will result in
14421  *      &ast; the internal flag being set on a child of MyActor
14422  *      &ast;/
14423  *
14424  *     /&ast; internal child - a background texture &ast;/
14425  *     self->priv->background_tex = clutter_texture_new ();
14426  *     clutter_actor_set_parent (self->priv->background_tex,
14427  *                               CLUTTER_ACTOR (self));
14428  *
14429  *     /&ast; internal child - a label &ast;/
14430  *     self->priv->label = clutter_text_new ();
14431  *     clutter_actor_set_parent (self->priv->label,
14432  *                               CLUTTER_ACTOR (self));
14433  *
14434  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14435  *
14436  *     /&ast; calling clutter_actor_set_parent() now will not result in
14437  *      &ast; the internal flag being set on a child of MyActor
14438  *      &ast;/
14439  *   }
14440  * ]|
14441  *
14442  * This function will be used by Clutter to toggle an "internal child"
14443  * flag whenever clutter_actor_set_parent() is called; internal children
14444  * are handled differently by Clutter, specifically when destroying their
14445  * parent.
14446  *
14447  * Call clutter_actor_pop_internal() when you finished adding internal
14448  * children.
14449  *
14450  * Nested calls to clutter_actor_push_internal() are allowed, but each
14451  * one must by followed by a clutter_actor_pop_internal() call.
14452  *
14453  * Since: 1.2
14454  *
14455  * Deprecated: 1.10: All children of an actor are accessible through
14456  *   the #ClutterActor API, and #ClutterActor implements the
14457  *   #ClutterContainer interface, so this function is only useful
14458  *   for legacy containers overriding the default implementation.
14459  */
14460 void
14461 clutter_actor_push_internal (ClutterActor *self)
14462 {
14463   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14464
14465   self->priv->internal_child += 1;
14466 }
14467
14468 /**
14469  * clutter_actor_pop_internal:
14470  * @self: a #ClutterActor
14471  *
14472  * Disables the effects of clutter_actor_push_internal().
14473  *
14474  * Since: 1.2
14475  *
14476  * Deprecated: 1.10: All children of an actor are accessible through
14477  *   the #ClutterActor API. This function is only useful for legacy
14478  *   containers overriding the default implementation of the
14479  *   #ClutterContainer interface.
14480  */
14481 void
14482 clutter_actor_pop_internal (ClutterActor *self)
14483 {
14484   ClutterActorPrivate *priv;
14485
14486   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14487
14488   priv = self->priv;
14489
14490   if (priv->internal_child == 0)
14491     {
14492       g_warning ("Mismatched %s: you need to call "
14493                  "clutter_actor_push_composite() at least once before "
14494                  "calling this function", G_STRFUNC);
14495       return;
14496     }
14497
14498   priv->internal_child -= 1;
14499 }
14500
14501 /**
14502  * clutter_actor_has_pointer:
14503  * @self: a #ClutterActor
14504  *
14505  * Checks whether an actor contains the pointer of a
14506  * #ClutterInputDevice
14507  *
14508  * Return value: %TRUE if the actor contains the pointer, and
14509  *   %FALSE otherwise
14510  *
14511  * Since: 1.2
14512  */
14513 gboolean
14514 clutter_actor_has_pointer (ClutterActor *self)
14515 {
14516   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14517
14518   return self->priv->has_pointer;
14519 }
14520
14521 /* XXX: This is a workaround for not being able to break the ABI of
14522  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14523  * clutter_actor_queue_clipped_redraw() for details.
14524  */
14525 ClutterPaintVolume *
14526 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14527 {
14528   return g_object_get_data (G_OBJECT (self),
14529                             "-clutter-actor-queue-redraw-clip");
14530 }
14531
14532 void
14533 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14534                                       ClutterPaintVolume *clip)
14535 {
14536   g_object_set_data (G_OBJECT (self),
14537                      "-clutter-actor-queue-redraw-clip",
14538                      clip);
14539 }
14540
14541 /**
14542  * clutter_actor_has_allocation:
14543  * @self: a #ClutterActor
14544  *
14545  * Checks if the actor has an up-to-date allocation assigned to
14546  * it. This means that the actor should have an allocation: it's
14547  * visible and has a parent. It also means that there is no
14548  * outstanding relayout request in progress for the actor or its
14549  * children (There might be other outstanding layout requests in
14550  * progress that will cause the actor to get a new allocation
14551  * when the stage is laid out, however).
14552  *
14553  * If this function returns %FALSE, then the actor will normally
14554  * be allocated before it is next drawn on the screen.
14555  *
14556  * Return value: %TRUE if the actor has an up-to-date allocation
14557  *
14558  * Since: 1.4
14559  */
14560 gboolean
14561 clutter_actor_has_allocation (ClutterActor *self)
14562 {
14563   ClutterActorPrivate *priv;
14564
14565   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14566
14567   priv = self->priv;
14568
14569   return priv->parent != NULL &&
14570          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14571          !priv->needs_allocation;
14572 }
14573
14574 /**
14575  * clutter_actor_add_action:
14576  * @self: a #ClutterActor
14577  * @action: a #ClutterAction
14578  *
14579  * Adds @action to the list of actions applied to @self
14580  *
14581  * A #ClutterAction can only belong to one actor at a time
14582  *
14583  * The #ClutterActor will hold a reference on @action until either
14584  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14585  * is called
14586  *
14587  * Since: 1.4
14588  */
14589 void
14590 clutter_actor_add_action (ClutterActor  *self,
14591                           ClutterAction *action)
14592 {
14593   ClutterActorPrivate *priv;
14594
14595   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14596   g_return_if_fail (CLUTTER_IS_ACTION (action));
14597
14598   priv = self->priv;
14599
14600   if (priv->actions == NULL)
14601     {
14602       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14603       priv->actions->actor = self;
14604     }
14605
14606   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14607
14608   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14609 }
14610
14611 /**
14612  * clutter_actor_add_action_with_name:
14613  * @self: a #ClutterActor
14614  * @name: the name to set on the action
14615  * @action: a #ClutterAction
14616  *
14617  * A convenience function for setting the name of a #ClutterAction
14618  * while adding it to the list of actions applied to @self
14619  *
14620  * This function is the logical equivalent of:
14621  *
14622  * |[
14623  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14624  *   clutter_actor_add_action (self, action);
14625  * ]|
14626  *
14627  * Since: 1.4
14628  */
14629 void
14630 clutter_actor_add_action_with_name (ClutterActor  *self,
14631                                     const gchar   *name,
14632                                     ClutterAction *action)
14633 {
14634   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14635   g_return_if_fail (name != NULL);
14636   g_return_if_fail (CLUTTER_IS_ACTION (action));
14637
14638   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14639   clutter_actor_add_action (self, action);
14640 }
14641
14642 /**
14643  * clutter_actor_remove_action:
14644  * @self: a #ClutterActor
14645  * @action: a #ClutterAction
14646  *
14647  * Removes @action from the list of actions applied to @self
14648  *
14649  * The reference held by @self on the #ClutterAction will be released
14650  *
14651  * Since: 1.4
14652  */
14653 void
14654 clutter_actor_remove_action (ClutterActor  *self,
14655                              ClutterAction *action)
14656 {
14657   ClutterActorPrivate *priv;
14658
14659   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14660   g_return_if_fail (CLUTTER_IS_ACTION (action));
14661
14662   priv = self->priv;
14663
14664   if (priv->actions == NULL)
14665     return;
14666
14667   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14668
14669   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14670 }
14671
14672 /**
14673  * clutter_actor_remove_action_by_name:
14674  * @self: a #ClutterActor
14675  * @name: the name of the action to remove
14676  *
14677  * Removes the #ClutterAction with the given name from the list
14678  * of actions applied to @self
14679  *
14680  * Since: 1.4
14681  */
14682 void
14683 clutter_actor_remove_action_by_name (ClutterActor *self,
14684                                      const gchar  *name)
14685 {
14686   ClutterActorPrivate *priv;
14687   ClutterActorMeta *meta;
14688
14689   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14690   g_return_if_fail (name != NULL);
14691
14692   priv = self->priv;
14693
14694   if (priv->actions == NULL)
14695     return;
14696
14697   meta = _clutter_meta_group_get_meta (priv->actions, name);
14698   if (meta == NULL)
14699     return;
14700
14701   _clutter_meta_group_remove_meta (priv->actions, meta);
14702
14703   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14704 }
14705
14706 /**
14707  * clutter_actor_get_actions:
14708  * @self: a #ClutterActor
14709  *
14710  * Retrieves the list of actions applied to @self
14711  *
14712  * Return value: (transfer container) (element-type Clutter.Action): a copy
14713  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14714  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14715  *   allocated by the returned #GList
14716  *
14717  * Since: 1.4
14718  */
14719 GList *
14720 clutter_actor_get_actions (ClutterActor *self)
14721 {
14722   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14723
14724   if (self->priv->actions == NULL)
14725     return NULL;
14726
14727   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14728 }
14729
14730 /**
14731  * clutter_actor_get_action:
14732  * @self: a #ClutterActor
14733  * @name: the name of the action to retrieve
14734  *
14735  * Retrieves the #ClutterAction with the given name in the list
14736  * of actions applied to @self
14737  *
14738  * Return value: (transfer none): a #ClutterAction for the given
14739  *   name, or %NULL. The returned #ClutterAction is owned by the
14740  *   actor and it should not be unreferenced directly
14741  *
14742  * Since: 1.4
14743  */
14744 ClutterAction *
14745 clutter_actor_get_action (ClutterActor *self,
14746                           const gchar  *name)
14747 {
14748   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14749   g_return_val_if_fail (name != NULL, NULL);
14750
14751   if (self->priv->actions == NULL)
14752     return NULL;
14753
14754   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14755 }
14756
14757 /**
14758  * clutter_actor_clear_actions:
14759  * @self: a #ClutterActor
14760  *
14761  * Clears the list of actions applied to @self
14762  *
14763  * Since: 1.4
14764  */
14765 void
14766 clutter_actor_clear_actions (ClutterActor *self)
14767 {
14768   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14769
14770   if (self->priv->actions == NULL)
14771     return;
14772
14773   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14774 }
14775
14776 /**
14777  * clutter_actor_add_constraint:
14778  * @self: a #ClutterActor
14779  * @constraint: a #ClutterConstraint
14780  *
14781  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14782  * to @self
14783  *
14784  * The #ClutterActor will hold a reference on the @constraint until
14785  * either clutter_actor_remove_constraint() or
14786  * clutter_actor_clear_constraints() is called.
14787  *
14788  * Since: 1.4
14789  */
14790 void
14791 clutter_actor_add_constraint (ClutterActor      *self,
14792                               ClutterConstraint *constraint)
14793 {
14794   ClutterActorPrivate *priv;
14795
14796   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14797   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14798
14799   priv = self->priv;
14800
14801   if (priv->constraints == NULL)
14802     {
14803       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14804       priv->constraints->actor = self;
14805     }
14806
14807   _clutter_meta_group_add_meta (priv->constraints,
14808                                 CLUTTER_ACTOR_META (constraint));
14809   clutter_actor_queue_relayout (self);
14810
14811   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14812 }
14813
14814 /**
14815  * clutter_actor_add_constraint_with_name:
14816  * @self: a #ClutterActor
14817  * @name: the name to set on the constraint
14818  * @constraint: a #ClutterConstraint
14819  *
14820  * A convenience function for setting the name of a #ClutterConstraint
14821  * while adding it to the list of constraints applied to @self
14822  *
14823  * This function is the logical equivalent of:
14824  *
14825  * |[
14826  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14827  *   clutter_actor_add_constraint (self, constraint);
14828  * ]|
14829  *
14830  * Since: 1.4
14831  */
14832 void
14833 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14834                                         const gchar       *name,
14835                                         ClutterConstraint *constraint)
14836 {
14837   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14838   g_return_if_fail (name != NULL);
14839   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14840
14841   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14842   clutter_actor_add_constraint (self, constraint);
14843 }
14844
14845 /**
14846  * clutter_actor_remove_constraint:
14847  * @self: a #ClutterActor
14848  * @constraint: a #ClutterConstraint
14849  *
14850  * Removes @constraint from the list of constraints applied to @self
14851  *
14852  * The reference held by @self on the #ClutterConstraint will be released
14853  *
14854  * Since: 1.4
14855  */
14856 void
14857 clutter_actor_remove_constraint (ClutterActor      *self,
14858                                  ClutterConstraint *constraint)
14859 {
14860   ClutterActorPrivate *priv;
14861
14862   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14863   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14864
14865   priv = self->priv;
14866
14867   if (priv->constraints == NULL)
14868     return;
14869
14870   _clutter_meta_group_remove_meta (priv->constraints,
14871                                    CLUTTER_ACTOR_META (constraint));
14872   clutter_actor_queue_relayout (self);
14873
14874   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14875 }
14876
14877 /**
14878  * clutter_actor_remove_constraint_by_name:
14879  * @self: a #ClutterActor
14880  * @name: the name of the constraint to remove
14881  *
14882  * Removes the #ClutterConstraint with the given name from the list
14883  * of constraints applied to @self
14884  *
14885  * Since: 1.4
14886  */
14887 void
14888 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14889                                          const gchar  *name)
14890 {
14891   ClutterActorPrivate *priv;
14892   ClutterActorMeta *meta;
14893
14894   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14895   g_return_if_fail (name != NULL);
14896
14897   priv = self->priv;
14898
14899   if (priv->constraints == NULL)
14900     return;
14901
14902   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14903   if (meta == NULL)
14904     return;
14905
14906   _clutter_meta_group_remove_meta (priv->constraints, meta);
14907   clutter_actor_queue_relayout (self);
14908 }
14909
14910 /**
14911  * clutter_actor_get_constraints:
14912  * @self: a #ClutterActor
14913  *
14914  * Retrieves the list of constraints applied to @self
14915  *
14916  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14917  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14918  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14919  *   allocated by the returned #GList
14920  *
14921  * Since: 1.4
14922  */
14923 GList *
14924 clutter_actor_get_constraints (ClutterActor *self)
14925 {
14926   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14927
14928   if (self->priv->constraints == NULL)
14929     return NULL;
14930
14931   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14932 }
14933
14934 /**
14935  * clutter_actor_get_constraint:
14936  * @self: a #ClutterActor
14937  * @name: the name of the constraint to retrieve
14938  *
14939  * Retrieves the #ClutterConstraint with the given name in the list
14940  * of constraints applied to @self
14941  *
14942  * Return value: (transfer none): a #ClutterConstraint for the given
14943  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14944  *   actor and it should not be unreferenced directly
14945  *
14946  * Since: 1.4
14947  */
14948 ClutterConstraint *
14949 clutter_actor_get_constraint (ClutterActor *self,
14950                               const gchar  *name)
14951 {
14952   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14953   g_return_val_if_fail (name != NULL, NULL);
14954
14955   if (self->priv->constraints == NULL)
14956     return NULL;
14957
14958   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14959 }
14960
14961 /**
14962  * clutter_actor_clear_constraints:
14963  * @self: a #ClutterActor
14964  *
14965  * Clears the list of constraints applied to @self
14966  *
14967  * Since: 1.4
14968  */
14969 void
14970 clutter_actor_clear_constraints (ClutterActor *self)
14971 {
14972   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14973
14974   if (self->priv->constraints == NULL)
14975     return;
14976
14977   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14978
14979   clutter_actor_queue_relayout (self);
14980 }
14981
14982 /**
14983  * clutter_actor_set_clip_to_allocation:
14984  * @self: a #ClutterActor
14985  * @clip_set: %TRUE to apply a clip tracking the allocation
14986  *
14987  * Sets whether @self should be clipped to the same size as its
14988  * allocation
14989  *
14990  * Since: 1.4
14991  */
14992 void
14993 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14994                                       gboolean      clip_set)
14995 {
14996   ClutterActorPrivate *priv;
14997
14998   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14999
15000   clip_set = !!clip_set;
15001
15002   priv = self->priv;
15003
15004   if (priv->clip_to_allocation != clip_set)
15005     {
15006       priv->clip_to_allocation = clip_set;
15007
15008       clutter_actor_queue_redraw (self);
15009
15010       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15011     }
15012 }
15013
15014 /**
15015  * clutter_actor_get_clip_to_allocation:
15016  * @self: a #ClutterActor
15017  *
15018  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15019  *
15020  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15021  *
15022  * Since: 1.4
15023  */
15024 gboolean
15025 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15026 {
15027   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15028
15029   return self->priv->clip_to_allocation;
15030 }
15031
15032 /**
15033  * clutter_actor_add_effect:
15034  * @self: a #ClutterActor
15035  * @effect: a #ClutterEffect
15036  *
15037  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15038  *
15039  * The #ClutterActor will hold a reference on the @effect until either
15040  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15041  * called.
15042  *
15043  * Since: 1.4
15044  */
15045 void
15046 clutter_actor_add_effect (ClutterActor  *self,
15047                           ClutterEffect *effect)
15048 {
15049   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15050   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15051
15052   _clutter_actor_add_effect_internal (self, effect);
15053
15054   clutter_actor_queue_redraw (self);
15055
15056   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15057 }
15058
15059 /**
15060  * clutter_actor_add_effect_with_name:
15061  * @self: a #ClutterActor
15062  * @name: the name to set on the effect
15063  * @effect: a #ClutterEffect
15064  *
15065  * A convenience function for setting the name of a #ClutterEffect
15066  * while adding it to the list of effectss applied to @self
15067  *
15068  * This function is the logical equivalent of:
15069  *
15070  * |[
15071  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15072  *   clutter_actor_add_effect (self, effect);
15073  * ]|
15074  *
15075  * Since: 1.4
15076  */
15077 void
15078 clutter_actor_add_effect_with_name (ClutterActor  *self,
15079                                     const gchar   *name,
15080                                     ClutterEffect *effect)
15081 {
15082   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15083   g_return_if_fail (name != NULL);
15084   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15085
15086   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15087   clutter_actor_add_effect (self, effect);
15088 }
15089
15090 /**
15091  * clutter_actor_remove_effect:
15092  * @self: a #ClutterActor
15093  * @effect: a #ClutterEffect
15094  *
15095  * Removes @effect from the list of effects applied to @self
15096  *
15097  * The reference held by @self on the #ClutterEffect will be released
15098  *
15099  * Since: 1.4
15100  */
15101 void
15102 clutter_actor_remove_effect (ClutterActor  *self,
15103                              ClutterEffect *effect)
15104 {
15105   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15106   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15107
15108   _clutter_actor_remove_effect_internal (self, effect);
15109
15110   clutter_actor_queue_redraw (self);
15111
15112   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15113 }
15114
15115 /**
15116  * clutter_actor_remove_effect_by_name:
15117  * @self: a #ClutterActor
15118  * @name: the name of the effect to remove
15119  *
15120  * Removes the #ClutterEffect with the given name from the list
15121  * of effects applied to @self
15122  *
15123  * Since: 1.4
15124  */
15125 void
15126 clutter_actor_remove_effect_by_name (ClutterActor *self,
15127                                      const gchar  *name)
15128 {
15129   ClutterActorPrivate *priv;
15130   ClutterActorMeta *meta;
15131
15132   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15133   g_return_if_fail (name != NULL);
15134
15135   priv = self->priv;
15136
15137   if (priv->effects == NULL)
15138     return;
15139
15140   meta = _clutter_meta_group_get_meta (priv->effects, name);
15141   if (meta == NULL)
15142     return;
15143
15144   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15145 }
15146
15147 /**
15148  * clutter_actor_get_effects:
15149  * @self: a #ClutterActor
15150  *
15151  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15152  *
15153  * Return value: (transfer container) (element-type Clutter.Effect): a list
15154  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15155  *   list are owned by Clutter and they should not be freed. You should
15156  *   free the returned list using g_list_free() when done
15157  *
15158  * Since: 1.4
15159  */
15160 GList *
15161 clutter_actor_get_effects (ClutterActor *self)
15162 {
15163   ClutterActorPrivate *priv;
15164
15165   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15166
15167   priv = self->priv;
15168
15169   if (priv->effects == NULL)
15170     return NULL;
15171
15172   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15173 }
15174
15175 /**
15176  * clutter_actor_get_effect:
15177  * @self: a #ClutterActor
15178  * @name: the name of the effect to retrieve
15179  *
15180  * Retrieves the #ClutterEffect with the given name in the list
15181  * of effects applied to @self
15182  *
15183  * Return value: (transfer none): a #ClutterEffect for the given
15184  *   name, or %NULL. The returned #ClutterEffect is owned by the
15185  *   actor and it should not be unreferenced directly
15186  *
15187  * Since: 1.4
15188  */
15189 ClutterEffect *
15190 clutter_actor_get_effect (ClutterActor *self,
15191                           const gchar  *name)
15192 {
15193   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15194   g_return_val_if_fail (name != NULL, NULL);
15195
15196   if (self->priv->effects == NULL)
15197     return NULL;
15198
15199   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15200 }
15201
15202 /**
15203  * clutter_actor_clear_effects:
15204  * @self: a #ClutterActor
15205  *
15206  * Clears the list of effects applied to @self
15207  *
15208  * Since: 1.4
15209  */
15210 void
15211 clutter_actor_clear_effects (ClutterActor *self)
15212 {
15213   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15214
15215   if (self->priv->effects == NULL)
15216     return;
15217
15218   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15219
15220   clutter_actor_queue_redraw (self);
15221 }
15222
15223 /**
15224  * clutter_actor_has_key_focus:
15225  * @self: a #ClutterActor
15226  *
15227  * Checks whether @self is the #ClutterActor that has key focus
15228  *
15229  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15230  *
15231  * Since: 1.4
15232  */
15233 gboolean
15234 clutter_actor_has_key_focus (ClutterActor *self)
15235 {
15236   ClutterActor *stage;
15237
15238   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15239
15240   stage = _clutter_actor_get_stage_internal (self);
15241   if (stage == NULL)
15242     return FALSE;
15243
15244   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15245 }
15246
15247 static gboolean
15248 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15249                                       ClutterPaintVolume *pv)
15250 {
15251   ClutterActorPrivate *priv = self->priv;
15252
15253   /* Actors are only expected to report a valid paint volume
15254    * while they have a valid allocation. */
15255   if (G_UNLIKELY (priv->needs_allocation))
15256     {
15257       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15258                     "Actor needs allocation",
15259                     _clutter_actor_get_debug_name (self));
15260       return FALSE;
15261     }
15262
15263   /* Check if there are any handlers connected to the paint
15264    * signal. If there are then all bets are off for what the paint
15265    * volume for this actor might possibly be!
15266    *
15267    * XXX: It's expected that this is going to end up being quite a
15268    * costly check to have to do here, but we haven't come up with
15269    * another solution that can reliably catch paint signal handlers at
15270    * the right time to either avoid artefacts due to invalid stage
15271    * clipping or due to incorrect culling.
15272    *
15273    * Previously we checked in clutter_actor_paint(), but at that time
15274    * we may already be using a stage clip that could be derived from
15275    * an invalid paint-volume. We used to try and handle that by
15276    * queuing a follow up, unclipped, redraw but still the previous
15277    * checking wasn't enough to catch invalid volumes involved in
15278    * culling (considering that containers may derive their volume from
15279    * children that haven't yet been painted)
15280    *
15281    * Longer term, improved solutions could be:
15282    * - Disallow painting in the paint signal, only allow using it
15283    *   for tracking when paints happen. We can add another API that
15284    *   allows monkey patching the paint of arbitrary actors but in a
15285    *   more controlled way and that also supports modifying the
15286    *   paint-volume.
15287    * - If we could be notified somehow when signal handlers are
15288    *   connected we wouldn't have to poll for handlers like this.
15289    */
15290   if (g_signal_has_handler_pending (self,
15291                                     actor_signals[PAINT],
15292                                     0,
15293                                     TRUE))
15294     {
15295       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15296                     "Actor has \"paint\" signal handlers",
15297                     _clutter_actor_get_debug_name (self));
15298       return FALSE;
15299     }
15300
15301   _clutter_paint_volume_init_static (pv, self);
15302
15303   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15304     {
15305       clutter_paint_volume_free (pv);
15306       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15307                     "Actor failed to report a volume",
15308                     _clutter_actor_get_debug_name (self));
15309       return FALSE;
15310     }
15311
15312   /* since effects can modify the paint volume, we allow them to actually
15313    * do this by making get_paint_volume() "context sensitive"
15314    */
15315   if (priv->effects != NULL)
15316     {
15317       if (priv->current_effect != NULL)
15318         {
15319           const GList *effects, *l;
15320
15321           /* if we are being called from within the paint sequence of
15322            * an actor, get the paint volume up to the current effect
15323            */
15324           effects = _clutter_meta_group_peek_metas (priv->effects);
15325           for (l = effects;
15326                l != NULL || (l != NULL && l->data != priv->current_effect);
15327                l = l->next)
15328             {
15329               if (!_clutter_effect_get_paint_volume (l->data, pv))
15330                 {
15331                   clutter_paint_volume_free (pv);
15332                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15333                                 "Effect (%s) failed to report a volume",
15334                                 _clutter_actor_get_debug_name (self),
15335                                 _clutter_actor_meta_get_debug_name (l->data));
15336                   return FALSE;
15337                 }
15338             }
15339         }
15340       else
15341         {
15342           const GList *effects, *l;
15343
15344           /* otherwise, get the cumulative volume */
15345           effects = _clutter_meta_group_peek_metas (priv->effects);
15346           for (l = effects; l != NULL; l = l->next)
15347             if (!_clutter_effect_get_paint_volume (l->data, pv))
15348               {
15349                 clutter_paint_volume_free (pv);
15350                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15351                               "Effect (%s) failed to report a volume",
15352                               _clutter_actor_get_debug_name (self),
15353                               _clutter_actor_meta_get_debug_name (l->data));
15354                 return FALSE;
15355               }
15356         }
15357     }
15358
15359   return TRUE;
15360 }
15361
15362 /* The public clutter_actor_get_paint_volume API returns a const
15363  * pointer since we return a pointer directly to the cached
15364  * PaintVolume associated with the actor and don't want the user to
15365  * inadvertently modify it, but for internal uses we sometimes need
15366  * access to the same PaintVolume but need to apply some book-keeping
15367  * modifications to it so we don't want a const pointer.
15368  */
15369 static ClutterPaintVolume *
15370 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15371 {
15372   ClutterActorPrivate *priv;
15373
15374   priv = self->priv;
15375
15376   if (priv->paint_volume_valid)
15377     clutter_paint_volume_free (&priv->paint_volume);
15378
15379   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15380     {
15381       priv->paint_volume_valid = TRUE;
15382       return &priv->paint_volume;
15383     }
15384   else
15385     {
15386       priv->paint_volume_valid = FALSE;
15387       return NULL;
15388     }
15389 }
15390
15391 /**
15392  * clutter_actor_get_paint_volume:
15393  * @self: a #ClutterActor
15394  *
15395  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15396  * when a paint volume can't be determined.
15397  *
15398  * The paint volume is defined as the 3D space occupied by an actor
15399  * when being painted.
15400  *
15401  * This function will call the <function>get_paint_volume()</function>
15402  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15403  * should not usually care about overriding the default implementation,
15404  * unless they are, for instance: painting outside their allocation, or
15405  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15406  * 3D depth).
15407  *
15408  * <note>2D actors overriding <function>get_paint_volume()</function>
15409  * ensure their volume has a depth of 0. (This will be true so long as
15410  * you don't call clutter_paint_volume_set_depth().)</note>
15411  *
15412  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15413  *   or %NULL if no volume could be determined. The returned pointer
15414  *   is not guaranteed to be valid across multiple frames; if you want
15415  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15416  *
15417  * Since: 1.6
15418  */
15419 const ClutterPaintVolume *
15420 clutter_actor_get_paint_volume (ClutterActor *self)
15421 {
15422   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15423
15424   return _clutter_actor_get_paint_volume_mutable (self);
15425 }
15426
15427 /**
15428  * clutter_actor_get_transformed_paint_volume:
15429  * @self: a #ClutterActor
15430  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15431  *    (or %NULL for the stage)
15432  *
15433  * Retrieves the 3D paint volume of an actor like
15434  * clutter_actor_get_paint_volume() does (Please refer to the
15435  * documentation of clutter_actor_get_paint_volume() for more
15436  * details.) and it additionally transforms the paint volume into the
15437  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15438  * is passed for @relative_to_ancestor)
15439  *
15440  * This can be used by containers that base their paint volume on
15441  * the volume of their children. Such containers can query the
15442  * transformed paint volume of all of its children and union them
15443  * together using clutter_paint_volume_union().
15444  *
15445  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15446  *   or %NULL if no volume could be determined. The returned pointer is
15447  *   not guaranteed to be valid across multiple frames; if you wish to
15448  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15449  *
15450  * Since: 1.6
15451  */
15452 const ClutterPaintVolume *
15453 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15454                                             ClutterActor *relative_to_ancestor)
15455 {
15456   const ClutterPaintVolume *volume;
15457   ClutterActor *stage;
15458   ClutterPaintVolume *transformed_volume;
15459
15460   stage = _clutter_actor_get_stage_internal (self);
15461   if (G_UNLIKELY (stage == NULL))
15462     return NULL;
15463
15464   if (relative_to_ancestor == NULL)
15465     relative_to_ancestor = stage;
15466
15467   volume = clutter_actor_get_paint_volume (self);
15468   if (volume == NULL)
15469     return NULL;
15470
15471   transformed_volume =
15472     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15473
15474   _clutter_paint_volume_copy_static (volume, transformed_volume);
15475
15476   _clutter_paint_volume_transform_relative (transformed_volume,
15477                                             relative_to_ancestor);
15478
15479   return transformed_volume;
15480 }
15481
15482 /**
15483  * clutter_actor_get_paint_box:
15484  * @self: a #ClutterActor
15485  * @box: (out): return location for a #ClutterActorBox
15486  *
15487  * Retrieves the paint volume of the passed #ClutterActor, and
15488  * transforms it into a 2D bounding box in stage coordinates.
15489  *
15490  * This function is useful to determine the on screen area occupied by
15491  * the actor. The box is only an approximation and may often be
15492  * considerably larger due to the optimizations used to calculate the
15493  * box. The box is never smaller though, so it can reliably be used
15494  * for culling.
15495  *
15496  * There are times when a 2D paint box can't be determined, e.g.
15497  * because the actor isn't yet parented under a stage or because
15498  * the actor is unable to determine a paint volume.
15499  *
15500  * Return value: %TRUE if a 2D paint box could be determined, else
15501  * %FALSE.
15502  *
15503  * Since: 1.6
15504  */
15505 gboolean
15506 clutter_actor_get_paint_box (ClutterActor    *self,
15507                              ClutterActorBox *box)
15508 {
15509   ClutterActor *stage;
15510   ClutterPaintVolume *pv;
15511
15512   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15513   g_return_val_if_fail (box != NULL, FALSE);
15514
15515   stage = _clutter_actor_get_stage_internal (self);
15516   if (G_UNLIKELY (!stage))
15517     return FALSE;
15518
15519   pv = _clutter_actor_get_paint_volume_mutable (self);
15520   if (G_UNLIKELY (!pv))
15521     return FALSE;
15522
15523   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15524
15525   return TRUE;
15526 }
15527
15528 /**
15529  * clutter_actor_has_overlaps:
15530  * @self: A #ClutterActor
15531  *
15532  * Asks the actor's implementation whether it may contain overlapping
15533  * primitives.
15534  *
15535  * For example; Clutter may use this to determine whether the painting
15536  * should be redirected to an offscreen buffer to correctly implement
15537  * the opacity property.
15538  *
15539  * Custom actors can override the default response by implementing the
15540  * #ClutterActor <function>has_overlaps</function> virtual function. See
15541  * clutter_actor_set_offscreen_redirect() for more information.
15542  *
15543  * Return value: %TRUE if the actor may have overlapping primitives, and
15544  *   %FALSE otherwise
15545  *
15546  * Since: 1.8
15547  */
15548 gboolean
15549 clutter_actor_has_overlaps (ClutterActor *self)
15550 {
15551   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15552
15553   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15554 }
15555
15556 /**
15557  * clutter_actor_has_effects:
15558  * @self: A #ClutterActor
15559  *
15560  * Returns whether the actor has any effects applied.
15561  *
15562  * Return value: %TRUE if the actor has any effects,
15563  *   %FALSE otherwise
15564  *
15565  * Since: 1.10
15566  */
15567 gboolean
15568 clutter_actor_has_effects (ClutterActor *self)
15569 {
15570   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15571
15572   if (self->priv->effects == NULL)
15573     return FALSE;
15574
15575   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15576 }
15577
15578 /**
15579  * clutter_actor_has_constraints:
15580  * @self: A #ClutterActor
15581  *
15582  * Returns whether the actor has any constraints applied.
15583  *
15584  * Return value: %TRUE if the actor has any constraints,
15585  *   %FALSE otherwise
15586  *
15587  * Since: 1.10
15588  */
15589 gboolean
15590 clutter_actor_has_constraints (ClutterActor *self)
15591 {
15592   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15593
15594   return self->priv->constraints != NULL;
15595 }
15596
15597 /**
15598  * clutter_actor_has_actions:
15599  * @self: A #ClutterActor
15600  *
15601  * Returns whether the actor has any actions applied.
15602  *
15603  * Return value: %TRUE if the actor has any actions,
15604  *   %FALSE otherwise
15605  *
15606  * Since: 1.10
15607  */
15608 gboolean
15609 clutter_actor_has_actions (ClutterActor *self)
15610 {
15611   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15612
15613   return self->priv->actions != NULL;
15614 }
15615
15616 /**
15617  * clutter_actor_get_n_children:
15618  * @self: a #ClutterActor
15619  *
15620  * Retrieves the number of children of @self.
15621  *
15622  * Return value: the number of children of an actor
15623  *
15624  * Since: 1.10
15625  */
15626 gint
15627 clutter_actor_get_n_children (ClutterActor *self)
15628 {
15629   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15630
15631   return self->priv->n_children;
15632 }
15633
15634 /**
15635  * clutter_actor_get_child_at_index:
15636  * @self: a #ClutterActor
15637  * @index_: the position in the list of children
15638  *
15639  * Retrieves the actor at the given @index_ inside the list of
15640  * children of @self.
15641  *
15642  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15643  *
15644  * Since: 1.10
15645  */
15646 ClutterActor *
15647 clutter_actor_get_child_at_index (ClutterActor *self,
15648                                   gint          index_)
15649 {
15650   ClutterActor *iter;
15651   int i;
15652
15653   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15654   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15655
15656   for (iter = self->priv->first_child, i = 0;
15657        iter != NULL && i < index_;
15658        iter = iter->priv->next_sibling, i += 1)
15659     ;
15660
15661   return iter;
15662 }
15663
15664 /*< private >
15665  * _clutter_actor_foreach_child:
15666  * @actor: The actor whos children you want to iterate
15667  * @callback: The function to call for each child
15668  * @user_data: Private data to pass to @callback
15669  *
15670  * Calls a given @callback once for each child of the specified @actor and
15671  * passing the @user_data pointer each time.
15672  *
15673  * Return value: returns %TRUE if all children were iterated, else
15674  *    %FALSE if a callback broke out of iteration early.
15675  */
15676 gboolean
15677 _clutter_actor_foreach_child (ClutterActor           *self,
15678                               ClutterForeachCallback  callback,
15679                               gpointer                user_data)
15680 {
15681   ClutterActorPrivate *priv = self->priv;
15682   ClutterActor *iter;
15683   gboolean cont;
15684
15685   for (cont = TRUE, iter = priv->first_child;
15686        cont && iter != NULL;
15687        iter = iter->priv->next_sibling)
15688     {
15689       cont = callback (iter, user_data);
15690     }
15691
15692   return cont;
15693 }
15694
15695 #if 0
15696 /* For debugging purposes this gives us a simple way to print out
15697  * the scenegraph e.g in gdb using:
15698  * [|
15699  *   _clutter_actor_traverse (stage,
15700  *                            0,
15701  *                            clutter_debug_print_actor_cb,
15702  *                            NULL,
15703  *                            NULL);
15704  * |]
15705  */
15706 static ClutterActorTraverseVisitFlags
15707 clutter_debug_print_actor_cb (ClutterActor *actor,
15708                               int depth,
15709                               void *user_data)
15710 {
15711   g_print ("%*s%s:%p\n",
15712            depth * 2, "",
15713            _clutter_actor_get_debug_name (actor),
15714            actor);
15715
15716   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15717 }
15718 #endif
15719
15720 static void
15721 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15722                                  ClutterTraverseCallback callback,
15723                                  gpointer                user_data)
15724 {
15725   GQueue *queue = g_queue_new ();
15726   ClutterActor dummy;
15727   int current_depth = 0;
15728
15729   g_queue_push_tail (queue, actor);
15730   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15731
15732   while ((actor = g_queue_pop_head (queue)))
15733     {
15734       ClutterActorTraverseVisitFlags flags;
15735
15736       if (actor == &dummy)
15737         {
15738           current_depth++;
15739           g_queue_push_tail (queue, &dummy);
15740           continue;
15741         }
15742
15743       flags = callback (actor, current_depth, user_data);
15744       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15745         break;
15746       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15747         {
15748           ClutterActor *iter;
15749
15750           for (iter = actor->priv->first_child;
15751                iter != NULL;
15752                iter = iter->priv->next_sibling)
15753             {
15754               g_queue_push_tail (queue, iter);
15755             }
15756         }
15757     }
15758
15759   g_queue_free (queue);
15760 }
15761
15762 static ClutterActorTraverseVisitFlags
15763 _clutter_actor_traverse_depth (ClutterActor           *actor,
15764                                ClutterTraverseCallback before_children_callback,
15765                                ClutterTraverseCallback after_children_callback,
15766                                int                     current_depth,
15767                                gpointer                user_data)
15768 {
15769   ClutterActorTraverseVisitFlags flags;
15770
15771   flags = before_children_callback (actor, current_depth, user_data);
15772   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15773     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15774
15775   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15776     {
15777       ClutterActor *iter;
15778
15779       for (iter = actor->priv->first_child;
15780            iter != NULL;
15781            iter = iter->priv->next_sibling)
15782         {
15783           flags = _clutter_actor_traverse_depth (iter,
15784                                                  before_children_callback,
15785                                                  after_children_callback,
15786                                                  current_depth + 1,
15787                                                  user_data);
15788
15789           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15790             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15791         }
15792     }
15793
15794   if (after_children_callback)
15795     return after_children_callback (actor, current_depth, user_data);
15796   else
15797     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15798 }
15799
15800 /* _clutter_actor_traverse:
15801  * @actor: The actor to start traversing the graph from
15802  * @flags: These flags may affect how the traversal is done
15803  * @before_children_callback: A function to call before visiting the
15804  *   children of the current actor.
15805  * @after_children_callback: A function to call after visiting the
15806  *   children of the current actor. (Ignored if
15807  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15808  * @user_data: The private data to pass to the callbacks
15809  *
15810  * Traverses the scenegraph starting at the specified @actor and
15811  * descending through all its children and its children's children.
15812  * For each actor traversed @before_children_callback and
15813  * @after_children_callback are called with the specified
15814  * @user_data, before and after visiting that actor's children.
15815  *
15816  * The callbacks can return flags that affect the ongoing traversal
15817  * such as by skipping over an actors children or bailing out of
15818  * any further traversing.
15819  */
15820 void
15821 _clutter_actor_traverse (ClutterActor              *actor,
15822                          ClutterActorTraverseFlags  flags,
15823                          ClutterTraverseCallback    before_children_callback,
15824                          ClutterTraverseCallback    after_children_callback,
15825                          gpointer                   user_data)
15826 {
15827   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15828     _clutter_actor_traverse_breadth (actor,
15829                                      before_children_callback,
15830                                      user_data);
15831   else /* DEPTH_FIRST */
15832     _clutter_actor_traverse_depth (actor,
15833                                    before_children_callback,
15834                                    after_children_callback,
15835                                    0, /* start depth */
15836                                    user_data);
15837 }
15838
15839 static void
15840 on_layout_manager_changed (ClutterLayoutManager *manager,
15841                            ClutterActor         *self)
15842 {
15843   clutter_actor_queue_relayout (self);
15844 }
15845
15846 /**
15847  * clutter_actor_set_layout_manager:
15848  * @self: a #ClutterActor
15849  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15850  *
15851  * Sets the #ClutterLayoutManager delegate object that will be used to
15852  * lay out the children of @self.
15853  *
15854  * The #ClutterActor will take a reference on the passed @manager which
15855  * will be released either when the layout manager is removed, or when
15856  * the actor is destroyed.
15857  *
15858  * Since: 1.10
15859  */
15860 void
15861 clutter_actor_set_layout_manager (ClutterActor         *self,
15862                                   ClutterLayoutManager *manager)
15863 {
15864   ClutterActorPrivate *priv;
15865
15866   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15867   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15868
15869   priv = self->priv;
15870
15871   if (priv->layout_manager != NULL)
15872     {
15873       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15874                                             G_CALLBACK (on_layout_manager_changed),
15875                                             self);
15876       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15877       g_object_unref (priv->layout_manager);
15878     }
15879
15880   priv->layout_manager = manager;
15881
15882   if (priv->layout_manager != NULL)
15883     {
15884       g_object_ref_sink (priv->layout_manager);
15885       clutter_layout_manager_set_container (priv->layout_manager,
15886                                             CLUTTER_CONTAINER (self));
15887       g_signal_connect (priv->layout_manager, "layout-changed",
15888                         G_CALLBACK (on_layout_manager_changed),
15889                         self);
15890     }
15891
15892   clutter_actor_queue_relayout (self);
15893
15894   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15895 }
15896
15897 /**
15898  * clutter_actor_get_layout_manager:
15899  * @self: a #ClutterActor
15900  *
15901  * Retrieves the #ClutterLayoutManager used by @self.
15902  *
15903  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15904  *   or %NULL
15905  *
15906  * Since: 1.10
15907  */
15908 ClutterLayoutManager *
15909 clutter_actor_get_layout_manager (ClutterActor *self)
15910 {
15911   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15912
15913   return self->priv->layout_manager;
15914 }
15915
15916 static const ClutterLayoutInfo default_layout_info = {
15917   0.f,                          /* fixed-x */
15918   0.f,                          /* fixed-y */
15919   { 0, 0, 0, 0 },               /* margin */
15920   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15921   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15922   0.f, 0.f,                     /* min_width, natural_width */
15923   0.f, 0.f,                     /* natual_width, natural_height */
15924 };
15925
15926 static void
15927 layout_info_free (gpointer data)
15928 {
15929   if (G_LIKELY (data != NULL))
15930     g_slice_free (ClutterLayoutInfo, data);
15931 }
15932
15933 /*< private >
15934  * _clutter_actor_get_layout_info:
15935  * @self: a #ClutterActor
15936  *
15937  * Retrieves a pointer to the ClutterLayoutInfo structure.
15938  *
15939  * If the actor does not have a ClutterLayoutInfo associated to it, one
15940  * will be created and initialized to the default values.
15941  *
15942  * This function should be used for setters.
15943  *
15944  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15945  * instead.
15946  *
15947  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15948  */
15949 ClutterLayoutInfo *
15950 _clutter_actor_get_layout_info (ClutterActor *self)
15951 {
15952   ClutterLayoutInfo *retval;
15953
15954   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15955   if (retval == NULL)
15956     {
15957       retval = g_slice_new (ClutterLayoutInfo);
15958
15959       *retval = default_layout_info;
15960
15961       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15962                                retval,
15963                                layout_info_free);
15964     }
15965
15966   return retval;
15967 }
15968
15969 /*< private >
15970  * _clutter_actor_get_layout_info_or_defaults:
15971  * @self: a #ClutterActor
15972  *
15973  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15974  *
15975  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15976  * then the default structure will be returned.
15977  *
15978  * This function should only be used for getters.
15979  *
15980  * Return value: a const pointer to the ClutterLayoutInfo structure
15981  */
15982 const ClutterLayoutInfo *
15983 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15984 {
15985   const ClutterLayoutInfo *info;
15986
15987   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15988   if (info == NULL)
15989     return &default_layout_info;
15990
15991   return info;
15992 }
15993
15994 /**
15995  * clutter_actor_set_x_align:
15996  * @self: a #ClutterActor
15997  * @x_align: the horizontal alignment policy
15998  *
15999  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16000  * actor received extra horizontal space.
16001  *
16002  * See also the #ClutterActor:x-align property.
16003  *
16004  * Since: 1.10
16005  */
16006 void
16007 clutter_actor_set_x_align (ClutterActor      *self,
16008                            ClutterActorAlign  x_align)
16009 {
16010   ClutterLayoutInfo *info;
16011
16012   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16013
16014   info = _clutter_actor_get_layout_info (self);
16015
16016   if (info->x_align != x_align)
16017     {
16018       info->x_align = x_align;
16019
16020       clutter_actor_queue_relayout (self);
16021
16022       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16023     }
16024 }
16025
16026 /**
16027  * clutter_actor_get_x_align:
16028  * @self: a #ClutterActor
16029  *
16030  * Retrieves the horizontal alignment policy set using
16031  * clutter_actor_set_x_align().
16032  *
16033  * Return value: the horizontal alignment policy.
16034  *
16035  * Since: 1.10
16036  */
16037 ClutterActorAlign
16038 clutter_actor_get_x_align (ClutterActor *self)
16039 {
16040   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16041
16042   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16043 }
16044
16045 /**
16046  * clutter_actor_set_y_align:
16047  * @self: a #ClutterActor
16048  * @y_align: the vertical alignment policy
16049  *
16050  * Sets the vertical alignment policy of a #ClutterActor, in case the
16051  * actor received extra vertical space.
16052  *
16053  * See also the #ClutterActor:y-align property.
16054  *
16055  * Since: 1.10
16056  */
16057 void
16058 clutter_actor_set_y_align (ClutterActor      *self,
16059                            ClutterActorAlign  y_align)
16060 {
16061   ClutterLayoutInfo *info;
16062
16063   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16064
16065   info = _clutter_actor_get_layout_info (self);
16066
16067   if (info->y_align != y_align)
16068     {
16069       info->y_align = y_align;
16070
16071       clutter_actor_queue_relayout (self);
16072
16073       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16074     }
16075 }
16076
16077 /**
16078  * clutter_actor_get_y_align:
16079  * @self: a #ClutterActor
16080  *
16081  * Retrieves the vertical alignment policy set using
16082  * clutter_actor_set_y_align().
16083  *
16084  * Return value: the vertical alignment policy.
16085  *
16086  * Since: 1.10
16087  */
16088 ClutterActorAlign
16089 clutter_actor_get_y_align (ClutterActor *self)
16090 {
16091   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16092
16093   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16094 }
16095
16096
16097 /**
16098  * clutter_margin_new:
16099  *
16100  * Creates a new #ClutterMargin.
16101  *
16102  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16103  *   clutter_margin_free() to free the resources associated with it when
16104  *   done.
16105  *
16106  * Since: 1.10
16107  */
16108 ClutterMargin *
16109 clutter_margin_new (void)
16110 {
16111   return g_slice_new0 (ClutterMargin);
16112 }
16113
16114 /**
16115  * clutter_margin_copy:
16116  * @margin_: a #ClutterMargin
16117  *
16118  * Creates a new #ClutterMargin and copies the contents of @margin_ into
16119  * the newly created structure.
16120  *
16121  * Return value: (transfer full): a copy of the #ClutterMargin.
16122  *
16123  * Since: 1.10
16124  */
16125 ClutterMargin *
16126 clutter_margin_copy (const ClutterMargin *margin_)
16127 {
16128   if (G_LIKELY (margin_ != NULL))
16129     return g_slice_dup (ClutterMargin, margin_);
16130
16131   return NULL;
16132 }
16133
16134 /**
16135  * clutter_margin_free:
16136  * @margin_: a #ClutterMargin
16137  *
16138  * Frees the resources allocated by clutter_margin_new() and
16139  * clutter_margin_copy().
16140  *
16141  * Since: 1.10
16142  */
16143 void
16144 clutter_margin_free (ClutterMargin *margin_)
16145 {
16146   if (G_LIKELY (margin_ != NULL))
16147     g_slice_free (ClutterMargin, margin_);
16148 }
16149
16150 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16151                      clutter_margin_copy,
16152                      clutter_margin_free)
16153
16154 /**
16155  * clutter_actor_set_margin:
16156  * @self: a #ClutterActor
16157  * @margin: a #ClutterMargin
16158  *
16159  * Sets all the components of the margin of a #ClutterActor.
16160  *
16161  * Since: 1.10
16162  */
16163 void
16164 clutter_actor_set_margin (ClutterActor        *self,
16165                           const ClutterMargin *margin)
16166 {
16167   ClutterLayoutInfo *info;
16168   gboolean changed;
16169   GObject *obj;
16170
16171   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16172   g_return_if_fail (margin != NULL);
16173
16174   obj = G_OBJECT (self);
16175   changed = FALSE;
16176
16177   g_object_freeze_notify (obj);
16178
16179   info = _clutter_actor_get_layout_info (self);
16180
16181   if (info->margin.top != margin->top)
16182     {
16183       info->margin.top = margin->top;
16184       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16185       changed = TRUE;
16186     }
16187
16188   if (info->margin.right != margin->right)
16189     {
16190       info->margin.right = margin->right;
16191       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16192       changed = TRUE;
16193     }
16194
16195   if (info->margin.bottom != margin->bottom)
16196     {
16197       info->margin.bottom = margin->bottom;
16198       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16199       changed = TRUE;
16200     }
16201
16202   if (info->margin.left != margin->left)
16203     {
16204       info->margin.left = margin->left;
16205       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16206       changed = TRUE;
16207     }
16208
16209   if (changed)
16210     clutter_actor_queue_relayout (self);
16211
16212   g_object_thaw_notify (obj);
16213 }
16214
16215 /**
16216  * clutter_actor_get_margin:
16217  * @self: a #ClutterActor
16218  * @margin: (out caller-allocates): return location for a #ClutterMargin
16219  *
16220  * Retrieves all the components of the margin of a #ClutterActor.
16221  *
16222  * Since: 1.10
16223  */
16224 void
16225 clutter_actor_get_margin (ClutterActor  *self,
16226                           ClutterMargin *margin)
16227 {
16228   const ClutterLayoutInfo *info;
16229
16230   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16231   g_return_if_fail (margin != NULL);
16232
16233   info = _clutter_actor_get_layout_info_or_defaults (self);
16234
16235   *margin = info->margin;
16236 }
16237
16238 /**
16239  * clutter_actor_set_margin_top:
16240  * @self: a #ClutterActor
16241  * @margin: the top margin
16242  *
16243  * Sets the margin from the top of a #ClutterActor.
16244  *
16245  * Since: 1.10
16246  */
16247 void
16248 clutter_actor_set_margin_top (ClutterActor *self,
16249                               gfloat        margin)
16250 {
16251   ClutterLayoutInfo *info;
16252
16253   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16254   g_return_if_fail (margin >= 0.f);
16255
16256   info = _clutter_actor_get_layout_info (self);
16257
16258   if (info->margin.top == margin)
16259     return;
16260
16261   info->margin.top = margin;
16262
16263   clutter_actor_queue_relayout (self);
16264
16265   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16266 }
16267
16268 /**
16269  * clutter_actor_get_margin_top:
16270  * @self: a #ClutterActor
16271  *
16272  * Retrieves the top margin of a #ClutterActor.
16273  *
16274  * Return value: the top margin
16275  *
16276  * Since: 1.10
16277  */
16278 gfloat
16279 clutter_actor_get_margin_top (ClutterActor *self)
16280 {
16281   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16282
16283   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16284 }
16285
16286 /**
16287  * clutter_actor_set_margin_bottom:
16288  * @self: a #ClutterActor
16289  * @margin: the bottom margin
16290  *
16291  * Sets the margin from the bottom of a #ClutterActor.
16292  *
16293  * Since: 1.10
16294  */
16295 void
16296 clutter_actor_set_margin_bottom (ClutterActor *self,
16297                                  gfloat        margin)
16298 {
16299   ClutterLayoutInfo *info;
16300
16301   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16302   g_return_if_fail (margin >= 0.f);
16303
16304   info = _clutter_actor_get_layout_info (self);
16305
16306   if (info->margin.bottom == margin)
16307     return;
16308
16309   info->margin.bottom = margin;
16310
16311   clutter_actor_queue_relayout (self);
16312
16313   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16314 }
16315
16316 /**
16317  * clutter_actor_get_margin_bottom:
16318  * @self: a #ClutterActor
16319  *
16320  * Retrieves the bottom margin of a #ClutterActor.
16321  *
16322  * Return value: the bottom margin
16323  *
16324  * Since: 1.10
16325  */
16326 gfloat
16327 clutter_actor_get_margin_bottom (ClutterActor *self)
16328 {
16329   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16330
16331   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16332 }
16333
16334 /**
16335  * clutter_actor_set_margin_left:
16336  * @self: a #ClutterActor
16337  * @margin: the left margin
16338  *
16339  * Sets the margin from the left of a #ClutterActor.
16340  *
16341  * Since: 1.10
16342  */
16343 void
16344 clutter_actor_set_margin_left (ClutterActor *self,
16345                                gfloat        margin)
16346 {
16347   ClutterLayoutInfo *info;
16348
16349   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16350   g_return_if_fail (margin >= 0.f);
16351
16352   info = _clutter_actor_get_layout_info (self);
16353
16354   if (info->margin.left == margin)
16355     return;
16356
16357   info->margin.left = margin;
16358
16359   clutter_actor_queue_relayout (self);
16360
16361   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16362 }
16363
16364 /**
16365  * clutter_actor_get_margin_left:
16366  * @self: a #ClutterActor
16367  *
16368  * Retrieves the left margin of a #ClutterActor.
16369  *
16370  * Return value: the left margin
16371  *
16372  * Since: 1.10
16373  */
16374 gfloat
16375 clutter_actor_get_margin_left (ClutterActor *self)
16376 {
16377   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16378
16379   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16380 }
16381
16382 /**
16383  * clutter_actor_set_margin_right:
16384  * @self: a #ClutterActor
16385  * @margin: the right margin
16386  *
16387  * Sets the margin from the right of a #ClutterActor.
16388  *
16389  * Since: 1.10
16390  */
16391 void
16392 clutter_actor_set_margin_right (ClutterActor *self,
16393                                 gfloat        margin)
16394 {
16395   ClutterLayoutInfo *info;
16396
16397   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16398   g_return_if_fail (margin >= 0.f);
16399
16400   info = _clutter_actor_get_layout_info (self);
16401
16402   if (info->margin.right == margin)
16403     return;
16404
16405   info->margin.right = margin;
16406
16407   clutter_actor_queue_relayout (self);
16408
16409   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16410 }
16411
16412 /**
16413  * clutter_actor_get_margin_right:
16414  * @self: a #ClutterActor
16415  *
16416  * Retrieves the right margin of a #ClutterActor.
16417  *
16418  * Return value: the right margin
16419  *
16420  * Since: 1.10
16421  */
16422 gfloat
16423 clutter_actor_get_margin_right (ClutterActor *self)
16424 {
16425   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16426
16427   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16428 }
16429
16430 static inline void
16431 clutter_actor_set_background_color_internal (ClutterActor *self,
16432                                              const ClutterColor *color)
16433 {
16434   ClutterActorPrivate *priv = self->priv;
16435   GObject *obj;
16436
16437   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16438     return;
16439
16440   obj = G_OBJECT (self);
16441
16442   priv->bg_color = *color;
16443   priv->bg_color_set = TRUE;
16444
16445   clutter_actor_queue_redraw (self);
16446
16447   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16448   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16449 }
16450
16451 /**
16452  * clutter_actor_set_background_color:
16453  * @self: a #ClutterActor
16454  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16455  *  set color
16456  *
16457  * Sets the background color of a #ClutterActor.
16458  *
16459  * The background color will be used to cover the whole allocation of the
16460  * actor. The default background color of an actor is transparent.
16461  *
16462  * To check whether an actor has a background color, you can use the
16463  * #ClutterActor:background-color-set actor property.
16464  *
16465  * The #ClutterActor:background-color property is animatable.
16466  *
16467  * Since: 1.10
16468  */
16469 void
16470 clutter_actor_set_background_color (ClutterActor       *self,
16471                                     const ClutterColor *color)
16472 {
16473   ClutterActorPrivate *priv;
16474   GObject *obj;
16475   GParamSpec *bg_color_pspec;
16476
16477   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16478
16479   obj = G_OBJECT (self);
16480
16481   priv = self->priv;
16482
16483   if (color == NULL)
16484     {
16485       priv->bg_color_set = FALSE;
16486       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16487       clutter_actor_queue_redraw (self);
16488       return;
16489     }
16490
16491   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16492   if (clutter_actor_get_easing_duration (self) != 0)
16493     {
16494       ClutterTransition *transition;
16495
16496       transition = _clutter_actor_get_transition (self, bg_color_pspec);
16497       if (transition == NULL)
16498         {
16499           transition = _clutter_actor_create_transition (self, bg_color_pspec,
16500                                                          &priv->bg_color,
16501                                                          color);
16502           clutter_timeline_start (CLUTTER_TIMELINE (transition));
16503         }
16504       else
16505         _clutter_actor_update_transition (self, bg_color_pspec, color);
16506
16507       clutter_actor_queue_redraw (self);
16508     }
16509   else
16510     clutter_actor_set_background_color_internal (self, color);
16511 }
16512
16513 /**
16514  * clutter_actor_get_background_color:
16515  * @self: a #ClutterActor
16516  * @color: (out caller-allocates): return location for a #ClutterColor
16517  *
16518  * Retrieves the color set using clutter_actor_set_background_color().
16519  *
16520  * Since: 1.10
16521  */
16522 void
16523 clutter_actor_get_background_color (ClutterActor *self,
16524                                     ClutterColor *color)
16525 {
16526   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16527   g_return_if_fail (color != NULL);
16528
16529   *color = self->priv->bg_color;
16530 }
16531
16532 /**
16533  * clutter_actor_get_previous_sibling:
16534  * @self: a #ClutterActor
16535  *
16536  * Retrieves the sibling of @self that comes before it in the list
16537  * of children of @self's parent.
16538  *
16539  * The returned pointer is only valid until the scene graph changes; it
16540  * is not safe to modify the list of children of @self while iterating
16541  * it.
16542  *
16543  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16544  *
16545  * Since: 1.10
16546  */
16547 ClutterActor *
16548 clutter_actor_get_previous_sibling (ClutterActor *self)
16549 {
16550   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16551
16552   return self->priv->prev_sibling;
16553 }
16554
16555 /**
16556  * clutter_actor_get_next_sibling:
16557  * @self: a #ClutterActor
16558  *
16559  * Retrieves the sibling of @self that comes after it in the list
16560  * of children of @self's parent.
16561  *
16562  * The returned pointer is only valid until the scene graph changes; it
16563  * is not safe to modify the list of children of @self while iterating
16564  * it.
16565  *
16566  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16567  *
16568  * Since: 1.10
16569  */
16570 ClutterActor *
16571 clutter_actor_get_next_sibling (ClutterActor *self)
16572 {
16573   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16574
16575   return self->priv->next_sibling;
16576 }
16577
16578 /**
16579  * clutter_actor_get_first_child:
16580  * @self: a #ClutterActor
16581  *
16582  * Retrieves the first child of @self.
16583  *
16584  * The returned pointer is only valid until the scene graph changes; it
16585  * is not safe to modify the list of children of @self while iterating
16586  * it.
16587  *
16588  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16589  *
16590  * Since: 1.10
16591  */
16592 ClutterActor *
16593 clutter_actor_get_first_child (ClutterActor *self)
16594 {
16595   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16596
16597   return self->priv->first_child;
16598 }
16599
16600 /**
16601  * clutter_actor_get_last_child:
16602  * @self: a #ClutterActor
16603  *
16604  * Retrieves the last child of @self.
16605  *
16606  * The returned pointer is only valid until the scene graph changes; it
16607  * is not safe to modify the list of children of @self while iterating
16608  * it.
16609  *
16610  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16611  *
16612  * Since: 1.10
16613  */
16614 ClutterActor *
16615 clutter_actor_get_last_child (ClutterActor *self)
16616 {
16617   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16618
16619   return self->priv->last_child;
16620 }
16621
16622 /* easy way to have properly named fields instead of the dummy ones
16623  * we use in the public structure
16624  */
16625 typedef struct _RealActorIter
16626 {
16627   ClutterActor *root;           /* dummy1 */
16628   ClutterActor *current;        /* dummy2 */
16629   gpointer padding_1;           /* dummy3 */
16630   gint age;                     /* dummy4 */
16631   gpointer padding_2;           /* dummy5 */
16632 } RealActorIter;
16633
16634 /**
16635  * clutter_actor_iter_init:
16636  * @iter: a #ClutterActorIter
16637  * @root: a #ClutterActor
16638  *
16639  * Initializes a #ClutterActorIter, which can then be used to iterate
16640  * efficiently over a section of the scene graph, and associates it
16641  * with @root.
16642  *
16643  * Modifying the scene graph section that contains @root will invalidate
16644  * the iterator.
16645  *
16646  * |[
16647  *   ClutterActorIter iter;
16648  *   ClutterActor *child;
16649  *
16650  *   clutter_actor_iter_init (&iter, container);
16651  *   while (clutter_actor_iter_next (&iter, &child))
16652  *     {
16653  *       /&ast; do something with child &ast;/
16654  *     }
16655  * ]|
16656  *
16657  * Since: 1.10
16658  */
16659 void
16660 clutter_actor_iter_init (ClutterActorIter *iter,
16661                          ClutterActor     *root)
16662 {
16663   RealActorIter *ri = (RealActorIter *) iter;
16664
16665   g_return_if_fail (iter != NULL);
16666   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16667
16668   ri->root = root;
16669   ri->current = NULL;
16670   ri->age = root->priv->age;
16671 }
16672
16673 /**
16674  * clutter_actor_iter_next:
16675  * @iter: a #ClutterActorIter
16676  * @child: (out): return location for a #ClutterActor
16677  *
16678  * Advances the @iter and retrieves the next child of the root #ClutterActor
16679  * that was used to initialize the #ClutterActorIterator.
16680  *
16681  * If the iterator can advance, this function returns %TRUE and sets the
16682  * @child argument.
16683  *
16684  * If the iterator cannot advance, this function returns %FALSE, and
16685  * the contents of @child are undefined.
16686  *
16687  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16688  *
16689  * Since: 1.10
16690  */
16691 gboolean
16692 clutter_actor_iter_next (ClutterActorIter  *iter,
16693                          ClutterActor     **child)
16694 {
16695   RealActorIter *ri = (RealActorIter *) iter;
16696
16697   g_return_val_if_fail (iter != NULL, FALSE);
16698   g_return_val_if_fail (ri->root != NULL, FALSE);
16699 #ifndef G_DISABLE_ASSERT
16700   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16701 #endif
16702
16703   if (ri->current == NULL)
16704     ri->current = ri->root->priv->first_child;
16705   else
16706     ri->current = ri->current->priv->next_sibling;
16707
16708   if (child != NULL)
16709     *child = ri->current;
16710
16711   return ri->current != NULL;
16712 }
16713
16714 /**
16715  * clutter_actor_iter_prev:
16716  * @iter: a #ClutterActorIter
16717  * @child: (out): return location for a #ClutterActor
16718  *
16719  * Advances the @iter and retrieves the previous child of the root
16720  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16721  *
16722  * If the iterator can advance, this function returns %TRUE and sets the
16723  * @child argument.
16724  *
16725  * If the iterator cannot advance, this function returns %FALSE, and
16726  * the contents of @child are undefined.
16727  *
16728  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16729  *
16730  * Since: 1.10
16731  */
16732 gboolean
16733 clutter_actor_iter_prev (ClutterActorIter  *iter,
16734                          ClutterActor     **child)
16735 {
16736   RealActorIter *ri = (RealActorIter *) iter;
16737
16738   g_return_val_if_fail (iter != NULL, FALSE);
16739   g_return_val_if_fail (ri->root != NULL, FALSE);
16740 #ifndef G_DISABLE_ASSERT
16741   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16742 #endif
16743
16744   if (ri->current == NULL)
16745     ri->current = ri->root->priv->last_child;
16746   else
16747     ri->current = ri->current->priv->prev_sibling;
16748
16749   if (child != NULL)
16750     *child = ri->current;
16751
16752   return ri->current != NULL;
16753 }
16754
16755 /**
16756  * clutter_actor_iter_remove:
16757  * @iter: a #ClutterActorIter
16758  *
16759  * Safely removes the #ClutterActor currently pointer to by the iterator
16760  * from its parent.
16761  *
16762  * This function can only be called after clutter_actor_iter_next() or
16763  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16764  * than once for the same actor.
16765  *
16766  * This function will call clutter_actor_remove_child() internally.
16767  *
16768  * Since: 1.10
16769  */
16770 void
16771 clutter_actor_iter_remove (ClutterActorIter *iter)
16772 {
16773   RealActorIter *ri = (RealActorIter *) iter;
16774   ClutterActor *cur;
16775
16776   g_return_if_fail (iter != NULL);
16777   g_return_if_fail (ri->root != NULL);
16778 #ifndef G_DISABLE_ASSERT
16779   g_return_if_fail (ri->age == ri->root->priv->age);
16780 #endif
16781   g_return_if_fail (ri->current != NULL);
16782
16783   cur = ri->current;
16784
16785   if (cur != NULL)
16786     {
16787       ri->current = cur->priv->prev_sibling;
16788
16789       clutter_actor_remove_child_internal (ri->root, cur,
16790                                            REMOVE_CHILD_DEFAULT_FLAGS);
16791
16792       ri->age += 1;
16793     }
16794 }
16795
16796 /**
16797  * clutter_actor_iter_destroy:
16798  * @iter: a #ClutterActorIter
16799  *
16800  * Safely destroys the #ClutterActor currently pointer to by the iterator
16801  * from its parent.
16802  *
16803  * This function can only be called after clutter_actor_iter_next() or
16804  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16805  * than once for the same actor.
16806  *
16807  * This function will call clutter_actor_destroy() internally.
16808  *
16809  * Since: 1.10
16810  */
16811 void
16812 clutter_actor_iter_destroy (ClutterActorIter *iter)
16813 {
16814   RealActorIter *ri = (RealActorIter *) iter;
16815   ClutterActor *cur;
16816
16817   g_return_if_fail (iter != NULL);
16818   g_return_if_fail (ri->root != NULL);
16819 #ifndef G_DISABLE_ASSERT
16820   g_return_if_fail (ri->age == ri->root->priv->age);
16821 #endif
16822   g_return_if_fail (ri->current != NULL);
16823
16824   cur = ri->current;
16825
16826   if (cur != NULL)
16827     {
16828       ri->current = cur->priv->prev_sibling;
16829
16830       clutter_actor_destroy (cur);
16831
16832       ri->age += 1;
16833     }
16834 }
16835
16836 static const ClutterAnimationInfo default_animation_info = {
16837   NULL,         /* transitions */
16838   NULL,         /* states */
16839   NULL,         /* cur_state */
16840 };
16841
16842 static void
16843 clutter_animation_info_free (gpointer data)
16844 {
16845   if (data != NULL)
16846     {
16847       ClutterAnimationInfo *info = data;
16848
16849       if (info->transitions != NULL)
16850         g_hash_table_unref (info->transitions);
16851
16852       if (info->states != NULL)
16853         g_array_unref (info->states);
16854
16855       g_slice_free (ClutterAnimationInfo, info);
16856     }
16857 }
16858
16859 const ClutterAnimationInfo *
16860 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16861 {
16862   const ClutterAnimationInfo *res;
16863   GObject *obj = G_OBJECT (self);
16864
16865   res = g_object_get_qdata (obj, quark_actor_animation_info);
16866   if (res != NULL)
16867     return res;
16868
16869   return &default_animation_info;
16870 }
16871
16872 ClutterAnimationInfo *
16873 _clutter_actor_get_animation_info (ClutterActor *self)
16874 {
16875   GObject *obj = G_OBJECT (self);
16876   ClutterAnimationInfo *res;
16877
16878   res = g_object_get_qdata (obj, quark_actor_animation_info);
16879   if (res == NULL)
16880     {
16881       res = g_slice_new (ClutterAnimationInfo);
16882
16883       *res = default_animation_info;
16884
16885       g_object_set_qdata_full (obj, quark_actor_animation_info,
16886                                res,
16887                                clutter_animation_info_free);
16888     }
16889
16890   return res;
16891 }
16892
16893 ClutterTransition *
16894 _clutter_actor_get_transition (ClutterActor *actor,
16895                                GParamSpec   *pspec)
16896 {
16897   const ClutterAnimationInfo *info;
16898
16899   info = _clutter_actor_get_animation_info_or_defaults (actor);
16900
16901   if (info->transitions == NULL)
16902     return NULL;
16903
16904   return g_hash_table_lookup (info->transitions, pspec->name);
16905 }
16906
16907 typedef struct _TransitionClosure
16908 {
16909   ClutterActor *actor;
16910   ClutterTransition *transition;
16911   gchar *name;
16912   gulong completed_id;
16913 } TransitionClosure;
16914
16915 static void
16916 transition_closure_free (gpointer data)
16917 {
16918   if (G_LIKELY (data != NULL))
16919     {
16920       TransitionClosure *clos = data;
16921
16922       g_signal_handler_disconnect (clos->transition, clos->completed_id);
16923       g_free (clos->name);
16924
16925       g_slice_free (TransitionClosure, clos);
16926     }
16927 }
16928
16929 static void
16930 on_transition_completed (ClutterTransition *transition,
16931                          TransitionClosure *clos)
16932 {
16933   ClutterAnimationInfo *info;
16934
16935   info = _clutter_actor_get_animation_info (clos->actor);
16936
16937   /* this will take care of cleaning clos for us */
16938   g_hash_table_remove (info->transitions, clos->name);
16939 }
16940
16941 void
16942 _clutter_actor_update_transition (ClutterActor *actor,
16943                                   GParamSpec   *pspec,
16944                                   ...)
16945 {
16946   TransitionClosure *clos;
16947   ClutterInterval *interval;
16948   const ClutterAnimationInfo *info;
16949   va_list var_args;
16950   GType ptype;
16951   GValue initial = G_VALUE_INIT;
16952   GValue final = G_VALUE_INIT;
16953   char *error = NULL;
16954
16955   info = _clutter_actor_get_animation_info_or_defaults (actor);
16956
16957   if (info->transitions == NULL)
16958     return;
16959
16960   clos = g_hash_table_lookup (info->transitions, pspec->name);
16961   if (clos == NULL)
16962     return;
16963
16964   va_start (var_args, pspec);
16965
16966   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16967
16968   g_value_init (&initial, ptype);
16969   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
16970                                         pspec->name,
16971                                         &initial);
16972
16973   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
16974   if (error != NULL)
16975     {
16976       g_critical ("%s: %s", G_STRLOC, error);
16977       g_free (error);
16978       goto out;
16979     }
16980
16981   interval = clutter_transition_get_interval (clos->transition);
16982   clutter_interval_set_initial_value (interval, &initial);
16983   clutter_interval_set_final_value (interval, &final);
16984
16985   clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
16986
16987 out:
16988   g_value_unset (&initial);
16989   g_value_unset (&final);
16990
16991   va_end (var_args);
16992 }
16993
16994 /*< private >*
16995  * _clutter_actor_create_transition:
16996  * @actor: a #ClutterActor
16997  * @pspec: the property used for the transition
16998  * @...: initial and final state
16999  *
17000  * Creates a #ClutterTransition for the property represented by @pspec.
17001  *
17002  * Return value: a #ClutterTransition
17003  */
17004 ClutterTransition *
17005 _clutter_actor_create_transition (ClutterActor *actor,
17006                                   GParamSpec   *pspec,
17007                                   ...)
17008 {
17009   ClutterAnimationInfo *info;
17010   ClutterTransition *res = NULL;
17011   gboolean call_restore = FALSE;
17012   TransitionClosure *clos;
17013   va_list var_args;
17014
17015   info = _clutter_actor_get_animation_info (actor);
17016
17017   if (info->states == NULL)
17018     {
17019       clutter_actor_save_easing_state (actor);
17020       call_restore = TRUE;
17021     }
17022
17023   if (info->transitions == NULL)
17024     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17025                                                NULL,
17026                                                transition_closure_free);
17027
17028   va_start (var_args, pspec);
17029
17030   clos = g_hash_table_lookup (info->transitions, pspec->name);
17031   if (clos == NULL)
17032     {
17033       ClutterInterval *interval;
17034       GValue initial = G_VALUE_INIT;
17035       GValue final = G_VALUE_INIT;
17036       GType ptype;
17037       char *error;
17038
17039       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17040
17041       G_VALUE_COLLECT_INIT (&initial, ptype,
17042                             var_args, 0,
17043                             &error);
17044       if (error != NULL)
17045         {
17046           g_critical ("%s: %s", G_STRLOC, error);
17047           g_free (error);
17048           goto out;
17049         }
17050
17051       G_VALUE_COLLECT_INIT (&final, ptype,
17052                             var_args, 0,
17053                             &error);
17054
17055       if (error != NULL)
17056         {
17057           g_critical ("%s: %s", G_STRLOC, error);
17058           g_value_unset (&initial);
17059           g_free (error);
17060           goto out;
17061         }
17062
17063       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17064
17065       g_value_unset (&initial);
17066       g_value_unset (&final);
17067
17068       res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
17069                                              pspec->name);
17070
17071       clutter_transition_set_interval (res, interval);
17072       clutter_transition_set_remove_on_complete (res, TRUE);
17073
17074       clutter_actor_add_transition (actor, pspec->name, res);
17075     }
17076   else
17077     res = clos->transition;
17078
17079 out:
17080   if (call_restore)
17081     clutter_actor_restore_easing_state (actor);
17082
17083   va_end (var_args);
17084
17085   return res;
17086 }
17087
17088 /**
17089  * clutter_actor_add_transition:
17090  * @self: a #ClutterActor
17091  * @name: the name of the transition to add
17092  * @transition: the #ClutterTransition to add
17093  *
17094  * Adds a @transition to the #ClutterActor's list of animations.
17095  *
17096  * The @name string is a per-actor unique identifier of the @transition: only
17097  * one #ClutterTransition can be associated to the specified @name.
17098  *
17099  * The @transition will be given the easing duration, mode, and delay
17100  * associated to the actor's current easing state; it is possible to modify
17101  * these values after calling clutter_actor_add_transition().
17102  *
17103  * This function is usually called implicitly when modifying an animatable
17104  * property.
17105  *
17106  * Since: 1.10
17107  */
17108 void
17109 clutter_actor_add_transition (ClutterActor      *self,
17110                               const char        *name,
17111                               ClutterTransition *transition)
17112 {
17113   ClutterTimeline *timeline;
17114   TransitionClosure *clos;
17115   ClutterAnimationInfo *info;
17116
17117   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17118   g_return_if_fail (name != NULL);
17119   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17120
17121   info = _clutter_actor_get_animation_info (self);
17122
17123   if (info->cur_state == NULL)
17124     {
17125       g_warning ("No easing state is defined for the actor '%s'; you "
17126                  "must call clutter_actor_save_easing_state() before "
17127                  "calling clutter_actor_add_transition().",
17128                  _clutter_actor_get_debug_name (self));
17129       return;
17130     }
17131
17132   if (info->transitions == NULL)
17133     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17134                                                NULL,
17135                                                transition_closure_free);
17136
17137   if (g_hash_table_lookup (info->transitions, name) != NULL)
17138     {
17139       g_warning ("A transition with name '%s' already exists for "
17140                  "the actor '%s'",
17141                  name,
17142                  _clutter_actor_get_debug_name (self));
17143       return;
17144     }
17145
17146   timeline = CLUTTER_TIMELINE (transition);
17147
17148   clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17149   clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17150   clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17151
17152   clos = g_slice_new (TransitionClosure);
17153   clos->actor = self;
17154   clos->transition = transition;
17155   clos->name = g_strdup (name);
17156   clos->completed_id = g_signal_connect (timeline, "completed",
17157                                          G_CALLBACK (on_transition_completed),
17158                                          clos);
17159
17160   g_hash_table_insert (info->transitions, clos->name, clos);
17161 }
17162
17163 /**
17164  * clutter_actor_remove_transition:
17165  * @self: a #ClutterActor
17166  * @name: the name of the transition to remove
17167  *
17168  * Removes the transition stored inside a #ClutterActor using @name
17169  * identifier.
17170  *
17171  * Since: 1.10
17172  */
17173 void
17174 clutter_actor_remove_transition (ClutterActor *self,
17175                                  const char   *name)
17176 {
17177   const ClutterAnimationInfo *info;
17178
17179   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17180   g_return_if_fail (name != NULL);
17181
17182   info = _clutter_actor_get_animation_info_or_defaults (self);
17183
17184   if (info->transitions == NULL)
17185     return;
17186
17187   g_hash_table_remove (info->transitions, name);
17188 }
17189
17190 /**
17191  * clutter_actor_remove_all_transitions:
17192  * @self: a #ClutterActor
17193  *
17194  * Removes all transitions associated to @self.
17195  *
17196  * Since: 1.10
17197  */
17198 void
17199 clutter_actor_remove_all_transitions (ClutterActor *self)
17200 {
17201   const ClutterAnimationInfo *info;
17202
17203   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17204
17205   info = _clutter_actor_get_animation_info_or_defaults (self);
17206   if (info->transitions == NULL)
17207     return;
17208
17209   g_hash_table_remove_all (info->transitions);
17210 }
17211
17212 /**
17213  * clutter_actor_set_easing_duration:
17214  * @self: a #ClutterActor
17215  * @msecs: the duration of the easing, or %NULL
17216  *
17217  * Sets the duration of the tweening for animatable properties
17218  * of @self for the current easing state.
17219  *
17220  * Calling this function will implicitly call
17221  * clutter_actor_save_easing_state() if no previous call to
17222  * that function was made.
17223  *
17224  * Since: 1.10
17225  */
17226 void
17227 clutter_actor_set_easing_duration (ClutterActor *self,
17228                                    guint         msecs)
17229 {
17230   ClutterAnimationInfo *info;
17231
17232   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17233
17234   info = _clutter_actor_get_animation_info (self);
17235
17236   if (info->states == NULL)
17237     clutter_actor_save_easing_state (self);
17238
17239   if (info->cur_state->easing_duration != msecs)
17240     info->cur_state->easing_duration = msecs;
17241 }
17242
17243 /**
17244  * clutter_actor_get_easing_duration:
17245  * @self: a #ClutterActor
17246  *
17247  * Retrieves the duration of the tweening for animatable
17248  * properties of @self for the current easing state.
17249  *
17250  * Return value: the duration of the tweening, in milliseconds
17251  *
17252  * Since: 1.10
17253  */
17254 guint
17255 clutter_actor_get_easing_duration (ClutterActor *self)
17256 {
17257   const ClutterAnimationInfo *info;
17258
17259   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17260
17261   info = _clutter_actor_get_animation_info_or_defaults (self);
17262
17263   if (info->cur_state != NULL)
17264     return info->cur_state->easing_duration;
17265
17266   return 0;
17267 }
17268
17269 /**
17270  * clutter_actor_set_easing_mode:
17271  * @self: a #ClutterActor
17272  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17273  *
17274  * Sets the easing mode for the tweening of animatable properties
17275  * of @self.
17276  *
17277  * Calling this function will implicitly call
17278  * clutter_actor_save_easing_state() if no previous calls to
17279  * that function were made.
17280  *
17281  * Since: 1.10
17282  */
17283 void
17284 clutter_actor_set_easing_mode (ClutterActor         *self,
17285                                ClutterAnimationMode  mode)
17286 {
17287   ClutterAnimationInfo *info;
17288
17289   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17290   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17291   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17292
17293   info = _clutter_actor_get_animation_info (self);
17294
17295   if (info->states == NULL)
17296     clutter_actor_save_easing_state (self);
17297
17298   if (info->cur_state->easing_mode != mode)
17299     info->cur_state->easing_mode = mode;
17300 }
17301
17302 /**
17303  * clutter_actor_get_easing_mode:
17304  * @self: a #ClutterActor
17305  *
17306  * Retrieves the easing mode for the tweening of animatable properties
17307  * of @self for the current easing state.
17308  *
17309  * Return value: an easing mode
17310  *
17311  * Since: 1.10
17312  */
17313 ClutterAnimationMode
17314 clutter_actor_get_easing_mode (ClutterActor *self)
17315 {
17316   const ClutterAnimationInfo *info;
17317
17318   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17319
17320   info = _clutter_actor_get_animation_info_or_defaults (self);
17321
17322   if (info->cur_state != NULL)
17323     return info->cur_state->easing_mode;
17324
17325   return CLUTTER_EASE_OUT_CUBIC;
17326 }
17327
17328 /**
17329  * clutter_actor_set_easing_delay:
17330  * @self: a #ClutterActor
17331  * @msecs: the delay before the start of the tweening, in milliseconds
17332  *
17333  * Sets the delay that should be applied before tweening animatable
17334  * properties.
17335  *
17336  * Calling this function will implicitly call
17337  * clutter_actor_save_easing_state() if no previous calls to
17338  * that function were made.
17339  *
17340  * Since: 1.10
17341  */
17342 void
17343 clutter_actor_set_easing_delay (ClutterActor *self,
17344                                 guint         msecs)
17345 {
17346   ClutterAnimationInfo *info;
17347
17348   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17349
17350   info = _clutter_actor_get_animation_info (self);
17351
17352   if (info->states == NULL)
17353     clutter_actor_save_easing_state (self);
17354
17355   if (info->cur_state->easing_delay != msecs)
17356     info->cur_state->easing_delay = msecs;
17357 }
17358
17359 /**
17360  * clutter_actor_get_easing_delay:
17361  * @self: a #ClutterActor
17362  *
17363  * Retrieves the delay that should be applied when tweening animatable
17364  * properties.
17365  *
17366  * Return value: a delay, in milliseconds
17367  *
17368  * Since: 1.10
17369  */
17370 guint
17371 clutter_actor_get_easing_delay (ClutterActor *self)
17372 {
17373   const ClutterAnimationInfo *info;
17374
17375   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17376
17377   info = _clutter_actor_get_animation_info_or_defaults (self);
17378
17379   if (info->cur_state != NULL)
17380     return info->cur_state->easing_delay;
17381
17382   return 0;
17383 }
17384
17385 /**
17386  * clutter_actor_get_transition:
17387  * @self: a #ClutterActor
17388  * @name: the name of the transition
17389  *
17390  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17391  * transition @name.
17392  *
17393  * Transitions created for animatable properties use the name of the
17394  * property itself, for instance the code below:
17395  *
17396  * |[
17397  *   clutter_actor_set_easing_duration (actor, 1000);
17398  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17399  *
17400  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17401  *   g_signal_connect (transition, "completed",
17402  *                     G_CALLBACK (on_transition_complete),
17403  *                     actor);
17404  * ]|
17405  *
17406  * will call the <function>on_transition_complete</function> callback when
17407  * the transition is complete.
17408  *
17409  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17410  *   was found to match the passed name; the returned instance is owned
17411  *   by Clutter and it should not be freed
17412  *
17413  * Since: 1.10
17414  */
17415 ClutterTransition *
17416 clutter_actor_get_transition (ClutterActor *self,
17417                               const char   *name)
17418 {
17419   TransitionClosure *clos;
17420   const ClutterAnimationInfo *info;
17421
17422   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17423   g_return_val_if_fail (name != NULL, NULL);
17424
17425   info = _clutter_actor_get_animation_info_or_defaults (self);
17426
17427   if (info->transitions == NULL)
17428     return NULL;
17429
17430   clos = g_hash_table_lookup (info->transitions, name);
17431   if (clos == NULL)
17432     return NULL;
17433
17434   return clos->transition;
17435 }
17436
17437 /**
17438  * clutter_actor_save_easing_state:
17439  * @self: a #ClutterActor
17440  *
17441  * Saves the current easing state for animatable properties, and creates
17442  * a new state with the default values for easing mode and duration.
17443  *
17444  * Since: 1.10
17445  */
17446 void
17447 clutter_actor_save_easing_state (ClutterActor *self)
17448 {
17449   ClutterAnimationInfo *info;
17450   AState new_state;
17451
17452   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17453
17454   info = _clutter_actor_get_animation_info (self);
17455
17456   if (info->states == NULL)
17457     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17458
17459   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17460   new_state.easing_duration = 250;
17461   new_state.easing_delay = 0;
17462
17463   g_array_append_val (info->states, new_state);
17464
17465   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17466 }
17467
17468 /**
17469  * clutter_actor_restore_easing_state:
17470  * @self: a #ClutterActor
17471  *
17472  * Restores the easing state as it was prior to a call to
17473  * clutter_actor_save_easing_state().
17474  *
17475  * Since: 1.10
17476  */
17477 void
17478 clutter_actor_restore_easing_state (ClutterActor *self)
17479 {
17480   ClutterAnimationInfo *info;
17481
17482   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17483
17484   info = _clutter_actor_get_animation_info (self);
17485
17486   if (info->states == NULL)
17487     {
17488       g_critical ("The function clutter_actor_restore_easing_state() has "
17489                   "called without a previous call to "
17490                   "clutter_actor_save_easing_state().");
17491       return;
17492     }
17493
17494   g_array_remove_index (info->states, info->states->len - 1);
17495   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17496 }
17497
17498 /**
17499  * clutter_actor_set_content:
17500  * @self: a #ClutterActor
17501  * @content: (allow-none): a #ClutterContent, or %NULL
17502  *
17503  * Sets the contents of a #ClutterActor.
17504  *
17505  * Since: 1.10
17506  */
17507 void
17508 clutter_actor_set_content (ClutterActor   *self,
17509                            ClutterContent *content)
17510 {
17511   ClutterActorPrivate *priv;
17512
17513   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17514   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17515
17516   priv = self->priv;
17517
17518   if (priv->content != NULL)
17519     {
17520       _clutter_content_detached (priv->content, self);
17521       g_object_unref (priv->content);
17522     }
17523
17524   priv->content = content;
17525
17526   if (priv->content != NULL)
17527     {
17528       g_object_ref (priv->content);
17529       _clutter_content_attached (priv->content, self);
17530     }
17531
17532   /* given that the content is always painted within the allocation,
17533    * we only need to queue a redraw here
17534    */
17535   clutter_actor_queue_redraw (self);
17536
17537   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17538
17539   /* if the content gravity is not resize-fill, and the new content has a
17540    * different preferred size than the previous one, then the content box
17541    * may have been changed. since we compute that lazily, we just notify
17542    * here, and let whomever watches :content-box do whatever they need to
17543    * do.
17544    */
17545   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17546     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17547 }
17548
17549 /**
17550  * clutter_actor_get_content:
17551  * @self: a #ClutterActor
17552  *
17553  * Retrieves the contents of @self.
17554  *
17555  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17556  *   or %NULL if none was set
17557  *
17558  * Since: 1.10
17559  */
17560 ClutterContent *
17561 clutter_actor_get_content (ClutterActor *self)
17562 {
17563   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17564
17565   return self->priv->content;
17566 }
17567
17568 /**
17569  * clutter_actor_set_content_gravity:
17570  * @self: a #ClutterActor
17571  * @gravity: the #ClutterContentGravity
17572  *
17573  * Sets the gravity of the #ClutterContent used by @self.
17574  *
17575  * See the description of the #ClutterActor:content-gravity property for
17576  * more information.
17577  *
17578  * Since: 1.10
17579  */
17580 void
17581 clutter_actor_set_content_gravity (ClutterActor *self,
17582                                    ClutterContentGravity  gravity)
17583 {
17584   ClutterActorPrivate *priv;
17585
17586   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17587
17588   priv = self->priv;
17589
17590   if (priv->content_gravity == gravity)
17591     return;
17592
17593   priv->content_gravity = gravity;
17594
17595   clutter_actor_queue_redraw (self);
17596
17597   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17598   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17599 }
17600
17601 /**
17602  * clutter_actor_get_content_gravity:
17603  * @self: a #ClutterActor
17604  *
17605  * Retrieves the content gravity as set using
17606  * clutter_actor_get_content_gravity().
17607  *
17608  * Return value: the content gravity
17609  *
17610  * Since: 1.10
17611  */
17612 ClutterContentGravity
17613 clutter_actor_get_content_gravity (ClutterActor *self)
17614 {
17615   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17616                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17617
17618   return self->priv->content_gravity;
17619 }
17620
17621 /**
17622  * clutter_actor_get_content_box:
17623  * @self: a #ClutterActor
17624  * @box: (out caller-allocates): the return location for the bounding
17625  *   box for the #ClutterContent
17626  *
17627  * Retrieves the bounding box for the #ClutterContent of @self.
17628  *
17629  * The bounding box is relative to the actor's allocation.
17630  *
17631  * If no #ClutterContent is set for @self, or if @self has not been
17632  * allocated yet, then the result is undefined.
17633  *
17634  * The content box is guaranteed to be, at most, as big as the allocation
17635  * of the #ClutterActor.
17636  *
17637  * If the #ClutterContent used by the actor has a preferred size, then
17638  * it is possible to modify the content box by using the
17639  * #ClutterActor:content-gravity property.
17640  *
17641  * Since: 1.10
17642  */
17643 void
17644 clutter_actor_get_content_box (ClutterActor    *self,
17645                                ClutterActorBox *box)
17646 {
17647   ClutterActorPrivate *priv;
17648   gfloat content_w, content_h;
17649   gfloat alloc_w, alloc_h;
17650
17651   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17652   g_return_if_fail (box != NULL);
17653
17654   priv = self->priv;
17655
17656   if (!clutter_actor_has_allocation (self))
17657     return;
17658
17659   box->x1 = 0.f;
17660   box->y1 = 0.f;
17661   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17662   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17663
17664   if (priv->content == NULL)
17665     return;
17666
17667   /* no need to do any more work */
17668   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17669     return;
17670
17671   /* if the content does not have a preferred size then there is
17672    * no point in computing the content box
17673    */
17674   if (!clutter_content_get_preferred_size (priv->content,
17675                                            &content_w,
17676                                            &content_h))
17677     return;
17678
17679   alloc_w = box->x2;
17680   alloc_h = box->y2;
17681
17682   switch (priv->content_gravity)
17683     {
17684     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17685       box->x2 = box->x1 + MIN (content_w, alloc_w);
17686       box->y2 = box->y1 + MIN (content_h, alloc_h);
17687       break;
17688
17689     case CLUTTER_CONTENT_GRAVITY_TOP:
17690       if (alloc_w > content_w)
17691         {
17692           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17693           box->x2 = box->x1 + content_w;
17694         }
17695       box->y2 = box->y1 + MIN (content_h, alloc_h);
17696       break;
17697
17698     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17699       if (alloc_w > content_w)
17700         {
17701           box->x1 += (alloc_w - content_w);
17702           box->x2 = box->x1 + content_w;
17703         }
17704       box->y2 = box->y1 + MIN (content_h, alloc_h);
17705       break;
17706
17707     case CLUTTER_CONTENT_GRAVITY_LEFT:
17708       box->x2 = box->x1 + MIN (content_w, alloc_w);
17709       if (alloc_h > content_h)
17710         {
17711           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17712           box->y2 = box->y1 + content_h;
17713         }
17714       break;
17715
17716     case CLUTTER_CONTENT_GRAVITY_CENTER:
17717       if (alloc_w > content_w)
17718         {
17719           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17720           box->x2 = box->x1 + content_w;
17721         }
17722       if (alloc_h > content_h)
17723         {
17724           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17725           box->y2 = box->y1 + content_h;
17726         }
17727       break;
17728
17729     case CLUTTER_CONTENT_GRAVITY_RIGHT:
17730       if (alloc_w > content_w)
17731         {
17732           box->x1 += (alloc_w - content_w);
17733           box->x2 = box->x1 + content_w;
17734         }
17735       if (alloc_h > content_h)
17736         {
17737           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17738           box->y2 = box->y1 + content_h;
17739         }
17740       break;
17741
17742     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17743       box->x2 = box->x1 + MIN (content_w, alloc_w);
17744       if (alloc_h > content_h)
17745         {
17746           box->y1 += (alloc_h - content_h);
17747           box->y2 = box->y1 + content_h;
17748         }
17749       break;
17750
17751     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17752       if (alloc_w > content_w)
17753         {
17754           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17755           box->x2 = box->x1 + content_w;
17756         }
17757       if (alloc_h > content_h)
17758         {
17759           box->y1 += (alloc_h - content_h);
17760           box->y2 = box->y1 + content_h;
17761         }
17762       break;
17763
17764     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17765       if (alloc_w > content_w)
17766         {
17767           box->x1 += (alloc_w - content_w);
17768           box->x2 = box->x1 + content_w;
17769         }
17770       if (alloc_h > content_h)
17771         {
17772           box->y1 += (alloc_h - content_h);
17773           box->y2 = box->y1 + content_h;
17774         }
17775       break;
17776
17777     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17778       g_assert_not_reached ();
17779       break;
17780
17781     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17782       {
17783         double r_c = content_w / content_h;
17784         double r_a = alloc_w / alloc_h;
17785
17786         if (r_c >= 1.0)
17787           {
17788             if (r_a >= 1.0)
17789               {
17790                 box->x1 = 0.f;
17791                 box->x2 = alloc_w;
17792
17793                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17794                 box->y2 = box->y1 + (alloc_w * r_c);
17795               }
17796             else
17797               {
17798                 box->y1 = 0.f;
17799                 box->y2 = alloc_h;
17800
17801                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17802                 box->x2 = box->x1 + (alloc_h * r_c);
17803               }
17804           }
17805         else
17806           {
17807             if (r_a >= 1.0)
17808               {
17809                 box->y1 = 0.f;
17810                 box->y2 = alloc_h;
17811
17812                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17813                 box->x2 = box->x1 + (alloc_h * r_c);
17814               }
17815             else
17816               {
17817                 box->x1 = 0.f;
17818                 box->x2 = alloc_w;
17819
17820                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17821                 box->y2 = box->y1 + (alloc_w * r_c);
17822               }
17823           }
17824       }
17825       break;
17826     }
17827 }
17828
17829 /**
17830  * clutter_actor_set_content_scaling_filters:
17831  * @self: a #ClutterActor
17832  * @min_filter: the minification filter for the content
17833  * @mag_filter: the magnification filter for the content
17834  *
17835  * Sets the minification and magnification filter to be applied when
17836  * scaling the #ClutterActor:content of a #ClutterActor.
17837  *
17838  * The #ClutterActor:minification-filter will be used when reducing
17839  * the size of the content; the #ClutterActor:magnification-filter
17840  * will be used when increasing the size of the content.
17841  *
17842  * Since: 1.10
17843  */
17844 void
17845 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
17846                                            ClutterScalingFilter  min_filter,
17847                                            ClutterScalingFilter  mag_filter)
17848 {
17849   ClutterActorPrivate *priv;
17850   gboolean changed;
17851   GObject *obj;
17852
17853   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17854
17855   priv = self->priv;
17856   obj = G_OBJECT (self);
17857
17858   g_object_freeze_notify (obj);
17859
17860   changed = FALSE;
17861
17862   if (priv->min_filter != min_filter)
17863     {
17864       priv->min_filter = min_filter;
17865       changed = TRUE;
17866
17867       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
17868     }
17869
17870   if (priv->mag_filter != mag_filter)
17871     {
17872       priv->mag_filter = mag_filter;
17873       changed = TRUE;
17874
17875       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
17876     }
17877
17878   if (changed)
17879     clutter_actor_queue_redraw (self);
17880
17881   g_object_thaw_notify (obj);
17882 }
17883
17884 /**
17885  * clutter_actor_get_content_scaling_filters:
17886  * @self: a #ClutterActor
17887  * @min_filter: (out) (allow-none): return location for the minification
17888  *   filter, or %NULL
17889  * @mag_filter: (out) (allow-none): return location for the magnification
17890  *   filter, or %NULL
17891  *
17892  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
17893  *
17894  * Since: 1.10
17895  */
17896 void
17897 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
17898                                            ClutterScalingFilter *min_filter,
17899                                            ClutterScalingFilter *mag_filter)
17900 {
17901   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17902
17903   if (min_filter != NULL)
17904     *min_filter = self->priv->min_filter;
17905
17906   if (mag_filter != NULL)
17907     *mag_filter = self->priv->mag_filter;
17908 }