docs: Change the short description of ClutterActor
[profile/ivi/clutter.git] / clutter / clutter-actor.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9  * Copyright (C) 2009, 2010, 2011, 2012 Intel Corp
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /**
26  * SECTION:clutter-actor
27  * @short_description: The basic element of the scene graph 
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="actor-example-image">
113  *     <title>Actors</title>
114  *     <graphic fileref="actor-example.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-painting">
119  *   <title>Painting an actor</title>
120  *   <para>There are three ways to paint an actor:</para>
121  *   <itemizedlist>
122  *     <listitem><para>set a delegate #ClutterContent as the value for the
123  *     #ClutterActor:content property of the actor;</para></listitem>
124  *     <listitem><para>subclass #ClutterActor and override the
125  *     #ClutterActorClass.paint_node() virtual function;</para></listitem>
126  *     <listitem><para>subclass #ClutterActor and override the
127  *     #ClutterActorClass.paint() virtual function.</para></listitem>
128  *   </itemizedlist>
129  *   <formalpara>
130  *     <title>Setting the Content property</title>
131  *     <para>A #ClutterContent is a delegate object that takes over the
132  *     painting operation of one, or more actors. The #ClutterContent
133  *     painting will be performed on top of the #ClutterActor:background-color
134  *     of the actor, and before calling the #ClutterActorClass.paint_node()
135  *     virtual function.</para>
136  *     <informalexample><programlisting>
137  * ClutterActor *actor = clutter_actor_new ();
138  *
139  * /&ast; set the bounding box &ast;/
140  * clutter_actor_set_position (actor, 50, 50);
141  * clutter_actor_set_size (actor, 100, 100);
142  *
143  * /&ast; set the content; the image_content variable is set elsewhere &ast;/
144  * clutter_actor_set_content (actor, image_content);
145  *     </programlisting></informalexample>
146  *   </formalpara>
147  *   <formalpara>
148  *     <title>Overriding the paint_node virtual function</title>
149  *     <para>The #ClutterActorClass.paint_node() virtual function is invoked
150  *     whenever an actor needs to be painted. The implementation of the
151  *     virtual function must only paint the contents of the actor itself,
152  *     and not the contents of its children, if the actor has any.</para>
153  *     <para>The #ClutterPaintNode passed to the virtual function is the
154  *     local root of the render tree; any node added to it will be
155  *     rendered at the correct position, as defined by the actor's
156  *     #ClutterActor:allocation.</para>
157  *     <informalexample><programlisting>
158  * static void
159  * my_actor_paint_node (ClutterActor     *actor,
160  *                      ClutterPaintNode *root)
161  * {
162  *   ClutterPaintNode *node;
163  *   ClutterActorBox box;
164  *
165  *   /&ast; where the content of the actor should be painted &ast;/
166  *   clutter_actor_get_allocation_box (actor, &box);
167  *
168  *   /&ast; the cogl_texture variable is set elsewhere &ast;/
169  *   node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White,
170  *                                    CLUTTER_SCALING_FILTER_TRILINEAR,
171  *                                    CLUTTER_SCALING_FILTER_LINEAR);
172  *
173  *   /&ast; paint the content of the node using the allocation &ast;/
174  *   clutter_paint_node_add_rectangle (node, &box);
175  *
176  *   /&ast; add the node, and transfer ownership &ast;/
177  *   clutter_paint_node_add_child (root, node);
178  *   clutter_paint_node_unref (node);
179  * }
180  *     </programlisting></informalexample>
181  *   </formalpara>
182  *   <formalpara>
183  *     <title>Overriding the paint virtual function</title>
184  *     <para>The #ClutterActorClass.paint() virtual function is invoked
185  *     when the #ClutterActor::paint signal is emitted, and after the other
186  *     signal handlers have been invoked. Overriding the paint virtual
187  *     function gives total control to the paint sequence of the actor
188  *     itself, including the children of the actor, if any.</para>
189  *     <warning><para>It is strongly discouraged to override the
190  *     #ClutterActorClass.paint() virtual function, as well as connecting
191  *     to the #ClutterActor::paint signal. These hooks into the paint
192  *     sequence are considered legacy, and will be removed when the Clutter
193  *     API changes.</para></warning>
194  *   </formalpara>
195  * </refsect2>
196  *
197  * <refsect2 id="ClutterActor-events">
198  *   <title>Handling events on an actor</title>
199  *   <para>A #ClutterActor can receive and handle input device events, for
200  *   instance pointer events and key events, as long as its
201  *   #ClutterActor:reactive property is set to %TRUE.</para>
202  *   <para>Once an actor has been determined to be the source of an event,
203  *   Clutter will traverse the scene graph from the top-level actor towards the
204  *   event source, emitting the #ClutterActor::captured-event signal on each
205  *   ancestor until it reaches the source; this phase is also called
206  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
207  *   stopped, the graph is walked backwards, from the source actor to the
208  *   top-level, and the #ClutterActor::event signal, along with other event
209  *   signals if needed, is emitted; this phase is also called <emphasis>the
210  *   bubble phase</emphasis>. At any point of the signal emission, signal
211  *   handlers can stop the propagation through the scene graph by returning
212  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
213  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
214  * </refsect2>
215  *
216  * <refsect2 id="ClutterActor-subclassing">
217  *   <title>Implementing an actor</title>
218  *   <para>Careful consideration should be given when deciding to implement
219  *   a #ClutterActor sub-class. It is generally recommended to implement a
220  *   sub-class of #ClutterActor only for actors that should be used as leaf
221  *   nodes of a scene graph.</para>
222  *   <para>If your actor should be painted in a custom way, you should
223  *   override the #ClutterActor::paint signal class handler. You can either
224  *   opt to chain up to the parent class implementation or decide to fully
225  *   override the default paint implementation; Clutter will set up the
226  *   transformations and clip regions prior to emitting the #ClutterActor::paint
227  *   signal.</para>
228  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
229  *   #ClutterActorClass.get_preferred_height() virtual functions it is
230  *   possible to change or provide the preferred size of an actor; similarly,
231  *   by overriding the #ClutterActorClass.allocate() virtual function it is
232  *   possible to control the layout of the children of an actor. Make sure to
233  *   always chain up to the parent implementation of the
234  *   #ClutterActorClass.allocate() virtual function.</para>
235  *   <para>In general, it is strongly encouraged to use delegation and
236  *   composition instead of direct subclassing.</para>
237  * </refsect2>
238  *
239  * <refsect2 id="ClutterActor-script">
240  *   <title>ClutterActor custom properties for #ClutterScript</title>
241  *   <para>#ClutterActor defines a custom "rotation" property which
242  *   allows a short-hand description of the rotations to be applied
243  *   to an actor.</para>
244  *   <para>The syntax of the "rotation" property is the following:</para>
245  *   <informalexample>
246  *     <programlisting>
247  * "rotation" : [
248  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
249  * ]
250  *     </programlisting>
251  *   </informalexample>
252  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
253  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
254  *   floating point value representing the rotation angle on the given axis,
255  *   in degrees.</para>
256  *   <para>The <emphasis>center</emphasis> array is optional, and if present
257  *   it must contain the center of rotation as described by two coordinates:
258  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
259  *   "z-axis".</para>
260  *   <para>#ClutterActor will also parse every positional and dimensional
261  *   property defined as a string through clutter_units_from_string(); you
262  *   should read the documentation for the #ClutterUnits parser format for
263  *   the valid units and syntax.</para>
264  * </refsect2>
265  *
266  * <refsect2 id="ClutterActor-animating">
267  *   <title>Custom animatable properties</title>
268  *   <para>#ClutterActor allows accessing properties of #ClutterAction
269  *   and #ClutterConstraint instances associated to an actor instance
270  *   for animation purposes.</para>
271  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
272  *   property it is necessary to set the #ClutterActorMeta:name property on the
273  *   given action or constraint.</para>
274  *   <para>The property can be accessed using the following syntax:</para>
275  *   <informalexample>
276  *     <programlisting>
277  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
278  *     </programlisting>
279  *   </informalexample>
280  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
281  *   <para>The <emphasis>section</emphasis> fragment can be one between
282  *   "actions", "constraints" and "effects".</para>
283  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
284  *   action or constraint, as specified by the #ClutterActorMeta:name
285  *   property.</para>
286  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
287  *   action or constraint property to be animated.</para>
288  *   <para>The example below animates a #ClutterBindConstraint applied to an
289  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
290  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
291  *   its initial state is fully transparent and overlapping the actor to
292  *   which is bound to. </para>
293  *   <informalexample><programlisting>
294  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
295  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
296  * clutter_actor_add_constraint (rect, constraint);
297  *
298  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
299  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
300  * clutter_actor_add_constraint (rect, constraint);
301  *
302  * clutter_actor_set_reactive (rect, TRUE);
303  * clutter_actor_set_opacity (rect, 0);
304  *
305  * g_signal_connect (rect, "button-press-event",
306  *                   G_CALLBACK (on_button_press),
307  *                   NULL);
308  *   </programlisting></informalexample>
309  *   <para>On button press, the rectangle "slides" from behind the actor to
310  *   which is bound to, using the #ClutterBindConstraint:offset property and
311  *   the #ClutterActor:opacity property.</para>
312  *   <informalexample><programlisting>
313  * float new_offset = clutter_actor_get_width (origin) + h_padding;
314  *
315  * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
316  *                        "opacity", 255,
317  *                        "@constraints.bind-x.offset", new_offset,
318  *                        NULL);
319  *   </programlisting></informalexample>
320  * </refsect2>
321  *
322  * <refsect2 id="ClutterActor-animatable-properties">
323  *   <title>Animatable properties</title>
324  *   <para>Certain properties on #ClutterActor are marked as "animatable";
325  *   these properties will be automatically tweened between the current
326  *   value and the new value when one is set.</para>
327  *   <para>For backward compatibility, animatable properties will only be
328  *   tweened if the easing duration is greater than 0, or if a new easing
329  *   state is set, for instance the following example:</para>
330  *   <informalexample><programlisting>
331  * clutter_actor_save_easing_state (actor);
332  * clutter_actor_set_position (actor, 200, 200);
333  * clutter_actor_restore_easing_state (actor);
334  *   </programlisting></informalexample>
335  *   <para>will tween the actor to the (200, 200) coordinates using the default
336  *   easing mode and duration of a new easing state. The example above is
337  *   equivalent to the following code:</para>
338  *   <informalexample><programlisting>
339  * clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC);
340  * clutter_actor_set_easing_duration (actor, 250);
341  * clutter_actor_set_position (actor, 200, 200);
342  * clutter_actor_restore_easing_state (actor);
343  *   </programlisting></informalexample>
344  *   <para>It is possible to nest easing states to tween animatable
345  *   properties using different modes and durations, for instance:</para>
346  *   <informalexample><programlisting>
347  * clutter_actor_save_easing_state (actor); /&ast; outer state &ast;/
348  *
349  * /&ast; set the duration of the animation to 2 seconds and change position &ast;/
350  * clutter_actor_set_easing_duration (actor, 2000);
351  * clutter_actor_set_position (actor, 0, 0);
352  *
353  * clutter_actor_save_easing_state (actor); /&ast; inner state &ast;/
354  *
355  * /&ast; set the duration of the animation to 5 seconds and change depth and opacity &ast;/
356  * clutter_actor_set_easing_duration (actor, 5000);
357  * clutter_actor_set_depth (actor, 200);
358  * clutter_actor_set_opacity (actor, 0);
359  *
360  * clutter_actor_restore_easing_state (actor);
361  *
362  * clutter_actor_restore_easing_state (actor);
363  *   </programlisting></informalexample>
364  * </refsect2>
365  */
366
367 /**
368  * CLUTTER_ACTOR_IS_MAPPED:
369  * @a: a #ClutterActor
370  *
371  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
372  *
373  * The mapped state is set when the actor is visible and all its parents up
374  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
375  *
376  * This check can be used to see if an actor is going to be painted, as only
377  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
378  *
379  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
380  * not be checked directly; instead, the recommended usage is to connect a
381  * handler on the #GObject::notify signal for the #ClutterActor:mapped
382  * property of #ClutterActor, and check the presence of
383  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
384  *
385  * It is also important to note that Clutter may delay the changes of
386  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
387  * limitations, or during the reparenting of an actor, to optimize
388  * unnecessary (and potentially expensive) state changes.
389  *
390  * Since: 0.2
391  */
392
393 /**
394  * CLUTTER_ACTOR_IS_REALIZED:
395  * @a: a #ClutterActor
396  *
397  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
398  *
399  * The realized state has an actor-dependant interpretation. If an
400  * actor wants to delay allocating resources until it is attached to a
401  * stage, it may use the realize state to do so. However it is
402  * perfectly acceptable for an actor to allocate Cogl resources before
403  * being realized because there is only one drawing context used by Clutter
404  * so any resources will work on any stage.  If an actor is mapped it
405  * must also be realized, but an actor can be realized and unmapped
406  * (this is so hiding an actor temporarily doesn't do an expensive
407  * unrealize/realize).
408  *
409  * To be realized an actor must be inside a stage, and all its parents
410  * must be realized.
411  *
412  * Since: 0.2
413  */
414
415 /**
416  * CLUTTER_ACTOR_IS_VISIBLE:
417  * @a: a #ClutterActor
418  *
419  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
420  * Equivalent to the ClutterActor::visible object property.
421  *
422  * Note that an actor is only painted onscreen if it's mapped, which
423  * means it's visible, and all its parents are visible, and one of the
424  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
425  *
426  * Since: 0.2
427  */
428
429 /**
430  * CLUTTER_ACTOR_IS_REACTIVE:
431  * @a: a #ClutterActor
432  *
433  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
434  *
435  * Only reactive actors will receive event-related signals.
436  *
437  * Since: 0.6
438  */
439
440 #ifdef HAVE_CONFIG_H
441 #include "config.h"
442 #endif
443
444 #include <math.h>
445
446 #include <gobject/gvaluecollector.h>
447
448 #include <cogl/cogl.h>
449
450 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
451 #define CLUTTER_ENABLE_EXPERIMENTAL_API
452
453 #include "clutter-actor-private.h"
454
455 #include "clutter-action.h"
456 #include "clutter-actor-meta-private.h"
457 #include "clutter-animatable.h"
458 #include "clutter-color-static.h"
459 #include "clutter-color.h"
460 #include "clutter-constraint.h"
461 #include "clutter-container.h"
462 #include "clutter-content-private.h"
463 #include "clutter-debug.h"
464 #include "clutter-effect-private.h"
465 #include "clutter-enum-types.h"
466 #include "clutter-fixed-layout.h"
467 #include "clutter-flatten-effect.h"
468 #include "clutter-interval.h"
469 #include "clutter-main.h"
470 #include "clutter-marshal.h"
471 #include "clutter-paint-nodes.h"
472 #include "clutter-paint-node-private.h"
473 #include "clutter-paint-volume-private.h"
474 #include "clutter-private.h"
475 #include "clutter-profile.h"
476 #include "clutter-property-transition.h"
477 #include "clutter-scriptable.h"
478 #include "clutter-script-private.h"
479 #include "clutter-stage-private.h"
480 #include "clutter-timeline.h"
481 #include "clutter-transition.h"
482 #include "clutter-units.h"
483
484 #include "deprecated/clutter-actor.h"
485 #include "deprecated/clutter-behaviour.h"
486 #include "deprecated/clutter-container.h"
487
488 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
489 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
490
491 /* Internal enum used to control mapped state update.  This is a hint
492  * which indicates when to do something other than just enforce
493  * invariants.
494  */
495 typedef enum {
496   MAP_STATE_CHECK,           /* just enforce invariants. */
497   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
498                               * used when about to unparent.
499                               */
500   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
501                               * used to set mapped on toplevels.
502                               */
503   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
504                               * used just before unmapping parent.
505                               */
506 } MapStateChange;
507
508 /* 3 entries should be a good compromise, few layout managers
509  * will ask for 3 different preferred size in each allocation cycle */
510 #define N_CACHED_SIZE_REQUESTS 3
511
512 struct _ClutterActorPrivate
513 {
514   /* request mode */
515   ClutterRequestMode request_mode;
516
517   /* our cached size requests for different width / height */
518   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
519   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
520
521   /* An age of 0 means the entry is not set */
522   guint cached_height_age;
523   guint cached_width_age;
524
525   /* the bounding box of the actor, relative to the parent's
526    * allocation
527    */
528   ClutterActorBox allocation;
529   ClutterAllocationFlags allocation_flags;
530
531   /* clip, in actor coordinates */
532   cairo_rectangle_t clip;
533
534   /* the cached transformation matrix; see apply_transform() */
535   CoglMatrix transform;
536
537   guint8 opacity;
538   gint opacity_override;
539
540   ClutterOffscreenRedirect offscreen_redirect;
541
542   /* This is an internal effect used to implement the
543      offscreen-redirect property */
544   ClutterEffect *flatten_effect;
545
546   /* scene graph */
547   ClutterActor *parent;
548   ClutterActor *prev_sibling;
549   ClutterActor *next_sibling;
550   ClutterActor *first_child;
551   ClutterActor *last_child;
552
553   gint n_children;
554
555   /* tracks whenever the children of an actor are changed; the
556    * age is incremented by 1 whenever an actor is added or
557    * removed. the age is not incremented when the first or the
558    * last child pointers are changed, or when grandchildren of
559    * an actor are changed.
560    */
561   gint age;
562
563   gchar *name; /* a non-unique name, used for debugging */
564   guint32 id; /* unique id, used for backward compatibility */
565
566   gint32 pick_id; /* per-stage unique id, used for picking */
567
568   /* a back-pointer to the Pango context that we can use
569    * to create pre-configured PangoLayout
570    */
571   PangoContext *pango_context;
572
573   /* the text direction configured for this child - either by
574    * application code, or by the actor's parent
575    */
576   ClutterTextDirection text_direction;
577
578   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
579   gint internal_child;
580
581   /* meta classes */
582   ClutterMetaGroup *actions;
583   ClutterMetaGroup *constraints;
584   ClutterMetaGroup *effects;
585
586   /* delegate object used to allocate the children of this actor */
587   ClutterLayoutManager *layout_manager;
588
589   /* delegate object used to paint the contents of this actor */
590   ClutterContent *content;
591
592   ClutterContentGravity content_gravity;
593   ClutterScalingFilter min_filter;
594   ClutterScalingFilter mag_filter;
595
596   /* used when painting, to update the paint volume */
597   ClutterEffect *current_effect;
598
599   /* This is used to store an effect which needs to be redrawn. A
600      redraw can be queued to start from a particular effect. This is
601      used by parametrised effects that can cache an image of the
602      actor. If a parameter of the effect changes then it only needs to
603      redraw the cached image, not the actual actor. The pointer is
604      only valid if is_dirty == TRUE. If the pointer is NULL then the
605      whole actor is dirty. */
606   ClutterEffect *effect_to_redraw;
607
608   /* This is used when painting effects to implement the
609      clutter_actor_continue_paint() function. It points to the node in
610      the list of effects that is next in the chain */
611   const GList *next_effect_to_paint;
612
613   ClutterPaintVolume paint_volume;
614
615   /* NB: This volume isn't relative to this actor, it is in eye
616    * coordinates so that it can remain valid after the actor changes.
617    */
618   ClutterPaintVolume last_paint_volume;
619
620   ClutterStageQueueRedrawEntry *queue_redraw_entry;
621
622   ClutterColor bg_color;
623
624   /* bitfields */
625
626   /* fixed position and sizes */
627   guint position_set                : 1;
628   guint min_width_set               : 1;
629   guint min_height_set              : 1;
630   guint natural_width_set           : 1;
631   guint natural_height_set          : 1;
632   /* cached request is invalid (implies allocation is too) */
633   guint needs_width_request         : 1;
634   /* cached request is invalid (implies allocation is too) */
635   guint needs_height_request        : 1;
636   /* cached allocation is invalid (request has changed, probably) */
637   guint needs_allocation            : 1;
638   guint show_on_set_parent          : 1;
639   guint has_clip                    : 1;
640   guint clip_to_allocation          : 1;
641   guint enable_model_view_transform : 1;
642   guint enable_paint_unmapped       : 1;
643   guint has_pointer                 : 1;
644   guint propagated_one_redraw       : 1;
645   guint paint_volume_valid          : 1;
646   guint last_paint_volume_valid     : 1;
647   guint in_clone_paint              : 1;
648   guint transform_valid             : 1;
649   /* This is TRUE if anything has queued a redraw since we were last
650      painted. In this case effect_to_redraw will point to an effect
651      the redraw was queued from or it will be NULL if the redraw was
652      queued without an effect. */
653   guint is_dirty                    : 1;
654   guint bg_color_set                : 1;
655 };
656
657 enum
658 {
659   PROP_0,
660
661   PROP_NAME,
662
663   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
664    * when set they force a size request, when gotten they
665    * get the allocation if the allocation is valid, and the
666    * request otherwise
667    */
668   PROP_X,
669   PROP_Y,
670   PROP_WIDTH,
671   PROP_HEIGHT,
672
673   /* Then the rest of these size-related properties are the "actual"
674    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
675    */
676   PROP_FIXED_X,
677   PROP_FIXED_Y,
678
679   PROP_FIXED_POSITION_SET,
680
681   PROP_MIN_WIDTH,
682   PROP_MIN_WIDTH_SET,
683
684   PROP_MIN_HEIGHT,
685   PROP_MIN_HEIGHT_SET,
686
687   PROP_NATURAL_WIDTH,
688   PROP_NATURAL_WIDTH_SET,
689
690   PROP_NATURAL_HEIGHT,
691   PROP_NATURAL_HEIGHT_SET,
692
693   PROP_REQUEST_MODE,
694
695   /* Allocation properties are read-only */
696   PROP_ALLOCATION,
697
698   PROP_DEPTH,
699
700   PROP_CLIP,
701   PROP_HAS_CLIP,
702   PROP_CLIP_TO_ALLOCATION,
703
704   PROP_OPACITY,
705
706   PROP_OFFSCREEN_REDIRECT,
707
708   PROP_VISIBLE,
709   PROP_MAPPED,
710   PROP_REALIZED,
711   PROP_REACTIVE,
712
713   PROP_SCALE_X,
714   PROP_SCALE_Y,
715   PROP_SCALE_CENTER_X,
716   PROP_SCALE_CENTER_Y,
717   PROP_SCALE_GRAVITY,
718
719   PROP_ROTATION_ANGLE_X,
720   PROP_ROTATION_ANGLE_Y,
721   PROP_ROTATION_ANGLE_Z,
722   PROP_ROTATION_CENTER_X,
723   PROP_ROTATION_CENTER_Y,
724   PROP_ROTATION_CENTER_Z,
725   /* This property only makes sense for the z rotation because the
726      others would depend on the actor having a size along the
727      z-axis */
728   PROP_ROTATION_CENTER_Z_GRAVITY,
729
730   PROP_ANCHOR_X,
731   PROP_ANCHOR_Y,
732   PROP_ANCHOR_GRAVITY,
733
734   PROP_SHOW_ON_SET_PARENT,
735
736   PROP_TEXT_DIRECTION,
737   PROP_HAS_POINTER,
738
739   PROP_ACTIONS,
740   PROP_CONSTRAINTS,
741   PROP_EFFECT,
742
743   PROP_LAYOUT_MANAGER,
744
745   PROP_X_ALIGN,
746   PROP_Y_ALIGN,
747   PROP_MARGIN_TOP,
748   PROP_MARGIN_BOTTOM,
749   PROP_MARGIN_LEFT,
750   PROP_MARGIN_RIGHT,
751
752   PROP_BACKGROUND_COLOR,
753   PROP_BACKGROUND_COLOR_SET,
754
755   PROP_FIRST_CHILD,
756   PROP_LAST_CHILD,
757
758   PROP_CONTENT,
759   PROP_CONTENT_GRAVITY,
760   PROP_CONTENT_BOX,
761   PROP_MINIFICATION_FILTER,
762   PROP_MAGNIFICATION_FILTER,
763
764   PROP_LAST
765 };
766
767 static GParamSpec *obj_props[PROP_LAST];
768
769 enum
770 {
771   SHOW,
772   HIDE,
773   DESTROY,
774   PARENT_SET,
775   KEY_FOCUS_IN,
776   KEY_FOCUS_OUT,
777   PAINT,
778   PICK,
779   REALIZE,
780   UNREALIZE,
781   QUEUE_REDRAW,
782   QUEUE_RELAYOUT,
783   EVENT,
784   CAPTURED_EVENT,
785   BUTTON_PRESS_EVENT,
786   BUTTON_RELEASE_EVENT,
787   SCROLL_EVENT,
788   KEY_PRESS_EVENT,
789   KEY_RELEASE_EVENT,
790   MOTION_EVENT,
791   ENTER_EVENT,
792   LEAVE_EVENT,
793   ALLOCATION_CHANGED,
794
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 x, y;
2060       gfloat width, height;
2061
2062       x = priv->allocation.x1;
2063       y = priv->allocation.y1;
2064       width = priv->allocation.x2 - priv->allocation.x1;
2065       height = priv->allocation.y2 - priv->allocation.y1;
2066
2067       if (x != old->x1)
2068         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2069
2070       if (y != old->y1)
2071         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2072
2073       if (width != (old->x2 - old->x1))
2074         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2075
2076       if (height != (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 ||
2133       x2_changed || y2_changed ||
2134       flags_changed)
2135     {
2136       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2137                     _clutter_actor_get_debug_name (self));
2138
2139       priv->transform_valid = FALSE;
2140
2141       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2142
2143       /* if the allocation changes, so does the content box */
2144       if (priv->content != NULL)
2145         g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2146
2147       retval = TRUE;
2148     }
2149   else
2150     retval = FALSE;
2151
2152   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2153
2154   g_object_thaw_notify (obj);
2155
2156   return retval;
2157 }
2158
2159 static void clutter_actor_real_allocate (ClutterActor           *self,
2160                                          const ClutterActorBox  *box,
2161                                          ClutterAllocationFlags  flags);
2162
2163 static inline void
2164 clutter_actor_maybe_layout_children (ClutterActor           *self,
2165                                      const ClutterActorBox  *allocation,
2166                                      ClutterAllocationFlags  flags)
2167 {
2168   ClutterActorPrivate *priv = self->priv;
2169
2170   /* this is going to be a bit hard to follow, so let's put an explanation
2171    * here.
2172    *
2173    * we want ClutterActor to have a default layout manager if the actor was
2174    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2175    *
2176    * we also want any subclass of ClutterActor that does not override the
2177    * ::allocate() virtual function to delegate to a layout manager.
2178    *
2179    * finally, we want to allow people subclassing ClutterActor and overriding
2180    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2181    *
2182    * on the other hand, we want existing actor subclasses overriding the
2183    * ::allocate() virtual function and chaining up to the parent's
2184    * implementation to continue working without allocating their children
2185    * twice, or without entering an allocation loop.
2186    *
2187    * for the first two points, we check if the class of the actor is
2188    * overridding the ::allocate() virtual function; if it isn't, then we
2189    * follow through with checking whether we have children and a layout
2190    * manager, and eventually calling clutter_layout_manager_allocate().
2191    *
2192    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2193    * allocation flags that we got passed, and if it is present, we continue
2194    * with the check above.
2195    *
2196    * if neither of these two checks yields a positive result, we just
2197    * assume that the ::allocate() virtual function that resulted in this
2198    * function being called will also allocate the children of the actor.
2199    */
2200
2201   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2202     goto check_layout;
2203
2204   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2205     goto check_layout;
2206
2207   return;
2208
2209 check_layout:
2210   if (priv->n_children != 0 &&
2211       priv->layout_manager != NULL)
2212     {
2213       ClutterContainer *container = CLUTTER_CONTAINER (self);
2214       ClutterAllocationFlags children_flags;
2215       ClutterActorBox children_box;
2216
2217       /* normalize the box passed to the layout manager */
2218       children_box.x1 = children_box.y1 = 0.f;
2219       children_box.x2 = (allocation->x2 - allocation->x1);
2220       children_box.y2 = (allocation->y2 - allocation->y1);
2221
2222       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2223        * the actor's children, since it refers only to the current
2224        * actor's allocation.
2225        */
2226       children_flags = flags;
2227       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2228
2229       CLUTTER_NOTE (LAYOUT,
2230                     "Allocating %d children of %s "
2231                     "at { %.2f, %.2f - %.2f x %.2f } "
2232                     "using %s",
2233                     priv->n_children,
2234                     _clutter_actor_get_debug_name (self),
2235                     allocation->x1,
2236                     allocation->y1,
2237                     (allocation->x2 - allocation->x1),
2238                     (allocation->y2 - allocation->y1),
2239                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2240
2241       clutter_layout_manager_allocate (priv->layout_manager,
2242                                        container,
2243                                        &children_box,
2244                                        children_flags);
2245     }
2246 }
2247
2248 static void
2249 clutter_actor_real_allocate (ClutterActor           *self,
2250                              const ClutterActorBox  *box,
2251                              ClutterAllocationFlags  flags)
2252 {
2253   ClutterActorPrivate *priv = self->priv;
2254   gboolean changed;
2255
2256   g_object_freeze_notify (G_OBJECT (self));
2257
2258   changed = clutter_actor_set_allocation_internal (self, box, flags);
2259
2260   /* we allocate our children before we notify changes in our geometry,
2261    * so that people connecting to properties will be able to get valid
2262    * data out of the sub-tree of the scene graph that has this actor at
2263    * the root.
2264    */
2265   clutter_actor_maybe_layout_children (self, box, flags);
2266
2267   if (changed)
2268     {
2269       ClutterActorBox signal_box = priv->allocation;
2270       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2271
2272       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2273                      &signal_box,
2274                      signal_flags);
2275     }
2276
2277   g_object_thaw_notify (G_OBJECT (self));
2278 }
2279
2280 static void
2281 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2282                                     ClutterActor *origin)
2283 {
2284   /* no point in queuing a redraw on a destroyed actor */
2285   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2286     return;
2287
2288   /* NB: We can't bail out early here if the actor is hidden in case
2289    * the actor bas been cloned. In this case the clone will need to
2290    * receive the signal so it can queue its own redraw.
2291    */
2292
2293   /* calls klass->queue_redraw in default handler */
2294   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2295 }
2296
2297 static void
2298 clutter_actor_real_queue_redraw (ClutterActor *self,
2299                                  ClutterActor *origin)
2300 {
2301   ClutterActor *parent;
2302
2303   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2304                 _clutter_actor_get_debug_name (self),
2305                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2306                                : "same actor");
2307
2308   /* no point in queuing a redraw on a destroyed actor */
2309   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2310     return;
2311
2312   /* If the queue redraw is coming from a child then the actor has
2313      become dirty and any queued effect is no longer valid */
2314   if (self != origin)
2315     {
2316       self->priv->is_dirty = TRUE;
2317       self->priv->effect_to_redraw = NULL;
2318     }
2319
2320   /* If the actor isn't visible, we still had to emit the signal
2321    * to allow for a ClutterClone, but the appearance of the parent
2322    * won't change so we don't have to propagate up the hierarchy.
2323    */
2324   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2325     return;
2326
2327   /* Although we could determine here that a full stage redraw
2328    * has already been queued and immediately bail out, we actually
2329    * guarantee that we will propagate a queue-redraw signal to our
2330    * parent at least once so that it's possible to implement a
2331    * container that tracks which of its children have queued a
2332    * redraw.
2333    */
2334   if (self->priv->propagated_one_redraw)
2335     {
2336       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2337       if (stage != NULL &&
2338           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2339         return;
2340     }
2341
2342   self->priv->propagated_one_redraw = TRUE;
2343
2344   /* notify parents, if they are all visible eventually we'll
2345    * queue redraw on the stage, which queues the redraw idle.
2346    */
2347   parent = clutter_actor_get_parent (self);
2348   if (parent != NULL)
2349     {
2350       /* this will go up recursively */
2351       _clutter_actor_signal_queue_redraw (parent, origin);
2352     }
2353 }
2354
2355 static void
2356 clutter_actor_real_queue_relayout (ClutterActor *self)
2357 {
2358   ClutterActorPrivate *priv = self->priv;
2359
2360   /* no point in queueing a redraw on a destroyed actor */
2361   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2362     return;
2363
2364   priv->needs_width_request  = TRUE;
2365   priv->needs_height_request = TRUE;
2366   priv->needs_allocation     = TRUE;
2367
2368   /* reset the cached size requests */
2369   memset (priv->width_requests, 0,
2370           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2371   memset (priv->height_requests, 0,
2372           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2373
2374   /* We need to go all the way up the hierarchy */
2375   if (priv->parent != NULL)
2376     _clutter_actor_queue_only_relayout (priv->parent);
2377 }
2378
2379 /**
2380  * clutter_actor_apply_relative_transform_to_point:
2381  * @self: A #ClutterActor
2382  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2383  *   default #ClutterStage
2384  * @point: A point as #ClutterVertex
2385  * @vertex: (out caller-allocates): The translated #ClutterVertex
2386  *
2387  * Transforms @point in coordinates relative to the actor into
2388  * ancestor-relative coordinates using the relevant transform
2389  * stack (i.e. scale, rotation, etc).
2390  *
2391  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2392  * this case, the coordinates returned will be the coordinates on
2393  * the stage before the projection is applied. This is different from
2394  * the behaviour of clutter_actor_apply_transform_to_point().
2395  *
2396  * Since: 0.6
2397  */
2398 void
2399 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2400                                                  ClutterActor        *ancestor,
2401                                                  const ClutterVertex *point,
2402                                                  ClutterVertex       *vertex)
2403 {
2404   gfloat w;
2405   CoglMatrix matrix;
2406
2407   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2408   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2409   g_return_if_fail (point != NULL);
2410   g_return_if_fail (vertex != NULL);
2411
2412   *vertex = *point;
2413   w = 1.0;
2414
2415   if (ancestor == NULL)
2416     ancestor = _clutter_actor_get_stage_internal (self);
2417
2418   if (ancestor == NULL)
2419     {
2420       *vertex = *point;
2421       return;
2422     }
2423
2424   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2425   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2426 }
2427
2428 static gboolean
2429 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2430                                          const ClutterVertex *vertices_in,
2431                                          ClutterVertex *vertices_out,
2432                                          int n_vertices)
2433 {
2434   ClutterActor *stage;
2435   CoglMatrix modelview;
2436   CoglMatrix projection;
2437   float viewport[4];
2438
2439   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2440
2441   stage = _clutter_actor_get_stage_internal (self);
2442
2443   /* We really can't do anything meaningful in this case so don't try
2444    * to do any transform */
2445   if (stage == NULL)
2446     return FALSE;
2447
2448   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2449    * that gets us to stage coordinates, we want to go all the way to eye
2450    * coordinates */
2451   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2452
2453   /* Fetch the projection and viewport */
2454   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2455   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2456                                &viewport[0],
2457                                &viewport[1],
2458                                &viewport[2],
2459                                &viewport[3]);
2460
2461   _clutter_util_fully_transform_vertices (&modelview,
2462                                           &projection,
2463                                           viewport,
2464                                           vertices_in,
2465                                           vertices_out,
2466                                           n_vertices);
2467
2468   return TRUE;
2469 }
2470
2471 /**
2472  * clutter_actor_apply_transform_to_point:
2473  * @self: A #ClutterActor
2474  * @point: A point as #ClutterVertex
2475  * @vertex: (out caller-allocates): The translated #ClutterVertex
2476  *
2477  * Transforms @point in coordinates relative to the actor
2478  * into screen-relative coordinates with the current actor
2479  * transformation (i.e. scale, rotation, etc)
2480  *
2481  * Since: 0.4
2482  **/
2483 void
2484 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2485                                         const ClutterVertex *point,
2486                                         ClutterVertex       *vertex)
2487 {
2488   g_return_if_fail (point != NULL);
2489   g_return_if_fail (vertex != NULL);
2490   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2491 }
2492
2493 /*
2494  * _clutter_actor_get_relative_transformation_matrix:
2495  * @self: The actor whose coordinate space you want to transform from.
2496  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2497  *            or %NULL if you want to transform all the way to eye coordinates.
2498  * @matrix: A #CoglMatrix to store the transformation
2499  *
2500  * This gets a transformation @matrix that will transform coordinates from the
2501  * coordinate space of @self into the coordinate space of @ancestor.
2502  *
2503  * For example if you need a matrix that can transform the local actor
2504  * coordinates of @self into stage coordinates you would pass the actor's stage
2505  * pointer as the @ancestor.
2506  *
2507  * If you pass %NULL then the transformation will take you all the way through
2508  * to eye coordinates. This can be useful if you want to extract the entire
2509  * modelview transform that Clutter applies before applying the projection
2510  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2511  * using cogl_set_modelview_matrix() for example then you would want a matrix
2512  * that transforms into eye coordinates.
2513  *
2514  * <note><para>This function explicitly initializes the given @matrix. If you just
2515  * want clutter to multiply a relative transformation with an existing matrix
2516  * you can use clutter_actor_apply_relative_transformation_matrix()
2517  * instead.</para></note>
2518  *
2519  */
2520 /* XXX: We should consider caching the stage relative modelview along with
2521  * the actor itself */
2522 static void
2523 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2524                                                    ClutterActor *ancestor,
2525                                                    CoglMatrix *matrix)
2526 {
2527   cogl_matrix_init_identity (matrix);
2528
2529   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2530 }
2531
2532 /* Project the given @box into stage window coordinates, writing the
2533  * transformed vertices to @verts[]. */
2534 static gboolean
2535 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2536                                           const ClutterActorBox *box,
2537                                           ClutterVertex          verts[])
2538 {
2539   ClutterVertex box_vertices[4];
2540
2541   box_vertices[0].x = box->x1;
2542   box_vertices[0].y = box->y1;
2543   box_vertices[0].z = 0;
2544   box_vertices[1].x = box->x2;
2545   box_vertices[1].y = box->y1;
2546   box_vertices[1].z = 0;
2547   box_vertices[2].x = box->x1;
2548   box_vertices[2].y = box->y2;
2549   box_vertices[2].z = 0;
2550   box_vertices[3].x = box->x2;
2551   box_vertices[3].y = box->y2;
2552   box_vertices[3].z = 0;
2553
2554   return
2555     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2556 }
2557
2558 /**
2559  * clutter_actor_get_allocation_vertices:
2560  * @self: A #ClutterActor
2561  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2562  *   against, or %NULL to use the #ClutterStage
2563  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2564  *   location for an array of 4 #ClutterVertex in which to store the result
2565  *
2566  * Calculates the transformed coordinates of the four corners of the
2567  * actor in the plane of @ancestor. The returned vertices relate to
2568  * the #ClutterActorBox coordinates as follows:
2569  * <itemizedlist>
2570  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2571  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2572  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2573  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2574  * </itemizedlist>
2575  *
2576  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2577  * this case, the coordinates returned will be the coordinates on
2578  * the stage before the projection is applied. This is different from
2579  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2580  *
2581  * Since: 0.6
2582  */
2583 void
2584 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2585                                        ClutterActor  *ancestor,
2586                                        ClutterVertex  verts[])
2587 {
2588   ClutterActorPrivate *priv;
2589   ClutterActorBox box;
2590   ClutterVertex vertices[4];
2591   CoglMatrix modelview;
2592
2593   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2594   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2595
2596   if (ancestor == NULL)
2597     ancestor = _clutter_actor_get_stage_internal (self);
2598
2599   /* Fallback to a NOP transform if the actor isn't parented under a
2600    * stage. */
2601   if (ancestor == NULL)
2602     ancestor = self;
2603
2604   priv = self->priv;
2605
2606   /* if the actor needs to be allocated we force a relayout, so that
2607    * we will have valid values to use in the transformations */
2608   if (priv->needs_allocation)
2609     {
2610       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2611       if (stage)
2612         _clutter_stage_maybe_relayout (stage);
2613       else
2614         {
2615           box.x1 = box.y1 = 0;
2616           /* The result isn't really meaningful in this case but at
2617            * least try to do something *vaguely* reasonable... */
2618           clutter_actor_get_size (self, &box.x2, &box.y2);
2619         }
2620     }
2621
2622   clutter_actor_get_allocation_box (self, &box);
2623
2624   vertices[0].x = box.x1;
2625   vertices[0].y = box.y1;
2626   vertices[0].z = 0;
2627   vertices[1].x = box.x2;
2628   vertices[1].y = box.y1;
2629   vertices[1].z = 0;
2630   vertices[2].x = box.x1;
2631   vertices[2].y = box.y2;
2632   vertices[2].z = 0;
2633   vertices[3].x = box.x2;
2634   vertices[3].y = box.y2;
2635   vertices[3].z = 0;
2636
2637   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2638                                                      &modelview);
2639
2640   cogl_matrix_transform_points (&modelview,
2641                                 3,
2642                                 sizeof (ClutterVertex),
2643                                 vertices,
2644                                 sizeof (ClutterVertex),
2645                                 vertices,
2646                                 4);
2647 }
2648
2649 /**
2650  * clutter_actor_get_abs_allocation_vertices:
2651  * @self: A #ClutterActor
2652  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2653  *   of 4 #ClutterVertex where to store the result.
2654  *
2655  * Calculates the transformed screen coordinates of the four corners of
2656  * the actor; the returned vertices relate to the #ClutterActorBox
2657  * coordinates  as follows:
2658  * <itemizedlist>
2659  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2660  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2661  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2662  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2663  * </itemizedlist>
2664  *
2665  * Since: 0.4
2666  */
2667 void
2668 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2669                                            ClutterVertex  verts[])
2670 {
2671   ClutterActorPrivate *priv;
2672   ClutterActorBox actor_space_allocation;
2673
2674   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2675
2676   priv = self->priv;
2677
2678   /* if the actor needs to be allocated we force a relayout, so that
2679    * the actor allocation box will be valid for
2680    * _clutter_actor_transform_and_project_box()
2681    */
2682   if (priv->needs_allocation)
2683     {
2684       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2685       /* There's nothing meaningful we can do now */
2686       if (!stage)
2687         return;
2688
2689       _clutter_stage_maybe_relayout (stage);
2690     }
2691
2692   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2693    * own coordinate space... */
2694   actor_space_allocation.x1 = 0;
2695   actor_space_allocation.y1 = 0;
2696   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2697   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2698   _clutter_actor_transform_and_project_box (self,
2699                                             &actor_space_allocation,
2700                                             verts);
2701 }
2702
2703 static void
2704 clutter_actor_real_apply_transform (ClutterActor *self,
2705                                     CoglMatrix   *matrix)
2706 {
2707   ClutterActorPrivate *priv = self->priv;
2708
2709   if (!priv->transform_valid)
2710     {
2711       CoglMatrix *transform = &priv->transform;
2712       const ClutterTransformInfo *info;
2713
2714       info = _clutter_actor_get_transform_info_or_defaults (self);
2715
2716       cogl_matrix_init_identity (transform);
2717
2718       cogl_matrix_translate (transform,
2719                              priv->allocation.x1,
2720                              priv->allocation.y1,
2721                              0.0);
2722
2723       if (info->depth)
2724         cogl_matrix_translate (transform, 0, 0, info->depth);
2725
2726       /*
2727        * because the rotation involves translations, we must scale
2728        * before applying the rotations (if we apply the scale after
2729        * the rotations, the translations included in the rotation are
2730        * not scaled and so the entire object will move on the screen
2731        * as a result of rotating it).
2732        */
2733       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2734         {
2735           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2736                                         &info->scale_center,
2737                                         cogl_matrix_scale (transform,
2738                                                            info->scale_x,
2739                                                            info->scale_y,
2740                                                            1.0));
2741         }
2742
2743       if (info->rz_angle)
2744         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2745                                       &info->rz_center,
2746                                       cogl_matrix_rotate (transform,
2747                                                           info->rz_angle,
2748                                                           0, 0, 1.0));
2749
2750       if (info->ry_angle)
2751         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2752                                       &info->ry_center,
2753                                       cogl_matrix_rotate (transform,
2754                                                           info->ry_angle,
2755                                                           0, 1.0, 0));
2756
2757       if (info->rx_angle)
2758         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2759                                       &info->rx_center,
2760                                       cogl_matrix_rotate (transform,
2761                                                           info->rx_angle,
2762                                                           1.0, 0, 0));
2763
2764       if (!clutter_anchor_coord_is_zero (&info->anchor))
2765         {
2766           gfloat x, y, z;
2767
2768           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2769           cogl_matrix_translate (transform, -x, -y, -z);
2770         }
2771
2772       priv->transform_valid = TRUE;
2773     }
2774
2775   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2776 }
2777
2778 /* Applies the transforms associated with this actor to the given
2779  * matrix. */
2780 void
2781 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2782                                           CoglMatrix *matrix)
2783 {
2784   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2785 }
2786
2787 /*
2788  * clutter_actor_apply_relative_transformation_matrix:
2789  * @self: The actor whose coordinate space you want to transform from.
2790  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2791  *            or %NULL if you want to transform all the way to eye coordinates.
2792  * @matrix: A #CoglMatrix to apply the transformation too.
2793  *
2794  * This multiplies a transform with @matrix that will transform coordinates
2795  * from the coordinate space of @self into the coordinate space of @ancestor.
2796  *
2797  * For example if you need a matrix that can transform the local actor
2798  * coordinates of @self into stage coordinates you would pass the actor's stage
2799  * pointer as the @ancestor.
2800  *
2801  * If you pass %NULL then the transformation will take you all the way through
2802  * to eye coordinates. This can be useful if you want to extract the entire
2803  * modelview transform that Clutter applies before applying the projection
2804  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2805  * using cogl_set_modelview_matrix() for example then you would want a matrix
2806  * that transforms into eye coordinates.
2807  *
2808  * <note>This function doesn't initialize the given @matrix, it simply
2809  * multiplies the requested transformation matrix with the existing contents of
2810  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2811  * before calling this function, or you can use
2812  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2813  */
2814 void
2815 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2816                                                      ClutterActor *ancestor,
2817                                                      CoglMatrix *matrix)
2818 {
2819   ClutterActor *parent;
2820
2821   /* Note we terminate before ever calling stage->apply_transform()
2822    * since that would conceptually be relative to the underlying
2823    * window OpenGL coordinates so we'd need a special @ancestor
2824    * value to represent the fake parent of the stage. */
2825   if (self == ancestor)
2826     return;
2827
2828   parent = clutter_actor_get_parent (self);
2829
2830   if (parent != NULL)
2831     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2832                                                          matrix);
2833
2834   _clutter_actor_apply_modelview_transform (self, matrix);
2835 }
2836
2837 static void
2838 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2839                                        ClutterPaintVolume *pv,
2840                                        const char *label,
2841                                        const CoglColor *color)
2842 {
2843   static CoglPipeline *outline = NULL;
2844   CoglPrimitive *prim;
2845   ClutterVertex line_ends[12 * 2];
2846   int n_vertices;
2847   CoglContext *ctx =
2848     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2849   /* XXX: at some point we'll query this from the stage but we can't
2850    * do that until the osx backend uses Cogl natively. */
2851   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2852
2853   if (outline == NULL)
2854     outline = cogl_pipeline_new (ctx);
2855
2856   _clutter_paint_volume_complete (pv);
2857
2858   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2859
2860   /* Front face */
2861   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2862   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2863   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2864   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2865
2866   if (!pv->is_2d)
2867     {
2868       /* Back face */
2869       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2870       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2871       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2872       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2873
2874       /* Lines connecting front face to back face */
2875       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2876       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2877       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2878       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2879     }
2880
2881   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2882                                 n_vertices,
2883                                 (CoglVertexP3 *)line_ends);
2884
2885   cogl_pipeline_set_color (outline, color);
2886   cogl_framebuffer_draw_primitive (fb, outline, prim);
2887   cogl_object_unref (prim);
2888
2889   if (label)
2890     {
2891       PangoLayout *layout;
2892       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2893       pango_layout_set_text (layout, label, -1);
2894       cogl_pango_render_layout (layout,
2895                                 pv->vertices[0].x,
2896                                 pv->vertices[0].y,
2897                                 color,
2898                                 0);
2899       g_object_unref (layout);
2900     }
2901 }
2902
2903 static void
2904 _clutter_actor_draw_paint_volume (ClutterActor *self)
2905 {
2906   ClutterPaintVolume *pv;
2907   CoglColor color;
2908
2909   pv = _clutter_actor_get_paint_volume_mutable (self);
2910   if (!pv)
2911     {
2912       gfloat width, height;
2913       ClutterPaintVolume fake_pv;
2914
2915       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2916       _clutter_paint_volume_init_static (&fake_pv, stage);
2917
2918       clutter_actor_get_size (self, &width, &height);
2919       clutter_paint_volume_set_width (&fake_pv, width);
2920       clutter_paint_volume_set_height (&fake_pv, height);
2921
2922       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2923       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2924                                              _clutter_actor_get_debug_name (self),
2925                                              &color);
2926
2927       clutter_paint_volume_free (&fake_pv);
2928     }
2929   else
2930     {
2931       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2932       _clutter_actor_draw_paint_volume_full (self, pv,
2933                                              _clutter_actor_get_debug_name (self),
2934                                              &color);
2935     }
2936 }
2937
2938 static void
2939 _clutter_actor_paint_cull_result (ClutterActor *self,
2940                                   gboolean success,
2941                                   ClutterCullResult result)
2942 {
2943   ClutterPaintVolume *pv;
2944   CoglColor color;
2945
2946   if (success)
2947     {
2948       if (result == CLUTTER_CULL_RESULT_IN)
2949         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2950       else if (result == CLUTTER_CULL_RESULT_OUT)
2951         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2952       else
2953         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2954     }
2955   else
2956     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2957
2958   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2959     _clutter_actor_draw_paint_volume_full (self, pv,
2960                                            _clutter_actor_get_debug_name (self),
2961                                            &color);
2962   else
2963     {
2964       PangoLayout *layout;
2965       char *label =
2966         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2967       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2968       cogl_set_source_color (&color);
2969
2970       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2971       pango_layout_set_text (layout, label, -1);
2972       cogl_pango_render_layout (layout,
2973                                 0,
2974                                 0,
2975                                 &color,
2976                                 0);
2977       g_free (label);
2978       g_object_unref (layout);
2979     }
2980 }
2981
2982 static int clone_paint_level = 0;
2983
2984 void
2985 _clutter_actor_push_clone_paint (void)
2986 {
2987   clone_paint_level++;
2988 }
2989
2990 void
2991 _clutter_actor_pop_clone_paint (void)
2992 {
2993   clone_paint_level--;
2994 }
2995
2996 static gboolean
2997 in_clone_paint (void)
2998 {
2999   return clone_paint_level > 0;
3000 }
3001
3002 /* Returns TRUE if the actor can be ignored */
3003 /* FIXME: we should return a ClutterCullResult, and
3004  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3005  * means there's no point in trying to cull descendants of the current
3006  * node. */
3007 static gboolean
3008 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3009 {
3010   ClutterActorPrivate *priv = self->priv;
3011   ClutterActor *stage;
3012   const ClutterPlane *stage_clip;
3013
3014   if (!priv->last_paint_volume_valid)
3015     {
3016       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3017                     "->last_paint_volume_valid == FALSE",
3018                     _clutter_actor_get_debug_name (self));
3019       return FALSE;
3020     }
3021
3022   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3023     return FALSE;
3024
3025   stage = _clutter_actor_get_stage_internal (self);
3026   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3027   if (G_UNLIKELY (!stage_clip))
3028     {
3029       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3030                     "No stage clip set",
3031                     _clutter_actor_get_debug_name (self));
3032       return FALSE;
3033     }
3034
3035   if (cogl_get_draw_framebuffer () !=
3036       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3037     {
3038       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3039                     "Current framebuffer doesn't correspond to stage",
3040                     _clutter_actor_get_debug_name (self));
3041       return FALSE;
3042     }
3043
3044   *result_out =
3045     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3046   return TRUE;
3047 }
3048
3049 static void
3050 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3051 {
3052   ClutterActorPrivate *priv = self->priv;
3053   const ClutterPaintVolume *pv;
3054
3055   if (priv->last_paint_volume_valid)
3056     {
3057       clutter_paint_volume_free (&priv->last_paint_volume);
3058       priv->last_paint_volume_valid = FALSE;
3059     }
3060
3061   pv = clutter_actor_get_paint_volume (self);
3062   if (!pv)
3063     {
3064       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3065                     "Actor failed to report a paint volume",
3066                     _clutter_actor_get_debug_name (self));
3067       return;
3068     }
3069
3070   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3071
3072   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3073                                             NULL); /* eye coordinates */
3074
3075   priv->last_paint_volume_valid = TRUE;
3076 }
3077
3078 static inline gboolean
3079 actor_has_shader_data (ClutterActor *self)
3080 {
3081   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3082 }
3083
3084 guint32
3085 _clutter_actor_get_pick_id (ClutterActor *self)
3086 {
3087   if (self->priv->pick_id < 0)
3088     return 0;
3089
3090   return self->priv->pick_id;
3091 }
3092
3093 /* This is the same as clutter_actor_add_effect except that it doesn't
3094    queue a redraw and it doesn't notify on the effect property */
3095 static void
3096 _clutter_actor_add_effect_internal (ClutterActor  *self,
3097                                     ClutterEffect *effect)
3098 {
3099   ClutterActorPrivate *priv = self->priv;
3100
3101   if (priv->effects == NULL)
3102     {
3103       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3104       priv->effects->actor = self;
3105     }
3106
3107   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3108 }
3109
3110 /* This is the same as clutter_actor_remove_effect except that it doesn't
3111    queue a redraw and it doesn't notify on the effect property */
3112 static void
3113 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3114                                        ClutterEffect *effect)
3115 {
3116   ClutterActorPrivate *priv = self->priv;
3117
3118   if (priv->effects == NULL)
3119     return;
3120
3121   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3122 }
3123
3124 static gboolean
3125 needs_flatten_effect (ClutterActor *self)
3126 {
3127   ClutterActorPrivate *priv = self->priv;
3128
3129   if (G_UNLIKELY (clutter_paint_debug_flags &
3130                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3131     return FALSE;
3132
3133   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3134     return TRUE;
3135   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3136     {
3137       if (clutter_actor_get_paint_opacity (self) < 255 &&
3138           clutter_actor_has_overlaps (self))
3139         return TRUE;
3140     }
3141
3142   return FALSE;
3143 }
3144
3145 static void
3146 add_or_remove_flatten_effect (ClutterActor *self)
3147 {
3148   ClutterActorPrivate *priv = self->priv;
3149
3150   /* Add or remove the flatten effect depending on the
3151      offscreen-redirect property. */
3152   if (needs_flatten_effect (self))
3153     {
3154       if (priv->flatten_effect == NULL)
3155         {
3156           ClutterActorMeta *actor_meta;
3157           gint priority;
3158
3159           priv->flatten_effect = _clutter_flatten_effect_new ();
3160           /* Keep a reference to the effect so that we can queue
3161              redraws from it */
3162           g_object_ref_sink (priv->flatten_effect);
3163
3164           /* Set the priority of the effect to high so that it will
3165              always be applied to the actor first. It uses an internal
3166              priority so that it won't be visible to applications */
3167           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3168           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3169           _clutter_actor_meta_set_priority (actor_meta, priority);
3170
3171           /* This will add the effect without queueing a redraw */
3172           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3173         }
3174     }
3175   else
3176     {
3177       if (priv->flatten_effect != NULL)
3178         {
3179           /* Destroy the effect so that it will lose its fbo cache of
3180              the actor */
3181           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3182           g_object_unref (priv->flatten_effect);
3183           priv->flatten_effect = NULL;
3184         }
3185     }
3186 }
3187
3188 static void
3189 clutter_actor_real_paint (ClutterActor *actor)
3190 {
3191   ClutterActorPrivate *priv = actor->priv;
3192   ClutterActor *iter;
3193
3194   for (iter = priv->first_child;
3195        iter != NULL;
3196        iter = iter->priv->next_sibling)
3197     {
3198       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3199                     _clutter_actor_get_debug_name (iter),
3200                     _clutter_actor_get_debug_name (actor),
3201                     iter->priv->allocation.x1,
3202                     iter->priv->allocation.y1,
3203                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3204                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3205
3206       clutter_actor_paint (iter);
3207     }
3208 }
3209
3210 static gboolean
3211 clutter_actor_paint_node (ClutterActor     *actor,
3212                           ClutterPaintNode *root)
3213 {
3214   ClutterActorPrivate *priv = actor->priv;
3215
3216   if (root == NULL)
3217     return FALSE;
3218
3219   if (priv->bg_color_set &&
3220       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3221     {
3222       ClutterPaintNode *node;
3223       ClutterColor bg_color;
3224       ClutterActorBox box;
3225
3226       box.x1 = 0.f;
3227       box.y1 = 0.f;
3228       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3229       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3230
3231       bg_color = priv->bg_color;
3232       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3233                      * priv->bg_color.alpha
3234                      / 255;
3235
3236       node = clutter_color_node_new (&bg_color);
3237       clutter_paint_node_set_name (node, "backgroundColor");
3238       clutter_paint_node_add_rectangle (node, &box);
3239       clutter_paint_node_add_child (root, node);
3240       clutter_paint_node_unref (node);
3241     }
3242
3243   if (priv->content != NULL)
3244     _clutter_content_paint_content (priv->content, actor, root);
3245
3246   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3247     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3248
3249   if (clutter_paint_node_get_n_children (root) == 0)
3250     return FALSE;
3251
3252 #ifdef CLUTTER_ENABLE_DEBUG
3253   if (CLUTTER_HAS_DEBUG (PAINT))
3254     {
3255       /* dump the tree only if we have one */
3256       _clutter_paint_node_dump_tree (root);
3257     }
3258 #endif /* CLUTTER_ENABLE_DEBUG */
3259
3260   _clutter_paint_node_paint (root);
3261
3262 #if 0
3263   /* XXX: Uncomment this when we disable emitting the paint signal */
3264   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3265 #endif
3266
3267   return TRUE;
3268 }
3269
3270 /**
3271  * clutter_actor_paint:
3272  * @self: A #ClutterActor
3273  *
3274  * Renders the actor to display.
3275  *
3276  * This function should not be called directly by applications.
3277  * Call clutter_actor_queue_redraw() to queue paints, instead.
3278  *
3279  * This function is context-aware, and will either cause a
3280  * regular paint or a pick paint.
3281  *
3282  * This function will emit the #ClutterActor::paint signal or
3283  * the #ClutterActor::pick signal, depending on the context.
3284  *
3285  * This function does not paint the actor if the actor is set to 0,
3286  * unless it is performing a pick paint.
3287  */
3288 void
3289 clutter_actor_paint (ClutterActor *self)
3290 {
3291   ClutterActorPrivate *priv;
3292   ClutterPickMode pick_mode;
3293   gboolean clip_set = FALSE;
3294   gboolean shader_applied = FALSE;
3295
3296   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3297                           "Actor real-paint counter",
3298                           "Increments each time any actor is painted",
3299                           0 /* no application private data */);
3300   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3301                           "Actor pick-paint counter",
3302                           "Increments each time any actor is painted "
3303                           "for picking",
3304                           0 /* no application private data */);
3305
3306   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3307
3308   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3309     return;
3310
3311   priv = self->priv;
3312
3313   pick_mode = _clutter_context_get_pick_mode ();
3314
3315   if (pick_mode == CLUTTER_PICK_NONE)
3316     priv->propagated_one_redraw = FALSE;
3317
3318   /* It's an important optimization that we consider painting of
3319    * actors with 0 opacity to be a NOP... */
3320   if (pick_mode == CLUTTER_PICK_NONE &&
3321       /* ignore top-levels, since they might be transparent */
3322       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3323       /* Use the override opacity if its been set */
3324       ((priv->opacity_override >= 0) ?
3325        priv->opacity_override : priv->opacity) == 0)
3326     return;
3327
3328   /* if we aren't paintable (not in a toplevel with all
3329    * parents paintable) then do nothing.
3330    */
3331   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3332     return;
3333
3334   /* mark that we are in the paint process */
3335   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3336
3337   cogl_push_matrix();
3338
3339   if (priv->enable_model_view_transform)
3340     {
3341       CoglMatrix matrix;
3342
3343       /* XXX: It could be better to cache the modelview with the actor
3344        * instead of progressively building up the transformations on
3345        * the matrix stack every time we paint. */
3346       cogl_get_modelview_matrix (&matrix);
3347       _clutter_actor_apply_modelview_transform (self, &matrix);
3348
3349 #ifdef CLUTTER_ENABLE_DEBUG
3350       /* Catch when out-of-band transforms have been made by actors not as part
3351        * of an apply_transform vfunc... */
3352       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3353         {
3354           CoglMatrix expected_matrix;
3355
3356           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3357                                                              &expected_matrix);
3358
3359           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3360             {
3361               GString *buf = g_string_sized_new (1024);
3362               ClutterActor *parent;
3363
3364               parent = self;
3365               while (parent != NULL)
3366                 {
3367                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3368
3369                   if (parent->priv->parent != NULL)
3370                     g_string_append (buf, "->");
3371
3372                   parent = parent->priv->parent;
3373                 }
3374
3375               g_warning ("Unexpected transform found when painting actor "
3376                          "\"%s\". This will be caused by one of the actor's "
3377                          "ancestors (%s) using the Cogl API directly to transform "
3378                          "children instead of using ::apply_transform().",
3379                          _clutter_actor_get_debug_name (self),
3380                          buf->str);
3381
3382               g_string_free (buf, TRUE);
3383             }
3384         }
3385 #endif /* CLUTTER_ENABLE_DEBUG */
3386
3387       cogl_set_modelview_matrix (&matrix);
3388     }
3389
3390   if (priv->has_clip)
3391     {
3392       cogl_clip_push_rectangle (priv->clip.x,
3393                                 priv->clip.y,
3394                                 priv->clip.x + priv->clip.width,
3395                                 priv->clip.y + priv->clip.height);
3396       clip_set = TRUE;
3397     }
3398   else if (priv->clip_to_allocation)
3399     {
3400       gfloat width, height;
3401
3402       width  = priv->allocation.x2 - priv->allocation.x1;
3403       height = priv->allocation.y2 - priv->allocation.y1;
3404
3405       cogl_clip_push_rectangle (0, 0, width, height);
3406       clip_set = TRUE;
3407     }
3408
3409   if (pick_mode == CLUTTER_PICK_NONE)
3410     {
3411       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3412
3413       /* We check whether we need to add the flatten effect before
3414          each paint so that we can avoid having a mechanism for
3415          applications to notify when the value of the
3416          has_overlaps virtual changes. */
3417       add_or_remove_flatten_effect (self);
3418     }
3419   else
3420     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3421
3422   /* We save the current paint volume so that the next time the
3423    * actor queues a redraw we can constrain the redraw to just
3424    * cover the union of the new bounding box and the old.
3425    *
3426    * We also fetch the current paint volume to perform culling so
3427    * we can avoid painting actors outside the current clip region.
3428    *
3429    * If we are painting inside a clone, we should neither update
3430    * the paint volume or use it to cull painting, since the paint
3431    * box represents the location of the source actor on the
3432    * screen.
3433    *
3434    * XXX: We are starting to do a lot of vertex transforms on
3435    * the CPU in a typical paint, so at some point we should
3436    * audit these and consider caching some things.
3437    *
3438    * NB: We don't perform culling while picking at this point because
3439    * clutter-stage.c doesn't setup the clipping planes appropriately.
3440    *
3441    * NB: We don't want to update the last-paint-volume during picking
3442    * because the last-paint-volume is used to determine the old screen
3443    * space location of an actor that has moved so we can know the
3444    * minimal region to redraw to clear an old view of the actor. If we
3445    * update this during picking then by the time we come around to
3446    * paint then the last-paint-volume would likely represent the new
3447    * actor position not the old.
3448    */
3449   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3450     {
3451       gboolean success;
3452       /* annoyingly gcc warns if uninitialized even though
3453        * the initialization is redundant :-( */
3454       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3455
3456       if (G_LIKELY ((clutter_paint_debug_flags &
3457                      (CLUTTER_DEBUG_DISABLE_CULLING |
3458                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3459                     (CLUTTER_DEBUG_DISABLE_CULLING |
3460                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3461         _clutter_actor_update_last_paint_volume (self);
3462
3463       success = cull_actor (self, &result);
3464
3465       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3466         _clutter_actor_paint_cull_result (self, success, result);
3467       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3468         goto done;
3469     }
3470
3471   if (priv->effects == NULL)
3472     {
3473       if (pick_mode == CLUTTER_PICK_NONE &&
3474           actor_has_shader_data (self))
3475         {
3476           _clutter_actor_shader_pre_paint (self, FALSE);
3477           shader_applied = TRUE;
3478         }
3479
3480       priv->next_effect_to_paint = NULL;
3481     }
3482   else
3483     priv->next_effect_to_paint =
3484       _clutter_meta_group_peek_metas (priv->effects);
3485
3486   clutter_actor_continue_paint (self);
3487
3488   if (shader_applied)
3489     _clutter_actor_shader_post_paint (self);
3490
3491   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3492                   pick_mode == CLUTTER_PICK_NONE))
3493     _clutter_actor_draw_paint_volume (self);
3494
3495 done:
3496   /* If we make it here then the actor has run through a complete
3497      paint run including all the effects so it's no longer dirty */
3498   if (pick_mode == CLUTTER_PICK_NONE)
3499     priv->is_dirty = FALSE;
3500
3501   if (clip_set)
3502     cogl_clip_pop();
3503
3504   cogl_pop_matrix();
3505
3506   /* paint sequence complete */
3507   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3508 }
3509
3510 /**
3511  * clutter_actor_continue_paint:
3512  * @self: A #ClutterActor
3513  *
3514  * Run the next stage of the paint sequence. This function should only
3515  * be called within the implementation of the ‘run’ virtual of a
3516  * #ClutterEffect. It will cause the run method of the next effect to
3517  * be applied, or it will paint the actual actor if the current effect
3518  * is the last effect in the chain.
3519  *
3520  * Since: 1.8
3521  */
3522 void
3523 clutter_actor_continue_paint (ClutterActor *self)
3524 {
3525   ClutterActorPrivate *priv;
3526
3527   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3528   /* This should only be called from with in the ‘run’ implementation
3529      of a ClutterEffect */
3530   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3531
3532   priv = self->priv;
3533
3534   /* Skip any effects that are disabled */
3535   while (priv->next_effect_to_paint &&
3536          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3537     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3538
3539   /* If this has come from the last effect then we'll just paint the
3540      actual actor */
3541   if (priv->next_effect_to_paint == NULL)
3542     {
3543       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3544         {
3545           ClutterPaintNode *dummy;
3546
3547           /* XXX - this will go away in 2.0, when we can get rid of this
3548            * stuff and switch to a pure retained render tree of PaintNodes
3549            * for the entire frame, starting from the Stage; the paint()
3550            * virtual function can then be called directly.
3551            */
3552           dummy = _clutter_dummy_node_new (self);
3553           clutter_paint_node_set_name (dummy, "Root");
3554
3555           /* XXX - for 1.12, we use the return value of paint_node() to
3556            * decide whether we should emit the ::paint signal.
3557            */
3558           clutter_actor_paint_node (self, dummy);
3559           clutter_paint_node_unref (dummy);
3560
3561           g_signal_emit (self, actor_signals[PAINT], 0);
3562         }
3563       else
3564         {
3565           ClutterColor col = { 0, };
3566
3567           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3568
3569           /* Actor will then paint silhouette of itself in supplied
3570            * color.  See clutter_stage_get_actor_at_pos() for where
3571            * picking is enabled.
3572            */
3573           g_signal_emit (self, actor_signals[PICK], 0, &col);
3574         }
3575     }
3576   else
3577     {
3578       ClutterEffect *old_current_effect;
3579       ClutterEffectPaintFlags run_flags = 0;
3580
3581       /* Cache the current effect so that we can put it back before
3582          returning */
3583       old_current_effect = priv->current_effect;
3584
3585       priv->current_effect = priv->next_effect_to_paint->data;
3586       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3587
3588       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3589         {
3590           if (priv->is_dirty)
3591             {
3592               /* If there's an effect queued with this redraw then all
3593                  effects up to that one will be considered dirty. It
3594                  is expected the queued effect will paint the cached
3595                  image and not call clutter_actor_continue_paint again
3596                  (although it should work ok if it does) */
3597               if (priv->effect_to_redraw == NULL ||
3598                   priv->current_effect != priv->effect_to_redraw)
3599                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3600             }
3601
3602           _clutter_effect_paint (priv->current_effect, run_flags);
3603         }
3604       else
3605         {
3606           /* We can't determine when an actor has been modified since
3607              its last pick so lets just assume it has always been
3608              modified */
3609           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3610
3611           _clutter_effect_pick (priv->current_effect, run_flags);
3612         }
3613
3614       priv->current_effect = old_current_effect;
3615     }
3616 }
3617
3618 static ClutterActorTraverseVisitFlags
3619 invalidate_queue_redraw_entry (ClutterActor *self,
3620                                int           depth,
3621                                gpointer      user_data)
3622 {
3623   ClutterActorPrivate *priv = self->priv;
3624
3625   if (priv->queue_redraw_entry != NULL)
3626     {
3627       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3628       priv->queue_redraw_entry = NULL;
3629     }
3630
3631   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3632 }
3633
3634 static inline void
3635 remove_child (ClutterActor *self,
3636               ClutterActor *child)
3637 {
3638   ClutterActor *prev_sibling, *next_sibling;
3639
3640   prev_sibling = child->priv->prev_sibling;
3641   next_sibling = child->priv->next_sibling;
3642
3643   if (prev_sibling != NULL)
3644     prev_sibling->priv->next_sibling = next_sibling;
3645
3646   if (next_sibling != NULL)
3647     next_sibling->priv->prev_sibling = prev_sibling;
3648
3649   if (self->priv->first_child == child)
3650     self->priv->first_child = next_sibling;
3651
3652   if (self->priv->last_child == child)
3653     self->priv->last_child = prev_sibling;
3654
3655   child->priv->parent = NULL;
3656   child->priv->prev_sibling = NULL;
3657   child->priv->next_sibling = NULL;
3658 }
3659
3660 typedef enum {
3661   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3662   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3663   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3664   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3665   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3666   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3667
3668   /* default flags for public API */
3669   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3670                                     REMOVE_CHILD_EMIT_PARENT_SET |
3671                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3672                                     REMOVE_CHILD_CHECK_STATE |
3673                                     REMOVE_CHILD_FLUSH_QUEUE |
3674                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3675
3676   /* flags for legacy/deprecated API */
3677   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3678                                     REMOVE_CHILD_FLUSH_QUEUE |
3679                                     REMOVE_CHILD_EMIT_PARENT_SET |
3680                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3681 } ClutterActorRemoveChildFlags;
3682
3683 /*< private >
3684  * clutter_actor_remove_child_internal:
3685  * @self: a #ClutterActor
3686  * @child: the child of @self that has to be removed
3687  * @flags: control the removal operations
3688  *
3689  * Removes @child from the list of children of @self.
3690  */
3691 static void
3692 clutter_actor_remove_child_internal (ClutterActor                 *self,
3693                                      ClutterActor                 *child,
3694                                      ClutterActorRemoveChildFlags  flags)
3695 {
3696   ClutterActor *old_first, *old_last;
3697   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3698   gboolean flush_queue;
3699   gboolean notify_first_last;
3700   gboolean was_mapped;
3701
3702   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3703   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3704   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3705   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3706   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3707   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3708
3709   g_object_freeze_notify (G_OBJECT (self));
3710
3711   if (destroy_meta)
3712     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3713
3714   if (check_state)
3715     {
3716       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3717
3718       /* we need to unrealize *before* we set parent_actor to NULL,
3719        * because in an unrealize method actors are dissociating from the
3720        * stage, which means they need to be able to
3721        * clutter_actor_get_stage().
3722        *
3723        * yhis should unmap and unrealize, unless we're reparenting.
3724        */
3725       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3726     }
3727   else
3728     was_mapped = FALSE;
3729
3730   if (flush_queue)
3731     {
3732       /* We take this opportunity to invalidate any queue redraw entry
3733        * associated with the actor and descendants since we won't be able to
3734        * determine the appropriate stage after this.
3735        *
3736        * we do this after we updated the mapped state because actors might
3737        * end up queueing redraws inside their mapped/unmapped virtual
3738        * functions, and if we invalidate the redraw entry we could end up
3739        * with an inconsistent state and weird memory corruption. see
3740        * bugs:
3741        *
3742        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3743        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3744        */
3745       _clutter_actor_traverse (child,
3746                                0,
3747                                invalidate_queue_redraw_entry,
3748                                NULL,
3749                                NULL);
3750     }
3751
3752   old_first = self->priv->first_child;
3753   old_last = self->priv->last_child;
3754
3755   remove_child (self, child);
3756
3757   self->priv->n_children -= 1;
3758
3759   self->priv->age += 1;
3760
3761   /* clutter_actor_reparent() will emit ::parent-set for us */
3762   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3763     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3764
3765   /* if the child was mapped then we need to relayout ourselves to account
3766    * for the removed child
3767    */
3768   if (was_mapped)
3769     clutter_actor_queue_relayout (self);
3770
3771   /* we need to emit the signal before dropping the reference */
3772   if (emit_actor_removed)
3773     g_signal_emit_by_name (self, "actor-removed", child);
3774
3775   if (notify_first_last)
3776     {
3777       if (old_first != self->priv->first_child)
3778         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3779
3780       if (old_last != self->priv->last_child)
3781         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3782     }
3783
3784   g_object_thaw_notify (G_OBJECT (self));
3785
3786   /* remove the reference we acquired in clutter_actor_add_child() */
3787   g_object_unref (child);
3788 }
3789
3790 static const ClutterTransformInfo default_transform_info = {
3791   0.0, { 0, },          /* rotation-x */
3792   0.0, { 0, },          /* rotation-y */
3793   0.0, { 0, },          /* rotation-z */
3794
3795   1.0, 1.0, { 0, },     /* scale */
3796
3797   { 0, },               /* anchor */
3798
3799   0.0,                  /* depth */
3800 };
3801
3802 /*< private >
3803  * _clutter_actor_get_transform_info_or_defaults:
3804  * @self: a #ClutterActor
3805  *
3806  * Retrieves the ClutterTransformInfo structure associated to an actor.
3807  *
3808  * If the actor does not have a ClutterTransformInfo structure associated
3809  * to it, then the default structure will be returned.
3810  *
3811  * This function should only be used for getters.
3812  *
3813  * Return value: a const pointer to the ClutterTransformInfo structure
3814  */
3815 const ClutterTransformInfo *
3816 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3817 {
3818   ClutterTransformInfo *info;
3819
3820   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3821   if (info != NULL)
3822     return info;
3823
3824   return &default_transform_info;
3825 }
3826
3827 static void
3828 clutter_transform_info_free (gpointer data)
3829 {
3830   if (data != NULL)
3831     g_slice_free (ClutterTransformInfo, data);
3832 }
3833
3834 /*< private >
3835  * _clutter_actor_get_transform_info:
3836  * @self: a #ClutterActor
3837  *
3838  * Retrieves a pointer to the ClutterTransformInfo structure.
3839  *
3840  * If the actor does not have a ClutterTransformInfo associated to it, one
3841  * will be created and initialized to the default values.
3842  *
3843  * This function should be used for setters.
3844  *
3845  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3846  * instead.
3847  *
3848  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3849  *   structure
3850  */
3851 ClutterTransformInfo *
3852 _clutter_actor_get_transform_info (ClutterActor *self)
3853 {
3854   ClutterTransformInfo *info;
3855
3856   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3857   if (info == NULL)
3858     {
3859       info = g_slice_new (ClutterTransformInfo);
3860
3861       *info = default_transform_info;
3862
3863       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3864                                info,
3865                                clutter_transform_info_free);
3866     }
3867
3868   return info;
3869 }
3870
3871 /*< private >
3872  * clutter_actor_set_rotation_angle_internal:
3873  * @self: a #ClutterActor
3874  * @axis: the axis of the angle to change
3875  * @angle: the angle of rotation
3876  *
3877  * Sets the rotation angle on the given axis without affecting the
3878  * rotation center point.
3879  */
3880 static inline void
3881 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3882                                            ClutterRotateAxis  axis,
3883                                            gdouble            angle)
3884 {
3885   GObject *obj = G_OBJECT (self);
3886   ClutterTransformInfo *info;
3887
3888   info = _clutter_actor_get_transform_info (self);
3889
3890   g_object_freeze_notify (obj);
3891
3892   switch (axis)
3893     {
3894     case CLUTTER_X_AXIS:
3895       info->rx_angle = angle;
3896       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3897       break;
3898
3899     case CLUTTER_Y_AXIS:
3900       info->ry_angle = angle;
3901       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3902       break;
3903
3904     case CLUTTER_Z_AXIS:
3905       info->rz_angle = angle;
3906       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3907       break;
3908     }
3909
3910   self->priv->transform_valid = FALSE;
3911
3912   g_object_thaw_notify (obj);
3913
3914   clutter_actor_queue_redraw (self);
3915 }
3916
3917 static inline void
3918 clutter_actor_set_rotation_angle (ClutterActor      *self,
3919                                   ClutterRotateAxis  axis,
3920                                   gdouble            angle)
3921 {
3922   ClutterTransformInfo *info;
3923
3924   info = _clutter_actor_get_transform_info (self);
3925
3926   if (clutter_actor_get_easing_duration (self) != 0)
3927     {
3928       ClutterTransition *transition;
3929       GParamSpec *pspec = NULL;
3930       double *cur_angle_p = NULL;
3931
3932       switch (axis)
3933         {
3934         case CLUTTER_X_AXIS:
3935           cur_angle_p = &info->rx_angle;
3936           pspec = obj_props[PROP_ROTATION_ANGLE_X];
3937           break;
3938
3939         case CLUTTER_Y_AXIS:
3940           cur_angle_p = &info->ry_angle;
3941           pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3942           break;
3943
3944         case CLUTTER_Z_AXIS:
3945           cur_angle_p = &info->rz_angle;
3946           pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3947           break;
3948         }
3949
3950       g_assert (pspec != NULL);
3951       g_assert (cur_angle_p != NULL);
3952
3953       transition = _clutter_actor_get_transition (self, pspec);
3954       if (transition == NULL)
3955         {
3956           transition = _clutter_actor_create_transition (self, pspec,
3957                                                          *cur_angle_p,
3958                                                          angle);
3959           clutter_timeline_start (CLUTTER_TIMELINE (transition));
3960         }
3961       else
3962         _clutter_actor_update_transition (self, pspec, angle);
3963
3964       self->priv->transform_valid = FALSE;
3965       clutter_actor_queue_redraw (self);
3966     }
3967   else
3968     clutter_actor_set_rotation_angle_internal (self, axis, angle);
3969 }
3970
3971 /*< private >
3972  * clutter_actor_set_rotation_center_internal:
3973  * @self: a #ClutterActor
3974  * @axis: the axis of the center to change
3975  * @center: the coordinates of the rotation center
3976  *
3977  * Sets the rotation center on the given axis without affecting the
3978  * rotation angle.
3979  */
3980 static inline void
3981 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3982                                             ClutterRotateAxis    axis,
3983                                             const ClutterVertex *center)
3984 {
3985   GObject *obj = G_OBJECT (self);
3986   ClutterTransformInfo *info;
3987   ClutterVertex v = { 0, 0, 0 };
3988
3989   info = _clutter_actor_get_transform_info (self);
3990
3991   if (center != NULL)
3992     v = *center;
3993
3994   g_object_freeze_notify (obj);
3995
3996   switch (axis)
3997     {
3998     case CLUTTER_X_AXIS:
3999       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4000       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4001       break;
4002
4003     case CLUTTER_Y_AXIS:
4004       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4005       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4006       break;
4007
4008     case CLUTTER_Z_AXIS:
4009       /* if the previously set rotation center was fractional, then
4010        * setting explicit coordinates will have to notify the
4011        * :rotation-center-z-gravity property as well
4012        */
4013       if (info->rz_center.is_fractional)
4014         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4015
4016       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4017       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4018       break;
4019     }
4020
4021   self->priv->transform_valid = FALSE;
4022
4023   g_object_thaw_notify (obj);
4024
4025   clutter_actor_queue_redraw (self);
4026 }
4027
4028 static void
4029 clutter_actor_animate_scale_factor (ClutterActor *self,
4030                                     double        old_factor,
4031                                     double        new_factor,
4032                                     GParamSpec   *pspec)
4033 {
4034   ClutterTransition *transition;
4035
4036   transition = _clutter_actor_get_transition (self, pspec);
4037   if (transition == NULL)
4038     {
4039       transition = _clutter_actor_create_transition (self, pspec,
4040                                                      old_factor,
4041                                                      new_factor);
4042       clutter_timeline_start (CLUTTER_TIMELINE (transition));
4043     }
4044   else
4045     _clutter_actor_update_transition (self, pspec, new_factor);
4046
4047
4048   self->priv->transform_valid = FALSE;
4049   clutter_actor_queue_redraw (self);
4050 }
4051
4052 static void
4053 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4054                                          double factor,
4055                                          GParamSpec *pspec)
4056 {
4057   GObject *obj = G_OBJECT (self);
4058   ClutterTransformInfo *info;
4059
4060   info = _clutter_actor_get_transform_info (self);
4061
4062   if (pspec == obj_props[PROP_SCALE_X])
4063     info->scale_x = factor;
4064   else
4065     info->scale_y = factor;
4066
4067   self->priv->transform_valid = FALSE;
4068   clutter_actor_queue_redraw (self);
4069   g_object_notify_by_pspec (obj, pspec);
4070 }
4071
4072 static inline void
4073 clutter_actor_set_scale_factor (ClutterActor      *self,
4074                                 ClutterRotateAxis  axis,
4075                                 gdouble            factor)
4076 {
4077   GObject *obj = G_OBJECT (self);
4078   ClutterTransformInfo *info;
4079   GParamSpec *pspec;
4080
4081   info = _clutter_actor_get_transform_info (self);
4082
4083   g_object_freeze_notify (obj);
4084
4085   switch (axis)
4086     {
4087     case CLUTTER_X_AXIS:
4088       pspec = obj_props[PROP_SCALE_X];
4089
4090       if (clutter_actor_get_easing_duration (self) != 0)
4091         clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
4092       else
4093         clutter_actor_set_scale_factor_internal (self, factor, pspec);
4094       break;
4095
4096     case CLUTTER_Y_AXIS:
4097       pspec = obj_props[PROP_SCALE_Y];
4098
4099       if (clutter_actor_get_easing_duration (self) != 0)
4100         clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4101       else
4102         clutter_actor_set_scale_factor_internal (self, factor, pspec);
4103       break;
4104
4105     default:
4106       g_assert_not_reached ();
4107     }
4108
4109   g_object_thaw_notify (obj);
4110 }
4111
4112 static inline void
4113 clutter_actor_set_scale_center (ClutterActor      *self,
4114                                 ClutterRotateAxis  axis,
4115                                 gfloat             coord)
4116 {
4117   GObject *obj = G_OBJECT (self);
4118   ClutterTransformInfo *info;
4119   gfloat center_x, center_y;
4120
4121   info = _clutter_actor_get_transform_info (self);
4122
4123   g_object_freeze_notify (obj);
4124
4125   /* get the current scale center coordinates */
4126   clutter_anchor_coord_get_units (self, &info->scale_center,
4127                                   &center_x,
4128                                   &center_y,
4129                                   NULL);
4130
4131   /* we need to notify this too, because setting explicit coordinates will
4132    * change the gravity as a side effect
4133    */
4134   if (info->scale_center.is_fractional)
4135     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4136
4137   switch (axis)
4138     {
4139     case CLUTTER_X_AXIS:
4140       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4141       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4142       break;
4143
4144     case CLUTTER_Y_AXIS:
4145       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4146       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4147       break;
4148
4149     default:
4150       g_assert_not_reached ();
4151     }
4152
4153   self->priv->transform_valid = FALSE;
4154
4155   clutter_actor_queue_redraw (self);
4156
4157   g_object_thaw_notify (obj);
4158 }
4159
4160 static inline void
4161 clutter_actor_set_anchor_coord (ClutterActor      *self,
4162                                 ClutterRotateAxis  axis,
4163                                 gfloat             coord)
4164 {
4165   GObject *obj = G_OBJECT (self);
4166   ClutterTransformInfo *info;
4167   gfloat anchor_x, anchor_y;
4168
4169   info = _clutter_actor_get_transform_info (self);
4170
4171   g_object_freeze_notify (obj);
4172
4173   clutter_anchor_coord_get_units (self, &info->anchor,
4174                                   &anchor_x,
4175                                   &anchor_y,
4176                                   NULL);
4177
4178   if (info->anchor.is_fractional)
4179     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4180
4181   switch (axis)
4182     {
4183     case CLUTTER_X_AXIS:
4184       clutter_anchor_coord_set_units (&info->anchor,
4185                                       coord,
4186                                       anchor_y,
4187                                       0.0);
4188       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4189       break;
4190
4191     case CLUTTER_Y_AXIS:
4192       clutter_anchor_coord_set_units (&info->anchor,
4193                                       anchor_x,
4194                                       coord,
4195                                       0.0);
4196       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4197       break;
4198
4199     default:
4200       g_assert_not_reached ();
4201     }
4202
4203   self->priv->transform_valid = FALSE;
4204
4205   clutter_actor_queue_redraw (self);
4206
4207   g_object_thaw_notify (obj);
4208 }
4209
4210 static void
4211 clutter_actor_set_property (GObject      *object,
4212                             guint         prop_id,
4213                             const GValue *value,
4214                             GParamSpec   *pspec)
4215 {
4216   ClutterActor *actor = CLUTTER_ACTOR (object);
4217   ClutterActorPrivate *priv = actor->priv;
4218
4219   switch (prop_id)
4220     {
4221     case PROP_X:
4222       clutter_actor_set_x (actor, g_value_get_float (value));
4223       break;
4224
4225     case PROP_Y:
4226       clutter_actor_set_y (actor, g_value_get_float (value));
4227       break;
4228
4229     case PROP_WIDTH:
4230       clutter_actor_set_width (actor, g_value_get_float (value));
4231       break;
4232
4233     case PROP_HEIGHT:
4234       clutter_actor_set_height (actor, g_value_get_float (value));
4235       break;
4236
4237     case PROP_FIXED_X:
4238       clutter_actor_set_x (actor, g_value_get_float (value));
4239       break;
4240
4241     case PROP_FIXED_Y:
4242       clutter_actor_set_y (actor, g_value_get_float (value));
4243       break;
4244
4245     case PROP_FIXED_POSITION_SET:
4246       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4247       break;
4248
4249     case PROP_MIN_WIDTH:
4250       clutter_actor_set_min_width (actor, g_value_get_float (value));
4251       break;
4252
4253     case PROP_MIN_HEIGHT:
4254       clutter_actor_set_min_height (actor, g_value_get_float (value));
4255       break;
4256
4257     case PROP_NATURAL_WIDTH:
4258       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4259       break;
4260
4261     case PROP_NATURAL_HEIGHT:
4262       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4263       break;
4264
4265     case PROP_MIN_WIDTH_SET:
4266       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4267       break;
4268
4269     case PROP_MIN_HEIGHT_SET:
4270       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4271       break;
4272
4273     case PROP_NATURAL_WIDTH_SET:
4274       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4275       break;
4276
4277     case PROP_NATURAL_HEIGHT_SET:
4278       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4279       break;
4280
4281     case PROP_REQUEST_MODE:
4282       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4283       break;
4284
4285     case PROP_DEPTH:
4286       clutter_actor_set_depth (actor, g_value_get_float (value));
4287       break;
4288
4289     case PROP_OPACITY:
4290       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4291       break;
4292
4293     case PROP_OFFSCREEN_REDIRECT:
4294       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4295       break;
4296
4297     case PROP_NAME:
4298       clutter_actor_set_name (actor, g_value_get_string (value));
4299       break;
4300
4301     case PROP_VISIBLE:
4302       if (g_value_get_boolean (value) == TRUE)
4303         clutter_actor_show (actor);
4304       else
4305         clutter_actor_hide (actor);
4306       break;
4307
4308     case PROP_SCALE_X:
4309       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4310                                       g_value_get_double (value));
4311       break;
4312
4313     case PROP_SCALE_Y:
4314       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4315                                       g_value_get_double (value));
4316       break;
4317
4318     case PROP_SCALE_CENTER_X:
4319       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4320                                       g_value_get_float (value));
4321       break;
4322
4323     case PROP_SCALE_CENTER_Y:
4324       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4325                                       g_value_get_float (value));
4326       break;
4327
4328     case PROP_SCALE_GRAVITY:
4329       {
4330         const ClutterTransformInfo *info;
4331         ClutterGravity gravity;
4332
4333         info = _clutter_actor_get_transform_info_or_defaults (actor);
4334         gravity = g_value_get_enum (value);
4335
4336         clutter_actor_set_scale_with_gravity (actor,
4337                                               info->scale_x,
4338                                               info->scale_y,
4339                                               gravity);
4340       }
4341       break;
4342
4343     case PROP_CLIP:
4344       {
4345         const ClutterGeometry *geom = g_value_get_boxed (value);
4346
4347         clutter_actor_set_clip (actor,
4348                                 geom->x, geom->y,
4349                                 geom->width, geom->height);
4350       }
4351       break;
4352
4353     case PROP_CLIP_TO_ALLOCATION:
4354       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4355       break;
4356
4357     case PROP_REACTIVE:
4358       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4359       break;
4360
4361     case PROP_ROTATION_ANGLE_X:
4362       clutter_actor_set_rotation_angle (actor,
4363                                         CLUTTER_X_AXIS,
4364                                         g_value_get_double (value));
4365       break;
4366
4367     case PROP_ROTATION_ANGLE_Y:
4368       clutter_actor_set_rotation_angle (actor,
4369                                         CLUTTER_Y_AXIS,
4370                                         g_value_get_double (value));
4371       break;
4372
4373     case PROP_ROTATION_ANGLE_Z:
4374       clutter_actor_set_rotation_angle (actor,
4375                                         CLUTTER_Z_AXIS,
4376                                         g_value_get_double (value));
4377       break;
4378
4379     case PROP_ROTATION_CENTER_X:
4380       clutter_actor_set_rotation_center_internal (actor,
4381                                                   CLUTTER_X_AXIS,
4382                                                   g_value_get_boxed (value));
4383       break;
4384
4385     case PROP_ROTATION_CENTER_Y:
4386       clutter_actor_set_rotation_center_internal (actor,
4387                                                   CLUTTER_Y_AXIS,
4388                                                   g_value_get_boxed (value));
4389       break;
4390
4391     case PROP_ROTATION_CENTER_Z:
4392       clutter_actor_set_rotation_center_internal (actor,
4393                                                   CLUTTER_Z_AXIS,
4394                                                   g_value_get_boxed (value));
4395       break;
4396
4397     case PROP_ROTATION_CENTER_Z_GRAVITY:
4398       {
4399         const ClutterTransformInfo *info;
4400
4401         info = _clutter_actor_get_transform_info_or_defaults (actor);
4402         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4403                                                    g_value_get_enum (value));
4404       }
4405       break;
4406
4407     case PROP_ANCHOR_X:
4408       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4409                                       g_value_get_float (value));
4410       break;
4411
4412     case PROP_ANCHOR_Y:
4413       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4414                                       g_value_get_float (value));
4415       break;
4416
4417     case PROP_ANCHOR_GRAVITY:
4418       clutter_actor_set_anchor_point_from_gravity (actor,
4419                                                    g_value_get_enum (value));
4420       break;
4421
4422     case PROP_SHOW_ON_SET_PARENT:
4423       priv->show_on_set_parent = g_value_get_boolean (value);
4424       break;
4425
4426     case PROP_TEXT_DIRECTION:
4427       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4428       break;
4429
4430     case PROP_ACTIONS:
4431       clutter_actor_add_action (actor, g_value_get_object (value));
4432       break;
4433
4434     case PROP_CONSTRAINTS:
4435       clutter_actor_add_constraint (actor, g_value_get_object (value));
4436       break;
4437
4438     case PROP_EFFECT:
4439       clutter_actor_add_effect (actor, g_value_get_object (value));
4440       break;
4441
4442     case PROP_LAYOUT_MANAGER:
4443       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4444       break;
4445
4446     case PROP_X_ALIGN:
4447       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4448       break;
4449
4450     case PROP_Y_ALIGN:
4451       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4452       break;
4453
4454     case PROP_MARGIN_TOP:
4455       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4456       break;
4457
4458     case PROP_MARGIN_BOTTOM:
4459       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4460       break;
4461
4462     case PROP_MARGIN_LEFT:
4463       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4464       break;
4465
4466     case PROP_MARGIN_RIGHT:
4467       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4468       break;
4469
4470     case PROP_BACKGROUND_COLOR:
4471       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4472       break;
4473
4474     case PROP_CONTENT:
4475       clutter_actor_set_content (actor, g_value_get_object (value));
4476       break;
4477
4478     case PROP_CONTENT_GRAVITY:
4479       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4480       break;
4481
4482     case PROP_MINIFICATION_FILTER:
4483       clutter_actor_set_content_scaling_filters (actor,
4484                                                  g_value_get_enum (value),
4485                                                  actor->priv->mag_filter);
4486       break;
4487
4488     case PROP_MAGNIFICATION_FILTER:
4489       clutter_actor_set_content_scaling_filters (actor,
4490                                                  actor->priv->min_filter,
4491                                                  g_value_get_enum (value));
4492       break;
4493
4494     default:
4495       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4496       break;
4497     }
4498 }
4499
4500 static void
4501 clutter_actor_get_property (GObject    *object,
4502                             guint       prop_id,
4503                             GValue     *value,
4504                             GParamSpec *pspec)
4505 {
4506   ClutterActor *actor = CLUTTER_ACTOR (object);
4507   ClutterActorPrivate *priv = actor->priv;
4508
4509   switch (prop_id)
4510     {
4511     case PROP_X:
4512       g_value_set_float (value, clutter_actor_get_x (actor));
4513       break;
4514
4515     case PROP_Y:
4516       g_value_set_float (value, clutter_actor_get_y (actor));
4517       break;
4518
4519     case PROP_WIDTH:
4520       g_value_set_float (value, clutter_actor_get_width (actor));
4521       break;
4522
4523     case PROP_HEIGHT:
4524       g_value_set_float (value, clutter_actor_get_height (actor));
4525       break;
4526
4527     case PROP_FIXED_X:
4528       {
4529         const ClutterLayoutInfo *info;
4530
4531         info = _clutter_actor_get_layout_info_or_defaults (actor);
4532         g_value_set_float (value, info->fixed_x);
4533       }
4534       break;
4535
4536     case PROP_FIXED_Y:
4537       {
4538         const ClutterLayoutInfo *info;
4539
4540         info = _clutter_actor_get_layout_info_or_defaults (actor);
4541         g_value_set_float (value, info->fixed_y);
4542       }
4543       break;
4544
4545     case PROP_FIXED_POSITION_SET:
4546       g_value_set_boolean (value, priv->position_set);
4547       break;
4548
4549     case PROP_MIN_WIDTH:
4550       {
4551         const ClutterLayoutInfo *info;
4552
4553         info = _clutter_actor_get_layout_info_or_defaults (actor);
4554         g_value_set_float (value, info->min_width);
4555       }
4556       break;
4557
4558     case PROP_MIN_HEIGHT:
4559       {
4560         const ClutterLayoutInfo *info;
4561
4562         info = _clutter_actor_get_layout_info_or_defaults (actor);
4563         g_value_set_float (value, info->min_height);
4564       }
4565       break;
4566
4567     case PROP_NATURAL_WIDTH:
4568       {
4569         const ClutterLayoutInfo *info;
4570
4571         info = _clutter_actor_get_layout_info_or_defaults (actor);
4572         g_value_set_float (value, info->natural_width);
4573       }
4574       break;
4575
4576     case PROP_NATURAL_HEIGHT:
4577       {
4578         const ClutterLayoutInfo *info;
4579
4580         info = _clutter_actor_get_layout_info_or_defaults (actor);
4581         g_value_set_float (value, info->natural_height);
4582       }
4583       break;
4584
4585     case PROP_MIN_WIDTH_SET:
4586       g_value_set_boolean (value, priv->min_width_set);
4587       break;
4588
4589     case PROP_MIN_HEIGHT_SET:
4590       g_value_set_boolean (value, priv->min_height_set);
4591       break;
4592
4593     case PROP_NATURAL_WIDTH_SET:
4594       g_value_set_boolean (value, priv->natural_width_set);
4595       break;
4596
4597     case PROP_NATURAL_HEIGHT_SET:
4598       g_value_set_boolean (value, priv->natural_height_set);
4599       break;
4600
4601     case PROP_REQUEST_MODE:
4602       g_value_set_enum (value, priv->request_mode);
4603       break;
4604
4605     case PROP_ALLOCATION:
4606       g_value_set_boxed (value, &priv->allocation);
4607       break;
4608
4609     case PROP_DEPTH:
4610       g_value_set_float (value, clutter_actor_get_depth (actor));
4611       break;
4612
4613     case PROP_OPACITY:
4614       g_value_set_uint (value, priv->opacity);
4615       break;
4616
4617     case PROP_OFFSCREEN_REDIRECT:
4618       g_value_set_enum (value, priv->offscreen_redirect);
4619       break;
4620
4621     case PROP_NAME:
4622       g_value_set_string (value, priv->name);
4623       break;
4624
4625     case PROP_VISIBLE:
4626       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4627       break;
4628
4629     case PROP_MAPPED:
4630       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4631       break;
4632
4633     case PROP_REALIZED:
4634       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4635       break;
4636
4637     case PROP_HAS_CLIP:
4638       g_value_set_boolean (value, priv->has_clip);
4639       break;
4640
4641     case PROP_CLIP:
4642       {
4643         ClutterGeometry clip;
4644
4645         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4646         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4647         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4648         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4649
4650         g_value_set_boxed (value, &clip);
4651       }
4652       break;
4653
4654     case PROP_CLIP_TO_ALLOCATION:
4655       g_value_set_boolean (value, priv->clip_to_allocation);
4656       break;
4657
4658     case PROP_SCALE_X:
4659       {
4660         const ClutterTransformInfo *info;
4661
4662         info = _clutter_actor_get_transform_info_or_defaults (actor);
4663         g_value_set_double (value, info->scale_x);
4664       }
4665       break;
4666
4667     case PROP_SCALE_Y:
4668       {
4669         const ClutterTransformInfo *info;
4670
4671         info = _clutter_actor_get_transform_info_or_defaults (actor);
4672         g_value_set_double (value, info->scale_y);
4673       }
4674       break;
4675
4676     case PROP_SCALE_CENTER_X:
4677       {
4678         gfloat center;
4679
4680         clutter_actor_get_scale_center (actor, &center, NULL);
4681
4682         g_value_set_float (value, center);
4683       }
4684       break;
4685
4686     case PROP_SCALE_CENTER_Y:
4687       {
4688         gfloat center;
4689
4690         clutter_actor_get_scale_center (actor, NULL, &center);
4691
4692         g_value_set_float (value, center);
4693       }
4694       break;
4695
4696     case PROP_SCALE_GRAVITY:
4697       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4698       break;
4699
4700     case PROP_REACTIVE:
4701       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4702       break;
4703
4704     case PROP_ROTATION_ANGLE_X:
4705       {
4706         const ClutterTransformInfo *info;
4707
4708         info = _clutter_actor_get_transform_info_or_defaults (actor);
4709         g_value_set_double (value, info->rx_angle);
4710       }
4711       break;
4712
4713     case PROP_ROTATION_ANGLE_Y:
4714       {
4715         const ClutterTransformInfo *info;
4716
4717         info = _clutter_actor_get_transform_info_or_defaults (actor);
4718         g_value_set_double (value, info->ry_angle);
4719       }
4720       break;
4721
4722     case PROP_ROTATION_ANGLE_Z:
4723       {
4724         const ClutterTransformInfo *info;
4725
4726         info = _clutter_actor_get_transform_info_or_defaults (actor);
4727         g_value_set_double (value, info->rz_angle);
4728       }
4729       break;
4730
4731     case PROP_ROTATION_CENTER_X:
4732       {
4733         ClutterVertex center;
4734
4735         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4736                                     &center.x,
4737                                     &center.y,
4738                                     &center.z);
4739
4740         g_value_set_boxed (value, &center);
4741       }
4742       break;
4743
4744     case PROP_ROTATION_CENTER_Y:
4745       {
4746         ClutterVertex center;
4747
4748         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4749                                     &center.x,
4750                                     &center.y,
4751                                     &center.z);
4752
4753         g_value_set_boxed (value, &center);
4754       }
4755       break;
4756
4757     case PROP_ROTATION_CENTER_Z:
4758       {
4759         ClutterVertex center;
4760
4761         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4762                                     &center.x,
4763                                     &center.y,
4764                                     &center.z);
4765
4766         g_value_set_boxed (value, &center);
4767       }
4768       break;
4769
4770     case PROP_ROTATION_CENTER_Z_GRAVITY:
4771       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4772       break;
4773
4774     case PROP_ANCHOR_X:
4775       {
4776         const ClutterTransformInfo *info;
4777         gfloat anchor_x;
4778
4779         info = _clutter_actor_get_transform_info_or_defaults (actor);
4780         clutter_anchor_coord_get_units (actor, &info->anchor,
4781                                         &anchor_x,
4782                                         NULL,
4783                                         NULL);
4784         g_value_set_float (value, anchor_x);
4785       }
4786       break;
4787
4788     case PROP_ANCHOR_Y:
4789       {
4790         const ClutterTransformInfo *info;
4791         gfloat anchor_y;
4792
4793         info = _clutter_actor_get_transform_info_or_defaults (actor);
4794         clutter_anchor_coord_get_units (actor, &info->anchor,
4795                                         NULL,
4796                                         &anchor_y,
4797                                         NULL);
4798         g_value_set_float (value, anchor_y);
4799       }
4800       break;
4801
4802     case PROP_ANCHOR_GRAVITY:
4803       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4804       break;
4805
4806     case PROP_SHOW_ON_SET_PARENT:
4807       g_value_set_boolean (value, priv->show_on_set_parent);
4808       break;
4809
4810     case PROP_TEXT_DIRECTION:
4811       g_value_set_enum (value, priv->text_direction);
4812       break;
4813
4814     case PROP_HAS_POINTER:
4815       g_value_set_boolean (value, priv->has_pointer);
4816       break;
4817
4818     case PROP_LAYOUT_MANAGER:
4819       g_value_set_object (value, priv->layout_manager);
4820       break;
4821
4822     case PROP_X_ALIGN:
4823       {
4824         const ClutterLayoutInfo *info;
4825
4826         info = _clutter_actor_get_layout_info_or_defaults (actor);
4827         g_value_set_enum (value, info->x_align);
4828       }
4829       break;
4830
4831     case PROP_Y_ALIGN:
4832       {
4833         const ClutterLayoutInfo *info;
4834
4835         info = _clutter_actor_get_layout_info_or_defaults (actor);
4836         g_value_set_enum (value, info->y_align);
4837       }
4838       break;
4839
4840     case PROP_MARGIN_TOP:
4841       {
4842         const ClutterLayoutInfo *info;
4843
4844         info = _clutter_actor_get_layout_info_or_defaults (actor);
4845         g_value_set_float (value, info->margin.top);
4846       }
4847       break;
4848
4849     case PROP_MARGIN_BOTTOM:
4850       {
4851         const ClutterLayoutInfo *info;
4852
4853         info = _clutter_actor_get_layout_info_or_defaults (actor);
4854         g_value_set_float (value, info->margin.bottom);
4855       }
4856       break;
4857
4858     case PROP_MARGIN_LEFT:
4859       {
4860         const ClutterLayoutInfo *info;
4861
4862         info = _clutter_actor_get_layout_info_or_defaults (actor);
4863         g_value_set_float (value, info->margin.left);
4864       }
4865       break;
4866
4867     case PROP_MARGIN_RIGHT:
4868       {
4869         const ClutterLayoutInfo *info;
4870
4871         info = _clutter_actor_get_layout_info_or_defaults (actor);
4872         g_value_set_float (value, info->margin.right);
4873       }
4874       break;
4875
4876     case PROP_BACKGROUND_COLOR_SET:
4877       g_value_set_boolean (value, priv->bg_color_set);
4878       break;
4879
4880     case PROP_BACKGROUND_COLOR:
4881       g_value_set_boxed (value, &priv->bg_color);
4882       break;
4883
4884     case PROP_FIRST_CHILD:
4885       g_value_set_object (value, priv->first_child);
4886       break;
4887
4888     case PROP_LAST_CHILD:
4889       g_value_set_object (value, priv->last_child);
4890       break;
4891
4892     case PROP_CONTENT:
4893       g_value_set_object (value, priv->content);
4894       break;
4895
4896     case PROP_CONTENT_GRAVITY:
4897       g_value_set_enum (value, priv->content_gravity);
4898       break;
4899
4900     case PROP_CONTENT_BOX:
4901       {
4902         ClutterActorBox box = { 0, };
4903
4904         clutter_actor_get_content_box (actor, &box);
4905         g_value_set_boxed (value, &box);
4906       }
4907       break;
4908
4909     case PROP_MINIFICATION_FILTER:
4910       g_value_set_enum (value, priv->min_filter);
4911       break;
4912
4913     case PROP_MAGNIFICATION_FILTER:
4914       g_value_set_enum (value, priv->mag_filter);
4915       break;
4916
4917     default:
4918       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4919       break;
4920     }
4921 }
4922
4923 static void
4924 clutter_actor_dispose (GObject *object)
4925 {
4926   ClutterActor *self = CLUTTER_ACTOR (object);
4927   ClutterActorPrivate *priv = self->priv;
4928
4929   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4930                 priv->id,
4931                 g_type_name (G_OBJECT_TYPE (self)),
4932                 object->ref_count);
4933
4934   g_signal_emit (self, actor_signals[DESTROY], 0);
4935
4936   /* avoid recursing when called from clutter_actor_destroy() */
4937   if (priv->parent != NULL)
4938     {
4939       ClutterActor *parent = priv->parent;
4940
4941       /* go through the Container implementation unless this
4942        * is an internal child and has been marked as such.
4943        *
4944        * removing the actor from its parent will reset the
4945        * realized and mapped states.
4946        */
4947       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4948         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4949       else
4950         clutter_actor_remove_child_internal (parent, self,
4951                                              REMOVE_CHILD_LEGACY_FLAGS);
4952     }
4953
4954   /* parent must be gone at this point */
4955   g_assert (priv->parent == NULL);
4956
4957   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4958     {
4959       /* can't be mapped or realized with no parent */
4960       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4961       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4962     }
4963
4964   g_clear_object (&priv->pango_context);
4965   g_clear_object (&priv->actions);
4966   g_clear_object (&priv->constraints);
4967   g_clear_object (&priv->effects);
4968   g_clear_object (&priv->flatten_effect);
4969
4970   if (priv->layout_manager != NULL)
4971     {
4972       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4973       g_clear_object (&priv->layout_manager);
4974     }
4975
4976   if (priv->content != NULL)
4977     {
4978       _clutter_content_detached (priv->content, self);
4979       g_clear_object (&priv->content);
4980     }
4981
4982   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4983 }
4984
4985 static void
4986 clutter_actor_finalize (GObject *object)
4987 {
4988   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4989
4990   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4991                 priv->name != NULL ? priv->name : "<none>",
4992                 priv->id,
4993                 g_type_name (G_OBJECT_TYPE (object)));
4994
4995   _clutter_context_release_id (priv->id);
4996
4997   g_free (priv->name);
4998
4999   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5000 }
5001
5002
5003 /**
5004  * clutter_actor_get_accessible:
5005  * @self: a #ClutterActor
5006  *
5007  * Returns the accessible object that describes the actor to an
5008  * assistive technology.
5009  *
5010  * If no class-specific #AtkObject implementation is available for the
5011  * actor instance in question, it will inherit an #AtkObject
5012  * implementation from the first ancestor class for which such an
5013  * implementation is defined.
5014  *
5015  * The documentation of the <ulink
5016  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5017  * library contains more information about accessible objects and
5018  * their uses.
5019  *
5020  * Returns: (transfer none): the #AtkObject associated with @actor
5021  */
5022 AtkObject *
5023 clutter_actor_get_accessible (ClutterActor *self)
5024 {
5025   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5026
5027   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5028 }
5029
5030 static AtkObject *
5031 clutter_actor_real_get_accessible (ClutterActor *actor)
5032 {
5033   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5034 }
5035
5036 static AtkObject *
5037 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5038 {
5039   AtkObject *accessible;
5040
5041   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5042   if (accessible != NULL)
5043     g_object_ref (accessible);
5044
5045   return accessible;
5046 }
5047
5048 static void
5049 atk_implementor_iface_init (AtkImplementorIface *iface)
5050 {
5051   iface->ref_accessible = _clutter_actor_ref_accessible;
5052 }
5053
5054 static gboolean
5055 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5056                                            ClutterPaintVolume *volume)
5057 {
5058   ClutterActorPrivate *priv = self->priv;
5059   gboolean res = FALSE;
5060
5061   /* we start from the allocation */
5062   clutter_paint_volume_set_width (volume,
5063                                   priv->allocation.x2 - priv->allocation.x1);
5064   clutter_paint_volume_set_height (volume,
5065                                    priv->allocation.y2 - priv->allocation.y1);
5066
5067   /* if the actor has a clip set then we have a pretty definite
5068    * size for the paint volume: the actor cannot possibly paint
5069    * outside the clip region.
5070    */
5071   if (priv->clip_to_allocation)
5072     {
5073       /* the allocation has already been set, so we just flip the
5074        * return value
5075        */
5076       res = TRUE;
5077     }
5078   else
5079     {
5080       ClutterActor *child;
5081
5082       if (priv->has_clip &&
5083           priv->clip.width >= 0 &&
5084           priv->clip.height >= 0)
5085         {
5086           ClutterVertex origin;
5087
5088           origin.x = priv->clip.x;
5089           origin.y = priv->clip.y;
5090           origin.z = 0;
5091
5092           clutter_paint_volume_set_origin (volume, &origin);
5093           clutter_paint_volume_set_width (volume, priv->clip.width);
5094           clutter_paint_volume_set_height (volume, priv->clip.height);
5095
5096           res = TRUE;
5097         }
5098
5099       /* if we don't have children we just bail out here... */
5100       if (priv->n_children == 0)
5101         return res;
5102
5103       /* ...but if we have children then we ask for their paint volume in
5104        * our coordinates. if any of our children replies that it doesn't
5105        * have a paint volume, we bail out
5106        */
5107       for (child = priv->first_child;
5108            child != NULL;
5109            child = child->priv->next_sibling)
5110         {
5111           const ClutterPaintVolume *child_volume;
5112
5113           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5114           if (child_volume == NULL)
5115             {
5116               res = FALSE;
5117               break;
5118             }
5119
5120           clutter_paint_volume_union (volume, child_volume);
5121           res = TRUE;
5122         }
5123     }
5124
5125   return res;
5126
5127 }
5128
5129 static gboolean
5130 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5131                                      ClutterPaintVolume *volume)
5132 {
5133   ClutterActorClass *klass;
5134   gboolean res;
5135
5136   klass = CLUTTER_ACTOR_GET_CLASS (self);
5137
5138   /* XXX - this thoroughly sucks, but we don't want to penalize users
5139    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5140    * redraw. This should go away in 2.0.
5141    */
5142   if (klass->paint == clutter_actor_real_paint &&
5143       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5144     {
5145       res = TRUE;
5146     }
5147   else
5148     {
5149       /* this is the default return value: we cannot know if a class
5150        * is going to paint outside its allocation, so we take the
5151        * conservative approach.
5152        */
5153       res = FALSE;
5154     }
5155
5156   if (clutter_actor_update_default_paint_volume (self, volume))
5157     return res;
5158
5159   return FALSE;
5160 }
5161
5162 /**
5163  * clutter_actor_get_default_paint_volume:
5164  * @self: a #ClutterActor
5165  *
5166  * Retrieves the default paint volume for @self.
5167  *
5168  * This function provides the same #ClutterPaintVolume that would be
5169  * computed by the default implementation inside #ClutterActor of the
5170  * #ClutterActorClass.get_paint_volume() virtual function.
5171  *
5172  * This function should only be used by #ClutterActor subclasses that
5173  * cannot chain up to the parent implementation when computing their
5174  * paint volume.
5175  *
5176  * Return value: (transfer none): a pointer to the default
5177  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5178  *   the actor could not compute a valid paint volume. The returned value
5179  *   is not guaranteed to be stable across multiple frames, so if you
5180  *   want to retain it, you will need to copy it using
5181  *   clutter_paint_volume_copy().
5182  *
5183  * Since: 1.10
5184  */
5185 const ClutterPaintVolume *
5186 clutter_actor_get_default_paint_volume (ClutterActor *self)
5187 {
5188   ClutterPaintVolume volume;
5189   ClutterPaintVolume *res;
5190
5191   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5192
5193   res = NULL;
5194   _clutter_paint_volume_init_static (&volume, self);
5195   if (clutter_actor_update_default_paint_volume (self, &volume))
5196     {
5197       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5198
5199       if (stage != NULL)
5200         {
5201           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5202           _clutter_paint_volume_copy_static (&volume, res);
5203         }
5204     }
5205
5206   clutter_paint_volume_free (&volume);
5207
5208   return res;
5209 }
5210
5211 static gboolean
5212 clutter_actor_real_has_overlaps (ClutterActor *self)
5213 {
5214   /* By default we'll assume that all actors need an offscreen redirect to get
5215    * the correct opacity. Actors such as ClutterTexture that would never need
5216    * an offscreen redirect can override this to return FALSE. */
5217   return TRUE;
5218 }
5219
5220 static void
5221 clutter_actor_real_destroy (ClutterActor *actor)
5222 {
5223   ClutterActorIter iter;
5224
5225   clutter_actor_iter_init (&iter, actor);
5226   while (clutter_actor_iter_next (&iter, NULL))
5227     clutter_actor_iter_destroy (&iter);
5228 }
5229
5230 static GObject *
5231 clutter_actor_constructor (GType gtype,
5232                            guint n_props,
5233                            GObjectConstructParam *props)
5234 {
5235   GObjectClass *gobject_class;
5236   ClutterActor *self;
5237   GObject *retval;
5238
5239   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5240   retval = gobject_class->constructor (gtype, n_props, props);
5241   self = CLUTTER_ACTOR (retval);
5242
5243   if (self->priv->layout_manager == NULL)
5244     {
5245       ClutterLayoutManager *default_layout;
5246
5247       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5248
5249       default_layout = clutter_fixed_layout_new ();
5250       clutter_actor_set_layout_manager (self, default_layout);
5251     }
5252
5253   return retval;
5254 }
5255
5256 static void
5257 clutter_actor_class_init (ClutterActorClass *klass)
5258 {
5259   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5260
5261   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5262   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5263   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5264   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5265
5266   object_class->constructor = clutter_actor_constructor;
5267   object_class->set_property = clutter_actor_set_property;
5268   object_class->get_property = clutter_actor_get_property;
5269   object_class->dispose = clutter_actor_dispose;
5270   object_class->finalize = clutter_actor_finalize;
5271
5272   klass->show = clutter_actor_real_show;
5273   klass->show_all = clutter_actor_show;
5274   klass->hide = clutter_actor_real_hide;
5275   klass->hide_all = clutter_actor_hide;
5276   klass->map = clutter_actor_real_map;
5277   klass->unmap = clutter_actor_real_unmap;
5278   klass->unrealize = clutter_actor_real_unrealize;
5279   klass->pick = clutter_actor_real_pick;
5280   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5281   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5282   klass->allocate = clutter_actor_real_allocate;
5283   klass->queue_redraw = clutter_actor_real_queue_redraw;
5284   klass->queue_relayout = clutter_actor_real_queue_relayout;
5285   klass->apply_transform = clutter_actor_real_apply_transform;
5286   klass->get_accessible = clutter_actor_real_get_accessible;
5287   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5288   klass->has_overlaps = clutter_actor_real_has_overlaps;
5289   klass->paint = clutter_actor_real_paint;
5290   klass->destroy = clutter_actor_real_destroy;
5291
5292   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5293
5294   /**
5295    * ClutterActor:x:
5296    *
5297    * X coordinate of the actor in pixels. If written, forces a fixed
5298    * position for the actor. If read, returns the fixed position if any,
5299    * otherwise the allocation if available, otherwise 0.
5300    *
5301    * The #ClutterActor:x property is animatable.
5302    */
5303   obj_props[PROP_X] =
5304     g_param_spec_float ("x",
5305                         P_("X coordinate"),
5306                         P_("X coordinate of the actor"),
5307                         -G_MAXFLOAT, G_MAXFLOAT,
5308                         0.0,
5309                         G_PARAM_READWRITE |
5310                         G_PARAM_STATIC_STRINGS |
5311                         CLUTTER_PARAM_ANIMATABLE);
5312
5313   /**
5314    * ClutterActor:y:
5315    *
5316    * Y coordinate of the actor in pixels. If written, forces a fixed
5317    * position for the actor.  If read, returns the fixed position if
5318    * any, otherwise the allocation if available, otherwise 0.
5319    *
5320    * The #ClutterActor:y property is animatable.
5321    */
5322   obj_props[PROP_Y] =
5323     g_param_spec_float ("y",
5324                         P_("Y coordinate"),
5325                         P_("Y coordinate of the actor"),
5326                         -G_MAXFLOAT, G_MAXFLOAT,
5327                         0.0,
5328                         G_PARAM_READWRITE |
5329                         G_PARAM_STATIC_STRINGS |
5330                         CLUTTER_PARAM_ANIMATABLE);
5331
5332   /**
5333    * ClutterActor:width:
5334    *
5335    * Width of the actor (in pixels). If written, forces the minimum and
5336    * natural size request of the actor to the given width. If read, returns
5337    * the allocated width if available, otherwise the width request.
5338    *
5339    * The #ClutterActor:width property is animatable.
5340    */
5341   obj_props[PROP_WIDTH] =
5342     g_param_spec_float ("width",
5343                         P_("Width"),
5344                         P_("Width of the actor"),
5345                         0.0, G_MAXFLOAT,
5346                         0.0,
5347                         G_PARAM_READWRITE |
5348                         G_PARAM_STATIC_STRINGS |
5349                         CLUTTER_PARAM_ANIMATABLE);
5350
5351   /**
5352    * ClutterActor:height:
5353    *
5354    * Height of the actor (in pixels).  If written, forces the minimum and
5355    * natural size request of the actor to the given height. If read, returns
5356    * the allocated height if available, otherwise the height request.
5357    *
5358    * The #ClutterActor:height property is animatable.
5359    */
5360   obj_props[PROP_HEIGHT] =
5361     g_param_spec_float ("height",
5362                         P_("Height"),
5363                         P_("Height of the actor"),
5364                         0.0, G_MAXFLOAT,
5365                         0.0,
5366                         G_PARAM_READWRITE |
5367                         G_PARAM_STATIC_STRINGS |
5368                         CLUTTER_PARAM_ANIMATABLE);
5369
5370   /**
5371    * ClutterActor:fixed-x:
5372    *
5373    * The fixed X position of the actor in pixels.
5374    *
5375    * Writing this property sets #ClutterActor:fixed-position-set
5376    * property as well, as a side effect
5377    *
5378    * Since: 0.8
5379    */
5380   obj_props[PROP_FIXED_X] =
5381     g_param_spec_float ("fixed-x",
5382                         P_("Fixed X"),
5383                         P_("Forced X position of the actor"),
5384                         -G_MAXFLOAT, G_MAXFLOAT,
5385                         0.0,
5386                         CLUTTER_PARAM_READWRITE);
5387
5388   /**
5389    * ClutterActor:fixed-y:
5390    *
5391    * The fixed Y position of the actor in pixels.
5392    *
5393    * Writing this property sets the #ClutterActor:fixed-position-set
5394    * property as well, as a side effect
5395    *
5396    * Since: 0.8
5397    */
5398   obj_props[PROP_FIXED_Y] =
5399     g_param_spec_float ("fixed-y",
5400                         P_("Fixed Y"),
5401                         P_("Forced Y position of the actor"),
5402                         -G_MAXFLOAT, G_MAXFLOAT,
5403                         0,
5404                         CLUTTER_PARAM_READWRITE);
5405
5406   /**
5407    * ClutterActor:fixed-position-set:
5408    *
5409    * This flag controls whether the #ClutterActor:fixed-x and
5410    * #ClutterActor:fixed-y properties are used
5411    *
5412    * Since: 0.8
5413    */
5414   obj_props[PROP_FIXED_POSITION_SET] =
5415     g_param_spec_boolean ("fixed-position-set",
5416                           P_("Fixed position set"),
5417                           P_("Whether to use fixed positioning for the actor"),
5418                           FALSE,
5419                           CLUTTER_PARAM_READWRITE);
5420
5421   /**
5422    * ClutterActor:min-width:
5423    *
5424    * A forced minimum width request for the actor, in pixels
5425    *
5426    * Writing this property sets the #ClutterActor:min-width-set property
5427    * as well, as a side effect.
5428    *
5429    *This property overrides the usual width request of the actor.
5430    *
5431    * Since: 0.8
5432    */
5433   obj_props[PROP_MIN_WIDTH] =
5434     g_param_spec_float ("min-width",
5435                         P_("Min Width"),
5436                         P_("Forced minimum width request for the actor"),
5437                         0.0, G_MAXFLOAT,
5438                         0.0,
5439                         CLUTTER_PARAM_READWRITE);
5440
5441   /**
5442    * ClutterActor:min-height:
5443    *
5444    * A forced minimum height request for the actor, in pixels
5445    *
5446    * Writing this property sets the #ClutterActor:min-height-set property
5447    * as well, as a side effect. This property overrides the usual height
5448    * request of the actor.
5449    *
5450    * Since: 0.8
5451    */
5452   obj_props[PROP_MIN_HEIGHT] =
5453     g_param_spec_float ("min-height",
5454                         P_("Min Height"),
5455                         P_("Forced minimum height request for the actor"),
5456                         0.0, G_MAXFLOAT,
5457                         0.0,
5458                         CLUTTER_PARAM_READWRITE);
5459
5460   /**
5461    * ClutterActor:natural-width:
5462    *
5463    * A forced natural width request for the actor, in pixels
5464    *
5465    * Writing this property sets the #ClutterActor:natural-width-set
5466    * property as well, as a side effect. This property overrides the
5467    * usual width request of the actor
5468    *
5469    * Since: 0.8
5470    */
5471   obj_props[PROP_NATURAL_WIDTH] =
5472     g_param_spec_float ("natural-width",
5473                         P_("Natural Width"),
5474                         P_("Forced natural width request for the actor"),
5475                         0.0, G_MAXFLOAT,
5476                         0.0,
5477                         CLUTTER_PARAM_READWRITE);
5478
5479   /**
5480    * ClutterActor:natural-height:
5481    *
5482    * A forced natural height request for the actor, in pixels
5483    *
5484    * Writing this property sets the #ClutterActor:natural-height-set
5485    * property as well, as a side effect. This property overrides the
5486    * usual height request of the actor
5487    *
5488    * Since: 0.8
5489    */
5490   obj_props[PROP_NATURAL_HEIGHT] =
5491     g_param_spec_float ("natural-height",
5492                         P_("Natural Height"),
5493                         P_("Forced natural height request for the actor"),
5494                         0.0, G_MAXFLOAT,
5495                         0.0,
5496                         CLUTTER_PARAM_READWRITE);
5497
5498   /**
5499    * ClutterActor:min-width-set:
5500    *
5501    * This flag controls whether the #ClutterActor:min-width property
5502    * is used
5503    *
5504    * Since: 0.8
5505    */
5506   obj_props[PROP_MIN_WIDTH_SET] =
5507     g_param_spec_boolean ("min-width-set",
5508                           P_("Minimum width set"),
5509                           P_("Whether to use the min-width property"),
5510                           FALSE,
5511                           CLUTTER_PARAM_READWRITE);
5512
5513   /**
5514    * ClutterActor:min-height-set:
5515    *
5516    * This flag controls whether the #ClutterActor:min-height property
5517    * is used
5518    *
5519    * Since: 0.8
5520    */
5521   obj_props[PROP_MIN_HEIGHT_SET] =
5522     g_param_spec_boolean ("min-height-set",
5523                           P_("Minimum height set"),
5524                           P_("Whether to use the min-height property"),
5525                           FALSE,
5526                           CLUTTER_PARAM_READWRITE);
5527
5528   /**
5529    * ClutterActor:natural-width-set:
5530    *
5531    * This flag controls whether the #ClutterActor:natural-width property
5532    * is used
5533    *
5534    * Since: 0.8
5535    */
5536   obj_props[PROP_NATURAL_WIDTH_SET] =
5537     g_param_spec_boolean ("natural-width-set",
5538                           P_("Natural width set"),
5539                           P_("Whether to use the natural-width property"),
5540                           FALSE,
5541                           CLUTTER_PARAM_READWRITE);
5542
5543   /**
5544    * ClutterActor:natural-height-set:
5545    *
5546    * This flag controls whether the #ClutterActor:natural-height property
5547    * is used
5548    *
5549    * Since: 0.8
5550    */
5551   obj_props[PROP_NATURAL_HEIGHT_SET] =
5552     g_param_spec_boolean ("natural-height-set",
5553                           P_("Natural height set"),
5554                           P_("Whether to use the natural-height property"),
5555                           FALSE,
5556                           CLUTTER_PARAM_READWRITE);
5557
5558   /**
5559    * ClutterActor:allocation:
5560    *
5561    * The allocation for the actor, in pixels
5562    *
5563    * This is property is read-only, but you might monitor it to know when an
5564    * actor moves or resizes
5565    *
5566    * Since: 0.8
5567    */
5568   obj_props[PROP_ALLOCATION] =
5569     g_param_spec_boxed ("allocation",
5570                         P_("Allocation"),
5571                         P_("The actor's allocation"),
5572                         CLUTTER_TYPE_ACTOR_BOX,
5573                         CLUTTER_PARAM_READABLE);
5574
5575   /**
5576    * ClutterActor:request-mode:
5577    *
5578    * Request mode for the #ClutterActor. The request mode determines the
5579    * type of geometry management used by the actor, either height for width
5580    * (the default) or width for height.
5581    *
5582    * For actors implementing height for width, the parent container should get
5583    * the preferred width first, and then the preferred height for that width.
5584    *
5585    * For actors implementing width for height, the parent container should get
5586    * the preferred height first, and then the preferred width for that height.
5587    *
5588    * For instance:
5589    *
5590    * |[
5591    *   ClutterRequestMode mode;
5592    *   gfloat natural_width, min_width;
5593    *   gfloat natural_height, min_height;
5594    *
5595    *   mode = clutter_actor_get_request_mode (child);
5596    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5597    *     {
5598    *       clutter_actor_get_preferred_width (child, -1,
5599    *                                          &amp;min_width,
5600    *                                          &amp;natural_width);
5601    *       clutter_actor_get_preferred_height (child, natural_width,
5602    *                                           &amp;min_height,
5603    *                                           &amp;natural_height);
5604    *     }
5605    *   else
5606    *     {
5607    *       clutter_actor_get_preferred_height (child, -1,
5608    *                                           &amp;min_height,
5609    *                                           &amp;natural_height);
5610    *       clutter_actor_get_preferred_width (child, natural_height,
5611    *                                          &amp;min_width,
5612    *                                          &amp;natural_width);
5613    *     }
5614    * ]|
5615    *
5616    * will retrieve the minimum and natural width and height depending on the
5617    * preferred request mode of the #ClutterActor "child".
5618    *
5619    * The clutter_actor_get_preferred_size() function will implement this
5620    * check for you.
5621    *
5622    * Since: 0.8
5623    */
5624   obj_props[PROP_REQUEST_MODE] =
5625     g_param_spec_enum ("request-mode",
5626                        P_("Request Mode"),
5627                        P_("The actor's request mode"),
5628                        CLUTTER_TYPE_REQUEST_MODE,
5629                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5630                        CLUTTER_PARAM_READWRITE);
5631
5632   /**
5633    * ClutterActor:depth:
5634    *
5635    * The position of the actor on the Z axis.
5636    *
5637    * The #ClutterActor:depth property is relative to the parent's
5638    * modelview matrix.
5639    *
5640    * The #ClutterActor:depth property is animatable.
5641    *
5642    * Since: 0.6
5643    */
5644   obj_props[PROP_DEPTH] =
5645     g_param_spec_float ("depth",
5646                         P_("Depth"),
5647                         P_("Position on the Z axis"),
5648                         -G_MAXFLOAT, G_MAXFLOAT,
5649                         0.0,
5650                         G_PARAM_READWRITE |
5651                         G_PARAM_STATIC_STRINGS |
5652                         CLUTTER_PARAM_ANIMATABLE);
5653
5654   /**
5655    * ClutterActor:opacity:
5656    *
5657    * Opacity of an actor, between 0 (fully transparent) and
5658    * 255 (fully opaque)
5659    *
5660    * The #ClutterActor:opacity property is animatable.
5661    */
5662   obj_props[PROP_OPACITY] =
5663     g_param_spec_uint ("opacity",
5664                        P_("Opacity"),
5665                        P_("Opacity of an actor"),
5666                        0, 255,
5667                        255,
5668                        G_PARAM_READWRITE |
5669                        G_PARAM_STATIC_STRINGS |
5670                        CLUTTER_PARAM_ANIMATABLE);
5671
5672   /**
5673    * ClutterActor:offscreen-redirect:
5674    *
5675    * Determines the conditions in which the actor will be redirected
5676    * to an offscreen framebuffer while being painted. For example this
5677    * can be used to cache an actor in a framebuffer or for improved
5678    * handling of transparent actors. See
5679    * clutter_actor_set_offscreen_redirect() for details.
5680    *
5681    * Since: 1.8
5682    */
5683   obj_props[PROP_OFFSCREEN_REDIRECT] =
5684     g_param_spec_flags ("offscreen-redirect",
5685                         P_("Offscreen redirect"),
5686                         P_("Flags controlling when to flatten the actor into a single image"),
5687                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5688                         0,
5689                         CLUTTER_PARAM_READWRITE);
5690
5691   /**
5692    * ClutterActor:visible:
5693    *
5694    * Whether the actor is set to be visible or not
5695    *
5696    * See also #ClutterActor:mapped
5697    */
5698   obj_props[PROP_VISIBLE] =
5699     g_param_spec_boolean ("visible",
5700                           P_("Visible"),
5701                           P_("Whether the actor is visible or not"),
5702                           FALSE,
5703                           CLUTTER_PARAM_READWRITE);
5704
5705   /**
5706    * ClutterActor:mapped:
5707    *
5708    * Whether the actor is mapped (will be painted when the stage
5709    * to which it belongs is mapped)
5710    *
5711    * Since: 1.0
5712    */
5713   obj_props[PROP_MAPPED] =
5714     g_param_spec_boolean ("mapped",
5715                           P_("Mapped"),
5716                           P_("Whether the actor will be painted"),
5717                           FALSE,
5718                           CLUTTER_PARAM_READABLE);
5719
5720   /**
5721    * ClutterActor:realized:
5722    *
5723    * Whether the actor has been realized
5724    *
5725    * Since: 1.0
5726    */
5727   obj_props[PROP_REALIZED] =
5728     g_param_spec_boolean ("realized",
5729                           P_("Realized"),
5730                           P_("Whether the actor has been realized"),
5731                           FALSE,
5732                           CLUTTER_PARAM_READABLE);
5733
5734   /**
5735    * ClutterActor:reactive:
5736    *
5737    * Whether the actor is reactive to events or not
5738    *
5739    * Only reactive actors will emit event-related signals
5740    *
5741    * Since: 0.6
5742    */
5743   obj_props[PROP_REACTIVE] =
5744     g_param_spec_boolean ("reactive",
5745                           P_("Reactive"),
5746                           P_("Whether the actor is reactive to events"),
5747                           FALSE,
5748                           CLUTTER_PARAM_READWRITE);
5749
5750   /**
5751    * ClutterActor:has-clip:
5752    *
5753    * Whether the actor has the #ClutterActor:clip property set or not
5754    */
5755   obj_props[PROP_HAS_CLIP] =
5756     g_param_spec_boolean ("has-clip",
5757                           P_("Has Clip"),
5758                           P_("Whether the actor has a clip set"),
5759                           FALSE,
5760                           CLUTTER_PARAM_READABLE);
5761
5762   /**
5763    * ClutterActor:clip:
5764    *
5765    * The clip region for the actor, in actor-relative coordinates
5766    *
5767    * Every part of the actor outside the clip region will not be
5768    * painted
5769    */
5770   obj_props[PROP_CLIP] =
5771     g_param_spec_boxed ("clip",
5772                         P_("Clip"),
5773                         P_("The clip region for the actor"),
5774                         CLUTTER_TYPE_GEOMETRY,
5775                         CLUTTER_PARAM_READWRITE);
5776
5777   /**
5778    * ClutterActor:name:
5779    *
5780    * The name of the actor
5781    *
5782    * Since: 0.2
5783    */
5784   obj_props[PROP_NAME] =
5785     g_param_spec_string ("name",
5786                          P_("Name"),
5787                          P_("Name of the actor"),
5788                          NULL,
5789                          CLUTTER_PARAM_READWRITE);
5790
5791   /**
5792    * ClutterActor:scale-x:
5793    *
5794    * The horizontal scale of the actor.
5795    *
5796    * The #ClutterActor:scale-x property is animatable.
5797    *
5798    * Since: 0.6
5799    */
5800   obj_props[PROP_SCALE_X] =
5801     g_param_spec_double ("scale-x",
5802                          P_("Scale X"),
5803                          P_("Scale factor on the X axis"),
5804                          0.0, G_MAXDOUBLE,
5805                          1.0,
5806                          G_PARAM_READWRITE |
5807                          G_PARAM_STATIC_STRINGS |
5808                          CLUTTER_PARAM_ANIMATABLE);
5809
5810   /**
5811    * ClutterActor:scale-y:
5812    *
5813    * The vertical scale of the actor.
5814    *
5815    * The #ClutterActor:scale-y property is animatable.
5816    *
5817    * Since: 0.6
5818    */
5819   obj_props[PROP_SCALE_Y] =
5820     g_param_spec_double ("scale-y",
5821                          P_("Scale Y"),
5822                          P_("Scale factor on the Y axis"),
5823                          0.0, G_MAXDOUBLE,
5824                          1.0,
5825                          G_PARAM_READWRITE |
5826                          G_PARAM_STATIC_STRINGS |
5827                          CLUTTER_PARAM_ANIMATABLE);
5828
5829   /**
5830    * ClutterActor:scale-center-x:
5831    *
5832    * The horizontal center point for scaling
5833    *
5834    * Since: 1.0
5835    */
5836   obj_props[PROP_SCALE_CENTER_X] =
5837     g_param_spec_float ("scale-center-x",
5838                         P_("Scale Center X"),
5839                         P_("Horizontal scale center"),
5840                         -G_MAXFLOAT, G_MAXFLOAT,
5841                         0.0,
5842                         CLUTTER_PARAM_READWRITE);
5843
5844   /**
5845    * ClutterActor:scale-center-y:
5846    *
5847    * The vertical center point for scaling
5848    *
5849    * Since: 1.0
5850    */
5851   obj_props[PROP_SCALE_CENTER_Y] =
5852     g_param_spec_float ("scale-center-y",
5853                         P_("Scale Center Y"),
5854                         P_("Vertical scale center"),
5855                         -G_MAXFLOAT, G_MAXFLOAT,
5856                         0.0,
5857                         CLUTTER_PARAM_READWRITE);
5858
5859   /**
5860    * ClutterActor:scale-gravity:
5861    *
5862    * The center point for scaling expressed as a #ClutterGravity
5863    *
5864    * Since: 1.0
5865    */
5866   obj_props[PROP_SCALE_GRAVITY] =
5867     g_param_spec_enum ("scale-gravity",
5868                        P_("Scale Gravity"),
5869                        P_("The center of scaling"),
5870                        CLUTTER_TYPE_GRAVITY,
5871                        CLUTTER_GRAVITY_NONE,
5872                        CLUTTER_PARAM_READWRITE);
5873
5874   /**
5875    * ClutterActor:rotation-angle-x:
5876    *
5877    * The rotation angle on the X axis.
5878    *
5879    * The #ClutterActor:rotation-angle-x property is animatable.
5880    *
5881    * Since: 0.6
5882    */
5883   obj_props[PROP_ROTATION_ANGLE_X] =
5884     g_param_spec_double ("rotation-angle-x",
5885                          P_("Rotation Angle X"),
5886                          P_("The rotation angle on the X axis"),
5887                          -G_MAXDOUBLE, G_MAXDOUBLE,
5888                          0.0,
5889                          G_PARAM_READWRITE |
5890                          G_PARAM_STATIC_STRINGS |
5891                          CLUTTER_PARAM_ANIMATABLE);
5892
5893   /**
5894    * ClutterActor:rotation-angle-y:
5895    *
5896    * The rotation angle on the Y axis
5897    *
5898    * The #ClutterActor:rotation-angle-y property is animatable.
5899    *
5900    * Since: 0.6
5901    */
5902   obj_props[PROP_ROTATION_ANGLE_Y] =
5903     g_param_spec_double ("rotation-angle-y",
5904                          P_("Rotation Angle Y"),
5905                          P_("The rotation angle on the Y axis"),
5906                          -G_MAXDOUBLE, G_MAXDOUBLE,
5907                          0.0,
5908                          G_PARAM_READWRITE |
5909                          G_PARAM_STATIC_STRINGS |
5910                          CLUTTER_PARAM_ANIMATABLE);
5911
5912   /**
5913    * ClutterActor:rotation-angle-z:
5914    *
5915    * The rotation angle on the Z axis
5916    *
5917    * The #ClutterActor:rotation-angle-z property is animatable.
5918    *
5919    * Since: 0.6
5920    */
5921   obj_props[PROP_ROTATION_ANGLE_Z] =
5922     g_param_spec_double ("rotation-angle-z",
5923                          P_("Rotation Angle Z"),
5924                          P_("The rotation angle on the Z axis"),
5925                          -G_MAXDOUBLE, G_MAXDOUBLE,
5926                          0.0,
5927                          G_PARAM_READWRITE |
5928                          G_PARAM_STATIC_STRINGS |
5929                          CLUTTER_PARAM_ANIMATABLE);
5930
5931   /**
5932    * ClutterActor:rotation-center-x:
5933    *
5934    * The rotation center on the X axis.
5935    *
5936    * Since: 0.6
5937    */
5938   obj_props[PROP_ROTATION_CENTER_X] =
5939     g_param_spec_boxed ("rotation-center-x",
5940                         P_("Rotation Center X"),
5941                         P_("The rotation center on the X axis"),
5942                         CLUTTER_TYPE_VERTEX,
5943                         CLUTTER_PARAM_READWRITE);
5944
5945   /**
5946    * ClutterActor:rotation-center-y:
5947    *
5948    * The rotation center on the Y axis.
5949    *
5950    * Since: 0.6
5951    */
5952   obj_props[PROP_ROTATION_CENTER_Y] =
5953     g_param_spec_boxed ("rotation-center-y",
5954                         P_("Rotation Center Y"),
5955                         P_("The rotation center on the Y axis"),
5956                         CLUTTER_TYPE_VERTEX,
5957                         CLUTTER_PARAM_READWRITE);
5958
5959   /**
5960    * ClutterActor:rotation-center-z:
5961    *
5962    * The rotation center on the Z axis.
5963    *
5964    * Since: 0.6
5965    */
5966   obj_props[PROP_ROTATION_CENTER_Z] =
5967     g_param_spec_boxed ("rotation-center-z",
5968                         P_("Rotation Center Z"),
5969                         P_("The rotation center on the Z axis"),
5970                         CLUTTER_TYPE_VERTEX,
5971                         CLUTTER_PARAM_READWRITE);
5972
5973   /**
5974    * ClutterActor:rotation-center-z-gravity:
5975    *
5976    * The rotation center on the Z axis expressed as a #ClutterGravity.
5977    *
5978    * Since: 1.0
5979    */
5980   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5981     g_param_spec_enum ("rotation-center-z-gravity",
5982                        P_("Rotation Center Z Gravity"),
5983                        P_("Center point for rotation around the Z axis"),
5984                        CLUTTER_TYPE_GRAVITY,
5985                        CLUTTER_GRAVITY_NONE,
5986                        CLUTTER_PARAM_READWRITE);
5987
5988   /**
5989    * ClutterActor:anchor-x:
5990    *
5991    * The X coordinate of an actor's anchor point, relative to
5992    * the actor coordinate space, in pixels
5993    *
5994    * Since: 0.8
5995    */
5996   obj_props[PROP_ANCHOR_X] =
5997     g_param_spec_float ("anchor-x",
5998                         P_("Anchor X"),
5999                         P_("X coordinate of the anchor point"),
6000                         -G_MAXFLOAT, G_MAXFLOAT,
6001                         0,
6002                         CLUTTER_PARAM_READWRITE);
6003
6004   /**
6005    * ClutterActor:anchor-y:
6006    *
6007    * The Y coordinate of an actor's anchor point, relative to
6008    * the actor coordinate space, in pixels
6009    *
6010    * Since: 0.8
6011    */
6012   obj_props[PROP_ANCHOR_Y] =
6013     g_param_spec_float ("anchor-y",
6014                         P_("Anchor Y"),
6015                         P_("Y coordinate of the anchor point"),
6016                         -G_MAXFLOAT, G_MAXFLOAT,
6017                         0,
6018                         CLUTTER_PARAM_READWRITE);
6019
6020   /**
6021    * ClutterActor:anchor-gravity:
6022    *
6023    * The anchor point expressed as a #ClutterGravity
6024    *
6025    * Since: 1.0
6026    */
6027   obj_props[PROP_ANCHOR_GRAVITY] =
6028     g_param_spec_enum ("anchor-gravity",
6029                        P_("Anchor Gravity"),
6030                        P_("The anchor point as a ClutterGravity"),
6031                        CLUTTER_TYPE_GRAVITY,
6032                        CLUTTER_GRAVITY_NONE,
6033                        CLUTTER_PARAM_READWRITE);
6034
6035   /**
6036    * ClutterActor:show-on-set-parent:
6037    *
6038    * If %TRUE, the actor is automatically shown when parented.
6039    *
6040    * Calling clutter_actor_hide() on an actor which has not been
6041    * parented will set this property to %FALSE as a side effect.
6042    *
6043    * Since: 0.8
6044    */
6045   obj_props[PROP_SHOW_ON_SET_PARENT] =
6046     g_param_spec_boolean ("show-on-set-parent",
6047                           P_("Show on set parent"),
6048                           P_("Whether the actor is shown when parented"),
6049                           TRUE,
6050                           CLUTTER_PARAM_READWRITE);
6051
6052   /**
6053    * ClutterActor:clip-to-allocation:
6054    *
6055    * Whether the clip region should track the allocated area
6056    * of the actor.
6057    *
6058    * This property is ignored if a clip area has been explicitly
6059    * set using clutter_actor_set_clip().
6060    *
6061    * Since: 1.0
6062    */
6063   obj_props[PROP_CLIP_TO_ALLOCATION] =
6064     g_param_spec_boolean ("clip-to-allocation",
6065                           P_("Clip to Allocation"),
6066                           P_("Sets the clip region to track the actor's allocation"),
6067                           FALSE,
6068                           CLUTTER_PARAM_READWRITE);
6069
6070   /**
6071    * ClutterActor:text-direction:
6072    *
6073    * The direction of the text inside a #ClutterActor.
6074    *
6075    * Since: 1.0
6076    */
6077   obj_props[PROP_TEXT_DIRECTION] =
6078     g_param_spec_enum ("text-direction",
6079                        P_("Text Direction"),
6080                        P_("Direction of the text"),
6081                        CLUTTER_TYPE_TEXT_DIRECTION,
6082                        CLUTTER_TEXT_DIRECTION_LTR,
6083                        CLUTTER_PARAM_READWRITE);
6084
6085   /**
6086    * ClutterActor:has-pointer:
6087    *
6088    * Whether the actor contains the pointer of a #ClutterInputDevice
6089    * or not.
6090    *
6091    * Since: 1.2
6092    */
6093   obj_props[PROP_HAS_POINTER] =
6094     g_param_spec_boolean ("has-pointer",
6095                           P_("Has Pointer"),
6096                           P_("Whether the actor contains the pointer of an input device"),
6097                           FALSE,
6098                           CLUTTER_PARAM_READABLE);
6099
6100   /**
6101    * ClutterActor:actions:
6102    *
6103    * Adds a #ClutterAction to the actor
6104    *
6105    * Since: 1.4
6106    */
6107   obj_props[PROP_ACTIONS] =
6108     g_param_spec_object ("actions",
6109                          P_("Actions"),
6110                          P_("Adds an action to the actor"),
6111                          CLUTTER_TYPE_ACTION,
6112                          CLUTTER_PARAM_WRITABLE);
6113
6114   /**
6115    * ClutterActor:constraints:
6116    *
6117    * Adds a #ClutterConstraint to the actor
6118    *
6119    * Since: 1.4
6120    */
6121   obj_props[PROP_CONSTRAINTS] =
6122     g_param_spec_object ("constraints",
6123                          P_("Constraints"),
6124                          P_("Adds a constraint to the actor"),
6125                          CLUTTER_TYPE_CONSTRAINT,
6126                          CLUTTER_PARAM_WRITABLE);
6127
6128   /**
6129    * ClutterActor:effect:
6130    *
6131    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6132    *
6133    * Since: 1.4
6134    */
6135   obj_props[PROP_EFFECT] =
6136     g_param_spec_object ("effect",
6137                          P_("Effect"),
6138                          P_("Add an effect to be applied on the actor"),
6139                          CLUTTER_TYPE_EFFECT,
6140                          CLUTTER_PARAM_WRITABLE);
6141
6142   /**
6143    * ClutterActor:layout-manager:
6144    *
6145    * A delegate object for controlling the layout of the children of
6146    * an actor.
6147    *
6148    * Since: 1.10
6149    */
6150   obj_props[PROP_LAYOUT_MANAGER] =
6151     g_param_spec_object ("layout-manager",
6152                          P_("Layout Manager"),
6153                          P_("The object controlling the layout of an actor's children"),
6154                          CLUTTER_TYPE_LAYOUT_MANAGER,
6155                          CLUTTER_PARAM_READWRITE);
6156
6157
6158   /**
6159    * ClutterActor:x-align:
6160    *
6161    * The alignment of an actor on the X axis, if the actor has been given
6162    * extra space for its allocation.
6163    *
6164    * Since: 1.10
6165    */
6166   obj_props[PROP_X_ALIGN] =
6167     g_param_spec_enum ("x-align",
6168                        P_("X Alignment"),
6169                        P_("The alignment of the actor on the X axis within its allocation"),
6170                        CLUTTER_TYPE_ACTOR_ALIGN,
6171                        CLUTTER_ACTOR_ALIGN_FILL,
6172                        CLUTTER_PARAM_READWRITE);
6173
6174   /**
6175    * ClutterActor:y-align:
6176    *
6177    * The alignment of an actor on the Y axis, if the actor has been given
6178    * extra space for its allocation.
6179    *
6180    * Since: 1.10
6181    */
6182   obj_props[PROP_Y_ALIGN] =
6183     g_param_spec_enum ("y-align",
6184                        P_("Y Alignment"),
6185                        P_("The alignment of the actor on the Y axis within its allocation"),
6186                        CLUTTER_TYPE_ACTOR_ALIGN,
6187                        CLUTTER_ACTOR_ALIGN_FILL,
6188                        CLUTTER_PARAM_READWRITE);
6189
6190   /**
6191    * ClutterActor:margin-top:
6192    *
6193    * The margin (in pixels) from the top of the actor.
6194    *
6195    * This property adds a margin to the actor's preferred size; the margin
6196    * will be automatically taken into account when allocating the actor.
6197    *
6198    * Since: 1.10
6199    */
6200   obj_props[PROP_MARGIN_TOP] =
6201     g_param_spec_float ("margin-top",
6202                         P_("Margin Top"),
6203                         P_("Extra space at the top"),
6204                         0.0, G_MAXFLOAT,
6205                         0.0,
6206                         CLUTTER_PARAM_READWRITE);
6207
6208   /**
6209    * ClutterActor:margin-bottom:
6210    *
6211    * The margin (in pixels) from the bottom of the actor.
6212    *
6213    * This property adds a margin to the actor's preferred size; the margin
6214    * will be automatically taken into account when allocating the actor.
6215    *
6216    * Since: 1.10
6217    */
6218   obj_props[PROP_MARGIN_BOTTOM] =
6219     g_param_spec_float ("margin-bottom",
6220                         P_("Margin Bottom"),
6221                         P_("Extra space at the bottom"),
6222                         0.0, G_MAXFLOAT,
6223                         0.0,
6224                         CLUTTER_PARAM_READWRITE);
6225
6226   /**
6227    * ClutterActor:margin-left:
6228    *
6229    * The margin (in pixels) from the left of the actor.
6230    *
6231    * This property adds a margin to the actor's preferred size; the margin
6232    * will be automatically taken into account when allocating the actor.
6233    *
6234    * Since: 1.10
6235    */
6236   obj_props[PROP_MARGIN_LEFT] =
6237     g_param_spec_float ("margin-left",
6238                         P_("Margin Left"),
6239                         P_("Extra space at the left"),
6240                         0.0, G_MAXFLOAT,
6241                         0.0,
6242                         CLUTTER_PARAM_READWRITE);
6243
6244   /**
6245    * ClutterActor:margin-right:
6246    *
6247    * The margin (in pixels) from the right of the actor.
6248    *
6249    * This property adds a margin to the actor's preferred size; the margin
6250    * will be automatically taken into account when allocating the actor.
6251    *
6252    * Since: 1.10
6253    */
6254   obj_props[PROP_MARGIN_RIGHT] =
6255     g_param_spec_float ("margin-right",
6256                         P_("Margin Right"),
6257                         P_("Extra space at the right"),
6258                         0.0, G_MAXFLOAT,
6259                         0.0,
6260                         CLUTTER_PARAM_READWRITE);
6261
6262   /**
6263    * ClutterActor:background-color-set:
6264    *
6265    * Whether the #ClutterActor:background-color property has been set.
6266    *
6267    * Since: 1.10
6268    */
6269   obj_props[PROP_BACKGROUND_COLOR_SET] =
6270     g_param_spec_boolean ("background-color-set",
6271                           P_("Background Color Set"),
6272                           P_("Whether the background color is set"),
6273                           FALSE,
6274                           CLUTTER_PARAM_READABLE);
6275
6276   /**
6277    * ClutterActor:background-color:
6278    *
6279    * Paints a solid fill of the actor's allocation using the specified
6280    * color.
6281    *
6282    * The #ClutterActor:background-color property is animatable.
6283    *
6284    * Since: 1.10
6285    */
6286   obj_props[PROP_BACKGROUND_COLOR] =
6287     clutter_param_spec_color ("background-color",
6288                               P_("Background color"),
6289                               P_("The actor's background color"),
6290                               CLUTTER_COLOR_Transparent,
6291                               G_PARAM_READWRITE |
6292                               G_PARAM_STATIC_STRINGS |
6293                               CLUTTER_PARAM_ANIMATABLE);
6294
6295   /**
6296    * ClutterActor:first-child:
6297    *
6298    * The actor's first child.
6299    *
6300    * Since: 1.10
6301    */
6302   obj_props[PROP_FIRST_CHILD] =
6303     g_param_spec_object ("first-child",
6304                          P_("First Child"),
6305                          P_("The actor's first child"),
6306                          CLUTTER_TYPE_ACTOR,
6307                          CLUTTER_PARAM_READABLE);
6308
6309   /**
6310    * ClutterActor:last-child:
6311    *
6312    * The actor's last child.
6313    *
6314    * Since: 1.10
6315    */
6316   obj_props[PROP_LAST_CHILD] =
6317     g_param_spec_object ("last-child",
6318                          P_("Last Child"),
6319                          P_("The actor's last child"),
6320                          CLUTTER_TYPE_ACTOR,
6321                          CLUTTER_PARAM_READABLE);
6322
6323   /**
6324    * ClutterActor:content:
6325    *
6326    * The #ClutterContent implementation that controls the content
6327    * of the actor.
6328    *
6329    * Since: 1.10
6330    */
6331   obj_props[PROP_CONTENT] =
6332     g_param_spec_object ("content",
6333                          P_("Content"),
6334                          P_("Delegate object for painting the actor's content"),
6335                          CLUTTER_TYPE_CONTENT,
6336                          CLUTTER_PARAM_READWRITE);
6337
6338   /**
6339    * ClutterActor:content-gravity:
6340    *
6341    * The alignment that should be honoured by the #ClutterContent
6342    * set with the #ClutterActor:content property.
6343    *
6344    * Changing the value of this property will change the bounding box of
6345    * the content; you can use the #ClutterActor:content-box property to
6346    * get the position and size of the content within the actor's
6347    * allocation.
6348    *
6349    * This property is meaningful only for #ClutterContent implementations
6350    * that have a preferred size, and if the preferred size is smaller than
6351    * the actor's allocation.
6352    *
6353    * Since: 1.10
6354    */
6355   obj_props[PROP_CONTENT_GRAVITY] =
6356     g_param_spec_enum ("content-gravity",
6357                        P_("Content Gravity"),
6358                        P_("Alignment of the actor's content"),
6359                        CLUTTER_TYPE_CONTENT_GRAVITY,
6360                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6361                        CLUTTER_PARAM_READWRITE);
6362
6363   /**
6364    * ClutterActor:content-box:
6365    *
6366    * The bounding box for the #ClutterContent used by the actor.
6367    *
6368    * The value of this property is controlled by the #ClutterActor:allocation
6369    * and #ClutterActor:content-gravity properties of #ClutterActor.
6370    *
6371    * The bounding box for the content is guaranteed to never exceed the
6372    * allocation's of the actor.
6373    *
6374    * Since: 1.10
6375    */
6376   obj_props[PROP_CONTENT_BOX] =
6377     g_param_spec_boxed ("content-box",
6378                         P_("Content Box"),
6379                         P_("The bounding box of the actor's content"),
6380                         CLUTTER_TYPE_ACTOR_BOX,
6381                         CLUTTER_PARAM_READABLE);
6382
6383   obj_props[PROP_MINIFICATION_FILTER] =
6384     g_param_spec_enum ("minification-filter",
6385                        P_("Minification Filter"),
6386                        P_("The filter used when reducing the size of the content"),
6387                        CLUTTER_TYPE_SCALING_FILTER,
6388                        CLUTTER_SCALING_FILTER_LINEAR,
6389                        CLUTTER_PARAM_READWRITE);
6390
6391   obj_props[PROP_MAGNIFICATION_FILTER] =
6392     g_param_spec_enum ("magnification-filter",
6393                        P_("Magnification Filter"),
6394                        P_("The filter used when increasing the size of the content"),
6395                        CLUTTER_TYPE_SCALING_FILTER,
6396                        CLUTTER_SCALING_FILTER_LINEAR,
6397                        CLUTTER_PARAM_READWRITE);
6398
6399   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6400
6401   /**
6402    * ClutterActor::destroy:
6403    * @actor: the #ClutterActor which emitted the signal
6404    *
6405    * The ::destroy signal notifies that all references held on the
6406    * actor which emitted it should be released.
6407    *
6408    * The ::destroy signal should be used by all holders of a reference
6409    * on @actor.
6410    *
6411    * This signal might result in the finalization of the #ClutterActor
6412    * if all references are released.
6413    *
6414    * Composite actors and actors implementing the #ClutterContainer
6415    * interface should override the default implementation of the
6416    * class handler of this signal and call clutter_actor_destroy() on
6417    * their children. When overriding the default class handler, it is
6418    * required to chain up to the parent's implementation.
6419    *
6420    * Since: 0.2
6421    */
6422   actor_signals[DESTROY] =
6423     g_signal_new (I_("destroy"),
6424                   G_TYPE_FROM_CLASS (object_class),
6425                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6426                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6427                   NULL, NULL,
6428                   _clutter_marshal_VOID__VOID,
6429                   G_TYPE_NONE, 0);
6430   /**
6431    * ClutterActor::show:
6432    * @actor: the object which received the signal
6433    *
6434    * The ::show signal is emitted when an actor is visible and
6435    * rendered on the stage.
6436    *
6437    * Since: 0.2
6438    */
6439   actor_signals[SHOW] =
6440     g_signal_new (I_("show"),
6441                   G_TYPE_FROM_CLASS (object_class),
6442                   G_SIGNAL_RUN_FIRST,
6443                   G_STRUCT_OFFSET (ClutterActorClass, show),
6444                   NULL, NULL,
6445                   _clutter_marshal_VOID__VOID,
6446                   G_TYPE_NONE, 0);
6447   /**
6448    * ClutterActor::hide:
6449    * @actor: the object which received the signal
6450    *
6451    * The ::hide signal is emitted when an actor is no longer rendered
6452    * on the stage.
6453    *
6454    * Since: 0.2
6455    */
6456   actor_signals[HIDE] =
6457     g_signal_new (I_("hide"),
6458                   G_TYPE_FROM_CLASS (object_class),
6459                   G_SIGNAL_RUN_FIRST,
6460                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6461                   NULL, NULL,
6462                   _clutter_marshal_VOID__VOID,
6463                   G_TYPE_NONE, 0);
6464   /**
6465    * ClutterActor::parent-set:
6466    * @actor: the object which received the signal
6467    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6468    *
6469    * This signal is emitted when the parent of the actor changes.
6470    *
6471    * Since: 0.2
6472    */
6473   actor_signals[PARENT_SET] =
6474     g_signal_new (I_("parent-set"),
6475                   G_TYPE_FROM_CLASS (object_class),
6476                   G_SIGNAL_RUN_LAST,
6477                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6478                   NULL, NULL,
6479                   _clutter_marshal_VOID__OBJECT,
6480                   G_TYPE_NONE, 1,
6481                   CLUTTER_TYPE_ACTOR);
6482
6483   /**
6484    * ClutterActor::queue-redraw:
6485    * @actor: the actor we're bubbling the redraw request through
6486    * @origin: the actor which initiated the redraw request
6487    *
6488    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6489    * is called on @origin.
6490    *
6491    * The default implementation for #ClutterActor chains up to the
6492    * parent actor and queues a redraw on the parent, thus "bubbling"
6493    * the redraw queue up through the actor graph. The default
6494    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6495    * in a main loop idle handler.
6496    *
6497    * Note that the @origin actor may be the stage, or a container; it
6498    * does not have to be a leaf node in the actor graph.
6499    *
6500    * Toolkits embedding a #ClutterStage which require a redraw and
6501    * relayout cycle can stop the emission of this signal using the
6502    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6503    * themselves, like:
6504    *
6505    * |[
6506    *   static void
6507    *   on_redraw_complete (gpointer data)
6508    *   {
6509    *     ClutterStage *stage = data;
6510    *
6511    *     /&ast; execute the Clutter drawing pipeline &ast;/
6512    *     clutter_stage_ensure_redraw (stage);
6513    *   }
6514    *
6515    *   static void
6516    *   on_stage_queue_redraw (ClutterStage *stage)
6517    *   {
6518    *     /&ast; this prevents the default handler to run &ast;/
6519    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6520    *
6521    *     /&ast; queue a redraw with the host toolkit and call
6522    *      &ast; a function when the redraw has been completed
6523    *      &ast;/
6524    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6525    *   }
6526    * ]|
6527    *
6528    * <note><para>This signal is emitted before the Clutter paint
6529    * pipeline is executed. If you want to know when the pipeline has
6530    * been completed you should connect to the ::paint signal on the
6531    * Stage with g_signal_connect_after().</para></note>
6532    *
6533    * Since: 1.0
6534    */
6535   actor_signals[QUEUE_REDRAW] =
6536     g_signal_new (I_("queue-redraw"),
6537                   G_TYPE_FROM_CLASS (object_class),
6538                   G_SIGNAL_RUN_LAST |
6539                   G_SIGNAL_NO_HOOKS,
6540                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6541                   NULL, NULL,
6542                   _clutter_marshal_VOID__OBJECT,
6543                   G_TYPE_NONE, 1,
6544                   CLUTTER_TYPE_ACTOR);
6545
6546   /**
6547    * ClutterActor::queue-relayout
6548    * @actor: the actor being queued for relayout
6549    *
6550    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6551    * is called on an actor.
6552    *
6553    * The default implementation for #ClutterActor chains up to the
6554    * parent actor and queues a relayout on the parent, thus "bubbling"
6555    * the relayout queue up through the actor graph.
6556    *
6557    * The main purpose of this signal is to allow relayout to be propagated
6558    * properly in the procense of #ClutterClone actors. Applications will
6559    * not normally need to connect to this signal.
6560    *
6561    * Since: 1.2
6562    */
6563   actor_signals[QUEUE_RELAYOUT] =
6564     g_signal_new (I_("queue-relayout"),
6565                   G_TYPE_FROM_CLASS (object_class),
6566                   G_SIGNAL_RUN_LAST |
6567                   G_SIGNAL_NO_HOOKS,
6568                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6569                   NULL, NULL,
6570                   _clutter_marshal_VOID__VOID,
6571                   G_TYPE_NONE, 0);
6572
6573   /**
6574    * ClutterActor::event:
6575    * @actor: the actor which received the event
6576    * @event: a #ClutterEvent
6577    *
6578    * The ::event signal is emitted each time an event is received
6579    * by the @actor. This signal will be emitted on every actor,
6580    * following the hierarchy chain, until it reaches the top-level
6581    * container (the #ClutterStage).
6582    *
6583    * Return value: %TRUE if the event has been handled by the actor,
6584    *   or %FALSE to continue the emission.
6585    *
6586    * Since: 0.6
6587    */
6588   actor_signals[EVENT] =
6589     g_signal_new (I_("event"),
6590                   G_TYPE_FROM_CLASS (object_class),
6591                   G_SIGNAL_RUN_LAST,
6592                   G_STRUCT_OFFSET (ClutterActorClass, event),
6593                   _clutter_boolean_handled_accumulator, NULL,
6594                   _clutter_marshal_BOOLEAN__BOXED,
6595                   G_TYPE_BOOLEAN, 1,
6596                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6597   /**
6598    * ClutterActor::button-press-event:
6599    * @actor: the actor which received the event
6600    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6601    *
6602    * The ::button-press-event signal is emitted each time a mouse button
6603    * is pressed on @actor.
6604    *
6605    * Return value: %TRUE if the event has been handled by the actor,
6606    *   or %FALSE to continue the emission.
6607    *
6608    * Since: 0.6
6609    */
6610   actor_signals[BUTTON_PRESS_EVENT] =
6611     g_signal_new (I_("button-press-event"),
6612                   G_TYPE_FROM_CLASS (object_class),
6613                   G_SIGNAL_RUN_LAST,
6614                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6615                   _clutter_boolean_handled_accumulator, NULL,
6616                   _clutter_marshal_BOOLEAN__BOXED,
6617                   G_TYPE_BOOLEAN, 1,
6618                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6619   /**
6620    * ClutterActor::button-release-event:
6621    * @actor: the actor which received the event
6622    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6623    *
6624    * The ::button-release-event signal is emitted each time a mouse button
6625    * is released on @actor.
6626    *
6627    * Return value: %TRUE if the event has been handled by the actor,
6628    *   or %FALSE to continue the emission.
6629    *
6630    * Since: 0.6
6631    */
6632   actor_signals[BUTTON_RELEASE_EVENT] =
6633     g_signal_new (I_("button-release-event"),
6634                   G_TYPE_FROM_CLASS (object_class),
6635                   G_SIGNAL_RUN_LAST,
6636                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6637                   _clutter_boolean_handled_accumulator, NULL,
6638                   _clutter_marshal_BOOLEAN__BOXED,
6639                   G_TYPE_BOOLEAN, 1,
6640                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6641   /**
6642    * ClutterActor::scroll-event:
6643    * @actor: the actor which received the event
6644    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6645    *
6646    * The ::scroll-event signal is emitted each time the mouse is
6647    * scrolled on @actor
6648    *
6649    * Return value: %TRUE if the event has been handled by the actor,
6650    *   or %FALSE to continue the emission.
6651    *
6652    * Since: 0.6
6653    */
6654   actor_signals[SCROLL_EVENT] =
6655     g_signal_new (I_("scroll-event"),
6656                   G_TYPE_FROM_CLASS (object_class),
6657                   G_SIGNAL_RUN_LAST,
6658                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6659                   _clutter_boolean_handled_accumulator, NULL,
6660                   _clutter_marshal_BOOLEAN__BOXED,
6661                   G_TYPE_BOOLEAN, 1,
6662                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6663   /**
6664    * ClutterActor::key-press-event:
6665    * @actor: the actor which received the event
6666    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6667    *
6668    * The ::key-press-event signal is emitted each time a keyboard button
6669    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6670    *
6671    * Return value: %TRUE if the event has been handled by the actor,
6672    *   or %FALSE to continue the emission.
6673    *
6674    * Since: 0.6
6675    */
6676   actor_signals[KEY_PRESS_EVENT] =
6677     g_signal_new (I_("key-press-event"),
6678                   G_TYPE_FROM_CLASS (object_class),
6679                   G_SIGNAL_RUN_LAST,
6680                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6681                   _clutter_boolean_handled_accumulator, NULL,
6682                   _clutter_marshal_BOOLEAN__BOXED,
6683                   G_TYPE_BOOLEAN, 1,
6684                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6685   /**
6686    * ClutterActor::key-release-event:
6687    * @actor: the actor which received the event
6688    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6689    *
6690    * The ::key-release-event signal is emitted each time a keyboard button
6691    * is released while @actor has key focus (see
6692    * clutter_stage_set_key_focus()).
6693    *
6694    * Return value: %TRUE if the event has been handled by the actor,
6695    *   or %FALSE to continue the emission.
6696    *
6697    * Since: 0.6
6698    */
6699   actor_signals[KEY_RELEASE_EVENT] =
6700     g_signal_new (I_("key-release-event"),
6701                   G_TYPE_FROM_CLASS (object_class),
6702                   G_SIGNAL_RUN_LAST,
6703                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6704                   _clutter_boolean_handled_accumulator, NULL,
6705                   _clutter_marshal_BOOLEAN__BOXED,
6706                   G_TYPE_BOOLEAN, 1,
6707                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6708   /**
6709    * ClutterActor::motion-event:
6710    * @actor: the actor which received the event
6711    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6712    *
6713    * The ::motion-event signal is emitted each time the mouse pointer is
6714    * moved over @actor.
6715    *
6716    * Return value: %TRUE if the event has been handled by the actor,
6717    *   or %FALSE to continue the emission.
6718    *
6719    * Since: 0.6
6720    */
6721   actor_signals[MOTION_EVENT] =
6722     g_signal_new (I_("motion-event"),
6723                   G_TYPE_FROM_CLASS (object_class),
6724                   G_SIGNAL_RUN_LAST,
6725                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6726                   _clutter_boolean_handled_accumulator, NULL,
6727                   _clutter_marshal_BOOLEAN__BOXED,
6728                   G_TYPE_BOOLEAN, 1,
6729                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6730
6731   /**
6732    * ClutterActor::key-focus-in:
6733    * @actor: the actor which now has key focus
6734    *
6735    * The ::key-focus-in signal is emitted when @actor receives key focus.
6736    *
6737    * Since: 0.6
6738    */
6739   actor_signals[KEY_FOCUS_IN] =
6740     g_signal_new (I_("key-focus-in"),
6741                   G_TYPE_FROM_CLASS (object_class),
6742                   G_SIGNAL_RUN_LAST,
6743                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6744                   NULL, NULL,
6745                   _clutter_marshal_VOID__VOID,
6746                   G_TYPE_NONE, 0);
6747
6748   /**
6749    * ClutterActor::key-focus-out:
6750    * @actor: the actor which now has key focus
6751    *
6752    * The ::key-focus-out signal is emitted when @actor loses key focus.
6753    *
6754    * Since: 0.6
6755    */
6756   actor_signals[KEY_FOCUS_OUT] =
6757     g_signal_new (I_("key-focus-out"),
6758                   G_TYPE_FROM_CLASS (object_class),
6759                   G_SIGNAL_RUN_LAST,
6760                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6761                   NULL, NULL,
6762                   _clutter_marshal_VOID__VOID,
6763                   G_TYPE_NONE, 0);
6764
6765   /**
6766    * ClutterActor::enter-event:
6767    * @actor: the actor which the pointer has entered.
6768    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6769    *
6770    * The ::enter-event signal is emitted when the pointer enters the @actor
6771    *
6772    * Return value: %TRUE if the event has been handled by the actor,
6773    *   or %FALSE to continue the emission.
6774    *
6775    * Since: 0.6
6776    */
6777   actor_signals[ENTER_EVENT] =
6778     g_signal_new (I_("enter-event"),
6779                   G_TYPE_FROM_CLASS (object_class),
6780                   G_SIGNAL_RUN_LAST,
6781                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6782                   _clutter_boolean_handled_accumulator, NULL,
6783                   _clutter_marshal_BOOLEAN__BOXED,
6784                   G_TYPE_BOOLEAN, 1,
6785                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6786
6787   /**
6788    * ClutterActor::leave-event:
6789    * @actor: the actor which the pointer has left
6790    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6791    *
6792    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6793    *
6794    * Return value: %TRUE if the event has been handled by the actor,
6795    *   or %FALSE to continue the emission.
6796    *
6797    * Since: 0.6
6798    */
6799   actor_signals[LEAVE_EVENT] =
6800     g_signal_new (I_("leave-event"),
6801                   G_TYPE_FROM_CLASS (object_class),
6802                   G_SIGNAL_RUN_LAST,
6803                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6804                   _clutter_boolean_handled_accumulator, NULL,
6805                   _clutter_marshal_BOOLEAN__BOXED,
6806                   G_TYPE_BOOLEAN, 1,
6807                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6808
6809   /**
6810    * ClutterActor::captured-event:
6811    * @actor: the actor which received the signal
6812    * @event: a #ClutterEvent
6813    *
6814    * The ::captured-event signal is emitted when an event is captured
6815    * by Clutter. This signal will be emitted starting from the top-level
6816    * container (the #ClutterStage) to the actor which received the event
6817    * going down the hierarchy. This signal can be used to intercept every
6818    * event before the specialized events (like
6819    * ClutterActor::button-press-event or ::key-released-event) are
6820    * emitted.
6821    *
6822    * Return value: %TRUE if the event has been handled by the actor,
6823    *   or %FALSE to continue the emission.
6824    *
6825    * Since: 0.6
6826    */
6827   actor_signals[CAPTURED_EVENT] =
6828     g_signal_new (I_("captured-event"),
6829                   G_TYPE_FROM_CLASS (object_class),
6830                   G_SIGNAL_RUN_LAST,
6831                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6832                   _clutter_boolean_handled_accumulator, NULL,
6833                   _clutter_marshal_BOOLEAN__BOXED,
6834                   G_TYPE_BOOLEAN, 1,
6835                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6836
6837   /**
6838    * ClutterActor::paint:
6839    * @actor: the #ClutterActor that received the signal
6840    *
6841    * The ::paint signal is emitted each time an actor is being painted.
6842    *
6843    * Subclasses of #ClutterActor should override the class signal handler
6844    * and paint themselves in that function.
6845    *
6846    * It is possible to connect a handler to the ::paint signal in order
6847    * to set up some custom aspect of a paint.
6848    *
6849    * Since: 0.8
6850    */
6851   actor_signals[PAINT] =
6852     g_signal_new (I_("paint"),
6853                   G_TYPE_FROM_CLASS (object_class),
6854                   G_SIGNAL_RUN_LAST |
6855                   G_SIGNAL_NO_HOOKS,
6856                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6857                   NULL, NULL,
6858                   _clutter_marshal_VOID__VOID,
6859                   G_TYPE_NONE, 0);
6860   /**
6861    * ClutterActor::realize:
6862    * @actor: the #ClutterActor that received the signal
6863    *
6864    * The ::realize signal is emitted each time an actor is being
6865    * realized.
6866    *
6867    * Since: 0.8
6868    */
6869   actor_signals[REALIZE] =
6870     g_signal_new (I_("realize"),
6871                   G_TYPE_FROM_CLASS (object_class),
6872                   G_SIGNAL_RUN_LAST,
6873                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6874                   NULL, NULL,
6875                   _clutter_marshal_VOID__VOID,
6876                   G_TYPE_NONE, 0);
6877   /**
6878    * ClutterActor::unrealize:
6879    * @actor: the #ClutterActor that received the signal
6880    *
6881    * The ::unrealize signal is emitted each time an actor is being
6882    * unrealized.
6883    *
6884    * Since: 0.8
6885    */
6886   actor_signals[UNREALIZE] =
6887     g_signal_new (I_("unrealize"),
6888                   G_TYPE_FROM_CLASS (object_class),
6889                   G_SIGNAL_RUN_LAST,
6890                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6891                   NULL, NULL,
6892                   _clutter_marshal_VOID__VOID,
6893                   G_TYPE_NONE, 0);
6894
6895   /**
6896    * ClutterActor::pick:
6897    * @actor: the #ClutterActor that received the signal
6898    * @color: the #ClutterColor to be used when picking
6899    *
6900    * The ::pick signal is emitted each time an actor is being painted
6901    * in "pick mode". The pick mode is used to identify the actor during
6902    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6903    * The actor should paint its shape using the passed @pick_color.
6904    *
6905    * Subclasses of #ClutterActor should override the class signal handler
6906    * and paint themselves in that function.
6907    *
6908    * It is possible to connect a handler to the ::pick signal in order
6909    * to set up some custom aspect of a paint in pick mode.
6910    *
6911    * Since: 1.0
6912    */
6913   actor_signals[PICK] =
6914     g_signal_new (I_("pick"),
6915                   G_TYPE_FROM_CLASS (object_class),
6916                   G_SIGNAL_RUN_LAST,
6917                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6918                   NULL, NULL,
6919                   _clutter_marshal_VOID__BOXED,
6920                   G_TYPE_NONE, 1,
6921                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6922
6923   /**
6924    * ClutterActor::allocation-changed:
6925    * @actor: the #ClutterActor that emitted the signal
6926    * @box: a #ClutterActorBox with the new allocation
6927    * @flags: #ClutterAllocationFlags for the allocation
6928    *
6929    * The ::allocation-changed signal is emitted when the
6930    * #ClutterActor:allocation property changes. Usually, application
6931    * code should just use the notifications for the :allocation property
6932    * but if you want to track the allocation flags as well, for instance
6933    * to know whether the absolute origin of @actor changed, then you might
6934    * want use this signal instead.
6935    *
6936    * Since: 1.0
6937    */
6938   actor_signals[ALLOCATION_CHANGED] =
6939     g_signal_new (I_("allocation-changed"),
6940                   G_TYPE_FROM_CLASS (object_class),
6941                   G_SIGNAL_RUN_LAST,
6942                   0,
6943                   NULL, NULL,
6944                   _clutter_marshal_VOID__BOXED_FLAGS,
6945                   G_TYPE_NONE, 2,
6946                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6947                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6948 }
6949
6950 static void
6951 clutter_actor_init (ClutterActor *self)
6952 {
6953   ClutterActorPrivate *priv;
6954
6955   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6956
6957   priv->id = _clutter_context_acquire_id (self);
6958   priv->pick_id = -1;
6959
6960   priv->opacity = 0xff;
6961   priv->show_on_set_parent = TRUE;
6962
6963   priv->needs_width_request = TRUE;
6964   priv->needs_height_request = TRUE;
6965   priv->needs_allocation = TRUE;
6966
6967   priv->cached_width_age = 1;
6968   priv->cached_height_age = 1;
6969
6970   priv->opacity_override = -1;
6971   priv->enable_model_view_transform = TRUE;
6972
6973   /* Initialize an empty paint volume to start with */
6974   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6975   priv->last_paint_volume_valid = TRUE;
6976
6977   priv->transform_valid = FALSE;
6978
6979   /* the default is to stretch the content, to match the
6980    * current behaviour of basically all actors. also, it's
6981    * the easiest thing to compute.
6982    */
6983   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
6984   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
6985   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
6986 }
6987
6988 /**
6989  * clutter_actor_new:
6990  *
6991  * Creates a new #ClutterActor.
6992  *
6993  * A newly created actor has a floating reference, which will be sunk
6994  * when it is added to another actor.
6995  *
6996  * Return value: (transfer full): the newly created #ClutterActor
6997  *
6998  * Since: 1.10
6999  */
7000 ClutterActor *
7001 clutter_actor_new (void)
7002 {
7003   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7004 }
7005
7006 /**
7007  * clutter_actor_destroy:
7008  * @self: a #ClutterActor
7009  *
7010  * Destroys an actor.  When an actor is destroyed, it will break any
7011  * references it holds to other objects.  If the actor is inside a
7012  * container, the actor will be removed.
7013  *
7014  * When you destroy a container, its children will be destroyed as well.
7015  *
7016  * Note: you cannot destroy the #ClutterStage returned by
7017  * clutter_stage_get_default().
7018  */
7019 void
7020 clutter_actor_destroy (ClutterActor *self)
7021 {
7022   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7023
7024   g_object_ref (self);
7025
7026   /* avoid recursion while destroying */
7027   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7028     {
7029       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7030
7031       g_object_run_dispose (G_OBJECT (self));
7032
7033       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7034     }
7035
7036   g_object_unref (self);
7037 }
7038
7039 void
7040 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7041                                     ClutterPaintVolume *clip)
7042 {
7043   ClutterActorPrivate *priv = self->priv;
7044   ClutterPaintVolume *pv;
7045   gboolean clipped;
7046
7047   /* Remove queue entry early in the process, otherwise a new
7048      queue_redraw() during signal handling could put back this
7049      object in the stage redraw list (but the entry is freed as
7050      soon as we return from this function, causing a segfault
7051      later)
7052   */
7053   priv->queue_redraw_entry = NULL;
7054
7055   /* If we've been explicitly passed a clip volume then there's
7056    * nothing more to calculate, but otherwise the only thing we know
7057    * is that the change is constrained to the given actor.
7058    *
7059    * The idea is that if we know the paint volume for where the actor
7060    * was last drawn (in eye coordinates) and we also have the paint
7061    * volume for where it will be drawn next (in actor coordinates)
7062    * then if we queue a redraw for both these volumes that will cover
7063    * everything that needs to be redrawn to clear the old view and
7064    * show the latest view of the actor.
7065    *
7066    * Don't clip this redraw if we don't know what position we had for
7067    * the previous redraw since we don't know where to set the clip so
7068    * it will clear the actor as it is currently.
7069    */
7070   if (clip)
7071     {
7072       _clutter_actor_set_queue_redraw_clip (self, clip);
7073       clipped = TRUE;
7074     }
7075   else if (G_LIKELY (priv->last_paint_volume_valid))
7076     {
7077       pv = _clutter_actor_get_paint_volume_mutable (self);
7078       if (pv)
7079         {
7080           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7081
7082           /* make sure we redraw the actors old position... */
7083           _clutter_actor_set_queue_redraw_clip (stage,
7084                                                 &priv->last_paint_volume);
7085           _clutter_actor_signal_queue_redraw (stage, stage);
7086           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7087
7088           /* XXX: Ideally the redraw signal would take a clip volume
7089            * argument, but that would be an ABI break. Until we can
7090            * break the ABI we pass the argument out-of-band
7091            */
7092
7093           /* setup the clip for the actors new position... */
7094           _clutter_actor_set_queue_redraw_clip (self, pv);
7095           clipped = TRUE;
7096         }
7097       else
7098         clipped = FALSE;
7099     }
7100   else
7101     clipped = FALSE;
7102
7103   _clutter_actor_signal_queue_redraw (self, self);
7104
7105   /* Just in case anyone is manually firing redraw signals without
7106    * using the public queue_redraw() API we are careful to ensure that
7107    * our out-of-band clip member is cleared before returning...
7108    *
7109    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7110    */
7111   if (G_LIKELY (clipped))
7112     _clutter_actor_set_queue_redraw_clip (self, NULL);
7113 }
7114
7115 static void
7116 _clutter_actor_get_allocation_clip (ClutterActor *self,
7117                                     ClutterActorBox *clip)
7118 {
7119   ClutterActorBox allocation;
7120
7121   /* XXX: we don't care if we get an out of date allocation here
7122    * because clutter_actor_queue_redraw_with_clip knows to ignore
7123    * the clip if the actor's allocation is invalid.
7124    *
7125    * This is noted because clutter_actor_get_allocation_box does some
7126    * unnecessary work to support buggy code with a comment suggesting
7127    * that it could be changed later which would be good for this use
7128    * case!
7129    */
7130   clutter_actor_get_allocation_box (self, &allocation);
7131
7132   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7133    * actor's own coordinate space but the allocation is in parent
7134    * coordinates */
7135   clip->x1 = 0;
7136   clip->y1 = 0;
7137   clip->x2 = allocation.x2 - allocation.x1;
7138   clip->y2 = allocation.y2 - allocation.y1;
7139 }
7140
7141 void
7142 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7143                                   ClutterRedrawFlags  flags,
7144                                   ClutterPaintVolume *volume,
7145                                   ClutterEffect      *effect)
7146 {
7147   ClutterActorPrivate *priv = self->priv;
7148   ClutterPaintVolume allocation_pv;
7149   ClutterPaintVolume *pv;
7150   gboolean should_free_pv;
7151   ClutterActor *stage;
7152
7153   /* Here's an outline of the actor queue redraw mechanism:
7154    *
7155    * The process starts in one of the following two functions which
7156    * are wrappers for this function:
7157    * clutter_actor_queue_redraw
7158    * _clutter_actor_queue_redraw_with_clip
7159    *
7160    * additionally, an effect can queue a redraw by wrapping this
7161    * function in clutter_effect_queue_rerun
7162    *
7163    * This functions queues an entry in a list associated with the
7164    * stage which is a list of actors that queued a redraw while
7165    * updating the timelines, performing layouting and processing other
7166    * mainloop sources before the next paint starts.
7167    *
7168    * We aim to minimize the processing done at this point because
7169    * there is a good chance other events will happen while updating
7170    * the scenegraph that would invalidate any expensive work we might
7171    * otherwise try to do here. For example we don't try and resolve
7172    * the screen space bounding box of an actor at this stage so as to
7173    * minimize how much of the screen redraw because it's possible
7174    * something else will happen which will force a full redraw anyway.
7175    *
7176    * When all updates are complete and we come to paint the stage then
7177    * we iterate this list and actually emit the "queue-redraw" signals
7178    * for each of the listed actors which will bubble up to the stage
7179    * for each actor and at that point we will transform the actors
7180    * paint volume into screen coordinates to determine the clip region
7181    * for what needs to be redrawn in the next paint.
7182    *
7183    * Besides minimizing redundant work another reason for this
7184    * deferred design is that it's more likely we will be able to
7185    * determine the paint volume of an actor once we've finished
7186    * updating the scenegraph because its allocation should be up to
7187    * date. NB: If we can't determine an actors paint volume then we
7188    * can't automatically queue a clipped redraw which can make a big
7189    * difference to performance.
7190    *
7191    * So the control flow goes like this:
7192    * One of clutter_actor_queue_redraw,
7193    *        _clutter_actor_queue_redraw_with_clip
7194    *     or clutter_effect_queue_rerun
7195    *
7196    * then control moves to:
7197    *   _clutter_stage_queue_actor_redraw
7198    *
7199    * later during _clutter_stage_do_update, once relayouting is done
7200    * and the scenegraph has been updated we will call:
7201    * _clutter_stage_finish_queue_redraws
7202    *
7203    * _clutter_stage_finish_queue_redraws will call
7204    * _clutter_actor_finish_queue_redraw for each listed actor.
7205    * Note: actors *are* allowed to queue further redraws during this
7206    * process (considering clone actors or texture_new_from_actor which
7207    * respond to their source queueing a redraw by queuing a redraw
7208    * themselves). We repeat the process until the list is empty.
7209    *
7210    * This will result in the "queue-redraw" signal being fired for
7211    * each actor which will pass control to the default signal handler:
7212    * clutter_actor_real_queue_redraw
7213    *
7214    * This will bubble up to the stages handler:
7215    * clutter_stage_real_queue_redraw
7216    *
7217    * clutter_stage_real_queue_redraw will transform the actors paint
7218    * volume into screen space and add it as a clip region for the next
7219    * paint.
7220    */
7221
7222   /* ignore queueing a redraw for actors being destroyed */
7223   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7224     return;
7225
7226   stage = _clutter_actor_get_stage_internal (self);
7227
7228   /* Ignore queueing a redraw for actors not descended from a stage */
7229   if (stage == NULL)
7230     return;
7231
7232   /* ignore queueing a redraw on stages that are being destroyed */
7233   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7234     return;
7235
7236   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7237     {
7238       ClutterActorBox allocation_clip;
7239       ClutterVertex origin;
7240
7241       /* If the actor doesn't have a valid allocation then we will
7242        * queue a full stage redraw. */
7243       if (priv->needs_allocation)
7244         {
7245           /* NB: NULL denotes an undefined clip which will result in a
7246            * full redraw... */
7247           _clutter_actor_set_queue_redraw_clip (self, NULL);
7248           _clutter_actor_signal_queue_redraw (self, self);
7249           return;
7250         }
7251
7252       _clutter_paint_volume_init_static (&allocation_pv, self);
7253       pv = &allocation_pv;
7254
7255       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7256
7257       origin.x = allocation_clip.x1;
7258       origin.y = allocation_clip.y1;
7259       origin.z = 0;
7260       clutter_paint_volume_set_origin (pv, &origin);
7261       clutter_paint_volume_set_width (pv,
7262                                       allocation_clip.x2 - allocation_clip.x1);
7263       clutter_paint_volume_set_height (pv,
7264                                        allocation_clip.y2 -
7265                                        allocation_clip.y1);
7266       should_free_pv = TRUE;
7267     }
7268   else
7269     {
7270       pv = volume;
7271       should_free_pv = FALSE;
7272     }
7273
7274   self->priv->queue_redraw_entry =
7275     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7276                                        priv->queue_redraw_entry,
7277                                        self,
7278                                        pv);
7279
7280   if (should_free_pv)
7281     clutter_paint_volume_free (pv);
7282
7283   /* If this is the first redraw queued then we can directly use the
7284      effect parameter */
7285   if (!priv->is_dirty)
7286     priv->effect_to_redraw = effect;
7287   /* Otherwise we need to merge it with the existing effect parameter */
7288   else if (effect != NULL)
7289     {
7290       /* If there's already an effect then we need to use whichever is
7291          later in the chain of actors. Otherwise a full redraw has
7292          already been queued on the actor so we need to ignore the
7293          effect parameter */
7294       if (priv->effect_to_redraw != NULL)
7295         {
7296           if (priv->effects == NULL)
7297             g_warning ("Redraw queued with an effect that is "
7298                        "not applied to the actor");
7299           else
7300             {
7301               const GList *l;
7302
7303               for (l = _clutter_meta_group_peek_metas (priv->effects);
7304                    l != NULL;
7305                    l = l->next)
7306                 {
7307                   if (l->data == priv->effect_to_redraw ||
7308                       l->data == effect)
7309                     priv->effect_to_redraw = l->data;
7310                 }
7311             }
7312         }
7313     }
7314   else
7315     {
7316       /* If no effect is specified then we need to redraw the whole
7317          actor */
7318       priv->effect_to_redraw = NULL;
7319     }
7320
7321   priv->is_dirty = TRUE;
7322 }
7323
7324 /**
7325  * clutter_actor_queue_redraw:
7326  * @self: A #ClutterActor
7327  *
7328  * Queues up a redraw of an actor and any children. The redraw occurs
7329  * once the main loop becomes idle (after the current batch of events
7330  * has been processed, roughly).
7331  *
7332  * Applications rarely need to call this, as redraws are handled
7333  * automatically by modification functions.
7334  *
7335  * This function will not do anything if @self is not visible, or
7336  * if the actor is inside an invisible part of the scenegraph.
7337  *
7338  * Also be aware that painting is a NOP for actors with an opacity of
7339  * 0
7340  *
7341  * When you are implementing a custom actor you must queue a redraw
7342  * whenever some private state changes that will affect painting or
7343  * picking of your actor.
7344  */
7345 void
7346 clutter_actor_queue_redraw (ClutterActor *self)
7347 {
7348   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7349
7350   _clutter_actor_queue_redraw_full (self,
7351                                     0, /* flags */
7352                                     NULL, /* clip volume */
7353                                     NULL /* effect */);
7354 }
7355
7356 /*< private >
7357  * _clutter_actor_queue_redraw_with_clip:
7358  * @self: A #ClutterActor
7359  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7360  *   this queue redraw.
7361  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7362  *   redrawn or %NULL if you are just using a @flag to state your
7363  *   desired clipping.
7364  *
7365  * Queues up a clipped redraw of an actor and any children. The redraw
7366  * occurs once the main loop becomes idle (after the current batch of
7367  * events has been processed, roughly).
7368  *
7369  * If no flags are given the clip volume is defined by @volume
7370  * specified in actor coordinates and tells Clutter that only content
7371  * within this volume has been changed so Clutter can optionally
7372  * optimize the redraw.
7373  *
7374  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7375  * should be %NULL and this tells Clutter to use the actor's current
7376  * allocation as a clip box. This flag can only be used for 2D actors,
7377  * because any actor with depth may be projected outside its
7378  * allocation.
7379  *
7380  * Applications rarely need to call this, as redraws are handled
7381  * automatically by modification functions.
7382  *
7383  * This function will not do anything if @self is not visible, or if
7384  * the actor is inside an invisible part of the scenegraph.
7385  *
7386  * Also be aware that painting is a NOP for actors with an opacity of
7387  * 0
7388  *
7389  * When you are implementing a custom actor you must queue a redraw
7390  * whenever some private state changes that will affect painting or
7391  * picking of your actor.
7392  */
7393 void
7394 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7395                                        ClutterRedrawFlags  flags,
7396                                        ClutterPaintVolume *volume)
7397 {
7398   _clutter_actor_queue_redraw_full (self,
7399                                     flags, /* flags */
7400                                     volume, /* clip volume */
7401                                     NULL /* effect */);
7402 }
7403
7404 static void
7405 _clutter_actor_queue_only_relayout (ClutterActor *self)
7406 {
7407   ClutterActorPrivate *priv = self->priv;
7408
7409   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7410     return;
7411
7412   if (priv->needs_width_request &&
7413       priv->needs_height_request &&
7414       priv->needs_allocation)
7415     return; /* save some cpu cycles */
7416
7417 #if CLUTTER_ENABLE_DEBUG
7418   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7419     {
7420       g_warning ("The actor '%s' is currently inside an allocation "
7421                  "cycle; calling clutter_actor_queue_relayout() is "
7422                  "not recommended",
7423                  _clutter_actor_get_debug_name (self));
7424     }
7425 #endif /* CLUTTER_ENABLE_DEBUG */
7426
7427   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7428 }
7429
7430 /**
7431  * clutter_actor_queue_redraw_with_clip:
7432  * @self: a #ClutterActor
7433  * @clip: (allow-none): a rectangular clip region, or %NULL
7434  *
7435  * Queues a redraw on @self limited to a specific, actor-relative
7436  * rectangular area.
7437  *
7438  * If @clip is %NULL this function is equivalent to
7439  * clutter_actor_queue_redraw().
7440  *
7441  * Since: 1.10
7442  */
7443 void
7444 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7445                                       const cairo_rectangle_int_t *clip)
7446 {
7447   ClutterPaintVolume volume;
7448   ClutterVertex origin;
7449
7450   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7451
7452   if (clip == NULL)
7453     {
7454       clutter_actor_queue_redraw (self);
7455       return;
7456     }
7457
7458   _clutter_paint_volume_init_static (&volume, self);
7459
7460   origin.x = clip->x;
7461   origin.y = clip->y;
7462   origin.z = 0.0f;
7463
7464   clutter_paint_volume_set_origin (&volume, &origin);
7465   clutter_paint_volume_set_width (&volume, clip->width);
7466   clutter_paint_volume_set_height (&volume, clip->height);
7467
7468   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7469
7470   clutter_paint_volume_free (&volume);
7471 }
7472
7473 /**
7474  * clutter_actor_queue_relayout:
7475  * @self: A #ClutterActor
7476  *
7477  * Indicates that the actor's size request or other layout-affecting
7478  * properties may have changed. This function is used inside #ClutterActor
7479  * subclass implementations, not by applications directly.
7480  *
7481  * Queueing a new layout automatically queues a redraw as well.
7482  *
7483  * Since: 0.8
7484  */
7485 void
7486 clutter_actor_queue_relayout (ClutterActor *self)
7487 {
7488   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7489
7490   _clutter_actor_queue_only_relayout (self);
7491   clutter_actor_queue_redraw (self);
7492 }
7493
7494 /**
7495  * clutter_actor_get_preferred_size:
7496  * @self: a #ClutterActor
7497  * @min_width_p: (out) (allow-none): return location for the minimum
7498  *   width, or %NULL
7499  * @min_height_p: (out) (allow-none): return location for the minimum
7500  *   height, or %NULL
7501  * @natural_width_p: (out) (allow-none): return location for the natural
7502  *   width, or %NULL
7503  * @natural_height_p: (out) (allow-none): return location for the natural
7504  *   height, or %NULL
7505  *
7506  * Computes the preferred minimum and natural size of an actor, taking into
7507  * account the actor's geometry management (either height-for-width
7508  * or width-for-height).
7509  *
7510  * The width and height used to compute the preferred height and preferred
7511  * width are the actor's natural ones.
7512  *
7513  * If you need to control the height for the preferred width, or the width for
7514  * the preferred height, you should use clutter_actor_get_preferred_width()
7515  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7516  * geometry management using the #ClutterActor:request-mode property.
7517  *
7518  * Since: 0.8
7519  */
7520 void
7521 clutter_actor_get_preferred_size (ClutterActor *self,
7522                                   gfloat       *min_width_p,
7523                                   gfloat       *min_height_p,
7524                                   gfloat       *natural_width_p,
7525                                   gfloat       *natural_height_p)
7526 {
7527   ClutterActorPrivate *priv;
7528   gfloat min_width, min_height;
7529   gfloat natural_width, natural_height;
7530
7531   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7532
7533   priv = self->priv;
7534
7535   min_width = min_height = 0;
7536   natural_width = natural_height = 0;
7537
7538   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7539     {
7540       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7541       clutter_actor_get_preferred_width (self, -1,
7542                                          &min_width,
7543                                          &natural_width);
7544       clutter_actor_get_preferred_height (self, natural_width,
7545                                           &min_height,
7546                                           &natural_height);
7547     }
7548   else
7549     {
7550       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7551       clutter_actor_get_preferred_height (self, -1,
7552                                           &min_height,
7553                                           &natural_height);
7554       clutter_actor_get_preferred_width (self, natural_height,
7555                                          &min_width,
7556                                          &natural_width);
7557     }
7558
7559   if (min_width_p)
7560     *min_width_p = min_width;
7561
7562   if (min_height_p)
7563     *min_height_p = min_height;
7564
7565   if (natural_width_p)
7566     *natural_width_p = natural_width;
7567
7568   if (natural_height_p)
7569     *natural_height_p = natural_height;
7570 }
7571
7572 /*< private >
7573  * effective_align:
7574  * @align: a #ClutterActorAlign
7575  * @direction: a #ClutterTextDirection
7576  *
7577  * Retrieves the correct alignment depending on the text direction
7578  *
7579  * Return value: the effective alignment
7580  */
7581 static ClutterActorAlign
7582 effective_align (ClutterActorAlign    align,
7583                  ClutterTextDirection direction)
7584 {
7585   ClutterActorAlign res;
7586
7587   switch (align)
7588     {
7589     case CLUTTER_ACTOR_ALIGN_START:
7590       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7591           ? CLUTTER_ACTOR_ALIGN_END
7592           : CLUTTER_ACTOR_ALIGN_START;
7593       break;
7594
7595     case CLUTTER_ACTOR_ALIGN_END:
7596       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7597           ? CLUTTER_ACTOR_ALIGN_START
7598           : CLUTTER_ACTOR_ALIGN_END;
7599       break;
7600
7601     default:
7602       res = align;
7603       break;
7604     }
7605
7606   return res;
7607 }
7608
7609 static inline void
7610 adjust_for_margin (float  margin_start,
7611                    float  margin_end,
7612                    float *minimum_size,
7613                    float *natural_size,
7614                    float *allocated_start,
7615                    float *allocated_end)
7616 {
7617   *minimum_size -= (margin_start + margin_end);
7618   *natural_size -= (margin_start + margin_end);
7619   *allocated_start += margin_start;
7620   *allocated_end -= margin_end;
7621 }
7622
7623 static inline void
7624 adjust_for_alignment (ClutterActorAlign  alignment,
7625                       float              natural_size,
7626                       float             *allocated_start,
7627                       float             *allocated_end)
7628 {
7629   float allocated_size = *allocated_end - *allocated_start;
7630
7631   switch (alignment)
7632     {
7633     case CLUTTER_ACTOR_ALIGN_FILL:
7634       /* do nothing */
7635       break;
7636
7637     case CLUTTER_ACTOR_ALIGN_START:
7638       /* keep start */
7639       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7640       break;
7641
7642     case CLUTTER_ACTOR_ALIGN_END:
7643       if (allocated_size > natural_size)
7644         {
7645           *allocated_start += (allocated_size - natural_size);
7646           *allocated_end = *allocated_start + natural_size;
7647         }
7648       break;
7649
7650     case CLUTTER_ACTOR_ALIGN_CENTER:
7651       if (allocated_size > natural_size)
7652         {
7653           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7654           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7655         }
7656       break;
7657     }
7658 }
7659
7660 /*< private >
7661  * clutter_actor_adjust_width:
7662  * @self: a #ClutterActor
7663  * @minimum_width: (inout): the actor's preferred minimum width, which
7664  *   will be adjusted depending on the margin
7665  * @natural_width: (inout): the actor's preferred natural width, which
7666  *   will be adjusted depending on the margin
7667  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7668  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7669  *
7670  * Adjusts the preferred and allocated position and size of an actor,
7671  * depending on the margin and alignment properties.
7672  */
7673 static void
7674 clutter_actor_adjust_width (ClutterActor *self,
7675                             gfloat       *minimum_width,
7676                             gfloat       *natural_width,
7677                             gfloat       *adjusted_x1,
7678                             gfloat       *adjusted_x2)
7679 {
7680   ClutterTextDirection text_dir;
7681   const ClutterLayoutInfo *info;
7682
7683   info = _clutter_actor_get_layout_info_or_defaults (self);
7684   text_dir = clutter_actor_get_text_direction (self);
7685
7686   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7687
7688   /* this will tweak natural_width to remove the margin, so that
7689    * adjust_for_alignment() will use the correct size
7690    */
7691   adjust_for_margin (info->margin.left, info->margin.right,
7692                      minimum_width, natural_width,
7693                      adjusted_x1, adjusted_x2);
7694
7695   adjust_for_alignment (effective_align (info->x_align, text_dir),
7696                         *natural_width,
7697                         adjusted_x1, adjusted_x2);
7698 }
7699
7700 /*< private >
7701  * clutter_actor_adjust_height:
7702  * @self: a #ClutterActor
7703  * @minimum_height: (inout): the actor's preferred minimum height, which
7704  *   will be adjusted depending on the margin
7705  * @natural_height: (inout): the actor's preferred natural height, which
7706  *   will be adjusted depending on the margin
7707  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7708  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7709  *
7710  * Adjusts the preferred and allocated position and size of an actor,
7711  * depending on the margin and alignment properties.
7712  */
7713 static void
7714 clutter_actor_adjust_height (ClutterActor *self,
7715                              gfloat       *minimum_height,
7716                              gfloat       *natural_height,
7717                              gfloat       *adjusted_y1,
7718                              gfloat       *adjusted_y2)
7719 {
7720   const ClutterLayoutInfo *info;
7721
7722   info = _clutter_actor_get_layout_info_or_defaults (self);
7723
7724   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7725
7726   /* this will tweak natural_height to remove the margin, so that
7727    * adjust_for_alignment() will use the correct size
7728    */
7729   adjust_for_margin (info->margin.top, info->margin.bottom,
7730                      minimum_height, natural_height,
7731                      adjusted_y1,
7732                      adjusted_y2);
7733
7734   /* we don't use effective_align() here, because text direction
7735    * only affects the horizontal axis
7736    */
7737   adjust_for_alignment (info->y_align,
7738                         *natural_height,
7739                         adjusted_y1,
7740                         adjusted_y2);
7741
7742 }
7743
7744 /* looks for a cached size request for this for_size. If not
7745  * found, returns the oldest entry so it can be overwritten */
7746 static gboolean
7747 _clutter_actor_get_cached_size_request (gfloat         for_size,
7748                                         SizeRequest   *cached_size_requests,
7749                                         SizeRequest  **result)
7750 {
7751   guint i;
7752
7753   *result = &cached_size_requests[0];
7754
7755   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7756     {
7757       SizeRequest *sr;
7758
7759       sr = &cached_size_requests[i];
7760
7761       if (sr->age > 0 &&
7762           sr->for_size == for_size)
7763         {
7764           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7765           *result = sr;
7766           return TRUE;
7767         }
7768       else if (sr->age < (*result)->age)
7769         {
7770           *result = sr;
7771         }
7772     }
7773
7774   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7775
7776   return FALSE;
7777 }
7778
7779 /**
7780  * clutter_actor_get_preferred_width:
7781  * @self: A #ClutterActor
7782  * @for_height: available height when computing the preferred width,
7783  *   or a negative value to indicate that no height is defined
7784  * @min_width_p: (out) (allow-none): return location for minimum width,
7785  *   or %NULL
7786  * @natural_width_p: (out) (allow-none): return location for the natural
7787  *   width, or %NULL
7788  *
7789  * Computes the requested minimum and natural widths for an actor,
7790  * optionally depending on the specified height, or if they are
7791  * already computed, returns the cached values.
7792  *
7793  * An actor may not get its request - depending on the layout
7794  * manager that's in effect.
7795  *
7796  * A request should not incorporate the actor's scale or anchor point;
7797  * those transformations do not affect layout, only rendering.
7798  *
7799  * Since: 0.8
7800  */
7801 void
7802 clutter_actor_get_preferred_width (ClutterActor *self,
7803                                    gfloat        for_height,
7804                                    gfloat       *min_width_p,
7805                                    gfloat       *natural_width_p)
7806 {
7807   float request_min_width, request_natural_width;
7808   SizeRequest *cached_size_request;
7809   const ClutterLayoutInfo *info;
7810   ClutterActorPrivate *priv;
7811   gboolean found_in_cache;
7812
7813   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7814
7815   priv = self->priv;
7816
7817   info = _clutter_actor_get_layout_info_or_defaults (self);
7818
7819   /* we shortcircuit the case of a fixed size set using set_width() */
7820   if (priv->min_width_set && priv->natural_width_set)
7821     {
7822       if (min_width_p != NULL)
7823         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7824
7825       if (natural_width_p != NULL)
7826         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7827
7828       return;
7829     }
7830
7831   /* the remaining cases are:
7832    *
7833    *   - either min_width or natural_width have been set
7834    *   - neither min_width or natural_width have been set
7835    *
7836    * in both cases, we go through the cache (and through the actor in case
7837    * of cache misses) and determine the authoritative value depending on
7838    * the *_set flags.
7839    */
7840
7841   if (!priv->needs_width_request)
7842     {
7843       found_in_cache =
7844         _clutter_actor_get_cached_size_request (for_height,
7845                                                 priv->width_requests,
7846                                                 &cached_size_request);
7847     }
7848   else
7849     {
7850       /* if the actor needs a width request we use the first slot */
7851       found_in_cache = FALSE;
7852       cached_size_request = &priv->width_requests[0];
7853     }
7854
7855   if (!found_in_cache)
7856     {
7857       gfloat minimum_width, natural_width;
7858       ClutterActorClass *klass;
7859
7860       minimum_width = natural_width = 0;
7861
7862       /* adjust for the margin */
7863       if (for_height >= 0)
7864         {
7865           for_height -= (info->margin.top + info->margin.bottom);
7866           if (for_height < 0)
7867             for_height = 0;
7868         }
7869
7870       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7871
7872       klass = CLUTTER_ACTOR_GET_CLASS (self);
7873       klass->get_preferred_width (self, for_height,
7874                                   &minimum_width,
7875                                   &natural_width);
7876
7877       /* adjust for the margin */
7878       minimum_width += (info->margin.left + info->margin.right);
7879       natural_width += (info->margin.left + info->margin.right);
7880
7881       /* Due to accumulated float errors, it's better not to warn
7882        * on this, but just fix it.
7883        */
7884       if (natural_width < minimum_width)
7885         natural_width = minimum_width;
7886
7887       cached_size_request->min_size = minimum_width;
7888       cached_size_request->natural_size = natural_width;
7889       cached_size_request->for_size = for_height;
7890       cached_size_request->age = priv->cached_width_age;
7891
7892       priv->cached_width_age += 1;
7893       priv->needs_width_request = FALSE;
7894     }
7895
7896   if (!priv->min_width_set)
7897     request_min_width = cached_size_request->min_size;
7898   else
7899     request_min_width = info->min_width;
7900
7901   if (!priv->natural_width_set)
7902     request_natural_width = cached_size_request->natural_size;
7903   else
7904     request_natural_width = info->natural_width;
7905
7906   if (min_width_p)
7907     *min_width_p = request_min_width;
7908
7909   if (natural_width_p)
7910     *natural_width_p = request_natural_width;
7911 }
7912
7913 /**
7914  * clutter_actor_get_preferred_height:
7915  * @self: A #ClutterActor
7916  * @for_width: available width to assume in computing desired height,
7917  *   or a negative value to indicate that no width is defined
7918  * @min_height_p: (out) (allow-none): return location for minimum height,
7919  *   or %NULL
7920  * @natural_height_p: (out) (allow-none): return location for natural
7921  *   height, or %NULL
7922  *
7923  * Computes the requested minimum and natural heights for an actor,
7924  * or if they are already computed, returns the cached values.
7925  *
7926  * An actor may not get its request - depending on the layout
7927  * manager that's in effect.
7928  *
7929  * A request should not incorporate the actor's scale or anchor point;
7930  * those transformations do not affect layout, only rendering.
7931  *
7932  * Since: 0.8
7933  */
7934 void
7935 clutter_actor_get_preferred_height (ClutterActor *self,
7936                                     gfloat        for_width,
7937                                     gfloat       *min_height_p,
7938                                     gfloat       *natural_height_p)
7939 {
7940   float request_min_height, request_natural_height;
7941   SizeRequest *cached_size_request;
7942   const ClutterLayoutInfo *info;
7943   ClutterActorPrivate *priv;
7944   gboolean found_in_cache;
7945
7946   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7947
7948   priv = self->priv;
7949
7950   info = _clutter_actor_get_layout_info_or_defaults (self);
7951
7952   /* we shortcircuit the case of a fixed size set using set_height() */
7953   if (priv->min_height_set && priv->natural_height_set)
7954     {
7955       if (min_height_p != NULL)
7956         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7957
7958       if (natural_height_p != NULL)
7959         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7960
7961       return;
7962     }
7963
7964   /* the remaining cases are:
7965    *
7966    *   - either min_height or natural_height have been set
7967    *   - neither min_height or natural_height have been set
7968    *
7969    * in both cases, we go through the cache (and through the actor in case
7970    * of cache misses) and determine the authoritative value depending on
7971    * the *_set flags.
7972    */
7973
7974   if (!priv->needs_height_request)
7975     {
7976       found_in_cache =
7977         _clutter_actor_get_cached_size_request (for_width,
7978                                                 priv->height_requests,
7979                                                 &cached_size_request);
7980     }
7981   else
7982     {
7983       found_in_cache = FALSE;
7984       cached_size_request = &priv->height_requests[0];
7985     }
7986
7987   if (!found_in_cache)
7988     {
7989       gfloat minimum_height, natural_height;
7990       ClutterActorClass *klass;
7991
7992       minimum_height = natural_height = 0;
7993
7994       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7995
7996       /* adjust for margin */
7997       if (for_width >= 0)
7998         {
7999           for_width -= (info->margin.left + info->margin.right);
8000           if (for_width < 0)
8001             for_width = 0;
8002         }
8003
8004       klass = CLUTTER_ACTOR_GET_CLASS (self);
8005       klass->get_preferred_height (self, for_width,
8006                                    &minimum_height,
8007                                    &natural_height);
8008
8009       /* adjust for margin */
8010       minimum_height += (info->margin.top + info->margin.bottom);
8011       natural_height += (info->margin.top + info->margin.bottom);
8012
8013       /* Due to accumulated float errors, it's better not to warn
8014        * on this, but just fix it.
8015        */
8016       if (natural_height < minimum_height)
8017         natural_height = minimum_height;
8018
8019       cached_size_request->min_size = minimum_height;
8020       cached_size_request->natural_size = natural_height;
8021       cached_size_request->for_size = for_width;
8022       cached_size_request->age = priv->cached_height_age;
8023
8024       priv->cached_height_age += 1;
8025       priv->needs_height_request = FALSE;
8026     }
8027
8028   if (!priv->min_height_set)
8029     request_min_height = cached_size_request->min_size;
8030   else
8031     request_min_height = info->min_height;
8032
8033   if (!priv->natural_height_set)
8034     request_natural_height = cached_size_request->natural_size;
8035   else
8036     request_natural_height = info->natural_height;
8037
8038   if (min_height_p)
8039     *min_height_p = request_min_height;
8040
8041   if (natural_height_p)
8042     *natural_height_p = request_natural_height;
8043 }
8044
8045 /**
8046  * clutter_actor_get_allocation_box:
8047  * @self: A #ClutterActor
8048  * @box: (out): the function fills this in with the actor's allocation
8049  *
8050  * Gets the layout box an actor has been assigned. The allocation can
8051  * only be assumed valid inside a paint() method; anywhere else, it
8052  * may be out-of-date.
8053  *
8054  * An allocation does not incorporate the actor's scale or anchor point;
8055  * those transformations do not affect layout, only rendering.
8056  *
8057  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8058  * of functions inside the implementation of the get_preferred_width()
8059  * or get_preferred_height() virtual functions.</note>
8060  *
8061  * Since: 0.8
8062  */
8063 void
8064 clutter_actor_get_allocation_box (ClutterActor    *self,
8065                                   ClutterActorBox *box)
8066 {
8067   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8068
8069   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8070    * which limits calling get_allocation to inside paint() basically; or
8071    * we can 2) force a layout, which could be expensive if someone calls
8072    * get_allocation somewhere silly; or we can 3) just return the latest
8073    * value, allowing it to be out-of-date, and assume people know what
8074    * they are doing.
8075    *
8076    * The least-surprises approach that keeps existing code working is
8077    * likely to be 2). People can end up doing some inefficient things,
8078    * though, and in general code that requires 2) is probably broken.
8079    */
8080
8081   /* this implements 2) */
8082   if (G_UNLIKELY (self->priv->needs_allocation))
8083     {
8084       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8085
8086       /* do not queue a relayout on an unparented actor */
8087       if (stage)
8088         _clutter_stage_maybe_relayout (stage);
8089     }
8090
8091   /* commenting out the code above and just keeping this assigment
8092    * implements 3)
8093    */
8094   *box = self->priv->allocation;
8095 }
8096
8097 /**
8098  * clutter_actor_get_allocation_geometry:
8099  * @self: A #ClutterActor
8100  * @geom: (out): allocation geometry in pixels
8101  *
8102  * Gets the layout box an actor has been assigned.  The allocation can
8103  * only be assumed valid inside a paint() method; anywhere else, it
8104  * may be out-of-date.
8105  *
8106  * An allocation does not incorporate the actor's scale or anchor point;
8107  * those transformations do not affect layout, only rendering.
8108  *
8109  * The returned rectangle is in pixels.
8110  *
8111  * Since: 0.8
8112  */
8113 void
8114 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8115                                        ClutterGeometry *geom)
8116 {
8117   ClutterActorBox box;
8118
8119   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8120   g_return_if_fail (geom != NULL);
8121
8122   clutter_actor_get_allocation_box (self, &box);
8123
8124   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8125   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8126   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8127   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8128 }
8129
8130 static void
8131 clutter_actor_update_constraints (ClutterActor    *self,
8132                                   ClutterActorBox *allocation)
8133 {
8134   ClutterActorPrivate *priv = self->priv;
8135   const GList *constraints, *l;
8136
8137   if (priv->constraints == NULL)
8138     return;
8139
8140   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8141   for (l = constraints; l != NULL; l = l->next)
8142     {
8143       ClutterConstraint *constraint = l->data;
8144       ClutterActorMeta *meta = l->data;
8145
8146       if (clutter_actor_meta_get_enabled (meta))
8147         {
8148           _clutter_constraint_update_allocation (constraint,
8149                                                  self,
8150                                                  allocation);
8151
8152           CLUTTER_NOTE (LAYOUT,
8153                         "Allocation of '%s' after constraint '%s': "
8154                         "{ %.2f, %.2f, %.2f, %.2f }",
8155                         _clutter_actor_get_debug_name (self),
8156                         _clutter_actor_meta_get_debug_name (meta),
8157                         allocation->x1,
8158                         allocation->y1,
8159                         allocation->x2,
8160                         allocation->y2);
8161         }
8162     }
8163 }
8164
8165 /*< private >
8166  * clutter_actor_adjust_allocation:
8167  * @self: a #ClutterActor
8168  * @allocation: (inout): the allocation to adjust
8169  *
8170  * Adjusts the passed allocation box taking into account the actor's
8171  * layout information, like alignment, expansion, and margin.
8172  */
8173 static void
8174 clutter_actor_adjust_allocation (ClutterActor    *self,
8175                                  ClutterActorBox *allocation)
8176 {
8177   ClutterActorBox adj_allocation;
8178   float alloc_width, alloc_height;
8179   float min_width, min_height;
8180   float nat_width, nat_height;
8181   ClutterRequestMode req_mode;
8182
8183   adj_allocation = *allocation;
8184
8185   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8186
8187   /* we want to hit the cache, so we use the public API */
8188   req_mode = clutter_actor_get_request_mode (self);
8189
8190   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8191     {
8192       clutter_actor_get_preferred_width (self, -1,
8193                                          &min_width,
8194                                          &nat_width);
8195       clutter_actor_get_preferred_height (self, alloc_width,
8196                                           &min_height,
8197                                           &nat_height);
8198     }
8199   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8200     {
8201       clutter_actor_get_preferred_height (self, -1,
8202                                           &min_height,
8203                                           &nat_height);
8204       clutter_actor_get_preferred_height (self, alloc_height,
8205                                           &min_width,
8206                                           &nat_width);
8207     }
8208
8209 #ifdef CLUTTER_ENABLE_DEBUG
8210   /* warn about underallocations */
8211   if (_clutter_diagnostic_enabled () &&
8212       (floorf (min_width - alloc_width) > 0 ||
8213        floorf (min_height - alloc_height) > 0))
8214     {
8215       ClutterActor *parent = clutter_actor_get_parent (self);
8216
8217       /* the only actors that are allowed to be underallocated are the Stage,
8218        * as it doesn't have an implicit size, and Actors that specifically
8219        * told us that they want to opt-out from layout control mechanisms
8220        * through the NO_LAYOUT escape hatch.
8221        */
8222       if (parent != NULL &&
8223           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8224         {
8225           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8226                      "of %.2f x %.2f from its parent actor '%s', but its "
8227                      "requested minimum size is of %.2f x %.2f",
8228                      _clutter_actor_get_debug_name (self),
8229                      alloc_width, alloc_height,
8230                      _clutter_actor_get_debug_name (parent),
8231                      min_width, min_height);
8232         }
8233     }
8234 #endif
8235
8236   clutter_actor_adjust_width (self,
8237                               &min_width,
8238                               &nat_width,
8239                               &adj_allocation.x1,
8240                               &adj_allocation.x2);
8241
8242   clutter_actor_adjust_height (self,
8243                                &min_height,
8244                                &nat_height,
8245                                &adj_allocation.y1,
8246                                &adj_allocation.y2);
8247
8248   /* we maintain the invariant that an allocation cannot be adjusted
8249    * to be outside the parent-given box
8250    */
8251   if (adj_allocation.x1 < allocation->x1 ||
8252       adj_allocation.y1 < allocation->y1 ||
8253       adj_allocation.x2 > allocation->x2 ||
8254       adj_allocation.y2 > allocation->y2)
8255     {
8256       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8257                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8258                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8259                  _clutter_actor_get_debug_name (self),
8260                  adj_allocation.x1, adj_allocation.y1,
8261                  adj_allocation.x2 - adj_allocation.x1,
8262                  adj_allocation.y2 - adj_allocation.y1,
8263                  allocation->x1, allocation->y1,
8264                  allocation->x2 - allocation->x1,
8265                  allocation->y2 - allocation->y1);
8266       return;
8267     }
8268
8269   *allocation = adj_allocation;
8270 }
8271
8272 /**
8273  * clutter_actor_allocate:
8274  * @self: A #ClutterActor
8275  * @box: new allocation of the actor, in parent-relative coordinates
8276  * @flags: flags that control the allocation
8277  *
8278  * Called by the parent of an actor to assign the actor its size.
8279  * Should never be called by applications (except when implementing
8280  * a container or layout manager).
8281  *
8282  * Actors can know from their allocation box whether they have moved
8283  * with respect to their parent actor. The @flags parameter describes
8284  * additional information about the allocation, for instance whether
8285  * the parent has moved with respect to the stage, for example because
8286  * a grandparent's origin has moved.
8287  *
8288  * Since: 0.8
8289  */
8290 void
8291 clutter_actor_allocate (ClutterActor           *self,
8292                         const ClutterActorBox  *box,
8293                         ClutterAllocationFlags  flags)
8294 {
8295   ClutterActorPrivate *priv;
8296   ClutterActorClass *klass;
8297   ClutterActorBox old_allocation, real_allocation;
8298   gboolean origin_changed, child_moved, size_changed;
8299   gboolean stage_allocation_changed;
8300
8301   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8302   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8303     {
8304       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8305                  "which isn't a descendent of the stage!\n",
8306                  self, _clutter_actor_get_debug_name (self));
8307       return;
8308     }
8309
8310   priv = self->priv;
8311
8312   old_allocation = priv->allocation;
8313   real_allocation = *box;
8314
8315   /* constraints are allowed to modify the allocation only here; we do
8316    * this prior to all the other checks so that we can bail out if the
8317    * allocation did not change
8318    */
8319   clutter_actor_update_constraints (self, &real_allocation);
8320
8321   /* adjust the allocation depending on the align/margin properties */
8322   clutter_actor_adjust_allocation (self, &real_allocation);
8323
8324   if (real_allocation.x2 < real_allocation.x1 ||
8325       real_allocation.y2 < real_allocation.y1)
8326     {
8327       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8328                  _clutter_actor_get_debug_name (self),
8329                  real_allocation.x2 - real_allocation.x1,
8330                  real_allocation.y2 - real_allocation.y1);
8331     }
8332
8333   /* we allow 0-sized actors, but not negative-sized ones */
8334   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8335   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8336
8337   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8338
8339   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8340                  real_allocation.y1 != old_allocation.y1);
8341
8342   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8343                   real_allocation.y2 != old_allocation.y2);
8344
8345   if (origin_changed || child_moved || size_changed)
8346     stage_allocation_changed = TRUE;
8347   else
8348     stage_allocation_changed = FALSE;
8349
8350   /* If we get an allocation "out of the blue"
8351    * (we did not queue relayout), then we want to
8352    * ignore it. But if we have needs_allocation set,
8353    * we want to guarantee that allocate() virtual
8354    * method is always called, i.e. that queue_relayout()
8355    * always results in an allocate() invocation on
8356    * an actor.
8357    *
8358    * The optimization here is to avoid re-allocating
8359    * actors that did not queue relayout and were
8360    * not moved.
8361    */
8362   if (!priv->needs_allocation && !stage_allocation_changed)
8363     {
8364       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8365       return;
8366     }
8367
8368   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8369    * clutter_actor_allocate(), it indicates whether the parent has its
8370    * absolute origin moved; when passed in to ClutterActor::allocate()
8371    * virtual method though, it indicates whether the child has its
8372    * absolute origin moved.  So we set it when child_moved is TRUE
8373    */
8374   if (child_moved)
8375     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8376
8377   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8378
8379   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8380                 _clutter_actor_get_debug_name (self));
8381
8382   klass = CLUTTER_ACTOR_GET_CLASS (self);
8383   klass->allocate (self, &real_allocation, flags);
8384
8385   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8386
8387   if (stage_allocation_changed)
8388     clutter_actor_queue_redraw (self);
8389 }
8390
8391 /**
8392  * clutter_actor_set_allocation:
8393  * @self: a #ClutterActor
8394  * @box: a #ClutterActorBox
8395  * @flags: allocation flags
8396  *
8397  * Stores the allocation of @self as defined by @box.
8398  *
8399  * This function can only be called from within the implementation of
8400  * the #ClutterActorClass.allocate() virtual function.
8401  *
8402  * The allocation should have been adjusted to take into account constraints,
8403  * alignment, and margin properties. If you are implementing a #ClutterActor
8404  * subclass that provides its own layout management policy for its children
8405  * instead of using a #ClutterLayoutManager delegate, you should not call
8406  * this function on the children of @self; instead, you should call
8407  * clutter_actor_allocate(), which will adjust the allocation box for
8408  * you.
8409  *
8410  * This function should only be used by subclasses of #ClutterActor
8411  * that wish to store their allocation but cannot chain up to the
8412  * parent's implementation; the default implementation of the
8413  * #ClutterActorClass.allocate() virtual function will call this
8414  * function.
8415  *
8416  * It is important to note that, while chaining up was the recommended
8417  * behaviour for #ClutterActor subclasses prior to the introduction of
8418  * this function, it is recommended to call clutter_actor_set_allocation()
8419  * instead.
8420  *
8421  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8422  * to handle the allocation of its children, this function will call
8423  * the clutter_layout_manager_allocate() function only if the
8424  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8425  * expected that the subclass will call clutter_layout_manager_allocate()
8426  * by itself. For instance, the following code:
8427  *
8428  * |[
8429  * static void
8430  * my_actor_allocate (ClutterActor *actor,
8431  *                    const ClutterActorBox *allocation,
8432  *                    ClutterAllocationFlags flags)
8433  * {
8434  *   ClutterActorBox new_alloc;
8435  *   ClutterAllocationFlags new_flags;
8436  *
8437  *   adjust_allocation (allocation, &amp;new_alloc);
8438  *
8439  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8440  *
8441  *   /&ast; this will use the layout manager set on the actor &ast;/
8442  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8443  * }
8444  * ]|
8445  *
8446  * is equivalent to this:
8447  *
8448  * |[
8449  * static void
8450  * my_actor_allocate (ClutterActor *actor,
8451  *                    const ClutterActorBox *allocation,
8452  *                    ClutterAllocationFlags flags)
8453  * {
8454  *   ClutterLayoutManager *layout;
8455  *   ClutterActorBox new_alloc;
8456  *
8457  *   adjust_allocation (allocation, &amp;new_alloc);
8458  *
8459  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8460  *
8461  *   layout = clutter_actor_get_layout_manager (actor);
8462  *   clutter_layout_manager_allocate (layout,
8463  *                                    CLUTTER_CONTAINER (actor),
8464  *                                    &amp;new_alloc,
8465  *                                    flags);
8466  * }
8467  * ]|
8468  *
8469  * Since: 1.10
8470  */
8471 void
8472 clutter_actor_set_allocation (ClutterActor           *self,
8473                               const ClutterActorBox  *box,
8474                               ClutterAllocationFlags  flags)
8475 {
8476   ClutterActorPrivate *priv;
8477   gboolean changed;
8478
8479   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8480   g_return_if_fail (box != NULL);
8481
8482   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8483     {
8484       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8485                   "can only be called from within the implementation of "
8486                   "the ClutterActor::allocate() virtual function.");
8487       return;
8488     }
8489
8490   priv = self->priv;
8491
8492   g_object_freeze_notify (G_OBJECT (self));
8493
8494   changed = clutter_actor_set_allocation_internal (self, box, flags);
8495
8496   /* we allocate our children before we notify changes in our geometry,
8497    * so that people connecting to properties will be able to get valid
8498    * data out of the sub-tree of the scene graph that has this actor at
8499    * the root.
8500    */
8501   clutter_actor_maybe_layout_children (self, box, flags);
8502
8503   if (changed)
8504     {
8505       ClutterActorBox signal_box = priv->allocation;
8506       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8507
8508       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8509                      &signal_box,
8510                      signal_flags);
8511     }
8512
8513   g_object_thaw_notify (G_OBJECT (self));
8514 }
8515
8516 /**
8517  * clutter_actor_set_geometry:
8518  * @self: A #ClutterActor
8519  * @geometry: A #ClutterGeometry
8520  *
8521  * Sets the actor's fixed position and forces its minimum and natural
8522  * size, in pixels. This means the untransformed actor will have the
8523  * given geometry. This is the same as calling clutter_actor_set_position()
8524  * and clutter_actor_set_size().
8525  *
8526  * Deprecated: 1.10: Use clutter_actor_set_position() and
8527  *   clutter_actor_set_size() instead.
8528  */
8529 void
8530 clutter_actor_set_geometry (ClutterActor          *self,
8531                             const ClutterGeometry *geometry)
8532 {
8533   g_object_freeze_notify (G_OBJECT (self));
8534
8535   clutter_actor_set_position (self, geometry->x, geometry->y);
8536   clutter_actor_set_size (self, geometry->width, geometry->height);
8537
8538   g_object_thaw_notify (G_OBJECT (self));
8539 }
8540
8541 /**
8542  * clutter_actor_get_geometry:
8543  * @self: A #ClutterActor
8544  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8545  *
8546  * Gets the size and position of an actor relative to its parent
8547  * actor. This is the same as calling clutter_actor_get_position() and
8548  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8549  * requested size and position if the actor's allocation is invalid.
8550  *
8551  * Deprecated: 1.10: Use clutter_actor_get_position() and
8552  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8553  *   instead.
8554  */
8555 void
8556 clutter_actor_get_geometry (ClutterActor    *self,
8557                             ClutterGeometry *geometry)
8558 {
8559   gfloat x, y, width, height;
8560
8561   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8562   g_return_if_fail (geometry != NULL);
8563
8564   clutter_actor_get_position (self, &x, &y);
8565   clutter_actor_get_size (self, &width, &height);
8566
8567   geometry->x = (int) x;
8568   geometry->y = (int) y;
8569   geometry->width = (int) width;
8570   geometry->height = (int) height;
8571 }
8572
8573 /**
8574  * clutter_actor_set_position:
8575  * @self: A #ClutterActor
8576  * @x: New left position of actor in pixels.
8577  * @y: New top position of actor in pixels.
8578  *
8579  * Sets the actor's fixed position in pixels relative to any parent
8580  * actor.
8581  *
8582  * If a layout manager is in use, this position will override the
8583  * layout manager and force a fixed position.
8584  */
8585 void
8586 clutter_actor_set_position (ClutterActor *self,
8587                             gfloat        x,
8588                             gfloat        y)
8589 {
8590   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8591
8592   g_object_freeze_notify (G_OBJECT (self));
8593
8594   clutter_actor_set_x (self, x);
8595   clutter_actor_set_y (self, y);
8596
8597   g_object_thaw_notify (G_OBJECT (self));
8598 }
8599
8600 /**
8601  * clutter_actor_get_fixed_position_set:
8602  * @self: A #ClutterActor
8603  *
8604  * Checks whether an actor has a fixed position set (and will thus be
8605  * unaffected by any layout manager).
8606  *
8607  * Return value: %TRUE if the fixed position is set on the actor
8608  *
8609  * Since: 0.8
8610  */
8611 gboolean
8612 clutter_actor_get_fixed_position_set (ClutterActor *self)
8613 {
8614   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8615
8616   return self->priv->position_set;
8617 }
8618
8619 /**
8620  * clutter_actor_set_fixed_position_set:
8621  * @self: A #ClutterActor
8622  * @is_set: whether to use fixed position
8623  *
8624  * Sets whether an actor has a fixed position set (and will thus be
8625  * unaffected by any layout manager).
8626  *
8627  * Since: 0.8
8628  */
8629 void
8630 clutter_actor_set_fixed_position_set (ClutterActor *self,
8631                                       gboolean      is_set)
8632 {
8633   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8634
8635   if (self->priv->position_set == (is_set != FALSE))
8636     return;
8637
8638   self->priv->position_set = is_set != FALSE;
8639   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8640
8641   clutter_actor_queue_relayout (self);
8642 }
8643
8644 /**
8645  * clutter_actor_move_by:
8646  * @self: A #ClutterActor
8647  * @dx: Distance to move Actor on X axis.
8648  * @dy: Distance to move Actor on Y axis.
8649  *
8650  * Moves an actor by the specified distance relative to its current
8651  * position in pixels.
8652  *
8653  * This function modifies the fixed position of an actor and thus removes
8654  * it from any layout management. Another way to move an actor is with an
8655  * anchor point, see clutter_actor_set_anchor_point().
8656  *
8657  * Since: 0.2
8658  */
8659 void
8660 clutter_actor_move_by (ClutterActor *self,
8661                        gfloat        dx,
8662                        gfloat        dy)
8663 {
8664   const ClutterLayoutInfo *info;
8665   gfloat x, y;
8666
8667   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8668
8669   info = _clutter_actor_get_layout_info_or_defaults (self);
8670   x = info->fixed_x;
8671   y = info->fixed_y;
8672
8673   clutter_actor_set_position (self, x + dx, y + dy);
8674 }
8675
8676 static void
8677 clutter_actor_set_min_width (ClutterActor *self,
8678                              gfloat        min_width)
8679 {
8680   ClutterActorPrivate *priv = self->priv;
8681   ClutterActorBox old = { 0, };
8682   ClutterLayoutInfo *info;
8683
8684   /* if we are setting the size on a top-level actor and the
8685    * backend only supports static top-levels (e.g. framebuffers)
8686    * then we ignore the passed value and we override it with
8687    * the stage implementation's preferred size.
8688    */
8689   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8690       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8691     return;
8692
8693   info = _clutter_actor_get_layout_info (self);
8694
8695   if (priv->min_width_set && min_width == info->min_width)
8696     return;
8697
8698   g_object_freeze_notify (G_OBJECT (self));
8699
8700   clutter_actor_store_old_geometry (self, &old);
8701
8702   info->min_width = min_width;
8703   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8704   clutter_actor_set_min_width_set (self, TRUE);
8705
8706   clutter_actor_notify_if_geometry_changed (self, &old);
8707
8708   g_object_thaw_notify (G_OBJECT (self));
8709
8710   clutter_actor_queue_relayout (self);
8711 }
8712
8713 static void
8714 clutter_actor_set_min_height (ClutterActor *self,
8715                               gfloat        min_height)
8716
8717 {
8718   ClutterActorPrivate *priv = self->priv;
8719   ClutterActorBox old = { 0, };
8720   ClutterLayoutInfo *info;
8721
8722   /* if we are setting the size on a top-level actor and the
8723    * backend only supports static top-levels (e.g. framebuffers)
8724    * then we ignore the passed value and we override it with
8725    * the stage implementation's preferred size.
8726    */
8727   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8728       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8729     return;
8730
8731   info = _clutter_actor_get_layout_info (self);
8732
8733   if (priv->min_height_set && min_height == info->min_height)
8734     return;
8735
8736   g_object_freeze_notify (G_OBJECT (self));
8737
8738   clutter_actor_store_old_geometry (self, &old);
8739
8740   info->min_height = min_height;
8741   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8742   clutter_actor_set_min_height_set (self, TRUE);
8743
8744   clutter_actor_notify_if_geometry_changed (self, &old);
8745
8746   g_object_thaw_notify (G_OBJECT (self));
8747
8748   clutter_actor_queue_relayout (self);
8749 }
8750
8751 static void
8752 clutter_actor_set_natural_width (ClutterActor *self,
8753                                  gfloat        natural_width)
8754 {
8755   ClutterActorPrivate *priv = self->priv;
8756   ClutterActorBox old = { 0, };
8757   ClutterLayoutInfo *info;
8758
8759   /* if we are setting the size on a top-level actor and the
8760    * backend only supports static top-levels (e.g. framebuffers)
8761    * then we ignore the passed value and we override it with
8762    * the stage implementation's preferred size.
8763    */
8764   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8765       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8766     return;
8767
8768   info = _clutter_actor_get_layout_info (self);
8769
8770   if (priv->natural_width_set && natural_width == info->natural_width)
8771     return;
8772
8773   g_object_freeze_notify (G_OBJECT (self));
8774
8775   clutter_actor_store_old_geometry (self, &old);
8776
8777   info->natural_width = natural_width;
8778   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8779   clutter_actor_set_natural_width_set (self, TRUE);
8780
8781   clutter_actor_notify_if_geometry_changed (self, &old);
8782
8783   g_object_thaw_notify (G_OBJECT (self));
8784
8785   clutter_actor_queue_relayout (self);
8786 }
8787
8788 static void
8789 clutter_actor_set_natural_height (ClutterActor *self,
8790                                   gfloat        natural_height)
8791 {
8792   ClutterActorPrivate *priv = self->priv;
8793   ClutterActorBox old = { 0, };
8794   ClutterLayoutInfo *info;
8795
8796   /* if we are setting the size on a top-level actor and the
8797    * backend only supports static top-levels (e.g. framebuffers)
8798    * then we ignore the passed value and we override it with
8799    * the stage implementation's preferred size.
8800    */
8801   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8802       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8803     return;
8804
8805   info = _clutter_actor_get_layout_info (self);
8806
8807   if (priv->natural_height_set && natural_height == info->natural_height)
8808     return;
8809
8810   g_object_freeze_notify (G_OBJECT (self));
8811
8812   clutter_actor_store_old_geometry (self, &old);
8813
8814   info->natural_height = natural_height;
8815   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8816   clutter_actor_set_natural_height_set (self, TRUE);
8817
8818   clutter_actor_notify_if_geometry_changed (self, &old);
8819
8820   g_object_thaw_notify (G_OBJECT (self));
8821
8822   clutter_actor_queue_relayout (self);
8823 }
8824
8825 static void
8826 clutter_actor_set_min_width_set (ClutterActor *self,
8827                                  gboolean      use_min_width)
8828 {
8829   ClutterActorPrivate *priv = self->priv;
8830   ClutterActorBox old = { 0, };
8831
8832   if (priv->min_width_set == (use_min_width != FALSE))
8833     return;
8834
8835   clutter_actor_store_old_geometry (self, &old);
8836
8837   priv->min_width_set = use_min_width != FALSE;
8838   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8839
8840   clutter_actor_notify_if_geometry_changed (self, &old);
8841
8842   clutter_actor_queue_relayout (self);
8843 }
8844
8845 static void
8846 clutter_actor_set_min_height_set (ClutterActor *self,
8847                                   gboolean      use_min_height)
8848 {
8849   ClutterActorPrivate *priv = self->priv;
8850   ClutterActorBox old = { 0, };
8851
8852   if (priv->min_height_set == (use_min_height != FALSE))
8853     return;
8854
8855   clutter_actor_store_old_geometry (self, &old);
8856
8857   priv->min_height_set = use_min_height != FALSE;
8858   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8859
8860   clutter_actor_notify_if_geometry_changed (self, &old);
8861
8862   clutter_actor_queue_relayout (self);
8863 }
8864
8865 static void
8866 clutter_actor_set_natural_width_set (ClutterActor *self,
8867                                      gboolean      use_natural_width)
8868 {
8869   ClutterActorPrivate *priv = self->priv;
8870   ClutterActorBox old = { 0, };
8871
8872   if (priv->natural_width_set == (use_natural_width != FALSE))
8873     return;
8874
8875   clutter_actor_store_old_geometry (self, &old);
8876
8877   priv->natural_width_set = use_natural_width != FALSE;
8878   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8879
8880   clutter_actor_notify_if_geometry_changed (self, &old);
8881
8882   clutter_actor_queue_relayout (self);
8883 }
8884
8885 static void
8886 clutter_actor_set_natural_height_set (ClutterActor *self,
8887                                       gboolean      use_natural_height)
8888 {
8889   ClutterActorPrivate *priv = self->priv;
8890   ClutterActorBox old = { 0, };
8891
8892   if (priv->natural_height_set == (use_natural_height != FALSE))
8893     return;
8894
8895   clutter_actor_store_old_geometry (self, &old);
8896
8897   priv->natural_height_set = use_natural_height != FALSE;
8898   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8899
8900   clutter_actor_notify_if_geometry_changed (self, &old);
8901
8902   clutter_actor_queue_relayout (self);
8903 }
8904
8905 /**
8906  * clutter_actor_set_request_mode:
8907  * @self: a #ClutterActor
8908  * @mode: the request mode
8909  *
8910  * Sets the geometry request mode of @self.
8911  *
8912  * The @mode determines the order for invoking
8913  * clutter_actor_get_preferred_width() and
8914  * clutter_actor_get_preferred_height()
8915  *
8916  * Since: 1.2
8917  */
8918 void
8919 clutter_actor_set_request_mode (ClutterActor       *self,
8920                                 ClutterRequestMode  mode)
8921 {
8922   ClutterActorPrivate *priv;
8923
8924   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8925
8926   priv = self->priv;
8927
8928   if (priv->request_mode == mode)
8929     return;
8930
8931   priv->request_mode = mode;
8932
8933   priv->needs_width_request = TRUE;
8934   priv->needs_height_request = TRUE;
8935
8936   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8937
8938   clutter_actor_queue_relayout (self);
8939 }
8940
8941 /**
8942  * clutter_actor_get_request_mode:
8943  * @self: a #ClutterActor
8944  *
8945  * Retrieves the geometry request mode of @self
8946  *
8947  * Return value: the request mode for the actor
8948  *
8949  * Since: 1.2
8950  */
8951 ClutterRequestMode
8952 clutter_actor_get_request_mode (ClutterActor *self)
8953 {
8954   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8955                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8956
8957   return self->priv->request_mode;
8958 }
8959
8960 /* variant of set_width() without checks and without notification
8961  * freeze+thaw, for internal usage only
8962  */
8963 static inline void
8964 clutter_actor_set_width_internal (ClutterActor *self,
8965                                   gfloat        width)
8966 {
8967   if (width >= 0)
8968     {
8969       /* the Stage will use the :min-width to control the minimum
8970        * width to be resized to, so we should not be setting it
8971        * along with the :natural-width
8972        */
8973       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8974         clutter_actor_set_min_width (self, width);
8975
8976       clutter_actor_set_natural_width (self, width);
8977     }
8978   else
8979     {
8980       /* we only unset the :natural-width for the Stage */
8981       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8982         clutter_actor_set_min_width_set (self, FALSE);
8983
8984       clutter_actor_set_natural_width_set (self, FALSE);
8985     }
8986 }
8987
8988 /* variant of set_height() without checks and without notification
8989  * freeze+thaw, for internal usage only
8990  */
8991 static inline void
8992 clutter_actor_set_height_internal (ClutterActor *self,
8993                                    gfloat        height)
8994 {
8995   if (height >= 0)
8996     {
8997       /* see the comment above in set_width_internal() */
8998       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8999         clutter_actor_set_min_height (self, height);
9000
9001       clutter_actor_set_natural_height (self, height);
9002     }
9003   else
9004     {
9005       /* see the comment above in set_width_internal() */
9006       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9007         clutter_actor_set_min_height_set (self, FALSE);
9008
9009       clutter_actor_set_natural_height_set (self, FALSE);
9010     }
9011 }
9012
9013 /**
9014  * clutter_actor_set_size:
9015  * @self: A #ClutterActor
9016  * @width: New width of actor in pixels, or -1
9017  * @height: New height of actor in pixels, or -1
9018  *
9019  * Sets the actor's size request in pixels. This overrides any
9020  * "normal" size request the actor would have. For example
9021  * a text actor might normally request the size of the text;
9022  * this function would force a specific size instead.
9023  *
9024  * If @width and/or @height are -1 the actor will use its
9025  * "normal" size request instead of overriding it, i.e.
9026  * you can "unset" the size with -1.
9027  *
9028  * This function sets or unsets both the minimum and natural size.
9029  */
9030 void
9031 clutter_actor_set_size (ClutterActor *self,
9032                         gfloat        width,
9033                         gfloat        height)
9034 {
9035   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9036
9037   g_object_freeze_notify (G_OBJECT (self));
9038
9039   clutter_actor_set_width (self, width);
9040   clutter_actor_set_height (self, height);
9041
9042   g_object_thaw_notify (G_OBJECT (self));
9043 }
9044
9045 /**
9046  * clutter_actor_get_size:
9047  * @self: A #ClutterActor
9048  * @width: (out) (allow-none): return location for the width, or %NULL.
9049  * @height: (out) (allow-none): return location for the height, or %NULL.
9050  *
9051  * This function tries to "do what you mean" and return
9052  * the size an actor will have. If the actor has a valid
9053  * allocation, the allocation will be returned; otherwise,
9054  * the actors natural size request will be returned.
9055  *
9056  * If you care whether you get the request vs. the allocation, you
9057  * should probably call a different function like
9058  * clutter_actor_get_allocation_box() or
9059  * clutter_actor_get_preferred_width().
9060  *
9061  * Since: 0.2
9062  */
9063 void
9064 clutter_actor_get_size (ClutterActor *self,
9065                         gfloat       *width,
9066                         gfloat       *height)
9067 {
9068   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9069
9070   if (width)
9071     *width = clutter_actor_get_width (self);
9072
9073   if (height)
9074     *height = clutter_actor_get_height (self);
9075 }
9076
9077 /**
9078  * clutter_actor_get_position:
9079  * @self: a #ClutterActor
9080  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9081  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9082  *
9083  * This function tries to "do what you mean" and tell you where the
9084  * actor is, prior to any transformations. Retrieves the fixed
9085  * position of an actor in pixels, if one has been set; otherwise, if
9086  * the allocation is valid, returns the actor's allocated position;
9087  * otherwise, returns 0,0.
9088  *
9089  * The returned position is in pixels.
9090  *
9091  * Since: 0.6
9092  */
9093 void
9094 clutter_actor_get_position (ClutterActor *self,
9095                             gfloat       *x,
9096                             gfloat       *y)
9097 {
9098   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9099
9100   if (x)
9101     *x = clutter_actor_get_x (self);
9102
9103   if (y)
9104     *y = clutter_actor_get_y (self);
9105 }
9106
9107 /**
9108  * clutter_actor_get_transformed_position:
9109  * @self: A #ClutterActor
9110  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9111  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9112  *
9113  * Gets the absolute position of an actor, in pixels relative to the stage.
9114  *
9115  * Since: 0.8
9116  */
9117 void
9118 clutter_actor_get_transformed_position (ClutterActor *self,
9119                                         gfloat       *x,
9120                                         gfloat       *y)
9121 {
9122   ClutterVertex v1;
9123   ClutterVertex v2;
9124
9125   v1.x = v1.y = v1.z = 0;
9126   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9127
9128   if (x)
9129     *x = v2.x;
9130
9131   if (y)
9132     *y = v2.y;
9133 }
9134
9135 /**
9136  * clutter_actor_get_transformed_size:
9137  * @self: A #ClutterActor
9138  * @width: (out) (allow-none): return location for the width, or %NULL
9139  * @height: (out) (allow-none): return location for the height, or %NULL
9140  *
9141  * Gets the absolute size of an actor in pixels, taking into account the
9142  * scaling factors.
9143  *
9144  * If the actor has a valid allocation, the allocated size will be used.
9145  * If the actor has not a valid allocation then the preferred size will
9146  * be transformed and returned.
9147  *
9148  * If you want the transformed allocation, see
9149  * clutter_actor_get_abs_allocation_vertices() instead.
9150  *
9151  * <note>When the actor (or one of its ancestors) is rotated around the
9152  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9153  * as a generic quadrangle; in that case this function returns the size
9154  * of the smallest rectangle that encapsulates the entire quad. Please
9155  * note that in this case no assumptions can be made about the relative
9156  * position of this envelope to the absolute position of the actor, as
9157  * returned by clutter_actor_get_transformed_position(); if you need this
9158  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9159  * to get the coords of the actual quadrangle.</note>
9160  *
9161  * Since: 0.8
9162  */
9163 void
9164 clutter_actor_get_transformed_size (ClutterActor *self,
9165                                     gfloat       *width,
9166                                     gfloat       *height)
9167 {
9168   ClutterActorPrivate *priv;
9169   ClutterVertex v[4];
9170   gfloat x_min, x_max, y_min, y_max;
9171   gint i;
9172
9173   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9174
9175   priv = self->priv;
9176
9177   /* if the actor hasn't been allocated yet, get the preferred
9178    * size and transform that
9179    */
9180   if (priv->needs_allocation)
9181     {
9182       gfloat natural_width, natural_height;
9183       ClutterActorBox box;
9184
9185       /* Make a fake allocation to transform.
9186        *
9187        * NB: _clutter_actor_transform_and_project_box expects a box in
9188        * the actor's coordinate space... */
9189
9190       box.x1 = 0;
9191       box.y1 = 0;
9192
9193       natural_width = natural_height = 0;
9194       clutter_actor_get_preferred_size (self, NULL, NULL,
9195                                         &natural_width,
9196                                         &natural_height);
9197
9198       box.x2 = natural_width;
9199       box.y2 = natural_height;
9200
9201       _clutter_actor_transform_and_project_box (self, &box, v);
9202     }
9203   else
9204     clutter_actor_get_abs_allocation_vertices (self, v);
9205
9206   x_min = x_max = v[0].x;
9207   y_min = y_max = v[0].y;
9208
9209   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9210     {
9211       if (v[i].x < x_min)
9212         x_min = v[i].x;
9213
9214       if (v[i].x > x_max)
9215         x_max = v[i].x;
9216
9217       if (v[i].y < y_min)
9218         y_min = v[i].y;
9219
9220       if (v[i].y > y_max)
9221         y_max = v[i].y;
9222     }
9223
9224   if (width)
9225     *width  = x_max - x_min;
9226
9227   if (height)
9228     *height = y_max - y_min;
9229 }
9230
9231 /**
9232  * clutter_actor_get_width:
9233  * @self: A #ClutterActor
9234  *
9235  * Retrieves the width of a #ClutterActor.
9236  *
9237  * If the actor has a valid allocation, this function will return the
9238  * width of the allocated area given to the actor.
9239  *
9240  * If the actor does not have a valid allocation, this function will
9241  * return the actor's natural width, that is the preferred width of
9242  * the actor.
9243  *
9244  * If you care whether you get the preferred width or the width that
9245  * has been assigned to the actor, you should probably call a different
9246  * function like clutter_actor_get_allocation_box() to retrieve the
9247  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9248  * preferred width.
9249  *
9250  * If an actor has a fixed width, for instance a width that has been
9251  * assigned using clutter_actor_set_width(), the width returned will
9252  * be the same value.
9253  *
9254  * Return value: the width of the actor, in pixels
9255  */
9256 gfloat
9257 clutter_actor_get_width (ClutterActor *self)
9258 {
9259   ClutterActorPrivate *priv;
9260
9261   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9262
9263   priv = self->priv;
9264
9265   if (priv->needs_allocation)
9266     {
9267       gfloat natural_width = 0;
9268
9269       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9270         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9271       else
9272         {
9273           gfloat natural_height = 0;
9274
9275           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9276           clutter_actor_get_preferred_width (self, natural_height,
9277                                              NULL,
9278                                              &natural_width);
9279         }
9280
9281       return natural_width;
9282     }
9283   else
9284     return priv->allocation.x2 - priv->allocation.x1;
9285 }
9286
9287 /**
9288  * clutter_actor_get_height:
9289  * @self: A #ClutterActor
9290  *
9291  * Retrieves the height of a #ClutterActor.
9292  *
9293  * If the actor has a valid allocation, this function will return the
9294  * height of the allocated area given to the actor.
9295  *
9296  * If the actor does not have a valid allocation, this function will
9297  * return the actor's natural height, that is the preferred height of
9298  * the actor.
9299  *
9300  * If you care whether you get the preferred height or the height that
9301  * has been assigned to the actor, you should probably call a different
9302  * function like clutter_actor_get_allocation_box() to retrieve the
9303  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9304  * preferred height.
9305  *
9306  * If an actor has a fixed height, for instance a height that has been
9307  * assigned using clutter_actor_set_height(), the height returned will
9308  * be the same value.
9309  *
9310  * Return value: the height of the actor, in pixels
9311  */
9312 gfloat
9313 clutter_actor_get_height (ClutterActor *self)
9314 {
9315   ClutterActorPrivate *priv;
9316
9317   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9318
9319   priv = self->priv;
9320
9321   if (priv->needs_allocation)
9322     {
9323       gfloat natural_height = 0;
9324
9325       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9326         {
9327           gfloat natural_width = 0;
9328
9329           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9330           clutter_actor_get_preferred_height (self, natural_width,
9331                                               NULL, &natural_height);
9332         }
9333       else
9334         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9335
9336       return natural_height;
9337     }
9338   else
9339     return priv->allocation.y2 - priv->allocation.y1;
9340 }
9341
9342 /**
9343  * clutter_actor_set_width:
9344  * @self: A #ClutterActor
9345  * @width: Requested new width for the actor, in pixels, or -1
9346  *
9347  * Forces a width on an actor, causing the actor's preferred width
9348  * and height (if any) to be ignored.
9349  *
9350  * If @width is -1 the actor will use its preferred width request
9351  * instead of overriding it, i.e. you can "unset" the width with -1.
9352  *
9353  * This function sets both the minimum and natural size of the actor.
9354  *
9355  * since: 0.2
9356  */
9357 void
9358 clutter_actor_set_width (ClutterActor *self,
9359                          gfloat        width)
9360 {
9361   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9362
9363   if (clutter_actor_get_easing_duration (self) != 0)
9364     {
9365       ClutterTransition *transition;
9366
9367       transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9368       if (transition == NULL)
9369         {
9370           float old_width = clutter_actor_get_width (self);
9371
9372           transition = _clutter_actor_create_transition (self,
9373                                                          obj_props[PROP_WIDTH],
9374                                                          old_width,
9375                                                          width);
9376           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9377         }
9378       else
9379         _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9380
9381       clutter_actor_queue_relayout (self);
9382     }
9383   else
9384     {
9385       g_object_freeze_notify (G_OBJECT (self));
9386
9387       clutter_actor_set_width_internal (self, width);
9388
9389       g_object_thaw_notify (G_OBJECT (self));
9390     }
9391 }
9392
9393 /**
9394  * clutter_actor_set_height:
9395  * @self: A #ClutterActor
9396  * @height: Requested new height for the actor, in pixels, or -1
9397  *
9398  * Forces a height on an actor, causing the actor's preferred width
9399  * and height (if any) to be ignored.
9400  *
9401  * If @height is -1 the actor will use its preferred height instead of
9402  * overriding it, i.e. you can "unset" the height with -1.
9403  *
9404  * This function sets both the minimum and natural size of the actor.
9405  *
9406  * since: 0.2
9407  */
9408 void
9409 clutter_actor_set_height (ClutterActor *self,
9410                           gfloat        height)
9411 {
9412   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9413
9414   if (clutter_actor_get_easing_duration (self) != 0)
9415     {
9416       ClutterTransition *transition;
9417
9418       transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9419       if (transition ==  NULL)
9420         {
9421           float old_height = clutter_actor_get_height (self);
9422
9423           transition = _clutter_actor_create_transition (self,
9424                                                          obj_props[PROP_HEIGHT],
9425                                                          old_height,
9426                                                          height);
9427           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9428         }
9429       else
9430         _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9431
9432       clutter_actor_queue_relayout (self);
9433     }
9434   else
9435     {
9436       g_object_freeze_notify (G_OBJECT (self));
9437
9438       clutter_actor_set_height_internal (self, height);
9439
9440       g_object_thaw_notify (G_OBJECT (self));
9441     }
9442 }
9443
9444 static inline void
9445 clutter_actor_set_x_internal (ClutterActor *self,
9446                               float         x)
9447 {
9448   ClutterActorPrivate *priv = self->priv;
9449   ClutterLayoutInfo *linfo;
9450   ClutterActorBox old = { 0, };
9451
9452   linfo = _clutter_actor_get_layout_info (self);
9453
9454   if (priv->position_set && linfo->fixed_x == x)
9455     return;
9456
9457   clutter_actor_store_old_geometry (self, &old);
9458
9459   linfo->fixed_x = x;
9460   clutter_actor_set_fixed_position_set (self, TRUE);
9461
9462   clutter_actor_notify_if_geometry_changed (self, &old);
9463
9464   clutter_actor_queue_relayout (self);
9465 }
9466
9467 static inline void
9468 clutter_actor_set_y_internal (ClutterActor *self,
9469                               float         y)
9470 {
9471   ClutterActorPrivate *priv = self->priv;
9472   ClutterLayoutInfo *linfo;
9473   ClutterActorBox old = { 0, };
9474
9475   linfo = _clutter_actor_get_layout_info (self);
9476
9477   if (priv->position_set && linfo->fixed_y == y)
9478     return;
9479
9480   clutter_actor_store_old_geometry (self, &old);
9481
9482   linfo->fixed_y = y;
9483   clutter_actor_set_fixed_position_set (self, TRUE);
9484
9485   clutter_actor_notify_if_geometry_changed (self, &old);
9486
9487   clutter_actor_queue_relayout (self);
9488 }
9489
9490 /**
9491  * clutter_actor_set_x:
9492  * @self: a #ClutterActor
9493  * @x: the actor's position on the X axis
9494  *
9495  * Sets the actor's X coordinate, relative to its parent, in pixels.
9496  *
9497  * Overrides any layout manager and forces a fixed position for
9498  * the actor.
9499  *
9500  * The #ClutterActor:x property is animatable.
9501  *
9502  * Since: 0.6
9503  */
9504 void
9505 clutter_actor_set_x (ClutterActor *self,
9506                      gfloat        x)
9507 {
9508   const ClutterLayoutInfo *linfo;
9509
9510   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9511
9512   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9513
9514   if (clutter_actor_get_easing_duration (self) != 0)
9515     {
9516       ClutterTransition *transition;
9517
9518       transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9519       if (transition == NULL)
9520         {
9521           transition = _clutter_actor_create_transition (self,
9522                                                          obj_props[PROP_X],
9523                                                          linfo->fixed_x,
9524                                                          x);
9525
9526           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9527         }
9528       else
9529         _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9530
9531       clutter_actor_queue_relayout (self);
9532     }
9533   else
9534     clutter_actor_set_x_internal (self, x);
9535 }
9536
9537 /**
9538  * clutter_actor_set_y:
9539  * @self: a #ClutterActor
9540  * @y: the actor's position on the Y axis
9541  *
9542  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9543  *
9544  * Overrides any layout manager and forces a fixed position for
9545  * the actor.
9546  *
9547  * The #ClutterActor:y property is animatable.
9548  *
9549  * Since: 0.6
9550  */
9551 void
9552 clutter_actor_set_y (ClutterActor *self,
9553                      gfloat        y)
9554 {
9555   const ClutterLayoutInfo *linfo;
9556
9557   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9558
9559   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9560
9561   if (clutter_actor_get_easing_duration (self) != 0)
9562     {
9563       ClutterTransition *transition;
9564
9565       transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9566       if (transition == NULL)
9567         {
9568           transition = _clutter_actor_create_transition (self,
9569                                                          obj_props[PROP_Y],
9570                                                          linfo->fixed_y,
9571                                                          y);
9572
9573           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9574         }
9575       else
9576         _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9577
9578       clutter_actor_queue_relayout (self);
9579     }
9580   else
9581     clutter_actor_set_y_internal (self, y);
9582
9583   clutter_actor_queue_relayout (self);
9584 }
9585
9586 /**
9587  * clutter_actor_get_x:
9588  * @self: A #ClutterActor
9589  *
9590  * Retrieves the X coordinate of a #ClutterActor.
9591  *
9592  * This function tries to "do what you mean", by returning the
9593  * correct value depending on the actor's state.
9594  *
9595  * If the actor has a valid allocation, this function will return
9596  * the X coordinate of the origin of the allocation box.
9597  *
9598  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9599  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9600  * function will return that coordinate.
9601  *
9602  * If both the allocation and a fixed position are missing, this function
9603  * will return 0.
9604  *
9605  * Return value: the X coordinate, in pixels, ignoring any
9606  *   transformation (i.e. scaling, rotation)
9607  */
9608 gfloat
9609 clutter_actor_get_x (ClutterActor *self)
9610 {
9611   ClutterActorPrivate *priv;
9612
9613   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9614
9615   priv = self->priv;
9616
9617   if (priv->needs_allocation)
9618     {
9619       if (priv->position_set)
9620         {
9621           const ClutterLayoutInfo *info;
9622
9623           info = _clutter_actor_get_layout_info_or_defaults (self);
9624
9625           return info->fixed_x;
9626         }
9627       else
9628         return 0;
9629     }
9630   else
9631     return priv->allocation.x1;
9632 }
9633
9634 /**
9635  * clutter_actor_get_y:
9636  * @self: A #ClutterActor
9637  *
9638  * Retrieves the Y coordinate of a #ClutterActor.
9639  *
9640  * This function tries to "do what you mean", by returning the
9641  * correct value depending on the actor's state.
9642  *
9643  * If the actor has a valid allocation, this function will return
9644  * the Y coordinate of the origin of the allocation box.
9645  *
9646  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9647  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9648  * function will return that coordinate.
9649  *
9650  * If both the allocation and a fixed position are missing, this function
9651  * will return 0.
9652  *
9653  * Return value: the Y coordinate, in pixels, ignoring any
9654  *   transformation (i.e. scaling, rotation)
9655  */
9656 gfloat
9657 clutter_actor_get_y (ClutterActor *self)
9658 {
9659   ClutterActorPrivate *priv;
9660
9661   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9662
9663   priv = self->priv;
9664
9665   if (priv->needs_allocation)
9666     {
9667       if (priv->position_set)
9668         {
9669           const ClutterLayoutInfo *info;
9670
9671           info = _clutter_actor_get_layout_info_or_defaults (self);
9672
9673           return info->fixed_y;
9674         }
9675       else
9676         return 0;
9677     }
9678   else
9679     return priv->allocation.y1;
9680 }
9681
9682 /**
9683  * clutter_actor_set_scale:
9684  * @self: A #ClutterActor
9685  * @scale_x: double factor to scale actor by horizontally.
9686  * @scale_y: double factor to scale actor by vertically.
9687  *
9688  * Scales an actor with the given factors. The scaling is relative to
9689  * the scale center and the anchor point. The scale center is
9690  * unchanged by this function and defaults to 0,0.
9691  *
9692  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9693  * animatable.
9694  *
9695  * Since: 0.2
9696  */
9697 void
9698 clutter_actor_set_scale (ClutterActor *self,
9699                          gdouble       scale_x,
9700                          gdouble       scale_y)
9701 {
9702   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9703
9704   g_object_freeze_notify (G_OBJECT (self));
9705
9706   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9707   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9708
9709   g_object_thaw_notify (G_OBJECT (self));
9710 }
9711
9712 /**
9713  * clutter_actor_set_scale_full:
9714  * @self: A #ClutterActor
9715  * @scale_x: double factor to scale actor by horizontally.
9716  * @scale_y: double factor to scale actor by vertically.
9717  * @center_x: X coordinate of the center of the scale.
9718  * @center_y: Y coordinate of the center of the scale
9719  *
9720  * Scales an actor with the given factors around the given center
9721  * point. The center point is specified in pixels relative to the
9722  * anchor point (usually the top left corner of the actor).
9723  *
9724  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9725  * are animatable.
9726  *
9727  * Since: 1.0
9728  */
9729 void
9730 clutter_actor_set_scale_full (ClutterActor *self,
9731                               gdouble       scale_x,
9732                               gdouble       scale_y,
9733                               gfloat        center_x,
9734                               gfloat        center_y)
9735 {
9736   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9737
9738   g_object_freeze_notify (G_OBJECT (self));
9739
9740   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9741   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9742   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9743   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9744
9745   g_object_thaw_notify (G_OBJECT (self));
9746 }
9747
9748 /**
9749  * clutter_actor_set_scale_with_gravity:
9750  * @self: A #ClutterActor
9751  * @scale_x: double factor to scale actor by horizontally.
9752  * @scale_y: double factor to scale actor by vertically.
9753  * @gravity: the location of the scale center expressed as a compass
9754  * direction.
9755  *
9756  * Scales an actor with the given factors around the given
9757  * center point. The center point is specified as one of the compass
9758  * directions in #ClutterGravity. For example, setting it to north
9759  * will cause the top of the actor to remain unchanged and the rest of
9760  * the actor to expand left, right and downwards.
9761  *
9762  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9763  * animatable.
9764  *
9765  * Since: 1.0
9766  */
9767 void
9768 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9769                                       gdouble         scale_x,
9770                                       gdouble         scale_y,
9771                                       ClutterGravity  gravity)
9772 {
9773   ClutterTransformInfo *info;
9774   GObject *obj;
9775
9776   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9777
9778   obj = G_OBJECT (self);
9779
9780   g_object_freeze_notify (obj);
9781
9782   info = _clutter_actor_get_transform_info (self);
9783   info->scale_x = scale_x;
9784   info->scale_y = scale_y;
9785
9786   if (gravity == CLUTTER_GRAVITY_NONE)
9787     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9788   else
9789     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9790
9791   self->priv->transform_valid = FALSE;
9792
9793   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9794   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9795   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9796   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9797   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9798
9799   clutter_actor_queue_redraw (self);
9800
9801   g_object_thaw_notify (obj);
9802 }
9803
9804 /**
9805  * clutter_actor_get_scale:
9806  * @self: A #ClutterActor
9807  * @scale_x: (out) (allow-none): Location to store horizonal
9808  *   scale factor, or %NULL.
9809  * @scale_y: (out) (allow-none): Location to store vertical
9810  *   scale factor, or %NULL.
9811  *
9812  * Retrieves an actors scale factors.
9813  *
9814  * Since: 0.2
9815  */
9816 void
9817 clutter_actor_get_scale (ClutterActor *self,
9818                          gdouble      *scale_x,
9819                          gdouble      *scale_y)
9820 {
9821   const ClutterTransformInfo *info;
9822
9823   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9824
9825   info = _clutter_actor_get_transform_info_or_defaults (self);
9826
9827   if (scale_x)
9828     *scale_x = info->scale_x;
9829
9830   if (scale_y)
9831     *scale_y = info->scale_y;
9832 }
9833
9834 /**
9835  * clutter_actor_get_scale_center:
9836  * @self: A #ClutterActor
9837  * @center_x: (out) (allow-none): Location to store the X position
9838  *   of the scale center, or %NULL.
9839  * @center_y: (out) (allow-none): Location to store the Y position
9840  *   of the scale center, or %NULL.
9841  *
9842  * Retrieves the scale center coordinate in pixels relative to the top
9843  * left corner of the actor. If the scale center was specified using a
9844  * #ClutterGravity this will calculate the pixel offset using the
9845  * current size of the actor.
9846  *
9847  * Since: 1.0
9848  */
9849 void
9850 clutter_actor_get_scale_center (ClutterActor *self,
9851                                 gfloat       *center_x,
9852                                 gfloat       *center_y)
9853 {
9854   const ClutterTransformInfo *info;
9855
9856   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9857
9858   info = _clutter_actor_get_transform_info_or_defaults (self);
9859
9860   clutter_anchor_coord_get_units (self, &info->scale_center,
9861                                   center_x,
9862                                   center_y,
9863                                   NULL);
9864 }
9865
9866 /**
9867  * clutter_actor_get_scale_gravity:
9868  * @self: A #ClutterActor
9869  *
9870  * Retrieves the scale center as a compass direction. If the scale
9871  * center was specified in pixels or units this will return
9872  * %CLUTTER_GRAVITY_NONE.
9873  *
9874  * Return value: the scale gravity
9875  *
9876  * Since: 1.0
9877  */
9878 ClutterGravity
9879 clutter_actor_get_scale_gravity (ClutterActor *self)
9880 {
9881   const ClutterTransformInfo *info;
9882
9883   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9884
9885   info = _clutter_actor_get_transform_info_or_defaults (self);
9886
9887   return clutter_anchor_coord_get_gravity (&info->scale_center);
9888 }
9889
9890 static inline void
9891 clutter_actor_set_opacity_internal (ClutterActor *self,
9892                                     guint8        opacity)
9893 {
9894   ClutterActorPrivate *priv = self->priv;
9895
9896   if (priv->opacity != opacity)
9897     {
9898       priv->opacity = opacity;
9899
9900       /* Queue a redraw from the flatten effect so that it can use
9901          its cached image if available instead of having to redraw the
9902          actual actor. If it doesn't end up using the FBO then the
9903          effect is still able to continue the paint anyway. If there
9904          is no flatten effect yet then this is equivalent to queueing
9905          a full redraw */
9906       _clutter_actor_queue_redraw_full (self,
9907                                         0, /* flags */
9908                                         NULL, /* clip */
9909                                         priv->flatten_effect);
9910
9911       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9912     }
9913 }
9914
9915 /**
9916  * clutter_actor_set_opacity:
9917  * @self: A #ClutterActor
9918  * @opacity: New opacity value for the actor.
9919  *
9920  * Sets the actor's opacity, with zero being completely transparent and
9921  * 255 (0xff) being fully opaque.
9922  *
9923  * The #ClutterActor:opacity property is animatable.
9924  */
9925 void
9926 clutter_actor_set_opacity (ClutterActor *self,
9927                            guint8        opacity)
9928 {
9929   ClutterActorPrivate *priv;
9930
9931   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9932
9933   priv = self->priv;
9934
9935   if (clutter_actor_get_easing_duration (self) != 0)
9936     {
9937       ClutterTransition *transition;
9938
9939       transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9940       if (transition == NULL)
9941         {
9942           transition = _clutter_actor_create_transition (self,
9943                                                          obj_props[PROP_OPACITY],
9944                                                          priv->opacity,
9945                                                          opacity);
9946           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9947         }
9948       else
9949         _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9950
9951       clutter_actor_queue_redraw (self);
9952     }
9953   else
9954     clutter_actor_set_opacity_internal (self, opacity);
9955 }
9956
9957 /*
9958  * clutter_actor_get_paint_opacity_internal:
9959  * @self: a #ClutterActor
9960  *
9961  * Retrieves the absolute opacity of the actor, as it appears on the stage
9962  *
9963  * This function does not do type checks
9964  *
9965  * Return value: the absolute opacity of the actor
9966  */
9967 static guint8
9968 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9969 {
9970   ClutterActorPrivate *priv = self->priv;
9971   ClutterActor *parent;
9972
9973   /* override the top-level opacity to always be 255; even in
9974    * case of ClutterStage:use-alpha being TRUE we want the rest
9975    * of the scene to be painted
9976    */
9977   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9978     return 255;
9979
9980   if (priv->opacity_override >= 0)
9981     return priv->opacity_override;
9982
9983   parent = priv->parent;
9984
9985   /* Factor in the actual actors opacity with parents */
9986   if (parent != NULL)
9987     {
9988       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9989
9990       if (opacity != 0xff)
9991         return (opacity * priv->opacity) / 0xff;
9992     }
9993
9994   return priv->opacity;
9995
9996 }
9997
9998 /**
9999  * clutter_actor_get_paint_opacity:
10000  * @self: A #ClutterActor
10001  *
10002  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10003  *
10004  * This function traverses the hierarchy chain and composites the opacity of
10005  * the actor with that of its parents.
10006  *
10007  * This function is intended for subclasses to use in the paint virtual
10008  * function, to paint themselves with the correct opacity.
10009  *
10010  * Return value: The actor opacity value.
10011  *
10012  * Since: 0.8
10013  */
10014 guint8
10015 clutter_actor_get_paint_opacity (ClutterActor *self)
10016 {
10017   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10018
10019   return clutter_actor_get_paint_opacity_internal (self);
10020 }
10021
10022 /**
10023  * clutter_actor_get_opacity:
10024  * @self: a #ClutterActor
10025  *
10026  * Retrieves the opacity value of an actor, as set by
10027  * clutter_actor_set_opacity().
10028  *
10029  * For retrieving the absolute opacity of the actor inside a paint
10030  * virtual function, see clutter_actor_get_paint_opacity().
10031  *
10032  * Return value: the opacity of the actor
10033  */
10034 guint8
10035 clutter_actor_get_opacity (ClutterActor *self)
10036 {
10037   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10038
10039   return self->priv->opacity;
10040 }
10041
10042 /**
10043  * clutter_actor_set_offscreen_redirect:
10044  * @self: A #ClutterActor
10045  * @redirect: New offscreen redirect flags for the actor.
10046  *
10047  * Defines the circumstances where the actor should be redirected into
10048  * an offscreen image. The offscreen image is used to flatten the
10049  * actor into a single image while painting for two main reasons.
10050  * Firstly, when the actor is painted a second time without any of its
10051  * contents changing it can simply repaint the cached image without
10052  * descending further down the actor hierarchy. Secondly, it will make
10053  * the opacity look correct even if there are overlapping primitives
10054  * in the actor.
10055  *
10056  * Caching the actor could in some cases be a performance win and in
10057  * some cases be a performance lose so it is important to determine
10058  * which value is right for an actor before modifying this value. For
10059  * example, there is never any reason to flatten an actor that is just
10060  * a single texture (such as a #ClutterTexture) because it is
10061  * effectively already cached in an image so the offscreen would be
10062  * redundant. Also if the actor contains primitives that are far apart
10063  * with a large transparent area in the middle (such as a large
10064  * CluterGroup with a small actor in the top left and a small actor in
10065  * the bottom right) then the cached image will contain the entire
10066  * image of the large area and the paint will waste time blending all
10067  * of the transparent pixels in the middle.
10068  *
10069  * The default method of implementing opacity on a container simply
10070  * forwards on the opacity to all of the children. If the children are
10071  * overlapping then it will appear as if they are two separate glassy
10072  * objects and there will be a break in the color where they
10073  * overlap. By redirecting to an offscreen buffer it will be as if the
10074  * two opaque objects are combined into one and then made transparent
10075  * which is usually what is expected.
10076  *
10077  * The image below demonstrates the difference between redirecting and
10078  * not. The image shows two Clutter groups, each containing a red and
10079  * a green rectangle which overlap. The opacity on the group is set to
10080  * 128 (which is 50%). When the offscreen redirect is not used, the
10081  * red rectangle can be seen through the blue rectangle as if the two
10082  * rectangles were separately transparent. When the redirect is used
10083  * the group as a whole is transparent instead so the red rectangle is
10084  * not visible where they overlap.
10085  *
10086  * <figure id="offscreen-redirect">
10087  *   <title>Sample of using an offscreen redirect for transparency</title>
10088  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10089  * </figure>
10090  *
10091  * The default value for this property is 0, so we effectively will
10092  * never redirect an actor offscreen by default. This means that there
10093  * are times that transparent actors may look glassy as described
10094  * above. The reason this is the default is because there is a
10095  * performance trade off between quality and performance here. In many
10096  * cases the default form of glassy opacity looks good enough, but if
10097  * it's not you will need to set the
10098  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10099  * redirection for opacity.
10100  *
10101  * Custom actors that don't contain any overlapping primitives are
10102  * recommended to override the has_overlaps() virtual to return %FALSE
10103  * for maximum efficiency.
10104  *
10105  * Since: 1.8
10106  */
10107 void
10108 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10109                                       ClutterOffscreenRedirect redirect)
10110 {
10111   ClutterActorPrivate *priv;
10112
10113   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10114
10115   priv = self->priv;
10116
10117   if (priv->offscreen_redirect != redirect)
10118     {
10119       priv->offscreen_redirect = redirect;
10120
10121       /* Queue a redraw from the effect so that it can use its cached
10122          image if available instead of having to redraw the actual
10123          actor. If it doesn't end up using the FBO then the effect is
10124          still able to continue the paint anyway. If there is no
10125          effect then this is equivalent to queuing a full redraw */
10126       _clutter_actor_queue_redraw_full (self,
10127                                         0, /* flags */
10128                                         NULL, /* clip */
10129                                         priv->flatten_effect);
10130
10131       g_object_notify_by_pspec (G_OBJECT (self),
10132                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10133     }
10134 }
10135
10136 /**
10137  * clutter_actor_get_offscreen_redirect:
10138  * @self: a #ClutterActor
10139  *
10140  * Retrieves whether to redirect the actor to an offscreen buffer, as
10141  * set by clutter_actor_set_offscreen_redirect().
10142  *
10143  * Return value: the value of the offscreen-redirect property of the actor
10144  *
10145  * Since: 1.8
10146  */
10147 ClutterOffscreenRedirect
10148 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10149 {
10150   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10151
10152   return self->priv->offscreen_redirect;
10153 }
10154
10155 /**
10156  * clutter_actor_set_name:
10157  * @self: A #ClutterActor
10158  * @name: Textual tag to apply to actor
10159  *
10160  * Sets the given name to @self. The name can be used to identify
10161  * a #ClutterActor.
10162  */
10163 void
10164 clutter_actor_set_name (ClutterActor *self,
10165                         const gchar  *name)
10166 {
10167   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10168
10169   g_free (self->priv->name);
10170   self->priv->name = g_strdup (name);
10171
10172   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10173 }
10174
10175 /**
10176  * clutter_actor_get_name:
10177  * @self: A #ClutterActor
10178  *
10179  * Retrieves the name of @self.
10180  *
10181  * Return value: the name of the actor, or %NULL. The returned string is
10182  *   owned by the actor and should not be modified or freed.
10183  */
10184 const gchar *
10185 clutter_actor_get_name (ClutterActor *self)
10186 {
10187   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10188
10189   return self->priv->name;
10190 }
10191
10192 /**
10193  * clutter_actor_get_gid:
10194  * @self: A #ClutterActor
10195  *
10196  * Retrieves the unique id for @self.
10197  *
10198  * Return value: Globally unique value for this object instance.
10199  *
10200  * Since: 0.6
10201  *
10202  * Deprecated: 1.8: The id is not used any longer.
10203  */
10204 guint32
10205 clutter_actor_get_gid (ClutterActor *self)
10206 {
10207   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10208
10209   return self->priv->id;
10210 }
10211
10212 static inline void
10213 clutter_actor_set_depth_internal (ClutterActor *self,
10214                                   float         depth)
10215 {
10216   ClutterTransformInfo *info;
10217
10218   info = _clutter_actor_get_transform_info (self);
10219
10220   if (info->depth != depth)
10221     {
10222       /* Sets Z value - XXX 2.0: should we invert? */
10223       info->depth = depth;
10224
10225       self->priv->transform_valid = FALSE;
10226
10227       /* FIXME - remove this crap; sadly, there are still containers
10228        * in Clutter that depend on this utter brain damage
10229        */
10230       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10231
10232       clutter_actor_queue_redraw (self);
10233
10234       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10235     }
10236 }
10237
10238 /**
10239  * clutter_actor_set_depth:
10240  * @self: a #ClutterActor
10241  * @depth: Z co-ord
10242  *
10243  * Sets the Z coordinate of @self to @depth.
10244  *
10245  * The unit used by @depth is dependant on the perspective setup. See
10246  * also clutter_stage_set_perspective().
10247  */
10248 void
10249 clutter_actor_set_depth (ClutterActor *self,
10250                          gfloat        depth)
10251 {
10252   const ClutterTransformInfo *tinfo;
10253
10254   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10255
10256   tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10257
10258   if (clutter_actor_get_easing_duration (self) != 0)
10259     {
10260       ClutterTransition *transition;
10261
10262       transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10263       if (transition == NULL)
10264         {
10265           transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10266                                                          tinfo->depth,
10267                                                          depth);
10268           clutter_timeline_start (CLUTTER_TIMELINE (transition));
10269         }
10270       else
10271         _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10272
10273       clutter_actor_queue_redraw (self);
10274     }
10275   else
10276     clutter_actor_set_depth_internal (self, depth);
10277 }
10278
10279 /**
10280  * clutter_actor_get_depth:
10281  * @self: a #ClutterActor
10282  *
10283  * Retrieves the depth of @self.
10284  *
10285  * Return value: the depth of the actor
10286  */
10287 gfloat
10288 clutter_actor_get_depth (ClutterActor *self)
10289 {
10290   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10291
10292   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10293 }
10294
10295 /**
10296  * clutter_actor_set_rotation:
10297  * @self: a #ClutterActor
10298  * @axis: the axis of rotation
10299  * @angle: the angle of rotation
10300  * @x: X coordinate of the rotation center
10301  * @y: Y coordinate of the rotation center
10302  * @z: Z coordinate of the rotation center
10303  *
10304  * Sets the rotation angle of @self around the given axis.
10305  *
10306  * The rotation center coordinates used depend on the value of @axis:
10307  * <itemizedlist>
10308  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10309  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10310  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10311  * </itemizedlist>
10312  *
10313  * The rotation coordinates are relative to the anchor point of the
10314  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10315  * point is set, the upper left corner is assumed as the origin.
10316  *
10317  * Since: 0.8
10318  */
10319 void
10320 clutter_actor_set_rotation (ClutterActor      *self,
10321                             ClutterRotateAxis  axis,
10322                             gdouble            angle,
10323                             gfloat             x,
10324                             gfloat             y,
10325                             gfloat             z)
10326 {
10327   ClutterVertex v;
10328
10329   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10330
10331   v.x = x;
10332   v.y = y;
10333   v.z = z;
10334
10335   g_object_freeze_notify (G_OBJECT (self));
10336
10337   clutter_actor_set_rotation_angle (self, axis, angle);
10338   clutter_actor_set_rotation_center_internal (self, axis, &v);
10339
10340   g_object_thaw_notify (G_OBJECT (self));
10341 }
10342
10343 /**
10344  * clutter_actor_set_z_rotation_from_gravity:
10345  * @self: a #ClutterActor
10346  * @angle: the angle of rotation
10347  * @gravity: the center point of the rotation
10348  *
10349  * Sets the rotation angle of @self around the Z axis using the center
10350  * point specified as a compass point. For example to rotate such that
10351  * the center of the actor remains static you can use
10352  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10353  * will move accordingly.
10354  *
10355  * Since: 1.0
10356  */
10357 void
10358 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10359                                            gdouble         angle,
10360                                            ClutterGravity  gravity)
10361 {
10362   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10363
10364   if (gravity == CLUTTER_GRAVITY_NONE)
10365     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10366   else
10367     {
10368       GObject *obj = G_OBJECT (self);
10369       ClutterTransformInfo *info;
10370
10371       info = _clutter_actor_get_transform_info (self);
10372
10373       g_object_freeze_notify (obj);
10374
10375       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10376
10377       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10378       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10379       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10380
10381       g_object_thaw_notify (obj);
10382     }
10383 }
10384
10385 /**
10386  * clutter_actor_get_rotation:
10387  * @self: a #ClutterActor
10388  * @axis: the axis of rotation
10389  * @x: (out): return value for the X coordinate of the center of rotation
10390  * @y: (out): return value for the Y coordinate of the center of rotation
10391  * @z: (out): return value for the Z coordinate of the center of rotation
10392  *
10393  * Retrieves the angle and center of rotation on the given axis,
10394  * set using clutter_actor_set_rotation().
10395  *
10396  * Return value: the angle of rotation
10397  *
10398  * Since: 0.8
10399  */
10400 gdouble
10401 clutter_actor_get_rotation (ClutterActor      *self,
10402                             ClutterRotateAxis  axis,
10403                             gfloat            *x,
10404                             gfloat            *y,
10405                             gfloat            *z)
10406 {
10407   const ClutterTransformInfo *info;
10408   const AnchorCoord *anchor_coord;
10409   gdouble retval = 0;
10410
10411   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10412
10413   info = _clutter_actor_get_transform_info_or_defaults (self);
10414
10415   switch (axis)
10416     {
10417     case CLUTTER_X_AXIS:
10418       anchor_coord = &info->rx_center;
10419       retval = info->rx_angle;
10420       break;
10421
10422     case CLUTTER_Y_AXIS:
10423       anchor_coord = &info->ry_center;
10424       retval = info->ry_angle;
10425       break;
10426
10427     case CLUTTER_Z_AXIS:
10428       anchor_coord = &info->rz_center;
10429       retval = info->rz_angle;
10430       break;
10431
10432     default:
10433       anchor_coord = NULL;
10434       retval = 0.0;
10435       break;
10436     }
10437
10438   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10439
10440   return retval;
10441 }
10442
10443 /**
10444  * clutter_actor_get_z_rotation_gravity:
10445  * @self: A #ClutterActor
10446  *
10447  * Retrieves the center for the rotation around the Z axis as a
10448  * compass direction. If the center was specified in pixels or units
10449  * this will return %CLUTTER_GRAVITY_NONE.
10450  *
10451  * Return value: the Z rotation center
10452  *
10453  * Since: 1.0
10454  */
10455 ClutterGravity
10456 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10457 {
10458   const ClutterTransformInfo *info;
10459
10460   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10461
10462   info = _clutter_actor_get_transform_info_or_defaults (self);
10463
10464   return clutter_anchor_coord_get_gravity (&info->rz_center);
10465 }
10466
10467 /**
10468  * clutter_actor_set_clip:
10469  * @self: A #ClutterActor
10470  * @xoff: X offset of the clip rectangle
10471  * @yoff: Y offset of the clip rectangle
10472  * @width: Width of the clip rectangle
10473  * @height: Height of the clip rectangle
10474  *
10475  * Sets clip area for @self. The clip area is always computed from the
10476  * upper left corner of the actor, even if the anchor point is set
10477  * otherwise.
10478  *
10479  * Since: 0.6
10480  */
10481 void
10482 clutter_actor_set_clip (ClutterActor *self,
10483                         gfloat        xoff,
10484                         gfloat        yoff,
10485                         gfloat        width,
10486                         gfloat        height)
10487 {
10488   ClutterActorPrivate *priv;
10489
10490   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10491
10492   priv = self->priv;
10493
10494   if (priv->has_clip &&
10495       priv->clip.x == xoff &&
10496       priv->clip.y == yoff &&
10497       priv->clip.width == width &&
10498       priv->clip.height == height)
10499     return;
10500
10501   priv->clip.x = xoff;
10502   priv->clip.y = yoff;
10503   priv->clip.width = width;
10504   priv->clip.height = height;
10505
10506   priv->has_clip = TRUE;
10507
10508   clutter_actor_queue_redraw (self);
10509
10510   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10511   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10512 }
10513
10514 /**
10515  * clutter_actor_remove_clip:
10516  * @self: A #ClutterActor
10517  *
10518  * Removes clip area from @self.
10519  */
10520 void
10521 clutter_actor_remove_clip (ClutterActor *self)
10522 {
10523   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10524
10525   if (!self->priv->has_clip)
10526     return;
10527
10528   self->priv->has_clip = FALSE;
10529
10530   clutter_actor_queue_redraw (self);
10531
10532   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10533 }
10534
10535 /**
10536  * clutter_actor_has_clip:
10537  * @self: a #ClutterActor
10538  *
10539  * Determines whether the actor has a clip area set or not.
10540  *
10541  * Return value: %TRUE if the actor has a clip area set.
10542  *
10543  * Since: 0.1.1
10544  */
10545 gboolean
10546 clutter_actor_has_clip (ClutterActor *self)
10547 {
10548   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10549
10550   return self->priv->has_clip;
10551 }
10552
10553 /**
10554  * clutter_actor_get_clip:
10555  * @self: a #ClutterActor
10556  * @xoff: (out) (allow-none): return location for the X offset of
10557  *   the clip rectangle, or %NULL
10558  * @yoff: (out) (allow-none): return location for the Y offset of
10559  *   the clip rectangle, or %NULL
10560  * @width: (out) (allow-none): return location for the width of
10561  *   the clip rectangle, or %NULL
10562  * @height: (out) (allow-none): return location for the height of
10563  *   the clip rectangle, or %NULL
10564  *
10565  * Gets the clip area for @self, if any is set
10566  *
10567  * Since: 0.6
10568  */
10569 void
10570 clutter_actor_get_clip (ClutterActor *self,
10571                         gfloat       *xoff,
10572                         gfloat       *yoff,
10573                         gfloat       *width,
10574                         gfloat       *height)
10575 {
10576   ClutterActorPrivate *priv;
10577
10578   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10579
10580   priv = self->priv;
10581
10582   if (!priv->has_clip)
10583     return;
10584
10585   if (xoff != NULL)
10586     *xoff = priv->clip.x;
10587
10588   if (yoff != NULL)
10589     *yoff = priv->clip.y;
10590
10591   if (width != NULL)
10592     *width = priv->clip.width;
10593
10594   if (height != NULL)
10595     *height = priv->clip.height;
10596 }
10597
10598 /**
10599  * clutter_actor_get_children:
10600  * @self: a #ClutterActor
10601  *
10602  * Retrieves the list of children of @self.
10603  *
10604  * Return value: (transfer container) (element-type ClutterActor): A newly
10605  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10606  *   done.
10607  *
10608  * Since: 1.10
10609  */
10610 GList *
10611 clutter_actor_get_children (ClutterActor *self)
10612 {
10613   ClutterActor *iter;
10614   GList *res;
10615
10616   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10617
10618   /* we walk the list backward so that we can use prepend(),
10619    * which is O(1)
10620    */
10621   for (iter = self->priv->last_child, res = NULL;
10622        iter != NULL;
10623        iter = iter->priv->prev_sibling)
10624     {
10625       res = g_list_prepend (res, iter);
10626     }
10627
10628   return res;
10629 }
10630
10631 /*< private >
10632  * insert_child_at_depth:
10633  * @self: a #ClutterActor
10634  * @child: a #ClutterActor
10635  *
10636  * Inserts @child inside the list of children held by @self, using
10637  * the depth as the insertion criteria.
10638  *
10639  * This sadly makes the insertion not O(1), but we can keep the
10640  * list sorted so that the painters algorithm we use for painting
10641  * the children will work correctly.
10642  */
10643 static void
10644 insert_child_at_depth (ClutterActor *self,
10645                        ClutterActor *child,
10646                        gpointer      dummy G_GNUC_UNUSED)
10647 {
10648   ClutterActor *iter;
10649   float child_depth;
10650
10651   child->priv->parent = self;
10652
10653   child_depth =
10654     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10655
10656   /* special-case the first child */
10657   if (self->priv->n_children == 0)
10658     {
10659       self->priv->first_child = child;
10660       self->priv->last_child = child;
10661
10662       child->priv->next_sibling = NULL;
10663       child->priv->prev_sibling = NULL;
10664
10665       return;
10666     }
10667
10668   /* Find the right place to insert the child so that it will still be
10669      sorted and the child will be after all of the actors at the same
10670      dept */
10671   for (iter = self->priv->first_child;
10672        iter != NULL;
10673        iter = iter->priv->next_sibling)
10674     {
10675       float iter_depth;
10676
10677       iter_depth =
10678         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10679
10680       if (iter_depth > child_depth)
10681         break;
10682     }
10683
10684   if (iter != NULL)
10685     {
10686       ClutterActor *tmp = iter->priv->prev_sibling;
10687
10688       if (tmp != NULL)
10689         tmp->priv->next_sibling = child;
10690
10691       /* Insert the node before the found one */
10692       child->priv->prev_sibling = iter->priv->prev_sibling;
10693       child->priv->next_sibling = iter;
10694       iter->priv->prev_sibling = child;
10695     }
10696   else
10697     {
10698       ClutterActor *tmp = self->priv->last_child;
10699
10700       if (tmp != NULL)
10701         tmp->priv->next_sibling = child;
10702
10703       /* insert the node at the end of the list */
10704       child->priv->prev_sibling = self->priv->last_child;
10705       child->priv->next_sibling = NULL;
10706     }
10707
10708   if (child->priv->prev_sibling == NULL)
10709     self->priv->first_child = child;
10710
10711   if (child->priv->next_sibling == NULL)
10712     self->priv->last_child = child;
10713 }
10714
10715 static void
10716 insert_child_at_index (ClutterActor *self,
10717                        ClutterActor *child,
10718                        gpointer      data_)
10719 {
10720   gint index_ = GPOINTER_TO_INT (data_);
10721
10722   child->priv->parent = self;
10723
10724   if (index_ == 0)
10725     {
10726       ClutterActor *tmp = self->priv->first_child;
10727
10728       if (tmp != NULL)
10729         tmp->priv->prev_sibling = child;
10730
10731       child->priv->prev_sibling = NULL;
10732       child->priv->next_sibling = tmp;
10733     }
10734   else if (index_ < 0 || index_ >= self->priv->n_children)
10735     {
10736       ClutterActor *tmp = self->priv->last_child;
10737
10738       if (tmp != NULL)
10739         tmp->priv->next_sibling = child;
10740
10741       child->priv->prev_sibling = tmp;
10742       child->priv->next_sibling = NULL;
10743     }
10744   else
10745     {
10746       ClutterActor *iter;
10747       int i;
10748
10749       for (iter = self->priv->first_child, i = 0;
10750            iter != NULL;
10751            iter = iter->priv->next_sibling, i += 1)
10752         {
10753           if (index_ == i)
10754             {
10755               ClutterActor *tmp = iter->priv->prev_sibling;
10756
10757               child->priv->prev_sibling = tmp;
10758               child->priv->next_sibling = iter;
10759
10760               iter->priv->prev_sibling = child;
10761
10762               if (tmp != NULL)
10763                 tmp->priv->next_sibling = child;
10764
10765               break;
10766             }
10767         }
10768     }
10769
10770   if (child->priv->prev_sibling == NULL)
10771     self->priv->first_child = child;
10772
10773   if (child->priv->next_sibling == NULL)
10774     self->priv->last_child = child;
10775 }
10776
10777 static void
10778 insert_child_above (ClutterActor *self,
10779                     ClutterActor *child,
10780                     gpointer      data)
10781 {
10782   ClutterActor *sibling = data;
10783
10784   child->priv->parent = self;
10785
10786   if (sibling == NULL)
10787     sibling = self->priv->last_child;
10788
10789   child->priv->prev_sibling = sibling;
10790
10791   if (sibling != NULL)
10792     {
10793       ClutterActor *tmp = sibling->priv->next_sibling;
10794
10795       child->priv->next_sibling = tmp;
10796
10797       if (tmp != NULL)
10798         tmp->priv->prev_sibling = child;
10799
10800       sibling->priv->next_sibling = child;
10801     }
10802   else
10803     child->priv->next_sibling = NULL;
10804
10805   if (child->priv->prev_sibling == NULL)
10806     self->priv->first_child = child;
10807
10808   if (child->priv->next_sibling == NULL)
10809     self->priv->last_child = child;
10810 }
10811
10812 static void
10813 insert_child_below (ClutterActor *self,
10814                     ClutterActor *child,
10815                     gpointer      data)
10816 {
10817   ClutterActor *sibling = data;
10818
10819   child->priv->parent = self;
10820
10821   if (sibling == NULL)
10822     sibling = self->priv->first_child;
10823
10824   child->priv->next_sibling = sibling;
10825
10826   if (sibling != NULL)
10827     {
10828       ClutterActor *tmp = sibling->priv->prev_sibling;
10829
10830       child->priv->prev_sibling = tmp;
10831
10832       if (tmp != NULL)
10833         tmp->priv->next_sibling = child;
10834
10835       sibling->priv->prev_sibling = child;
10836     }
10837   else
10838     child->priv->prev_sibling = NULL;
10839
10840   if (child->priv->prev_sibling == NULL)
10841     self->priv->first_child = child;
10842
10843   if (child->priv->next_sibling == NULL)
10844     self->priv->last_child = child;
10845 }
10846
10847 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10848                                            ClutterActor *child,
10849                                            gpointer      data);
10850
10851 typedef enum {
10852   ADD_CHILD_CREATE_META       = 1 << 0,
10853   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10854   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10855   ADD_CHILD_CHECK_STATE       = 1 << 3,
10856   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10857
10858   /* default flags for public API */
10859   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10860                                ADD_CHILD_EMIT_PARENT_SET |
10861                                ADD_CHILD_EMIT_ACTOR_ADDED |
10862                                ADD_CHILD_CHECK_STATE |
10863                                ADD_CHILD_NOTIFY_FIRST_LAST,
10864
10865   /* flags for legacy/deprecated API */
10866   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10867                                ADD_CHILD_CHECK_STATE |
10868                                ADD_CHILD_NOTIFY_FIRST_LAST
10869 } ClutterActorAddChildFlags;
10870
10871 /*< private >
10872  * clutter_actor_add_child_internal:
10873  * @self: a #ClutterActor
10874  * @child: a #ClutterActor
10875  * @flags: control flags for actions
10876  * @add_func: delegate function
10877  * @data: (closure): data to pass to @add_func
10878  *
10879  * Adds @child to the list of children of @self.
10880  *
10881  * The actual insertion inside the list is delegated to @add_func: this
10882  * function will just set up the state, perform basic checks, and emit
10883  * signals.
10884  *
10885  * The @flags argument is used to perform additional operations.
10886  */
10887 static inline void
10888 clutter_actor_add_child_internal (ClutterActor              *self,
10889                                   ClutterActor              *child,
10890                                   ClutterActorAddChildFlags  flags,
10891                                   ClutterActorAddChildFunc   add_func,
10892                                   gpointer                   data)
10893 {
10894   ClutterTextDirection text_dir;
10895   gboolean create_meta;
10896   gboolean emit_parent_set, emit_actor_added;
10897   gboolean check_state;
10898   gboolean notify_first_last;
10899   ClutterActor *old_first_child, *old_last_child;
10900
10901   if (child->priv->parent != NULL)
10902     {
10903       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10904                  "use clutter_actor_remove_child() first.",
10905                  _clutter_actor_get_debug_name (child),
10906                  _clutter_actor_get_debug_name (child->priv->parent));
10907       return;
10908     }
10909
10910   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10911     {
10912       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10913                  "a child of another actor.",
10914                  _clutter_actor_get_debug_name (child));
10915       return;
10916     }
10917
10918 #if 0
10919   /* XXX - this check disallows calling methods that change the stacking
10920    * order within the destruction sequence, by triggering a critical
10921    * warning first, and leaving the actor in an undefined state, which
10922    * then ends up being caught by an assertion.
10923    *
10924    * the reproducible sequence is:
10925    *
10926    *   - actor gets destroyed;
10927    *   - another actor, linked to the first, will try to change the
10928    *     stacking order of the first actor;
10929    *   - changing the stacking order is a composite operation composed
10930    *     by the following steps:
10931    *     1. ref() the child;
10932    *     2. remove_child_internal(), which removes the reference;
10933    *     3. add_child_internal(), which adds a reference;
10934    *   - the state of the actor is not changed between (2) and (3), as
10935    *     it could be an expensive recomputation;
10936    *   - if (3) bails out, then the actor is in an undefined state, but
10937    *     still alive;
10938    *   - the destruction sequence terminates, but the actor is unparented
10939    *     while its state indicates being parented instead.
10940    *   - assertion failure.
10941    *
10942    * the obvious fix would be to decompose each set_child_*_sibling()
10943    * method into proper remove_child()/add_child(), with state validation;
10944    * this may cause excessive work, though, and trigger a cascade of other
10945    * bugs in code that assumes that a change in the stacking order is an
10946    * atomic operation.
10947    *
10948    * another potential fix is to just remove this check here, and let
10949    * code doing stacking order changes inside the destruction sequence
10950    * of an actor continue doing the work.
10951    *
10952    * the third fix is to silently bail out early from every
10953    * set_child_*_sibling() and set_child_at_index() method, and avoid
10954    * doing work.
10955    *
10956    * I have a preference for the second solution, since it involves the
10957    * least amount of work, and the least amount of code duplication.
10958    *
10959    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10960    */
10961   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10962     {
10963       g_warning ("The actor '%s' is currently being destroyed, and "
10964                  "cannot be added as a child of another actor.",
10965                  _clutter_actor_get_debug_name (child));
10966       return;
10967     }
10968 #endif
10969
10970   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10971   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10972   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10973   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10974   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10975
10976   old_first_child = self->priv->first_child;
10977   old_last_child = self->priv->last_child;
10978
10979   g_object_freeze_notify (G_OBJECT (self));
10980
10981   if (create_meta)
10982     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10983
10984   g_object_ref_sink (child);
10985   child->priv->parent = NULL;
10986   child->priv->next_sibling = NULL;
10987   child->priv->prev_sibling = NULL;
10988
10989   /* delegate the actual insertion */
10990   add_func (self, child, data);
10991
10992   g_assert (child->priv->parent == self);
10993
10994   self->priv->n_children += 1;
10995
10996   self->priv->age += 1;
10997
10998   /* if push_internal() has been called then we automatically set
10999    * the flag on the actor
11000    */
11001   if (self->priv->internal_child)
11002     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11003
11004   /* clutter_actor_reparent() will emit ::parent-set for us */
11005   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11006     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11007
11008   if (check_state)
11009     {
11010       /* If parent is mapped or realized, we need to also be mapped or
11011        * realized once we're inside the parent.
11012        */
11013       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11014
11015       /* propagate the parent's text direction to the child */
11016       text_dir = clutter_actor_get_text_direction (self);
11017       clutter_actor_set_text_direction (child, text_dir);
11018     }
11019
11020   if (child->priv->show_on_set_parent)
11021     clutter_actor_show (child);
11022
11023   if (CLUTTER_ACTOR_IS_MAPPED (child))
11024     clutter_actor_queue_redraw (child);
11025
11026   /* maintain the invariant that if an actor needs layout,
11027    * its parents do as well
11028    */
11029   if (child->priv->needs_width_request ||
11030       child->priv->needs_height_request ||
11031       child->priv->needs_allocation)
11032     {
11033       /* we work around the short-circuiting we do
11034        * in clutter_actor_queue_relayout() since we
11035        * want to force a relayout
11036        */
11037       child->priv->needs_width_request = TRUE;
11038       child->priv->needs_height_request = TRUE;
11039       child->priv->needs_allocation = TRUE;
11040
11041       clutter_actor_queue_relayout (child->priv->parent);
11042     }
11043
11044   if (emit_actor_added)
11045     g_signal_emit_by_name (self, "actor-added", child);
11046
11047   if (notify_first_last)
11048     {
11049       if (old_first_child != self->priv->first_child)
11050         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11051
11052       if (old_last_child != self->priv->last_child)
11053         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11054     }
11055
11056   g_object_thaw_notify (G_OBJECT (self));
11057 }
11058
11059 /**
11060  * clutter_actor_add_child:
11061  * @self: a #ClutterActor
11062  * @child: a #ClutterActor
11063  *
11064  * Adds @child to the children of @self.
11065  *
11066  * This function will acquire a reference on @child that will only
11067  * be released when calling clutter_actor_remove_child().
11068  *
11069  * This function will take into consideration the #ClutterActor:depth
11070  * of @child, and will keep the list of children sorted.
11071  *
11072  * This function will emit the #ClutterContainer::actor-added signal
11073  * on @self.
11074  *
11075  * Since: 1.10
11076  */
11077 void
11078 clutter_actor_add_child (ClutterActor *self,
11079                          ClutterActor *child)
11080 {
11081   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11082   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11083   g_return_if_fail (self != child);
11084   g_return_if_fail (child->priv->parent == NULL);
11085
11086   clutter_actor_add_child_internal (self, child,
11087                                     ADD_CHILD_DEFAULT_FLAGS,
11088                                     insert_child_at_depth,
11089                                     NULL);
11090 }
11091
11092 /**
11093  * clutter_actor_insert_child_at_index:
11094  * @self: a #ClutterActor
11095  * @child: a #ClutterActor
11096  * @index_: the index
11097  *
11098  * Inserts @child into the list of children of @self, using the
11099  * given @index_. If @index_ is greater than the number of children
11100  * in @self, or is less than 0, then the new child is added at the end.
11101  *
11102  * This function will acquire a reference on @child that will only
11103  * be released when calling clutter_actor_remove_child().
11104  *
11105  * This function will not take into consideration the #ClutterActor:depth
11106  * of @child.
11107  *
11108  * This function will emit the #ClutterContainer::actor-added signal
11109  * on @self.
11110  *
11111  * Since: 1.10
11112  */
11113 void
11114 clutter_actor_insert_child_at_index (ClutterActor *self,
11115                                      ClutterActor *child,
11116                                      gint          index_)
11117 {
11118   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11119   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11120   g_return_if_fail (self != child);
11121   g_return_if_fail (child->priv->parent == NULL);
11122
11123   clutter_actor_add_child_internal (self, child,
11124                                     ADD_CHILD_DEFAULT_FLAGS,
11125                                     insert_child_at_index,
11126                                     GINT_TO_POINTER (index_));
11127 }
11128
11129 /**
11130  * clutter_actor_insert_child_above:
11131  * @self: a #ClutterActor
11132  * @child: a #ClutterActor
11133  * @sibling: (allow-none): a child of @self, or %NULL
11134  *
11135  * Inserts @child into the list of children of @self, above another
11136  * child of @self or, if @sibling is %NULL, above all the children
11137  * of @self.
11138  *
11139  * This function will acquire a reference on @child that will only
11140  * be released when calling clutter_actor_remove_child().
11141  *
11142  * This function will not take into consideration the #ClutterActor:depth
11143  * of @child.
11144  *
11145  * This function will emit the #ClutterContainer::actor-added signal
11146  * on @self.
11147  *
11148  * Since: 1.10
11149  */
11150 void
11151 clutter_actor_insert_child_above (ClutterActor *self,
11152                                   ClutterActor *child,
11153                                   ClutterActor *sibling)
11154 {
11155   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11156   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11157   g_return_if_fail (self != child);
11158   g_return_if_fail (child != sibling);
11159   g_return_if_fail (child->priv->parent == NULL);
11160   g_return_if_fail (sibling == NULL ||
11161                     (CLUTTER_IS_ACTOR (sibling) &&
11162                      sibling->priv->parent == self));
11163
11164   clutter_actor_add_child_internal (self, child,
11165                                     ADD_CHILD_DEFAULT_FLAGS,
11166                                     insert_child_above,
11167                                     sibling);
11168 }
11169
11170 /**
11171  * clutter_actor_insert_child_below:
11172  * @self: a #ClutterActor
11173  * @child: a #ClutterActor
11174  * @sibling: (allow-none): a child of @self, or %NULL
11175  *
11176  * Inserts @child into the list of children of @self, below another
11177  * child of @self or, if @sibling is %NULL, below all the children
11178  * of @self.
11179  *
11180  * This function will acquire a reference on @child that will only
11181  * be released when calling clutter_actor_remove_child().
11182  *
11183  * This function will not take into consideration the #ClutterActor:depth
11184  * of @child.
11185  *
11186  * This function will emit the #ClutterContainer::actor-added signal
11187  * on @self.
11188  *
11189  * Since: 1.10
11190  */
11191 void
11192 clutter_actor_insert_child_below (ClutterActor *self,
11193                                   ClutterActor *child,
11194                                   ClutterActor *sibling)
11195 {
11196   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11197   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11198   g_return_if_fail (self != child);
11199   g_return_if_fail (child != sibling);
11200   g_return_if_fail (child->priv->parent == NULL);
11201   g_return_if_fail (sibling == NULL ||
11202                     (CLUTTER_IS_ACTOR (sibling) &&
11203                      sibling->priv->parent == self));
11204
11205   clutter_actor_add_child_internal (self, child,
11206                                     ADD_CHILD_DEFAULT_FLAGS,
11207                                     insert_child_below,
11208                                     sibling);
11209 }
11210
11211 /**
11212  * clutter_actor_set_parent:
11213  * @self: A #ClutterActor
11214  * @parent: A new #ClutterActor parent
11215  *
11216  * Sets the parent of @self to @parent.
11217  *
11218  * This function will result in @parent acquiring a reference on @self,
11219  * eventually by sinking its floating reference first. The reference
11220  * will be released by clutter_actor_unparent().
11221  *
11222  * This function should only be called by legacy #ClutterActor<!-- -->s
11223  * implementing the #ClutterContainer interface.
11224  *
11225  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11226  */
11227 void
11228 clutter_actor_set_parent (ClutterActor *self,
11229                           ClutterActor *parent)
11230 {
11231   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11232   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11233   g_return_if_fail (self != parent);
11234   g_return_if_fail (self->priv->parent == NULL);
11235
11236   /* as this function will be called inside ClutterContainer::add
11237    * implementations or when building up a composite actor, we have
11238    * to preserve the old behaviour, and not create child meta or
11239    * emit the ::actor-added signal, to avoid recursion or double
11240    * emissions
11241    */
11242   clutter_actor_add_child_internal (parent, self,
11243                                     ADD_CHILD_LEGACY_FLAGS,
11244                                     insert_child_at_depth,
11245                                     NULL);
11246 }
11247
11248 /**
11249  * clutter_actor_get_parent:
11250  * @self: A #ClutterActor
11251  *
11252  * Retrieves the parent of @self.
11253  *
11254  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11255  *  if no parent is set
11256  */
11257 ClutterActor *
11258 clutter_actor_get_parent (ClutterActor *self)
11259 {
11260   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11261
11262   return self->priv->parent;
11263 }
11264
11265 /**
11266  * clutter_actor_get_paint_visibility:
11267  * @self: A #ClutterActor
11268  *
11269  * Retrieves the 'paint' visibility of an actor recursively checking for non
11270  * visible parents.
11271  *
11272  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11273  *
11274  * Return Value: %TRUE if the actor is visibile and will be painted.
11275  *
11276  * Since: 0.8.4
11277  */
11278 gboolean
11279 clutter_actor_get_paint_visibility (ClutterActor *actor)
11280 {
11281   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11282
11283   return CLUTTER_ACTOR_IS_MAPPED (actor);
11284 }
11285
11286 /**
11287  * clutter_actor_remove_child:
11288  * @self: a #ClutterActor
11289  * @child: a #ClutterActor
11290  *
11291  * Removes @child from the children of @self.
11292  *
11293  * This function will release the reference added by
11294  * clutter_actor_add_child(), so if you want to keep using @child
11295  * you will have to acquire a referenced on it before calling this
11296  * function.
11297  *
11298  * This function will emit the #ClutterContainer::actor-removed
11299  * signal on @self.
11300  *
11301  * Since: 1.10
11302  */
11303 void
11304 clutter_actor_remove_child (ClutterActor *self,
11305                             ClutterActor *child)
11306 {
11307   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11308   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11309   g_return_if_fail (self != child);
11310   g_return_if_fail (child->priv->parent != NULL);
11311   g_return_if_fail (child->priv->parent == self);
11312
11313   clutter_actor_remove_child_internal (self, child,
11314                                        REMOVE_CHILD_DEFAULT_FLAGS);
11315 }
11316
11317 /**
11318  * clutter_actor_remove_all_children:
11319  * @self: a #ClutterActor
11320  *
11321  * Removes all children of @self.
11322  *
11323  * This function releases the reference added by inserting a child actor
11324  * in the list of children of @self.
11325  *
11326  * If the reference count of a child drops to zero, the child will be
11327  * destroyed. If you want to ensure the destruction of all the children
11328  * of @self, use clutter_actor_destroy_all_children().
11329  *
11330  * Since: 1.10
11331  */
11332 void
11333 clutter_actor_remove_all_children (ClutterActor *self)
11334 {
11335   ClutterActorIter iter;
11336
11337   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11338
11339   if (self->priv->n_children == 0)
11340     return;
11341
11342   g_object_freeze_notify (G_OBJECT (self));
11343
11344   clutter_actor_iter_init (&iter, self);
11345   while (clutter_actor_iter_next (&iter, NULL))
11346     clutter_actor_iter_remove (&iter);
11347
11348   g_object_thaw_notify (G_OBJECT (self));
11349
11350   /* sanity check */
11351   g_assert (self->priv->first_child == NULL);
11352   g_assert (self->priv->last_child == NULL);
11353   g_assert (self->priv->n_children == 0);
11354 }
11355
11356 /**
11357  * clutter_actor_destroy_all_children:
11358  * @self: a #ClutterActor
11359  *
11360  * Destroys all children of @self.
11361  *
11362  * This function releases the reference added by inserting a child
11363  * actor in the list of children of @self, and ensures that the
11364  * #ClutterActor::destroy signal is emitted on each child of the
11365  * actor.
11366  *
11367  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11368  * when its reference count drops to 0; the default handler of the
11369  * #ClutterActor::destroy signal will destroy all the children of an
11370  * actor. This function ensures that all children are destroyed, instead
11371  * of just removed from @self, unlike clutter_actor_remove_all_children()
11372  * which will merely release the reference and remove each child.
11373  *
11374  * Unless you acquired an additional reference on each child of @self
11375  * prior to calling clutter_actor_remove_all_children() and want to reuse
11376  * the actors, you should use clutter_actor_destroy_all_children() in
11377  * order to make sure that children are destroyed and signal handlers
11378  * are disconnected even in cases where circular references prevent this
11379  * from automatically happening through reference counting alone.
11380  *
11381  * Since: 1.10
11382  */
11383 void
11384 clutter_actor_destroy_all_children (ClutterActor *self)
11385 {
11386   ClutterActorIter iter;
11387
11388   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11389
11390   if (self->priv->n_children == 0)
11391     return;
11392
11393   g_object_freeze_notify (G_OBJECT (self));
11394
11395   clutter_actor_iter_init (&iter, self);
11396   while (clutter_actor_iter_next (&iter, NULL))
11397     clutter_actor_iter_destroy (&iter);
11398
11399   g_object_thaw_notify (G_OBJECT (self));
11400
11401   /* sanity check */
11402   g_assert (self->priv->first_child == NULL);
11403   g_assert (self->priv->last_child == NULL);
11404   g_assert (self->priv->n_children == 0);
11405 }
11406
11407 typedef struct _InsertBetweenData {
11408   ClutterActor *prev_sibling;
11409   ClutterActor *next_sibling;
11410 } InsertBetweenData;
11411
11412 static void
11413 insert_child_between (ClutterActor *self,
11414                       ClutterActor *child,
11415                       gpointer      data_)
11416 {
11417   InsertBetweenData *data = data_;
11418   ClutterActor *prev_sibling = data->prev_sibling;
11419   ClutterActor *next_sibling = data->next_sibling;
11420
11421   child->priv->parent = self;
11422   child->priv->prev_sibling = prev_sibling;
11423   child->priv->next_sibling = next_sibling;
11424
11425   if (prev_sibling != NULL)
11426     prev_sibling->priv->next_sibling = child;
11427
11428   if (next_sibling != NULL)
11429     next_sibling->priv->prev_sibling = child;
11430
11431   if (child->priv->prev_sibling == NULL)
11432     self->priv->first_child = child;
11433
11434   if (child->priv->next_sibling == NULL)
11435     self->priv->last_child = child;
11436 }
11437
11438 /**
11439  * clutter_actor_replace_child:
11440  * @self: a #ClutterActor
11441  * @old_child: the child of @self to replace
11442  * @new_child: the #ClutterActor to replace @old_child
11443  *
11444  * Replaces @old_child with @new_child in the list of children of @self.
11445  *
11446  * Since: 1.10
11447  */
11448 void
11449 clutter_actor_replace_child (ClutterActor *self,
11450                              ClutterActor *old_child,
11451                              ClutterActor *new_child)
11452 {
11453   ClutterActor *prev_sibling, *next_sibling;
11454   InsertBetweenData clos;
11455
11456   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11457   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11458   g_return_if_fail (old_child->priv->parent == self);
11459   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11460   g_return_if_fail (old_child != new_child);
11461   g_return_if_fail (new_child != self);
11462   g_return_if_fail (new_child->priv->parent == NULL);
11463
11464   prev_sibling = old_child->priv->prev_sibling;
11465   next_sibling = old_child->priv->next_sibling;
11466   clutter_actor_remove_child_internal (self, old_child,
11467                                        REMOVE_CHILD_DEFAULT_FLAGS);
11468
11469   clos.prev_sibling = prev_sibling;
11470   clos.next_sibling = next_sibling;
11471   clutter_actor_add_child_internal (self, new_child,
11472                                     ADD_CHILD_DEFAULT_FLAGS,
11473                                     insert_child_between,
11474                                     &clos);
11475 }
11476
11477 /**
11478  * clutter_actor_unparent:
11479  * @self: a #ClutterActor
11480  *
11481  * Removes the parent of @self.
11482  *
11483  * This will cause the parent of @self to release the reference
11484  * acquired when calling clutter_actor_set_parent(), so if you
11485  * want to keep @self you will have to acquire a reference of
11486  * your own, through g_object_ref().
11487  *
11488  * This function should only be called by legacy #ClutterActor<!-- -->s
11489  * implementing the #ClutterContainer interface.
11490  *
11491  * Since: 0.1.1
11492  *
11493  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11494  */
11495 void
11496 clutter_actor_unparent (ClutterActor *self)
11497 {
11498   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11499
11500   if (self->priv->parent == NULL)
11501     return;
11502
11503   clutter_actor_remove_child_internal (self->priv->parent, self,
11504                                        REMOVE_CHILD_LEGACY_FLAGS);
11505 }
11506
11507 /**
11508  * clutter_actor_reparent:
11509  * @self: a #ClutterActor
11510  * @new_parent: the new #ClutterActor parent
11511  *
11512  * Resets the parent actor of @self.
11513  *
11514  * This function is logically equivalent to calling clutter_actor_unparent()
11515  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11516  * ensures the child is not finalized when unparented, and emits the
11517  * #ClutterActor::parent-set signal only once.
11518  *
11519  * In reality, calling this function is less useful than it sounds, as some
11520  * application code may rely on changes in the intermediate state between
11521  * removal and addition of the actor from its old parent to the @new_parent.
11522  * Thus, it is strongly encouraged to avoid using this function in application
11523  * code.
11524  *
11525  * Since: 0.2
11526  *
11527  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11528  *   clutter_actor_add_child() instead; remember to take a reference on
11529  *   the actor being removed before calling clutter_actor_remove_child()
11530  *   to avoid the reference count dropping to zero and the actor being
11531  *   destroyed.
11532  */
11533 void
11534 clutter_actor_reparent (ClutterActor *self,
11535                         ClutterActor *new_parent)
11536 {
11537   ClutterActorPrivate *priv;
11538
11539   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11540   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11541   g_return_if_fail (self != new_parent);
11542
11543   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11544     {
11545       g_warning ("Cannot set a parent on a toplevel actor");
11546       return;
11547     }
11548
11549   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11550     {
11551       g_warning ("Cannot set a parent currently being destroyed");
11552       return;
11553     }
11554
11555   priv = self->priv;
11556
11557   if (priv->parent != new_parent)
11558     {
11559       ClutterActor *old_parent;
11560
11561       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11562
11563       old_parent = priv->parent;
11564
11565       g_object_ref (self);
11566
11567       if (old_parent != NULL)
11568         {
11569          /* go through the Container implementation if this is a regular
11570           * child and not an internal one
11571           */
11572          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11573            {
11574              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11575
11576              /* this will have to call unparent() */
11577              clutter_container_remove_actor (parent, self);
11578            }
11579          else
11580            clutter_actor_remove_child_internal (old_parent, self,
11581                                                 REMOVE_CHILD_LEGACY_FLAGS);
11582         }
11583
11584       /* Note, will call set_parent() */
11585       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11586         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11587       else
11588         clutter_actor_add_child_internal (new_parent, self,
11589                                           ADD_CHILD_LEGACY_FLAGS,
11590                                           insert_child_at_depth,
11591                                           NULL);
11592
11593       /* we emit the ::parent-set signal once */
11594       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11595
11596       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11597
11598       /* the IN_REPARENT flag suspends state updates */
11599       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11600
11601       g_object_unref (self);
11602    }
11603 }
11604
11605 /**
11606  * clutter_actor_contains:
11607  * @self: A #ClutterActor
11608  * @descendant: A #ClutterActor, possibly contained in @self
11609  *
11610  * Determines if @descendant is contained inside @self (either as an
11611  * immediate child, or as a deeper descendant). If @self and
11612  * @descendant point to the same actor then it will also return %TRUE.
11613  *
11614  * Return value: whether @descendent is contained within @self
11615  *
11616  * Since: 1.4
11617  */
11618 gboolean
11619 clutter_actor_contains (ClutterActor *self,
11620                         ClutterActor *descendant)
11621 {
11622   ClutterActor *actor;
11623
11624   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11625   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11626
11627   for (actor = descendant; actor; actor = actor->priv->parent)
11628     if (actor == self)
11629       return TRUE;
11630
11631   return FALSE;
11632 }
11633
11634 /**
11635  * clutter_actor_set_child_above_sibling:
11636  * @self: a #ClutterActor
11637  * @child: a #ClutterActor child of @self
11638  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11639  *
11640  * Sets @child to be above @sibling in the list of children of @self.
11641  *
11642  * If @sibling is %NULL, @child will be the new last child of @self.
11643  *
11644  * This function is logically equivalent to removing @child and using
11645  * clutter_actor_insert_child_above(), but it will not emit signals
11646  * or change state on @child.
11647  *
11648  * Since: 1.10
11649  */
11650 void
11651 clutter_actor_set_child_above_sibling (ClutterActor *self,
11652                                        ClutterActor *child,
11653                                        ClutterActor *sibling)
11654 {
11655   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11656   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11657   g_return_if_fail (child->priv->parent == self);
11658   g_return_if_fail (child != sibling);
11659   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11660
11661   if (sibling != NULL)
11662     g_return_if_fail (sibling->priv->parent == self);
11663
11664   /* we don't want to change the state of child, or emit signals, or
11665    * regenerate ChildMeta instances here, but we still want to follow
11666    * the correct sequence of steps encoded in remove_child() and
11667    * add_child(), so that correctness is ensured, and we only go
11668    * through one known code path.
11669    */
11670   g_object_ref (child);
11671   clutter_actor_remove_child_internal (self, child, 0);
11672   clutter_actor_add_child_internal (self, child,
11673                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11674                                     insert_child_above,
11675                                     sibling);
11676
11677   clutter_actor_queue_relayout (self);
11678 }
11679
11680 /**
11681  * clutter_actor_set_child_below_sibling:
11682  * @self: a #ClutterActor
11683  * @child: a #ClutterActor child of @self
11684  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11685  *
11686  * Sets @child to be below @sibling in the list of children of @self.
11687  *
11688  * If @sibling is %NULL, @child will be the new first child of @self.
11689  *
11690  * This function is logically equivalent to removing @self and using
11691  * clutter_actor_insert_child_below(), but it will not emit signals
11692  * or change state on @child.
11693  *
11694  * Since: 1.10
11695  */
11696 void
11697 clutter_actor_set_child_below_sibling (ClutterActor *self,
11698                                        ClutterActor *child,
11699                                        ClutterActor *sibling)
11700 {
11701   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11702   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11703   g_return_if_fail (child->priv->parent == self);
11704   g_return_if_fail (child != sibling);
11705   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11706
11707   if (sibling != NULL)
11708     g_return_if_fail (sibling->priv->parent == self);
11709
11710   /* see the comment in set_child_above_sibling() */
11711   g_object_ref (child);
11712   clutter_actor_remove_child_internal (self, child, 0);
11713   clutter_actor_add_child_internal (self, child,
11714                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11715                                     insert_child_below,
11716                                     sibling);
11717
11718   clutter_actor_queue_relayout (self);
11719 }
11720
11721 /**
11722  * clutter_actor_set_child_at_index:
11723  * @self: a #ClutterActor
11724  * @child: a #ClutterActor child of @self
11725  * @index_: the new index for @child
11726  *
11727  * Changes the index of @child in the list of children of @self.
11728  *
11729  * This function is logically equivalent to removing @child and
11730  * calling clutter_actor_insert_child_at_index(), but it will not
11731  * emit signals or change state on @child.
11732  *
11733  * Since: 1.10
11734  */
11735 void
11736 clutter_actor_set_child_at_index (ClutterActor *self,
11737                                   ClutterActor *child,
11738                                   gint          index_)
11739 {
11740   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11741   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11742   g_return_if_fail (child->priv->parent == self);
11743   g_return_if_fail (index_ <= self->priv->n_children);
11744
11745   g_object_ref (child);
11746   clutter_actor_remove_child_internal (self, child, 0);
11747   clutter_actor_add_child_internal (self, child,
11748                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11749                                     insert_child_at_index,
11750                                     GINT_TO_POINTER (index_));
11751
11752   clutter_actor_queue_relayout (self);
11753 }
11754
11755 /**
11756  * clutter_actor_raise:
11757  * @self: A #ClutterActor
11758  * @below: (allow-none): A #ClutterActor to raise above.
11759  *
11760  * Puts @self above @below.
11761  *
11762  * Both actors must have the same parent, and the parent must implement
11763  * the #ClutterContainer interface
11764  *
11765  * This function calls clutter_container_raise_child() internally.
11766  *
11767  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11768  */
11769 void
11770 clutter_actor_raise (ClutterActor *self,
11771                      ClutterActor *below)
11772 {
11773   ClutterActor *parent;
11774
11775   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11776
11777   parent = clutter_actor_get_parent (self);
11778   if (parent == NULL)
11779     {
11780       g_warning ("%s: Actor '%s' is not inside a container",
11781                  G_STRFUNC,
11782                  _clutter_actor_get_debug_name (self));
11783       return;
11784     }
11785
11786   if (below != NULL)
11787     {
11788       if (parent != clutter_actor_get_parent (below))
11789         {
11790           g_warning ("%s Actor '%s' is not in the same container as "
11791                      "actor '%s'",
11792                      G_STRFUNC,
11793                      _clutter_actor_get_debug_name (self),
11794                      _clutter_actor_get_debug_name (below));
11795           return;
11796         }
11797     }
11798
11799   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11800 }
11801
11802 /**
11803  * clutter_actor_lower:
11804  * @self: A #ClutterActor
11805  * @above: (allow-none): A #ClutterActor to lower below
11806  *
11807  * Puts @self below @above.
11808  *
11809  * Both actors must have the same parent, and the parent must implement
11810  * the #ClutterContainer interface.
11811  *
11812  * This function calls clutter_container_lower_child() internally.
11813  *
11814  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11815  */
11816 void
11817 clutter_actor_lower (ClutterActor *self,
11818                      ClutterActor *above)
11819 {
11820   ClutterActor *parent;
11821
11822   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11823
11824   parent = clutter_actor_get_parent (self);
11825   if (parent == NULL)
11826     {
11827       g_warning ("%s: Actor of type %s is not inside a container",
11828                  G_STRFUNC,
11829                  _clutter_actor_get_debug_name (self));
11830       return;
11831     }
11832
11833   if (above)
11834     {
11835       if (parent != clutter_actor_get_parent (above))
11836         {
11837           g_warning ("%s: Actor '%s' is not in the same container as "
11838                      "actor '%s'",
11839                      G_STRFUNC,
11840                      _clutter_actor_get_debug_name (self),
11841                      _clutter_actor_get_debug_name (above));
11842           return;
11843         }
11844     }
11845
11846   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11847 }
11848
11849 /**
11850  * clutter_actor_raise_top:
11851  * @self: A #ClutterActor
11852  *
11853  * Raises @self to the top.
11854  *
11855  * This function calls clutter_actor_raise() internally.
11856  *
11857  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11858  *   a %NULL sibling, instead.
11859  */
11860 void
11861 clutter_actor_raise_top (ClutterActor *self)
11862 {
11863   clutter_actor_raise (self, NULL);
11864 }
11865
11866 /**
11867  * clutter_actor_lower_bottom:
11868  * @self: A #ClutterActor
11869  *
11870  * Lowers @self to the bottom.
11871  *
11872  * This function calls clutter_actor_lower() internally.
11873  *
11874  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11875  *   a %NULL sibling, instead.
11876  */
11877 void
11878 clutter_actor_lower_bottom (ClutterActor *self)
11879 {
11880   clutter_actor_lower (self, NULL);
11881 }
11882
11883 /*
11884  * Event handling
11885  */
11886
11887 /**
11888  * clutter_actor_event:
11889  * @actor: a #ClutterActor
11890  * @event: a #ClutterEvent
11891  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11892  *
11893  * This function is used to emit an event on the main stage.
11894  * You should rarely need to use this function, except for
11895  * synthetising events.
11896  *
11897  * Return value: the return value from the signal emission: %TRUE
11898  *   if the actor handled the event, or %FALSE if the event was
11899  *   not handled
11900  *
11901  * Since: 0.6
11902  */
11903 gboolean
11904 clutter_actor_event (ClutterActor *actor,
11905                      ClutterEvent *event,
11906                      gboolean      capture)
11907 {
11908   gboolean retval = FALSE;
11909   gint signal_num = -1;
11910
11911   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11912   g_return_val_if_fail (event != NULL, FALSE);
11913
11914   g_object_ref (actor);
11915
11916   if (capture)
11917     {
11918       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11919                      event,
11920                      &retval);
11921       goto out;
11922     }
11923
11924   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11925
11926   if (!retval)
11927     {
11928       switch (event->type)
11929         {
11930         case CLUTTER_NOTHING:
11931           break;
11932         case CLUTTER_BUTTON_PRESS:
11933           signal_num = BUTTON_PRESS_EVENT;
11934           break;
11935         case CLUTTER_BUTTON_RELEASE:
11936           signal_num = BUTTON_RELEASE_EVENT;
11937           break;
11938         case CLUTTER_SCROLL:
11939           signal_num = SCROLL_EVENT;
11940           break;
11941         case CLUTTER_KEY_PRESS:
11942           signal_num = KEY_PRESS_EVENT;
11943           break;
11944         case CLUTTER_KEY_RELEASE:
11945           signal_num = KEY_RELEASE_EVENT;
11946           break;
11947         case CLUTTER_MOTION:
11948           signal_num = MOTION_EVENT;
11949           break;
11950         case CLUTTER_ENTER:
11951           signal_num = ENTER_EVENT;
11952           break;
11953         case CLUTTER_LEAVE:
11954           signal_num = LEAVE_EVENT;
11955           break;
11956         case CLUTTER_DELETE:
11957         case CLUTTER_DESTROY_NOTIFY:
11958         case CLUTTER_CLIENT_MESSAGE:
11959         default:
11960           signal_num = -1;
11961           break;
11962         }
11963
11964       if (signal_num != -1)
11965         g_signal_emit (actor, actor_signals[signal_num], 0,
11966                        event, &retval);
11967     }
11968
11969 out:
11970   g_object_unref (actor);
11971
11972   return retval;
11973 }
11974
11975 /**
11976  * clutter_actor_set_reactive:
11977  * @actor: a #ClutterActor
11978  * @reactive: whether the actor should be reactive to events
11979  *
11980  * Sets @actor as reactive. Reactive actors will receive events.
11981  *
11982  * Since: 0.6
11983  */
11984 void
11985 clutter_actor_set_reactive (ClutterActor *actor,
11986                             gboolean      reactive)
11987 {
11988   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11989
11990   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11991     return;
11992
11993   if (reactive)
11994     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11995   else
11996     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11997
11998   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11999 }
12000
12001 /**
12002  * clutter_actor_get_reactive:
12003  * @actor: a #ClutterActor
12004  *
12005  * Checks whether @actor is marked as reactive.
12006  *
12007  * Return value: %TRUE if the actor is reactive
12008  *
12009  * Since: 0.6
12010  */
12011 gboolean
12012 clutter_actor_get_reactive (ClutterActor *actor)
12013 {
12014   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12015
12016   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12017 }
12018
12019 /**
12020  * clutter_actor_get_anchor_point:
12021  * @self: a #ClutterActor
12022  * @anchor_x: (out): return location for the X coordinate of the anchor point
12023  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12024  *
12025  * Gets the current anchor point of the @actor in pixels.
12026  *
12027  * Since: 0.6
12028  */
12029 void
12030 clutter_actor_get_anchor_point (ClutterActor *self,
12031                                 gfloat       *anchor_x,
12032                                 gfloat       *anchor_y)
12033 {
12034   const ClutterTransformInfo *info;
12035
12036   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12037
12038   info = _clutter_actor_get_transform_info_or_defaults (self);
12039   clutter_anchor_coord_get_units (self, &info->anchor,
12040                                   anchor_x,
12041                                   anchor_y,
12042                                   NULL);
12043 }
12044
12045 /**
12046  * clutter_actor_set_anchor_point:
12047  * @self: a #ClutterActor
12048  * @anchor_x: X coordinate of the anchor point
12049  * @anchor_y: Y coordinate of the anchor point
12050  *
12051  * Sets an anchor point for @self. The anchor point is a point in the
12052  * coordinate space of an actor to which the actor position within its
12053  * parent is relative; the default is (0, 0), i.e. the top-left corner
12054  * of the actor.
12055  *
12056  * Since: 0.6
12057  */
12058 void
12059 clutter_actor_set_anchor_point (ClutterActor *self,
12060                                 gfloat        anchor_x,
12061                                 gfloat        anchor_y)
12062 {
12063   ClutterTransformInfo *info;
12064   ClutterActorPrivate *priv;
12065   gboolean changed = FALSE;
12066   gfloat old_anchor_x, old_anchor_y;
12067   GObject *obj;
12068
12069   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12070
12071   obj = G_OBJECT (self);
12072   priv = self->priv;
12073   info = _clutter_actor_get_transform_info (self);
12074
12075   g_object_freeze_notify (obj);
12076
12077   clutter_anchor_coord_get_units (self, &info->anchor,
12078                                   &old_anchor_x,
12079                                   &old_anchor_y,
12080                                   NULL);
12081
12082   if (info->anchor.is_fractional)
12083     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12084
12085   if (old_anchor_x != anchor_x)
12086     {
12087       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12088       changed = TRUE;
12089     }
12090
12091   if (old_anchor_y != anchor_y)
12092     {
12093       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12094       changed = TRUE;
12095     }
12096
12097   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12098
12099   if (changed)
12100     {
12101       priv->transform_valid = FALSE;
12102       clutter_actor_queue_redraw (self);
12103     }
12104
12105   g_object_thaw_notify (obj);
12106 }
12107
12108 /**
12109  * clutter_actor_get_anchor_point_gravity:
12110  * @self: a #ClutterActor
12111  *
12112  * Retrieves the anchor position expressed as a #ClutterGravity. If
12113  * the anchor point was specified using pixels or units this will
12114  * return %CLUTTER_GRAVITY_NONE.
12115  *
12116  * Return value: the #ClutterGravity used by the anchor point
12117  *
12118  * Since: 1.0
12119  */
12120 ClutterGravity
12121 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12122 {
12123   const ClutterTransformInfo *info;
12124
12125   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12126
12127   info = _clutter_actor_get_transform_info_or_defaults (self);
12128
12129   return clutter_anchor_coord_get_gravity (&info->anchor);
12130 }
12131
12132 /**
12133  * clutter_actor_move_anchor_point:
12134  * @self: a #ClutterActor
12135  * @anchor_x: X coordinate of the anchor point
12136  * @anchor_y: Y coordinate of the anchor point
12137  *
12138  * Sets an anchor point for the actor, and adjusts the actor postion so that
12139  * the relative position of the actor toward its parent remains the same.
12140  *
12141  * Since: 0.6
12142  */
12143 void
12144 clutter_actor_move_anchor_point (ClutterActor *self,
12145                                  gfloat        anchor_x,
12146                                  gfloat        anchor_y)
12147 {
12148   gfloat old_anchor_x, old_anchor_y;
12149   const ClutterTransformInfo *info;
12150
12151   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12152
12153   info = _clutter_actor_get_transform_info (self);
12154   clutter_anchor_coord_get_units (self, &info->anchor,
12155                                   &old_anchor_x,
12156                                   &old_anchor_y,
12157                                   NULL);
12158
12159   g_object_freeze_notify (G_OBJECT (self));
12160
12161   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12162
12163   if (self->priv->position_set)
12164     clutter_actor_move_by (self,
12165                            anchor_x - old_anchor_x,
12166                            anchor_y - old_anchor_y);
12167
12168   g_object_thaw_notify (G_OBJECT (self));
12169 }
12170
12171 /**
12172  * clutter_actor_move_anchor_point_from_gravity:
12173  * @self: a #ClutterActor
12174  * @gravity: #ClutterGravity.
12175  *
12176  * Sets an anchor point on the actor based on the given gravity, adjusting the
12177  * actor postion so that its relative position within its parent remains
12178  * unchanged.
12179  *
12180  * Since version 1.0 the anchor point will be stored as a gravity so
12181  * that if the actor changes size then the anchor point will move. For
12182  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12183  * and later double the size of the actor, the anchor point will move
12184  * to the bottom right.
12185  *
12186  * Since: 0.6
12187  */
12188 void
12189 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12190                                               ClutterGravity  gravity)
12191 {
12192   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12193   const ClutterTransformInfo *info;
12194   ClutterActorPrivate *priv;
12195
12196   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12197
12198   priv = self->priv;
12199   info = _clutter_actor_get_transform_info (self);
12200
12201   g_object_freeze_notify (G_OBJECT (self));
12202
12203   clutter_anchor_coord_get_units (self, &info->anchor,
12204                                   &old_anchor_x,
12205                                   &old_anchor_y,
12206                                   NULL);
12207   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12208   clutter_anchor_coord_get_units (self, &info->anchor,
12209                                   &new_anchor_x,
12210                                   &new_anchor_y,
12211                                   NULL);
12212
12213   if (priv->position_set)
12214     clutter_actor_move_by (self,
12215                            new_anchor_x - old_anchor_x,
12216                            new_anchor_y - old_anchor_y);
12217
12218   g_object_thaw_notify (G_OBJECT (self));
12219 }
12220
12221 /**
12222  * clutter_actor_set_anchor_point_from_gravity:
12223  * @self: a #ClutterActor
12224  * @gravity: #ClutterGravity.
12225  *
12226  * Sets an anchor point on the actor, based on the given gravity (this is a
12227  * convenience function wrapping clutter_actor_set_anchor_point()).
12228  *
12229  * Since version 1.0 the anchor point will be stored as a gravity so
12230  * that if the actor changes size then the anchor point will move. For
12231  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12232  * and later double the size of the actor, the anchor point will move
12233  * to the bottom right.
12234  *
12235  * Since: 0.6
12236  */
12237 void
12238 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12239                                              ClutterGravity  gravity)
12240 {
12241   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12242
12243   if (gravity == CLUTTER_GRAVITY_NONE)
12244     clutter_actor_set_anchor_point (self, 0, 0);
12245   else
12246     {
12247       GObject *obj = G_OBJECT (self);
12248       ClutterTransformInfo *info;
12249
12250       g_object_freeze_notify (obj);
12251
12252       info = _clutter_actor_get_transform_info (self);
12253       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12254
12255       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12256       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12257       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12258
12259       self->priv->transform_valid = FALSE;
12260
12261       clutter_actor_queue_redraw (self);
12262
12263       g_object_thaw_notify (obj);
12264     }
12265 }
12266
12267 static void
12268 clutter_container_iface_init (ClutterContainerIface *iface)
12269 {
12270   /* we don't override anything, as ClutterContainer already has a default
12271    * implementation that we can use, and which calls into our own API.
12272    */
12273 }
12274
12275 typedef enum
12276 {
12277   PARSE_X,
12278   PARSE_Y,
12279   PARSE_WIDTH,
12280   PARSE_HEIGHT,
12281   PARSE_ANCHOR_X,
12282   PARSE_ANCHOR_Y
12283 } ParseDimension;
12284
12285 static gfloat
12286 parse_units (ClutterActor   *self,
12287              ParseDimension  dimension,
12288              JsonNode       *node)
12289 {
12290   GValue value = { 0, };
12291   gfloat retval = 0;
12292
12293   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12294     return 0;
12295
12296   json_node_get_value (node, &value);
12297
12298   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12299     {
12300       retval = (gfloat) g_value_get_int64 (&value);
12301     }
12302   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12303     {
12304       retval = g_value_get_double (&value);
12305     }
12306   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12307     {
12308       ClutterUnits units;
12309       gboolean res;
12310
12311       res = clutter_units_from_string (&units, g_value_get_string (&value));
12312       if (res)
12313         retval = clutter_units_to_pixels (&units);
12314       else
12315         {
12316           g_warning ("Invalid value '%s': integers, strings or floating point "
12317                      "values can be used for the x, y, width and height "
12318                      "properties. Valid modifiers for strings are 'px', 'mm', "
12319                      "'pt' and 'em'.",
12320                      g_value_get_string (&value));
12321           retval = 0;
12322         }
12323     }
12324   else
12325     {
12326       g_warning ("Invalid value of type '%s': integers, strings of floating "
12327                  "point values can be used for the x, y, width, height "
12328                  "anchor-x and anchor-y properties.",
12329                  g_type_name (G_VALUE_TYPE (&value)));
12330     }
12331
12332   g_value_unset (&value);
12333
12334   return retval;
12335 }
12336
12337 typedef struct {
12338   ClutterRotateAxis axis;
12339
12340   gdouble angle;
12341
12342   gfloat center_x;
12343   gfloat center_y;
12344   gfloat center_z;
12345 } RotationInfo;
12346
12347 static inline gboolean
12348 parse_rotation_array (ClutterActor *actor,
12349                       JsonArray    *array,
12350                       RotationInfo *info)
12351 {
12352   JsonNode *element;
12353
12354   if (json_array_get_length (array) != 2)
12355     return FALSE;
12356
12357   /* angle */
12358   element = json_array_get_element (array, 0);
12359   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12360     info->angle = json_node_get_double (element);
12361   else
12362     return FALSE;
12363
12364   /* center */
12365   element = json_array_get_element (array, 1);
12366   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12367     {
12368       JsonArray *center = json_node_get_array (element);
12369
12370       if (json_array_get_length (center) != 2)
12371         return FALSE;
12372
12373       switch (info->axis)
12374         {
12375         case CLUTTER_X_AXIS:
12376           info->center_y = parse_units (actor, PARSE_Y,
12377                                         json_array_get_element (center, 0));
12378           info->center_z = parse_units (actor, PARSE_Y,
12379                                         json_array_get_element (center, 1));
12380           return TRUE;
12381
12382         case CLUTTER_Y_AXIS:
12383           info->center_x = parse_units (actor, PARSE_X,
12384                                         json_array_get_element (center, 0));
12385           info->center_z = parse_units (actor, PARSE_X,
12386                                         json_array_get_element (center, 1));
12387           return TRUE;
12388
12389         case CLUTTER_Z_AXIS:
12390           info->center_x = parse_units (actor, PARSE_X,
12391                                         json_array_get_element (center, 0));
12392           info->center_y = parse_units (actor, PARSE_Y,
12393                                         json_array_get_element (center, 1));
12394           return TRUE;
12395         }
12396     }
12397
12398   return FALSE;
12399 }
12400
12401 static gboolean
12402 parse_rotation (ClutterActor *actor,
12403                 JsonNode     *node,
12404                 RotationInfo *info)
12405 {
12406   JsonArray *array;
12407   guint len, i;
12408   gboolean retval = FALSE;
12409
12410   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12411     {
12412       g_warning ("Invalid node of type '%s' found, expecting an array",
12413                  json_node_type_name (node));
12414       return FALSE;
12415     }
12416
12417   array = json_node_get_array (node);
12418   len = json_array_get_length (array);
12419
12420   for (i = 0; i < len; i++)
12421     {
12422       JsonNode *element = json_array_get_element (array, i);
12423       JsonObject *object;
12424       JsonNode *member;
12425
12426       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12427         {
12428           g_warning ("Invalid node of type '%s' found, expecting an object",
12429                      json_node_type_name (element));
12430           return FALSE;
12431         }
12432
12433       object = json_node_get_object (element);
12434
12435       if (json_object_has_member (object, "x-axis"))
12436         {
12437           member = json_object_get_member (object, "x-axis");
12438
12439           info->axis = CLUTTER_X_AXIS;
12440
12441           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12442             {
12443               info->angle = json_node_get_double (member);
12444               retval = TRUE;
12445             }
12446           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12447             retval = parse_rotation_array (actor,
12448                                            json_node_get_array (member),
12449                                            info);
12450           else
12451             retval = FALSE;
12452         }
12453       else if (json_object_has_member (object, "y-axis"))
12454         {
12455           member = json_object_get_member (object, "y-axis");
12456
12457           info->axis = CLUTTER_Y_AXIS;
12458
12459           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12460             {
12461               info->angle = json_node_get_double (member);
12462               retval = TRUE;
12463             }
12464           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12465             retval = parse_rotation_array (actor,
12466                                            json_node_get_array (member),
12467                                            info);
12468           else
12469             retval = FALSE;
12470         }
12471       else if (json_object_has_member (object, "z-axis"))
12472         {
12473           member = json_object_get_member (object, "z-axis");
12474
12475           info->axis = CLUTTER_Z_AXIS;
12476
12477           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12478             {
12479               info->angle = json_node_get_double (member);
12480               retval = TRUE;
12481             }
12482           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12483             retval = parse_rotation_array (actor,
12484                                            json_node_get_array (member),
12485                                            info);
12486           else
12487             retval = FALSE;
12488         }
12489     }
12490
12491   return retval;
12492 }
12493
12494 static GSList *
12495 parse_actor_metas (ClutterScript *script,
12496                    ClutterActor  *actor,
12497                    JsonNode      *node)
12498 {
12499   GList *elements, *l;
12500   GSList *retval = NULL;
12501
12502   if (!JSON_NODE_HOLDS_ARRAY (node))
12503     return NULL;
12504
12505   elements = json_array_get_elements (json_node_get_array (node));
12506
12507   for (l = elements; l != NULL; l = l->next)
12508     {
12509       JsonNode *element = l->data;
12510       const gchar *id_ = _clutter_script_get_id_from_node (element);
12511       GObject *meta;
12512
12513       if (id_ == NULL || *id_ == '\0')
12514         continue;
12515
12516       meta = clutter_script_get_object (script, id_);
12517       if (meta == NULL)
12518         continue;
12519
12520       retval = g_slist_prepend (retval, meta);
12521     }
12522
12523   g_list_free (elements);
12524
12525   return g_slist_reverse (retval);
12526 }
12527
12528 static GSList *
12529 parse_behaviours (ClutterScript *script,
12530                   ClutterActor  *actor,
12531                   JsonNode      *node)
12532 {
12533   GList *elements, *l;
12534   GSList *retval = NULL;
12535
12536   if (!JSON_NODE_HOLDS_ARRAY (node))
12537     return NULL;
12538
12539   elements = json_array_get_elements (json_node_get_array (node));
12540
12541   for (l = elements; l != NULL; l = l->next)
12542     {
12543       JsonNode *element = l->data;
12544       const gchar *id_ = _clutter_script_get_id_from_node (element);
12545       GObject *behaviour;
12546
12547       if (id_ == NULL || *id_ == '\0')
12548         continue;
12549
12550       behaviour = clutter_script_get_object (script, id_);
12551       if (behaviour == NULL)
12552         continue;
12553
12554       retval = g_slist_prepend (retval, behaviour);
12555     }
12556
12557   g_list_free (elements);
12558
12559   return g_slist_reverse (retval);
12560 }
12561
12562 static gboolean
12563 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12564                                  ClutterScript     *script,
12565                                  GValue            *value,
12566                                  const gchar       *name,
12567                                  JsonNode          *node)
12568 {
12569   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12570   gboolean retval = FALSE;
12571
12572   if ((name[0] == 'x' && name[1] == '\0') ||
12573       (name[0] == 'y' && name[1] == '\0') ||
12574       (strcmp (name, "width") == 0) ||
12575       (strcmp (name, "height") == 0) ||
12576       (strcmp (name, "anchor_x") == 0) ||
12577       (strcmp (name, "anchor_y") == 0))
12578     {
12579       ParseDimension dimension;
12580       gfloat units;
12581
12582       if (name[0] == 'x')
12583         dimension = PARSE_X;
12584       else if (name[0] == 'y')
12585         dimension = PARSE_Y;
12586       else if (name[0] == 'w')
12587         dimension = PARSE_WIDTH;
12588       else if (name[0] == 'h')
12589         dimension = PARSE_HEIGHT;
12590       else if (name[0] == 'a' && name[7] == 'x')
12591         dimension = PARSE_ANCHOR_X;
12592       else if (name[0] == 'a' && name[7] == 'y')
12593         dimension = PARSE_ANCHOR_Y;
12594       else
12595         return FALSE;
12596
12597       units = parse_units (actor, dimension, node);
12598
12599       /* convert back to pixels: all properties are pixel-based */
12600       g_value_init (value, G_TYPE_FLOAT);
12601       g_value_set_float (value, units);
12602
12603       retval = TRUE;
12604     }
12605   else if (strcmp (name, "rotation") == 0)
12606     {
12607       RotationInfo *info;
12608
12609       info = g_slice_new0 (RotationInfo);
12610       retval = parse_rotation (actor, node, info);
12611
12612       if (retval)
12613         {
12614           g_value_init (value, G_TYPE_POINTER);
12615           g_value_set_pointer (value, info);
12616         }
12617       else
12618         g_slice_free (RotationInfo, info);
12619     }
12620   else if (strcmp (name, "behaviours") == 0)
12621     {
12622       GSList *l;
12623
12624 #ifdef CLUTTER_ENABLE_DEBUG
12625       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12626         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12627                                      "and it should not be used in newly "
12628                                      "written ClutterScript definitions.");
12629 #endif
12630
12631       l = parse_behaviours (script, actor, node);
12632
12633       g_value_init (value, G_TYPE_POINTER);
12634       g_value_set_pointer (value, l);
12635
12636       retval = TRUE;
12637     }
12638   else if (strcmp (name, "actions") == 0 ||
12639            strcmp (name, "constraints") == 0 ||
12640            strcmp (name, "effects") == 0)
12641     {
12642       GSList *l;
12643
12644       l = parse_actor_metas (script, actor, node);
12645
12646       g_value_init (value, G_TYPE_POINTER);
12647       g_value_set_pointer (value, l);
12648
12649       retval = TRUE;
12650     }
12651
12652   return retval;
12653 }
12654
12655 static void
12656 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12657                                    ClutterScript     *script,
12658                                    const gchar       *name,
12659                                    const GValue      *value)
12660 {
12661   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12662
12663 #ifdef CLUTTER_ENABLE_DEBUG
12664   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12665     {
12666       gchar *tmp = g_strdup_value_contents (value);
12667
12668       CLUTTER_NOTE (SCRIPT,
12669                     "in ClutterActor::set_custom_property('%s') = %s",
12670                     name,
12671                     tmp);
12672
12673       g_free (tmp);
12674     }
12675 #endif /* CLUTTER_ENABLE_DEBUG */
12676
12677   if (strcmp (name, "rotation") == 0)
12678     {
12679       RotationInfo *info;
12680
12681       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12682         return;
12683
12684       info = g_value_get_pointer (value);
12685
12686       clutter_actor_set_rotation (actor,
12687                                   info->axis, info->angle,
12688                                   info->center_x,
12689                                   info->center_y,
12690                                   info->center_z);
12691
12692       g_slice_free (RotationInfo, info);
12693
12694       return;
12695     }
12696
12697   if (strcmp (name, "behaviours") == 0)
12698     {
12699       GSList *behaviours, *l;
12700
12701       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12702         return;
12703
12704       behaviours = g_value_get_pointer (value);
12705       for (l = behaviours; l != NULL; l = l->next)
12706         {
12707           ClutterBehaviour *behaviour = l->data;
12708
12709           clutter_behaviour_apply (behaviour, actor);
12710         }
12711
12712       g_slist_free (behaviours);
12713
12714       return;
12715     }
12716
12717   if (strcmp (name, "actions") == 0 ||
12718       strcmp (name, "constraints") == 0 ||
12719       strcmp (name, "effects") == 0)
12720     {
12721       GSList *metas, *l;
12722
12723       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12724         return;
12725
12726       metas = g_value_get_pointer (value);
12727       for (l = metas; l != NULL; l = l->next)
12728         {
12729           if (name[0] == 'a')
12730             clutter_actor_add_action (actor, l->data);
12731
12732           if (name[0] == 'c')
12733             clutter_actor_add_constraint (actor, l->data);
12734
12735           if (name[0] == 'e')
12736             clutter_actor_add_effect (actor, l->data);
12737         }
12738
12739       g_slist_free (metas);
12740
12741       return;
12742     }
12743
12744   g_object_set_property (G_OBJECT (scriptable), name, value);
12745 }
12746
12747 static void
12748 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12749 {
12750   iface->parse_custom_node = clutter_actor_parse_custom_node;
12751   iface->set_custom_property = clutter_actor_set_custom_property;
12752 }
12753
12754 static ClutterActorMeta *
12755 get_meta_from_animation_property (ClutterActor  *actor,
12756                                   const gchar   *name,
12757                                   gchar        **name_p)
12758 {
12759   ClutterActorPrivate *priv = actor->priv;
12760   ClutterActorMeta *meta = NULL;
12761   gchar **tokens;
12762
12763   /* if this is not a special property, fall through */
12764   if (name[0] != '@')
12765     return NULL;
12766
12767   /* detect the properties named using the following spec:
12768    *
12769    *   @<section>.<meta-name>.<property-name>
12770    *
12771    * where <section> can be one of the following:
12772    *
12773    *   - actions
12774    *   - constraints
12775    *   - effects
12776    *
12777    * and <meta-name> is the name set on a specific ActorMeta
12778    */
12779
12780   tokens = g_strsplit (name + 1, ".", -1);
12781   if (tokens == NULL || g_strv_length (tokens) != 3)
12782     {
12783       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12784                     name + 1);
12785       g_strfreev (tokens);
12786       return NULL;
12787     }
12788
12789   if (strcmp (tokens[0], "actions") == 0)
12790     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12791
12792   if (strcmp (tokens[0], "constraints") == 0)
12793     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12794
12795   if (strcmp (tokens[0], "effects") == 0)
12796     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12797
12798   if (name_p != NULL)
12799     *name_p = g_strdup (tokens[2]);
12800
12801   CLUTTER_NOTE (ANIMATION,
12802                 "Looking for property '%s' of object '%s' in section '%s'",
12803                 tokens[2],
12804                 tokens[1],
12805                 tokens[0]);
12806
12807   g_strfreev (tokens);
12808
12809   return meta;
12810 }
12811
12812 static GParamSpec *
12813 clutter_actor_find_property (ClutterAnimatable *animatable,
12814                              const gchar       *property_name)
12815 {
12816   ClutterActorMeta *meta = NULL;
12817   GObjectClass *klass = NULL;
12818   GParamSpec *pspec = NULL;
12819   gchar *p_name = NULL;
12820
12821   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12822                                            property_name,
12823                                            &p_name);
12824
12825   if (meta != NULL)
12826     {
12827       klass = G_OBJECT_GET_CLASS (meta);
12828
12829       pspec = g_object_class_find_property (klass, p_name);
12830     }
12831   else
12832     {
12833       klass = G_OBJECT_GET_CLASS (animatable);
12834
12835       pspec = g_object_class_find_property (klass, property_name);
12836     }
12837
12838   g_free (p_name);
12839
12840   return pspec;
12841 }
12842
12843 static void
12844 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12845                                  const gchar       *property_name,
12846                                  GValue            *initial)
12847 {
12848   ClutterActorMeta *meta = NULL;
12849   gchar *p_name = NULL;
12850
12851   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12852                                            property_name,
12853                                            &p_name);
12854
12855   if (meta != NULL)
12856     g_object_get_property (G_OBJECT (meta), p_name, initial);
12857   else
12858     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12859
12860   g_free (p_name);
12861 }
12862
12863 /*
12864  * clutter_actor_set_animatable_property:
12865  * @actor: a #ClutterActor
12866  * @prop_id: the paramspec id
12867  * @value: the value to set
12868  * @pspec: the paramspec
12869  *
12870  * Sets values of animatable properties.
12871  *
12872  * This is a variant of clutter_actor_set_property() that gets called
12873  * by the #ClutterAnimatable implementation of #ClutterActor for the
12874  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12875  * #GParamSpec.
12876  *
12877  * Unlike the implementation of #GObjectClass.set_property(), this
12878  * function will not update the interval if a transition involving an
12879  * animatable property is in progress - this avoids cycles with the
12880  * transition API calling the public API.
12881  */
12882 static void
12883 clutter_actor_set_animatable_property (ClutterActor *actor,
12884                                        guint         prop_id,
12885                                        const GValue *value,
12886                                        GParamSpec   *pspec)
12887 {
12888   switch (prop_id)
12889     {
12890     case PROP_X:
12891       clutter_actor_set_x_internal (actor, g_value_get_float (value));
12892       break;
12893
12894     case PROP_Y:
12895       clutter_actor_set_y_internal (actor, g_value_get_float (value));
12896       break;
12897
12898     case PROP_WIDTH:
12899       clutter_actor_set_width_internal (actor, g_value_get_float (value));
12900       break;
12901
12902     case PROP_HEIGHT:
12903       clutter_actor_set_height_internal (actor, g_value_get_float (value));
12904       break;
12905
12906     case PROP_DEPTH:
12907       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12908       break;
12909
12910     case PROP_OPACITY:
12911       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12912       break;
12913
12914     case PROP_BACKGROUND_COLOR:
12915       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12916       break;
12917
12918     case PROP_SCALE_X:
12919       clutter_actor_set_scale_factor_internal (actor,
12920                                                g_value_get_double (value),
12921                                                pspec);
12922       break;
12923
12924     case PROP_SCALE_Y:
12925       clutter_actor_set_scale_factor_internal (actor,
12926                                                g_value_get_double (value),
12927                                                pspec);
12928       break;
12929
12930     case PROP_ROTATION_ANGLE_X:
12931       clutter_actor_set_rotation_angle_internal (actor,
12932                                                  CLUTTER_X_AXIS,
12933                                                  g_value_get_double (value));
12934       break;
12935
12936     case PROP_ROTATION_ANGLE_Y:
12937       clutter_actor_set_rotation_angle_internal (actor,
12938                                                  CLUTTER_Y_AXIS,
12939                                                  g_value_get_double (value));
12940       break;
12941
12942     case PROP_ROTATION_ANGLE_Z:
12943       clutter_actor_set_rotation_angle_internal (actor,
12944                                                  CLUTTER_Z_AXIS,
12945                                                  g_value_get_double (value));
12946       break;
12947
12948     default:
12949       g_object_set_property (G_OBJECT (actor), pspec->name, value);
12950       break;
12951     }
12952 }
12953
12954 static void
12955 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12956                                const gchar       *property_name,
12957                                const GValue      *final)
12958 {
12959   ClutterActor *actor = CLUTTER_ACTOR (animatable);
12960   ClutterActorMeta *meta = NULL;
12961   gchar *p_name = NULL;
12962
12963   meta = get_meta_from_animation_property (actor,
12964                                            property_name,
12965                                            &p_name);
12966   if (meta != NULL)
12967     g_object_set_property (G_OBJECT (meta), p_name, final);
12968   else
12969     {
12970       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12971       GParamSpec *pspec;
12972
12973       pspec = g_object_class_find_property (obj_class, property_name);
12974
12975       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12976         {
12977           /* XXX - I'm going to the special hell for this */
12978           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12979         }
12980       else
12981         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
12982     }
12983
12984   g_free (p_name);
12985 }
12986
12987 static void
12988 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12989 {
12990   iface->find_property = clutter_actor_find_property;
12991   iface->get_initial_state = clutter_actor_get_initial_state;
12992   iface->set_final_state = clutter_actor_set_final_state;
12993 }
12994
12995 /**
12996  * clutter_actor_transform_stage_point:
12997  * @self: A #ClutterActor
12998  * @x: (in): x screen coordinate of the point to unproject
12999  * @y: (in): y screen coordinate of the point to unproject
13000  * @x_out: (out): return location for the unprojected x coordinance
13001  * @y_out: (out): return location for the unprojected y coordinance
13002  *
13003  * This function translates screen coordinates (@x, @y) to
13004  * coordinates relative to the actor. For example, it can be used to translate
13005  * screen events from global screen coordinates into actor-local coordinates.
13006  *
13007  * The conversion can fail, notably if the transform stack results in the
13008  * actor being projected on the screen as a mere line.
13009  *
13010  * The conversion should not be expected to be pixel-perfect due to the
13011  * nature of the operation. In general the error grows when the skewing
13012  * of the actor rectangle on screen increases.
13013  *
13014  * <note><para>This function can be computationally intensive.</para></note>
13015  *
13016  * <note><para>This function only works when the allocation is up-to-date,
13017  * i.e. inside of paint().</para></note>
13018  *
13019  * Return value: %TRUE if conversion was successful.
13020  *
13021  * Since: 0.6
13022  */
13023 gboolean
13024 clutter_actor_transform_stage_point (ClutterActor *self,
13025                                      gfloat        x,
13026                                      gfloat        y,
13027                                      gfloat       *x_out,
13028                                      gfloat       *y_out)
13029 {
13030   ClutterVertex v[4];
13031   float ST[3][3];
13032   float RQ[3][3];
13033   int du, dv, xi, yi;
13034   float px, py;
13035   float xf, yf, wf, det;
13036   ClutterActorPrivate *priv;
13037
13038   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13039
13040   priv = self->priv;
13041
13042   /* This implementation is based on the quad -> quad projection algorithm
13043    * described by Paul Heckbert in:
13044    *
13045    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13046    *
13047    * and the sample implementation at:
13048    *
13049    *   http://www.cs.cmu.edu/~ph/src/texfund/
13050    *
13051    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13052    * quad to rectangle only, which significantly simplifies things; the
13053    * function calls have been unrolled, and most of the math is done in fixed
13054    * point.
13055    */
13056
13057   clutter_actor_get_abs_allocation_vertices (self, v);
13058
13059   /* Keeping these as ints simplifies the multiplication (no significant
13060    * loss of precision here).
13061    */
13062   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13063   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13064
13065   if (!du || !dv)
13066     return FALSE;
13067
13068 #define UX2FP(x)        (x)
13069 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13070
13071   /* First, find mapping from unit uv square to xy quadrilateral; this
13072    * equivalent to the pmap_square_quad() functions in the sample
13073    * implementation, which we can simplify, since our target is always
13074    * a rectangle.
13075    */
13076   px = v[0].x - v[1].x + v[3].x - v[2].x;
13077   py = v[0].y - v[1].y + v[3].y - v[2].y;
13078
13079   if (!px && !py)
13080     {
13081       /* affine transform */
13082       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13083       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13084       RQ[2][0] = UX2FP (v[0].x);
13085       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13086       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13087       RQ[2][1] = UX2FP (v[0].y);
13088       RQ[0][2] = 0;
13089       RQ[1][2] = 0;
13090       RQ[2][2] = 1.0;
13091     }
13092   else
13093     {
13094       /* projective transform */
13095       double dx1, dx2, dy1, dy2, del;
13096
13097       dx1 = UX2FP (v[1].x - v[3].x);
13098       dx2 = UX2FP (v[2].x - v[3].x);
13099       dy1 = UX2FP (v[1].y - v[3].y);
13100       dy2 = UX2FP (v[2].y - v[3].y);
13101
13102       del = DET2FP (dx1, dx2, dy1, dy2);
13103       if (!del)
13104         return FALSE;
13105
13106       /*
13107        * The division here needs to be done in floating point for
13108        * precisions reasons.
13109        */
13110       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13111       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13112       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13113       RQ[2][2] = 1.0;
13114       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13115       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13116       RQ[2][0] = UX2FP (v[0].x);
13117       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13118       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13119       RQ[2][1] = UX2FP (v[0].y);
13120     }
13121
13122   /*
13123    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13124    * square. Since our rectangle is based at 0,0 we only need to scale.
13125    */
13126   RQ[0][0] /= du;
13127   RQ[1][0] /= dv;
13128   RQ[0][1] /= du;
13129   RQ[1][1] /= dv;
13130   RQ[0][2] /= du;
13131   RQ[1][2] /= dv;
13132
13133   /*
13134    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13135    * inverse of that.
13136    */
13137   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13138   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13139   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13140   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13141   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13142   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13143   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13144   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13145   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13146
13147   /*
13148    * Check the resulting matrix is OK.
13149    */
13150   det = (RQ[0][0] * ST[0][0])
13151       + (RQ[0][1] * ST[0][1])
13152       + (RQ[0][2] * ST[0][2]);
13153   if (!det)
13154     return FALSE;
13155
13156   /*
13157    * Now transform our point with the ST matrix; the notional w
13158    * coordinate is 1, hence the last part is simply added.
13159    */
13160   xi = (int) x;
13161   yi = (int) y;
13162
13163   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13164   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13165   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13166
13167   if (x_out)
13168     *x_out = xf / wf;
13169
13170   if (y_out)
13171     *y_out = yf / wf;
13172
13173 #undef UX2FP
13174 #undef DET2FP
13175
13176   return TRUE;
13177 }
13178
13179 /*
13180  * ClutterGeometry
13181  */
13182
13183 static ClutterGeometry*
13184 clutter_geometry_copy (const ClutterGeometry *geometry)
13185 {
13186   return g_slice_dup (ClutterGeometry, geometry);
13187 }
13188
13189 static void
13190 clutter_geometry_free (ClutterGeometry *geometry)
13191 {
13192   if (G_LIKELY (geometry != NULL))
13193     g_slice_free (ClutterGeometry, geometry);
13194 }
13195
13196 /**
13197  * clutter_geometry_union:
13198  * @geometry_a: a #ClutterGeometry
13199  * @geometry_b: another #ClutterGeometry
13200  * @result: (out): location to store the result
13201  *
13202  * Find the union of two rectangles represented as #ClutterGeometry.
13203  *
13204  * Since: 1.4
13205  */
13206 void
13207 clutter_geometry_union (const ClutterGeometry *geometry_a,
13208                         const ClutterGeometry *geometry_b,
13209                         ClutterGeometry       *result)
13210 {
13211   /* We don't try to handle rectangles that can't be represented
13212    * as a signed integer box */
13213   gint x_1 = MIN (geometry_a->x, geometry_b->x);
13214   gint y_1 = MIN (geometry_a->y, geometry_b->y);
13215   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13216                   geometry_b->x + (gint)geometry_b->width);
13217   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13218                   geometry_b->y + (gint)geometry_b->height);
13219   result->x = x_1;
13220   result->y = y_1;
13221   result->width = x_2 - x_1;
13222   result->height = y_2 - y_1;
13223 }
13224
13225 /**
13226  * clutter_geometry_intersects:
13227  * @geometry0: The first geometry to test
13228  * @geometry1: The second geometry to test
13229  *
13230  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13231  * they do else %FALSE.
13232  *
13233  * Return value: %TRUE of @geometry0 and geometry1 intersect else
13234  * %FALSE.
13235  *
13236  * Since: 1.4
13237  */
13238 gboolean
13239 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13240                              const ClutterGeometry *geometry1)
13241 {
13242   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13243       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13244       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13245       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13246     return FALSE;
13247   else
13248     return TRUE;
13249 }
13250
13251 static gboolean
13252 clutter_geometry_progress (const GValue *a,
13253                            const GValue *b,
13254                            gdouble       progress,
13255                            GValue       *retval)
13256 {
13257   const ClutterGeometry *a_geom = g_value_get_boxed (a);
13258   const ClutterGeometry *b_geom = g_value_get_boxed (b);
13259   ClutterGeometry res = { 0, };
13260   gint a_width = a_geom->width;
13261   gint b_width = b_geom->width;
13262   gint a_height = a_geom->height;
13263   gint b_height = b_geom->height;
13264
13265   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13266   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13267
13268   res.width = a_width + (b_width - a_width) * progress;
13269   res.height = a_height + (b_height - a_height) * progress;
13270
13271   g_value_set_boxed (retval, &res);
13272
13273   return TRUE;
13274 }
13275
13276 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13277                                clutter_geometry_copy,
13278                                clutter_geometry_free,
13279                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13280
13281 /*
13282  * ClutterVertices
13283  */
13284
13285 /**
13286  * clutter_vertex_new:
13287  * @x: X coordinate
13288  * @y: Y coordinate
13289  * @z: Z coordinate
13290  *
13291  * Creates a new #ClutterVertex for the point in 3D space
13292  * identified by the 3 coordinates @x, @y, @z
13293  *
13294  * Return value: the newly allocate #ClutterVertex. Use
13295  *   clutter_vertex_free() to free the resources
13296  *
13297  * Since: 1.0
13298  */
13299 ClutterVertex *
13300 clutter_vertex_new (gfloat x,
13301                     gfloat y,
13302                     gfloat z)
13303 {
13304   ClutterVertex *vertex;
13305
13306   vertex = g_slice_new (ClutterVertex);
13307   vertex->x = x;
13308   vertex->y = y;
13309   vertex->z = z;
13310
13311   return vertex;
13312 }
13313
13314 /**
13315  * clutter_vertex_copy:
13316  * @vertex: a #ClutterVertex
13317  *
13318  * Copies @vertex
13319  *
13320  * Return value: a newly allocated copy of #ClutterVertex. Use
13321  *   clutter_vertex_free() to free the allocated resources
13322  *
13323  * Since: 1.0
13324  */
13325 ClutterVertex *
13326 clutter_vertex_copy (const ClutterVertex *vertex)
13327 {
13328   if (G_LIKELY (vertex != NULL))
13329     return g_slice_dup (ClutterVertex, vertex);
13330
13331   return NULL;
13332 }
13333
13334 /**
13335  * clutter_vertex_free:
13336  * @vertex: a #ClutterVertex
13337  *
13338  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13339  *
13340  * Since: 1.0
13341  */
13342 void
13343 clutter_vertex_free (ClutterVertex *vertex)
13344 {
13345   if (G_UNLIKELY (vertex != NULL))
13346     g_slice_free (ClutterVertex, vertex);
13347 }
13348
13349 /**
13350  * clutter_vertex_equal:
13351  * @vertex_a: a #ClutterVertex
13352  * @vertex_b: a #ClutterVertex
13353  *
13354  * Compares @vertex_a and @vertex_b for equality
13355  *
13356  * Return value: %TRUE if the passed #ClutterVertex are equal
13357  *
13358  * Since: 1.0
13359  */
13360 gboolean
13361 clutter_vertex_equal (const ClutterVertex *vertex_a,
13362                       const ClutterVertex *vertex_b)
13363 {
13364   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13365
13366   if (vertex_a == vertex_b)
13367     return TRUE;
13368
13369   return vertex_a->x == vertex_b->x &&
13370          vertex_a->y == vertex_b->y &&
13371          vertex_a->z == vertex_b->z;
13372 }
13373
13374 static gboolean
13375 clutter_vertex_progress (const GValue *a,
13376                          const GValue *b,
13377                          gdouble       progress,
13378                          GValue       *retval)
13379 {
13380   const ClutterVertex *av = g_value_get_boxed (a);
13381   const ClutterVertex *bv = g_value_get_boxed (b);
13382   ClutterVertex res = { 0, };
13383
13384   res.x = av->x + (bv->x - av->x) * progress;
13385   res.y = av->y + (bv->y - av->y) * progress;
13386   res.z = av->z + (bv->z - av->z) * progress;
13387
13388   g_value_set_boxed (retval, &res);
13389
13390   return TRUE;
13391 }
13392
13393 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13394                                clutter_vertex_copy,
13395                                clutter_vertex_free,
13396                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13397
13398 /**
13399  * clutter_actor_is_rotated:
13400  * @self: a #ClutterActor
13401  *
13402  * Checks whether any rotation is applied to the actor.
13403  *
13404  * Return value: %TRUE if the actor is rotated.
13405  *
13406  * Since: 0.6
13407  */
13408 gboolean
13409 clutter_actor_is_rotated (ClutterActor *self)
13410 {
13411   const ClutterTransformInfo *info;
13412
13413   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13414
13415   info = _clutter_actor_get_transform_info_or_defaults (self);
13416
13417   if (info->rx_angle || info->ry_angle || info->rz_angle)
13418     return TRUE;
13419
13420   return FALSE;
13421 }
13422
13423 /**
13424  * clutter_actor_is_scaled:
13425  * @self: a #ClutterActor
13426  *
13427  * Checks whether the actor is scaled in either dimension.
13428  *
13429  * Return value: %TRUE if the actor is scaled.
13430  *
13431  * Since: 0.6
13432  */
13433 gboolean
13434 clutter_actor_is_scaled (ClutterActor *self)
13435 {
13436   const ClutterTransformInfo *info;
13437
13438   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13439
13440   info = _clutter_actor_get_transform_info_or_defaults (self);
13441
13442   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13443     return TRUE;
13444
13445   return FALSE;
13446 }
13447
13448 ClutterActor *
13449 _clutter_actor_get_stage_internal (ClutterActor *actor)
13450 {
13451   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13452     actor = actor->priv->parent;
13453
13454   return actor;
13455 }
13456
13457 /**
13458  * clutter_actor_get_stage:
13459  * @actor: a #ClutterActor
13460  *
13461  * Retrieves the #ClutterStage where @actor is contained.
13462  *
13463  * Return value: (transfer none) (type Clutter.Stage): the stage
13464  *   containing the actor, or %NULL
13465  *
13466  * Since: 0.8
13467  */
13468 ClutterActor *
13469 clutter_actor_get_stage (ClutterActor *actor)
13470 {
13471   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13472
13473   return _clutter_actor_get_stage_internal (actor);
13474 }
13475
13476 /**
13477  * clutter_actor_allocate_available_size:
13478  * @self: a #ClutterActor
13479  * @x: the actor's X coordinate
13480  * @y: the actor's Y coordinate
13481  * @available_width: the maximum available width, or -1 to use the
13482  *   actor's natural width
13483  * @available_height: the maximum available height, or -1 to use the
13484  *   actor's natural height
13485  * @flags: flags controlling the allocation
13486  *
13487  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13488  * preferred size, but limiting it to the maximum available width
13489  * and height provided.
13490  *
13491  * This function will do the right thing when dealing with the
13492  * actor's request mode.
13493  *
13494  * The implementation of this function is equivalent to:
13495  *
13496  * |[
13497  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13498  *     {
13499  *       clutter_actor_get_preferred_width (self, available_height,
13500  *                                          &amp;min_width,
13501  *                                          &amp;natural_width);
13502  *       width = CLAMP (natural_width, min_width, available_width);
13503  *
13504  *       clutter_actor_get_preferred_height (self, width,
13505  *                                           &amp;min_height,
13506  *                                           &amp;natural_height);
13507  *       height = CLAMP (natural_height, min_height, available_height);
13508  *     }
13509  *   else
13510  *     {
13511  *       clutter_actor_get_preferred_height (self, available_width,
13512  *                                           &amp;min_height,
13513  *                                           &amp;natural_height);
13514  *       height = CLAMP (natural_height, min_height, available_height);
13515  *
13516  *       clutter_actor_get_preferred_width (self, height,
13517  *                                          &amp;min_width,
13518  *                                          &amp;natural_width);
13519  *       width = CLAMP (natural_width, min_width, available_width);
13520  *     }
13521  *
13522  *   box.x1 = x; box.y1 = y;
13523  *   box.x2 = box.x1 + available_width;
13524  *   box.y2 = box.y1 + available_height;
13525  *   clutter_actor_allocate (self, &amp;box, flags);
13526  * ]|
13527  *
13528  * This function can be used by fluid layout managers to allocate
13529  * an actor's preferred size without making it bigger than the area
13530  * available for the container.
13531  *
13532  * Since: 1.0
13533  */
13534 void
13535 clutter_actor_allocate_available_size (ClutterActor           *self,
13536                                        gfloat                  x,
13537                                        gfloat                  y,
13538                                        gfloat                  available_width,
13539                                        gfloat                  available_height,
13540                                        ClutterAllocationFlags  flags)
13541 {
13542   ClutterActorPrivate *priv;
13543   gfloat width, height;
13544   gfloat min_width, min_height;
13545   gfloat natural_width, natural_height;
13546   ClutterActorBox box;
13547
13548   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13549
13550   priv = self->priv;
13551
13552   width = height = 0.0;
13553
13554   switch (priv->request_mode)
13555     {
13556     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13557       clutter_actor_get_preferred_width (self, available_height,
13558                                          &min_width,
13559                                          &natural_width);
13560       width  = CLAMP (natural_width, min_width, available_width);
13561
13562       clutter_actor_get_preferred_height (self, width,
13563                                           &min_height,
13564                                           &natural_height);
13565       height = CLAMP (natural_height, min_height, available_height);
13566       break;
13567
13568     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13569       clutter_actor_get_preferred_height (self, available_width,
13570                                           &min_height,
13571                                           &natural_height);
13572       height = CLAMP (natural_height, min_height, available_height);
13573
13574       clutter_actor_get_preferred_width (self, height,
13575                                          &min_width,
13576                                          &natural_width);
13577       width  = CLAMP (natural_width, min_width, available_width);
13578       break;
13579     }
13580
13581
13582   box.x1 = x;
13583   box.y1 = y;
13584   box.x2 = box.x1 + width;
13585   box.y2 = box.y1 + height;
13586   clutter_actor_allocate (self, &box, flags);
13587 }
13588
13589 /**
13590  * clutter_actor_allocate_preferred_size:
13591  * @self: a #ClutterActor
13592  * @flags: flags controlling the allocation
13593  *
13594  * Allocates the natural size of @self.
13595  *
13596  * This function is a utility call for #ClutterActor implementations
13597  * that allocates the actor's preferred natural size. It can be used
13598  * by fixed layout managers (like #ClutterGroup or so called
13599  * 'composite actors') inside the ClutterActor::allocate
13600  * implementation to give each child exactly how much space it
13601  * requires.
13602  *
13603  * This function is not meant to be used by applications. It is also
13604  * not meant to be used outside the implementation of the
13605  * ClutterActor::allocate virtual function.
13606  *
13607  * Since: 0.8
13608  */
13609 void
13610 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13611                                        ClutterAllocationFlags  flags)
13612 {
13613   gfloat actor_x, actor_y;
13614   gfloat natural_width, natural_height;
13615   ClutterActorBox actor_box;
13616
13617   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13618
13619   actor_x = clutter_actor_get_x (self);
13620   actor_y = clutter_actor_get_y (self);
13621
13622   clutter_actor_get_preferred_size (self,
13623                                     NULL, NULL,
13624                                     &natural_width,
13625                                     &natural_height);
13626
13627   actor_box.x1 = actor_x;
13628   actor_box.y1 = actor_y;
13629   actor_box.x2 = actor_box.x1 + natural_width;
13630   actor_box.y2 = actor_box.y1 + natural_height;
13631
13632   clutter_actor_allocate (self, &actor_box, flags);
13633 }
13634
13635 /**
13636  * clutter_actor_allocate_align_fill:
13637  * @self: a #ClutterActor
13638  * @box: a #ClutterActorBox, containing the available width and height
13639  * @x_align: the horizontal alignment, between 0 and 1
13640  * @y_align: the vertical alignment, between 0 and 1
13641  * @x_fill: whether the actor should fill horizontally
13642  * @y_fill: whether the actor should fill vertically
13643  * @flags: allocation flags to be passed to clutter_actor_allocate()
13644  *
13645  * Allocates @self by taking into consideration the available allocation
13646  * area; an alignment factor on either axis; and whether the actor should
13647  * fill the allocation on either axis.
13648  *
13649  * The @box should contain the available allocation width and height;
13650  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13651  * allocation will be offset by their value.
13652  *
13653  * This function takes into consideration the geometry request specified by
13654  * the #ClutterActor:request-mode property, and the text direction.
13655  *
13656  * This function is useful for fluid layout managers, like #ClutterBinLayout
13657  * or #ClutterTableLayout
13658  *
13659  * Since: 1.4
13660  */
13661 void
13662 clutter_actor_allocate_align_fill (ClutterActor           *self,
13663                                    const ClutterActorBox  *box,
13664                                    gdouble                 x_align,
13665                                    gdouble                 y_align,
13666                                    gboolean                x_fill,
13667                                    gboolean                y_fill,
13668                                    ClutterAllocationFlags  flags)
13669 {
13670   ClutterActorPrivate *priv;
13671   ClutterActorBox allocation = { 0, };
13672   gfloat x_offset, y_offset;
13673   gfloat available_width, available_height;
13674   gfloat child_width, child_height;
13675
13676   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13677   g_return_if_fail (box != NULL);
13678   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13679   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13680
13681   priv = self->priv;
13682
13683   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13684   clutter_actor_box_get_size (box, &available_width, &available_height);
13685
13686   if (available_width < 0)
13687     available_width = 0;
13688
13689   if (available_height < 0)
13690     available_height = 0;
13691
13692   if (x_fill)
13693     {
13694       allocation.x1 = x_offset;
13695       allocation.x2 = allocation.x1 + available_width;
13696     }
13697
13698   if (y_fill)
13699     {
13700       allocation.y1 = y_offset;
13701       allocation.y2 = allocation.y1 + available_height;
13702     }
13703
13704   /* if we are filling horizontally and vertically then we're done */
13705   if (x_fill && y_fill)
13706     goto out;
13707
13708   child_width = child_height = 0.0f;
13709
13710   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13711     {
13712       gfloat min_width, natural_width;
13713       gfloat min_height, natural_height;
13714
13715       clutter_actor_get_preferred_width (self, available_height,
13716                                          &min_width,
13717                                          &natural_width);
13718
13719       child_width = CLAMP (natural_width, min_width, available_width);
13720
13721       if (!y_fill)
13722         {
13723           clutter_actor_get_preferred_height (self, child_width,
13724                                               &min_height,
13725                                               &natural_height);
13726
13727           child_height = CLAMP (natural_height, min_height, available_height);
13728         }
13729     }
13730   else
13731     {
13732       gfloat min_width, natural_width;
13733       gfloat min_height, natural_height;
13734
13735       clutter_actor_get_preferred_height (self, available_width,
13736                                           &min_height,
13737                                           &natural_height);
13738
13739       child_height = CLAMP (natural_height, min_height, available_height);
13740
13741       if (!x_fill)
13742         {
13743           clutter_actor_get_preferred_width (self, child_height,
13744                                              &min_width,
13745                                              &natural_width);
13746
13747           child_width = CLAMP (natural_width, min_width, available_width);
13748         }
13749     }
13750
13751   /* invert the horizontal alignment for RTL languages */
13752   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13753     x_align = 1.0 - x_align;
13754
13755   if (!x_fill)
13756     {
13757       allocation.x1 = x_offset
13758                     + ((available_width - child_width) * x_align);
13759       allocation.x2 = allocation.x1 + child_width;
13760     }
13761
13762   if (!y_fill)
13763     {
13764       allocation.y1 = y_offset
13765                     + ((available_height - child_height) * y_align);
13766       allocation.y2 = allocation.y1 + child_height;
13767     }
13768
13769 out:
13770   clutter_actor_box_clamp_to_pixel (&allocation);
13771   clutter_actor_allocate (self, &allocation, flags);
13772 }
13773
13774 /**
13775  * clutter_actor_grab_key_focus:
13776  * @self: a #ClutterActor
13777  *
13778  * Sets the key focus of the #ClutterStage including @self
13779  * to this #ClutterActor.
13780  *
13781  * Since: 1.0
13782  */
13783 void
13784 clutter_actor_grab_key_focus (ClutterActor *self)
13785 {
13786   ClutterActor *stage;
13787
13788   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13789
13790   stage = _clutter_actor_get_stage_internal (self);
13791   if (stage != NULL)
13792     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13793 }
13794
13795 /**
13796  * clutter_actor_get_pango_context:
13797  * @self: a #ClutterActor
13798  *
13799  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13800  * is already configured using the appropriate font map, resolution
13801  * and font options.
13802  *
13803  * Unlike clutter_actor_create_pango_context(), this context is owend
13804  * by the #ClutterActor and it will be updated each time the options
13805  * stored by the #ClutterBackend change.
13806  *
13807  * You can use the returned #PangoContext to create a #PangoLayout
13808  * and render text using cogl_pango_render_layout() to reuse the
13809  * glyphs cache also used by Clutter.
13810  *
13811  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13812  *   The returned #PangoContext is owned by the actor and should not be
13813  *   unreferenced by the application code
13814  *
13815  * Since: 1.0
13816  */
13817 PangoContext *
13818 clutter_actor_get_pango_context (ClutterActor *self)
13819 {
13820   ClutterActorPrivate *priv;
13821
13822   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13823
13824   priv = self->priv;
13825
13826   if (priv->pango_context != NULL)
13827     return priv->pango_context;
13828
13829   priv->pango_context = _clutter_context_get_pango_context ();
13830   g_object_ref (priv->pango_context);
13831
13832   return priv->pango_context;
13833 }
13834
13835 /**
13836  * clutter_actor_create_pango_context:
13837  * @self: a #ClutterActor
13838  *
13839  * Creates a #PangoContext for the given actor. The #PangoContext
13840  * is already configured using the appropriate font map, resolution
13841  * and font options.
13842  *
13843  * See also clutter_actor_get_pango_context().
13844  *
13845  * Return value: (transfer full): the newly created #PangoContext.
13846  *   Use g_object_unref() on the returned value to deallocate its
13847  *   resources
13848  *
13849  * Since: 1.0
13850  */
13851 PangoContext *
13852 clutter_actor_create_pango_context (ClutterActor *self)
13853 {
13854   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13855
13856   return _clutter_context_create_pango_context ();
13857 }
13858
13859 /**
13860  * clutter_actor_create_pango_layout:
13861  * @self: a #ClutterActor
13862  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13863  *
13864  * Creates a new #PangoLayout from the same #PangoContext used
13865  * by the #ClutterActor. The #PangoLayout is already configured
13866  * with the font map, resolution and font options, and the
13867  * given @text.
13868  *
13869  * If you want to keep around a #PangoLayout created by this
13870  * function you will have to connect to the #ClutterBackend::font-changed
13871  * and #ClutterBackend::resolution-changed signals, and call
13872  * pango_layout_context_changed() in response to them.
13873  *
13874  * Return value: (transfer full): the newly created #PangoLayout.
13875  *   Use g_object_unref() when done
13876  *
13877  * Since: 1.0
13878  */
13879 PangoLayout *
13880 clutter_actor_create_pango_layout (ClutterActor *self,
13881                                    const gchar  *text)
13882 {
13883   PangoContext *context;
13884   PangoLayout *layout;
13885
13886   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13887
13888   context = clutter_actor_get_pango_context (self);
13889   layout = pango_layout_new (context);
13890
13891   if (text)
13892     pango_layout_set_text (layout, text, -1);
13893
13894   return layout;
13895 }
13896
13897 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13898  * ClutterOffscreenEffect.
13899  */
13900 void
13901 _clutter_actor_set_opacity_override (ClutterActor *self,
13902                                      gint          opacity)
13903 {
13904   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13905
13906   self->priv->opacity_override = opacity;
13907 }
13908
13909 gint
13910 _clutter_actor_get_opacity_override (ClutterActor *self)
13911 {
13912   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13913
13914   return self->priv->opacity_override;
13915 }
13916
13917 /* Allows you to disable applying the actors model view transform during
13918  * a paint. Used by ClutterClone. */
13919 void
13920 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13921                                                 gboolean      enable)
13922 {
13923   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13924
13925   self->priv->enable_model_view_transform = enable;
13926 }
13927
13928 void
13929 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13930                                           gboolean      enable)
13931 {
13932   ClutterActorPrivate *priv;
13933
13934   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13935
13936   priv = self->priv;
13937
13938   priv->enable_paint_unmapped = enable;
13939
13940   if (priv->enable_paint_unmapped)
13941     {
13942       /* Make sure that the parents of the widget are realized first;
13943        * otherwise checks in clutter_actor_update_map_state() will
13944        * fail.
13945        */
13946       clutter_actor_realize (self);
13947
13948       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13949     }
13950   else
13951     {
13952       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13953     }
13954 }
13955
13956 static void
13957 clutter_anchor_coord_get_units (ClutterActor      *self,
13958                                 const AnchorCoord *coord,
13959                                 gfloat            *x,
13960                                 gfloat            *y,
13961                                 gfloat            *z)
13962 {
13963   if (coord->is_fractional)
13964     {
13965       gfloat actor_width, actor_height;
13966
13967       clutter_actor_get_size (self, &actor_width, &actor_height);
13968
13969       if (x)
13970         *x = actor_width * coord->v.fraction.x;
13971
13972       if (y)
13973         *y = actor_height * coord->v.fraction.y;
13974
13975       if (z)
13976         *z = 0;
13977     }
13978   else
13979     {
13980       if (x)
13981         *x = coord->v.units.x;
13982
13983       if (y)
13984         *y = coord->v.units.y;
13985
13986       if (z)
13987         *z = coord->v.units.z;
13988     }
13989 }
13990
13991 static void
13992 clutter_anchor_coord_set_units (AnchorCoord *coord,
13993                                 gfloat       x,
13994                                 gfloat       y,
13995                                 gfloat       z)
13996 {
13997   coord->is_fractional = FALSE;
13998   coord->v.units.x = x;
13999   coord->v.units.y = y;
14000   coord->v.units.z = z;
14001 }
14002
14003 static ClutterGravity
14004 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14005 {
14006   if (coord->is_fractional)
14007     {
14008       if (coord->v.fraction.x == 0.0)
14009         {
14010           if (coord->v.fraction.y == 0.0)
14011             return CLUTTER_GRAVITY_NORTH_WEST;
14012           else if (coord->v.fraction.y == 0.5)
14013             return CLUTTER_GRAVITY_WEST;
14014           else if (coord->v.fraction.y == 1.0)
14015             return CLUTTER_GRAVITY_SOUTH_WEST;
14016           else
14017             return CLUTTER_GRAVITY_NONE;
14018         }
14019       else if (coord->v.fraction.x == 0.5)
14020         {
14021           if (coord->v.fraction.y == 0.0)
14022             return CLUTTER_GRAVITY_NORTH;
14023           else if (coord->v.fraction.y == 0.5)
14024             return CLUTTER_GRAVITY_CENTER;
14025           else if (coord->v.fraction.y == 1.0)
14026             return CLUTTER_GRAVITY_SOUTH;
14027           else
14028             return CLUTTER_GRAVITY_NONE;
14029         }
14030       else if (coord->v.fraction.x == 1.0)
14031         {
14032           if (coord->v.fraction.y == 0.0)
14033             return CLUTTER_GRAVITY_NORTH_EAST;
14034           else if (coord->v.fraction.y == 0.5)
14035             return CLUTTER_GRAVITY_EAST;
14036           else if (coord->v.fraction.y == 1.0)
14037             return CLUTTER_GRAVITY_SOUTH_EAST;
14038           else
14039             return CLUTTER_GRAVITY_NONE;
14040         }
14041       else
14042         return CLUTTER_GRAVITY_NONE;
14043     }
14044   else
14045     return CLUTTER_GRAVITY_NONE;
14046 }
14047
14048 static void
14049 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14050                                   ClutterGravity  gravity)
14051 {
14052   switch (gravity)
14053     {
14054     case CLUTTER_GRAVITY_NORTH:
14055       coord->v.fraction.x = 0.5;
14056       coord->v.fraction.y = 0.0;
14057       break;
14058
14059     case CLUTTER_GRAVITY_NORTH_EAST:
14060       coord->v.fraction.x = 1.0;
14061       coord->v.fraction.y = 0.0;
14062       break;
14063
14064     case CLUTTER_GRAVITY_EAST:
14065       coord->v.fraction.x = 1.0;
14066       coord->v.fraction.y = 0.5;
14067       break;
14068
14069     case CLUTTER_GRAVITY_SOUTH_EAST:
14070       coord->v.fraction.x = 1.0;
14071       coord->v.fraction.y = 1.0;
14072       break;
14073
14074     case CLUTTER_GRAVITY_SOUTH:
14075       coord->v.fraction.x = 0.5;
14076       coord->v.fraction.y = 1.0;
14077       break;
14078
14079     case CLUTTER_GRAVITY_SOUTH_WEST:
14080       coord->v.fraction.x = 0.0;
14081       coord->v.fraction.y = 1.0;
14082       break;
14083
14084     case CLUTTER_GRAVITY_WEST:
14085       coord->v.fraction.x = 0.0;
14086       coord->v.fraction.y = 0.5;
14087       break;
14088
14089     case CLUTTER_GRAVITY_NORTH_WEST:
14090       coord->v.fraction.x = 0.0;
14091       coord->v.fraction.y = 0.0;
14092       break;
14093
14094     case CLUTTER_GRAVITY_CENTER:
14095       coord->v.fraction.x = 0.5;
14096       coord->v.fraction.y = 0.5;
14097       break;
14098
14099     default:
14100       coord->v.fraction.x = 0.0;
14101       coord->v.fraction.y = 0.0;
14102       break;
14103     }
14104
14105   coord->is_fractional = TRUE;
14106 }
14107
14108 static gboolean
14109 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14110 {
14111   if (coord->is_fractional)
14112     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14113   else
14114     return (coord->v.units.x == 0.0
14115             && coord->v.units.y == 0.0
14116             && coord->v.units.z == 0.0);
14117 }
14118
14119 /**
14120  * clutter_actor_get_flags:
14121  * @self: a #ClutterActor
14122  *
14123  * Retrieves the flags set on @self
14124  *
14125  * Return value: a bitwise or of #ClutterActorFlags or 0
14126  *
14127  * Since: 1.0
14128  */
14129 ClutterActorFlags
14130 clutter_actor_get_flags (ClutterActor *self)
14131 {
14132   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14133
14134   return self->flags;
14135 }
14136
14137 /**
14138  * clutter_actor_set_flags:
14139  * @self: a #ClutterActor
14140  * @flags: the flags to set
14141  *
14142  * Sets @flags on @self
14143  *
14144  * This function will emit notifications for the changed properties
14145  *
14146  * Since: 1.0
14147  */
14148 void
14149 clutter_actor_set_flags (ClutterActor      *self,
14150                          ClutterActorFlags  flags)
14151 {
14152   ClutterActorFlags old_flags;
14153   GObject *obj;
14154   gboolean was_reactive_set, reactive_set;
14155   gboolean was_realized_set, realized_set;
14156   gboolean was_mapped_set, mapped_set;
14157   gboolean was_visible_set, visible_set;
14158
14159   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14160
14161   if (self->flags == flags)
14162     return;
14163
14164   obj = G_OBJECT (self);
14165   g_object_ref (obj);
14166   g_object_freeze_notify (obj);
14167
14168   old_flags = self->flags;
14169
14170   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14171   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14172   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14173   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14174
14175   self->flags |= flags;
14176
14177   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14178   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14179   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14180   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14181
14182   if (reactive_set != was_reactive_set)
14183     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14184
14185   if (realized_set != was_realized_set)
14186     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14187
14188   if (mapped_set != was_mapped_set)
14189     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14190
14191   if (visible_set != was_visible_set)
14192     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14193
14194   g_object_thaw_notify (obj);
14195   g_object_unref (obj);
14196 }
14197
14198 /**
14199  * clutter_actor_unset_flags:
14200  * @self: a #ClutterActor
14201  * @flags: the flags to unset
14202  *
14203  * Unsets @flags on @self
14204  *
14205  * This function will emit notifications for the changed properties
14206  *
14207  * Since: 1.0
14208  */
14209 void
14210 clutter_actor_unset_flags (ClutterActor      *self,
14211                            ClutterActorFlags  flags)
14212 {
14213   ClutterActorFlags old_flags;
14214   GObject *obj;
14215   gboolean was_reactive_set, reactive_set;
14216   gboolean was_realized_set, realized_set;
14217   gboolean was_mapped_set, mapped_set;
14218   gboolean was_visible_set, visible_set;
14219
14220   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14221
14222   obj = G_OBJECT (self);
14223   g_object_freeze_notify (obj);
14224
14225   old_flags = self->flags;
14226
14227   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14228   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14229   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14230   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14231
14232   self->flags &= ~flags;
14233
14234   if (self->flags == old_flags)
14235     return;
14236
14237   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14238   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14239   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14240   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14241
14242   if (reactive_set != was_reactive_set)
14243     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14244
14245   if (realized_set != was_realized_set)
14246     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14247
14248   if (mapped_set != was_mapped_set)
14249     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14250
14251   if (visible_set != was_visible_set)
14252     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14253
14254   g_object_thaw_notify (obj);
14255 }
14256
14257 /**
14258  * clutter_actor_get_transformation_matrix:
14259  * @self: a #ClutterActor
14260  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14261  *
14262  * Retrieves the transformations applied to @self relative to its
14263  * parent.
14264  *
14265  * Since: 1.0
14266  */
14267 void
14268 clutter_actor_get_transformation_matrix (ClutterActor *self,
14269                                          CoglMatrix   *matrix)
14270 {
14271   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14272
14273   cogl_matrix_init_identity (matrix);
14274
14275   _clutter_actor_apply_modelview_transform (self, matrix);
14276 }
14277
14278 void
14279 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14280                                    gboolean      is_in_clone_paint)
14281 {
14282   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14283   self->priv->in_clone_paint = is_in_clone_paint;
14284 }
14285
14286 /**
14287  * clutter_actor_is_in_clone_paint:
14288  * @self: a #ClutterActor
14289  *
14290  * Checks whether @self is being currently painted by a #ClutterClone
14291  *
14292  * This function is useful only inside the ::paint virtual function
14293  * implementations or within handlers for the #ClutterActor::paint
14294  * signal
14295  *
14296  * This function should not be used by applications
14297  *
14298  * Return value: %TRUE if the #ClutterActor is currently being painted
14299  *   by a #ClutterClone, and %FALSE otherwise
14300  *
14301  * Since: 1.0
14302  */
14303 gboolean
14304 clutter_actor_is_in_clone_paint (ClutterActor *self)
14305 {
14306   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14307
14308   return self->priv->in_clone_paint;
14309 }
14310
14311 static gboolean
14312 set_direction_recursive (ClutterActor *actor,
14313                          gpointer      user_data)
14314 {
14315   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14316
14317   clutter_actor_set_text_direction (actor, text_dir);
14318
14319   return TRUE;
14320 }
14321
14322 /**
14323  * clutter_actor_set_text_direction:
14324  * @self: a #ClutterActor
14325  * @text_dir: the text direction for @self
14326  *
14327  * Sets the #ClutterTextDirection for an actor
14328  *
14329  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14330  *
14331  * If @self implements #ClutterContainer then this function will recurse
14332  * inside all the children of @self (including the internal ones).
14333  *
14334  * Composite actors not implementing #ClutterContainer, or actors requiring
14335  * special handling when the text direction changes, should connect to
14336  * the #GObject::notify signal for the #ClutterActor:text-direction property
14337  *
14338  * Since: 1.2
14339  */
14340 void
14341 clutter_actor_set_text_direction (ClutterActor         *self,
14342                                   ClutterTextDirection  text_dir)
14343 {
14344   ClutterActorPrivate *priv;
14345
14346   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14347   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14348
14349   priv = self->priv;
14350
14351   if (priv->text_direction != text_dir)
14352     {
14353       priv->text_direction = text_dir;
14354
14355       /* we need to emit the notify::text-direction first, so that
14356        * the sub-classes can catch that and do specific handling of
14357        * the text direction; see clutter_text_direction_changed_cb()
14358        * inside clutter-text.c
14359        */
14360       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14361
14362       _clutter_actor_foreach_child (self, set_direction_recursive,
14363                                     GINT_TO_POINTER (text_dir));
14364
14365       clutter_actor_queue_relayout (self);
14366     }
14367 }
14368
14369 void
14370 _clutter_actor_set_has_pointer (ClutterActor *self,
14371                                 gboolean      has_pointer)
14372 {
14373   ClutterActorPrivate *priv = self->priv;
14374
14375   if (priv->has_pointer != has_pointer)
14376     {
14377       priv->has_pointer = has_pointer;
14378
14379       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14380     }
14381 }
14382
14383 /**
14384  * clutter_actor_get_text_direction:
14385  * @self: a #ClutterActor
14386  *
14387  * Retrieves the value set using clutter_actor_set_text_direction()
14388  *
14389  * If no text direction has been previously set, the default text
14390  * direction, as returned by clutter_get_default_text_direction(), will
14391  * be returned instead
14392  *
14393  * Return value: the #ClutterTextDirection for the actor
14394  *
14395  * Since: 1.2
14396  */
14397 ClutterTextDirection
14398 clutter_actor_get_text_direction (ClutterActor *self)
14399 {
14400   ClutterActorPrivate *priv;
14401
14402   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14403                         CLUTTER_TEXT_DIRECTION_LTR);
14404
14405   priv = self->priv;
14406
14407   /* if no direction has been set yet use the default */
14408   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14409     priv->text_direction = clutter_get_default_text_direction ();
14410
14411   return priv->text_direction;
14412 }
14413
14414 /**
14415  * clutter_actor_push_internal:
14416  * @self: a #ClutterActor
14417  *
14418  * Should be used by actors implementing the #ClutterContainer and with
14419  * internal children added through clutter_actor_set_parent(), for instance:
14420  *
14421  * |[
14422  *   static void
14423  *   my_actor_init (MyActor *self)
14424  *   {
14425  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14426  *
14427  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14428  *
14429  *     /&ast; calling clutter_actor_set_parent() now will result in
14430  *      &ast; the internal flag being set on a child of MyActor
14431  *      &ast;/
14432  *
14433  *     /&ast; internal child - a background texture &ast;/
14434  *     self->priv->background_tex = clutter_texture_new ();
14435  *     clutter_actor_set_parent (self->priv->background_tex,
14436  *                               CLUTTER_ACTOR (self));
14437  *
14438  *     /&ast; internal child - a label &ast;/
14439  *     self->priv->label = clutter_text_new ();
14440  *     clutter_actor_set_parent (self->priv->label,
14441  *                               CLUTTER_ACTOR (self));
14442  *
14443  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14444  *
14445  *     /&ast; calling clutter_actor_set_parent() now will not result in
14446  *      &ast; the internal flag being set on a child of MyActor
14447  *      &ast;/
14448  *   }
14449  * ]|
14450  *
14451  * This function will be used by Clutter to toggle an "internal child"
14452  * flag whenever clutter_actor_set_parent() is called; internal children
14453  * are handled differently by Clutter, specifically when destroying their
14454  * parent.
14455  *
14456  * Call clutter_actor_pop_internal() when you finished adding internal
14457  * children.
14458  *
14459  * Nested calls to clutter_actor_push_internal() are allowed, but each
14460  * one must by followed by a clutter_actor_pop_internal() call.
14461  *
14462  * Since: 1.2
14463  *
14464  * Deprecated: 1.10: All children of an actor are accessible through
14465  *   the #ClutterActor API, and #ClutterActor implements the
14466  *   #ClutterContainer interface, so this function is only useful
14467  *   for legacy containers overriding the default implementation.
14468  */
14469 void
14470 clutter_actor_push_internal (ClutterActor *self)
14471 {
14472   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14473
14474   self->priv->internal_child += 1;
14475 }
14476
14477 /**
14478  * clutter_actor_pop_internal:
14479  * @self: a #ClutterActor
14480  *
14481  * Disables the effects of clutter_actor_push_internal().
14482  *
14483  * Since: 1.2
14484  *
14485  * Deprecated: 1.10: All children of an actor are accessible through
14486  *   the #ClutterActor API. This function is only useful for legacy
14487  *   containers overriding the default implementation of the
14488  *   #ClutterContainer interface.
14489  */
14490 void
14491 clutter_actor_pop_internal (ClutterActor *self)
14492 {
14493   ClutterActorPrivate *priv;
14494
14495   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14496
14497   priv = self->priv;
14498
14499   if (priv->internal_child == 0)
14500     {
14501       g_warning ("Mismatched %s: you need to call "
14502                  "clutter_actor_push_composite() at least once before "
14503                  "calling this function", G_STRFUNC);
14504       return;
14505     }
14506
14507   priv->internal_child -= 1;
14508 }
14509
14510 /**
14511  * clutter_actor_has_pointer:
14512  * @self: a #ClutterActor
14513  *
14514  * Checks whether an actor contains the pointer of a
14515  * #ClutterInputDevice
14516  *
14517  * Return value: %TRUE if the actor contains the pointer, and
14518  *   %FALSE otherwise
14519  *
14520  * Since: 1.2
14521  */
14522 gboolean
14523 clutter_actor_has_pointer (ClutterActor *self)
14524 {
14525   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14526
14527   return self->priv->has_pointer;
14528 }
14529
14530 /* XXX: This is a workaround for not being able to break the ABI of
14531  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14532  * clutter_actor_queue_clipped_redraw() for details.
14533  */
14534 ClutterPaintVolume *
14535 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14536 {
14537   return g_object_get_data (G_OBJECT (self),
14538                             "-clutter-actor-queue-redraw-clip");
14539 }
14540
14541 void
14542 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14543                                       ClutterPaintVolume *clip)
14544 {
14545   g_object_set_data (G_OBJECT (self),
14546                      "-clutter-actor-queue-redraw-clip",
14547                      clip);
14548 }
14549
14550 /**
14551  * clutter_actor_has_allocation:
14552  * @self: a #ClutterActor
14553  *
14554  * Checks if the actor has an up-to-date allocation assigned to
14555  * it. This means that the actor should have an allocation: it's
14556  * visible and has a parent. It also means that there is no
14557  * outstanding relayout request in progress for the actor or its
14558  * children (There might be other outstanding layout requests in
14559  * progress that will cause the actor to get a new allocation
14560  * when the stage is laid out, however).
14561  *
14562  * If this function returns %FALSE, then the actor will normally
14563  * be allocated before it is next drawn on the screen.
14564  *
14565  * Return value: %TRUE if the actor has an up-to-date allocation
14566  *
14567  * Since: 1.4
14568  */
14569 gboolean
14570 clutter_actor_has_allocation (ClutterActor *self)
14571 {
14572   ClutterActorPrivate *priv;
14573
14574   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14575
14576   priv = self->priv;
14577
14578   return priv->parent != NULL &&
14579          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14580          !priv->needs_allocation;
14581 }
14582
14583 /**
14584  * clutter_actor_add_action:
14585  * @self: a #ClutterActor
14586  * @action: a #ClutterAction
14587  *
14588  * Adds @action to the list of actions applied to @self
14589  *
14590  * A #ClutterAction can only belong to one actor at a time
14591  *
14592  * The #ClutterActor will hold a reference on @action until either
14593  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14594  * is called
14595  *
14596  * Since: 1.4
14597  */
14598 void
14599 clutter_actor_add_action (ClutterActor  *self,
14600                           ClutterAction *action)
14601 {
14602   ClutterActorPrivate *priv;
14603
14604   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14605   g_return_if_fail (CLUTTER_IS_ACTION (action));
14606
14607   priv = self->priv;
14608
14609   if (priv->actions == NULL)
14610     {
14611       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14612       priv->actions->actor = self;
14613     }
14614
14615   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14616
14617   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14618 }
14619
14620 /**
14621  * clutter_actor_add_action_with_name:
14622  * @self: a #ClutterActor
14623  * @name: the name to set on the action
14624  * @action: a #ClutterAction
14625  *
14626  * A convenience function for setting the name of a #ClutterAction
14627  * while adding it to the list of actions applied to @self
14628  *
14629  * This function is the logical equivalent of:
14630  *
14631  * |[
14632  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14633  *   clutter_actor_add_action (self, action);
14634  * ]|
14635  *
14636  * Since: 1.4
14637  */
14638 void
14639 clutter_actor_add_action_with_name (ClutterActor  *self,
14640                                     const gchar   *name,
14641                                     ClutterAction *action)
14642 {
14643   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14644   g_return_if_fail (name != NULL);
14645   g_return_if_fail (CLUTTER_IS_ACTION (action));
14646
14647   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14648   clutter_actor_add_action (self, action);
14649 }
14650
14651 /**
14652  * clutter_actor_remove_action:
14653  * @self: a #ClutterActor
14654  * @action: a #ClutterAction
14655  *
14656  * Removes @action from the list of actions applied to @self
14657  *
14658  * The reference held by @self on the #ClutterAction will be released
14659  *
14660  * Since: 1.4
14661  */
14662 void
14663 clutter_actor_remove_action (ClutterActor  *self,
14664                              ClutterAction *action)
14665 {
14666   ClutterActorPrivate *priv;
14667
14668   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14669   g_return_if_fail (CLUTTER_IS_ACTION (action));
14670
14671   priv = self->priv;
14672
14673   if (priv->actions == NULL)
14674     return;
14675
14676   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14677
14678   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14679 }
14680
14681 /**
14682  * clutter_actor_remove_action_by_name:
14683  * @self: a #ClutterActor
14684  * @name: the name of the action to remove
14685  *
14686  * Removes the #ClutterAction with the given name from the list
14687  * of actions applied to @self
14688  *
14689  * Since: 1.4
14690  */
14691 void
14692 clutter_actor_remove_action_by_name (ClutterActor *self,
14693                                      const gchar  *name)
14694 {
14695   ClutterActorPrivate *priv;
14696   ClutterActorMeta *meta;
14697
14698   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14699   g_return_if_fail (name != NULL);
14700
14701   priv = self->priv;
14702
14703   if (priv->actions == NULL)
14704     return;
14705
14706   meta = _clutter_meta_group_get_meta (priv->actions, name);
14707   if (meta == NULL)
14708     return;
14709
14710   _clutter_meta_group_remove_meta (priv->actions, meta);
14711
14712   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14713 }
14714
14715 /**
14716  * clutter_actor_get_actions:
14717  * @self: a #ClutterActor
14718  *
14719  * Retrieves the list of actions applied to @self
14720  *
14721  * Return value: (transfer container) (element-type Clutter.Action): a copy
14722  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14723  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14724  *   allocated by the returned #GList
14725  *
14726  * Since: 1.4
14727  */
14728 GList *
14729 clutter_actor_get_actions (ClutterActor *self)
14730 {
14731   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14732
14733   if (self->priv->actions == NULL)
14734     return NULL;
14735
14736   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14737 }
14738
14739 /**
14740  * clutter_actor_get_action:
14741  * @self: a #ClutterActor
14742  * @name: the name of the action to retrieve
14743  *
14744  * Retrieves the #ClutterAction with the given name in the list
14745  * of actions applied to @self
14746  *
14747  * Return value: (transfer none): a #ClutterAction for the given
14748  *   name, or %NULL. The returned #ClutterAction is owned by the
14749  *   actor and it should not be unreferenced directly
14750  *
14751  * Since: 1.4
14752  */
14753 ClutterAction *
14754 clutter_actor_get_action (ClutterActor *self,
14755                           const gchar  *name)
14756 {
14757   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14758   g_return_val_if_fail (name != NULL, NULL);
14759
14760   if (self->priv->actions == NULL)
14761     return NULL;
14762
14763   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14764 }
14765
14766 /**
14767  * clutter_actor_clear_actions:
14768  * @self: a #ClutterActor
14769  *
14770  * Clears the list of actions applied to @self
14771  *
14772  * Since: 1.4
14773  */
14774 void
14775 clutter_actor_clear_actions (ClutterActor *self)
14776 {
14777   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14778
14779   if (self->priv->actions == NULL)
14780     return;
14781
14782   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14783 }
14784
14785 /**
14786  * clutter_actor_add_constraint:
14787  * @self: a #ClutterActor
14788  * @constraint: a #ClutterConstraint
14789  *
14790  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14791  * to @self
14792  *
14793  * The #ClutterActor will hold a reference on the @constraint until
14794  * either clutter_actor_remove_constraint() or
14795  * clutter_actor_clear_constraints() is called.
14796  *
14797  * Since: 1.4
14798  */
14799 void
14800 clutter_actor_add_constraint (ClutterActor      *self,
14801                               ClutterConstraint *constraint)
14802 {
14803   ClutterActorPrivate *priv;
14804
14805   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14806   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14807
14808   priv = self->priv;
14809
14810   if (priv->constraints == NULL)
14811     {
14812       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14813       priv->constraints->actor = self;
14814     }
14815
14816   _clutter_meta_group_add_meta (priv->constraints,
14817                                 CLUTTER_ACTOR_META (constraint));
14818   clutter_actor_queue_relayout (self);
14819
14820   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14821 }
14822
14823 /**
14824  * clutter_actor_add_constraint_with_name:
14825  * @self: a #ClutterActor
14826  * @name: the name to set on the constraint
14827  * @constraint: a #ClutterConstraint
14828  *
14829  * A convenience function for setting the name of a #ClutterConstraint
14830  * while adding it to the list of constraints applied to @self
14831  *
14832  * This function is the logical equivalent of:
14833  *
14834  * |[
14835  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14836  *   clutter_actor_add_constraint (self, constraint);
14837  * ]|
14838  *
14839  * Since: 1.4
14840  */
14841 void
14842 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14843                                         const gchar       *name,
14844                                         ClutterConstraint *constraint)
14845 {
14846   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14847   g_return_if_fail (name != NULL);
14848   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14849
14850   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14851   clutter_actor_add_constraint (self, constraint);
14852 }
14853
14854 /**
14855  * clutter_actor_remove_constraint:
14856  * @self: a #ClutterActor
14857  * @constraint: a #ClutterConstraint
14858  *
14859  * Removes @constraint from the list of constraints applied to @self
14860  *
14861  * The reference held by @self on the #ClutterConstraint will be released
14862  *
14863  * Since: 1.4
14864  */
14865 void
14866 clutter_actor_remove_constraint (ClutterActor      *self,
14867                                  ClutterConstraint *constraint)
14868 {
14869   ClutterActorPrivate *priv;
14870
14871   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14872   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14873
14874   priv = self->priv;
14875
14876   if (priv->constraints == NULL)
14877     return;
14878
14879   _clutter_meta_group_remove_meta (priv->constraints,
14880                                    CLUTTER_ACTOR_META (constraint));
14881   clutter_actor_queue_relayout (self);
14882
14883   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14884 }
14885
14886 /**
14887  * clutter_actor_remove_constraint_by_name:
14888  * @self: a #ClutterActor
14889  * @name: the name of the constraint to remove
14890  *
14891  * Removes the #ClutterConstraint with the given name from the list
14892  * of constraints applied to @self
14893  *
14894  * Since: 1.4
14895  */
14896 void
14897 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14898                                          const gchar  *name)
14899 {
14900   ClutterActorPrivate *priv;
14901   ClutterActorMeta *meta;
14902
14903   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14904   g_return_if_fail (name != NULL);
14905
14906   priv = self->priv;
14907
14908   if (priv->constraints == NULL)
14909     return;
14910
14911   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14912   if (meta == NULL)
14913     return;
14914
14915   _clutter_meta_group_remove_meta (priv->constraints, meta);
14916   clutter_actor_queue_relayout (self);
14917 }
14918
14919 /**
14920  * clutter_actor_get_constraints:
14921  * @self: a #ClutterActor
14922  *
14923  * Retrieves the list of constraints applied to @self
14924  *
14925  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14926  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14927  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14928  *   allocated by the returned #GList
14929  *
14930  * Since: 1.4
14931  */
14932 GList *
14933 clutter_actor_get_constraints (ClutterActor *self)
14934 {
14935   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14936
14937   if (self->priv->constraints == NULL)
14938     return NULL;
14939
14940   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14941 }
14942
14943 /**
14944  * clutter_actor_get_constraint:
14945  * @self: a #ClutterActor
14946  * @name: the name of the constraint to retrieve
14947  *
14948  * Retrieves the #ClutterConstraint with the given name in the list
14949  * of constraints applied to @self
14950  *
14951  * Return value: (transfer none): a #ClutterConstraint for the given
14952  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14953  *   actor and it should not be unreferenced directly
14954  *
14955  * Since: 1.4
14956  */
14957 ClutterConstraint *
14958 clutter_actor_get_constraint (ClutterActor *self,
14959                               const gchar  *name)
14960 {
14961   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14962   g_return_val_if_fail (name != NULL, NULL);
14963
14964   if (self->priv->constraints == NULL)
14965     return NULL;
14966
14967   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14968 }
14969
14970 /**
14971  * clutter_actor_clear_constraints:
14972  * @self: a #ClutterActor
14973  *
14974  * Clears the list of constraints applied to @self
14975  *
14976  * Since: 1.4
14977  */
14978 void
14979 clutter_actor_clear_constraints (ClutterActor *self)
14980 {
14981   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14982
14983   if (self->priv->constraints == NULL)
14984     return;
14985
14986   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14987
14988   clutter_actor_queue_relayout (self);
14989 }
14990
14991 /**
14992  * clutter_actor_set_clip_to_allocation:
14993  * @self: a #ClutterActor
14994  * @clip_set: %TRUE to apply a clip tracking the allocation
14995  *
14996  * Sets whether @self should be clipped to the same size as its
14997  * allocation
14998  *
14999  * Since: 1.4
15000  */
15001 void
15002 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15003                                       gboolean      clip_set)
15004 {
15005   ClutterActorPrivate *priv;
15006
15007   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15008
15009   clip_set = !!clip_set;
15010
15011   priv = self->priv;
15012
15013   if (priv->clip_to_allocation != clip_set)
15014     {
15015       priv->clip_to_allocation = clip_set;
15016
15017       clutter_actor_queue_redraw (self);
15018
15019       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15020     }
15021 }
15022
15023 /**
15024  * clutter_actor_get_clip_to_allocation:
15025  * @self: a #ClutterActor
15026  *
15027  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15028  *
15029  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15030  *
15031  * Since: 1.4
15032  */
15033 gboolean
15034 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15035 {
15036   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15037
15038   return self->priv->clip_to_allocation;
15039 }
15040
15041 /**
15042  * clutter_actor_add_effect:
15043  * @self: a #ClutterActor
15044  * @effect: a #ClutterEffect
15045  *
15046  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15047  *
15048  * The #ClutterActor will hold a reference on the @effect until either
15049  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15050  * called.
15051  *
15052  * Since: 1.4
15053  */
15054 void
15055 clutter_actor_add_effect (ClutterActor  *self,
15056                           ClutterEffect *effect)
15057 {
15058   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15059   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15060
15061   _clutter_actor_add_effect_internal (self, effect);
15062
15063   clutter_actor_queue_redraw (self);
15064
15065   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15066 }
15067
15068 /**
15069  * clutter_actor_add_effect_with_name:
15070  * @self: a #ClutterActor
15071  * @name: the name to set on the effect
15072  * @effect: a #ClutterEffect
15073  *
15074  * A convenience function for setting the name of a #ClutterEffect
15075  * while adding it to the list of effectss applied to @self
15076  *
15077  * This function is the logical equivalent of:
15078  *
15079  * |[
15080  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15081  *   clutter_actor_add_effect (self, effect);
15082  * ]|
15083  *
15084  * Since: 1.4
15085  */
15086 void
15087 clutter_actor_add_effect_with_name (ClutterActor  *self,
15088                                     const gchar   *name,
15089                                     ClutterEffect *effect)
15090 {
15091   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15092   g_return_if_fail (name != NULL);
15093   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15094
15095   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15096   clutter_actor_add_effect (self, effect);
15097 }
15098
15099 /**
15100  * clutter_actor_remove_effect:
15101  * @self: a #ClutterActor
15102  * @effect: a #ClutterEffect
15103  *
15104  * Removes @effect from the list of effects applied to @self
15105  *
15106  * The reference held by @self on the #ClutterEffect will be released
15107  *
15108  * Since: 1.4
15109  */
15110 void
15111 clutter_actor_remove_effect (ClutterActor  *self,
15112                              ClutterEffect *effect)
15113 {
15114   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15115   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15116
15117   _clutter_actor_remove_effect_internal (self, effect);
15118
15119   clutter_actor_queue_redraw (self);
15120
15121   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15122 }
15123
15124 /**
15125  * clutter_actor_remove_effect_by_name:
15126  * @self: a #ClutterActor
15127  * @name: the name of the effect to remove
15128  *
15129  * Removes the #ClutterEffect with the given name from the list
15130  * of effects applied to @self
15131  *
15132  * Since: 1.4
15133  */
15134 void
15135 clutter_actor_remove_effect_by_name (ClutterActor *self,
15136                                      const gchar  *name)
15137 {
15138   ClutterActorPrivate *priv;
15139   ClutterActorMeta *meta;
15140
15141   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15142   g_return_if_fail (name != NULL);
15143
15144   priv = self->priv;
15145
15146   if (priv->effects == NULL)
15147     return;
15148
15149   meta = _clutter_meta_group_get_meta (priv->effects, name);
15150   if (meta == NULL)
15151     return;
15152
15153   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15154 }
15155
15156 /**
15157  * clutter_actor_get_effects:
15158  * @self: a #ClutterActor
15159  *
15160  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15161  *
15162  * Return value: (transfer container) (element-type Clutter.Effect): a list
15163  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15164  *   list are owned by Clutter and they should not be freed. You should
15165  *   free the returned list using g_list_free() when done
15166  *
15167  * Since: 1.4
15168  */
15169 GList *
15170 clutter_actor_get_effects (ClutterActor *self)
15171 {
15172   ClutterActorPrivate *priv;
15173
15174   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15175
15176   priv = self->priv;
15177
15178   if (priv->effects == NULL)
15179     return NULL;
15180
15181   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15182 }
15183
15184 /**
15185  * clutter_actor_get_effect:
15186  * @self: a #ClutterActor
15187  * @name: the name of the effect to retrieve
15188  *
15189  * Retrieves the #ClutterEffect with the given name in the list
15190  * of effects applied to @self
15191  *
15192  * Return value: (transfer none): a #ClutterEffect for the given
15193  *   name, or %NULL. The returned #ClutterEffect is owned by the
15194  *   actor and it should not be unreferenced directly
15195  *
15196  * Since: 1.4
15197  */
15198 ClutterEffect *
15199 clutter_actor_get_effect (ClutterActor *self,
15200                           const gchar  *name)
15201 {
15202   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15203   g_return_val_if_fail (name != NULL, NULL);
15204
15205   if (self->priv->effects == NULL)
15206     return NULL;
15207
15208   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15209 }
15210
15211 /**
15212  * clutter_actor_clear_effects:
15213  * @self: a #ClutterActor
15214  *
15215  * Clears the list of effects applied to @self
15216  *
15217  * Since: 1.4
15218  */
15219 void
15220 clutter_actor_clear_effects (ClutterActor *self)
15221 {
15222   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15223
15224   if (self->priv->effects == NULL)
15225     return;
15226
15227   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15228
15229   clutter_actor_queue_redraw (self);
15230 }
15231
15232 /**
15233  * clutter_actor_has_key_focus:
15234  * @self: a #ClutterActor
15235  *
15236  * Checks whether @self is the #ClutterActor that has key focus
15237  *
15238  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15239  *
15240  * Since: 1.4
15241  */
15242 gboolean
15243 clutter_actor_has_key_focus (ClutterActor *self)
15244 {
15245   ClutterActor *stage;
15246
15247   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15248
15249   stage = _clutter_actor_get_stage_internal (self);
15250   if (stage == NULL)
15251     return FALSE;
15252
15253   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15254 }
15255
15256 static gboolean
15257 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15258                                       ClutterPaintVolume *pv)
15259 {
15260   ClutterActorPrivate *priv = self->priv;
15261
15262   /* Actors are only expected to report a valid paint volume
15263    * while they have a valid allocation. */
15264   if (G_UNLIKELY (priv->needs_allocation))
15265     {
15266       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15267                     "Actor needs allocation",
15268                     _clutter_actor_get_debug_name (self));
15269       return FALSE;
15270     }
15271
15272   /* Check if there are any handlers connected to the paint
15273    * signal. If there are then all bets are off for what the paint
15274    * volume for this actor might possibly be!
15275    *
15276    * XXX: It's expected that this is going to end up being quite a
15277    * costly check to have to do here, but we haven't come up with
15278    * another solution that can reliably catch paint signal handlers at
15279    * the right time to either avoid artefacts due to invalid stage
15280    * clipping or due to incorrect culling.
15281    *
15282    * Previously we checked in clutter_actor_paint(), but at that time
15283    * we may already be using a stage clip that could be derived from
15284    * an invalid paint-volume. We used to try and handle that by
15285    * queuing a follow up, unclipped, redraw but still the previous
15286    * checking wasn't enough to catch invalid volumes involved in
15287    * culling (considering that containers may derive their volume from
15288    * children that haven't yet been painted)
15289    *
15290    * Longer term, improved solutions could be:
15291    * - Disallow painting in the paint signal, only allow using it
15292    *   for tracking when paints happen. We can add another API that
15293    *   allows monkey patching the paint of arbitrary actors but in a
15294    *   more controlled way and that also supports modifying the
15295    *   paint-volume.
15296    * - If we could be notified somehow when signal handlers are
15297    *   connected we wouldn't have to poll for handlers like this.
15298    */
15299   if (g_signal_has_handler_pending (self,
15300                                     actor_signals[PAINT],
15301                                     0,
15302                                     TRUE))
15303     {
15304       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15305                     "Actor has \"paint\" signal handlers",
15306                     _clutter_actor_get_debug_name (self));
15307       return FALSE;
15308     }
15309
15310   _clutter_paint_volume_init_static (pv, self);
15311
15312   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15313     {
15314       clutter_paint_volume_free (pv);
15315       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15316                     "Actor failed to report a volume",
15317                     _clutter_actor_get_debug_name (self));
15318       return FALSE;
15319     }
15320
15321   /* since effects can modify the paint volume, we allow them to actually
15322    * do this by making get_paint_volume() "context sensitive"
15323    */
15324   if (priv->effects != NULL)
15325     {
15326       if (priv->current_effect != NULL)
15327         {
15328           const GList *effects, *l;
15329
15330           /* if we are being called from within the paint sequence of
15331            * an actor, get the paint volume up to the current effect
15332            */
15333           effects = _clutter_meta_group_peek_metas (priv->effects);
15334           for (l = effects;
15335                l != NULL || (l != NULL && l->data != priv->current_effect);
15336                l = l->next)
15337             {
15338               if (!_clutter_effect_get_paint_volume (l->data, pv))
15339                 {
15340                   clutter_paint_volume_free (pv);
15341                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15342                                 "Effect (%s) failed to report a volume",
15343                                 _clutter_actor_get_debug_name (self),
15344                                 _clutter_actor_meta_get_debug_name (l->data));
15345                   return FALSE;
15346                 }
15347             }
15348         }
15349       else
15350         {
15351           const GList *effects, *l;
15352
15353           /* otherwise, get the cumulative volume */
15354           effects = _clutter_meta_group_peek_metas (priv->effects);
15355           for (l = effects; l != NULL; l = l->next)
15356             if (!_clutter_effect_get_paint_volume (l->data, pv))
15357               {
15358                 clutter_paint_volume_free (pv);
15359                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15360                               "Effect (%s) failed to report a volume",
15361                               _clutter_actor_get_debug_name (self),
15362                               _clutter_actor_meta_get_debug_name (l->data));
15363                 return FALSE;
15364               }
15365         }
15366     }
15367
15368   return TRUE;
15369 }
15370
15371 /* The public clutter_actor_get_paint_volume API returns a const
15372  * pointer since we return a pointer directly to the cached
15373  * PaintVolume associated with the actor and don't want the user to
15374  * inadvertently modify it, but for internal uses we sometimes need
15375  * access to the same PaintVolume but need to apply some book-keeping
15376  * modifications to it so we don't want a const pointer.
15377  */
15378 static ClutterPaintVolume *
15379 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15380 {
15381   ClutterActorPrivate *priv;
15382
15383   priv = self->priv;
15384
15385   if (priv->paint_volume_valid)
15386     clutter_paint_volume_free (&priv->paint_volume);
15387
15388   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15389     {
15390       priv->paint_volume_valid = TRUE;
15391       return &priv->paint_volume;
15392     }
15393   else
15394     {
15395       priv->paint_volume_valid = FALSE;
15396       return NULL;
15397     }
15398 }
15399
15400 /**
15401  * clutter_actor_get_paint_volume:
15402  * @self: a #ClutterActor
15403  *
15404  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15405  * when a paint volume can't be determined.
15406  *
15407  * The paint volume is defined as the 3D space occupied by an actor
15408  * when being painted.
15409  *
15410  * This function will call the <function>get_paint_volume()</function>
15411  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15412  * should not usually care about overriding the default implementation,
15413  * unless they are, for instance: painting outside their allocation, or
15414  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15415  * 3D depth).
15416  *
15417  * <note>2D actors overriding <function>get_paint_volume()</function>
15418  * ensure their volume has a depth of 0. (This will be true so long as
15419  * you don't call clutter_paint_volume_set_depth().)</note>
15420  *
15421  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15422  *   or %NULL if no volume could be determined. The returned pointer
15423  *   is not guaranteed to be valid across multiple frames; if you want
15424  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15425  *
15426  * Since: 1.6
15427  */
15428 const ClutterPaintVolume *
15429 clutter_actor_get_paint_volume (ClutterActor *self)
15430 {
15431   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15432
15433   return _clutter_actor_get_paint_volume_mutable (self);
15434 }
15435
15436 /**
15437  * clutter_actor_get_transformed_paint_volume:
15438  * @self: a #ClutterActor
15439  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15440  *    (or %NULL for the stage)
15441  *
15442  * Retrieves the 3D paint volume of an actor like
15443  * clutter_actor_get_paint_volume() does (Please refer to the
15444  * documentation of clutter_actor_get_paint_volume() for more
15445  * details.) and it additionally transforms the paint volume into the
15446  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15447  * is passed for @relative_to_ancestor)
15448  *
15449  * This can be used by containers that base their paint volume on
15450  * the volume of their children. Such containers can query the
15451  * transformed paint volume of all of its children and union them
15452  * together using clutter_paint_volume_union().
15453  *
15454  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15455  *   or %NULL if no volume could be determined. The returned pointer is
15456  *   not guaranteed to be valid across multiple frames; if you wish to
15457  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15458  *
15459  * Since: 1.6
15460  */
15461 const ClutterPaintVolume *
15462 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15463                                             ClutterActor *relative_to_ancestor)
15464 {
15465   const ClutterPaintVolume *volume;
15466   ClutterActor *stage;
15467   ClutterPaintVolume *transformed_volume;
15468
15469   stage = _clutter_actor_get_stage_internal (self);
15470   if (G_UNLIKELY (stage == NULL))
15471     return NULL;
15472
15473   if (relative_to_ancestor == NULL)
15474     relative_to_ancestor = stage;
15475
15476   volume = clutter_actor_get_paint_volume (self);
15477   if (volume == NULL)
15478     return NULL;
15479
15480   transformed_volume =
15481     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15482
15483   _clutter_paint_volume_copy_static (volume, transformed_volume);
15484
15485   _clutter_paint_volume_transform_relative (transformed_volume,
15486                                             relative_to_ancestor);
15487
15488   return transformed_volume;
15489 }
15490
15491 /**
15492  * clutter_actor_get_paint_box:
15493  * @self: a #ClutterActor
15494  * @box: (out): return location for a #ClutterActorBox
15495  *
15496  * Retrieves the paint volume of the passed #ClutterActor, and
15497  * transforms it into a 2D bounding box in stage coordinates.
15498  *
15499  * This function is useful to determine the on screen area occupied by
15500  * the actor. The box is only an approximation and may often be
15501  * considerably larger due to the optimizations used to calculate the
15502  * box. The box is never smaller though, so it can reliably be used
15503  * for culling.
15504  *
15505  * There are times when a 2D paint box can't be determined, e.g.
15506  * because the actor isn't yet parented under a stage or because
15507  * the actor is unable to determine a paint volume.
15508  *
15509  * Return value: %TRUE if a 2D paint box could be determined, else
15510  * %FALSE.
15511  *
15512  * Since: 1.6
15513  */
15514 gboolean
15515 clutter_actor_get_paint_box (ClutterActor    *self,
15516                              ClutterActorBox *box)
15517 {
15518   ClutterActor *stage;
15519   ClutterPaintVolume *pv;
15520
15521   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15522   g_return_val_if_fail (box != NULL, FALSE);
15523
15524   stage = _clutter_actor_get_stage_internal (self);
15525   if (G_UNLIKELY (!stage))
15526     return FALSE;
15527
15528   pv = _clutter_actor_get_paint_volume_mutable (self);
15529   if (G_UNLIKELY (!pv))
15530     return FALSE;
15531
15532   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15533
15534   return TRUE;
15535 }
15536
15537 /**
15538  * clutter_actor_has_overlaps:
15539  * @self: A #ClutterActor
15540  *
15541  * Asks the actor's implementation whether it may contain overlapping
15542  * primitives.
15543  *
15544  * For example; Clutter may use this to determine whether the painting
15545  * should be redirected to an offscreen buffer to correctly implement
15546  * the opacity property.
15547  *
15548  * Custom actors can override the default response by implementing the
15549  * #ClutterActor <function>has_overlaps</function> virtual function. See
15550  * clutter_actor_set_offscreen_redirect() for more information.
15551  *
15552  * Return value: %TRUE if the actor may have overlapping primitives, and
15553  *   %FALSE otherwise
15554  *
15555  * Since: 1.8
15556  */
15557 gboolean
15558 clutter_actor_has_overlaps (ClutterActor *self)
15559 {
15560   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15561
15562   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15563 }
15564
15565 /**
15566  * clutter_actor_has_effects:
15567  * @self: A #ClutterActor
15568  *
15569  * Returns whether the actor has any effects applied.
15570  *
15571  * Return value: %TRUE if the actor has any effects,
15572  *   %FALSE otherwise
15573  *
15574  * Since: 1.10
15575  */
15576 gboolean
15577 clutter_actor_has_effects (ClutterActor *self)
15578 {
15579   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15580
15581   if (self->priv->effects == NULL)
15582     return FALSE;
15583
15584   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15585 }
15586
15587 /**
15588  * clutter_actor_has_constraints:
15589  * @self: A #ClutterActor
15590  *
15591  * Returns whether the actor has any constraints applied.
15592  *
15593  * Return value: %TRUE if the actor has any constraints,
15594  *   %FALSE otherwise
15595  *
15596  * Since: 1.10
15597  */
15598 gboolean
15599 clutter_actor_has_constraints (ClutterActor *self)
15600 {
15601   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15602
15603   return self->priv->constraints != NULL;
15604 }
15605
15606 /**
15607  * clutter_actor_has_actions:
15608  * @self: A #ClutterActor
15609  *
15610  * Returns whether the actor has any actions applied.
15611  *
15612  * Return value: %TRUE if the actor has any actions,
15613  *   %FALSE otherwise
15614  *
15615  * Since: 1.10
15616  */
15617 gboolean
15618 clutter_actor_has_actions (ClutterActor *self)
15619 {
15620   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15621
15622   return self->priv->actions != NULL;
15623 }
15624
15625 /**
15626  * clutter_actor_get_n_children:
15627  * @self: a #ClutterActor
15628  *
15629  * Retrieves the number of children of @self.
15630  *
15631  * Return value: the number of children of an actor
15632  *
15633  * Since: 1.10
15634  */
15635 gint
15636 clutter_actor_get_n_children (ClutterActor *self)
15637 {
15638   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15639
15640   return self->priv->n_children;
15641 }
15642
15643 /**
15644  * clutter_actor_get_child_at_index:
15645  * @self: a #ClutterActor
15646  * @index_: the position in the list of children
15647  *
15648  * Retrieves the actor at the given @index_ inside the list of
15649  * children of @self.
15650  *
15651  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15652  *
15653  * Since: 1.10
15654  */
15655 ClutterActor *
15656 clutter_actor_get_child_at_index (ClutterActor *self,
15657                                   gint          index_)
15658 {
15659   ClutterActor *iter;
15660   int i;
15661
15662   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15663   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15664
15665   for (iter = self->priv->first_child, i = 0;
15666        iter != NULL && i < index_;
15667        iter = iter->priv->next_sibling, i += 1)
15668     ;
15669
15670   return iter;
15671 }
15672
15673 /*< private >
15674  * _clutter_actor_foreach_child:
15675  * @actor: The actor whos children you want to iterate
15676  * @callback: The function to call for each child
15677  * @user_data: Private data to pass to @callback
15678  *
15679  * Calls a given @callback once for each child of the specified @actor and
15680  * passing the @user_data pointer each time.
15681  *
15682  * Return value: returns %TRUE if all children were iterated, else
15683  *    %FALSE if a callback broke out of iteration early.
15684  */
15685 gboolean
15686 _clutter_actor_foreach_child (ClutterActor           *self,
15687                               ClutterForeachCallback  callback,
15688                               gpointer                user_data)
15689 {
15690   ClutterActorPrivate *priv = self->priv;
15691   ClutterActor *iter;
15692   gboolean cont;
15693
15694   for (cont = TRUE, iter = priv->first_child;
15695        cont && iter != NULL;
15696        iter = iter->priv->next_sibling)
15697     {
15698       cont = callback (iter, user_data);
15699     }
15700
15701   return cont;
15702 }
15703
15704 #if 0
15705 /* For debugging purposes this gives us a simple way to print out
15706  * the scenegraph e.g in gdb using:
15707  * [|
15708  *   _clutter_actor_traverse (stage,
15709  *                            0,
15710  *                            clutter_debug_print_actor_cb,
15711  *                            NULL,
15712  *                            NULL);
15713  * |]
15714  */
15715 static ClutterActorTraverseVisitFlags
15716 clutter_debug_print_actor_cb (ClutterActor *actor,
15717                               int depth,
15718                               void *user_data)
15719 {
15720   g_print ("%*s%s:%p\n",
15721            depth * 2, "",
15722            _clutter_actor_get_debug_name (actor),
15723            actor);
15724
15725   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15726 }
15727 #endif
15728
15729 static void
15730 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15731                                  ClutterTraverseCallback callback,
15732                                  gpointer                user_data)
15733 {
15734   GQueue *queue = g_queue_new ();
15735   ClutterActor dummy;
15736   int current_depth = 0;
15737
15738   g_queue_push_tail (queue, actor);
15739   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15740
15741   while ((actor = g_queue_pop_head (queue)))
15742     {
15743       ClutterActorTraverseVisitFlags flags;
15744
15745       if (actor == &dummy)
15746         {
15747           current_depth++;
15748           g_queue_push_tail (queue, &dummy);
15749           continue;
15750         }
15751
15752       flags = callback (actor, current_depth, user_data);
15753       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15754         break;
15755       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15756         {
15757           ClutterActor *iter;
15758
15759           for (iter = actor->priv->first_child;
15760                iter != NULL;
15761                iter = iter->priv->next_sibling)
15762             {
15763               g_queue_push_tail (queue, iter);
15764             }
15765         }
15766     }
15767
15768   g_queue_free (queue);
15769 }
15770
15771 static ClutterActorTraverseVisitFlags
15772 _clutter_actor_traverse_depth (ClutterActor           *actor,
15773                                ClutterTraverseCallback before_children_callback,
15774                                ClutterTraverseCallback after_children_callback,
15775                                int                     current_depth,
15776                                gpointer                user_data)
15777 {
15778   ClutterActorTraverseVisitFlags flags;
15779
15780   flags = before_children_callback (actor, current_depth, user_data);
15781   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15782     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15783
15784   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15785     {
15786       ClutterActor *iter;
15787
15788       for (iter = actor->priv->first_child;
15789            iter != NULL;
15790            iter = iter->priv->next_sibling)
15791         {
15792           flags = _clutter_actor_traverse_depth (iter,
15793                                                  before_children_callback,
15794                                                  after_children_callback,
15795                                                  current_depth + 1,
15796                                                  user_data);
15797
15798           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15799             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15800         }
15801     }
15802
15803   if (after_children_callback)
15804     return after_children_callback (actor, current_depth, user_data);
15805   else
15806     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15807 }
15808
15809 /* _clutter_actor_traverse:
15810  * @actor: The actor to start traversing the graph from
15811  * @flags: These flags may affect how the traversal is done
15812  * @before_children_callback: A function to call before visiting the
15813  *   children of the current actor.
15814  * @after_children_callback: A function to call after visiting the
15815  *   children of the current actor. (Ignored if
15816  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15817  * @user_data: The private data to pass to the callbacks
15818  *
15819  * Traverses the scenegraph starting at the specified @actor and
15820  * descending through all its children and its children's children.
15821  * For each actor traversed @before_children_callback and
15822  * @after_children_callback are called with the specified
15823  * @user_data, before and after visiting that actor's children.
15824  *
15825  * The callbacks can return flags that affect the ongoing traversal
15826  * such as by skipping over an actors children or bailing out of
15827  * any further traversing.
15828  */
15829 void
15830 _clutter_actor_traverse (ClutterActor              *actor,
15831                          ClutterActorTraverseFlags  flags,
15832                          ClutterTraverseCallback    before_children_callback,
15833                          ClutterTraverseCallback    after_children_callback,
15834                          gpointer                   user_data)
15835 {
15836   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15837     _clutter_actor_traverse_breadth (actor,
15838                                      before_children_callback,
15839                                      user_data);
15840   else /* DEPTH_FIRST */
15841     _clutter_actor_traverse_depth (actor,
15842                                    before_children_callback,
15843                                    after_children_callback,
15844                                    0, /* start depth */
15845                                    user_data);
15846 }
15847
15848 static void
15849 on_layout_manager_changed (ClutterLayoutManager *manager,
15850                            ClutterActor         *self)
15851 {
15852   clutter_actor_queue_relayout (self);
15853 }
15854
15855 /**
15856  * clutter_actor_set_layout_manager:
15857  * @self: a #ClutterActor
15858  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15859  *
15860  * Sets the #ClutterLayoutManager delegate object that will be used to
15861  * lay out the children of @self.
15862  *
15863  * The #ClutterActor will take a reference on the passed @manager which
15864  * will be released either when the layout manager is removed, or when
15865  * the actor is destroyed.
15866  *
15867  * Since: 1.10
15868  */
15869 void
15870 clutter_actor_set_layout_manager (ClutterActor         *self,
15871                                   ClutterLayoutManager *manager)
15872 {
15873   ClutterActorPrivate *priv;
15874
15875   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15876   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15877
15878   priv = self->priv;
15879
15880   if (priv->layout_manager != NULL)
15881     {
15882       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15883                                             G_CALLBACK (on_layout_manager_changed),
15884                                             self);
15885       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15886       g_object_unref (priv->layout_manager);
15887     }
15888
15889   priv->layout_manager = manager;
15890
15891   if (priv->layout_manager != NULL)
15892     {
15893       g_object_ref_sink (priv->layout_manager);
15894       clutter_layout_manager_set_container (priv->layout_manager,
15895                                             CLUTTER_CONTAINER (self));
15896       g_signal_connect (priv->layout_manager, "layout-changed",
15897                         G_CALLBACK (on_layout_manager_changed),
15898                         self);
15899     }
15900
15901   clutter_actor_queue_relayout (self);
15902
15903   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15904 }
15905
15906 /**
15907  * clutter_actor_get_layout_manager:
15908  * @self: a #ClutterActor
15909  *
15910  * Retrieves the #ClutterLayoutManager used by @self.
15911  *
15912  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15913  *   or %NULL
15914  *
15915  * Since: 1.10
15916  */
15917 ClutterLayoutManager *
15918 clutter_actor_get_layout_manager (ClutterActor *self)
15919 {
15920   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15921
15922   return self->priv->layout_manager;
15923 }
15924
15925 static const ClutterLayoutInfo default_layout_info = {
15926   0.f,                          /* fixed-x */
15927   0.f,                          /* fixed-y */
15928   { 0, 0, 0, 0 },               /* margin */
15929   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15930   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15931   0.f, 0.f,                     /* min_width, natural_width */
15932   0.f, 0.f,                     /* natual_width, natural_height */
15933 };
15934
15935 static void
15936 layout_info_free (gpointer data)
15937 {
15938   if (G_LIKELY (data != NULL))
15939     g_slice_free (ClutterLayoutInfo, data);
15940 }
15941
15942 /*< private >
15943  * _clutter_actor_get_layout_info:
15944  * @self: a #ClutterActor
15945  *
15946  * Retrieves a pointer to the ClutterLayoutInfo structure.
15947  *
15948  * If the actor does not have a ClutterLayoutInfo associated to it, one
15949  * will be created and initialized to the default values.
15950  *
15951  * This function should be used for setters.
15952  *
15953  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15954  * instead.
15955  *
15956  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15957  */
15958 ClutterLayoutInfo *
15959 _clutter_actor_get_layout_info (ClutterActor *self)
15960 {
15961   ClutterLayoutInfo *retval;
15962
15963   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15964   if (retval == NULL)
15965     {
15966       retval = g_slice_new (ClutterLayoutInfo);
15967
15968       *retval = default_layout_info;
15969
15970       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15971                                retval,
15972                                layout_info_free);
15973     }
15974
15975   return retval;
15976 }
15977
15978 /*< private >
15979  * _clutter_actor_get_layout_info_or_defaults:
15980  * @self: a #ClutterActor
15981  *
15982  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15983  *
15984  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15985  * then the default structure will be returned.
15986  *
15987  * This function should only be used for getters.
15988  *
15989  * Return value: a const pointer to the ClutterLayoutInfo structure
15990  */
15991 const ClutterLayoutInfo *
15992 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15993 {
15994   const ClutterLayoutInfo *info;
15995
15996   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15997   if (info == NULL)
15998     return &default_layout_info;
15999
16000   return info;
16001 }
16002
16003 /**
16004  * clutter_actor_set_x_align:
16005  * @self: a #ClutterActor
16006  * @x_align: the horizontal alignment policy
16007  *
16008  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16009  * actor received extra horizontal space.
16010  *
16011  * See also the #ClutterActor:x-align property.
16012  *
16013  * Since: 1.10
16014  */
16015 void
16016 clutter_actor_set_x_align (ClutterActor      *self,
16017                            ClutterActorAlign  x_align)
16018 {
16019   ClutterLayoutInfo *info;
16020
16021   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16022
16023   info = _clutter_actor_get_layout_info (self);
16024
16025   if (info->x_align != x_align)
16026     {
16027       info->x_align = x_align;
16028
16029       clutter_actor_queue_relayout (self);
16030
16031       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16032     }
16033 }
16034
16035 /**
16036  * clutter_actor_get_x_align:
16037  * @self: a #ClutterActor
16038  *
16039  * Retrieves the horizontal alignment policy set using
16040  * clutter_actor_set_x_align().
16041  *
16042  * Return value: the horizontal alignment policy.
16043  *
16044  * Since: 1.10
16045  */
16046 ClutterActorAlign
16047 clutter_actor_get_x_align (ClutterActor *self)
16048 {
16049   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16050
16051   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16052 }
16053
16054 /**
16055  * clutter_actor_set_y_align:
16056  * @self: a #ClutterActor
16057  * @y_align: the vertical alignment policy
16058  *
16059  * Sets the vertical alignment policy of a #ClutterActor, in case the
16060  * actor received extra vertical space.
16061  *
16062  * See also the #ClutterActor:y-align property.
16063  *
16064  * Since: 1.10
16065  */
16066 void
16067 clutter_actor_set_y_align (ClutterActor      *self,
16068                            ClutterActorAlign  y_align)
16069 {
16070   ClutterLayoutInfo *info;
16071
16072   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16073
16074   info = _clutter_actor_get_layout_info (self);
16075
16076   if (info->y_align != y_align)
16077     {
16078       info->y_align = y_align;
16079
16080       clutter_actor_queue_relayout (self);
16081
16082       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16083     }
16084 }
16085
16086 /**
16087  * clutter_actor_get_y_align:
16088  * @self: a #ClutterActor
16089  *
16090  * Retrieves the vertical alignment policy set using
16091  * clutter_actor_set_y_align().
16092  *
16093  * Return value: the vertical alignment policy.
16094  *
16095  * Since: 1.10
16096  */
16097 ClutterActorAlign
16098 clutter_actor_get_y_align (ClutterActor *self)
16099 {
16100   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16101
16102   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16103 }
16104
16105
16106 /**
16107  * clutter_margin_new:
16108  *
16109  * Creates a new #ClutterMargin.
16110  *
16111  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16112  *   clutter_margin_free() to free the resources associated with it when
16113  *   done.
16114  *
16115  * Since: 1.10
16116  */
16117 ClutterMargin *
16118 clutter_margin_new (void)
16119 {
16120   return g_slice_new0 (ClutterMargin);
16121 }
16122
16123 /**
16124  * clutter_margin_copy:
16125  * @margin_: a #ClutterMargin
16126  *
16127  * Creates a new #ClutterMargin and copies the contents of @margin_ into
16128  * the newly created structure.
16129  *
16130  * Return value: (transfer full): a copy of the #ClutterMargin.
16131  *
16132  * Since: 1.10
16133  */
16134 ClutterMargin *
16135 clutter_margin_copy (const ClutterMargin *margin_)
16136 {
16137   if (G_LIKELY (margin_ != NULL))
16138     return g_slice_dup (ClutterMargin, margin_);
16139
16140   return NULL;
16141 }
16142
16143 /**
16144  * clutter_margin_free:
16145  * @margin_: a #ClutterMargin
16146  *
16147  * Frees the resources allocated by clutter_margin_new() and
16148  * clutter_margin_copy().
16149  *
16150  * Since: 1.10
16151  */
16152 void
16153 clutter_margin_free (ClutterMargin *margin_)
16154 {
16155   if (G_LIKELY (margin_ != NULL))
16156     g_slice_free (ClutterMargin, margin_);
16157 }
16158
16159 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16160                      clutter_margin_copy,
16161                      clutter_margin_free)
16162
16163 /**
16164  * clutter_actor_set_margin:
16165  * @self: a #ClutterActor
16166  * @margin: a #ClutterMargin
16167  *
16168  * Sets all the components of the margin of a #ClutterActor.
16169  *
16170  * Since: 1.10
16171  */
16172 void
16173 clutter_actor_set_margin (ClutterActor        *self,
16174                           const ClutterMargin *margin)
16175 {
16176   ClutterLayoutInfo *info;
16177   gboolean changed;
16178   GObject *obj;
16179
16180   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16181   g_return_if_fail (margin != NULL);
16182
16183   obj = G_OBJECT (self);
16184   changed = FALSE;
16185
16186   g_object_freeze_notify (obj);
16187
16188   info = _clutter_actor_get_layout_info (self);
16189
16190   if (info->margin.top != margin->top)
16191     {
16192       info->margin.top = margin->top;
16193       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16194       changed = TRUE;
16195     }
16196
16197   if (info->margin.right != margin->right)
16198     {
16199       info->margin.right = margin->right;
16200       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16201       changed = TRUE;
16202     }
16203
16204   if (info->margin.bottom != margin->bottom)
16205     {
16206       info->margin.bottom = margin->bottom;
16207       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16208       changed = TRUE;
16209     }
16210
16211   if (info->margin.left != margin->left)
16212     {
16213       info->margin.left = margin->left;
16214       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16215       changed = TRUE;
16216     }
16217
16218   if (changed)
16219     clutter_actor_queue_relayout (self);
16220
16221   g_object_thaw_notify (obj);
16222 }
16223
16224 /**
16225  * clutter_actor_get_margin:
16226  * @self: a #ClutterActor
16227  * @margin: (out caller-allocates): return location for a #ClutterMargin
16228  *
16229  * Retrieves all the components of the margin of a #ClutterActor.
16230  *
16231  * Since: 1.10
16232  */
16233 void
16234 clutter_actor_get_margin (ClutterActor  *self,
16235                           ClutterMargin *margin)
16236 {
16237   const ClutterLayoutInfo *info;
16238
16239   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16240   g_return_if_fail (margin != NULL);
16241
16242   info = _clutter_actor_get_layout_info_or_defaults (self);
16243
16244   *margin = info->margin;
16245 }
16246
16247 /**
16248  * clutter_actor_set_margin_top:
16249  * @self: a #ClutterActor
16250  * @margin: the top margin
16251  *
16252  * Sets the margin from the top of a #ClutterActor.
16253  *
16254  * Since: 1.10
16255  */
16256 void
16257 clutter_actor_set_margin_top (ClutterActor *self,
16258                               gfloat        margin)
16259 {
16260   ClutterLayoutInfo *info;
16261
16262   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16263   g_return_if_fail (margin >= 0.f);
16264
16265   info = _clutter_actor_get_layout_info (self);
16266
16267   if (info->margin.top == margin)
16268     return;
16269
16270   info->margin.top = margin;
16271
16272   clutter_actor_queue_relayout (self);
16273
16274   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16275 }
16276
16277 /**
16278  * clutter_actor_get_margin_top:
16279  * @self: a #ClutterActor
16280  *
16281  * Retrieves the top margin of a #ClutterActor.
16282  *
16283  * Return value: the top margin
16284  *
16285  * Since: 1.10
16286  */
16287 gfloat
16288 clutter_actor_get_margin_top (ClutterActor *self)
16289 {
16290   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16291
16292   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16293 }
16294
16295 /**
16296  * clutter_actor_set_margin_bottom:
16297  * @self: a #ClutterActor
16298  * @margin: the bottom margin
16299  *
16300  * Sets the margin from the bottom of a #ClutterActor.
16301  *
16302  * Since: 1.10
16303  */
16304 void
16305 clutter_actor_set_margin_bottom (ClutterActor *self,
16306                                  gfloat        margin)
16307 {
16308   ClutterLayoutInfo *info;
16309
16310   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16311   g_return_if_fail (margin >= 0.f);
16312
16313   info = _clutter_actor_get_layout_info (self);
16314
16315   if (info->margin.bottom == margin)
16316     return;
16317
16318   info->margin.bottom = margin;
16319
16320   clutter_actor_queue_relayout (self);
16321
16322   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16323 }
16324
16325 /**
16326  * clutter_actor_get_margin_bottom:
16327  * @self: a #ClutterActor
16328  *
16329  * Retrieves the bottom margin of a #ClutterActor.
16330  *
16331  * Return value: the bottom margin
16332  *
16333  * Since: 1.10
16334  */
16335 gfloat
16336 clutter_actor_get_margin_bottom (ClutterActor *self)
16337 {
16338   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16339
16340   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16341 }
16342
16343 /**
16344  * clutter_actor_set_margin_left:
16345  * @self: a #ClutterActor
16346  * @margin: the left margin
16347  *
16348  * Sets the margin from the left of a #ClutterActor.
16349  *
16350  * Since: 1.10
16351  */
16352 void
16353 clutter_actor_set_margin_left (ClutterActor *self,
16354                                gfloat        margin)
16355 {
16356   ClutterLayoutInfo *info;
16357
16358   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16359   g_return_if_fail (margin >= 0.f);
16360
16361   info = _clutter_actor_get_layout_info (self);
16362
16363   if (info->margin.left == margin)
16364     return;
16365
16366   info->margin.left = margin;
16367
16368   clutter_actor_queue_relayout (self);
16369
16370   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16371 }
16372
16373 /**
16374  * clutter_actor_get_margin_left:
16375  * @self: a #ClutterActor
16376  *
16377  * Retrieves the left margin of a #ClutterActor.
16378  *
16379  * Return value: the left margin
16380  *
16381  * Since: 1.10
16382  */
16383 gfloat
16384 clutter_actor_get_margin_left (ClutterActor *self)
16385 {
16386   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16387
16388   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16389 }
16390
16391 /**
16392  * clutter_actor_set_margin_right:
16393  * @self: a #ClutterActor
16394  * @margin: the right margin
16395  *
16396  * Sets the margin from the right of a #ClutterActor.
16397  *
16398  * Since: 1.10
16399  */
16400 void
16401 clutter_actor_set_margin_right (ClutterActor *self,
16402                                 gfloat        margin)
16403 {
16404   ClutterLayoutInfo *info;
16405
16406   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16407   g_return_if_fail (margin >= 0.f);
16408
16409   info = _clutter_actor_get_layout_info (self);
16410
16411   if (info->margin.right == margin)
16412     return;
16413
16414   info->margin.right = margin;
16415
16416   clutter_actor_queue_relayout (self);
16417
16418   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16419 }
16420
16421 /**
16422  * clutter_actor_get_margin_right:
16423  * @self: a #ClutterActor
16424  *
16425  * Retrieves the right margin of a #ClutterActor.
16426  *
16427  * Return value: the right margin
16428  *
16429  * Since: 1.10
16430  */
16431 gfloat
16432 clutter_actor_get_margin_right (ClutterActor *self)
16433 {
16434   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16435
16436   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16437 }
16438
16439 static inline void
16440 clutter_actor_set_background_color_internal (ClutterActor *self,
16441                                              const ClutterColor *color)
16442 {
16443   ClutterActorPrivate *priv = self->priv;
16444   GObject *obj;
16445
16446   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16447     return;
16448
16449   obj = G_OBJECT (self);
16450
16451   priv->bg_color = *color;
16452   priv->bg_color_set = TRUE;
16453
16454   clutter_actor_queue_redraw (self);
16455
16456   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16457   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16458 }
16459
16460 /**
16461  * clutter_actor_set_background_color:
16462  * @self: a #ClutterActor
16463  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16464  *  set color
16465  *
16466  * Sets the background color of a #ClutterActor.
16467  *
16468  * The background color will be used to cover the whole allocation of the
16469  * actor. The default background color of an actor is transparent.
16470  *
16471  * To check whether an actor has a background color, you can use the
16472  * #ClutterActor:background-color-set actor property.
16473  *
16474  * The #ClutterActor:background-color property is animatable.
16475  *
16476  * Since: 1.10
16477  */
16478 void
16479 clutter_actor_set_background_color (ClutterActor       *self,
16480                                     const ClutterColor *color)
16481 {
16482   ClutterActorPrivate *priv;
16483   GObject *obj;
16484   GParamSpec *bg_color_pspec;
16485
16486   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16487
16488   obj = G_OBJECT (self);
16489
16490   priv = self->priv;
16491
16492   if (color == NULL)
16493     {
16494       priv->bg_color_set = FALSE;
16495       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16496       clutter_actor_queue_redraw (self);
16497       return;
16498     }
16499
16500   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16501   if (clutter_actor_get_easing_duration (self) != 0)
16502     {
16503       ClutterTransition *transition;
16504
16505       transition = _clutter_actor_get_transition (self, bg_color_pspec);
16506       if (transition == NULL)
16507         {
16508           transition = _clutter_actor_create_transition (self, bg_color_pspec,
16509                                                          &priv->bg_color,
16510                                                          color);
16511           clutter_timeline_start (CLUTTER_TIMELINE (transition));
16512         }
16513       else
16514         _clutter_actor_update_transition (self, bg_color_pspec, color);
16515
16516       clutter_actor_queue_redraw (self);
16517     }
16518   else
16519     clutter_actor_set_background_color_internal (self, color);
16520 }
16521
16522 /**
16523  * clutter_actor_get_background_color:
16524  * @self: a #ClutterActor
16525  * @color: (out caller-allocates): return location for a #ClutterColor
16526  *
16527  * Retrieves the color set using clutter_actor_set_background_color().
16528  *
16529  * Since: 1.10
16530  */
16531 void
16532 clutter_actor_get_background_color (ClutterActor *self,
16533                                     ClutterColor *color)
16534 {
16535   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16536   g_return_if_fail (color != NULL);
16537
16538   *color = self->priv->bg_color;
16539 }
16540
16541 /**
16542  * clutter_actor_get_previous_sibling:
16543  * @self: a #ClutterActor
16544  *
16545  * Retrieves the sibling of @self that comes before it in the list
16546  * of children of @self's parent.
16547  *
16548  * The returned pointer is only valid until the scene graph changes; it
16549  * is not safe to modify the list of children of @self while iterating
16550  * it.
16551  *
16552  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16553  *
16554  * Since: 1.10
16555  */
16556 ClutterActor *
16557 clutter_actor_get_previous_sibling (ClutterActor *self)
16558 {
16559   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16560
16561   return self->priv->prev_sibling;
16562 }
16563
16564 /**
16565  * clutter_actor_get_next_sibling:
16566  * @self: a #ClutterActor
16567  *
16568  * Retrieves the sibling of @self that comes after it in the list
16569  * of children of @self's parent.
16570  *
16571  * The returned pointer is only valid until the scene graph changes; it
16572  * is not safe to modify the list of children of @self while iterating
16573  * it.
16574  *
16575  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16576  *
16577  * Since: 1.10
16578  */
16579 ClutterActor *
16580 clutter_actor_get_next_sibling (ClutterActor *self)
16581 {
16582   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16583
16584   return self->priv->next_sibling;
16585 }
16586
16587 /**
16588  * clutter_actor_get_first_child:
16589  * @self: a #ClutterActor
16590  *
16591  * Retrieves the first child of @self.
16592  *
16593  * The returned pointer is only valid until the scene graph changes; it
16594  * is not safe to modify the list of children of @self while iterating
16595  * it.
16596  *
16597  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16598  *
16599  * Since: 1.10
16600  */
16601 ClutterActor *
16602 clutter_actor_get_first_child (ClutterActor *self)
16603 {
16604   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16605
16606   return self->priv->first_child;
16607 }
16608
16609 /**
16610  * clutter_actor_get_last_child:
16611  * @self: a #ClutterActor
16612  *
16613  * Retrieves the last child of @self.
16614  *
16615  * The returned pointer is only valid until the scene graph changes; it
16616  * is not safe to modify the list of children of @self while iterating
16617  * it.
16618  *
16619  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16620  *
16621  * Since: 1.10
16622  */
16623 ClutterActor *
16624 clutter_actor_get_last_child (ClutterActor *self)
16625 {
16626   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16627
16628   return self->priv->last_child;
16629 }
16630
16631 /* easy way to have properly named fields instead of the dummy ones
16632  * we use in the public structure
16633  */
16634 typedef struct _RealActorIter
16635 {
16636   ClutterActor *root;           /* dummy1 */
16637   ClutterActor *current;        /* dummy2 */
16638   gpointer padding_1;           /* dummy3 */
16639   gint age;                     /* dummy4 */
16640   gpointer padding_2;           /* dummy5 */
16641 } RealActorIter;
16642
16643 /**
16644  * clutter_actor_iter_init:
16645  * @iter: a #ClutterActorIter
16646  * @root: a #ClutterActor
16647  *
16648  * Initializes a #ClutterActorIter, which can then be used to iterate
16649  * efficiently over a section of the scene graph, and associates it
16650  * with @root.
16651  *
16652  * Modifying the scene graph section that contains @root will invalidate
16653  * the iterator.
16654  *
16655  * |[
16656  *   ClutterActorIter iter;
16657  *   ClutterActor *child;
16658  *
16659  *   clutter_actor_iter_init (&iter, container);
16660  *   while (clutter_actor_iter_next (&iter, &child))
16661  *     {
16662  *       /&ast; do something with child &ast;/
16663  *     }
16664  * ]|
16665  *
16666  * Since: 1.10
16667  */
16668 void
16669 clutter_actor_iter_init (ClutterActorIter *iter,
16670                          ClutterActor     *root)
16671 {
16672   RealActorIter *ri = (RealActorIter *) iter;
16673
16674   g_return_if_fail (iter != NULL);
16675   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16676
16677   ri->root = root;
16678   ri->current = NULL;
16679   ri->age = root->priv->age;
16680 }
16681
16682 /**
16683  * clutter_actor_iter_next:
16684  * @iter: a #ClutterActorIter
16685  * @child: (out): return location for a #ClutterActor
16686  *
16687  * Advances the @iter and retrieves the next child of the root #ClutterActor
16688  * that was used to initialize the #ClutterActorIterator.
16689  *
16690  * If the iterator can advance, this function returns %TRUE and sets the
16691  * @child argument.
16692  *
16693  * If the iterator cannot advance, this function returns %FALSE, and
16694  * the contents of @child are undefined.
16695  *
16696  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16697  *
16698  * Since: 1.10
16699  */
16700 gboolean
16701 clutter_actor_iter_next (ClutterActorIter  *iter,
16702                          ClutterActor     **child)
16703 {
16704   RealActorIter *ri = (RealActorIter *) iter;
16705
16706   g_return_val_if_fail (iter != NULL, FALSE);
16707   g_return_val_if_fail (ri->root != NULL, FALSE);
16708 #ifndef G_DISABLE_ASSERT
16709   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16710 #endif
16711
16712   if (ri->current == NULL)
16713     ri->current = ri->root->priv->first_child;
16714   else
16715     ri->current = ri->current->priv->next_sibling;
16716
16717   if (child != NULL)
16718     *child = ri->current;
16719
16720   return ri->current != NULL;
16721 }
16722
16723 /**
16724  * clutter_actor_iter_prev:
16725  * @iter: a #ClutterActorIter
16726  * @child: (out): return location for a #ClutterActor
16727  *
16728  * Advances the @iter and retrieves the previous child of the root
16729  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16730  *
16731  * If the iterator can advance, this function returns %TRUE and sets the
16732  * @child argument.
16733  *
16734  * If the iterator cannot advance, this function returns %FALSE, and
16735  * the contents of @child are undefined.
16736  *
16737  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16738  *
16739  * Since: 1.10
16740  */
16741 gboolean
16742 clutter_actor_iter_prev (ClutterActorIter  *iter,
16743                          ClutterActor     **child)
16744 {
16745   RealActorIter *ri = (RealActorIter *) iter;
16746
16747   g_return_val_if_fail (iter != NULL, FALSE);
16748   g_return_val_if_fail (ri->root != NULL, FALSE);
16749 #ifndef G_DISABLE_ASSERT
16750   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16751 #endif
16752
16753   if (ri->current == NULL)
16754     ri->current = ri->root->priv->last_child;
16755   else
16756     ri->current = ri->current->priv->prev_sibling;
16757
16758   if (child != NULL)
16759     *child = ri->current;
16760
16761   return ri->current != NULL;
16762 }
16763
16764 /**
16765  * clutter_actor_iter_remove:
16766  * @iter: a #ClutterActorIter
16767  *
16768  * Safely removes the #ClutterActor currently pointer to by the iterator
16769  * from its parent.
16770  *
16771  * This function can only be called after clutter_actor_iter_next() or
16772  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16773  * than once for the same actor.
16774  *
16775  * This function will call clutter_actor_remove_child() internally.
16776  *
16777  * Since: 1.10
16778  */
16779 void
16780 clutter_actor_iter_remove (ClutterActorIter *iter)
16781 {
16782   RealActorIter *ri = (RealActorIter *) iter;
16783   ClutterActor *cur;
16784
16785   g_return_if_fail (iter != NULL);
16786   g_return_if_fail (ri->root != NULL);
16787 #ifndef G_DISABLE_ASSERT
16788   g_return_if_fail (ri->age == ri->root->priv->age);
16789 #endif
16790   g_return_if_fail (ri->current != NULL);
16791
16792   cur = ri->current;
16793
16794   if (cur != NULL)
16795     {
16796       ri->current = cur->priv->prev_sibling;
16797
16798       clutter_actor_remove_child_internal (ri->root, cur,
16799                                            REMOVE_CHILD_DEFAULT_FLAGS);
16800
16801       ri->age += 1;
16802     }
16803 }
16804
16805 /**
16806  * clutter_actor_iter_destroy:
16807  * @iter: a #ClutterActorIter
16808  *
16809  * Safely destroys the #ClutterActor currently pointer to by the iterator
16810  * from its parent.
16811  *
16812  * This function can only be called after clutter_actor_iter_next() or
16813  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16814  * than once for the same actor.
16815  *
16816  * This function will call clutter_actor_destroy() internally.
16817  *
16818  * Since: 1.10
16819  */
16820 void
16821 clutter_actor_iter_destroy (ClutterActorIter *iter)
16822 {
16823   RealActorIter *ri = (RealActorIter *) iter;
16824   ClutterActor *cur;
16825
16826   g_return_if_fail (iter != NULL);
16827   g_return_if_fail (ri->root != NULL);
16828 #ifndef G_DISABLE_ASSERT
16829   g_return_if_fail (ri->age == ri->root->priv->age);
16830 #endif
16831   g_return_if_fail (ri->current != NULL);
16832
16833   cur = ri->current;
16834
16835   if (cur != NULL)
16836     {
16837       ri->current = cur->priv->prev_sibling;
16838
16839       clutter_actor_destroy (cur);
16840
16841       ri->age += 1;
16842     }
16843 }
16844
16845 static const ClutterAnimationInfo default_animation_info = {
16846   NULL,         /* transitions */
16847   NULL,         /* states */
16848   NULL,         /* cur_state */
16849 };
16850
16851 static void
16852 clutter_animation_info_free (gpointer data)
16853 {
16854   if (data != NULL)
16855     {
16856       ClutterAnimationInfo *info = data;
16857
16858       if (info->transitions != NULL)
16859         g_hash_table_unref (info->transitions);
16860
16861       if (info->states != NULL)
16862         g_array_unref (info->states);
16863
16864       g_slice_free (ClutterAnimationInfo, info);
16865     }
16866 }
16867
16868 const ClutterAnimationInfo *
16869 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16870 {
16871   const ClutterAnimationInfo *res;
16872   GObject *obj = G_OBJECT (self);
16873
16874   res = g_object_get_qdata (obj, quark_actor_animation_info);
16875   if (res != NULL)
16876     return res;
16877
16878   return &default_animation_info;
16879 }
16880
16881 ClutterAnimationInfo *
16882 _clutter_actor_get_animation_info (ClutterActor *self)
16883 {
16884   GObject *obj = G_OBJECT (self);
16885   ClutterAnimationInfo *res;
16886
16887   res = g_object_get_qdata (obj, quark_actor_animation_info);
16888   if (res == NULL)
16889     {
16890       res = g_slice_new (ClutterAnimationInfo);
16891
16892       *res = default_animation_info;
16893
16894       g_object_set_qdata_full (obj, quark_actor_animation_info,
16895                                res,
16896                                clutter_animation_info_free);
16897     }
16898
16899   return res;
16900 }
16901
16902 ClutterTransition *
16903 _clutter_actor_get_transition (ClutterActor *actor,
16904                                GParamSpec   *pspec)
16905 {
16906   const ClutterAnimationInfo *info;
16907
16908   info = _clutter_actor_get_animation_info_or_defaults (actor);
16909
16910   if (info->transitions == NULL)
16911     return NULL;
16912
16913   return g_hash_table_lookup (info->transitions, pspec->name);
16914 }
16915
16916 typedef struct _TransitionClosure
16917 {
16918   ClutterActor *actor;
16919   ClutterTransition *transition;
16920   gchar *name;
16921   gulong completed_id;
16922 } TransitionClosure;
16923
16924 static void
16925 transition_closure_free (gpointer data)
16926 {
16927   if (G_LIKELY (data != NULL))
16928     {
16929       TransitionClosure *clos = data;
16930
16931       g_signal_handler_disconnect (clos->transition, clos->completed_id);
16932       g_free (clos->name);
16933
16934       g_slice_free (TransitionClosure, clos);
16935     }
16936 }
16937
16938 static void
16939 on_transition_completed (ClutterTransition *transition,
16940                          TransitionClosure *clos)
16941 {
16942   ClutterAnimationInfo *info;
16943
16944   info = _clutter_actor_get_animation_info (clos->actor);
16945
16946   /* this will take care of cleaning clos for us */
16947   g_hash_table_remove (info->transitions, clos->name);
16948 }
16949
16950 void
16951 _clutter_actor_update_transition (ClutterActor *actor,
16952                                   GParamSpec   *pspec,
16953                                   ...)
16954 {
16955   TransitionClosure *clos;
16956   ClutterInterval *interval;
16957   const ClutterAnimationInfo *info;
16958   va_list var_args;
16959   GType ptype;
16960   GValue initial = G_VALUE_INIT;
16961   GValue final = G_VALUE_INIT;
16962   char *error = NULL;
16963
16964   info = _clutter_actor_get_animation_info_or_defaults (actor);
16965
16966   if (info->transitions == NULL)
16967     return;
16968
16969   clos = g_hash_table_lookup (info->transitions, pspec->name);
16970   if (clos == NULL)
16971     return;
16972
16973   va_start (var_args, pspec);
16974
16975   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16976
16977   g_value_init (&initial, ptype);
16978   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
16979                                         pspec->name,
16980                                         &initial);
16981
16982   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
16983   if (error != NULL)
16984     {
16985       g_critical ("%s: %s", G_STRLOC, error);
16986       g_free (error);
16987       goto out;
16988     }
16989
16990   interval = clutter_transition_get_interval (clos->transition);
16991   clutter_interval_set_initial_value (interval, &initial);
16992   clutter_interval_set_final_value (interval, &final);
16993
16994   clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
16995
16996 out:
16997   g_value_unset (&initial);
16998   g_value_unset (&final);
16999
17000   va_end (var_args);
17001 }
17002
17003 /*< private >*
17004  * _clutter_actor_create_transition:
17005  * @actor: a #ClutterActor
17006  * @pspec: the property used for the transition
17007  * @...: initial and final state
17008  *
17009  * Creates a #ClutterTransition for the property represented by @pspec.
17010  *
17011  * Return value: a #ClutterTransition
17012  */
17013 ClutterTransition *
17014 _clutter_actor_create_transition (ClutterActor *actor,
17015                                   GParamSpec   *pspec,
17016                                   ...)
17017 {
17018   ClutterAnimationInfo *info;
17019   ClutterTransition *res = NULL;
17020   gboolean call_restore = FALSE;
17021   TransitionClosure *clos;
17022   va_list var_args;
17023
17024   info = _clutter_actor_get_animation_info (actor);
17025
17026   if (info->states == NULL)
17027     {
17028       clutter_actor_save_easing_state (actor);
17029       call_restore = TRUE;
17030     }
17031
17032   if (info->transitions == NULL)
17033     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17034                                                NULL,
17035                                                transition_closure_free);
17036
17037   va_start (var_args, pspec);
17038
17039   clos = g_hash_table_lookup (info->transitions, pspec->name);
17040   if (clos == NULL)
17041     {
17042       ClutterInterval *interval;
17043       GValue initial = G_VALUE_INIT;
17044       GValue final = G_VALUE_INIT;
17045       GType ptype;
17046       char *error;
17047
17048       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17049
17050       G_VALUE_COLLECT_INIT (&initial, ptype,
17051                             var_args, 0,
17052                             &error);
17053       if (error != NULL)
17054         {
17055           g_critical ("%s: %s", G_STRLOC, error);
17056           g_free (error);
17057           goto out;
17058         }
17059
17060       G_VALUE_COLLECT_INIT (&final, ptype,
17061                             var_args, 0,
17062                             &error);
17063
17064       if (error != NULL)
17065         {
17066           g_critical ("%s: %s", G_STRLOC, error);
17067           g_value_unset (&initial);
17068           g_free (error);
17069           goto out;
17070         }
17071
17072       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17073
17074       g_value_unset (&initial);
17075       g_value_unset (&final);
17076
17077       res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
17078                                              pspec->name);
17079
17080       clutter_transition_set_interval (res, interval);
17081       clutter_transition_set_remove_on_complete (res, TRUE);
17082
17083       clutter_actor_add_transition (actor, pspec->name, res);
17084     }
17085   else
17086     res = clos->transition;
17087
17088 out:
17089   if (call_restore)
17090     clutter_actor_restore_easing_state (actor);
17091
17092   va_end (var_args);
17093
17094   return res;
17095 }
17096
17097 /**
17098  * clutter_actor_add_transition:
17099  * @self: a #ClutterActor
17100  * @name: the name of the transition to add
17101  * @transition: the #ClutterTransition to add
17102  *
17103  * Adds a @transition to the #ClutterActor's list of animations.
17104  *
17105  * The @name string is a per-actor unique identifier of the @transition: only
17106  * one #ClutterTransition can be associated to the specified @name.
17107  *
17108  * The @transition will be given the easing duration, mode, and delay
17109  * associated to the actor's current easing state; it is possible to modify
17110  * these values after calling clutter_actor_add_transition().
17111  *
17112  * This function is usually called implicitly when modifying an animatable
17113  * property.
17114  *
17115  * Since: 1.10
17116  */
17117 void
17118 clutter_actor_add_transition (ClutterActor      *self,
17119                               const char        *name,
17120                               ClutterTransition *transition)
17121 {
17122   ClutterTimeline *timeline;
17123   TransitionClosure *clos;
17124   ClutterAnimationInfo *info;
17125
17126   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17127   g_return_if_fail (name != NULL);
17128   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17129
17130   info = _clutter_actor_get_animation_info (self);
17131
17132   if (info->cur_state == NULL)
17133     {
17134       g_warning ("No easing state is defined for the actor '%s'; you "
17135                  "must call clutter_actor_save_easing_state() before "
17136                  "calling clutter_actor_add_transition().",
17137                  _clutter_actor_get_debug_name (self));
17138       return;
17139     }
17140
17141   if (info->transitions == NULL)
17142     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17143                                                NULL,
17144                                                transition_closure_free);
17145
17146   if (g_hash_table_lookup (info->transitions, name) != NULL)
17147     {
17148       g_warning ("A transition with name '%s' already exists for "
17149                  "the actor '%s'",
17150                  name,
17151                  _clutter_actor_get_debug_name (self));
17152       return;
17153     }
17154
17155   timeline = CLUTTER_TIMELINE (transition);
17156
17157   clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17158   clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17159   clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17160
17161   clos = g_slice_new (TransitionClosure);
17162   clos->actor = self;
17163   clos->transition = transition;
17164   clos->name = g_strdup (name);
17165   clos->completed_id = g_signal_connect (timeline, "completed",
17166                                          G_CALLBACK (on_transition_completed),
17167                                          clos);
17168
17169   g_hash_table_insert (info->transitions, clos->name, clos);
17170 }
17171
17172 /**
17173  * clutter_actor_remove_transition:
17174  * @self: a #ClutterActor
17175  * @name: the name of the transition to remove
17176  *
17177  * Removes the transition stored inside a #ClutterActor using @name
17178  * identifier.
17179  *
17180  * Since: 1.10
17181  */
17182 void
17183 clutter_actor_remove_transition (ClutterActor *self,
17184                                  const char   *name)
17185 {
17186   const ClutterAnimationInfo *info;
17187
17188   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17189   g_return_if_fail (name != NULL);
17190
17191   info = _clutter_actor_get_animation_info_or_defaults (self);
17192
17193   if (info->transitions == NULL)
17194     return;
17195
17196   g_hash_table_remove (info->transitions, name);
17197 }
17198
17199 /**
17200  * clutter_actor_remove_all_transitions:
17201  * @self: a #ClutterActor
17202  *
17203  * Removes all transitions associated to @self.
17204  *
17205  * Since: 1.10
17206  */
17207 void
17208 clutter_actor_remove_all_transitions (ClutterActor *self)
17209 {
17210   const ClutterAnimationInfo *info;
17211
17212   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17213
17214   info = _clutter_actor_get_animation_info_or_defaults (self);
17215   if (info->transitions == NULL)
17216     return;
17217
17218   g_hash_table_remove_all (info->transitions);
17219 }
17220
17221 /**
17222  * clutter_actor_set_easing_duration:
17223  * @self: a #ClutterActor
17224  * @msecs: the duration of the easing, or %NULL
17225  *
17226  * Sets the duration of the tweening for animatable properties
17227  * of @self for the current easing state.
17228  *
17229  * Calling this function will implicitly call
17230  * clutter_actor_save_easing_state() if no previous call to
17231  * that function was made.
17232  *
17233  * Since: 1.10
17234  */
17235 void
17236 clutter_actor_set_easing_duration (ClutterActor *self,
17237                                    guint         msecs)
17238 {
17239   ClutterAnimationInfo *info;
17240
17241   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17242
17243   info = _clutter_actor_get_animation_info (self);
17244
17245   if (info->states == NULL)
17246     clutter_actor_save_easing_state (self);
17247
17248   if (info->cur_state->easing_duration != msecs)
17249     info->cur_state->easing_duration = msecs;
17250 }
17251
17252 /**
17253  * clutter_actor_get_easing_duration:
17254  * @self: a #ClutterActor
17255  *
17256  * Retrieves the duration of the tweening for animatable
17257  * properties of @self for the current easing state.
17258  *
17259  * Return value: the duration of the tweening, in milliseconds
17260  *
17261  * Since: 1.10
17262  */
17263 guint
17264 clutter_actor_get_easing_duration (ClutterActor *self)
17265 {
17266   const ClutterAnimationInfo *info;
17267
17268   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17269
17270   info = _clutter_actor_get_animation_info_or_defaults (self);
17271
17272   if (info->cur_state != NULL)
17273     return info->cur_state->easing_duration;
17274
17275   return 0;
17276 }
17277
17278 /**
17279  * clutter_actor_set_easing_mode:
17280  * @self: a #ClutterActor
17281  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17282  *
17283  * Sets the easing mode for the tweening of animatable properties
17284  * of @self.
17285  *
17286  * Calling this function will implicitly call
17287  * clutter_actor_save_easing_state() if no previous calls to
17288  * that function were made.
17289  *
17290  * Since: 1.10
17291  */
17292 void
17293 clutter_actor_set_easing_mode (ClutterActor         *self,
17294                                ClutterAnimationMode  mode)
17295 {
17296   ClutterAnimationInfo *info;
17297
17298   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17299   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17300   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17301
17302   info = _clutter_actor_get_animation_info (self);
17303
17304   if (info->states == NULL)
17305     clutter_actor_save_easing_state (self);
17306
17307   if (info->cur_state->easing_mode != mode)
17308     info->cur_state->easing_mode = mode;
17309 }
17310
17311 /**
17312  * clutter_actor_get_easing_mode:
17313  * @self: a #ClutterActor
17314  *
17315  * Retrieves the easing mode for the tweening of animatable properties
17316  * of @self for the current easing state.
17317  *
17318  * Return value: an easing mode
17319  *
17320  * Since: 1.10
17321  */
17322 ClutterAnimationMode
17323 clutter_actor_get_easing_mode (ClutterActor *self)
17324 {
17325   const ClutterAnimationInfo *info;
17326
17327   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17328
17329   info = _clutter_actor_get_animation_info_or_defaults (self);
17330
17331   if (info->cur_state != NULL)
17332     return info->cur_state->easing_mode;
17333
17334   return CLUTTER_EASE_OUT_CUBIC;
17335 }
17336
17337 /**
17338  * clutter_actor_set_easing_delay:
17339  * @self: a #ClutterActor
17340  * @msecs: the delay before the start of the tweening, in milliseconds
17341  *
17342  * Sets the delay that should be applied before tweening animatable
17343  * properties.
17344  *
17345  * Calling this function will implicitly call
17346  * clutter_actor_save_easing_state() if no previous calls to
17347  * that function were made.
17348  *
17349  * Since: 1.10
17350  */
17351 void
17352 clutter_actor_set_easing_delay (ClutterActor *self,
17353                                 guint         msecs)
17354 {
17355   ClutterAnimationInfo *info;
17356
17357   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17358
17359   info = _clutter_actor_get_animation_info (self);
17360
17361   if (info->states == NULL)
17362     clutter_actor_save_easing_state (self);
17363
17364   if (info->cur_state->easing_delay != msecs)
17365     info->cur_state->easing_delay = msecs;
17366 }
17367
17368 /**
17369  * clutter_actor_get_easing_delay:
17370  * @self: a #ClutterActor
17371  *
17372  * Retrieves the delay that should be applied when tweening animatable
17373  * properties.
17374  *
17375  * Return value: a delay, in milliseconds
17376  *
17377  * Since: 1.10
17378  */
17379 guint
17380 clutter_actor_get_easing_delay (ClutterActor *self)
17381 {
17382   const ClutterAnimationInfo *info;
17383
17384   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17385
17386   info = _clutter_actor_get_animation_info_or_defaults (self);
17387
17388   if (info->cur_state != NULL)
17389     return info->cur_state->easing_delay;
17390
17391   return 0;
17392 }
17393
17394 /**
17395  * clutter_actor_get_transition:
17396  * @self: a #ClutterActor
17397  * @name: the name of the transition
17398  *
17399  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17400  * transition @name.
17401  *
17402  * Transitions created for animatable properties use the name of the
17403  * property itself, for instance the code below:
17404  *
17405  * |[
17406  *   clutter_actor_set_easing_duration (actor, 1000);
17407  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17408  *
17409  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17410  *   g_signal_connect (transition, "completed",
17411  *                     G_CALLBACK (on_transition_complete),
17412  *                     actor);
17413  * ]|
17414  *
17415  * will call the <function>on_transition_complete</function> callback when
17416  * the transition is complete.
17417  *
17418  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17419  *   was found to match the passed name; the returned instance is owned
17420  *   by Clutter and it should not be freed
17421  *
17422  * Since: 1.10
17423  */
17424 ClutterTransition *
17425 clutter_actor_get_transition (ClutterActor *self,
17426                               const char   *name)
17427 {
17428   TransitionClosure *clos;
17429   const ClutterAnimationInfo *info;
17430
17431   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17432   g_return_val_if_fail (name != NULL, NULL);
17433
17434   info = _clutter_actor_get_animation_info_or_defaults (self);
17435
17436   if (info->transitions == NULL)
17437     return NULL;
17438
17439   clos = g_hash_table_lookup (info->transitions, name);
17440   if (clos == NULL)
17441     return NULL;
17442
17443   return clos->transition;
17444 }
17445
17446 /**
17447  * clutter_actor_save_easing_state:
17448  * @self: a #ClutterActor
17449  *
17450  * Saves the current easing state for animatable properties, and creates
17451  * a new state with the default values for easing mode and duration.
17452  *
17453  * Since: 1.10
17454  */
17455 void
17456 clutter_actor_save_easing_state (ClutterActor *self)
17457 {
17458   ClutterAnimationInfo *info;
17459   AState new_state;
17460
17461   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17462
17463   info = _clutter_actor_get_animation_info (self);
17464
17465   if (info->states == NULL)
17466     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17467
17468   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17469   new_state.easing_duration = 250;
17470   new_state.easing_delay = 0;
17471
17472   g_array_append_val (info->states, new_state);
17473
17474   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17475 }
17476
17477 /**
17478  * clutter_actor_restore_easing_state:
17479  * @self: a #ClutterActor
17480  *
17481  * Restores the easing state as it was prior to a call to
17482  * clutter_actor_save_easing_state().
17483  *
17484  * Since: 1.10
17485  */
17486 void
17487 clutter_actor_restore_easing_state (ClutterActor *self)
17488 {
17489   ClutterAnimationInfo *info;
17490
17491   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17492
17493   info = _clutter_actor_get_animation_info (self);
17494
17495   if (info->states == NULL)
17496     {
17497       g_critical ("The function clutter_actor_restore_easing_state() has "
17498                   "called without a previous call to "
17499                   "clutter_actor_save_easing_state().");
17500       return;
17501     }
17502
17503   g_array_remove_index (info->states, info->states->len - 1);
17504   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17505 }
17506
17507 /**
17508  * clutter_actor_set_content:
17509  * @self: a #ClutterActor
17510  * @content: (allow-none): a #ClutterContent, or %NULL
17511  *
17512  * Sets the contents of a #ClutterActor.
17513  *
17514  * Since: 1.10
17515  */
17516 void
17517 clutter_actor_set_content (ClutterActor   *self,
17518                            ClutterContent *content)
17519 {
17520   ClutterActorPrivate *priv;
17521
17522   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17523   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17524
17525   priv = self->priv;
17526
17527   if (priv->content != NULL)
17528     {
17529       _clutter_content_detached (priv->content, self);
17530       g_object_unref (priv->content);
17531     }
17532
17533   priv->content = content;
17534
17535   if (priv->content != NULL)
17536     {
17537       g_object_ref (priv->content);
17538       _clutter_content_attached (priv->content, self);
17539     }
17540
17541   /* given that the content is always painted within the allocation,
17542    * we only need to queue a redraw here
17543    */
17544   clutter_actor_queue_redraw (self);
17545
17546   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17547
17548   /* if the content gravity is not resize-fill, and the new content has a
17549    * different preferred size than the previous one, then the content box
17550    * may have been changed. since we compute that lazily, we just notify
17551    * here, and let whomever watches :content-box do whatever they need to
17552    * do.
17553    */
17554   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17555     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17556 }
17557
17558 /**
17559  * clutter_actor_get_content:
17560  * @self: a #ClutterActor
17561  *
17562  * Retrieves the contents of @self.
17563  *
17564  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17565  *   or %NULL if none was set
17566  *
17567  * Since: 1.10
17568  */
17569 ClutterContent *
17570 clutter_actor_get_content (ClutterActor *self)
17571 {
17572   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17573
17574   return self->priv->content;
17575 }
17576
17577 /**
17578  * clutter_actor_set_content_gravity:
17579  * @self: a #ClutterActor
17580  * @gravity: the #ClutterContentGravity
17581  *
17582  * Sets the gravity of the #ClutterContent used by @self.
17583  *
17584  * See the description of the #ClutterActor:content-gravity property for
17585  * more information.
17586  *
17587  * Since: 1.10
17588  */
17589 void
17590 clutter_actor_set_content_gravity (ClutterActor *self,
17591                                    ClutterContentGravity  gravity)
17592 {
17593   ClutterActorPrivate *priv;
17594
17595   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17596
17597   priv = self->priv;
17598
17599   if (priv->content_gravity == gravity)
17600     return;
17601
17602   priv->content_gravity = gravity;
17603
17604   clutter_actor_queue_redraw (self);
17605
17606   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17607   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17608 }
17609
17610 /**
17611  * clutter_actor_get_content_gravity:
17612  * @self: a #ClutterActor
17613  *
17614  * Retrieves the content gravity as set using
17615  * clutter_actor_get_content_gravity().
17616  *
17617  * Return value: the content gravity
17618  *
17619  * Since: 1.10
17620  */
17621 ClutterContentGravity
17622 clutter_actor_get_content_gravity (ClutterActor *self)
17623 {
17624   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17625                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17626
17627   return self->priv->content_gravity;
17628 }
17629
17630 /**
17631  * clutter_actor_get_content_box:
17632  * @self: a #ClutterActor
17633  * @box: (out caller-allocates): the return location for the bounding
17634  *   box for the #ClutterContent
17635  *
17636  * Retrieves the bounding box for the #ClutterContent of @self.
17637  *
17638  * The bounding box is relative to the actor's allocation.
17639  *
17640  * If no #ClutterContent is set for @self, or if @self has not been
17641  * allocated yet, then the result is undefined.
17642  *
17643  * The content box is guaranteed to be, at most, as big as the allocation
17644  * of the #ClutterActor.
17645  *
17646  * If the #ClutterContent used by the actor has a preferred size, then
17647  * it is possible to modify the content box by using the
17648  * #ClutterActor:content-gravity property.
17649  *
17650  * Since: 1.10
17651  */
17652 void
17653 clutter_actor_get_content_box (ClutterActor    *self,
17654                                ClutterActorBox *box)
17655 {
17656   ClutterActorPrivate *priv;
17657   gfloat content_w, content_h;
17658   gfloat alloc_w, alloc_h;
17659
17660   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17661   g_return_if_fail (box != NULL);
17662
17663   priv = self->priv;
17664
17665   box->x1 = 0.f;
17666   box->y1 = 0.f;
17667   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17668   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17669
17670   if (priv->content == NULL)
17671     return;
17672
17673   /* no need to do any more work */
17674   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17675     return;
17676
17677   /* if the content does not have a preferred size then there is
17678    * no point in computing the content box
17679    */
17680   if (!clutter_content_get_preferred_size (priv->content,
17681                                            &content_w,
17682                                            &content_h))
17683     return;
17684
17685   alloc_w = box->x2;
17686   alloc_h = box->y2;
17687
17688   switch (priv->content_gravity)
17689     {
17690     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17691       box->x2 = box->x1 + MIN (content_w, alloc_w);
17692       box->y2 = box->y1 + MIN (content_h, alloc_h);
17693       break;
17694
17695     case CLUTTER_CONTENT_GRAVITY_TOP:
17696       if (alloc_w > content_w)
17697         {
17698           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17699           box->x2 = box->x1 + content_w;
17700         }
17701       box->y2 = box->y1 + MIN (content_h, alloc_h);
17702       break;
17703
17704     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17705       if (alloc_w > content_w)
17706         {
17707           box->x1 += (alloc_w - content_w);
17708           box->x2 = box->x1 + content_w;
17709         }
17710       box->y2 = box->y1 + MIN (content_h, alloc_h);
17711       break;
17712
17713     case CLUTTER_CONTENT_GRAVITY_LEFT:
17714       box->x2 = box->x1 + MIN (content_w, alloc_w);
17715       if (alloc_h > content_h)
17716         {
17717           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17718           box->y2 = box->y1 + content_h;
17719         }
17720       break;
17721
17722     case CLUTTER_CONTENT_GRAVITY_CENTER:
17723       if (alloc_w > content_w)
17724         {
17725           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17726           box->x2 = box->x1 + content_w;
17727         }
17728       if (alloc_h > content_h)
17729         {
17730           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17731           box->y2 = box->y1 + content_h;
17732         }
17733       break;
17734
17735     case CLUTTER_CONTENT_GRAVITY_RIGHT:
17736       if (alloc_w > content_w)
17737         {
17738           box->x1 += (alloc_w - content_w);
17739           box->x2 = box->x1 + content_w;
17740         }
17741       if (alloc_h > content_h)
17742         {
17743           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17744           box->y2 = box->y1 + content_h;
17745         }
17746       break;
17747
17748     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17749       box->x2 = box->x1 + MIN (content_w, alloc_w);
17750       if (alloc_h > content_h)
17751         {
17752           box->y1 += (alloc_h - content_h);
17753           box->y2 = box->y1 + content_h;
17754         }
17755       break;
17756
17757     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17758       if (alloc_w > content_w)
17759         {
17760           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17761           box->x2 = box->x1 + content_w;
17762         }
17763       if (alloc_h > content_h)
17764         {
17765           box->y1 += (alloc_h - content_h);
17766           box->y2 = box->y1 + content_h;
17767         }
17768       break;
17769
17770     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17771       if (alloc_w > content_w)
17772         {
17773           box->x1 += (alloc_w - content_w);
17774           box->x2 = box->x1 + content_w;
17775         }
17776       if (alloc_h > content_h)
17777         {
17778           box->y1 += (alloc_h - content_h);
17779           box->y2 = box->y1 + content_h;
17780         }
17781       break;
17782
17783     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17784       g_assert_not_reached ();
17785       break;
17786
17787     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17788       {
17789         double r_c = content_w / content_h;
17790         double r_a = alloc_w / alloc_h;
17791
17792         if (r_c >= 1.0)
17793           {
17794             if (r_a >= 1.0)
17795               {
17796                 box->x1 = 0.f;
17797                 box->x2 = alloc_w;
17798
17799                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17800                 box->y2 = box->y1 + (alloc_w * r_c);
17801               }
17802             else
17803               {
17804                 box->y1 = 0.f;
17805                 box->y2 = alloc_h;
17806
17807                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17808                 box->x2 = box->x1 + (alloc_h * r_c);
17809               }
17810           }
17811         else
17812           {
17813             if (r_a >= 1.0)
17814               {
17815                 box->y1 = 0.f;
17816                 box->y2 = alloc_h;
17817
17818                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17819                 box->x2 = box->x1 + (alloc_h * r_c);
17820               }
17821             else
17822               {
17823                 box->x1 = 0.f;
17824                 box->x2 = alloc_w;
17825
17826                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17827                 box->y2 = box->y1 + (alloc_w * r_c);
17828               }
17829           }
17830       }
17831       break;
17832     }
17833 }
17834
17835 /**
17836  * clutter_actor_set_content_scaling_filters:
17837  * @self: a #ClutterActor
17838  * @min_filter: the minification filter for the content
17839  * @mag_filter: the magnification filter for the content
17840  *
17841  * Sets the minification and magnification filter to be applied when
17842  * scaling the #ClutterActor:content of a #ClutterActor.
17843  *
17844  * The #ClutterActor:minification-filter will be used when reducing
17845  * the size of the content; the #ClutterActor:magnification-filter
17846  * will be used when increasing the size of the content.
17847  *
17848  * Since: 1.10
17849  */
17850 void
17851 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
17852                                            ClutterScalingFilter  min_filter,
17853                                            ClutterScalingFilter  mag_filter)
17854 {
17855   ClutterActorPrivate *priv;
17856   gboolean changed;
17857   GObject *obj;
17858
17859   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17860
17861   priv = self->priv;
17862   obj = G_OBJECT (self);
17863
17864   g_object_freeze_notify (obj);
17865
17866   changed = FALSE;
17867
17868   if (priv->min_filter != min_filter)
17869     {
17870       priv->min_filter = min_filter;
17871       changed = TRUE;
17872
17873       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
17874     }
17875
17876   if (priv->mag_filter != mag_filter)
17877     {
17878       priv->mag_filter = mag_filter;
17879       changed = TRUE;
17880
17881       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
17882     }
17883
17884   if (changed)
17885     clutter_actor_queue_redraw (self);
17886
17887   g_object_thaw_notify (obj);
17888 }
17889
17890 /**
17891  * clutter_actor_get_content_scaling_filters:
17892  * @self: a #ClutterActor
17893  * @min_filter: (out) (allow-none): return location for the minification
17894  *   filter, or %NULL
17895  * @mag_filter: (out) (allow-none): return location for the magnification
17896  *   filter, or %NULL
17897  *
17898  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
17899  *
17900  * Since: 1.10
17901  */
17902 void
17903 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
17904                                            ClutterScalingFilter *min_filter,
17905                                            ClutterScalingFilter *mag_filter)
17906 {
17907   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17908
17909   if (min_filter != NULL)
17910     *min_filter = self->priv->min_filter;
17911
17912   if (mag_filter != NULL)
17913     *mag_filter = self->priv->mag_filter;
17914 }