docs: Update documentation on the paint sequence
[profile/ivi/clutter.git] / clutter / clutter-actor.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9  * Copyright (C) 2009, 2010, 2011, 2012 Intel Corp
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /**
26  * SECTION:clutter-actor
27  * @short_description: Base abstract class for all visual stage actors.
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="actor-example-image">
113  *     <title>Actors</title>
114  *     <graphic fileref="actor-example.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-painting">
119  *   <title>Painting an actor</title>
120  *   <para>There are three ways to paint an actor:</para>
121  *   <itemizedlist>
122  *     <listitem><para>set a delegate #ClutterContent as the value for the
123  *     #ClutterActor:content property of the actor;</para></listitem>
124  *     <listitem><para>subclass #ClutterActor and override the
125  *     #ClutterActorClass.paint_node() virtual function;</para></listitem>
126  *     <listitem><para>subclass #ClutterActor and override the
127  *     #ClutterActorClass.paint() virtual function.</para></listitem>
128  *   </itemizedlist>
129  *   <formalpara>
130  *     <title>Setting the Content property</title>
131  *     <para>A #ClutterContent is a delegate object that takes over the
132  *     painting operation of one, or more actors. The #ClutterContent
133  *     painting will be performed on top of the #ClutterActor:background-color
134  *     of the actor, and before calling the #ClutterActorClass.paint_node()
135  *     virtual function.</para>
136  *     <informalexample><programlisting>
137  * ClutterActor *actor = clutter_actor_new ();
138  *
139  * /&ast; set the bounding box &ast;/
140  * clutter_actor_set_position (actor, 50, 50);
141  * clutter_actor_set_size (actor, 100, 100);
142  *
143  * /&ast; set the content; the image_content variable is set elsewhere &ast;/
144  * clutter_actor_set_content (actor, image_content);
145  *     </programlisting></informalexample>
146  *   </formalpara>
147  *   <formalpara>
148  *     <title>Overriding the paint_node virtual function</title>
149  *     <para>The #ClutterActorClass.paint_node() virtual function is invoked
150  *     whenever an actor needs to be painted. The implementation of the
151  *     virtual function must only paint the contents of the actor itself,
152  *     and not the contents of its children, if the actor has any.</para>
153  *     <para>The #ClutterPaintNode passed to the virtual function is the
154  *     local root of the render tree; any node added to it will be
155  *     rendered at the correct position, as defined by the actor's
156  *     #ClutterActor:allocation.</para>
157  *     <informalexample><programlisting>
158  * static void
159  * my_actor_paint_node (ClutterActor     *actor,
160  *                      ClutterPaintNode *root)
161  * {
162  *   ClutterPaintNode *node;
163  *   ClutterActorBox box;
164  *
165  *   /&ast; where the content of the actor should be painted &ast;/
166  *   clutter_actor_get_allocation_box (actor, &box);
167  *
168  *   /&ast; the cogl_texture variable is set elsewhere &ast;/
169  *   node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White);
170  *
171  *   /&ast; paint the content of the node using the allocation &ast;/
172  *   clutter_paint_node_add_rectangle (node, &box);
173  *
174  *   /&ast; add the node, and transfer ownership &ast;/
175  *   clutter_paint_node_add_child (root, node);
176  *   clutter_paint_node_unref (node);
177  * }
178  *     </programlisting></informalexample>
179  *   </formalpara>
180  *   <formalpara>
181  *     <title>Overriding the paint virtual function</title>
182  *     <para>The #ClutterActorClass.paint() virtual function is invoked
183  *     when the #ClutterActor::paint signal is emitted, and after the other
184  *     signal handlers have been invoked. Overriding the paint virtual
185  *     function gives total control to the paint sequence of the actor
186  *     itself, including the children of the actor, if any.</para>
187  *     <warning><para>It is strongly discouraged to override the
188  *     #ClutterActorClass.paint() virtual function, as well as connecting
189  *     to the #ClutterActor::paint signal. These hooks into the paint
190  *     sequence are considered legacy, and will be removed when the Clutter
191  *     API changes.</para></warning>
192  *   </formalpara>
193  * </refsect2>
194  *
195  * <refsect2 id="ClutterActor-events">
196  *   <title>Handling events on an actor</title>
197  *   <para>A #ClutterActor can receive and handle input device events, for
198  *   instance pointer events and key events, as long as its
199  *   #ClutterActor:reactive property is set to %TRUE.</para>
200  *   <para>Once an actor has been determined to be the source of an event,
201  *   Clutter will traverse the scene graph from the top-level actor towards the
202  *   event source, emitting the #ClutterActor::captured-event signal on each
203  *   ancestor until it reaches the source; this phase is also called
204  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
205  *   stopped, the graph is walked backwards, from the source actor to the
206  *   top-level, and the #ClutterActor::event signal, along with other event
207  *   signals if needed, is emitted; this phase is also called <emphasis>the
208  *   bubble phase</emphasis>. At any point of the signal emission, signal
209  *   handlers can stop the propagation through the scene graph by returning
210  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
211  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
212  * </refsect2>
213  *
214  * <refsect2 id="ClutterActor-subclassing">
215  *   <title>Implementing an actor</title>
216  *   <para>Careful consideration should be given when deciding to implement
217  *   a #ClutterActor sub-class. It is generally recommended to implement a
218  *   sub-class of #ClutterActor only for actors that should be used as leaf
219  *   nodes of a scene graph.</para>
220  *   <para>If your actor should be painted in a custom way, you should
221  *   override the #ClutterActor::paint signal class handler. You can either
222  *   opt to chain up to the parent class implementation or decide to fully
223  *   override the default paint implementation; Clutter will set up the
224  *   transformations and clip regions prior to emitting the #ClutterActor::paint
225  *   signal.</para>
226  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
227  *   #ClutterActorClass.get_preferred_height() virtual functions it is
228  *   possible to change or provide the preferred size of an actor; similarly,
229  *   by overriding the #ClutterActorClass.allocate() virtual function it is
230  *   possible to control the layout of the children of an actor. Make sure to
231  *   always chain up to the parent implementation of the
232  *   #ClutterActorClass.allocate() virtual function.</para>
233  *   <para>In general, it is strongly encouraged to use delegation and
234  *   composition instead of direct subclassing.</para>
235  * </refsect2>
236  *
237  * <refsect2 id="ClutterActor-script">
238  *   <title>ClutterActor custom properties for #ClutterScript</title>
239  *   <para>#ClutterActor defines a custom "rotation" property which
240  *   allows a short-hand description of the rotations to be applied
241  *   to an actor.</para>
242  *   <para>The syntax of the "rotation" property is the following:</para>
243  *   <informalexample>
244  *     <programlisting>
245  * "rotation" : [
246  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
247  * ]
248  *     </programlisting>
249  *   </informalexample>
250  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
251  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
252  *   floating point value representing the rotation angle on the given axis,
253  *   in degrees.</para>
254  *   <para>The <emphasis>center</emphasis> array is optional, and if present
255  *   it must contain the center of rotation as described by two coordinates:
256  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
257  *   "z-axis".</para>
258  *   <para>#ClutterActor will also parse every positional and dimensional
259  *   property defined as a string through clutter_units_from_string(); you
260  *   should read the documentation for the #ClutterUnits parser format for
261  *   the valid units and syntax.</para>
262  * </refsect2>
263  *
264  * <refsect2 id="ClutterActor-animating">
265  *   <title>Custom animatable properties</title>
266  *   <para>#ClutterActor allows accessing properties of #ClutterAction
267  *   and #ClutterConstraint instances associated to an actor instance
268  *   for animation purposes.</para>
269  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
270  *   property it is necessary to set the #ClutterActorMeta:name property on the
271  *   given action or constraint.</para>
272  *   <para>The property can be accessed using the following syntax:</para>
273  *   <informalexample>
274  *     <programlisting>
275  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
276  *     </programlisting>
277  *   </informalexample>
278  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
279  *   <para>The <emphasis>section</emphasis> fragment can be one between
280  *   "actions", "constraints" and "effects".</para>
281  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
282  *   action or constraint, as specified by the #ClutterActorMeta:name
283  *   property.</para>
284  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
285  *   action or constraint property to be animated.</para>
286  *   <para>The example below animates a #ClutterBindConstraint applied to an
287  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
288  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
289  *   its initial state is fully transparent and overlapping the actor to
290  *   which is bound to. </para>
291  *   <informalexample><programlisting>
292  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
293  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
294  * clutter_actor_add_constraint (rect, constraint);
295  *
296  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
297  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
298  * clutter_actor_add_constraint (rect, constraint);
299  *
300  * clutter_actor_set_reactive (rect, TRUE);
301  * clutter_actor_set_opacity (rect, 0);
302  *
303  * g_signal_connect (rect, "button-press-event",
304  *                   G_CALLBACK (on_button_press),
305  *                   NULL);
306  *   </programlisting></informalexample>
307  *   <para>On button press, the rectangle "slides" from behind the actor to
308  *   which is bound to, using the #ClutterBindConstraint:offset property and
309  *   the #ClutterActor:opacity property.</para>
310  *   <informalexample><programlisting>
311  * float new_offset = clutter_actor_get_width (origin) + h_padding;
312  *
313  * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
314  *                        "opacity", 255,
315  *                        "@constraints.bind-x.offset", new_offset,
316  *                        NULL);
317  *   </programlisting></informalexample>
318  * </refsect2>
319  *
320  * <refsect2 id="ClutterActor-animatable-properties">
321  *   <title>Animatable properties</title>
322  *   <para>Certain properties on #ClutterActor are marked as "animatable";
323  *   these properties will be automatically tweened between the current
324  *   value and the new value when one is set.</para>
325  *   <para>For backward compatibility, animatable properties will only be
326  *   tweened if the easing duration is greater than 0, or if a new easing
327  *   state is set, for instance the following example:</para>
328  *   <informalexample><programlisting>
329  * clutter_actor_save_easing_state (actor);
330  * clutter_actor_set_position (actor, 200, 200);
331  * clutter_actor_restore_easing_state (actor);
332  *   </programlisting></informalexample>
333  *   <para>will tween the actor to the (200, 200) coordinates using the default
334  *   easing mode and duration of a new easing state. The example above is
335  *   equivalent to the following code:</para>
336  *   <informalexample><programlisting>
337  * clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC);
338  * clutter_actor_set_easing_duration (actor, 250);
339  * clutter_actor_set_position (actor, 200, 200);
340  * clutter_actor_restore_easing_state (actor);
341  *   </programlisting></informalexample>
342  *   <para>It is possible to nest easing states to tween animatable
343  *   properties using different modes and durations, for instance:</para>
344  *   <informalexample><programlisting>
345  * clutter_actor_save_easing_state (actor); /&ast; outer state &ast;/
346  *
347  * /&ast; set the duration of the animation to 2 seconds and change position &ast;/
348  * clutter_actor_set_easing_duration (actor, 2000);
349  * clutter_actor_set_position (actor, 0, 0);
350  *
351  * clutter_actor_save_easing_state (actor); /&ast; inner state &ast;/
352  *
353  * /&ast; set the duration of the animation to 5 seconds and change depth and opacity &ast;/
354  * clutter_actor_set_easing_duration (actor, 5000);
355  * clutter_actor_set_depth (actor, 200);
356  * clutter_actor_set_opacity (actor, 0);
357  *
358  * clutter_actor_restore_easing_state (actor);
359  *
360  * clutter_actor_restore_easing_state (actor);
361  *   </programlisting></informalexample>
362  * </refsect2>
363  */
364
365 /**
366  * CLUTTER_ACTOR_IS_MAPPED:
367  * @a: a #ClutterActor
368  *
369  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
370  *
371  * The mapped state is set when the actor is visible and all its parents up
372  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
373  *
374  * This check can be used to see if an actor is going to be painted, as only
375  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
376  *
377  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
378  * not be checked directly; instead, the recommended usage is to connect a
379  * handler on the #GObject::notify signal for the #ClutterActor:mapped
380  * property of #ClutterActor, and check the presence of
381  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
382  *
383  * It is also important to note that Clutter may delay the changes of
384  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
385  * limitations, or during the reparenting of an actor, to optimize
386  * unnecessary (and potentially expensive) state changes.
387  *
388  * Since: 0.2
389  */
390
391 /**
392  * CLUTTER_ACTOR_IS_REALIZED:
393  * @a: a #ClutterActor
394  *
395  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
396  *
397  * The realized state has an actor-dependant interpretation. If an
398  * actor wants to delay allocating resources until it is attached to a
399  * stage, it may use the realize state to do so. However it is
400  * perfectly acceptable for an actor to allocate Cogl resources before
401  * being realized because there is only one drawing context used by Clutter
402  * so any resources will work on any stage.  If an actor is mapped it
403  * must also be realized, but an actor can be realized and unmapped
404  * (this is so hiding an actor temporarily doesn't do an expensive
405  * unrealize/realize).
406  *
407  * To be realized an actor must be inside a stage, and all its parents
408  * must be realized.
409  *
410  * Since: 0.2
411  */
412
413 /**
414  * CLUTTER_ACTOR_IS_VISIBLE:
415  * @a: a #ClutterActor
416  *
417  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
418  * Equivalent to the ClutterActor::visible object property.
419  *
420  * Note that an actor is only painted onscreen if it's mapped, which
421  * means it's visible, and all its parents are visible, and one of the
422  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
423  *
424  * Since: 0.2
425  */
426
427 /**
428  * CLUTTER_ACTOR_IS_REACTIVE:
429  * @a: a #ClutterActor
430  *
431  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
432  *
433  * Only reactive actors will receive event-related signals.
434  *
435  * Since: 0.6
436  */
437
438 #ifdef HAVE_CONFIG_H
439 #include "config.h"
440 #endif
441
442 #include <math.h>
443
444 #include <gobject/gvaluecollector.h>
445
446 #include <cogl/cogl.h>
447
448 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
449 #define CLUTTER_ENABLE_EXPERIMENTAL_API
450
451 #include "clutter-actor-private.h"
452
453 #include "clutter-action.h"
454 #include "clutter-actor-meta-private.h"
455 #include "clutter-animatable.h"
456 #include "clutter-color-static.h"
457 #include "clutter-color.h"
458 #include "clutter-constraint.h"
459 #include "clutter-container.h"
460 #include "clutter-content-private.h"
461 #include "clutter-debug.h"
462 #include "clutter-effect-private.h"
463 #include "clutter-enum-types.h"
464 #include "clutter-fixed-layout.h"
465 #include "clutter-flatten-effect.h"
466 #include "clutter-interval.h"
467 #include "clutter-main.h"
468 #include "clutter-marshal.h"
469 #include "clutter-paint-nodes.h"
470 #include "clutter-paint-node-private.h"
471 #include "clutter-paint-volume-private.h"
472 #include "clutter-private.h"
473 #include "clutter-profile.h"
474 #include "clutter-property-transition.h"
475 #include "clutter-scriptable.h"
476 #include "clutter-script-private.h"
477 #include "clutter-stage-private.h"
478 #include "clutter-timeline.h"
479 #include "clutter-transition.h"
480 #include "clutter-units.h"
481
482 #include "deprecated/clutter-actor.h"
483 #include "deprecated/clutter-behaviour.h"
484 #include "deprecated/clutter-container.h"
485
486 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
487 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
488
489 /* Internal enum used to control mapped state update.  This is a hint
490  * which indicates when to do something other than just enforce
491  * invariants.
492  */
493 typedef enum {
494   MAP_STATE_CHECK,           /* just enforce invariants. */
495   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
496                               * used when about to unparent.
497                               */
498   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
499                               * used to set mapped on toplevels.
500                               */
501   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
502                               * used just before unmapping parent.
503                               */
504 } MapStateChange;
505
506 /* 3 entries should be a good compromise, few layout managers
507  * will ask for 3 different preferred size in each allocation cycle */
508 #define N_CACHED_SIZE_REQUESTS 3
509
510 struct _ClutterActorPrivate
511 {
512   /* request mode */
513   ClutterRequestMode request_mode;
514
515   /* our cached size requests for different width / height */
516   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
517   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
518
519   /* An age of 0 means the entry is not set */
520   guint cached_height_age;
521   guint cached_width_age;
522
523   /* the bounding box of the actor, relative to the parent's
524    * allocation
525    */
526   ClutterActorBox allocation;
527   ClutterAllocationFlags allocation_flags;
528
529   /* clip, in actor coordinates */
530   cairo_rectangle_t clip;
531
532   /* the cached transformation matrix; see apply_transform() */
533   CoglMatrix transform;
534
535   guint8 opacity;
536   gint opacity_override;
537
538   ClutterOffscreenRedirect offscreen_redirect;
539
540   /* This is an internal effect used to implement the
541      offscreen-redirect property */
542   ClutterEffect *flatten_effect;
543
544   /* scene graph */
545   ClutterActor *parent;
546   ClutterActor *prev_sibling;
547   ClutterActor *next_sibling;
548   ClutterActor *first_child;
549   ClutterActor *last_child;
550
551   gint n_children;
552
553   /* tracks whenever the children of an actor are changed; the
554    * age is incremented by 1 whenever an actor is added or
555    * removed. the age is not incremented when the first or the
556    * last child pointers are changed, or when grandchildren of
557    * an actor are changed.
558    */
559   gint age;
560
561   gchar *name; /* a non-unique name, used for debugging */
562   guint32 id; /* unique id, used for backward compatibility */
563
564   gint32 pick_id; /* per-stage unique id, used for picking */
565
566   /* a back-pointer to the Pango context that we can use
567    * to create pre-configured PangoLayout
568    */
569   PangoContext *pango_context;
570
571   /* the text direction configured for this child - either by
572    * application code, or by the actor's parent
573    */
574   ClutterTextDirection text_direction;
575
576   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
577   gint internal_child;
578
579   /* meta classes */
580   ClutterMetaGroup *actions;
581   ClutterMetaGroup *constraints;
582   ClutterMetaGroup *effects;
583
584   /* delegate object used to allocate the children of this actor */
585   ClutterLayoutManager *layout_manager;
586
587   /* delegate object used to paint the contents of this actor */
588   ClutterContent *content;
589
590   ClutterContentGravity content_gravity;
591
592   /* used when painting, to update the paint volume */
593   ClutterEffect *current_effect;
594
595   /* This is used to store an effect which needs to be redrawn. A
596      redraw can be queued to start from a particular effect. This is
597      used by parametrised effects that can cache an image of the
598      actor. If a parameter of the effect changes then it only needs to
599      redraw the cached image, not the actual actor. The pointer is
600      only valid if is_dirty == TRUE. If the pointer is NULL then the
601      whole actor is dirty. */
602   ClutterEffect *effect_to_redraw;
603
604   /* This is used when painting effects to implement the
605      clutter_actor_continue_paint() function. It points to the node in
606      the list of effects that is next in the chain */
607   const GList *next_effect_to_paint;
608
609   ClutterPaintVolume paint_volume;
610
611   /* NB: This volume isn't relative to this actor, it is in eye
612    * coordinates so that it can remain valid after the actor changes.
613    */
614   ClutterPaintVolume last_paint_volume;
615
616   ClutterStageQueueRedrawEntry *queue_redraw_entry;
617
618   ClutterColor bg_color;
619
620   /* bitfields */
621
622   /* fixed position and sizes */
623   guint position_set                : 1;
624   guint min_width_set               : 1;
625   guint min_height_set              : 1;
626   guint natural_width_set           : 1;
627   guint natural_height_set          : 1;
628   /* cached request is invalid (implies allocation is too) */
629   guint needs_width_request         : 1;
630   /* cached request is invalid (implies allocation is too) */
631   guint needs_height_request        : 1;
632   /* cached allocation is invalid (request has changed, probably) */
633   guint needs_allocation            : 1;
634   guint show_on_set_parent          : 1;
635   guint has_clip                    : 1;
636   guint clip_to_allocation          : 1;
637   guint enable_model_view_transform : 1;
638   guint enable_paint_unmapped       : 1;
639   guint has_pointer                 : 1;
640   guint propagated_one_redraw       : 1;
641   guint paint_volume_valid          : 1;
642   guint last_paint_volume_valid     : 1;
643   guint in_clone_paint              : 1;
644   guint transform_valid             : 1;
645   /* This is TRUE if anything has queued a redraw since we were last
646      painted. In this case effect_to_redraw will point to an effect
647      the redraw was queued from or it will be NULL if the redraw was
648      queued without an effect. */
649   guint is_dirty                    : 1;
650   guint bg_color_set                : 1;
651 };
652
653 enum
654 {
655   PROP_0,
656
657   PROP_NAME,
658
659   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
660    * when set they force a size request, when gotten they
661    * get the allocation if the allocation is valid, and the
662    * request otherwise
663    */
664   PROP_X,
665   PROP_Y,
666   PROP_WIDTH,
667   PROP_HEIGHT,
668
669   /* Then the rest of these size-related properties are the "actual"
670    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
671    */
672   PROP_FIXED_X,
673   PROP_FIXED_Y,
674
675   PROP_FIXED_POSITION_SET,
676
677   PROP_MIN_WIDTH,
678   PROP_MIN_WIDTH_SET,
679
680   PROP_MIN_HEIGHT,
681   PROP_MIN_HEIGHT_SET,
682
683   PROP_NATURAL_WIDTH,
684   PROP_NATURAL_WIDTH_SET,
685
686   PROP_NATURAL_HEIGHT,
687   PROP_NATURAL_HEIGHT_SET,
688
689   PROP_REQUEST_MODE,
690
691   /* Allocation properties are read-only */
692   PROP_ALLOCATION,
693
694   PROP_DEPTH,
695
696   PROP_CLIP,
697   PROP_HAS_CLIP,
698   PROP_CLIP_TO_ALLOCATION,
699
700   PROP_OPACITY,
701
702   PROP_OFFSCREEN_REDIRECT,
703
704   PROP_VISIBLE,
705   PROP_MAPPED,
706   PROP_REALIZED,
707   PROP_REACTIVE,
708
709   PROP_SCALE_X,
710   PROP_SCALE_Y,
711   PROP_SCALE_CENTER_X,
712   PROP_SCALE_CENTER_Y,
713   PROP_SCALE_GRAVITY,
714
715   PROP_ROTATION_ANGLE_X,
716   PROP_ROTATION_ANGLE_Y,
717   PROP_ROTATION_ANGLE_Z,
718   PROP_ROTATION_CENTER_X,
719   PROP_ROTATION_CENTER_Y,
720   PROP_ROTATION_CENTER_Z,
721   /* This property only makes sense for the z rotation because the
722      others would depend on the actor having a size along the
723      z-axis */
724   PROP_ROTATION_CENTER_Z_GRAVITY,
725
726   PROP_ANCHOR_X,
727   PROP_ANCHOR_Y,
728   PROP_ANCHOR_GRAVITY,
729
730   PROP_SHOW_ON_SET_PARENT,
731
732   PROP_TEXT_DIRECTION,
733   PROP_HAS_POINTER,
734
735   PROP_ACTIONS,
736   PROP_CONSTRAINTS,
737   PROP_EFFECT,
738
739   PROP_LAYOUT_MANAGER,
740
741   PROP_X_ALIGN,
742   PROP_Y_ALIGN,
743   PROP_MARGIN_TOP,
744   PROP_MARGIN_BOTTOM,
745   PROP_MARGIN_LEFT,
746   PROP_MARGIN_RIGHT,
747
748   PROP_BACKGROUND_COLOR,
749   PROP_BACKGROUND_COLOR_SET,
750
751   PROP_FIRST_CHILD,
752   PROP_LAST_CHILD,
753
754   PROP_CONTENT,
755   PROP_CONTENT_GRAVITY,
756   PROP_CONTENT_BOX,
757
758   PROP_LAST
759 };
760
761 static GParamSpec *obj_props[PROP_LAST];
762
763 enum
764 {
765   SHOW,
766   HIDE,
767   DESTROY,
768   PARENT_SET,
769   KEY_FOCUS_IN,
770   KEY_FOCUS_OUT,
771   PAINT,
772   PICK,
773   REALIZE,
774   UNREALIZE,
775   QUEUE_REDRAW,
776   QUEUE_RELAYOUT,
777   EVENT,
778   CAPTURED_EVENT,
779   BUTTON_PRESS_EVENT,
780   BUTTON_RELEASE_EVENT,
781   SCROLL_EVENT,
782   KEY_PRESS_EVENT,
783   KEY_RELEASE_EVENT,
784   MOTION_EVENT,
785   ENTER_EVENT,
786   LEAVE_EVENT,
787   ALLOCATION_CHANGED,
788
789   LAST_SIGNAL
790 };
791
792 static guint actor_signals[LAST_SIGNAL] = { 0, };
793
794 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
795 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
796 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
797 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
798
799 /* These setters are all static for now, maybe they should be in the
800  * public API, but they are perhaps obscure enough to leave only as
801  * properties
802  */
803 static void clutter_actor_set_min_width          (ClutterActor *self,
804                                                   gfloat        min_width);
805 static void clutter_actor_set_min_height         (ClutterActor *self,
806                                                   gfloat        min_height);
807 static void clutter_actor_set_natural_width      (ClutterActor *self,
808                                                   gfloat        natural_width);
809 static void clutter_actor_set_natural_height     (ClutterActor *self,
810                                                   gfloat        natural_height);
811 static void clutter_actor_set_min_width_set      (ClutterActor *self,
812                                                   gboolean      use_min_width);
813 static void clutter_actor_set_min_height_set     (ClutterActor *self,
814                                                   gboolean      use_min_height);
815 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
816                                                   gboolean  use_natural_width);
817 static void clutter_actor_set_natural_height_set (ClutterActor *self,
818                                                   gboolean  use_natural_height);
819 static void clutter_actor_update_map_state       (ClutterActor  *self,
820                                                   MapStateChange change);
821 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
822
823 /* Helper routines for managing anchor coords */
824 static void clutter_anchor_coord_get_units (ClutterActor      *self,
825                                             const AnchorCoord *coord,
826                                             gfloat            *x,
827                                             gfloat            *y,
828                                             gfloat            *z);
829 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
830                                             gfloat             x,
831                                             gfloat             y,
832                                             gfloat             z);
833
834 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
835 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
836                                                         ClutterGravity     gravity);
837
838 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
839
840 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
841
842 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
843                                                                ClutterActor *ancestor,
844                                                                CoglMatrix *matrix);
845
846 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
847
848 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
849
850 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
851                                                                 const ClutterColor *color);
852
853 static void on_layout_manager_changed (ClutterLayoutManager *manager,
854                                        ClutterActor         *self);
855
856 /* Helper macro which translates by the anchor coord, applies the
857    given transformation and then translates back */
858 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
859   gfloat _tx, _ty, _tz;                                                \
860   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
861   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
862   { _transform; }                                                      \
863   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
864
865 static GQuark quark_shader_data = 0;
866 static GQuark quark_actor_layout_info = 0;
867 static GQuark quark_actor_transform_info = 0;
868 static GQuark quark_actor_animation_info = 0;
869
870 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
871                          clutter_actor,
872                          G_TYPE_INITIALLY_UNOWNED,
873                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
874                                                 clutter_container_iface_init)
875                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
876                                                 clutter_scriptable_iface_init)
877                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
878                                                 clutter_animatable_iface_init)
879                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
880                                                 atk_implementor_iface_init));
881
882 /*< private >
883  * clutter_actor_get_debug_name:
884  * @actor: a #ClutterActor
885  *
886  * Retrieves a printable name of @actor for debugging messages
887  *
888  * Return value: a string with a printable name
889  */
890 const gchar *
891 _clutter_actor_get_debug_name (ClutterActor *actor)
892 {
893   return actor->priv->name != NULL ? actor->priv->name
894                                    : G_OBJECT_TYPE_NAME (actor);
895 }
896
897 #ifdef CLUTTER_ENABLE_DEBUG
898 /* XXX - this is for debugging only, remove once working (or leave
899  * in only in some debug mode). Should leave it for a little while
900  * until we're confident in the new map/realize/visible handling.
901  */
902 static inline void
903 clutter_actor_verify_map_state (ClutterActor *self)
904 {
905   ClutterActorPrivate *priv = self->priv;
906
907   if (CLUTTER_ACTOR_IS_REALIZED (self))
908     {
909       /* all bets are off during reparent when we're potentially realized,
910        * but should not be according to invariants
911        */
912       if (!CLUTTER_ACTOR_IN_REPARENT (self))
913         {
914           if (priv->parent == NULL)
915             {
916               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
917                 {
918                 }
919               else
920                 g_warning ("Realized non-toplevel actor '%s' should "
921                            "have a parent",
922                            _clutter_actor_get_debug_name (self));
923             }
924           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
925             {
926               g_warning ("Realized actor %s has an unrealized parent %s",
927                          _clutter_actor_get_debug_name (self),
928                          _clutter_actor_get_debug_name (priv->parent));
929             }
930         }
931     }
932
933   if (CLUTTER_ACTOR_IS_MAPPED (self))
934     {
935       if (!CLUTTER_ACTOR_IS_REALIZED (self))
936         g_warning ("Actor '%s' is mapped but not realized",
937                    _clutter_actor_get_debug_name (self));
938
939       /* remaining bets are off during reparent when we're potentially
940        * mapped, but should not be according to invariants
941        */
942       if (!CLUTTER_ACTOR_IN_REPARENT (self))
943         {
944           if (priv->parent == NULL)
945             {
946               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
947                 {
948                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
949                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
950                     {
951                       g_warning ("Toplevel actor '%s' is mapped "
952                                  "but not visible",
953                                  _clutter_actor_get_debug_name (self));
954                     }
955                 }
956               else
957                 {
958                   g_warning ("Mapped actor '%s' should have a parent",
959                              _clutter_actor_get_debug_name (self));
960                 }
961             }
962           else
963             {
964               ClutterActor *iter = self;
965
966               /* check for the enable_paint_unmapped flag on the actor
967                * and parents; if the flag is enabled at any point of this
968                * branch of the scene graph then all the later checks
969                * become pointless
970                */
971               while (iter != NULL)
972                 {
973                   if (iter->priv->enable_paint_unmapped)
974                     return;
975
976                   iter = iter->priv->parent;
977                 }
978
979               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
980                 {
981                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
982                              "is not visible",
983                              _clutter_actor_get_debug_name (self),
984                              _clutter_actor_get_debug_name (priv->parent));
985                 }
986
987               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
988                 {
989                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
990                              "is not realized",
991                              _clutter_actor_get_debug_name (self),
992                              _clutter_actor_get_debug_name (priv->parent));
993                 }
994
995               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
996                 {
997                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
998                     g_warning ("Actor '%s' is mapped but its non-toplevel "
999                                "parent '%s' is not mapped",
1000                                _clutter_actor_get_debug_name (self),
1001                                _clutter_actor_get_debug_name (priv->parent));
1002                 }
1003             }
1004         }
1005     }
1006 }
1007
1008 #endif /* CLUTTER_ENABLE_DEBUG */
1009
1010 static void
1011 clutter_actor_set_mapped (ClutterActor *self,
1012                           gboolean      mapped)
1013 {
1014   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1015     return;
1016
1017   if (mapped)
1018     {
1019       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1020       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1021     }
1022   else
1023     {
1024       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1025       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1026     }
1027 }
1028
1029 /* this function updates the mapped and realized states according to
1030  * invariants, in the appropriate order.
1031  */
1032 static void
1033 clutter_actor_update_map_state (ClutterActor  *self,
1034                                 MapStateChange change)
1035 {
1036   gboolean was_mapped;
1037
1038   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1039
1040   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1041     {
1042       /* the mapped flag on top-level actors must be set by the
1043        * per-backend implementation because it might be asynchronous.
1044        *
1045        * That is, the MAPPED flag on toplevels currently tracks the X
1046        * server mapped-ness of the window, while the expected behavior
1047        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1048        * This creates some weird complexity by breaking the invariant
1049        * that if we're visible and all ancestors shown then we are
1050        * also mapped - instead, we are mapped if all ancestors
1051        * _possibly excepting_ the stage are mapped. The stage
1052        * will map/unmap for example when it is minimized or
1053        * moved to another workspace.
1054        *
1055        * So, the only invariant on the stage is that if visible it
1056        * should be realized, and that it has to be visible to be
1057        * mapped.
1058        */
1059       if (CLUTTER_ACTOR_IS_VISIBLE (self))
1060         clutter_actor_realize (self);
1061
1062       switch (change)
1063         {
1064         case MAP_STATE_CHECK:
1065           break;
1066
1067         case MAP_STATE_MAKE_MAPPED:
1068           g_assert (!was_mapped);
1069           clutter_actor_set_mapped (self, TRUE);
1070           break;
1071
1072         case MAP_STATE_MAKE_UNMAPPED:
1073           g_assert (was_mapped);
1074           clutter_actor_set_mapped (self, FALSE);
1075           break;
1076
1077         case MAP_STATE_MAKE_UNREALIZED:
1078           /* we only use MAKE_UNREALIZED in unparent,
1079            * and unparenting a stage isn't possible.
1080            * If someone wants to just unrealize a stage
1081            * then clutter_actor_unrealize() doesn't
1082            * go through this codepath.
1083            */
1084           g_warning ("Trying to force unrealize stage is not allowed");
1085           break;
1086         }
1087
1088       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1089           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1090           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1091         {
1092           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1093                      "it is somehow still mapped",
1094                      _clutter_actor_get_debug_name (self));
1095         }
1096     }
1097   else
1098     {
1099       ClutterActorPrivate *priv = self->priv;
1100       ClutterActor *parent = priv->parent;
1101       gboolean should_be_mapped;
1102       gboolean may_be_realized;
1103       gboolean must_be_realized;
1104
1105       should_be_mapped = FALSE;
1106       may_be_realized = TRUE;
1107       must_be_realized = FALSE;
1108
1109       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1110         {
1111           may_be_realized = FALSE;
1112         }
1113       else
1114         {
1115           /* Maintain invariant that if parent is mapped, and we are
1116            * visible, then we are mapped ...  unless parent is a
1117            * stage, in which case we map regardless of parent's map
1118            * state but do require stage to be visible and realized.
1119            *
1120            * If parent is realized, that does not force us to be
1121            * realized; but if parent is unrealized, that does force
1122            * us to be unrealized.
1123            *
1124            * The reason we don't force children to realize with
1125            * parents is _clutter_actor_rerealize(); if we require that
1126            * a realized parent means children are realized, then to
1127            * unrealize an actor we would have to unrealize its
1128            * parents, which would end up meaning unrealizing and
1129            * hiding the entire stage. So we allow unrealizing a
1130            * child (as long as that child is not mapped) while that
1131            * child still has a realized parent.
1132            *
1133            * Also, if we unrealize from leaf nodes to root, and
1134            * realize from root to leaf, the invariants are never
1135            * violated if we allow children to be unrealized
1136            * while parents are realized.
1137            *
1138            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1139            * to force us to unmap, even though parent is still
1140            * mapped. This is because we're unmapping from leaf nodes
1141            * up to root nodes.
1142            */
1143           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1144               change != MAP_STATE_MAKE_UNMAPPED)
1145             {
1146               gboolean parent_is_visible_realized_toplevel;
1147
1148               parent_is_visible_realized_toplevel =
1149                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1150                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1151                  CLUTTER_ACTOR_IS_REALIZED (parent));
1152
1153               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1154                   parent_is_visible_realized_toplevel)
1155                 {
1156                   must_be_realized = TRUE;
1157                   should_be_mapped = TRUE;
1158                 }
1159             }
1160
1161           /* if the actor has been set to be painted even if unmapped
1162            * then we should map it and check for realization as well;
1163            * this is an override for the branch of the scene graph
1164            * which begins with this node
1165            */
1166           if (priv->enable_paint_unmapped)
1167             {
1168               if (priv->parent == NULL)
1169                 g_warning ("Attempting to map an unparented actor '%s'",
1170                            _clutter_actor_get_debug_name (self));
1171
1172               should_be_mapped = TRUE;
1173               must_be_realized = TRUE;
1174             }
1175
1176           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1177             may_be_realized = FALSE;
1178         }
1179
1180       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1181         {
1182           if (parent == NULL)
1183             g_warning ("Attempting to map a child that does not "
1184                        "meet the necessary invariants: the actor '%s' "
1185                        "has no parent",
1186                        _clutter_actor_get_debug_name (self));
1187           else
1188             g_warning ("Attempting to map a child that does not "
1189                        "meet the necessary invariants: the actor '%s' "
1190                        "is parented to an unmapped actor '%s'",
1191                        _clutter_actor_get_debug_name (self),
1192                        _clutter_actor_get_debug_name (priv->parent));
1193         }
1194
1195       /* If in reparent, we temporarily suspend unmap and unrealize.
1196        *
1197        * We want to go in the order "realize, map" and "unmap, unrealize"
1198        */
1199
1200       /* Unmap */
1201       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1202         clutter_actor_set_mapped (self, FALSE);
1203
1204       /* Realize */
1205       if (must_be_realized)
1206         clutter_actor_realize (self);
1207
1208       /* if we must be realized then we may be, presumably */
1209       g_assert (!(must_be_realized && !may_be_realized));
1210
1211       /* Unrealize */
1212       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1213         clutter_actor_unrealize_not_hiding (self);
1214
1215       /* Map */
1216       if (should_be_mapped)
1217         {
1218           if (!must_be_realized)
1219             g_warning ("Somehow we think actor '%s' should be mapped but "
1220                        "not realized, which isn't allowed",
1221                        _clutter_actor_get_debug_name (self));
1222
1223           /* realization is allowed to fail (though I don't know what
1224            * an app is supposed to do about that - shouldn't it just
1225            * be a g_error? anyway, we have to avoid mapping if this
1226            * happens)
1227            */
1228           if (CLUTTER_ACTOR_IS_REALIZED (self))
1229             clutter_actor_set_mapped (self, TRUE);
1230         }
1231     }
1232
1233 #ifdef CLUTTER_ENABLE_DEBUG
1234   /* check all invariants were kept */
1235   clutter_actor_verify_map_state (self);
1236 #endif
1237 }
1238
1239 static void
1240 clutter_actor_real_map (ClutterActor *self)
1241 {
1242   ClutterActorPrivate *priv = self->priv;
1243   ClutterActor *stage, *iter;
1244
1245   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1246
1247   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1248                 _clutter_actor_get_debug_name (self));
1249
1250   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1251
1252   stage = _clutter_actor_get_stage_internal (self);
1253   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1254
1255   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1256                 priv->pick_id,
1257                 _clutter_actor_get_debug_name (self));
1258
1259   /* notify on parent mapped before potentially mapping
1260    * children, so apps see a top-down notification.
1261    */
1262   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1263
1264   for (iter = self->priv->first_child;
1265        iter != NULL;
1266        iter = iter->priv->next_sibling)
1267     {
1268       clutter_actor_map (iter);
1269     }
1270 }
1271
1272 /**
1273  * clutter_actor_map:
1274  * @self: A #ClutterActor
1275  *
1276  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1277  * and realizes its children if they are visible. Does nothing if the
1278  * actor is not visible.
1279  *
1280  * Calling this function is strongly disencouraged: the default
1281  * implementation of #ClutterActorClass.map() will map all the children
1282  * of an actor when mapping its parent.
1283  *
1284  * When overriding map, it is mandatory to chain up to the parent
1285  * implementation.
1286  *
1287  * Since: 1.0
1288  */
1289 void
1290 clutter_actor_map (ClutterActor *self)
1291 {
1292   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1293
1294   if (CLUTTER_ACTOR_IS_MAPPED (self))
1295     return;
1296
1297   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1298     return;
1299
1300   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1301 }
1302
1303 static void
1304 clutter_actor_real_unmap (ClutterActor *self)
1305 {
1306   ClutterActorPrivate *priv = self->priv;
1307   ClutterActor *iter;
1308
1309   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1310
1311   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1312                 _clutter_actor_get_debug_name (self));
1313
1314   for (iter = self->priv->first_child;
1315        iter != NULL;
1316        iter = iter->priv->next_sibling)
1317     {
1318       clutter_actor_unmap (iter);
1319     }
1320
1321   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1322
1323   /* clear the contents of the last paint volume, so that hiding + moving +
1324    * showing will not result in the wrong area being repainted
1325    */
1326   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1327   priv->last_paint_volume_valid = TRUE;
1328
1329   /* notify on parent mapped after potentially unmapping
1330    * children, so apps see a bottom-up notification.
1331    */
1332   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1333
1334   /* relinquish keyboard focus if we were unmapped while owning it */
1335   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1336     {
1337       ClutterStage *stage;
1338
1339       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1340
1341       if (stage != NULL)
1342         _clutter_stage_release_pick_id (stage, priv->pick_id);
1343
1344       priv->pick_id = -1;
1345
1346       if (stage != NULL &&
1347           clutter_stage_get_key_focus (stage) == self)
1348         {
1349           clutter_stage_set_key_focus (stage, NULL);
1350         }
1351     }
1352 }
1353
1354 /**
1355  * clutter_actor_unmap:
1356  * @self: A #ClutterActor
1357  *
1358  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1359  * unmaps its children if they were mapped.
1360  *
1361  * Calling this function is not encouraged: the default #ClutterActor
1362  * implementation of #ClutterActorClass.unmap() will also unmap any
1363  * eventual children by default when their parent is unmapped.
1364  *
1365  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1366  * chain up to the parent implementation.
1367  *
1368  * <note>It is important to note that the implementation of the
1369  * #ClutterActorClass.unmap() virtual function may be called after
1370  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1371  * implementation, but it is guaranteed to be called before the
1372  * #GObjectClass.finalize() implementation.</note>
1373  *
1374  * Since: 1.0
1375  */
1376 void
1377 clutter_actor_unmap (ClutterActor *self)
1378 {
1379   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1380
1381   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1382     return;
1383
1384   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1385 }
1386
1387 static void
1388 clutter_actor_real_show (ClutterActor *self)
1389 {
1390   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1391     {
1392       ClutterActorPrivate *priv = self->priv;
1393
1394       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1395
1396       /* we notify on the "visible" flag in the clutter_actor_show()
1397        * wrapper so the entire show signal emission completes first
1398        * (?)
1399        */
1400       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1401
1402       /* we queue a relayout unless the actor is inside a
1403        * container that explicitly told us not to
1404        */
1405       if (priv->parent != NULL &&
1406           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1407         {
1408           /* While an actor is hidden the parent may not have
1409            * allocated/requested so we need to start from scratch
1410            * and avoid the short-circuiting in
1411            * clutter_actor_queue_relayout().
1412            */
1413           priv->needs_width_request  = FALSE;
1414           priv->needs_height_request = FALSE;
1415           priv->needs_allocation     = FALSE;
1416           clutter_actor_queue_relayout (self);
1417         }
1418     }
1419 }
1420
1421 static inline void
1422 set_show_on_set_parent (ClutterActor *self,
1423                         gboolean      set_show)
1424 {
1425   ClutterActorPrivate *priv = self->priv;
1426
1427   set_show = !!set_show;
1428
1429   if (priv->show_on_set_parent == set_show)
1430     return;
1431
1432   if (priv->parent == NULL)
1433     {
1434       priv->show_on_set_parent = set_show;
1435       g_object_notify_by_pspec (G_OBJECT (self),
1436                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1437     }
1438 }
1439
1440 /**
1441  * clutter_actor_show:
1442  * @self: A #ClutterActor
1443  *
1444  * Flags an actor to be displayed. An actor that isn't shown will not
1445  * be rendered on the stage.
1446  *
1447  * Actors are visible by default.
1448  *
1449  * If this function is called on an actor without a parent, the
1450  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1451  * effect.
1452  */
1453 void
1454 clutter_actor_show (ClutterActor *self)
1455 {
1456   ClutterActorPrivate *priv;
1457
1458   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1459
1460   /* simple optimization */
1461   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1462     {
1463       /* we still need to set the :show-on-set-parent property, in
1464        * case show() is called on an unparented actor
1465        */
1466       set_show_on_set_parent (self, TRUE);
1467       return;
1468     }
1469
1470 #ifdef CLUTTER_ENABLE_DEBUG
1471   clutter_actor_verify_map_state (self);
1472 #endif
1473
1474   priv = self->priv;
1475
1476   g_object_freeze_notify (G_OBJECT (self));
1477
1478   set_show_on_set_parent (self, TRUE);
1479
1480   g_signal_emit (self, actor_signals[SHOW], 0);
1481   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1482
1483   if (priv->parent != NULL)
1484     clutter_actor_queue_redraw (priv->parent);
1485
1486   g_object_thaw_notify (G_OBJECT (self));
1487 }
1488
1489 /**
1490  * clutter_actor_show_all:
1491  * @self: a #ClutterActor
1492  *
1493  * Calls clutter_actor_show() on all children of an actor (if any).
1494  *
1495  * Since: 0.2
1496  *
1497  * Deprecated: 1.10: Actors are visible by default
1498  */
1499 void
1500 clutter_actor_show_all (ClutterActor *self)
1501 {
1502   ClutterActorClass *klass;
1503
1504   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1505
1506   klass = CLUTTER_ACTOR_GET_CLASS (self);
1507   if (klass->show_all)
1508     klass->show_all (self);
1509 }
1510
1511 static void
1512 clutter_actor_real_hide (ClutterActor *self)
1513 {
1514   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1515     {
1516       ClutterActorPrivate *priv = self->priv;
1517
1518       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1519
1520       /* we notify on the "visible" flag in the clutter_actor_hide()
1521        * wrapper so the entire hide signal emission completes first
1522        * (?)
1523        */
1524       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1525
1526       /* we queue a relayout unless the actor is inside a
1527        * container that explicitly told us not to
1528        */
1529       if (priv->parent != NULL &&
1530           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1531         clutter_actor_queue_relayout (priv->parent);
1532     }
1533 }
1534
1535 /**
1536  * clutter_actor_hide:
1537  * @self: A #ClutterActor
1538  *
1539  * Flags an actor to be hidden. A hidden actor will not be
1540  * rendered on the stage.
1541  *
1542  * Actors are visible by default.
1543  *
1544  * If this function is called on an actor without a parent, the
1545  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1546  * as a side-effect.
1547  */
1548 void
1549 clutter_actor_hide (ClutterActor *self)
1550 {
1551   ClutterActorPrivate *priv;
1552
1553   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1554
1555   /* simple optimization */
1556   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1557     {
1558       /* we still need to set the :show-on-set-parent property, in
1559        * case hide() is called on an unparented actor
1560        */
1561       set_show_on_set_parent (self, FALSE);
1562       return;
1563     }
1564
1565 #ifdef CLUTTER_ENABLE_DEBUG
1566   clutter_actor_verify_map_state (self);
1567 #endif
1568
1569   priv = self->priv;
1570
1571   g_object_freeze_notify (G_OBJECT (self));
1572
1573   set_show_on_set_parent (self, FALSE);
1574
1575   g_signal_emit (self, actor_signals[HIDE], 0);
1576   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1577
1578   if (priv->parent != NULL)
1579     clutter_actor_queue_redraw (priv->parent);
1580
1581   g_object_thaw_notify (G_OBJECT (self));
1582 }
1583
1584 /**
1585  * clutter_actor_hide_all:
1586  * @self: a #ClutterActor
1587  *
1588  * Calls clutter_actor_hide() on all child actors (if any).
1589  *
1590  * Since: 0.2
1591  *
1592  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1593  *   prevent its children from being painted as well.
1594  */
1595 void
1596 clutter_actor_hide_all (ClutterActor *self)
1597 {
1598   ClutterActorClass *klass;
1599
1600   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1601
1602   klass = CLUTTER_ACTOR_GET_CLASS (self);
1603   if (klass->hide_all)
1604     klass->hide_all (self);
1605 }
1606
1607 /**
1608  * clutter_actor_realize:
1609  * @self: A #ClutterActor
1610  *
1611  * Realization informs the actor that it is attached to a stage. It
1612  * can use this to allocate resources if it wanted to delay allocation
1613  * until it would be rendered. However it is perfectly acceptable for
1614  * an actor to create resources before being realized because Clutter
1615  * only ever has a single rendering context so that actor is free to
1616  * be moved from one stage to another.
1617  *
1618  * This function does nothing if the actor is already realized.
1619  *
1620  * Because a realized actor must have realized parent actors, calling
1621  * clutter_actor_realize() will also realize all parents of the actor.
1622  *
1623  * This function does not realize child actors, except in the special
1624  * case that realizing the stage, when the stage is visible, will
1625  * suddenly map (and thus realize) the children of the stage.
1626  **/
1627 void
1628 clutter_actor_realize (ClutterActor *self)
1629 {
1630   ClutterActorPrivate *priv;
1631
1632   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1633
1634   priv = self->priv;
1635
1636 #ifdef CLUTTER_ENABLE_DEBUG
1637   clutter_actor_verify_map_state (self);
1638 #endif
1639
1640   if (CLUTTER_ACTOR_IS_REALIZED (self))
1641     return;
1642
1643   /* To be realized, our parent actors must be realized first.
1644    * This will only succeed if we're inside a toplevel.
1645    */
1646   if (priv->parent != NULL)
1647     clutter_actor_realize (priv->parent);
1648
1649   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1650     {
1651       /* toplevels can be realized at any time */
1652     }
1653   else
1654     {
1655       /* "Fail" the realization if parent is missing or unrealized;
1656        * this should really be a g_warning() not some kind of runtime
1657        * failure; how can an app possibly recover? Instead it's a bug
1658        * in the app and the app should get an explanatory warning so
1659        * someone can fix it. But for now it's too hard to fix this
1660        * because e.g. ClutterTexture needs reworking.
1661        */
1662       if (priv->parent == NULL ||
1663           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1664         return;
1665     }
1666
1667   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1668
1669   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1670   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1671
1672   g_signal_emit (self, actor_signals[REALIZE], 0);
1673
1674   /* Stage actor is allowed to unset the realized flag again in its
1675    * default signal handler, though that is a pathological situation.
1676    */
1677
1678   /* If realization "failed" we'll have to update child state. */
1679   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1680 }
1681
1682 static void
1683 clutter_actor_real_unrealize (ClutterActor *self)
1684 {
1685   /* we must be unmapped (implying our children are also unmapped) */
1686   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1687 }
1688
1689 /**
1690  * clutter_actor_unrealize:
1691  * @self: A #ClutterActor
1692  *
1693  * Unrealization informs the actor that it may be being destroyed or
1694  * moved to another stage. The actor may want to destroy any
1695  * underlying graphics resources at this point. However it is
1696  * perfectly acceptable for it to retain the resources until the actor
1697  * is destroyed because Clutter only ever uses a single rendering
1698  * context and all of the graphics resources are valid on any stage.
1699  *
1700  * Because mapped actors must be realized, actors may not be
1701  * unrealized if they are mapped. This function hides the actor to be
1702  * sure it isn't mapped, an application-visible side effect that you
1703  * may not be expecting.
1704  *
1705  * This function should not be called by application code.
1706  */
1707 void
1708 clutter_actor_unrealize (ClutterActor *self)
1709 {
1710   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1711   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1712
1713 /* This function should not really be in the public API, because
1714  * there isn't a good reason to call it. ClutterActor will already
1715  * unrealize things for you when it's important to do so.
1716  *
1717  * If you were using clutter_actor_unrealize() in a dispose
1718  * implementation, then don't, just chain up to ClutterActor's
1719  * dispose.
1720  *
1721  * If you were using clutter_actor_unrealize() to implement
1722  * unrealizing children of your container, then don't, ClutterActor
1723  * will already take care of that.
1724  *
1725  * If you were using clutter_actor_unrealize() to re-realize to
1726  * create your resources in a different way, then use
1727  * _clutter_actor_rerealize() (inside Clutter) or just call your
1728  * code that recreates your resources directly (outside Clutter).
1729  */
1730
1731 #ifdef CLUTTER_ENABLE_DEBUG
1732   clutter_actor_verify_map_state (self);
1733 #endif
1734
1735   clutter_actor_hide (self);
1736
1737   clutter_actor_unrealize_not_hiding (self);
1738 }
1739
1740 static ClutterActorTraverseVisitFlags
1741 unrealize_actor_before_children_cb (ClutterActor *self,
1742                                     int depth,
1743                                     void *user_data)
1744 {
1745   /* If an actor is already unrealized we know its children have also
1746    * already been unrealized... */
1747   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1748     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1749
1750   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1751
1752   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1753 }
1754
1755 static ClutterActorTraverseVisitFlags
1756 unrealize_actor_after_children_cb (ClutterActor *self,
1757                                    int depth,
1758                                    void *user_data)
1759 {
1760   /* We want to unset the realized flag only _after_
1761    * child actors are unrealized, to maintain invariants.
1762    */
1763   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1764   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1765   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1766 }
1767
1768 /*
1769  * clutter_actor_unrealize_not_hiding:
1770  * @self: A #ClutterActor
1771  *
1772  * Unrealization informs the actor that it may be being destroyed or
1773  * moved to another stage. The actor may want to destroy any
1774  * underlying graphics resources at this point. However it is
1775  * perfectly acceptable for it to retain the resources until the actor
1776  * is destroyed because Clutter only ever uses a single rendering
1777  * context and all of the graphics resources are valid on any stage.
1778  *
1779  * Because mapped actors must be realized, actors may not be
1780  * unrealized if they are mapped. You must hide the actor or one of
1781  * its parents before attempting to unrealize.
1782  *
1783  * This function is separate from clutter_actor_unrealize() because it
1784  * does not automatically hide the actor.
1785  * Actors need not be hidden to be unrealized, they just need to
1786  * be unmapped. In fact we don't want to mess up the application's
1787  * setting of the "visible" flag, so hiding is very undesirable.
1788  *
1789  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1790  * backward compatibility.
1791  */
1792 static void
1793 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1794 {
1795   _clutter_actor_traverse (self,
1796                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1797                            unrealize_actor_before_children_cb,
1798                            unrealize_actor_after_children_cb,
1799                            NULL);
1800 }
1801
1802 /*
1803  * _clutter_actor_rerealize:
1804  * @self: A #ClutterActor
1805  * @callback: Function to call while unrealized
1806  * @data: data for callback
1807  *
1808  * If an actor is already unrealized, this just calls the callback.
1809  *
1810  * If it is realized, it unrealizes temporarily, calls the callback,
1811  * and then re-realizes the actor.
1812  *
1813  * As a side effect, leaves all children of the actor unrealized if
1814  * the actor was realized but not showing.  This is because when we
1815  * unrealize the actor temporarily we must unrealize its children
1816  * (e.g. children of a stage can't be realized if stage window is
1817  * gone). And we aren't clever enough to save the realization state of
1818  * all children. In most cases this should not matter, because
1819  * the children will automatically realize when they next become mapped.
1820  */
1821 void
1822 _clutter_actor_rerealize (ClutterActor    *self,
1823                           ClutterCallback  callback,
1824                           void            *data)
1825 {
1826   gboolean was_mapped;
1827   gboolean was_showing;
1828   gboolean was_realized;
1829
1830   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1831
1832 #ifdef CLUTTER_ENABLE_DEBUG
1833   clutter_actor_verify_map_state (self);
1834 #endif
1835
1836   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1837   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1838   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1839
1840   /* Must be unmapped to unrealize. Note we only have to hide this
1841    * actor if it was mapped (if all parents were showing).  If actor
1842    * is merely visible (but not mapped), then that's fine, we can
1843    * leave it visible.
1844    */
1845   if (was_mapped)
1846     clutter_actor_hide (self);
1847
1848   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1849
1850   /* unrealize self and all children */
1851   clutter_actor_unrealize_not_hiding (self);
1852
1853   if (callback != NULL)
1854     {
1855       (* callback) (self, data);
1856     }
1857
1858   if (was_showing)
1859     clutter_actor_show (self); /* will realize only if mapping implies it */
1860   else if (was_realized)
1861     clutter_actor_realize (self); /* realize self and all parents */
1862 }
1863
1864 static void
1865 clutter_actor_real_pick (ClutterActor       *self,
1866                          const ClutterColor *color)
1867 {
1868   /* the default implementation is just to paint a rectangle
1869    * with the same size of the actor using the passed color
1870    */
1871   if (clutter_actor_should_pick_paint (self))
1872     {
1873       ClutterActorBox box = { 0, };
1874       float width, height;
1875
1876       clutter_actor_get_allocation_box (self, &box);
1877
1878       width = box.x2 - box.x1;
1879       height = box.y2 - box.y1;
1880
1881       cogl_set_source_color4ub (color->red,
1882                                 color->green,
1883                                 color->blue,
1884                                 color->alpha);
1885
1886       cogl_rectangle (0, 0, width, height);
1887     }
1888
1889   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1890    * with existing container classes that override the pick() virtual
1891    * and chain up to the default implementation - otherwise we'll end up
1892    * painting our children twice.
1893    *
1894    * this has to go away for 2.0; hopefully along the pick() itself.
1895    */
1896   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1897     {
1898       ClutterActor *iter;
1899
1900       for (iter = self->priv->first_child;
1901            iter != NULL;
1902            iter = iter->priv->next_sibling)
1903         clutter_actor_paint (iter);
1904     }
1905 }
1906
1907 /**
1908  * clutter_actor_should_pick_paint:
1909  * @self: A #ClutterActor
1910  *
1911  * Should be called inside the implementation of the
1912  * #ClutterActor::pick virtual function in order to check whether
1913  * the actor should paint itself in pick mode or not.
1914  *
1915  * This function should never be called directly by applications.
1916  *
1917  * Return value: %TRUE if the actor should paint its silhouette,
1918  *   %FALSE otherwise
1919  */
1920 gboolean
1921 clutter_actor_should_pick_paint (ClutterActor *self)
1922 {
1923   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1924
1925   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1926       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1927        CLUTTER_ACTOR_IS_REACTIVE (self)))
1928     return TRUE;
1929
1930   return FALSE;
1931 }
1932
1933 static void
1934 clutter_actor_real_get_preferred_width (ClutterActor *self,
1935                                         gfloat        for_height,
1936                                         gfloat       *min_width_p,
1937                                         gfloat       *natural_width_p)
1938 {
1939   ClutterActorPrivate *priv = self->priv;
1940
1941   if (priv->n_children != 0 &&
1942       priv->layout_manager != NULL)
1943     {
1944       ClutterContainer *container = CLUTTER_CONTAINER (self);
1945
1946       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1947                     "for the preferred width",
1948                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1949                     priv->layout_manager);
1950
1951       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1952                                                   container,
1953                                                   for_height,
1954                                                   min_width_p,
1955                                                   natural_width_p);
1956
1957       return;
1958     }
1959
1960   /* Default implementation is always 0x0, usually an actor
1961    * using this default is relying on someone to set the
1962    * request manually
1963    */
1964   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1965
1966   if (min_width_p)
1967     *min_width_p = 0;
1968
1969   if (natural_width_p)
1970     *natural_width_p = 0;
1971 }
1972
1973 static void
1974 clutter_actor_real_get_preferred_height (ClutterActor *self,
1975                                          gfloat        for_width,
1976                                          gfloat       *min_height_p,
1977                                          gfloat       *natural_height_p)
1978 {
1979   ClutterActorPrivate *priv = self->priv;
1980
1981   if (priv->n_children != 0 &&
1982       priv->layout_manager != NULL)
1983     {
1984       ClutterContainer *container = CLUTTER_CONTAINER (self);
1985
1986       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1987                     "for the preferred height",
1988                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1989                     priv->layout_manager);
1990
1991       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1992                                                    container,
1993                                                    for_width,
1994                                                    min_height_p,
1995                                                    natural_height_p);
1996
1997       return;
1998     }
1999   /* Default implementation is always 0x0, usually an actor
2000    * using this default is relying on someone to set the
2001    * request manually
2002    */
2003   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2004
2005   if (min_height_p)
2006     *min_height_p = 0;
2007
2008   if (natural_height_p)
2009     *natural_height_p = 0;
2010 }
2011
2012 static void
2013 clutter_actor_store_old_geometry (ClutterActor    *self,
2014                                   ClutterActorBox *box)
2015 {
2016   *box = self->priv->allocation;
2017 }
2018
2019 static inline void
2020 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2021                                           const ClutterActorBox *old)
2022 {
2023   ClutterActorPrivate *priv = self->priv;
2024   GObject *obj = G_OBJECT (self);
2025
2026   g_object_freeze_notify (obj);
2027
2028   /* to avoid excessive requisition or allocation cycles we
2029    * use the cached values.
2030    *
2031    * - if we don't have an allocation we assume that we need
2032    *   to notify anyway
2033    * - if we don't have a width or a height request we notify
2034    *   width and height
2035    * - if we have a valid allocation then we check the old
2036    *   bounding box with the current allocation and we notify
2037    *   the changes
2038    */
2039   if (priv->needs_allocation)
2040     {
2041       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2042       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2043       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2044       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2045     }
2046   else if (priv->needs_width_request || priv->needs_height_request)
2047     {
2048       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2049       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2050     }
2051   else
2052     {
2053       gfloat xu, yu;
2054       gfloat widthu, heightu;
2055
2056       xu = priv->allocation.x1;
2057       yu = priv->allocation.y1;
2058       widthu = priv->allocation.x2 - priv->allocation.x1;
2059       heightu = priv->allocation.y2 - priv->allocation.y1;
2060
2061       if (xu != old->x1)
2062         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2063
2064       if (yu != old->y1)
2065         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2066
2067       if (widthu != (old->x2 - old->x1))
2068         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2069
2070       if (heightu != (old->y2 - old->y1))
2071         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2072     }
2073
2074   g_object_thaw_notify (obj);
2075 }
2076
2077 /*< private >
2078  * clutter_actor_set_allocation_internal:
2079  * @self: a #ClutterActor
2080  * @box: a #ClutterActorBox
2081  * @flags: allocation flags
2082  *
2083  * Stores the allocation of @self.
2084  *
2085  * This function only performs basic storage and property notification.
2086  *
2087  * This function should be called by clutter_actor_set_allocation()
2088  * and by the default implementation of #ClutterActorClass.allocate().
2089  *
2090  * Return value: %TRUE if the allocation of the #ClutterActor has been
2091  *   changed, and %FALSE otherwise
2092  */
2093 static inline gboolean
2094 clutter_actor_set_allocation_internal (ClutterActor           *self,
2095                                        const ClutterActorBox  *box,
2096                                        ClutterAllocationFlags  flags)
2097 {
2098   ClutterActorPrivate *priv = self->priv;
2099   GObject *obj;
2100   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2101   gboolean flags_changed;
2102   gboolean retval;
2103   ClutterActorBox old_alloc = { 0, };
2104
2105   obj = G_OBJECT (self);
2106
2107   g_object_freeze_notify (obj);
2108
2109   clutter_actor_store_old_geometry (self, &old_alloc);
2110
2111   x1_changed = priv->allocation.x1 != box->x1;
2112   y1_changed = priv->allocation.y1 != box->y1;
2113   x2_changed = priv->allocation.x2 != box->x2;
2114   y2_changed = priv->allocation.y2 != box->y2;
2115
2116   flags_changed = priv->allocation_flags != flags;
2117
2118   priv->allocation = *box;
2119   priv->allocation_flags = flags;
2120
2121   /* allocation is authoritative */
2122   priv->needs_width_request = FALSE;
2123   priv->needs_height_request = FALSE;
2124   priv->needs_allocation = FALSE;
2125
2126   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
2127     {
2128       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2129                     _clutter_actor_get_debug_name (self));
2130
2131       priv->transform_valid = FALSE;
2132
2133       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2134
2135       /* if the allocation changes, so does the content box */
2136       if (priv->content != NULL)
2137         g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2138
2139       retval = TRUE;
2140     }
2141   else
2142     retval = FALSE;
2143
2144   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2145
2146   g_object_thaw_notify (obj);
2147
2148   return retval;
2149 }
2150
2151 static void clutter_actor_real_allocate (ClutterActor           *self,
2152                                          const ClutterActorBox  *box,
2153                                          ClutterAllocationFlags  flags);
2154
2155 static inline void
2156 clutter_actor_maybe_layout_children (ClutterActor           *self,
2157                                      const ClutterActorBox  *allocation,
2158                                      ClutterAllocationFlags  flags)
2159 {
2160   ClutterActorPrivate *priv = self->priv;
2161
2162   /* this is going to be a bit hard to follow, so let's put an explanation
2163    * here.
2164    *
2165    * we want ClutterActor to have a default layout manager if the actor was
2166    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2167    *
2168    * we also want any subclass of ClutterActor that does not override the
2169    * ::allocate() virtual function to delegate to a layout manager.
2170    *
2171    * finally, we want to allow people subclassing ClutterActor and overriding
2172    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2173    *
2174    * on the other hand, we want existing actor subclasses overriding the
2175    * ::allocate() virtual function and chaining up to the parent's
2176    * implementation to continue working without allocating their children
2177    * twice, or without entering an allocation loop.
2178    *
2179    * for the first two points, we check if the class of the actor is
2180    * overridding the ::allocate() virtual function; if it isn't, then we
2181    * follow through with checking whether we have children and a layout
2182    * manager, and eventually calling clutter_layout_manager_allocate().
2183    *
2184    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2185    * allocation flags that we got passed, and if it is present, we continue
2186    * with the check above.
2187    *
2188    * if neither of these two checks yields a positive result, we just
2189    * assume that the ::allocate() virtual function that resulted in this
2190    * function being called will also allocate the children of the actor.
2191    */
2192
2193   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2194     goto check_layout;
2195
2196   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2197     goto check_layout;
2198
2199   return;
2200
2201 check_layout:
2202   if (priv->n_children != 0 &&
2203       priv->layout_manager != NULL)
2204     {
2205       ClutterContainer *container = CLUTTER_CONTAINER (self);
2206       ClutterAllocationFlags children_flags;
2207       ClutterActorBox children_box;
2208
2209       /* normalize the box passed to the layout manager */
2210       children_box.x1 = children_box.y1 = 0.f;
2211       children_box.x2 = (allocation->x2 - allocation->x1);
2212       children_box.y2 = (allocation->y2 - allocation->y1);
2213
2214       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2215        * the actor's children, since it refers only to the current
2216        * actor's allocation.
2217        */
2218       children_flags = flags;
2219       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2220
2221       CLUTTER_NOTE (LAYOUT,
2222                     "Allocating %d children of %s "
2223                     "at { %.2f, %.2f - %.2f x %.2f } "
2224                     "using %s",
2225                     priv->n_children,
2226                     _clutter_actor_get_debug_name (self),
2227                     allocation->x1,
2228                     allocation->y1,
2229                     (allocation->x2 - allocation->x1),
2230                     (allocation->y2 - allocation->y1),
2231                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2232
2233       clutter_layout_manager_allocate (priv->layout_manager,
2234                                        container,
2235                                        &children_box,
2236                                        children_flags);
2237     }
2238 }
2239
2240 static void
2241 clutter_actor_real_allocate (ClutterActor           *self,
2242                              const ClutterActorBox  *box,
2243                              ClutterAllocationFlags  flags)
2244 {
2245   ClutterActorPrivate *priv = self->priv;
2246   gboolean changed;
2247
2248   g_object_freeze_notify (G_OBJECT (self));
2249
2250   changed = clutter_actor_set_allocation_internal (self, box, flags);
2251
2252   /* we allocate our children before we notify changes in our geometry,
2253    * so that people connecting to properties will be able to get valid
2254    * data out of the sub-tree of the scene graph that has this actor at
2255    * the root.
2256    */
2257   clutter_actor_maybe_layout_children (self, box, flags);
2258
2259   if (changed)
2260     {
2261       ClutterActorBox signal_box = priv->allocation;
2262       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2263
2264       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2265                      &signal_box,
2266                      signal_flags);
2267     }
2268
2269   g_object_thaw_notify (G_OBJECT (self));
2270 }
2271
2272 static void
2273 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2274                                     ClutterActor *origin)
2275 {
2276   /* no point in queuing a redraw on a destroyed actor */
2277   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2278     return;
2279
2280   /* NB: We can't bail out early here if the actor is hidden in case
2281    * the actor bas been cloned. In this case the clone will need to
2282    * receive the signal so it can queue its own redraw.
2283    */
2284
2285   /* calls klass->queue_redraw in default handler */
2286   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2287 }
2288
2289 static void
2290 clutter_actor_real_queue_redraw (ClutterActor *self,
2291                                  ClutterActor *origin)
2292 {
2293   ClutterActor *parent;
2294
2295   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2296                 _clutter_actor_get_debug_name (self),
2297                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2298                                : "same actor");
2299
2300   /* no point in queuing a redraw on a destroyed actor */
2301   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2302     return;
2303
2304   /* If the queue redraw is coming from a child then the actor has
2305      become dirty and any queued effect is no longer valid */
2306   if (self != origin)
2307     {
2308       self->priv->is_dirty = TRUE;
2309       self->priv->effect_to_redraw = NULL;
2310     }
2311
2312   /* If the actor isn't visible, we still had to emit the signal
2313    * to allow for a ClutterClone, but the appearance of the parent
2314    * won't change so we don't have to propagate up the hierarchy.
2315    */
2316   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2317     return;
2318
2319   /* Although we could determine here that a full stage redraw
2320    * has already been queued and immediately bail out, we actually
2321    * guarantee that we will propagate a queue-redraw signal to our
2322    * parent at least once so that it's possible to implement a
2323    * container that tracks which of its children have queued a
2324    * redraw.
2325    */
2326   if (self->priv->propagated_one_redraw)
2327     {
2328       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2329       if (stage != NULL &&
2330           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2331         return;
2332     }
2333
2334   self->priv->propagated_one_redraw = TRUE;
2335
2336   /* notify parents, if they are all visible eventually we'll
2337    * queue redraw on the stage, which queues the redraw idle.
2338    */
2339   parent = clutter_actor_get_parent (self);
2340   if (parent != NULL)
2341     {
2342       /* this will go up recursively */
2343       _clutter_actor_signal_queue_redraw (parent, origin);
2344     }
2345 }
2346
2347 static void
2348 clutter_actor_real_queue_relayout (ClutterActor *self)
2349 {
2350   ClutterActorPrivate *priv = self->priv;
2351
2352   /* no point in queueing a redraw on a destroyed actor */
2353   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2354     return;
2355
2356   priv->needs_width_request  = TRUE;
2357   priv->needs_height_request = TRUE;
2358   priv->needs_allocation     = TRUE;
2359
2360   /* reset the cached size requests */
2361   memset (priv->width_requests, 0,
2362           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2363   memset (priv->height_requests, 0,
2364           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2365
2366   /* We need to go all the way up the hierarchy */
2367   if (priv->parent != NULL)
2368     _clutter_actor_queue_only_relayout (priv->parent);
2369 }
2370
2371 /**
2372  * clutter_actor_apply_relative_transform_to_point:
2373  * @self: A #ClutterActor
2374  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2375  *   default #ClutterStage
2376  * @point: A point as #ClutterVertex
2377  * @vertex: (out caller-allocates): The translated #ClutterVertex
2378  *
2379  * Transforms @point in coordinates relative to the actor into
2380  * ancestor-relative coordinates using the relevant transform
2381  * stack (i.e. scale, rotation, etc).
2382  *
2383  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2384  * this case, the coordinates returned will be the coordinates on
2385  * the stage before the projection is applied. This is different from
2386  * the behaviour of clutter_actor_apply_transform_to_point().
2387  *
2388  * Since: 0.6
2389  */
2390 void
2391 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2392                                                  ClutterActor        *ancestor,
2393                                                  const ClutterVertex *point,
2394                                                  ClutterVertex       *vertex)
2395 {
2396   gfloat w;
2397   CoglMatrix matrix;
2398
2399   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2400   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2401   g_return_if_fail (point != NULL);
2402   g_return_if_fail (vertex != NULL);
2403
2404   *vertex = *point;
2405   w = 1.0;
2406
2407   if (ancestor == NULL)
2408     ancestor = _clutter_actor_get_stage_internal (self);
2409
2410   if (ancestor == NULL)
2411     {
2412       *vertex = *point;
2413       return;
2414     }
2415
2416   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2417   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2418 }
2419
2420 static gboolean
2421 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2422                                          const ClutterVertex *vertices_in,
2423                                          ClutterVertex *vertices_out,
2424                                          int n_vertices)
2425 {
2426   ClutterActor *stage;
2427   CoglMatrix modelview;
2428   CoglMatrix projection;
2429   float viewport[4];
2430
2431   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2432
2433   stage = _clutter_actor_get_stage_internal (self);
2434
2435   /* We really can't do anything meaningful in this case so don't try
2436    * to do any transform */
2437   if (stage == NULL)
2438     return FALSE;
2439
2440   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2441    * that gets us to stage coordinates, we want to go all the way to eye
2442    * coordinates */
2443   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2444
2445   /* Fetch the projection and viewport */
2446   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2447   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2448                                &viewport[0],
2449                                &viewport[1],
2450                                &viewport[2],
2451                                &viewport[3]);
2452
2453   _clutter_util_fully_transform_vertices (&modelview,
2454                                           &projection,
2455                                           viewport,
2456                                           vertices_in,
2457                                           vertices_out,
2458                                           n_vertices);
2459
2460   return TRUE;
2461 }
2462
2463 /**
2464  * clutter_actor_apply_transform_to_point:
2465  * @self: A #ClutterActor
2466  * @point: A point as #ClutterVertex
2467  * @vertex: (out caller-allocates): The translated #ClutterVertex
2468  *
2469  * Transforms @point in coordinates relative to the actor
2470  * into screen-relative coordinates with the current actor
2471  * transformation (i.e. scale, rotation, etc)
2472  *
2473  * Since: 0.4
2474  **/
2475 void
2476 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2477                                         const ClutterVertex *point,
2478                                         ClutterVertex       *vertex)
2479 {
2480   g_return_if_fail (point != NULL);
2481   g_return_if_fail (vertex != NULL);
2482   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2483 }
2484
2485 /*
2486  * _clutter_actor_get_relative_transformation_matrix:
2487  * @self: The actor whose coordinate space you want to transform from.
2488  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2489  *            or %NULL if you want to transform all the way to eye coordinates.
2490  * @matrix: A #CoglMatrix to store the transformation
2491  *
2492  * This gets a transformation @matrix that will transform coordinates from the
2493  * coordinate space of @self into the coordinate space of @ancestor.
2494  *
2495  * For example if you need a matrix that can transform the local actor
2496  * coordinates of @self into stage coordinates you would pass the actor's stage
2497  * pointer as the @ancestor.
2498  *
2499  * If you pass %NULL then the transformation will take you all the way through
2500  * to eye coordinates. This can be useful if you want to extract the entire
2501  * modelview transform that Clutter applies before applying the projection
2502  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2503  * using cogl_set_modelview_matrix() for example then you would want a matrix
2504  * that transforms into eye coordinates.
2505  *
2506  * <note><para>This function explicitly initializes the given @matrix. If you just
2507  * want clutter to multiply a relative transformation with an existing matrix
2508  * you can use clutter_actor_apply_relative_transformation_matrix()
2509  * instead.</para></note>
2510  *
2511  */
2512 /* XXX: We should consider caching the stage relative modelview along with
2513  * the actor itself */
2514 static void
2515 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2516                                                    ClutterActor *ancestor,
2517                                                    CoglMatrix *matrix)
2518 {
2519   cogl_matrix_init_identity (matrix);
2520
2521   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2522 }
2523
2524 /* Project the given @box into stage window coordinates, writing the
2525  * transformed vertices to @verts[]. */
2526 static gboolean
2527 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2528                                           const ClutterActorBox *box,
2529                                           ClutterVertex          verts[])
2530 {
2531   ClutterVertex box_vertices[4];
2532
2533   box_vertices[0].x = box->x1;
2534   box_vertices[0].y = box->y1;
2535   box_vertices[0].z = 0;
2536   box_vertices[1].x = box->x2;
2537   box_vertices[1].y = box->y1;
2538   box_vertices[1].z = 0;
2539   box_vertices[2].x = box->x1;
2540   box_vertices[2].y = box->y2;
2541   box_vertices[2].z = 0;
2542   box_vertices[3].x = box->x2;
2543   box_vertices[3].y = box->y2;
2544   box_vertices[3].z = 0;
2545
2546   return
2547     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2548 }
2549
2550 /**
2551  * clutter_actor_get_allocation_vertices:
2552  * @self: A #ClutterActor
2553  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2554  *   against, or %NULL to use the #ClutterStage
2555  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2556  *   location for an array of 4 #ClutterVertex in which to store the result
2557  *
2558  * Calculates the transformed coordinates of the four corners of the
2559  * actor in the plane of @ancestor. The returned vertices relate to
2560  * the #ClutterActorBox coordinates as follows:
2561  * <itemizedlist>
2562  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2563  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2564  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2565  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2566  * </itemizedlist>
2567  *
2568  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2569  * this case, the coordinates returned will be the coordinates on
2570  * the stage before the projection is applied. This is different from
2571  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2572  *
2573  * Since: 0.6
2574  */
2575 void
2576 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2577                                        ClutterActor  *ancestor,
2578                                        ClutterVertex  verts[])
2579 {
2580   ClutterActorPrivate *priv;
2581   ClutterActorBox box;
2582   ClutterVertex vertices[4];
2583   CoglMatrix modelview;
2584
2585   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2586   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2587
2588   if (ancestor == NULL)
2589     ancestor = _clutter_actor_get_stage_internal (self);
2590
2591   /* Fallback to a NOP transform if the actor isn't parented under a
2592    * stage. */
2593   if (ancestor == NULL)
2594     ancestor = self;
2595
2596   priv = self->priv;
2597
2598   /* if the actor needs to be allocated we force a relayout, so that
2599    * we will have valid values to use in the transformations */
2600   if (priv->needs_allocation)
2601     {
2602       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2603       if (stage)
2604         _clutter_stage_maybe_relayout (stage);
2605       else
2606         {
2607           box.x1 = box.y1 = 0;
2608           /* The result isn't really meaningful in this case but at
2609            * least try to do something *vaguely* reasonable... */
2610           clutter_actor_get_size (self, &box.x2, &box.y2);
2611         }
2612     }
2613
2614   clutter_actor_get_allocation_box (self, &box);
2615
2616   vertices[0].x = box.x1;
2617   vertices[0].y = box.y1;
2618   vertices[0].z = 0;
2619   vertices[1].x = box.x2;
2620   vertices[1].y = box.y1;
2621   vertices[1].z = 0;
2622   vertices[2].x = box.x1;
2623   vertices[2].y = box.y2;
2624   vertices[2].z = 0;
2625   vertices[3].x = box.x2;
2626   vertices[3].y = box.y2;
2627   vertices[3].z = 0;
2628
2629   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2630                                                      &modelview);
2631
2632   cogl_matrix_transform_points (&modelview,
2633                                 3,
2634                                 sizeof (ClutterVertex),
2635                                 vertices,
2636                                 sizeof (ClutterVertex),
2637                                 vertices,
2638                                 4);
2639 }
2640
2641 /**
2642  * clutter_actor_get_abs_allocation_vertices:
2643  * @self: A #ClutterActor
2644  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2645  *   of 4 #ClutterVertex where to store the result.
2646  *
2647  * Calculates the transformed screen coordinates of the four corners of
2648  * the actor; the returned vertices relate to the #ClutterActorBox
2649  * coordinates  as follows:
2650  * <itemizedlist>
2651  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2652  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2653  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2654  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2655  * </itemizedlist>
2656  *
2657  * Since: 0.4
2658  */
2659 void
2660 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2661                                            ClutterVertex  verts[])
2662 {
2663   ClutterActorPrivate *priv;
2664   ClutterActorBox actor_space_allocation;
2665
2666   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2667
2668   priv = self->priv;
2669
2670   /* if the actor needs to be allocated we force a relayout, so that
2671    * the actor allocation box will be valid for
2672    * _clutter_actor_transform_and_project_box()
2673    */
2674   if (priv->needs_allocation)
2675     {
2676       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2677       /* There's nothing meaningful we can do now */
2678       if (!stage)
2679         return;
2680
2681       _clutter_stage_maybe_relayout (stage);
2682     }
2683
2684   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2685    * own coordinate space... */
2686   actor_space_allocation.x1 = 0;
2687   actor_space_allocation.y1 = 0;
2688   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2689   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2690   _clutter_actor_transform_and_project_box (self,
2691                                             &actor_space_allocation,
2692                                             verts);
2693 }
2694
2695 static void
2696 clutter_actor_real_apply_transform (ClutterActor *self,
2697                                     CoglMatrix   *matrix)
2698 {
2699   ClutterActorPrivate *priv = self->priv;
2700
2701   if (!priv->transform_valid)
2702     {
2703       CoglMatrix *transform = &priv->transform;
2704       const ClutterTransformInfo *info;
2705
2706       info = _clutter_actor_get_transform_info_or_defaults (self);
2707
2708       cogl_matrix_init_identity (transform);
2709
2710       cogl_matrix_translate (transform,
2711                              priv->allocation.x1,
2712                              priv->allocation.y1,
2713                              0.0);
2714
2715       if (info->depth)
2716         cogl_matrix_translate (transform, 0, 0, info->depth);
2717
2718       /*
2719        * because the rotation involves translations, we must scale
2720        * before applying the rotations (if we apply the scale after
2721        * the rotations, the translations included in the rotation are
2722        * not scaled and so the entire object will move on the screen
2723        * as a result of rotating it).
2724        */
2725       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2726         {
2727           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2728                                         &info->scale_center,
2729                                         cogl_matrix_scale (transform,
2730                                                            info->scale_x,
2731                                                            info->scale_y,
2732                                                            1.0));
2733         }
2734
2735       if (info->rz_angle)
2736         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2737                                       &info->rz_center,
2738                                       cogl_matrix_rotate (transform,
2739                                                           info->rz_angle,
2740                                                           0, 0, 1.0));
2741
2742       if (info->ry_angle)
2743         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2744                                       &info->ry_center,
2745                                       cogl_matrix_rotate (transform,
2746                                                           info->ry_angle,
2747                                                           0, 1.0, 0));
2748
2749       if (info->rx_angle)
2750         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2751                                       &info->rx_center,
2752                                       cogl_matrix_rotate (transform,
2753                                                           info->rx_angle,
2754                                                           1.0, 0, 0));
2755
2756       if (!clutter_anchor_coord_is_zero (&info->anchor))
2757         {
2758           gfloat x, y, z;
2759
2760           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2761           cogl_matrix_translate (transform, -x, -y, -z);
2762         }
2763
2764       priv->transform_valid = TRUE;
2765     }
2766
2767   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2768 }
2769
2770 /* Applies the transforms associated with this actor to the given
2771  * matrix. */
2772 void
2773 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2774                                           CoglMatrix *matrix)
2775 {
2776   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2777 }
2778
2779 /*
2780  * clutter_actor_apply_relative_transformation_matrix:
2781  * @self: The actor whose coordinate space you want to transform from.
2782  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2783  *            or %NULL if you want to transform all the way to eye coordinates.
2784  * @matrix: A #CoglMatrix to apply the transformation too.
2785  *
2786  * This multiplies a transform with @matrix that will transform coordinates
2787  * from the coordinate space of @self into the coordinate space of @ancestor.
2788  *
2789  * For example if you need a matrix that can transform the local actor
2790  * coordinates of @self into stage coordinates you would pass the actor's stage
2791  * pointer as the @ancestor.
2792  *
2793  * If you pass %NULL then the transformation will take you all the way through
2794  * to eye coordinates. This can be useful if you want to extract the entire
2795  * modelview transform that Clutter applies before applying the projection
2796  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2797  * using cogl_set_modelview_matrix() for example then you would want a matrix
2798  * that transforms into eye coordinates.
2799  *
2800  * <note>This function doesn't initialize the given @matrix, it simply
2801  * multiplies the requested transformation matrix with the existing contents of
2802  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2803  * before calling this function, or you can use
2804  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2805  */
2806 void
2807 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2808                                                      ClutterActor *ancestor,
2809                                                      CoglMatrix *matrix)
2810 {
2811   ClutterActor *parent;
2812
2813   /* Note we terminate before ever calling stage->apply_transform()
2814    * since that would conceptually be relative to the underlying
2815    * window OpenGL coordinates so we'd need a special @ancestor
2816    * value to represent the fake parent of the stage. */
2817   if (self == ancestor)
2818     return;
2819
2820   parent = clutter_actor_get_parent (self);
2821
2822   if (parent != NULL)
2823     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2824                                                          matrix);
2825
2826   _clutter_actor_apply_modelview_transform (self, matrix);
2827 }
2828
2829 static void
2830 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2831                                        ClutterPaintVolume *pv,
2832                                        const char *label,
2833                                        const CoglColor *color)
2834 {
2835   static CoglPipeline *outline = NULL;
2836   CoglPrimitive *prim;
2837   ClutterVertex line_ends[12 * 2];
2838   int n_vertices;
2839   CoglContext *ctx =
2840     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2841   /* XXX: at some point we'll query this from the stage but we can't
2842    * do that until the osx backend uses Cogl natively. */
2843   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2844
2845   if (outline == NULL)
2846     outline = cogl_pipeline_new (ctx);
2847
2848   _clutter_paint_volume_complete (pv);
2849
2850   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2851
2852   /* Front face */
2853   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2854   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2855   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2856   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2857
2858   if (!pv->is_2d)
2859     {
2860       /* Back face */
2861       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2862       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2863       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2864       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2865
2866       /* Lines connecting front face to back face */
2867       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2868       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2869       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2870       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2871     }
2872
2873   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2874                                 n_vertices,
2875                                 (CoglVertexP3 *)line_ends);
2876
2877   cogl_pipeline_set_color (outline, color);
2878   cogl_framebuffer_draw_primitive (fb, outline, prim);
2879   cogl_object_unref (prim);
2880
2881   if (label)
2882     {
2883       PangoLayout *layout;
2884       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2885       pango_layout_set_text (layout, label, -1);
2886       cogl_pango_render_layout (layout,
2887                                 pv->vertices[0].x,
2888                                 pv->vertices[0].y,
2889                                 color,
2890                                 0);
2891       g_object_unref (layout);
2892     }
2893 }
2894
2895 static void
2896 _clutter_actor_draw_paint_volume (ClutterActor *self)
2897 {
2898   ClutterPaintVolume *pv;
2899   CoglColor color;
2900
2901   pv = _clutter_actor_get_paint_volume_mutable (self);
2902   if (!pv)
2903     {
2904       gfloat width, height;
2905       ClutterPaintVolume fake_pv;
2906
2907       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2908       _clutter_paint_volume_init_static (&fake_pv, stage);
2909
2910       clutter_actor_get_size (self, &width, &height);
2911       clutter_paint_volume_set_width (&fake_pv, width);
2912       clutter_paint_volume_set_height (&fake_pv, height);
2913
2914       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2915       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2916                                              _clutter_actor_get_debug_name (self),
2917                                              &color);
2918
2919       clutter_paint_volume_free (&fake_pv);
2920     }
2921   else
2922     {
2923       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2924       _clutter_actor_draw_paint_volume_full (self, pv,
2925                                              _clutter_actor_get_debug_name (self),
2926                                              &color);
2927     }
2928 }
2929
2930 static void
2931 _clutter_actor_paint_cull_result (ClutterActor *self,
2932                                   gboolean success,
2933                                   ClutterCullResult result)
2934 {
2935   ClutterPaintVolume *pv;
2936   CoglColor color;
2937
2938   if (success)
2939     {
2940       if (result == CLUTTER_CULL_RESULT_IN)
2941         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2942       else if (result == CLUTTER_CULL_RESULT_OUT)
2943         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2944       else
2945         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2946     }
2947   else
2948     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2949
2950   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2951     _clutter_actor_draw_paint_volume_full (self, pv,
2952                                            _clutter_actor_get_debug_name (self),
2953                                            &color);
2954   else
2955     {
2956       PangoLayout *layout;
2957       char *label =
2958         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2959       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2960       cogl_set_source_color (&color);
2961
2962       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2963       pango_layout_set_text (layout, label, -1);
2964       cogl_pango_render_layout (layout,
2965                                 0,
2966                                 0,
2967                                 &color,
2968                                 0);
2969       g_free (label);
2970       g_object_unref (layout);
2971     }
2972 }
2973
2974 static int clone_paint_level = 0;
2975
2976 void
2977 _clutter_actor_push_clone_paint (void)
2978 {
2979   clone_paint_level++;
2980 }
2981
2982 void
2983 _clutter_actor_pop_clone_paint (void)
2984 {
2985   clone_paint_level--;
2986 }
2987
2988 static gboolean
2989 in_clone_paint (void)
2990 {
2991   return clone_paint_level > 0;
2992 }
2993
2994 /* Returns TRUE if the actor can be ignored */
2995 /* FIXME: we should return a ClutterCullResult, and
2996  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2997  * means there's no point in trying to cull descendants of the current
2998  * node. */
2999 static gboolean
3000 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3001 {
3002   ClutterActorPrivate *priv = self->priv;
3003   ClutterActor *stage;
3004   const ClutterPlane *stage_clip;
3005
3006   if (!priv->last_paint_volume_valid)
3007     {
3008       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3009                     "->last_paint_volume_valid == FALSE",
3010                     _clutter_actor_get_debug_name (self));
3011       return FALSE;
3012     }
3013
3014   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3015     return FALSE;
3016
3017   stage = _clutter_actor_get_stage_internal (self);
3018   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3019   if (G_UNLIKELY (!stage_clip))
3020     {
3021       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3022                     "No stage clip set",
3023                     _clutter_actor_get_debug_name (self));
3024       return FALSE;
3025     }
3026
3027   if (cogl_get_draw_framebuffer () !=
3028       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3029     {
3030       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3031                     "Current framebuffer doesn't correspond to stage",
3032                     _clutter_actor_get_debug_name (self));
3033       return FALSE;
3034     }
3035
3036   *result_out =
3037     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3038   return TRUE;
3039 }
3040
3041 static void
3042 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3043 {
3044   ClutterActorPrivate *priv = self->priv;
3045   const ClutterPaintVolume *pv;
3046
3047   if (priv->last_paint_volume_valid)
3048     {
3049       clutter_paint_volume_free (&priv->last_paint_volume);
3050       priv->last_paint_volume_valid = FALSE;
3051     }
3052
3053   pv = clutter_actor_get_paint_volume (self);
3054   if (!pv)
3055     {
3056       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3057                     "Actor failed to report a paint volume",
3058                     _clutter_actor_get_debug_name (self));
3059       return;
3060     }
3061
3062   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3063
3064   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3065                                             NULL); /* eye coordinates */
3066
3067   priv->last_paint_volume_valid = TRUE;
3068 }
3069
3070 static inline gboolean
3071 actor_has_shader_data (ClutterActor *self)
3072 {
3073   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3074 }
3075
3076 guint32
3077 _clutter_actor_get_pick_id (ClutterActor *self)
3078 {
3079   if (self->priv->pick_id < 0)
3080     return 0;
3081
3082   return self->priv->pick_id;
3083 }
3084
3085 /* This is the same as clutter_actor_add_effect except that it doesn't
3086    queue a redraw and it doesn't notify on the effect property */
3087 static void
3088 _clutter_actor_add_effect_internal (ClutterActor  *self,
3089                                     ClutterEffect *effect)
3090 {
3091   ClutterActorPrivate *priv = self->priv;
3092
3093   if (priv->effects == NULL)
3094     {
3095       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3096       priv->effects->actor = self;
3097     }
3098
3099   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3100 }
3101
3102 /* This is the same as clutter_actor_remove_effect except that it doesn't
3103    queue a redraw and it doesn't notify on the effect property */
3104 static void
3105 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3106                                        ClutterEffect *effect)
3107 {
3108   ClutterActorPrivate *priv = self->priv;
3109
3110   if (priv->effects == NULL)
3111     return;
3112
3113   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3114 }
3115
3116 static gboolean
3117 needs_flatten_effect (ClutterActor *self)
3118 {
3119   ClutterActorPrivate *priv = self->priv;
3120
3121   if (G_UNLIKELY (clutter_paint_debug_flags &
3122                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3123     return FALSE;
3124
3125   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3126     return TRUE;
3127   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3128     {
3129       if (clutter_actor_get_paint_opacity (self) < 255 &&
3130           clutter_actor_has_overlaps (self))
3131         return TRUE;
3132     }
3133
3134   return FALSE;
3135 }
3136
3137 static void
3138 add_or_remove_flatten_effect (ClutterActor *self)
3139 {
3140   ClutterActorPrivate *priv = self->priv;
3141
3142   /* Add or remove the flatten effect depending on the
3143      offscreen-redirect property. */
3144   if (needs_flatten_effect (self))
3145     {
3146       if (priv->flatten_effect == NULL)
3147         {
3148           ClutterActorMeta *actor_meta;
3149           gint priority;
3150
3151           priv->flatten_effect = _clutter_flatten_effect_new ();
3152           /* Keep a reference to the effect so that we can queue
3153              redraws from it */
3154           g_object_ref_sink (priv->flatten_effect);
3155
3156           /* Set the priority of the effect to high so that it will
3157              always be applied to the actor first. It uses an internal
3158              priority so that it won't be visible to applications */
3159           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3160           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3161           _clutter_actor_meta_set_priority (actor_meta, priority);
3162
3163           /* This will add the effect without queueing a redraw */
3164           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3165         }
3166     }
3167   else
3168     {
3169       if (priv->flatten_effect != NULL)
3170         {
3171           /* Destroy the effect so that it will lose its fbo cache of
3172              the actor */
3173           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3174           g_object_unref (priv->flatten_effect);
3175           priv->flatten_effect = NULL;
3176         }
3177     }
3178 }
3179
3180 static void
3181 clutter_actor_paint_node (ClutterActor     *actor,
3182                           ClutterPaintNode *root)
3183 {
3184   ClutterActorPrivate *priv = actor->priv;
3185
3186   if (priv->bg_color_set)
3187     {
3188       ClutterPaintNode *node;
3189       ClutterColor bg_color;
3190
3191       bg_color = priv->bg_color;
3192       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3193                      * priv->bg_color.alpha
3194                      / 255;
3195
3196       node = clutter_color_node_new (&bg_color);
3197       clutter_paint_node_set_name (node, "backgroundColor");
3198       clutter_paint_node_add_rectangle (node, &priv->allocation);
3199       clutter_paint_node_add_child (root, node);
3200       clutter_paint_node_unref (node);
3201     }
3202
3203   if (priv->content != NULL)
3204     _clutter_content_paint_content (priv->content, actor, root);
3205
3206   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3207     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3208
3209   if (clutter_paint_node_get_n_children (root) == 0)
3210     return;
3211
3212   _clutter_paint_node_paint (root);
3213 }
3214
3215 static void
3216 clutter_actor_real_paint (ClutterActor *actor)
3217 {
3218   ClutterActorPrivate *priv = actor->priv;
3219   ClutterActor *iter;
3220
3221   for (iter = priv->first_child;
3222        iter != NULL;
3223        iter = iter->priv->next_sibling)
3224     {
3225       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3226                     _clutter_actor_get_debug_name (iter),
3227                     _clutter_actor_get_debug_name (actor),
3228                     iter->priv->allocation.x1,
3229                     iter->priv->allocation.y1,
3230                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3231                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3232
3233       clutter_actor_paint (iter);
3234     }
3235 }
3236
3237 /**
3238  * clutter_actor_paint:
3239  * @self: A #ClutterActor
3240  *
3241  * Renders the actor to display.
3242  *
3243  * This function should not be called directly by applications.
3244  * Call clutter_actor_queue_redraw() to queue paints, instead.
3245  *
3246  * This function is context-aware, and will either cause a
3247  * regular paint or a pick paint.
3248  *
3249  * This function will emit the #ClutterActor::paint signal or
3250  * the #ClutterActor::pick signal, depending on the context.
3251  *
3252  * This function does not paint the actor if the actor is set to 0,
3253  * unless it is performing a pick paint.
3254  */
3255 void
3256 clutter_actor_paint (ClutterActor *self)
3257 {
3258   ClutterActorPrivate *priv;
3259   ClutterPickMode pick_mode;
3260   gboolean clip_set = FALSE;
3261   gboolean shader_applied = FALSE;
3262
3263   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3264                           "Actor real-paint counter",
3265                           "Increments each time any actor is painted",
3266                           0 /* no application private data */);
3267   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3268                           "Actor pick-paint counter",
3269                           "Increments each time any actor is painted "
3270                           "for picking",
3271                           0 /* no application private data */);
3272
3273   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3274
3275   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3276     return;
3277
3278   priv = self->priv;
3279
3280   pick_mode = _clutter_context_get_pick_mode ();
3281
3282   if (pick_mode == CLUTTER_PICK_NONE)
3283     priv->propagated_one_redraw = FALSE;
3284
3285   /* It's an important optimization that we consider painting of
3286    * actors with 0 opacity to be a NOP... */
3287   if (pick_mode == CLUTTER_PICK_NONE &&
3288       /* ignore top-levels, since they might be transparent */
3289       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3290       /* Use the override opacity if its been set */
3291       ((priv->opacity_override >= 0) ?
3292        priv->opacity_override : priv->opacity) == 0)
3293     return;
3294
3295   /* if we aren't paintable (not in a toplevel with all
3296    * parents paintable) then do nothing.
3297    */
3298   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3299     return;
3300
3301   /* mark that we are in the paint process */
3302   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3303
3304   cogl_push_matrix();
3305
3306   if (priv->enable_model_view_transform)
3307     {
3308       CoglMatrix matrix;
3309
3310       /* XXX: It could be better to cache the modelview with the actor
3311        * instead of progressively building up the transformations on
3312        * the matrix stack every time we paint. */
3313       cogl_get_modelview_matrix (&matrix);
3314       _clutter_actor_apply_modelview_transform (self, &matrix);
3315
3316 #ifdef CLUTTER_ENABLE_DEBUG
3317       /* Catch when out-of-band transforms have been made by actors not as part
3318        * of an apply_transform vfunc... */
3319       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3320         {
3321           CoglMatrix expected_matrix;
3322
3323           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3324                                                              &expected_matrix);
3325
3326           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3327             {
3328               GString *buf = g_string_sized_new (1024);
3329               ClutterActor *parent;
3330
3331               parent = self;
3332               while (parent != NULL)
3333                 {
3334                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3335
3336                   if (parent->priv->parent != NULL)
3337                     g_string_append (buf, "->");
3338
3339                   parent = parent->priv->parent;
3340                 }
3341
3342               g_warning ("Unexpected transform found when painting actor "
3343                          "\"%s\". This will be caused by one of the actor's "
3344                          "ancestors (%s) using the Cogl API directly to transform "
3345                          "children instead of using ::apply_transform().",
3346                          _clutter_actor_get_debug_name (self),
3347                          buf->str);
3348
3349               g_string_free (buf, TRUE);
3350             }
3351         }
3352 #endif /* CLUTTER_ENABLE_DEBUG */
3353
3354       cogl_set_modelview_matrix (&matrix);
3355     }
3356
3357   if (priv->has_clip)
3358     {
3359       cogl_clip_push_rectangle (priv->clip.x,
3360                                 priv->clip.y,
3361                                 priv->clip.x + priv->clip.width,
3362                                 priv->clip.y + priv->clip.height);
3363       clip_set = TRUE;
3364     }
3365   else if (priv->clip_to_allocation)
3366     {
3367       gfloat width, height;
3368
3369       width  = priv->allocation.x2 - priv->allocation.x1;
3370       height = priv->allocation.y2 - priv->allocation.y1;
3371
3372       cogl_clip_push_rectangle (0, 0, width, height);
3373       clip_set = TRUE;
3374     }
3375
3376   if (pick_mode == CLUTTER_PICK_NONE)
3377     {
3378       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3379
3380       /* We check whether we need to add the flatten effect before
3381          each paint so that we can avoid having a mechanism for
3382          applications to notify when the value of the
3383          has_overlaps virtual changes. */
3384       add_or_remove_flatten_effect (self);
3385     }
3386   else
3387     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3388
3389   /* We save the current paint volume so that the next time the
3390    * actor queues a redraw we can constrain the redraw to just
3391    * cover the union of the new bounding box and the old.
3392    *
3393    * We also fetch the current paint volume to perform culling so
3394    * we can avoid painting actors outside the current clip region.
3395    *
3396    * If we are painting inside a clone, we should neither update
3397    * the paint volume or use it to cull painting, since the paint
3398    * box represents the location of the source actor on the
3399    * screen.
3400    *
3401    * XXX: We are starting to do a lot of vertex transforms on
3402    * the CPU in a typical paint, so at some point we should
3403    * audit these and consider caching some things.
3404    *
3405    * NB: We don't perform culling while picking at this point because
3406    * clutter-stage.c doesn't setup the clipping planes appropriately.
3407    *
3408    * NB: We don't want to update the last-paint-volume during picking
3409    * because the last-paint-volume is used to determine the old screen
3410    * space location of an actor that has moved so we can know the
3411    * minimal region to redraw to clear an old view of the actor. If we
3412    * update this during picking then by the time we come around to
3413    * paint then the last-paint-volume would likely represent the new
3414    * actor position not the old.
3415    */
3416   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3417     {
3418       gboolean success;
3419       /* annoyingly gcc warns if uninitialized even though
3420        * the initialization is redundant :-( */
3421       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3422
3423       if (G_LIKELY ((clutter_paint_debug_flags &
3424                      (CLUTTER_DEBUG_DISABLE_CULLING |
3425                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3426                     (CLUTTER_DEBUG_DISABLE_CULLING |
3427                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3428         _clutter_actor_update_last_paint_volume (self);
3429
3430       success = cull_actor (self, &result);
3431
3432       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3433         _clutter_actor_paint_cull_result (self, success, result);
3434       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3435         goto done;
3436     }
3437
3438   if (priv->effects == NULL)
3439     {
3440       if (pick_mode == CLUTTER_PICK_NONE &&
3441           actor_has_shader_data (self))
3442         {
3443           _clutter_actor_shader_pre_paint (self, FALSE);
3444           shader_applied = TRUE;
3445         }
3446
3447       priv->next_effect_to_paint = NULL;
3448     }
3449   else
3450     priv->next_effect_to_paint =
3451       _clutter_meta_group_peek_metas (priv->effects);
3452
3453   clutter_actor_continue_paint (self);
3454
3455   if (shader_applied)
3456     _clutter_actor_shader_post_paint (self);
3457
3458   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3459                   pick_mode == CLUTTER_PICK_NONE))
3460     _clutter_actor_draw_paint_volume (self);
3461
3462 done:
3463   /* If we make it here then the actor has run through a complete
3464      paint run including all the effects so it's no longer dirty */
3465   if (pick_mode == CLUTTER_PICK_NONE)
3466     priv->is_dirty = FALSE;
3467
3468   if (clip_set)
3469     cogl_clip_pop();
3470
3471   cogl_pop_matrix();
3472
3473   /* paint sequence complete */
3474   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3475 }
3476
3477 /**
3478  * clutter_actor_continue_paint:
3479  * @self: A #ClutterActor
3480  *
3481  * Run the next stage of the paint sequence. This function should only
3482  * be called within the implementation of the ‘run’ virtual of a
3483  * #ClutterEffect. It will cause the run method of the next effect to
3484  * be applied, or it will paint the actual actor if the current effect
3485  * is the last effect in the chain.
3486  *
3487  * Since: 1.8
3488  */
3489 void
3490 clutter_actor_continue_paint (ClutterActor *self)
3491 {
3492   ClutterActorPrivate *priv;
3493
3494   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3495   /* This should only be called from with in the ‘run’ implementation
3496      of a ClutterEffect */
3497   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3498
3499   priv = self->priv;
3500
3501   /* Skip any effects that are disabled */
3502   while (priv->next_effect_to_paint &&
3503          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3504     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3505
3506   /* If this has come from the last effect then we'll just paint the
3507      actual actor */
3508   if (priv->next_effect_to_paint == NULL)
3509     {
3510       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3511         {
3512           ClutterPaintNode *dummy;
3513
3514           /* XXX - this will go away in 2.0, when we can get rid of this
3515            * stuff and switch to a pure retained render tree of PaintNodes
3516            * for the entire frame, starting from the Stage.
3517            */
3518           dummy = _clutter_dummy_node_new ();
3519           clutter_paint_node_set_name (dummy, "Root");
3520           clutter_actor_paint_node (self, dummy);
3521
3522           if (clutter_paint_node_get_n_children (dummy) != 0)
3523             {
3524 #ifdef CLUTTER_ENABLE_DEBUG
3525               if (CLUTTER_HAS_DEBUG (PAINT))
3526                 {
3527                   /* dump the tree only if we have one */
3528                   _clutter_paint_node_dump_tree (dummy);
3529                 }
3530 #endif /* CLUTTER_ENABLE_DEBUG */
3531
3532               _clutter_paint_node_paint (dummy);
3533             }
3534
3535           clutter_paint_node_unref (dummy);
3536
3537           g_signal_emit (self, actor_signals[PAINT], 0);
3538         }
3539       else
3540         {
3541           ClutterColor col = { 0, };
3542
3543           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3544
3545           /* Actor will then paint silhouette of itself in supplied
3546            * color.  See clutter_stage_get_actor_at_pos() for where
3547            * picking is enabled.
3548            */
3549           g_signal_emit (self, actor_signals[PICK], 0, &col);
3550         }
3551     }
3552   else
3553     {
3554       ClutterEffect *old_current_effect;
3555       ClutterEffectPaintFlags run_flags = 0;
3556
3557       /* Cache the current effect so that we can put it back before
3558          returning */
3559       old_current_effect = priv->current_effect;
3560
3561       priv->current_effect = priv->next_effect_to_paint->data;
3562       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3563
3564       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3565         {
3566           if (priv->is_dirty)
3567             {
3568               /* If there's an effect queued with this redraw then all
3569                  effects up to that one will be considered dirty. It
3570                  is expected the queued effect will paint the cached
3571                  image and not call clutter_actor_continue_paint again
3572                  (although it should work ok if it does) */
3573               if (priv->effect_to_redraw == NULL ||
3574                   priv->current_effect != priv->effect_to_redraw)
3575                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3576             }
3577
3578           _clutter_effect_paint (priv->current_effect, run_flags);
3579         }
3580       else
3581         {
3582           /* We can't determine when an actor has been modified since
3583              its last pick so lets just assume it has always been
3584              modified */
3585           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3586
3587           _clutter_effect_pick (priv->current_effect, run_flags);
3588         }
3589
3590       priv->current_effect = old_current_effect;
3591     }
3592 }
3593
3594 static ClutterActorTraverseVisitFlags
3595 invalidate_queue_redraw_entry (ClutterActor *self,
3596                                int           depth,
3597                                gpointer      user_data)
3598 {
3599   ClutterActorPrivate *priv = self->priv;
3600
3601   if (priv->queue_redraw_entry != NULL)
3602     {
3603       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3604       priv->queue_redraw_entry = NULL;
3605     }
3606
3607   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3608 }
3609
3610 static inline void
3611 remove_child (ClutterActor *self,
3612               ClutterActor *child)
3613 {
3614   ClutterActor *prev_sibling, *next_sibling;
3615
3616   prev_sibling = child->priv->prev_sibling;
3617   next_sibling = child->priv->next_sibling;
3618
3619   if (prev_sibling != NULL)
3620     prev_sibling->priv->next_sibling = next_sibling;
3621
3622   if (next_sibling != NULL)
3623     next_sibling->priv->prev_sibling = prev_sibling;
3624
3625   if (self->priv->first_child == child)
3626     self->priv->first_child = next_sibling;
3627
3628   if (self->priv->last_child == child)
3629     self->priv->last_child = prev_sibling;
3630
3631   child->priv->parent = NULL;
3632   child->priv->prev_sibling = NULL;
3633   child->priv->next_sibling = NULL;
3634 }
3635
3636 typedef enum {
3637   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3638   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3639   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3640   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3641   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3642   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3643
3644   /* default flags for public API */
3645   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3646                                     REMOVE_CHILD_EMIT_PARENT_SET |
3647                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3648                                     REMOVE_CHILD_CHECK_STATE |
3649                                     REMOVE_CHILD_FLUSH_QUEUE |
3650                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3651
3652   /* flags for legacy/deprecated API */
3653   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3654                                     REMOVE_CHILD_FLUSH_QUEUE |
3655                                     REMOVE_CHILD_EMIT_PARENT_SET |
3656                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3657 } ClutterActorRemoveChildFlags;
3658
3659 /*< private >
3660  * clutter_actor_remove_child_internal:
3661  * @self: a #ClutterActor
3662  * @child: the child of @self that has to be removed
3663  * @flags: control the removal operations
3664  *
3665  * Removes @child from the list of children of @self.
3666  */
3667 static void
3668 clutter_actor_remove_child_internal (ClutterActor                 *self,
3669                                      ClutterActor                 *child,
3670                                      ClutterActorRemoveChildFlags  flags)
3671 {
3672   ClutterActor *old_first, *old_last;
3673   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3674   gboolean flush_queue;
3675   gboolean notify_first_last;
3676   gboolean was_mapped;
3677
3678   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3679   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3680   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3681   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3682   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3683   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3684
3685   g_object_freeze_notify (G_OBJECT (self));
3686
3687   if (destroy_meta)
3688     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3689
3690   if (check_state)
3691     {
3692       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3693
3694       /* we need to unrealize *before* we set parent_actor to NULL,
3695        * because in an unrealize method actors are dissociating from the
3696        * stage, which means they need to be able to
3697        * clutter_actor_get_stage().
3698        *
3699        * yhis should unmap and unrealize, unless we're reparenting.
3700        */
3701       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3702     }
3703   else
3704     was_mapped = FALSE;
3705
3706   if (flush_queue)
3707     {
3708       /* We take this opportunity to invalidate any queue redraw entry
3709        * associated with the actor and descendants since we won't be able to
3710        * determine the appropriate stage after this.
3711        *
3712        * we do this after we updated the mapped state because actors might
3713        * end up queueing redraws inside their mapped/unmapped virtual
3714        * functions, and if we invalidate the redraw entry we could end up
3715        * with an inconsistent state and weird memory corruption. see
3716        * bugs:
3717        *
3718        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3719        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3720        */
3721       _clutter_actor_traverse (child,
3722                                0,
3723                                invalidate_queue_redraw_entry,
3724                                NULL,
3725                                NULL);
3726     }
3727
3728   old_first = self->priv->first_child;
3729   old_last = self->priv->last_child;
3730
3731   remove_child (self, child);
3732
3733   self->priv->n_children -= 1;
3734
3735   self->priv->age += 1;
3736
3737   /* clutter_actor_reparent() will emit ::parent-set for us */
3738   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3739     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3740
3741   /* if the child was mapped then we need to relayout ourselves to account
3742    * for the removed child
3743    */
3744   if (was_mapped)
3745     clutter_actor_queue_relayout (self);
3746
3747   /* we need to emit the signal before dropping the reference */
3748   if (emit_actor_removed)
3749     g_signal_emit_by_name (self, "actor-removed", child);
3750
3751   if (notify_first_last)
3752     {
3753       if (old_first != self->priv->first_child)
3754         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3755
3756       if (old_last != self->priv->last_child)
3757         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3758     }
3759
3760   g_object_thaw_notify (G_OBJECT (self));
3761
3762   /* remove the reference we acquired in clutter_actor_add_child() */
3763   g_object_unref (child);
3764 }
3765
3766 static const ClutterTransformInfo default_transform_info = {
3767   0.0, { 0, },          /* rotation-x */
3768   0.0, { 0, },          /* rotation-y */
3769   0.0, { 0, },          /* rotation-z */
3770
3771   1.0, 1.0, { 0, },     /* scale */
3772
3773   { 0, },               /* anchor */
3774
3775   0.0,                  /* depth */
3776 };
3777
3778 /*< private >
3779  * _clutter_actor_get_transform_info_or_defaults:
3780  * @self: a #ClutterActor
3781  *
3782  * Retrieves the ClutterTransformInfo structure associated to an actor.
3783  *
3784  * If the actor does not have a ClutterTransformInfo structure associated
3785  * to it, then the default structure will be returned.
3786  *
3787  * This function should only be used for getters.
3788  *
3789  * Return value: a const pointer to the ClutterTransformInfo structure
3790  */
3791 const ClutterTransformInfo *
3792 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3793 {
3794   ClutterTransformInfo *info;
3795
3796   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3797   if (info != NULL)
3798     return info;
3799
3800   return &default_transform_info;
3801 }
3802
3803 static void
3804 clutter_transform_info_free (gpointer data)
3805 {
3806   if (data != NULL)
3807     g_slice_free (ClutterTransformInfo, data);
3808 }
3809
3810 /*< private >
3811  * _clutter_actor_get_transform_info:
3812  * @self: a #ClutterActor
3813  *
3814  * Retrieves a pointer to the ClutterTransformInfo structure.
3815  *
3816  * If the actor does not have a ClutterTransformInfo associated to it, one
3817  * will be created and initialized to the default values.
3818  *
3819  * This function should be used for setters.
3820  *
3821  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3822  * instead.
3823  *
3824  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3825  *   structure
3826  */
3827 ClutterTransformInfo *
3828 _clutter_actor_get_transform_info (ClutterActor *self)
3829 {
3830   ClutterTransformInfo *info;
3831
3832   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3833   if (info == NULL)
3834     {
3835       info = g_slice_new (ClutterTransformInfo);
3836
3837       *info = default_transform_info;
3838
3839       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3840                                info,
3841                                clutter_transform_info_free);
3842     }
3843
3844   return info;
3845 }
3846
3847 /*< private >
3848  * clutter_actor_set_rotation_angle_internal:
3849  * @self: a #ClutterActor
3850  * @axis: the axis of the angle to change
3851  * @angle: the angle of rotation
3852  *
3853  * Sets the rotation angle on the given axis without affecting the
3854  * rotation center point.
3855  */
3856 static inline void
3857 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3858                                            ClutterRotateAxis  axis,
3859                                            gdouble            angle)
3860 {
3861   GObject *obj = G_OBJECT (self);
3862   ClutterTransformInfo *info;
3863
3864   info = _clutter_actor_get_transform_info (self);
3865
3866   g_object_freeze_notify (obj);
3867
3868   switch (axis)
3869     {
3870     case CLUTTER_X_AXIS:
3871       info->rx_angle = angle;
3872       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3873       break;
3874
3875     case CLUTTER_Y_AXIS:
3876       info->ry_angle = angle;
3877       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3878       break;
3879
3880     case CLUTTER_Z_AXIS:
3881       info->rz_angle = angle;
3882       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3883       break;
3884     }
3885
3886   self->priv->transform_valid = FALSE;
3887
3888   g_object_thaw_notify (obj);
3889
3890   clutter_actor_queue_redraw (self);
3891 }
3892
3893 static inline void
3894 clutter_actor_set_rotation_angle (ClutterActor      *self,
3895                                   ClutterRotateAxis  axis,
3896                                   gdouble            angle)
3897 {
3898   ClutterTransformInfo *info;
3899
3900   info = _clutter_actor_get_transform_info (self);
3901
3902   if (clutter_actor_get_easing_duration (self) != 0)
3903     {
3904       ClutterTransition *transition;
3905       GParamSpec *pspec = NULL;
3906       double *cur_angle_p = NULL;
3907
3908       switch (axis)
3909         {
3910         case CLUTTER_X_AXIS:
3911           cur_angle_p = &info->rx_angle;
3912           pspec = obj_props[PROP_ROTATION_ANGLE_X];
3913           break;
3914
3915         case CLUTTER_Y_AXIS:
3916           cur_angle_p = &info->ry_angle;
3917           pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3918           break;
3919
3920         case CLUTTER_Z_AXIS:
3921           cur_angle_p = &info->rz_angle;
3922           pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3923           break;
3924         }
3925
3926       g_assert (pspec != NULL);
3927       g_assert (cur_angle_p != NULL);
3928
3929       transition = _clutter_actor_get_transition (self, pspec);
3930       if (transition == NULL)
3931         {
3932           transition = _clutter_actor_create_transition (self, pspec,
3933                                                          *cur_angle_p,
3934                                                          angle);
3935           clutter_timeline_start (CLUTTER_TIMELINE (transition));
3936         }
3937       else
3938         _clutter_actor_update_transition (self, pspec, angle);
3939
3940       self->priv->transform_valid = FALSE;
3941       clutter_actor_queue_redraw (self);
3942     }
3943   else
3944     clutter_actor_set_rotation_angle_internal (self, axis, angle);
3945 }
3946
3947 /*< private >
3948  * clutter_actor_set_rotation_center_internal:
3949  * @self: a #ClutterActor
3950  * @axis: the axis of the center to change
3951  * @center: the coordinates of the rotation center
3952  *
3953  * Sets the rotation center on the given axis without affecting the
3954  * rotation angle.
3955  */
3956 static inline void
3957 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3958                                             ClutterRotateAxis    axis,
3959                                             const ClutterVertex *center)
3960 {
3961   GObject *obj = G_OBJECT (self);
3962   ClutterTransformInfo *info;
3963   ClutterVertex v = { 0, 0, 0 };
3964
3965   info = _clutter_actor_get_transform_info (self);
3966
3967   if (center != NULL)
3968     v = *center;
3969
3970   g_object_freeze_notify (obj);
3971
3972   switch (axis)
3973     {
3974     case CLUTTER_X_AXIS:
3975       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3976       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3977       break;
3978
3979     case CLUTTER_Y_AXIS:
3980       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3981       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3982       break;
3983
3984     case CLUTTER_Z_AXIS:
3985       /* if the previously set rotation center was fractional, then
3986        * setting explicit coordinates will have to notify the
3987        * :rotation-center-z-gravity property as well
3988        */
3989       if (info->rz_center.is_fractional)
3990         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3991
3992       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3993       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3994       break;
3995     }
3996
3997   self->priv->transform_valid = FALSE;
3998
3999   g_object_thaw_notify (obj);
4000
4001   clutter_actor_queue_redraw (self);
4002 }
4003
4004 static void
4005 clutter_actor_animate_scale_factor (ClutterActor *self,
4006                                     double        old_factor,
4007                                     double        new_factor,
4008                                     GParamSpec   *pspec)
4009 {
4010   ClutterTransition *transition;
4011
4012   transition = _clutter_actor_get_transition (self, pspec);
4013   if (transition == NULL)
4014     {
4015       transition = _clutter_actor_create_transition (self, pspec,
4016                                                      old_factor,
4017                                                      new_factor);
4018       clutter_timeline_start (CLUTTER_TIMELINE (transition));
4019     }
4020   else
4021     _clutter_actor_update_transition (self, pspec, new_factor);
4022
4023
4024   self->priv->transform_valid = FALSE;
4025   clutter_actor_queue_redraw (self);
4026 }
4027
4028 static void
4029 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4030                                          double factor,
4031                                          GParamSpec *pspec)
4032 {
4033   GObject *obj = G_OBJECT (self);
4034   ClutterTransformInfo *info;
4035
4036   info = _clutter_actor_get_transform_info (self);
4037
4038   if (pspec == obj_props[PROP_SCALE_X])
4039     info->scale_x = factor;
4040   else
4041     info->scale_y = factor;
4042
4043   self->priv->transform_valid = FALSE;
4044   clutter_actor_queue_redraw (self);
4045   g_object_notify_by_pspec (obj, pspec);
4046 }
4047
4048 static inline void
4049 clutter_actor_set_scale_factor (ClutterActor      *self,
4050                                 ClutterRotateAxis  axis,
4051                                 gdouble            factor)
4052 {
4053   GObject *obj = G_OBJECT (self);
4054   ClutterTransformInfo *info;
4055   GParamSpec *pspec;
4056
4057   info = _clutter_actor_get_transform_info (self);
4058
4059   g_object_freeze_notify (obj);
4060
4061   switch (axis)
4062     {
4063     case CLUTTER_X_AXIS:
4064       pspec = obj_props[PROP_SCALE_X];
4065
4066       if (clutter_actor_get_easing_duration (self) != 0)
4067         clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
4068       else
4069         clutter_actor_set_scale_factor_internal (self, factor, pspec);
4070       break;
4071
4072     case CLUTTER_Y_AXIS:
4073       pspec = obj_props[PROP_SCALE_Y];
4074
4075       if (clutter_actor_get_easing_duration (self) != 0)
4076         clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4077       else
4078         clutter_actor_set_scale_factor_internal (self, factor, pspec);
4079       break;
4080
4081     default:
4082       g_assert_not_reached ();
4083     }
4084
4085   g_object_thaw_notify (obj);
4086 }
4087
4088 static inline void
4089 clutter_actor_set_scale_center (ClutterActor      *self,
4090                                 ClutterRotateAxis  axis,
4091                                 gfloat             coord)
4092 {
4093   GObject *obj = G_OBJECT (self);
4094   ClutterTransformInfo *info;
4095   gfloat center_x, center_y;
4096
4097   info = _clutter_actor_get_transform_info (self);
4098
4099   g_object_freeze_notify (obj);
4100
4101   /* get the current scale center coordinates */
4102   clutter_anchor_coord_get_units (self, &info->scale_center,
4103                                   &center_x,
4104                                   &center_y,
4105                                   NULL);
4106
4107   /* we need to notify this too, because setting explicit coordinates will
4108    * change the gravity as a side effect
4109    */
4110   if (info->scale_center.is_fractional)
4111     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4112
4113   switch (axis)
4114     {
4115     case CLUTTER_X_AXIS:
4116       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4117       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4118       break;
4119
4120     case CLUTTER_Y_AXIS:
4121       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4122       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4123       break;
4124
4125     default:
4126       g_assert_not_reached ();
4127     }
4128
4129   self->priv->transform_valid = FALSE;
4130
4131   clutter_actor_queue_redraw (self);
4132
4133   g_object_thaw_notify (obj);
4134 }
4135
4136 static inline void
4137 clutter_actor_set_anchor_coord (ClutterActor      *self,
4138                                 ClutterRotateAxis  axis,
4139                                 gfloat             coord)
4140 {
4141   GObject *obj = G_OBJECT (self);
4142   ClutterTransformInfo *info;
4143   gfloat anchor_x, anchor_y;
4144
4145   info = _clutter_actor_get_transform_info (self);
4146
4147   g_object_freeze_notify (obj);
4148
4149   clutter_anchor_coord_get_units (self, &info->anchor,
4150                                   &anchor_x,
4151                                   &anchor_y,
4152                                   NULL);
4153
4154   if (info->anchor.is_fractional)
4155     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4156
4157   switch (axis)
4158     {
4159     case CLUTTER_X_AXIS:
4160       clutter_anchor_coord_set_units (&info->anchor,
4161                                       coord,
4162                                       anchor_y,
4163                                       0.0);
4164       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4165       break;
4166
4167     case CLUTTER_Y_AXIS:
4168       clutter_anchor_coord_set_units (&info->anchor,
4169                                       anchor_x,
4170                                       coord,
4171                                       0.0);
4172       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4173       break;
4174
4175     default:
4176       g_assert_not_reached ();
4177     }
4178
4179   self->priv->transform_valid = FALSE;
4180
4181   clutter_actor_queue_redraw (self);
4182
4183   g_object_thaw_notify (obj);
4184 }
4185
4186 static void
4187 clutter_actor_set_property (GObject      *object,
4188                             guint         prop_id,
4189                             const GValue *value,
4190                             GParamSpec   *pspec)
4191 {
4192   ClutterActor *actor = CLUTTER_ACTOR (object);
4193   ClutterActorPrivate *priv = actor->priv;
4194
4195   switch (prop_id)
4196     {
4197     case PROP_X:
4198       clutter_actor_set_x (actor, g_value_get_float (value));
4199       break;
4200
4201     case PROP_Y:
4202       clutter_actor_set_y (actor, g_value_get_float (value));
4203       break;
4204
4205     case PROP_WIDTH:
4206       clutter_actor_set_width (actor, g_value_get_float (value));
4207       break;
4208
4209     case PROP_HEIGHT:
4210       clutter_actor_set_height (actor, g_value_get_float (value));
4211       break;
4212
4213     case PROP_FIXED_X:
4214       clutter_actor_set_x (actor, g_value_get_float (value));
4215       break;
4216
4217     case PROP_FIXED_Y:
4218       clutter_actor_set_y (actor, g_value_get_float (value));
4219       break;
4220
4221     case PROP_FIXED_POSITION_SET:
4222       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4223       break;
4224
4225     case PROP_MIN_WIDTH:
4226       clutter_actor_set_min_width (actor, g_value_get_float (value));
4227       break;
4228
4229     case PROP_MIN_HEIGHT:
4230       clutter_actor_set_min_height (actor, g_value_get_float (value));
4231       break;
4232
4233     case PROP_NATURAL_WIDTH:
4234       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4235       break;
4236
4237     case PROP_NATURAL_HEIGHT:
4238       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4239       break;
4240
4241     case PROP_MIN_WIDTH_SET:
4242       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4243       break;
4244
4245     case PROP_MIN_HEIGHT_SET:
4246       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4247       break;
4248
4249     case PROP_NATURAL_WIDTH_SET:
4250       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4251       break;
4252
4253     case PROP_NATURAL_HEIGHT_SET:
4254       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4255       break;
4256
4257     case PROP_REQUEST_MODE:
4258       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4259       break;
4260
4261     case PROP_DEPTH:
4262       clutter_actor_set_depth (actor, g_value_get_float (value));
4263       break;
4264
4265     case PROP_OPACITY:
4266       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4267       break;
4268
4269     case PROP_OFFSCREEN_REDIRECT:
4270       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4271       break;
4272
4273     case PROP_NAME:
4274       clutter_actor_set_name (actor, g_value_get_string (value));
4275       break;
4276
4277     case PROP_VISIBLE:
4278       if (g_value_get_boolean (value) == TRUE)
4279         clutter_actor_show (actor);
4280       else
4281         clutter_actor_hide (actor);
4282       break;
4283
4284     case PROP_SCALE_X:
4285       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4286                                       g_value_get_double (value));
4287       break;
4288
4289     case PROP_SCALE_Y:
4290       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4291                                       g_value_get_double (value));
4292       break;
4293
4294     case PROP_SCALE_CENTER_X:
4295       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4296                                       g_value_get_float (value));
4297       break;
4298
4299     case PROP_SCALE_CENTER_Y:
4300       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4301                                       g_value_get_float (value));
4302       break;
4303
4304     case PROP_SCALE_GRAVITY:
4305       {
4306         const ClutterTransformInfo *info;
4307         ClutterGravity gravity;
4308
4309         info = _clutter_actor_get_transform_info_or_defaults (actor);
4310         gravity = g_value_get_enum (value);
4311
4312         clutter_actor_set_scale_with_gravity (actor,
4313                                               info->scale_x,
4314                                               info->scale_y,
4315                                               gravity);
4316       }
4317       break;
4318
4319     case PROP_CLIP:
4320       {
4321         const ClutterGeometry *geom = g_value_get_boxed (value);
4322
4323         clutter_actor_set_clip (actor,
4324                                 geom->x, geom->y,
4325                                 geom->width, geom->height);
4326       }
4327       break;
4328
4329     case PROP_CLIP_TO_ALLOCATION:
4330       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4331       break;
4332
4333     case PROP_REACTIVE:
4334       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4335       break;
4336
4337     case PROP_ROTATION_ANGLE_X:
4338       clutter_actor_set_rotation_angle (actor,
4339                                         CLUTTER_X_AXIS,
4340                                         g_value_get_double (value));
4341       break;
4342
4343     case PROP_ROTATION_ANGLE_Y:
4344       clutter_actor_set_rotation_angle (actor,
4345                                         CLUTTER_Y_AXIS,
4346                                         g_value_get_double (value));
4347       break;
4348
4349     case PROP_ROTATION_ANGLE_Z:
4350       clutter_actor_set_rotation_angle (actor,
4351                                         CLUTTER_Z_AXIS,
4352                                         g_value_get_double (value));
4353       break;
4354
4355     case PROP_ROTATION_CENTER_X:
4356       clutter_actor_set_rotation_center_internal (actor,
4357                                                   CLUTTER_X_AXIS,
4358                                                   g_value_get_boxed (value));
4359       break;
4360
4361     case PROP_ROTATION_CENTER_Y:
4362       clutter_actor_set_rotation_center_internal (actor,
4363                                                   CLUTTER_Y_AXIS,
4364                                                   g_value_get_boxed (value));
4365       break;
4366
4367     case PROP_ROTATION_CENTER_Z:
4368       clutter_actor_set_rotation_center_internal (actor,
4369                                                   CLUTTER_Z_AXIS,
4370                                                   g_value_get_boxed (value));
4371       break;
4372
4373     case PROP_ROTATION_CENTER_Z_GRAVITY:
4374       {
4375         const ClutterTransformInfo *info;
4376
4377         info = _clutter_actor_get_transform_info_or_defaults (actor);
4378         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4379                                                    g_value_get_enum (value));
4380       }
4381       break;
4382
4383     case PROP_ANCHOR_X:
4384       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4385                                       g_value_get_float (value));
4386       break;
4387
4388     case PROP_ANCHOR_Y:
4389       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4390                                       g_value_get_float (value));
4391       break;
4392
4393     case PROP_ANCHOR_GRAVITY:
4394       clutter_actor_set_anchor_point_from_gravity (actor,
4395                                                    g_value_get_enum (value));
4396       break;
4397
4398     case PROP_SHOW_ON_SET_PARENT:
4399       priv->show_on_set_parent = g_value_get_boolean (value);
4400       break;
4401
4402     case PROP_TEXT_DIRECTION:
4403       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4404       break;
4405
4406     case PROP_ACTIONS:
4407       clutter_actor_add_action (actor, g_value_get_object (value));
4408       break;
4409
4410     case PROP_CONSTRAINTS:
4411       clutter_actor_add_constraint (actor, g_value_get_object (value));
4412       break;
4413
4414     case PROP_EFFECT:
4415       clutter_actor_add_effect (actor, g_value_get_object (value));
4416       break;
4417
4418     case PROP_LAYOUT_MANAGER:
4419       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4420       break;
4421
4422     case PROP_X_ALIGN:
4423       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4424       break;
4425
4426     case PROP_Y_ALIGN:
4427       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4428       break;
4429
4430     case PROP_MARGIN_TOP:
4431       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4432       break;
4433
4434     case PROP_MARGIN_BOTTOM:
4435       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4436       break;
4437
4438     case PROP_MARGIN_LEFT:
4439       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4440       break;
4441
4442     case PROP_MARGIN_RIGHT:
4443       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4444       break;
4445
4446     case PROP_BACKGROUND_COLOR:
4447       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4448       break;
4449
4450     case PROP_CONTENT:
4451       clutter_actor_set_content (actor, g_value_get_object (value));
4452       break;
4453
4454     case PROP_CONTENT_GRAVITY:
4455       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4456       break;
4457
4458     default:
4459       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4460       break;
4461     }
4462 }
4463
4464 static void
4465 clutter_actor_get_property (GObject    *object,
4466                             guint       prop_id,
4467                             GValue     *value,
4468                             GParamSpec *pspec)
4469 {
4470   ClutterActor *actor = CLUTTER_ACTOR (object);
4471   ClutterActorPrivate *priv = actor->priv;
4472
4473   switch (prop_id)
4474     {
4475     case PROP_X:
4476       g_value_set_float (value, clutter_actor_get_x (actor));
4477       break;
4478
4479     case PROP_Y:
4480       g_value_set_float (value, clutter_actor_get_y (actor));
4481       break;
4482
4483     case PROP_WIDTH:
4484       g_value_set_float (value, clutter_actor_get_width (actor));
4485       break;
4486
4487     case PROP_HEIGHT:
4488       g_value_set_float (value, clutter_actor_get_height (actor));
4489       break;
4490
4491     case PROP_FIXED_X:
4492       {
4493         const ClutterLayoutInfo *info;
4494
4495         info = _clutter_actor_get_layout_info_or_defaults (actor);
4496         g_value_set_float (value, info->fixed_x);
4497       }
4498       break;
4499
4500     case PROP_FIXED_Y:
4501       {
4502         const ClutterLayoutInfo *info;
4503
4504         info = _clutter_actor_get_layout_info_or_defaults (actor);
4505         g_value_set_float (value, info->fixed_y);
4506       }
4507       break;
4508
4509     case PROP_FIXED_POSITION_SET:
4510       g_value_set_boolean (value, priv->position_set);
4511       break;
4512
4513     case PROP_MIN_WIDTH:
4514       {
4515         const ClutterLayoutInfo *info;
4516
4517         info = _clutter_actor_get_layout_info_or_defaults (actor);
4518         g_value_set_float (value, info->min_width);
4519       }
4520       break;
4521
4522     case PROP_MIN_HEIGHT:
4523       {
4524         const ClutterLayoutInfo *info;
4525
4526         info = _clutter_actor_get_layout_info_or_defaults (actor);
4527         g_value_set_float (value, info->min_height);
4528       }
4529       break;
4530
4531     case PROP_NATURAL_WIDTH:
4532       {
4533         const ClutterLayoutInfo *info;
4534
4535         info = _clutter_actor_get_layout_info_or_defaults (actor);
4536         g_value_set_float (value, info->natural_width);
4537       }
4538       break;
4539
4540     case PROP_NATURAL_HEIGHT:
4541       {
4542         const ClutterLayoutInfo *info;
4543
4544         info = _clutter_actor_get_layout_info_or_defaults (actor);
4545         g_value_set_float (value, info->natural_height);
4546       }
4547       break;
4548
4549     case PROP_MIN_WIDTH_SET:
4550       g_value_set_boolean (value, priv->min_width_set);
4551       break;
4552
4553     case PROP_MIN_HEIGHT_SET:
4554       g_value_set_boolean (value, priv->min_height_set);
4555       break;
4556
4557     case PROP_NATURAL_WIDTH_SET:
4558       g_value_set_boolean (value, priv->natural_width_set);
4559       break;
4560
4561     case PROP_NATURAL_HEIGHT_SET:
4562       g_value_set_boolean (value, priv->natural_height_set);
4563       break;
4564
4565     case PROP_REQUEST_MODE:
4566       g_value_set_enum (value, priv->request_mode);
4567       break;
4568
4569     case PROP_ALLOCATION:
4570       g_value_set_boxed (value, &priv->allocation);
4571       break;
4572
4573     case PROP_DEPTH:
4574       g_value_set_float (value, clutter_actor_get_depth (actor));
4575       break;
4576
4577     case PROP_OPACITY:
4578       g_value_set_uint (value, priv->opacity);
4579       break;
4580
4581     case PROP_OFFSCREEN_REDIRECT:
4582       g_value_set_enum (value, priv->offscreen_redirect);
4583       break;
4584
4585     case PROP_NAME:
4586       g_value_set_string (value, priv->name);
4587       break;
4588
4589     case PROP_VISIBLE:
4590       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4591       break;
4592
4593     case PROP_MAPPED:
4594       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4595       break;
4596
4597     case PROP_REALIZED:
4598       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4599       break;
4600
4601     case PROP_HAS_CLIP:
4602       g_value_set_boolean (value, priv->has_clip);
4603       break;
4604
4605     case PROP_CLIP:
4606       {
4607         ClutterGeometry clip;
4608
4609         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4610         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4611         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4612         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4613
4614         g_value_set_boxed (value, &clip);
4615       }
4616       break;
4617
4618     case PROP_CLIP_TO_ALLOCATION:
4619       g_value_set_boolean (value, priv->clip_to_allocation);
4620       break;
4621
4622     case PROP_SCALE_X:
4623       {
4624         const ClutterTransformInfo *info;
4625
4626         info = _clutter_actor_get_transform_info_or_defaults (actor);
4627         g_value_set_double (value, info->scale_x);
4628       }
4629       break;
4630
4631     case PROP_SCALE_Y:
4632       {
4633         const ClutterTransformInfo *info;
4634
4635         info = _clutter_actor_get_transform_info_or_defaults (actor);
4636         g_value_set_double (value, info->scale_y);
4637       }
4638       break;
4639
4640     case PROP_SCALE_CENTER_X:
4641       {
4642         gfloat center;
4643
4644         clutter_actor_get_scale_center (actor, &center, NULL);
4645
4646         g_value_set_float (value, center);
4647       }
4648       break;
4649
4650     case PROP_SCALE_CENTER_Y:
4651       {
4652         gfloat center;
4653
4654         clutter_actor_get_scale_center (actor, NULL, &center);
4655
4656         g_value_set_float (value, center);
4657       }
4658       break;
4659
4660     case PROP_SCALE_GRAVITY:
4661       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4662       break;
4663
4664     case PROP_REACTIVE:
4665       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4666       break;
4667
4668     case PROP_ROTATION_ANGLE_X:
4669       {
4670         const ClutterTransformInfo *info;
4671
4672         info = _clutter_actor_get_transform_info_or_defaults (actor);
4673         g_value_set_double (value, info->rx_angle);
4674       }
4675       break;
4676
4677     case PROP_ROTATION_ANGLE_Y:
4678       {
4679         const ClutterTransformInfo *info;
4680
4681         info = _clutter_actor_get_transform_info_or_defaults (actor);
4682         g_value_set_double (value, info->ry_angle);
4683       }
4684       break;
4685
4686     case PROP_ROTATION_ANGLE_Z:
4687       {
4688         const ClutterTransformInfo *info;
4689
4690         info = _clutter_actor_get_transform_info_or_defaults (actor);
4691         g_value_set_double (value, info->rz_angle);
4692       }
4693       break;
4694
4695     case PROP_ROTATION_CENTER_X:
4696       {
4697         ClutterVertex center;
4698
4699         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4700                                     &center.x,
4701                                     &center.y,
4702                                     &center.z);
4703
4704         g_value_set_boxed (value, &center);
4705       }
4706       break;
4707
4708     case PROP_ROTATION_CENTER_Y:
4709       {
4710         ClutterVertex center;
4711
4712         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4713                                     &center.x,
4714                                     &center.y,
4715                                     &center.z);
4716
4717         g_value_set_boxed (value, &center);
4718       }
4719       break;
4720
4721     case PROP_ROTATION_CENTER_Z:
4722       {
4723         ClutterVertex center;
4724
4725         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4726                                     &center.x,
4727                                     &center.y,
4728                                     &center.z);
4729
4730         g_value_set_boxed (value, &center);
4731       }
4732       break;
4733
4734     case PROP_ROTATION_CENTER_Z_GRAVITY:
4735       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4736       break;
4737
4738     case PROP_ANCHOR_X:
4739       {
4740         const ClutterTransformInfo *info;
4741         gfloat anchor_x;
4742
4743         info = _clutter_actor_get_transform_info_or_defaults (actor);
4744         clutter_anchor_coord_get_units (actor, &info->anchor,
4745                                         &anchor_x,
4746                                         NULL,
4747                                         NULL);
4748         g_value_set_float (value, anchor_x);
4749       }
4750       break;
4751
4752     case PROP_ANCHOR_Y:
4753       {
4754         const ClutterTransformInfo *info;
4755         gfloat anchor_y;
4756
4757         info = _clutter_actor_get_transform_info_or_defaults (actor);
4758         clutter_anchor_coord_get_units (actor, &info->anchor,
4759                                         NULL,
4760                                         &anchor_y,
4761                                         NULL);
4762         g_value_set_float (value, anchor_y);
4763       }
4764       break;
4765
4766     case PROP_ANCHOR_GRAVITY:
4767       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4768       break;
4769
4770     case PROP_SHOW_ON_SET_PARENT:
4771       g_value_set_boolean (value, priv->show_on_set_parent);
4772       break;
4773
4774     case PROP_TEXT_DIRECTION:
4775       g_value_set_enum (value, priv->text_direction);
4776       break;
4777
4778     case PROP_HAS_POINTER:
4779       g_value_set_boolean (value, priv->has_pointer);
4780       break;
4781
4782     case PROP_LAYOUT_MANAGER:
4783       g_value_set_object (value, priv->layout_manager);
4784       break;
4785
4786     case PROP_X_ALIGN:
4787       {
4788         const ClutterLayoutInfo *info;
4789
4790         info = _clutter_actor_get_layout_info_or_defaults (actor);
4791         g_value_set_enum (value, info->x_align);
4792       }
4793       break;
4794
4795     case PROP_Y_ALIGN:
4796       {
4797         const ClutterLayoutInfo *info;
4798
4799         info = _clutter_actor_get_layout_info_or_defaults (actor);
4800         g_value_set_enum (value, info->y_align);
4801       }
4802       break;
4803
4804     case PROP_MARGIN_TOP:
4805       {
4806         const ClutterLayoutInfo *info;
4807
4808         info = _clutter_actor_get_layout_info_or_defaults (actor);
4809         g_value_set_float (value, info->margin.top);
4810       }
4811       break;
4812
4813     case PROP_MARGIN_BOTTOM:
4814       {
4815         const ClutterLayoutInfo *info;
4816
4817         info = _clutter_actor_get_layout_info_or_defaults (actor);
4818         g_value_set_float (value, info->margin.bottom);
4819       }
4820       break;
4821
4822     case PROP_MARGIN_LEFT:
4823       {
4824         const ClutterLayoutInfo *info;
4825
4826         info = _clutter_actor_get_layout_info_or_defaults (actor);
4827         g_value_set_float (value, info->margin.left);
4828       }
4829       break;
4830
4831     case PROP_MARGIN_RIGHT:
4832       {
4833         const ClutterLayoutInfo *info;
4834
4835         info = _clutter_actor_get_layout_info_or_defaults (actor);
4836         g_value_set_float (value, info->margin.right);
4837       }
4838       break;
4839
4840     case PROP_BACKGROUND_COLOR_SET:
4841       g_value_set_boolean (value, priv->bg_color_set);
4842       break;
4843
4844     case PROP_BACKGROUND_COLOR:
4845       g_value_set_boxed (value, &priv->bg_color);
4846       break;
4847
4848     case PROP_FIRST_CHILD:
4849       g_value_set_object (value, priv->first_child);
4850       break;
4851
4852     case PROP_LAST_CHILD:
4853       g_value_set_object (value, priv->last_child);
4854       break;
4855
4856     case PROP_CONTENT:
4857       g_value_set_object (value, priv->content);
4858       break;
4859
4860     case PROP_CONTENT_GRAVITY:
4861       g_value_set_enum (value, priv->content_gravity);
4862       break;
4863
4864     case PROP_CONTENT_BOX:
4865       {
4866         ClutterActorBox box = { 0, };
4867
4868         clutter_actor_get_content_box (actor, &box);
4869         g_value_set_boxed (value, &box);
4870       }
4871       break;
4872
4873     default:
4874       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4875       break;
4876     }
4877 }
4878
4879 static void
4880 clutter_actor_dispose (GObject *object)
4881 {
4882   ClutterActor *self = CLUTTER_ACTOR (object);
4883   ClutterActorPrivate *priv = self->priv;
4884
4885   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4886                 priv->id,
4887                 g_type_name (G_OBJECT_TYPE (self)),
4888                 object->ref_count);
4889
4890   g_signal_emit (self, actor_signals[DESTROY], 0);
4891
4892   /* avoid recursing when called from clutter_actor_destroy() */
4893   if (priv->parent != NULL)
4894     {
4895       ClutterActor *parent = priv->parent;
4896
4897       /* go through the Container implementation unless this
4898        * is an internal child and has been marked as such.
4899        *
4900        * removing the actor from its parent will reset the
4901        * realized and mapped states.
4902        */
4903       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4904         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4905       else
4906         clutter_actor_remove_child_internal (parent, self,
4907                                              REMOVE_CHILD_LEGACY_FLAGS);
4908     }
4909
4910   /* parent must be gone at this point */
4911   g_assert (priv->parent == NULL);
4912
4913   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4914     {
4915       /* can't be mapped or realized with no parent */
4916       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4917       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4918     }
4919
4920   g_clear_object (&priv->pango_context);
4921   g_clear_object (&priv->actions);
4922   g_clear_object (&priv->constraints);
4923   g_clear_object (&priv->effects);
4924   g_clear_object (&priv->flatten_effect);
4925
4926   if (priv->layout_manager != NULL)
4927     {
4928       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4929       g_clear_object (&priv->layout_manager);
4930     }
4931
4932   if (priv->content != NULL)
4933     {
4934       _clutter_content_detached (priv->content, self);
4935       g_clear_object (&priv->content);
4936     }
4937
4938   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4939 }
4940
4941 static void
4942 clutter_actor_finalize (GObject *object)
4943 {
4944   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4945
4946   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4947                 priv->name != NULL ? priv->name : "<none>",
4948                 priv->id,
4949                 g_type_name (G_OBJECT_TYPE (object)));
4950
4951   _clutter_context_release_id (priv->id);
4952
4953   g_free (priv->name);
4954
4955   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4956 }
4957
4958
4959 /**
4960  * clutter_actor_get_accessible:
4961  * @self: a #ClutterActor
4962  *
4963  * Returns the accessible object that describes the actor to an
4964  * assistive technology.
4965  *
4966  * If no class-specific #AtkObject implementation is available for the
4967  * actor instance in question, it will inherit an #AtkObject
4968  * implementation from the first ancestor class for which such an
4969  * implementation is defined.
4970  *
4971  * The documentation of the <ulink
4972  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4973  * library contains more information about accessible objects and
4974  * their uses.
4975  *
4976  * Returns: (transfer none): the #AtkObject associated with @actor
4977  */
4978 AtkObject *
4979 clutter_actor_get_accessible (ClutterActor *self)
4980 {
4981   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4982
4983   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4984 }
4985
4986 static AtkObject *
4987 clutter_actor_real_get_accessible (ClutterActor *actor)
4988 {
4989   return atk_gobject_accessible_for_object (G_OBJECT (actor));
4990 }
4991
4992 static AtkObject *
4993 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4994 {
4995   AtkObject *accessible;
4996
4997   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4998   if (accessible != NULL)
4999     g_object_ref (accessible);
5000
5001   return accessible;
5002 }
5003
5004 static void
5005 atk_implementor_iface_init (AtkImplementorIface *iface)
5006 {
5007   iface->ref_accessible = _clutter_actor_ref_accessible;
5008 }
5009
5010 static gboolean
5011 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5012                                            ClutterPaintVolume *volume)
5013 {
5014   ClutterActorPrivate *priv = self->priv;
5015   gboolean res = FALSE;
5016
5017   /* we start from the allocation */
5018   clutter_paint_volume_set_width (volume,
5019                                   priv->allocation.x2 - priv->allocation.x1);
5020   clutter_paint_volume_set_height (volume,
5021                                    priv->allocation.y2 - priv->allocation.y1);
5022
5023   /* if the actor has a clip set then we have a pretty definite
5024    * size for the paint volume: the actor cannot possibly paint
5025    * outside the clip region.
5026    */
5027   if (priv->clip_to_allocation)
5028     {
5029       /* the allocation has already been set, so we just flip the
5030        * return value
5031        */
5032       res = TRUE;
5033     }
5034   else
5035     {
5036       ClutterActor *child;
5037
5038       if (priv->has_clip &&
5039           priv->clip.width >= 0 &&
5040           priv->clip.height >= 0)
5041         {
5042           ClutterVertex origin;
5043
5044           origin.x = priv->clip.x;
5045           origin.y = priv->clip.y;
5046           origin.z = 0;
5047
5048           clutter_paint_volume_set_origin (volume, &origin);
5049           clutter_paint_volume_set_width (volume, priv->clip.width);
5050           clutter_paint_volume_set_height (volume, priv->clip.height);
5051
5052           res = TRUE;
5053         }
5054
5055       /* if we don't have children we just bail out here... */
5056       if (priv->n_children == 0)
5057         return res;
5058
5059       /* ...but if we have children then we ask for their paint volume in
5060        * our coordinates. if any of our children replies that it doesn't
5061        * have a paint volume, we bail out
5062        */
5063       for (child = priv->first_child;
5064            child != NULL;
5065            child = child->priv->next_sibling)
5066         {
5067           const ClutterPaintVolume *child_volume;
5068
5069           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5070           if (child_volume == NULL)
5071             {
5072               res = FALSE;
5073               break;
5074             }
5075
5076           clutter_paint_volume_union (volume, child_volume);
5077           res = TRUE;
5078         }
5079     }
5080
5081   return res;
5082
5083 }
5084
5085 static gboolean
5086 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5087                                      ClutterPaintVolume *volume)
5088 {
5089   ClutterActorClass *klass;
5090   gboolean res;
5091
5092   klass = CLUTTER_ACTOR_GET_CLASS (self);
5093
5094   /* XXX - this thoroughly sucks, but we don't want to penalize users
5095    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5096    * redraw. This should go away in 2.0.
5097    */
5098   if (klass->paint == clutter_actor_real_paint &&
5099       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5100     {
5101       res = TRUE;
5102     }
5103   else
5104     {
5105       /* this is the default return value: we cannot know if a class
5106        * is going to paint outside its allocation, so we take the
5107        * conservative approach.
5108        */
5109       res = FALSE;
5110     }
5111
5112   if (clutter_actor_update_default_paint_volume (self, volume))
5113     return res;
5114
5115   return FALSE;
5116 }
5117
5118 /**
5119  * clutter_actor_get_default_paint_volume:
5120  * @self: a #ClutterActor
5121  *
5122  * Retrieves the default paint volume for @self.
5123  *
5124  * This function provides the same #ClutterPaintVolume that would be
5125  * computed by the default implementation inside #ClutterActor of the
5126  * #ClutterActorClass.get_paint_volume() virtual function.
5127  *
5128  * This function should only be used by #ClutterActor subclasses that
5129  * cannot chain up to the parent implementation when computing their
5130  * paint volume.
5131  *
5132  * Return value: (transfer none): a pointer to the default
5133  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5134  *   the actor could not compute a valid paint volume. The returned value
5135  *   is not guaranteed to be stable across multiple frames, so if you
5136  *   want to retain it, you will need to copy it using
5137  *   clutter_paint_volume_copy().
5138  *
5139  * Since: 1.10
5140  */
5141 const ClutterPaintVolume *
5142 clutter_actor_get_default_paint_volume (ClutterActor *self)
5143 {
5144   ClutterPaintVolume volume;
5145   ClutterPaintVolume *res;
5146
5147   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5148
5149   res = NULL;
5150   _clutter_paint_volume_init_static (&volume, self);
5151   if (clutter_actor_update_default_paint_volume (self, &volume))
5152     {
5153       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5154
5155       if (stage != NULL)
5156         {
5157           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5158           _clutter_paint_volume_copy_static (&volume, res);
5159         }
5160     }
5161
5162   clutter_paint_volume_free (&volume);
5163
5164   return res;
5165 }
5166
5167 static gboolean
5168 clutter_actor_real_has_overlaps (ClutterActor *self)
5169 {
5170   /* By default we'll assume that all actors need an offscreen redirect to get
5171    * the correct opacity. Actors such as ClutterTexture that would never need
5172    * an offscreen redirect can override this to return FALSE. */
5173   return TRUE;
5174 }
5175
5176 static void
5177 clutter_actor_real_destroy (ClutterActor *actor)
5178 {
5179   ClutterActorIter iter;
5180
5181   clutter_actor_iter_init (&iter, actor);
5182   while (clutter_actor_iter_next (&iter, NULL))
5183     clutter_actor_iter_destroy (&iter);
5184 }
5185
5186 static GObject *
5187 clutter_actor_constructor (GType gtype,
5188                            guint n_props,
5189                            GObjectConstructParam *props)
5190 {
5191   GObjectClass *gobject_class;
5192   ClutterActor *self;
5193   GObject *retval;
5194
5195   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5196   retval = gobject_class->constructor (gtype, n_props, props);
5197   self = CLUTTER_ACTOR (retval);
5198
5199   if (self->priv->layout_manager == NULL)
5200     {
5201       ClutterLayoutManager *default_layout;
5202
5203       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5204
5205       default_layout = clutter_fixed_layout_new ();
5206       clutter_actor_set_layout_manager (self, default_layout);
5207     }
5208
5209   return retval;
5210 }
5211
5212 static void
5213 clutter_actor_class_init (ClutterActorClass *klass)
5214 {
5215   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5216
5217   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5218   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5219   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5220   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5221
5222   object_class->constructor = clutter_actor_constructor;
5223   object_class->set_property = clutter_actor_set_property;
5224   object_class->get_property = clutter_actor_get_property;
5225   object_class->dispose = clutter_actor_dispose;
5226   object_class->finalize = clutter_actor_finalize;
5227
5228   klass->show = clutter_actor_real_show;
5229   klass->show_all = clutter_actor_show;
5230   klass->hide = clutter_actor_real_hide;
5231   klass->hide_all = clutter_actor_hide;
5232   klass->map = clutter_actor_real_map;
5233   klass->unmap = clutter_actor_real_unmap;
5234   klass->unrealize = clutter_actor_real_unrealize;
5235   klass->pick = clutter_actor_real_pick;
5236   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5237   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5238   klass->allocate = clutter_actor_real_allocate;
5239   klass->queue_redraw = clutter_actor_real_queue_redraw;
5240   klass->queue_relayout = clutter_actor_real_queue_relayout;
5241   klass->apply_transform = clutter_actor_real_apply_transform;
5242   klass->get_accessible = clutter_actor_real_get_accessible;
5243   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5244   klass->has_overlaps = clutter_actor_real_has_overlaps;
5245   klass->paint = clutter_actor_real_paint;
5246   klass->destroy = clutter_actor_real_destroy;
5247
5248   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5249
5250   /**
5251    * ClutterActor:x:
5252    *
5253    * X coordinate of the actor in pixels. If written, forces a fixed
5254    * position for the actor. If read, returns the fixed position if any,
5255    * otherwise the allocation if available, otherwise 0.
5256    *
5257    * The #ClutterActor:x property is animatable.
5258    */
5259   obj_props[PROP_X] =
5260     g_param_spec_float ("x",
5261                         P_("X coordinate"),
5262                         P_("X coordinate of the actor"),
5263                         -G_MAXFLOAT, G_MAXFLOAT,
5264                         0.0,
5265                         G_PARAM_READWRITE |
5266                         G_PARAM_STATIC_STRINGS |
5267                         CLUTTER_PARAM_ANIMATABLE);
5268
5269   /**
5270    * ClutterActor:y:
5271    *
5272    * Y coordinate of the actor in pixels. If written, forces a fixed
5273    * position for the actor.  If read, returns the fixed position if
5274    * any, otherwise the allocation if available, otherwise 0.
5275    *
5276    * The #ClutterActor:y property is animatable.
5277    */
5278   obj_props[PROP_Y] =
5279     g_param_spec_float ("y",
5280                         P_("Y coordinate"),
5281                         P_("Y coordinate of the actor"),
5282                         -G_MAXFLOAT, G_MAXFLOAT,
5283                         0.0,
5284                         G_PARAM_READWRITE |
5285                         G_PARAM_STATIC_STRINGS |
5286                         CLUTTER_PARAM_ANIMATABLE);
5287
5288   /**
5289    * ClutterActor:width:
5290    *
5291    * Width of the actor (in pixels). If written, forces the minimum and
5292    * natural size request of the actor to the given width. If read, returns
5293    * the allocated width if available, otherwise the width request.
5294    *
5295    * The #ClutterActor:width property is animatable.
5296    */
5297   obj_props[PROP_WIDTH] =
5298     g_param_spec_float ("width",
5299                         P_("Width"),
5300                         P_("Width of the actor"),
5301                         0.0, G_MAXFLOAT,
5302                         0.0,
5303                         G_PARAM_READWRITE |
5304                         G_PARAM_STATIC_STRINGS |
5305                         CLUTTER_PARAM_ANIMATABLE);
5306
5307   /**
5308    * ClutterActor:height:
5309    *
5310    * Height of the actor (in pixels).  If written, forces the minimum and
5311    * natural size request of the actor to the given height. If read, returns
5312    * the allocated height if available, otherwise the height request.
5313    *
5314    * The #ClutterActor:height property is animatable.
5315    */
5316   obj_props[PROP_HEIGHT] =
5317     g_param_spec_float ("height",
5318                         P_("Height"),
5319                         P_("Height of the actor"),
5320                         0.0, G_MAXFLOAT,
5321                         0.0,
5322                         G_PARAM_READWRITE |
5323                         G_PARAM_STATIC_STRINGS |
5324                         CLUTTER_PARAM_ANIMATABLE);
5325
5326   /**
5327    * ClutterActor:fixed-x:
5328    *
5329    * The fixed X position of the actor in pixels.
5330    *
5331    * Writing this property sets #ClutterActor:fixed-position-set
5332    * property as well, as a side effect
5333    *
5334    * Since: 0.8
5335    */
5336   obj_props[PROP_FIXED_X] =
5337     g_param_spec_float ("fixed-x",
5338                         P_("Fixed X"),
5339                         P_("Forced X position of the actor"),
5340                         -G_MAXFLOAT, G_MAXFLOAT,
5341                         0.0,
5342                         CLUTTER_PARAM_READWRITE);
5343
5344   /**
5345    * ClutterActor:fixed-y:
5346    *
5347    * The fixed Y position of the actor in pixels.
5348    *
5349    * Writing this property sets the #ClutterActor:fixed-position-set
5350    * property as well, as a side effect
5351    *
5352    * Since: 0.8
5353    */
5354   obj_props[PROP_FIXED_Y] =
5355     g_param_spec_float ("fixed-y",
5356                         P_("Fixed Y"),
5357                         P_("Forced Y position of the actor"),
5358                         -G_MAXFLOAT, G_MAXFLOAT,
5359                         0,
5360                         CLUTTER_PARAM_READWRITE);
5361
5362   /**
5363    * ClutterActor:fixed-position-set:
5364    *
5365    * This flag controls whether the #ClutterActor:fixed-x and
5366    * #ClutterActor:fixed-y properties are used
5367    *
5368    * Since: 0.8
5369    */
5370   obj_props[PROP_FIXED_POSITION_SET] =
5371     g_param_spec_boolean ("fixed-position-set",
5372                           P_("Fixed position set"),
5373                           P_("Whether to use fixed positioning for the actor"),
5374                           FALSE,
5375                           CLUTTER_PARAM_READWRITE);
5376
5377   /**
5378    * ClutterActor:min-width:
5379    *
5380    * A forced minimum width request for the actor, in pixels
5381    *
5382    * Writing this property sets the #ClutterActor:min-width-set property
5383    * as well, as a side effect.
5384    *
5385    *This property overrides the usual width request of the actor.
5386    *
5387    * Since: 0.8
5388    */
5389   obj_props[PROP_MIN_WIDTH] =
5390     g_param_spec_float ("min-width",
5391                         P_("Min Width"),
5392                         P_("Forced minimum width request for the actor"),
5393                         0.0, G_MAXFLOAT,
5394                         0.0,
5395                         CLUTTER_PARAM_READWRITE);
5396
5397   /**
5398    * ClutterActor:min-height:
5399    *
5400    * A forced minimum height request for the actor, in pixels
5401    *
5402    * Writing this property sets the #ClutterActor:min-height-set property
5403    * as well, as a side effect. This property overrides the usual height
5404    * request of the actor.
5405    *
5406    * Since: 0.8
5407    */
5408   obj_props[PROP_MIN_HEIGHT] =
5409     g_param_spec_float ("min-height",
5410                         P_("Min Height"),
5411                         P_("Forced minimum height request for the actor"),
5412                         0.0, G_MAXFLOAT,
5413                         0.0,
5414                         CLUTTER_PARAM_READWRITE);
5415
5416   /**
5417    * ClutterActor:natural-width:
5418    *
5419    * A forced natural width request for the actor, in pixels
5420    *
5421    * Writing this property sets the #ClutterActor:natural-width-set
5422    * property as well, as a side effect. This property overrides the
5423    * usual width request of the actor
5424    *
5425    * Since: 0.8
5426    */
5427   obj_props[PROP_NATURAL_WIDTH] =
5428     g_param_spec_float ("natural-width",
5429                         P_("Natural Width"),
5430                         P_("Forced natural width request for the actor"),
5431                         0.0, G_MAXFLOAT,
5432                         0.0,
5433                         CLUTTER_PARAM_READWRITE);
5434
5435   /**
5436    * ClutterActor:natural-height:
5437    *
5438    * A forced natural height request for the actor, in pixels
5439    *
5440    * Writing this property sets the #ClutterActor:natural-height-set
5441    * property as well, as a side effect. This property overrides the
5442    * usual height request of the actor
5443    *
5444    * Since: 0.8
5445    */
5446   obj_props[PROP_NATURAL_HEIGHT] =
5447     g_param_spec_float ("natural-height",
5448                         P_("Natural Height"),
5449                         P_("Forced natural height request for the actor"),
5450                         0.0, G_MAXFLOAT,
5451                         0.0,
5452                         CLUTTER_PARAM_READWRITE);
5453
5454   /**
5455    * ClutterActor:min-width-set:
5456    *
5457    * This flag controls whether the #ClutterActor:min-width property
5458    * is used
5459    *
5460    * Since: 0.8
5461    */
5462   obj_props[PROP_MIN_WIDTH_SET] =
5463     g_param_spec_boolean ("min-width-set",
5464                           P_("Minimum width set"),
5465                           P_("Whether to use the min-width property"),
5466                           FALSE,
5467                           CLUTTER_PARAM_READWRITE);
5468
5469   /**
5470    * ClutterActor:min-height-set:
5471    *
5472    * This flag controls whether the #ClutterActor:min-height property
5473    * is used
5474    *
5475    * Since: 0.8
5476    */
5477   obj_props[PROP_MIN_HEIGHT_SET] =
5478     g_param_spec_boolean ("min-height-set",
5479                           P_("Minimum height set"),
5480                           P_("Whether to use the min-height property"),
5481                           FALSE,
5482                           CLUTTER_PARAM_READWRITE);
5483
5484   /**
5485    * ClutterActor:natural-width-set:
5486    *
5487    * This flag controls whether the #ClutterActor:natural-width property
5488    * is used
5489    *
5490    * Since: 0.8
5491    */
5492   obj_props[PROP_NATURAL_WIDTH_SET] =
5493     g_param_spec_boolean ("natural-width-set",
5494                           P_("Natural width set"),
5495                           P_("Whether to use the natural-width property"),
5496                           FALSE,
5497                           CLUTTER_PARAM_READWRITE);
5498
5499   /**
5500    * ClutterActor:natural-height-set:
5501    *
5502    * This flag controls whether the #ClutterActor:natural-height property
5503    * is used
5504    *
5505    * Since: 0.8
5506    */
5507   obj_props[PROP_NATURAL_HEIGHT_SET] =
5508     g_param_spec_boolean ("natural-height-set",
5509                           P_("Natural height set"),
5510                           P_("Whether to use the natural-height property"),
5511                           FALSE,
5512                           CLUTTER_PARAM_READWRITE);
5513
5514   /**
5515    * ClutterActor:allocation:
5516    *
5517    * The allocation for the actor, in pixels
5518    *
5519    * This is property is read-only, but you might monitor it to know when an
5520    * actor moves or resizes
5521    *
5522    * Since: 0.8
5523    */
5524   obj_props[PROP_ALLOCATION] =
5525     g_param_spec_boxed ("allocation",
5526                         P_("Allocation"),
5527                         P_("The actor's allocation"),
5528                         CLUTTER_TYPE_ACTOR_BOX,
5529                         CLUTTER_PARAM_READABLE);
5530
5531   /**
5532    * ClutterActor:request-mode:
5533    *
5534    * Request mode for the #ClutterActor. The request mode determines the
5535    * type of geometry management used by the actor, either height for width
5536    * (the default) or width for height.
5537    *
5538    * For actors implementing height for width, the parent container should get
5539    * the preferred width first, and then the preferred height for that width.
5540    *
5541    * For actors implementing width for height, the parent container should get
5542    * the preferred height first, and then the preferred width for that height.
5543    *
5544    * For instance:
5545    *
5546    * |[
5547    *   ClutterRequestMode mode;
5548    *   gfloat natural_width, min_width;
5549    *   gfloat natural_height, min_height;
5550    *
5551    *   mode = clutter_actor_get_request_mode (child);
5552    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5553    *     {
5554    *       clutter_actor_get_preferred_width (child, -1,
5555    *                                          &amp;min_width,
5556    *                                          &amp;natural_width);
5557    *       clutter_actor_get_preferred_height (child, natural_width,
5558    *                                           &amp;min_height,
5559    *                                           &amp;natural_height);
5560    *     }
5561    *   else
5562    *     {
5563    *       clutter_actor_get_preferred_height (child, -1,
5564    *                                           &amp;min_height,
5565    *                                           &amp;natural_height);
5566    *       clutter_actor_get_preferred_width (child, natural_height,
5567    *                                          &amp;min_width,
5568    *                                          &amp;natural_width);
5569    *     }
5570    * ]|
5571    *
5572    * will retrieve the minimum and natural width and height depending on the
5573    * preferred request mode of the #ClutterActor "child".
5574    *
5575    * The clutter_actor_get_preferred_size() function will implement this
5576    * check for you.
5577    *
5578    * Since: 0.8
5579    */
5580   obj_props[PROP_REQUEST_MODE] =
5581     g_param_spec_enum ("request-mode",
5582                        P_("Request Mode"),
5583                        P_("The actor's request mode"),
5584                        CLUTTER_TYPE_REQUEST_MODE,
5585                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5586                        CLUTTER_PARAM_READWRITE);
5587
5588   /**
5589    * ClutterActor:depth:
5590    *
5591    * The position of the actor on the Z axis.
5592    *
5593    * The #ClutterActor:depth property is relative to the parent's
5594    * modelview matrix.
5595    *
5596    * The #ClutterActor:depth property is animatable.
5597    *
5598    * Since: 0.6
5599    */
5600   obj_props[PROP_DEPTH] =
5601     g_param_spec_float ("depth",
5602                         P_("Depth"),
5603                         P_("Position on the Z axis"),
5604                         -G_MAXFLOAT, G_MAXFLOAT,
5605                         0.0,
5606                         G_PARAM_READWRITE |
5607                         G_PARAM_STATIC_STRINGS |
5608                         CLUTTER_PARAM_ANIMATABLE);
5609
5610   /**
5611    * ClutterActor:opacity:
5612    *
5613    * Opacity of an actor, between 0 (fully transparent) and
5614    * 255 (fully opaque)
5615    *
5616    * The #ClutterActor:opacity property is animatable.
5617    */
5618   obj_props[PROP_OPACITY] =
5619     g_param_spec_uint ("opacity",
5620                        P_("Opacity"),
5621                        P_("Opacity of an actor"),
5622                        0, 255,
5623                        255,
5624                        G_PARAM_READWRITE |
5625                        G_PARAM_STATIC_STRINGS |
5626                        CLUTTER_PARAM_ANIMATABLE);
5627
5628   /**
5629    * ClutterActor:offscreen-redirect:
5630    *
5631    * Determines the conditions in which the actor will be redirected
5632    * to an offscreen framebuffer while being painted. For example this
5633    * can be used to cache an actor in a framebuffer or for improved
5634    * handling of transparent actors. See
5635    * clutter_actor_set_offscreen_redirect() for details.
5636    *
5637    * Since: 1.8
5638    */
5639   obj_props[PROP_OFFSCREEN_REDIRECT] =
5640     g_param_spec_flags ("offscreen-redirect",
5641                         P_("Offscreen redirect"),
5642                         P_("Flags controlling when to flatten the actor into a single image"),
5643                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5644                         0,
5645                         CLUTTER_PARAM_READWRITE);
5646
5647   /**
5648    * ClutterActor:visible:
5649    *
5650    * Whether the actor is set to be visible or not
5651    *
5652    * See also #ClutterActor:mapped
5653    */
5654   obj_props[PROP_VISIBLE] =
5655     g_param_spec_boolean ("visible",
5656                           P_("Visible"),
5657                           P_("Whether the actor is visible or not"),
5658                           FALSE,
5659                           CLUTTER_PARAM_READWRITE);
5660
5661   /**
5662    * ClutterActor:mapped:
5663    *
5664    * Whether the actor is mapped (will be painted when the stage
5665    * to which it belongs is mapped)
5666    *
5667    * Since: 1.0
5668    */
5669   obj_props[PROP_MAPPED] =
5670     g_param_spec_boolean ("mapped",
5671                           P_("Mapped"),
5672                           P_("Whether the actor will be painted"),
5673                           FALSE,
5674                           CLUTTER_PARAM_READABLE);
5675
5676   /**
5677    * ClutterActor:realized:
5678    *
5679    * Whether the actor has been realized
5680    *
5681    * Since: 1.0
5682    */
5683   obj_props[PROP_REALIZED] =
5684     g_param_spec_boolean ("realized",
5685                           P_("Realized"),
5686                           P_("Whether the actor has been realized"),
5687                           FALSE,
5688                           CLUTTER_PARAM_READABLE);
5689
5690   /**
5691    * ClutterActor:reactive:
5692    *
5693    * Whether the actor is reactive to events or not
5694    *
5695    * Only reactive actors will emit event-related signals
5696    *
5697    * Since: 0.6
5698    */
5699   obj_props[PROP_REACTIVE] =
5700     g_param_spec_boolean ("reactive",
5701                           P_("Reactive"),
5702                           P_("Whether the actor is reactive to events"),
5703                           FALSE,
5704                           CLUTTER_PARAM_READWRITE);
5705
5706   /**
5707    * ClutterActor:has-clip:
5708    *
5709    * Whether the actor has the #ClutterActor:clip property set or not
5710    */
5711   obj_props[PROP_HAS_CLIP] =
5712     g_param_spec_boolean ("has-clip",
5713                           P_("Has Clip"),
5714                           P_("Whether the actor has a clip set"),
5715                           FALSE,
5716                           CLUTTER_PARAM_READABLE);
5717
5718   /**
5719    * ClutterActor:clip:
5720    *
5721    * The clip region for the actor, in actor-relative coordinates
5722    *
5723    * Every part of the actor outside the clip region will not be
5724    * painted
5725    */
5726   obj_props[PROP_CLIP] =
5727     g_param_spec_boxed ("clip",
5728                         P_("Clip"),
5729                         P_("The clip region for the actor"),
5730                         CLUTTER_TYPE_GEOMETRY,
5731                         CLUTTER_PARAM_READWRITE);
5732
5733   /**
5734    * ClutterActor:name:
5735    *
5736    * The name of the actor
5737    *
5738    * Since: 0.2
5739    */
5740   obj_props[PROP_NAME] =
5741     g_param_spec_string ("name",
5742                          P_("Name"),
5743                          P_("Name of the actor"),
5744                          NULL,
5745                          CLUTTER_PARAM_READWRITE);
5746
5747   /**
5748    * ClutterActor:scale-x:
5749    *
5750    * The horizontal scale of the actor.
5751    *
5752    * The #ClutterActor:scale-x property is animatable.
5753    *
5754    * Since: 0.6
5755    */
5756   obj_props[PROP_SCALE_X] =
5757     g_param_spec_double ("scale-x",
5758                          P_("Scale X"),
5759                          P_("Scale factor on the X axis"),
5760                          0.0, G_MAXDOUBLE,
5761                          1.0,
5762                          G_PARAM_READWRITE |
5763                          G_PARAM_STATIC_STRINGS |
5764                          CLUTTER_PARAM_ANIMATABLE);
5765
5766   /**
5767    * ClutterActor:scale-y:
5768    *
5769    * The vertical scale of the actor.
5770    *
5771    * The #ClutterActor:scale-y property is animatable.
5772    *
5773    * Since: 0.6
5774    */
5775   obj_props[PROP_SCALE_Y] =
5776     g_param_spec_double ("scale-y",
5777                          P_("Scale Y"),
5778                          P_("Scale factor on the Y axis"),
5779                          0.0, G_MAXDOUBLE,
5780                          1.0,
5781                          G_PARAM_READWRITE |
5782                          G_PARAM_STATIC_STRINGS |
5783                          CLUTTER_PARAM_ANIMATABLE);
5784
5785   /**
5786    * ClutterActor:scale-center-x:
5787    *
5788    * The horizontal center point for scaling
5789    *
5790    * Since: 1.0
5791    */
5792   obj_props[PROP_SCALE_CENTER_X] =
5793     g_param_spec_float ("scale-center-x",
5794                         P_("Scale Center X"),
5795                         P_("Horizontal scale center"),
5796                         -G_MAXFLOAT, G_MAXFLOAT,
5797                         0.0,
5798                         CLUTTER_PARAM_READWRITE);
5799
5800   /**
5801    * ClutterActor:scale-center-y:
5802    *
5803    * The vertical center point for scaling
5804    *
5805    * Since: 1.0
5806    */
5807   obj_props[PROP_SCALE_CENTER_Y] =
5808     g_param_spec_float ("scale-center-y",
5809                         P_("Scale Center Y"),
5810                         P_("Vertical scale center"),
5811                         -G_MAXFLOAT, G_MAXFLOAT,
5812                         0.0,
5813                         CLUTTER_PARAM_READWRITE);
5814
5815   /**
5816    * ClutterActor:scale-gravity:
5817    *
5818    * The center point for scaling expressed as a #ClutterGravity
5819    *
5820    * Since: 1.0
5821    */
5822   obj_props[PROP_SCALE_GRAVITY] =
5823     g_param_spec_enum ("scale-gravity",
5824                        P_("Scale Gravity"),
5825                        P_("The center of scaling"),
5826                        CLUTTER_TYPE_GRAVITY,
5827                        CLUTTER_GRAVITY_NONE,
5828                        CLUTTER_PARAM_READWRITE);
5829
5830   /**
5831    * ClutterActor:rotation-angle-x:
5832    *
5833    * The rotation angle on the X axis.
5834    *
5835    * The #ClutterActor:rotation-angle-x property is animatable.
5836    *
5837    * Since: 0.6
5838    */
5839   obj_props[PROP_ROTATION_ANGLE_X] =
5840     g_param_spec_double ("rotation-angle-x",
5841                          P_("Rotation Angle X"),
5842                          P_("The rotation angle on the X axis"),
5843                          -G_MAXDOUBLE, G_MAXDOUBLE,
5844                          0.0,
5845                          G_PARAM_READWRITE |
5846                          G_PARAM_STATIC_STRINGS |
5847                          CLUTTER_PARAM_ANIMATABLE);
5848
5849   /**
5850    * ClutterActor:rotation-angle-y:
5851    *
5852    * The rotation angle on the Y axis
5853    *
5854    * The #ClutterActor:rotation-angle-y property is animatable.
5855    *
5856    * Since: 0.6
5857    */
5858   obj_props[PROP_ROTATION_ANGLE_Y] =
5859     g_param_spec_double ("rotation-angle-y",
5860                          P_("Rotation Angle Y"),
5861                          P_("The rotation angle on the Y axis"),
5862                          -G_MAXDOUBLE, G_MAXDOUBLE,
5863                          0.0,
5864                          G_PARAM_READWRITE |
5865                          G_PARAM_STATIC_STRINGS |
5866                          CLUTTER_PARAM_ANIMATABLE);
5867
5868   /**
5869    * ClutterActor:rotation-angle-z:
5870    *
5871    * The rotation angle on the Z axis
5872    *
5873    * The #ClutterActor:rotation-angle-z property is animatable.
5874    *
5875    * Since: 0.6
5876    */
5877   obj_props[PROP_ROTATION_ANGLE_Z] =
5878     g_param_spec_double ("rotation-angle-z",
5879                          P_("Rotation Angle Z"),
5880                          P_("The rotation angle on the Z axis"),
5881                          -G_MAXDOUBLE, G_MAXDOUBLE,
5882                          0.0,
5883                          G_PARAM_READWRITE |
5884                          G_PARAM_STATIC_STRINGS |
5885                          CLUTTER_PARAM_ANIMATABLE);
5886
5887   /**
5888    * ClutterActor:rotation-center-x:
5889    *
5890    * The rotation center on the X axis.
5891    *
5892    * Since: 0.6
5893    */
5894   obj_props[PROP_ROTATION_CENTER_X] =
5895     g_param_spec_boxed ("rotation-center-x",
5896                         P_("Rotation Center X"),
5897                         P_("The rotation center on the X axis"),
5898                         CLUTTER_TYPE_VERTEX,
5899                         CLUTTER_PARAM_READWRITE);
5900
5901   /**
5902    * ClutterActor:rotation-center-y:
5903    *
5904    * The rotation center on the Y axis.
5905    *
5906    * Since: 0.6
5907    */
5908   obj_props[PROP_ROTATION_CENTER_Y] =
5909     g_param_spec_boxed ("rotation-center-y",
5910                         P_("Rotation Center Y"),
5911                         P_("The rotation center on the Y axis"),
5912                         CLUTTER_TYPE_VERTEX,
5913                         CLUTTER_PARAM_READWRITE);
5914
5915   /**
5916    * ClutterActor:rotation-center-z:
5917    *
5918    * The rotation center on the Z axis.
5919    *
5920    * Since: 0.6
5921    */
5922   obj_props[PROP_ROTATION_CENTER_Z] =
5923     g_param_spec_boxed ("rotation-center-z",
5924                         P_("Rotation Center Z"),
5925                         P_("The rotation center on the Z axis"),
5926                         CLUTTER_TYPE_VERTEX,
5927                         CLUTTER_PARAM_READWRITE);
5928
5929   /**
5930    * ClutterActor:rotation-center-z-gravity:
5931    *
5932    * The rotation center on the Z axis expressed as a #ClutterGravity.
5933    *
5934    * Since: 1.0
5935    */
5936   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5937     g_param_spec_enum ("rotation-center-z-gravity",
5938                        P_("Rotation Center Z Gravity"),
5939                        P_("Center point for rotation around the Z axis"),
5940                        CLUTTER_TYPE_GRAVITY,
5941                        CLUTTER_GRAVITY_NONE,
5942                        CLUTTER_PARAM_READWRITE);
5943
5944   /**
5945    * ClutterActor:anchor-x:
5946    *
5947    * The X coordinate of an actor's anchor point, relative to
5948    * the actor coordinate space, in pixels
5949    *
5950    * Since: 0.8
5951    */
5952   obj_props[PROP_ANCHOR_X] =
5953     g_param_spec_float ("anchor-x",
5954                         P_("Anchor X"),
5955                         P_("X coordinate of the anchor point"),
5956                         -G_MAXFLOAT, G_MAXFLOAT,
5957                         0,
5958                         CLUTTER_PARAM_READWRITE);
5959
5960   /**
5961    * ClutterActor:anchor-y:
5962    *
5963    * The Y coordinate of an actor's anchor point, relative to
5964    * the actor coordinate space, in pixels
5965    *
5966    * Since: 0.8
5967    */
5968   obj_props[PROP_ANCHOR_Y] =
5969     g_param_spec_float ("anchor-y",
5970                         P_("Anchor Y"),
5971                         P_("Y coordinate of the anchor point"),
5972                         -G_MAXFLOAT, G_MAXFLOAT,
5973                         0,
5974                         CLUTTER_PARAM_READWRITE);
5975
5976   /**
5977    * ClutterActor:anchor-gravity:
5978    *
5979    * The anchor point expressed as a #ClutterGravity
5980    *
5981    * Since: 1.0
5982    */
5983   obj_props[PROP_ANCHOR_GRAVITY] =
5984     g_param_spec_enum ("anchor-gravity",
5985                        P_("Anchor Gravity"),
5986                        P_("The anchor point as a ClutterGravity"),
5987                        CLUTTER_TYPE_GRAVITY,
5988                        CLUTTER_GRAVITY_NONE,
5989                        CLUTTER_PARAM_READWRITE);
5990
5991   /**
5992    * ClutterActor:show-on-set-parent:
5993    *
5994    * If %TRUE, the actor is automatically shown when parented.
5995    *
5996    * Calling clutter_actor_hide() on an actor which has not been
5997    * parented will set this property to %FALSE as a side effect.
5998    *
5999    * Since: 0.8
6000    */
6001   obj_props[PROP_SHOW_ON_SET_PARENT] =
6002     g_param_spec_boolean ("show-on-set-parent",
6003                           P_("Show on set parent"),
6004                           P_("Whether the actor is shown when parented"),
6005                           TRUE,
6006                           CLUTTER_PARAM_READWRITE);
6007
6008   /**
6009    * ClutterActor:clip-to-allocation:
6010    *
6011    * Whether the clip region should track the allocated area
6012    * of the actor.
6013    *
6014    * This property is ignored if a clip area has been explicitly
6015    * set using clutter_actor_set_clip().
6016    *
6017    * Since: 1.0
6018    */
6019   obj_props[PROP_CLIP_TO_ALLOCATION] =
6020     g_param_spec_boolean ("clip-to-allocation",
6021                           P_("Clip to Allocation"),
6022                           P_("Sets the clip region to track the actor's allocation"),
6023                           FALSE,
6024                           CLUTTER_PARAM_READWRITE);
6025
6026   /**
6027    * ClutterActor:text-direction:
6028    *
6029    * The direction of the text inside a #ClutterActor.
6030    *
6031    * Since: 1.0
6032    */
6033   obj_props[PROP_TEXT_DIRECTION] =
6034     g_param_spec_enum ("text-direction",
6035                        P_("Text Direction"),
6036                        P_("Direction of the text"),
6037                        CLUTTER_TYPE_TEXT_DIRECTION,
6038                        CLUTTER_TEXT_DIRECTION_LTR,
6039                        CLUTTER_PARAM_READWRITE);
6040
6041   /**
6042    * ClutterActor:has-pointer:
6043    *
6044    * Whether the actor contains the pointer of a #ClutterInputDevice
6045    * or not.
6046    *
6047    * Since: 1.2
6048    */
6049   obj_props[PROP_HAS_POINTER] =
6050     g_param_spec_boolean ("has-pointer",
6051                           P_("Has Pointer"),
6052                           P_("Whether the actor contains the pointer of an input device"),
6053                           FALSE,
6054                           CLUTTER_PARAM_READABLE);
6055
6056   /**
6057    * ClutterActor:actions:
6058    *
6059    * Adds a #ClutterAction to the actor
6060    *
6061    * Since: 1.4
6062    */
6063   obj_props[PROP_ACTIONS] =
6064     g_param_spec_object ("actions",
6065                          P_("Actions"),
6066                          P_("Adds an action to the actor"),
6067                          CLUTTER_TYPE_ACTION,
6068                          CLUTTER_PARAM_WRITABLE);
6069
6070   /**
6071    * ClutterActor:constraints:
6072    *
6073    * Adds a #ClutterConstraint to the actor
6074    *
6075    * Since: 1.4
6076    */
6077   obj_props[PROP_CONSTRAINTS] =
6078     g_param_spec_object ("constraints",
6079                          P_("Constraints"),
6080                          P_("Adds a constraint to the actor"),
6081                          CLUTTER_TYPE_CONSTRAINT,
6082                          CLUTTER_PARAM_WRITABLE);
6083
6084   /**
6085    * ClutterActor:effect:
6086    *
6087    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6088    *
6089    * Since: 1.4
6090    */
6091   obj_props[PROP_EFFECT] =
6092     g_param_spec_object ("effect",
6093                          P_("Effect"),
6094                          P_("Add an effect to be applied on the actor"),
6095                          CLUTTER_TYPE_EFFECT,
6096                          CLUTTER_PARAM_WRITABLE);
6097
6098   /**
6099    * ClutterActor:layout-manager:
6100    *
6101    * A delegate object for controlling the layout of the children of
6102    * an actor.
6103    *
6104    * Since: 1.10
6105    */
6106   obj_props[PROP_LAYOUT_MANAGER] =
6107     g_param_spec_object ("layout-manager",
6108                          P_("Layout Manager"),
6109                          P_("The object controlling the layout of an actor's children"),
6110                          CLUTTER_TYPE_LAYOUT_MANAGER,
6111                          CLUTTER_PARAM_READWRITE);
6112
6113
6114   /**
6115    * ClutterActor:x-align:
6116    *
6117    * The alignment of an actor on the X axis, if the actor has been given
6118    * extra space for its allocation.
6119    *
6120    * Since: 1.10
6121    */
6122   obj_props[PROP_X_ALIGN] =
6123     g_param_spec_enum ("x-align",
6124                        P_("X Alignment"),
6125                        P_("The alignment of the actor on the X axis within its allocation"),
6126                        CLUTTER_TYPE_ACTOR_ALIGN,
6127                        CLUTTER_ACTOR_ALIGN_FILL,
6128                        CLUTTER_PARAM_READWRITE);
6129
6130   /**
6131    * ClutterActor:y-align:
6132    *
6133    * The alignment of an actor on the Y axis, if the actor has been given
6134    * extra space for its allocation.
6135    *
6136    * Since: 1.10
6137    */
6138   obj_props[PROP_Y_ALIGN] =
6139     g_param_spec_enum ("y-align",
6140                        P_("Y Alignment"),
6141                        P_("The alignment of the actor on the Y axis within its allocation"),
6142                        CLUTTER_TYPE_ACTOR_ALIGN,
6143                        CLUTTER_ACTOR_ALIGN_FILL,
6144                        CLUTTER_PARAM_READWRITE);
6145
6146   /**
6147    * ClutterActor:margin-top:
6148    *
6149    * The margin (in pixels) from the top of the actor.
6150    *
6151    * This property adds a margin to the actor's preferred size; the margin
6152    * will be automatically taken into account when allocating the actor.
6153    *
6154    * Since: 1.10
6155    */
6156   obj_props[PROP_MARGIN_TOP] =
6157     g_param_spec_float ("margin-top",
6158                         P_("Margin Top"),
6159                         P_("Extra space at the top"),
6160                         0.0, G_MAXFLOAT,
6161                         0.0,
6162                         CLUTTER_PARAM_READWRITE);
6163
6164   /**
6165    * ClutterActor:margin-bottom:
6166    *
6167    * The margin (in pixels) from the bottom of the actor.
6168    *
6169    * This property adds a margin to the actor's preferred size; the margin
6170    * will be automatically taken into account when allocating the actor.
6171    *
6172    * Since: 1.10
6173    */
6174   obj_props[PROP_MARGIN_BOTTOM] =
6175     g_param_spec_float ("margin-bottom",
6176                         P_("Margin Bottom"),
6177                         P_("Extra space at the bottom"),
6178                         0.0, G_MAXFLOAT,
6179                         0.0,
6180                         CLUTTER_PARAM_READWRITE);
6181
6182   /**
6183    * ClutterActor:margin-left:
6184    *
6185    * The margin (in pixels) from the left of the actor.
6186    *
6187    * This property adds a margin to the actor's preferred size; the margin
6188    * will be automatically taken into account when allocating the actor.
6189    *
6190    * Since: 1.10
6191    */
6192   obj_props[PROP_MARGIN_LEFT] =
6193     g_param_spec_float ("margin-left",
6194                         P_("Margin Left"),
6195                         P_("Extra space at the left"),
6196                         0.0, G_MAXFLOAT,
6197                         0.0,
6198                         CLUTTER_PARAM_READWRITE);
6199
6200   /**
6201    * ClutterActor:margin-right:
6202    *
6203    * The margin (in pixels) from the right of the actor.
6204    *
6205    * This property adds a margin to the actor's preferred size; the margin
6206    * will be automatically taken into account when allocating the actor.
6207    *
6208    * Since: 1.10
6209    */
6210   obj_props[PROP_MARGIN_RIGHT] =
6211     g_param_spec_float ("margin-right",
6212                         P_("Margin Right"),
6213                         P_("Extra space at the right"),
6214                         0.0, G_MAXFLOAT,
6215                         0.0,
6216                         CLUTTER_PARAM_READWRITE);
6217
6218   /**
6219    * ClutterActor:background-color-set:
6220    *
6221    * Whether the #ClutterActor:background-color property has been set.
6222    *
6223    * Since: 1.10
6224    */
6225   obj_props[PROP_BACKGROUND_COLOR_SET] =
6226     g_param_spec_boolean ("background-color-set",
6227                           P_("Background Color Set"),
6228                           P_("Whether the background color is set"),
6229                           FALSE,
6230                           CLUTTER_PARAM_READABLE);
6231
6232   /**
6233    * ClutterActor:background-color:
6234    *
6235    * Paints a solid fill of the actor's allocation using the specified
6236    * color.
6237    *
6238    * The #ClutterActor:background-color property is animatable.
6239    *
6240    * Since: 1.10
6241    */
6242   obj_props[PROP_BACKGROUND_COLOR] =
6243     clutter_param_spec_color ("background-color",
6244                               P_("Background color"),
6245                               P_("The actor's background color"),
6246                               CLUTTER_COLOR_Transparent,
6247                               G_PARAM_READWRITE |
6248                               G_PARAM_STATIC_STRINGS |
6249                               CLUTTER_PARAM_ANIMATABLE);
6250
6251   /**
6252    * ClutterActor:first-child:
6253    *
6254    * The actor's first child.
6255    *
6256    * Since: 1.10
6257    */
6258   obj_props[PROP_FIRST_CHILD] =
6259     g_param_spec_object ("first-child",
6260                          P_("First Child"),
6261                          P_("The actor's first child"),
6262                          CLUTTER_TYPE_ACTOR,
6263                          CLUTTER_PARAM_READABLE);
6264
6265   /**
6266    * ClutterActor:last-child:
6267    *
6268    * The actor's last child.
6269    *
6270    * Since: 1.10
6271    */
6272   obj_props[PROP_LAST_CHILD] =
6273     g_param_spec_object ("last-child",
6274                          P_("Last Child"),
6275                          P_("The actor's last child"),
6276                          CLUTTER_TYPE_ACTOR,
6277                          CLUTTER_PARAM_READABLE);
6278
6279   /**
6280    * ClutterActor:content:
6281    *
6282    * The #ClutterContent implementation that controls the content
6283    * of the actor.
6284    *
6285    * Since: 1.10
6286    */
6287   obj_props[PROP_CONTENT] =
6288     g_param_spec_object ("content",
6289                          P_("Content"),
6290                          P_("Delegate object for painting the actor's content"),
6291                          CLUTTER_TYPE_CONTENT,
6292                          CLUTTER_PARAM_READWRITE);
6293
6294   /**
6295    * ClutterActor:content-gravity:
6296    *
6297    * The alignment that should be honoured by the #ClutterContent
6298    * set with the #ClutterActor:content property.
6299    *
6300    * Changing the value of this property will change the bounding box of
6301    * the content; you can use the #ClutterActor:content-box property to
6302    * get the position and size of the content within the actor's
6303    * allocation.
6304    *
6305    * This property is meaningful only for #ClutterContent implementations
6306    * that have a preferred size, and if the preferred size is smaller than
6307    * the actor's allocation.
6308    *
6309    * Since: 1.10
6310    */
6311   obj_props[PROP_CONTENT_GRAVITY] =
6312     g_param_spec_enum ("content-gravity",
6313                        P_("Content Gravity"),
6314                        P_("Alignment of the actor's content"),
6315                        CLUTTER_TYPE_CONTENT_GRAVITY,
6316                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6317                        CLUTTER_PARAM_READWRITE);
6318
6319   /**
6320    * ClutterActor:content-box:
6321    *
6322    * The bounding box for the #ClutterContent used by the actor.
6323    *
6324    * The value of this property is controlled by the #ClutterActor:allocation
6325    * and #ClutterActor:content-gravity properties of #ClutterActor.
6326    *
6327    * The bounding box for the content is guaranteed to never exceed the
6328    * allocation's of the actor.
6329    *
6330    * Since: 1.10
6331    */
6332   obj_props[PROP_CONTENT_BOX] =
6333     g_param_spec_boxed ("content-box",
6334                         P_("Content Box"),
6335                         P_("The bounding box of the actor's content"),
6336                         CLUTTER_TYPE_ACTOR_BOX,
6337                         CLUTTER_PARAM_READABLE);
6338
6339   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6340
6341   /**
6342    * ClutterActor::destroy:
6343    * @actor: the #ClutterActor which emitted the signal
6344    *
6345    * The ::destroy signal notifies that all references held on the
6346    * actor which emitted it should be released.
6347    *
6348    * The ::destroy signal should be used by all holders of a reference
6349    * on @actor.
6350    *
6351    * This signal might result in the finalization of the #ClutterActor
6352    * if all references are released.
6353    *
6354    * Composite actors and actors implementing the #ClutterContainer
6355    * interface should override the default implementation of the
6356    * class handler of this signal and call clutter_actor_destroy() on
6357    * their children. When overriding the default class handler, it is
6358    * required to chain up to the parent's implementation.
6359    *
6360    * Since: 0.2
6361    */
6362   actor_signals[DESTROY] =
6363     g_signal_new (I_("destroy"),
6364                   G_TYPE_FROM_CLASS (object_class),
6365                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6366                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6367                   NULL, NULL,
6368                   _clutter_marshal_VOID__VOID,
6369                   G_TYPE_NONE, 0);
6370   /**
6371    * ClutterActor::show:
6372    * @actor: the object which received the signal
6373    *
6374    * The ::show signal is emitted when an actor is visible and
6375    * rendered on the stage.
6376    *
6377    * Since: 0.2
6378    */
6379   actor_signals[SHOW] =
6380     g_signal_new (I_("show"),
6381                   G_TYPE_FROM_CLASS (object_class),
6382                   G_SIGNAL_RUN_FIRST,
6383                   G_STRUCT_OFFSET (ClutterActorClass, show),
6384                   NULL, NULL,
6385                   _clutter_marshal_VOID__VOID,
6386                   G_TYPE_NONE, 0);
6387   /**
6388    * ClutterActor::hide:
6389    * @actor: the object which received the signal
6390    *
6391    * The ::hide signal is emitted when an actor is no longer rendered
6392    * on the stage.
6393    *
6394    * Since: 0.2
6395    */
6396   actor_signals[HIDE] =
6397     g_signal_new (I_("hide"),
6398                   G_TYPE_FROM_CLASS (object_class),
6399                   G_SIGNAL_RUN_FIRST,
6400                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6401                   NULL, NULL,
6402                   _clutter_marshal_VOID__VOID,
6403                   G_TYPE_NONE, 0);
6404   /**
6405    * ClutterActor::parent-set:
6406    * @actor: the object which received the signal
6407    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6408    *
6409    * This signal is emitted when the parent of the actor changes.
6410    *
6411    * Since: 0.2
6412    */
6413   actor_signals[PARENT_SET] =
6414     g_signal_new (I_("parent-set"),
6415                   G_TYPE_FROM_CLASS (object_class),
6416                   G_SIGNAL_RUN_LAST,
6417                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6418                   NULL, NULL,
6419                   _clutter_marshal_VOID__OBJECT,
6420                   G_TYPE_NONE, 1,
6421                   CLUTTER_TYPE_ACTOR);
6422
6423   /**
6424    * ClutterActor::queue-redraw:
6425    * @actor: the actor we're bubbling the redraw request through
6426    * @origin: the actor which initiated the redraw request
6427    *
6428    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6429    * is called on @origin.
6430    *
6431    * The default implementation for #ClutterActor chains up to the
6432    * parent actor and queues a redraw on the parent, thus "bubbling"
6433    * the redraw queue up through the actor graph. The default
6434    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6435    * in a main loop idle handler.
6436    *
6437    * Note that the @origin actor may be the stage, or a container; it
6438    * does not have to be a leaf node in the actor graph.
6439    *
6440    * Toolkits embedding a #ClutterStage which require a redraw and
6441    * relayout cycle can stop the emission of this signal using the
6442    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6443    * themselves, like:
6444    *
6445    * |[
6446    *   static void
6447    *   on_redraw_complete (gpointer data)
6448    *   {
6449    *     ClutterStage *stage = data;
6450    *
6451    *     /&ast; execute the Clutter drawing pipeline &ast;/
6452    *     clutter_stage_ensure_redraw (stage);
6453    *   }
6454    *
6455    *   static void
6456    *   on_stage_queue_redraw (ClutterStage *stage)
6457    *   {
6458    *     /&ast; this prevents the default handler to run &ast;/
6459    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6460    *
6461    *     /&ast; queue a redraw with the host toolkit and call
6462    *      &ast; a function when the redraw has been completed
6463    *      &ast;/
6464    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6465    *   }
6466    * ]|
6467    *
6468    * <note><para>This signal is emitted before the Clutter paint
6469    * pipeline is executed. If you want to know when the pipeline has
6470    * been completed you should connect to the ::paint signal on the
6471    * Stage with g_signal_connect_after().</para></note>
6472    *
6473    * Since: 1.0
6474    */
6475   actor_signals[QUEUE_REDRAW] =
6476     g_signal_new (I_("queue-redraw"),
6477                   G_TYPE_FROM_CLASS (object_class),
6478                   G_SIGNAL_RUN_LAST |
6479                   G_SIGNAL_NO_HOOKS,
6480                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6481                   NULL, NULL,
6482                   _clutter_marshal_VOID__OBJECT,
6483                   G_TYPE_NONE, 1,
6484                   CLUTTER_TYPE_ACTOR);
6485
6486   /**
6487    * ClutterActor::queue-relayout
6488    * @actor: the actor being queued for relayout
6489    *
6490    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6491    * is called on an actor.
6492    *
6493    * The default implementation for #ClutterActor chains up to the
6494    * parent actor and queues a relayout on the parent, thus "bubbling"
6495    * the relayout queue up through the actor graph.
6496    *
6497    * The main purpose of this signal is to allow relayout to be propagated
6498    * properly in the procense of #ClutterClone actors. Applications will
6499    * not normally need to connect to this signal.
6500    *
6501    * Since: 1.2
6502    */
6503   actor_signals[QUEUE_RELAYOUT] =
6504     g_signal_new (I_("queue-relayout"),
6505                   G_TYPE_FROM_CLASS (object_class),
6506                   G_SIGNAL_RUN_LAST |
6507                   G_SIGNAL_NO_HOOKS,
6508                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6509                   NULL, NULL,
6510                   _clutter_marshal_VOID__VOID,
6511                   G_TYPE_NONE, 0);
6512
6513   /**
6514    * ClutterActor::event:
6515    * @actor: the actor which received the event
6516    * @event: a #ClutterEvent
6517    *
6518    * The ::event signal is emitted each time an event is received
6519    * by the @actor. This signal will be emitted on every actor,
6520    * following the hierarchy chain, until it reaches the top-level
6521    * container (the #ClutterStage).
6522    *
6523    * Return value: %TRUE if the event has been handled by the actor,
6524    *   or %FALSE to continue the emission.
6525    *
6526    * Since: 0.6
6527    */
6528   actor_signals[EVENT] =
6529     g_signal_new (I_("event"),
6530                   G_TYPE_FROM_CLASS (object_class),
6531                   G_SIGNAL_RUN_LAST,
6532                   G_STRUCT_OFFSET (ClutterActorClass, event),
6533                   _clutter_boolean_handled_accumulator, NULL,
6534                   _clutter_marshal_BOOLEAN__BOXED,
6535                   G_TYPE_BOOLEAN, 1,
6536                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6537   /**
6538    * ClutterActor::button-press-event:
6539    * @actor: the actor which received the event
6540    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6541    *
6542    * The ::button-press-event signal is emitted each time a mouse button
6543    * is pressed on @actor.
6544    *
6545    * Return value: %TRUE if the event has been handled by the actor,
6546    *   or %FALSE to continue the emission.
6547    *
6548    * Since: 0.6
6549    */
6550   actor_signals[BUTTON_PRESS_EVENT] =
6551     g_signal_new (I_("button-press-event"),
6552                   G_TYPE_FROM_CLASS (object_class),
6553                   G_SIGNAL_RUN_LAST,
6554                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6555                   _clutter_boolean_handled_accumulator, NULL,
6556                   _clutter_marshal_BOOLEAN__BOXED,
6557                   G_TYPE_BOOLEAN, 1,
6558                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6559   /**
6560    * ClutterActor::button-release-event:
6561    * @actor: the actor which received the event
6562    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6563    *
6564    * The ::button-release-event signal is emitted each time a mouse button
6565    * is released on @actor.
6566    *
6567    * Return value: %TRUE if the event has been handled by the actor,
6568    *   or %FALSE to continue the emission.
6569    *
6570    * Since: 0.6
6571    */
6572   actor_signals[BUTTON_RELEASE_EVENT] =
6573     g_signal_new (I_("button-release-event"),
6574                   G_TYPE_FROM_CLASS (object_class),
6575                   G_SIGNAL_RUN_LAST,
6576                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6577                   _clutter_boolean_handled_accumulator, NULL,
6578                   _clutter_marshal_BOOLEAN__BOXED,
6579                   G_TYPE_BOOLEAN, 1,
6580                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6581   /**
6582    * ClutterActor::scroll-event:
6583    * @actor: the actor which received the event
6584    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6585    *
6586    * The ::scroll-event signal is emitted each time the mouse is
6587    * scrolled on @actor
6588    *
6589    * Return value: %TRUE if the event has been handled by the actor,
6590    *   or %FALSE to continue the emission.
6591    *
6592    * Since: 0.6
6593    */
6594   actor_signals[SCROLL_EVENT] =
6595     g_signal_new (I_("scroll-event"),
6596                   G_TYPE_FROM_CLASS (object_class),
6597                   G_SIGNAL_RUN_LAST,
6598                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6599                   _clutter_boolean_handled_accumulator, NULL,
6600                   _clutter_marshal_BOOLEAN__BOXED,
6601                   G_TYPE_BOOLEAN, 1,
6602                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6603   /**
6604    * ClutterActor::key-press-event:
6605    * @actor: the actor which received the event
6606    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6607    *
6608    * The ::key-press-event signal is emitted each time a keyboard button
6609    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6610    *
6611    * Return value: %TRUE if the event has been handled by the actor,
6612    *   or %FALSE to continue the emission.
6613    *
6614    * Since: 0.6
6615    */
6616   actor_signals[KEY_PRESS_EVENT] =
6617     g_signal_new (I_("key-press-event"),
6618                   G_TYPE_FROM_CLASS (object_class),
6619                   G_SIGNAL_RUN_LAST,
6620                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6621                   _clutter_boolean_handled_accumulator, NULL,
6622                   _clutter_marshal_BOOLEAN__BOXED,
6623                   G_TYPE_BOOLEAN, 1,
6624                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6625   /**
6626    * ClutterActor::key-release-event:
6627    * @actor: the actor which received the event
6628    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6629    *
6630    * The ::key-release-event signal is emitted each time a keyboard button
6631    * is released while @actor has key focus (see
6632    * clutter_stage_set_key_focus()).
6633    *
6634    * Return value: %TRUE if the event has been handled by the actor,
6635    *   or %FALSE to continue the emission.
6636    *
6637    * Since: 0.6
6638    */
6639   actor_signals[KEY_RELEASE_EVENT] =
6640     g_signal_new (I_("key-release-event"),
6641                   G_TYPE_FROM_CLASS (object_class),
6642                   G_SIGNAL_RUN_LAST,
6643                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6644                   _clutter_boolean_handled_accumulator, NULL,
6645                   _clutter_marshal_BOOLEAN__BOXED,
6646                   G_TYPE_BOOLEAN, 1,
6647                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6648   /**
6649    * ClutterActor::motion-event:
6650    * @actor: the actor which received the event
6651    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6652    *
6653    * The ::motion-event signal is emitted each time the mouse pointer is
6654    * moved over @actor.
6655    *
6656    * Return value: %TRUE if the event has been handled by the actor,
6657    *   or %FALSE to continue the emission.
6658    *
6659    * Since: 0.6
6660    */
6661   actor_signals[MOTION_EVENT] =
6662     g_signal_new (I_("motion-event"),
6663                   G_TYPE_FROM_CLASS (object_class),
6664                   G_SIGNAL_RUN_LAST,
6665                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6666                   _clutter_boolean_handled_accumulator, NULL,
6667                   _clutter_marshal_BOOLEAN__BOXED,
6668                   G_TYPE_BOOLEAN, 1,
6669                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6670
6671   /**
6672    * ClutterActor::key-focus-in:
6673    * @actor: the actor which now has key focus
6674    *
6675    * The ::key-focus-in signal is emitted when @actor receives key focus.
6676    *
6677    * Since: 0.6
6678    */
6679   actor_signals[KEY_FOCUS_IN] =
6680     g_signal_new (I_("key-focus-in"),
6681                   G_TYPE_FROM_CLASS (object_class),
6682                   G_SIGNAL_RUN_LAST,
6683                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6684                   NULL, NULL,
6685                   _clutter_marshal_VOID__VOID,
6686                   G_TYPE_NONE, 0);
6687
6688   /**
6689    * ClutterActor::key-focus-out:
6690    * @actor: the actor which now has key focus
6691    *
6692    * The ::key-focus-out signal is emitted when @actor loses key focus.
6693    *
6694    * Since: 0.6
6695    */
6696   actor_signals[KEY_FOCUS_OUT] =
6697     g_signal_new (I_("key-focus-out"),
6698                   G_TYPE_FROM_CLASS (object_class),
6699                   G_SIGNAL_RUN_LAST,
6700                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6701                   NULL, NULL,
6702                   _clutter_marshal_VOID__VOID,
6703                   G_TYPE_NONE, 0);
6704
6705   /**
6706    * ClutterActor::enter-event:
6707    * @actor: the actor which the pointer has entered.
6708    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6709    *
6710    * The ::enter-event signal is emitted when the pointer enters the @actor
6711    *
6712    * Return value: %TRUE if the event has been handled by the actor,
6713    *   or %FALSE to continue the emission.
6714    *
6715    * Since: 0.6
6716    */
6717   actor_signals[ENTER_EVENT] =
6718     g_signal_new (I_("enter-event"),
6719                   G_TYPE_FROM_CLASS (object_class),
6720                   G_SIGNAL_RUN_LAST,
6721                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6722                   _clutter_boolean_handled_accumulator, NULL,
6723                   _clutter_marshal_BOOLEAN__BOXED,
6724                   G_TYPE_BOOLEAN, 1,
6725                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6726
6727   /**
6728    * ClutterActor::leave-event:
6729    * @actor: the actor which the pointer has left
6730    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6731    *
6732    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6733    *
6734    * Return value: %TRUE if the event has been handled by the actor,
6735    *   or %FALSE to continue the emission.
6736    *
6737    * Since: 0.6
6738    */
6739   actor_signals[LEAVE_EVENT] =
6740     g_signal_new (I_("leave-event"),
6741                   G_TYPE_FROM_CLASS (object_class),
6742                   G_SIGNAL_RUN_LAST,
6743                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6744                   _clutter_boolean_handled_accumulator, NULL,
6745                   _clutter_marshal_BOOLEAN__BOXED,
6746                   G_TYPE_BOOLEAN, 1,
6747                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6748
6749   /**
6750    * ClutterActor::captured-event:
6751    * @actor: the actor which received the signal
6752    * @event: a #ClutterEvent
6753    *
6754    * The ::captured-event signal is emitted when an event is captured
6755    * by Clutter. This signal will be emitted starting from the top-level
6756    * container (the #ClutterStage) to the actor which received the event
6757    * going down the hierarchy. This signal can be used to intercept every
6758    * event before the specialized events (like
6759    * ClutterActor::button-press-event or ::key-released-event) are
6760    * emitted.
6761    *
6762    * Return value: %TRUE if the event has been handled by the actor,
6763    *   or %FALSE to continue the emission.
6764    *
6765    * Since: 0.6
6766    */
6767   actor_signals[CAPTURED_EVENT] =
6768     g_signal_new (I_("captured-event"),
6769                   G_TYPE_FROM_CLASS (object_class),
6770                   G_SIGNAL_RUN_LAST,
6771                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6772                   _clutter_boolean_handled_accumulator, NULL,
6773                   _clutter_marshal_BOOLEAN__BOXED,
6774                   G_TYPE_BOOLEAN, 1,
6775                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6776
6777   /**
6778    * ClutterActor::paint:
6779    * @actor: the #ClutterActor that received the signal
6780    *
6781    * The ::paint signal is emitted each time an actor is being painted.
6782    *
6783    * Subclasses of #ClutterActor should override the class signal handler
6784    * and paint themselves in that function.
6785    *
6786    * It is possible to connect a handler to the ::paint signal in order
6787    * to set up some custom aspect of a paint.
6788    *
6789    * Since: 0.8
6790    */
6791   actor_signals[PAINT] =
6792     g_signal_new (I_("paint"),
6793                   G_TYPE_FROM_CLASS (object_class),
6794                   G_SIGNAL_RUN_LAST |
6795                   G_SIGNAL_NO_HOOKS,
6796                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6797                   NULL, NULL,
6798                   _clutter_marshal_VOID__VOID,
6799                   G_TYPE_NONE, 0);
6800   /**
6801    * ClutterActor::realize:
6802    * @actor: the #ClutterActor that received the signal
6803    *
6804    * The ::realize signal is emitted each time an actor is being
6805    * realized.
6806    *
6807    * Since: 0.8
6808    */
6809   actor_signals[REALIZE] =
6810     g_signal_new (I_("realize"),
6811                   G_TYPE_FROM_CLASS (object_class),
6812                   G_SIGNAL_RUN_LAST,
6813                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6814                   NULL, NULL,
6815                   _clutter_marshal_VOID__VOID,
6816                   G_TYPE_NONE, 0);
6817   /**
6818    * ClutterActor::unrealize:
6819    * @actor: the #ClutterActor that received the signal
6820    *
6821    * The ::unrealize signal is emitted each time an actor is being
6822    * unrealized.
6823    *
6824    * Since: 0.8
6825    */
6826   actor_signals[UNREALIZE] =
6827     g_signal_new (I_("unrealize"),
6828                   G_TYPE_FROM_CLASS (object_class),
6829                   G_SIGNAL_RUN_LAST,
6830                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6831                   NULL, NULL,
6832                   _clutter_marshal_VOID__VOID,
6833                   G_TYPE_NONE, 0);
6834
6835   /**
6836    * ClutterActor::pick:
6837    * @actor: the #ClutterActor that received the signal
6838    * @color: the #ClutterColor to be used when picking
6839    *
6840    * The ::pick signal is emitted each time an actor is being painted
6841    * in "pick mode". The pick mode is used to identify the actor during
6842    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6843    * The actor should paint its shape using the passed @pick_color.
6844    *
6845    * Subclasses of #ClutterActor should override the class signal handler
6846    * and paint themselves in that function.
6847    *
6848    * It is possible to connect a handler to the ::pick signal in order
6849    * to set up some custom aspect of a paint in pick mode.
6850    *
6851    * Since: 1.0
6852    */
6853   actor_signals[PICK] =
6854     g_signal_new (I_("pick"),
6855                   G_TYPE_FROM_CLASS (object_class),
6856                   G_SIGNAL_RUN_LAST,
6857                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6858                   NULL, NULL,
6859                   _clutter_marshal_VOID__BOXED,
6860                   G_TYPE_NONE, 1,
6861                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6862
6863   /**
6864    * ClutterActor::allocation-changed:
6865    * @actor: the #ClutterActor that emitted the signal
6866    * @box: a #ClutterActorBox with the new allocation
6867    * @flags: #ClutterAllocationFlags for the allocation
6868    *
6869    * The ::allocation-changed signal is emitted when the
6870    * #ClutterActor:allocation property changes. Usually, application
6871    * code should just use the notifications for the :allocation property
6872    * but if you want to track the allocation flags as well, for instance
6873    * to know whether the absolute origin of @actor changed, then you might
6874    * want use this signal instead.
6875    *
6876    * Since: 1.0
6877    */
6878   actor_signals[ALLOCATION_CHANGED] =
6879     g_signal_new (I_("allocation-changed"),
6880                   G_TYPE_FROM_CLASS (object_class),
6881                   G_SIGNAL_RUN_LAST,
6882                   0,
6883                   NULL, NULL,
6884                   _clutter_marshal_VOID__BOXED_FLAGS,
6885                   G_TYPE_NONE, 2,
6886                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6887                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6888 }
6889
6890 static void
6891 clutter_actor_init (ClutterActor *self)
6892 {
6893   ClutterActorPrivate *priv;
6894
6895   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6896
6897   priv->id = _clutter_context_acquire_id (self);
6898   priv->pick_id = -1;
6899
6900   priv->opacity = 0xff;
6901   priv->show_on_set_parent = TRUE;
6902
6903   priv->needs_width_request = TRUE;
6904   priv->needs_height_request = TRUE;
6905   priv->needs_allocation = TRUE;
6906
6907   priv->cached_width_age = 1;
6908   priv->cached_height_age = 1;
6909
6910   priv->opacity_override = -1;
6911   priv->enable_model_view_transform = TRUE;
6912
6913   /* Initialize an empty paint volume to start with */
6914   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6915   priv->last_paint_volume_valid = TRUE;
6916
6917   priv->transform_valid = FALSE;
6918
6919   /* the default is to stretch the content, to match the
6920    * current behaviour of basically all actors. also, it's
6921    * the easiest thing to compute.
6922    */
6923   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
6924 }
6925
6926 /**
6927  * clutter_actor_new:
6928  *
6929  * Creates a new #ClutterActor.
6930  *
6931  * A newly created actor has a floating reference, which will be sunk
6932  * when it is added to another actor.
6933  *
6934  * Return value: (transfer full): the newly created #ClutterActor
6935  *
6936  * Since: 1.10
6937  */
6938 ClutterActor *
6939 clutter_actor_new (void)
6940 {
6941   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6942 }
6943
6944 /**
6945  * clutter_actor_destroy:
6946  * @self: a #ClutterActor
6947  *
6948  * Destroys an actor.  When an actor is destroyed, it will break any
6949  * references it holds to other objects.  If the actor is inside a
6950  * container, the actor will be removed.
6951  *
6952  * When you destroy a container, its children will be destroyed as well.
6953  *
6954  * Note: you cannot destroy the #ClutterStage returned by
6955  * clutter_stage_get_default().
6956  */
6957 void
6958 clutter_actor_destroy (ClutterActor *self)
6959 {
6960   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6961
6962   g_object_ref (self);
6963
6964   /* avoid recursion while destroying */
6965   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6966     {
6967       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6968
6969       g_object_run_dispose (G_OBJECT (self));
6970
6971       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6972     }
6973
6974   g_object_unref (self);
6975 }
6976
6977 void
6978 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6979                                     ClutterPaintVolume *clip)
6980 {
6981   ClutterActorPrivate *priv = self->priv;
6982   ClutterPaintVolume *pv;
6983   gboolean clipped;
6984
6985   /* Remove queue entry early in the process, otherwise a new
6986      queue_redraw() during signal handling could put back this
6987      object in the stage redraw list (but the entry is freed as
6988      soon as we return from this function, causing a segfault
6989      later)
6990   */
6991   priv->queue_redraw_entry = NULL;
6992
6993   /* If we've been explicitly passed a clip volume then there's
6994    * nothing more to calculate, but otherwise the only thing we know
6995    * is that the change is constrained to the given actor.
6996    *
6997    * The idea is that if we know the paint volume for where the actor
6998    * was last drawn (in eye coordinates) and we also have the paint
6999    * volume for where it will be drawn next (in actor coordinates)
7000    * then if we queue a redraw for both these volumes that will cover
7001    * everything that needs to be redrawn to clear the old view and
7002    * show the latest view of the actor.
7003    *
7004    * Don't clip this redraw if we don't know what position we had for
7005    * the previous redraw since we don't know where to set the clip so
7006    * it will clear the actor as it is currently.
7007    */
7008   if (clip)
7009     {
7010       _clutter_actor_set_queue_redraw_clip (self, clip);
7011       clipped = TRUE;
7012     }
7013   else if (G_LIKELY (priv->last_paint_volume_valid))
7014     {
7015       pv = _clutter_actor_get_paint_volume_mutable (self);
7016       if (pv)
7017         {
7018           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7019
7020           /* make sure we redraw the actors old position... */
7021           _clutter_actor_set_queue_redraw_clip (stage,
7022                                                 &priv->last_paint_volume);
7023           _clutter_actor_signal_queue_redraw (stage, stage);
7024           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7025
7026           /* XXX: Ideally the redraw signal would take a clip volume
7027            * argument, but that would be an ABI break. Until we can
7028            * break the ABI we pass the argument out-of-band
7029            */
7030
7031           /* setup the clip for the actors new position... */
7032           _clutter_actor_set_queue_redraw_clip (self, pv);
7033           clipped = TRUE;
7034         }
7035       else
7036         clipped = FALSE;
7037     }
7038   else
7039     clipped = FALSE;
7040
7041   _clutter_actor_signal_queue_redraw (self, self);
7042
7043   /* Just in case anyone is manually firing redraw signals without
7044    * using the public queue_redraw() API we are careful to ensure that
7045    * our out-of-band clip member is cleared before returning...
7046    *
7047    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7048    */
7049   if (G_LIKELY (clipped))
7050     _clutter_actor_set_queue_redraw_clip (self, NULL);
7051 }
7052
7053 static void
7054 _clutter_actor_get_allocation_clip (ClutterActor *self,
7055                                     ClutterActorBox *clip)
7056 {
7057   ClutterActorBox allocation;
7058
7059   /* XXX: we don't care if we get an out of date allocation here
7060    * because clutter_actor_queue_redraw_with_clip knows to ignore
7061    * the clip if the actor's allocation is invalid.
7062    *
7063    * This is noted because clutter_actor_get_allocation_box does some
7064    * unnecessary work to support buggy code with a comment suggesting
7065    * that it could be changed later which would be good for this use
7066    * case!
7067    */
7068   clutter_actor_get_allocation_box (self, &allocation);
7069
7070   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7071    * actor's own coordinate space but the allocation is in parent
7072    * coordinates */
7073   clip->x1 = 0;
7074   clip->y1 = 0;
7075   clip->x2 = allocation.x2 - allocation.x1;
7076   clip->y2 = allocation.y2 - allocation.y1;
7077 }
7078
7079 void
7080 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7081                                   ClutterRedrawFlags  flags,
7082                                   ClutterPaintVolume *volume,
7083                                   ClutterEffect      *effect)
7084 {
7085   ClutterActorPrivate *priv = self->priv;
7086   ClutterPaintVolume allocation_pv;
7087   ClutterPaintVolume *pv;
7088   gboolean should_free_pv;
7089   ClutterActor *stage;
7090
7091   /* Here's an outline of the actor queue redraw mechanism:
7092    *
7093    * The process starts in one of the following two functions which
7094    * are wrappers for this function:
7095    * clutter_actor_queue_redraw
7096    * _clutter_actor_queue_redraw_with_clip
7097    *
7098    * additionally, an effect can queue a redraw by wrapping this
7099    * function in clutter_effect_queue_rerun
7100    *
7101    * This functions queues an entry in a list associated with the
7102    * stage which is a list of actors that queued a redraw while
7103    * updating the timelines, performing layouting and processing other
7104    * mainloop sources before the next paint starts.
7105    *
7106    * We aim to minimize the processing done at this point because
7107    * there is a good chance other events will happen while updating
7108    * the scenegraph that would invalidate any expensive work we might
7109    * otherwise try to do here. For example we don't try and resolve
7110    * the screen space bounding box of an actor at this stage so as to
7111    * minimize how much of the screen redraw because it's possible
7112    * something else will happen which will force a full redraw anyway.
7113    *
7114    * When all updates are complete and we come to paint the stage then
7115    * we iterate this list and actually emit the "queue-redraw" signals
7116    * for each of the listed actors which will bubble up to the stage
7117    * for each actor and at that point we will transform the actors
7118    * paint volume into screen coordinates to determine the clip region
7119    * for what needs to be redrawn in the next paint.
7120    *
7121    * Besides minimizing redundant work another reason for this
7122    * deferred design is that it's more likely we will be able to
7123    * determine the paint volume of an actor once we've finished
7124    * updating the scenegraph because its allocation should be up to
7125    * date. NB: If we can't determine an actors paint volume then we
7126    * can't automatically queue a clipped redraw which can make a big
7127    * difference to performance.
7128    *
7129    * So the control flow goes like this:
7130    * One of clutter_actor_queue_redraw,
7131    *        _clutter_actor_queue_redraw_with_clip
7132    *     or clutter_effect_queue_rerun
7133    *
7134    * then control moves to:
7135    *   _clutter_stage_queue_actor_redraw
7136    *
7137    * later during _clutter_stage_do_update, once relayouting is done
7138    * and the scenegraph has been updated we will call:
7139    * _clutter_stage_finish_queue_redraws
7140    *
7141    * _clutter_stage_finish_queue_redraws will call
7142    * _clutter_actor_finish_queue_redraw for each listed actor.
7143    * Note: actors *are* allowed to queue further redraws during this
7144    * process (considering clone actors or texture_new_from_actor which
7145    * respond to their source queueing a redraw by queuing a redraw
7146    * themselves). We repeat the process until the list is empty.
7147    *
7148    * This will result in the "queue-redraw" signal being fired for
7149    * each actor which will pass control to the default signal handler:
7150    * clutter_actor_real_queue_redraw
7151    *
7152    * This will bubble up to the stages handler:
7153    * clutter_stage_real_queue_redraw
7154    *
7155    * clutter_stage_real_queue_redraw will transform the actors paint
7156    * volume into screen space and add it as a clip region for the next
7157    * paint.
7158    */
7159
7160   /* ignore queueing a redraw for actors being destroyed */
7161   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7162     return;
7163
7164   stage = _clutter_actor_get_stage_internal (self);
7165
7166   /* Ignore queueing a redraw for actors not descended from a stage */
7167   if (stage == NULL)
7168     return;
7169
7170   /* ignore queueing a redraw on stages that are being destroyed */
7171   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7172     return;
7173
7174   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7175     {
7176       ClutterActorBox allocation_clip;
7177       ClutterVertex origin;
7178
7179       /* If the actor doesn't have a valid allocation then we will
7180        * queue a full stage redraw. */
7181       if (priv->needs_allocation)
7182         {
7183           /* NB: NULL denotes an undefined clip which will result in a
7184            * full redraw... */
7185           _clutter_actor_set_queue_redraw_clip (self, NULL);
7186           _clutter_actor_signal_queue_redraw (self, self);
7187           return;
7188         }
7189
7190       _clutter_paint_volume_init_static (&allocation_pv, self);
7191       pv = &allocation_pv;
7192
7193       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7194
7195       origin.x = allocation_clip.x1;
7196       origin.y = allocation_clip.y1;
7197       origin.z = 0;
7198       clutter_paint_volume_set_origin (pv, &origin);
7199       clutter_paint_volume_set_width (pv,
7200                                       allocation_clip.x2 - allocation_clip.x1);
7201       clutter_paint_volume_set_height (pv,
7202                                        allocation_clip.y2 -
7203                                        allocation_clip.y1);
7204       should_free_pv = TRUE;
7205     }
7206   else
7207     {
7208       pv = volume;
7209       should_free_pv = FALSE;
7210     }
7211
7212   self->priv->queue_redraw_entry =
7213     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7214                                        priv->queue_redraw_entry,
7215                                        self,
7216                                        pv);
7217
7218   if (should_free_pv)
7219     clutter_paint_volume_free (pv);
7220
7221   /* If this is the first redraw queued then we can directly use the
7222      effect parameter */
7223   if (!priv->is_dirty)
7224     priv->effect_to_redraw = effect;
7225   /* Otherwise we need to merge it with the existing effect parameter */
7226   else if (effect != NULL)
7227     {
7228       /* If there's already an effect then we need to use whichever is
7229          later in the chain of actors. Otherwise a full redraw has
7230          already been queued on the actor so we need to ignore the
7231          effect parameter */
7232       if (priv->effect_to_redraw != NULL)
7233         {
7234           if (priv->effects == NULL)
7235             g_warning ("Redraw queued with an effect that is "
7236                        "not applied to the actor");
7237           else
7238             {
7239               const GList *l;
7240
7241               for (l = _clutter_meta_group_peek_metas (priv->effects);
7242                    l != NULL;
7243                    l = l->next)
7244                 {
7245                   if (l->data == priv->effect_to_redraw ||
7246                       l->data == effect)
7247                     priv->effect_to_redraw = l->data;
7248                 }
7249             }
7250         }
7251     }
7252   else
7253     {
7254       /* If no effect is specified then we need to redraw the whole
7255          actor */
7256       priv->effect_to_redraw = NULL;
7257     }
7258
7259   priv->is_dirty = TRUE;
7260 }
7261
7262 /**
7263  * clutter_actor_queue_redraw:
7264  * @self: A #ClutterActor
7265  *
7266  * Queues up a redraw of an actor and any children. The redraw occurs
7267  * once the main loop becomes idle (after the current batch of events
7268  * has been processed, roughly).
7269  *
7270  * Applications rarely need to call this, as redraws are handled
7271  * automatically by modification functions.
7272  *
7273  * This function will not do anything if @self is not visible, or
7274  * if the actor is inside an invisible part of the scenegraph.
7275  *
7276  * Also be aware that painting is a NOP for actors with an opacity of
7277  * 0
7278  *
7279  * When you are implementing a custom actor you must queue a redraw
7280  * whenever some private state changes that will affect painting or
7281  * picking of your actor.
7282  */
7283 void
7284 clutter_actor_queue_redraw (ClutterActor *self)
7285 {
7286   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7287
7288   _clutter_actor_queue_redraw_full (self,
7289                                     0, /* flags */
7290                                     NULL, /* clip volume */
7291                                     NULL /* effect */);
7292 }
7293
7294 /*< private >
7295  * _clutter_actor_queue_redraw_with_clip:
7296  * @self: A #ClutterActor
7297  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7298  *   this queue redraw.
7299  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7300  *   redrawn or %NULL if you are just using a @flag to state your
7301  *   desired clipping.
7302  *
7303  * Queues up a clipped redraw of an actor and any children. The redraw
7304  * occurs once the main loop becomes idle (after the current batch of
7305  * events has been processed, roughly).
7306  *
7307  * If no flags are given the clip volume is defined by @volume
7308  * specified in actor coordinates and tells Clutter that only content
7309  * within this volume has been changed so Clutter can optionally
7310  * optimize the redraw.
7311  *
7312  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7313  * should be %NULL and this tells Clutter to use the actor's current
7314  * allocation as a clip box. This flag can only be used for 2D actors,
7315  * because any actor with depth may be projected outside its
7316  * allocation.
7317  *
7318  * Applications rarely need to call this, as redraws are handled
7319  * automatically by modification functions.
7320  *
7321  * This function will not do anything if @self is not visible, or if
7322  * the actor is inside an invisible part of the scenegraph.
7323  *
7324  * Also be aware that painting is a NOP for actors with an opacity of
7325  * 0
7326  *
7327  * When you are implementing a custom actor you must queue a redraw
7328  * whenever some private state changes that will affect painting or
7329  * picking of your actor.
7330  */
7331 void
7332 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7333                                        ClutterRedrawFlags  flags,
7334                                        ClutterPaintVolume *volume)
7335 {
7336   _clutter_actor_queue_redraw_full (self,
7337                                     flags, /* flags */
7338                                     volume, /* clip volume */
7339                                     NULL /* effect */);
7340 }
7341
7342 static void
7343 _clutter_actor_queue_only_relayout (ClutterActor *self)
7344 {
7345   ClutterActorPrivate *priv = self->priv;
7346
7347   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7348     return;
7349
7350   if (priv->needs_width_request &&
7351       priv->needs_height_request &&
7352       priv->needs_allocation)
7353     return; /* save some cpu cycles */
7354
7355 #if CLUTTER_ENABLE_DEBUG
7356   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7357     {
7358       g_warning ("The actor '%s' is currently inside an allocation "
7359                  "cycle; calling clutter_actor_queue_relayout() is "
7360                  "not recommended",
7361                  _clutter_actor_get_debug_name (self));
7362     }
7363 #endif /* CLUTTER_ENABLE_DEBUG */
7364
7365   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7366 }
7367
7368 /**
7369  * clutter_actor_queue_redraw_with_clip:
7370  * @self: a #ClutterActor
7371  * @clip: (allow-none): a rectangular clip region, or %NULL
7372  *
7373  * Queues a redraw on @self limited to a specific, actor-relative
7374  * rectangular area.
7375  *
7376  * If @clip is %NULL this function is equivalent to
7377  * clutter_actor_queue_redraw().
7378  *
7379  * Since: 1.10
7380  */
7381 void
7382 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7383                                       const cairo_rectangle_int_t *clip)
7384 {
7385   ClutterPaintVolume volume;
7386   ClutterVertex origin;
7387
7388   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7389
7390   if (clip == NULL)
7391     {
7392       clutter_actor_queue_redraw (self);
7393       return;
7394     }
7395
7396   _clutter_paint_volume_init_static (&volume, self);
7397
7398   origin.x = clip->x;
7399   origin.y = clip->y;
7400   origin.z = 0.0f;
7401
7402   clutter_paint_volume_set_origin (&volume, &origin);
7403   clutter_paint_volume_set_width (&volume, clip->width);
7404   clutter_paint_volume_set_height (&volume, clip->height);
7405
7406   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7407
7408   clutter_paint_volume_free (&volume);
7409 }
7410
7411 /**
7412  * clutter_actor_queue_relayout:
7413  * @self: A #ClutterActor
7414  *
7415  * Indicates that the actor's size request or other layout-affecting
7416  * properties may have changed. This function is used inside #ClutterActor
7417  * subclass implementations, not by applications directly.
7418  *
7419  * Queueing a new layout automatically queues a redraw as well.
7420  *
7421  * Since: 0.8
7422  */
7423 void
7424 clutter_actor_queue_relayout (ClutterActor *self)
7425 {
7426   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7427
7428   _clutter_actor_queue_only_relayout (self);
7429   clutter_actor_queue_redraw (self);
7430 }
7431
7432 /**
7433  * clutter_actor_get_preferred_size:
7434  * @self: a #ClutterActor
7435  * @min_width_p: (out) (allow-none): return location for the minimum
7436  *   width, or %NULL
7437  * @min_height_p: (out) (allow-none): return location for the minimum
7438  *   height, or %NULL
7439  * @natural_width_p: (out) (allow-none): return location for the natural
7440  *   width, or %NULL
7441  * @natural_height_p: (out) (allow-none): return location for the natural
7442  *   height, or %NULL
7443  *
7444  * Computes the preferred minimum and natural size of an actor, taking into
7445  * account the actor's geometry management (either height-for-width
7446  * or width-for-height).
7447  *
7448  * The width and height used to compute the preferred height and preferred
7449  * width are the actor's natural ones.
7450  *
7451  * If you need to control the height for the preferred width, or the width for
7452  * the preferred height, you should use clutter_actor_get_preferred_width()
7453  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7454  * geometry management using the #ClutterActor:request-mode property.
7455  *
7456  * Since: 0.8
7457  */
7458 void
7459 clutter_actor_get_preferred_size (ClutterActor *self,
7460                                   gfloat       *min_width_p,
7461                                   gfloat       *min_height_p,
7462                                   gfloat       *natural_width_p,
7463                                   gfloat       *natural_height_p)
7464 {
7465   ClutterActorPrivate *priv;
7466   gfloat min_width, min_height;
7467   gfloat natural_width, natural_height;
7468
7469   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7470
7471   priv = self->priv;
7472
7473   min_width = min_height = 0;
7474   natural_width = natural_height = 0;
7475
7476   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7477     {
7478       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7479       clutter_actor_get_preferred_width (self, -1,
7480                                          &min_width,
7481                                          &natural_width);
7482       clutter_actor_get_preferred_height (self, natural_width,
7483                                           &min_height,
7484                                           &natural_height);
7485     }
7486   else
7487     {
7488       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7489       clutter_actor_get_preferred_height (self, -1,
7490                                           &min_height,
7491                                           &natural_height);
7492       clutter_actor_get_preferred_width (self, natural_height,
7493                                          &min_width,
7494                                          &natural_width);
7495     }
7496
7497   if (min_width_p)
7498     *min_width_p = min_width;
7499
7500   if (min_height_p)
7501     *min_height_p = min_height;
7502
7503   if (natural_width_p)
7504     *natural_width_p = natural_width;
7505
7506   if (natural_height_p)
7507     *natural_height_p = natural_height;
7508 }
7509
7510 /*< private >
7511  * effective_align:
7512  * @align: a #ClutterActorAlign
7513  * @direction: a #ClutterTextDirection
7514  *
7515  * Retrieves the correct alignment depending on the text direction
7516  *
7517  * Return value: the effective alignment
7518  */
7519 static ClutterActorAlign
7520 effective_align (ClutterActorAlign    align,
7521                  ClutterTextDirection direction)
7522 {
7523   ClutterActorAlign res;
7524
7525   switch (align)
7526     {
7527     case CLUTTER_ACTOR_ALIGN_START:
7528       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7529           ? CLUTTER_ACTOR_ALIGN_END
7530           : CLUTTER_ACTOR_ALIGN_START;
7531       break;
7532
7533     case CLUTTER_ACTOR_ALIGN_END:
7534       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7535           ? CLUTTER_ACTOR_ALIGN_START
7536           : CLUTTER_ACTOR_ALIGN_END;
7537       break;
7538
7539     default:
7540       res = align;
7541       break;
7542     }
7543
7544   return res;
7545 }
7546
7547 static inline void
7548 adjust_for_margin (float  margin_start,
7549                    float  margin_end,
7550                    float *minimum_size,
7551                    float *natural_size,
7552                    float *allocated_start,
7553                    float *allocated_end)
7554 {
7555   *minimum_size -= (margin_start + margin_end);
7556   *natural_size -= (margin_start + margin_end);
7557   *allocated_start += margin_start;
7558   *allocated_end -= margin_end;
7559 }
7560
7561 static inline void
7562 adjust_for_alignment (ClutterActorAlign  alignment,
7563                       float              natural_size,
7564                       float             *allocated_start,
7565                       float             *allocated_end)
7566 {
7567   float allocated_size = *allocated_end - *allocated_start;
7568
7569   switch (alignment)
7570     {
7571     case CLUTTER_ACTOR_ALIGN_FILL:
7572       /* do nothing */
7573       break;
7574
7575     case CLUTTER_ACTOR_ALIGN_START:
7576       /* keep start */
7577       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7578       break;
7579
7580     case CLUTTER_ACTOR_ALIGN_END:
7581       if (allocated_size > natural_size)
7582         {
7583           *allocated_start += (allocated_size - natural_size);
7584           *allocated_end = *allocated_start + natural_size;
7585         }
7586       break;
7587
7588     case CLUTTER_ACTOR_ALIGN_CENTER:
7589       if (allocated_size > natural_size)
7590         {
7591           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7592           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7593         }
7594       break;
7595     }
7596 }
7597
7598 /*< private >
7599  * clutter_actor_adjust_width:
7600  * @self: a #ClutterActor
7601  * @minimum_width: (inout): the actor's preferred minimum width, which
7602  *   will be adjusted depending on the margin
7603  * @natural_width: (inout): the actor's preferred natural width, which
7604  *   will be adjusted depending on the margin
7605  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7606  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7607  *
7608  * Adjusts the preferred and allocated position and size of an actor,
7609  * depending on the margin and alignment properties.
7610  */
7611 static void
7612 clutter_actor_adjust_width (ClutterActor *self,
7613                             gfloat       *minimum_width,
7614                             gfloat       *natural_width,
7615                             gfloat       *adjusted_x1,
7616                             gfloat       *adjusted_x2)
7617 {
7618   ClutterTextDirection text_dir;
7619   const ClutterLayoutInfo *info;
7620
7621   info = _clutter_actor_get_layout_info_or_defaults (self);
7622   text_dir = clutter_actor_get_text_direction (self);
7623
7624   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7625
7626   /* this will tweak natural_width to remove the margin, so that
7627    * adjust_for_alignment() will use the correct size
7628    */
7629   adjust_for_margin (info->margin.left, info->margin.right,
7630                      minimum_width, natural_width,
7631                      adjusted_x1, adjusted_x2);
7632
7633   adjust_for_alignment (effective_align (info->x_align, text_dir),
7634                         *natural_width,
7635                         adjusted_x1, adjusted_x2);
7636 }
7637
7638 /*< private >
7639  * clutter_actor_adjust_height:
7640  * @self: a #ClutterActor
7641  * @minimum_height: (inout): the actor's preferred minimum height, which
7642  *   will be adjusted depending on the margin
7643  * @natural_height: (inout): the actor's preferred natural height, which
7644  *   will be adjusted depending on the margin
7645  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7646  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7647  *
7648  * Adjusts the preferred and allocated position and size of an actor,
7649  * depending on the margin and alignment properties.
7650  */
7651 static void
7652 clutter_actor_adjust_height (ClutterActor *self,
7653                              gfloat       *minimum_height,
7654                              gfloat       *natural_height,
7655                              gfloat       *adjusted_y1,
7656                              gfloat       *adjusted_y2)
7657 {
7658   const ClutterLayoutInfo *info;
7659
7660   info = _clutter_actor_get_layout_info_or_defaults (self);
7661
7662   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7663
7664   /* this will tweak natural_height to remove the margin, so that
7665    * adjust_for_alignment() will use the correct size
7666    */
7667   adjust_for_margin (info->margin.top, info->margin.bottom,
7668                      minimum_height, natural_height,
7669                      adjusted_y1,
7670                      adjusted_y2);
7671
7672   /* we don't use effective_align() here, because text direction
7673    * only affects the horizontal axis
7674    */
7675   adjust_for_alignment (info->y_align,
7676                         *natural_height,
7677                         adjusted_y1,
7678                         adjusted_y2);
7679
7680 }
7681
7682 /* looks for a cached size request for this for_size. If not
7683  * found, returns the oldest entry so it can be overwritten */
7684 static gboolean
7685 _clutter_actor_get_cached_size_request (gfloat         for_size,
7686                                         SizeRequest   *cached_size_requests,
7687                                         SizeRequest  **result)
7688 {
7689   guint i;
7690
7691   *result = &cached_size_requests[0];
7692
7693   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7694     {
7695       SizeRequest *sr;
7696
7697       sr = &cached_size_requests[i];
7698
7699       if (sr->age > 0 &&
7700           sr->for_size == for_size)
7701         {
7702           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7703           *result = sr;
7704           return TRUE;
7705         }
7706       else if (sr->age < (*result)->age)
7707         {
7708           *result = sr;
7709         }
7710     }
7711
7712   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7713
7714   return FALSE;
7715 }
7716
7717 /**
7718  * clutter_actor_get_preferred_width:
7719  * @self: A #ClutterActor
7720  * @for_height: available height when computing the preferred width,
7721  *   or a negative value to indicate that no height is defined
7722  * @min_width_p: (out) (allow-none): return location for minimum width,
7723  *   or %NULL
7724  * @natural_width_p: (out) (allow-none): return location for the natural
7725  *   width, or %NULL
7726  *
7727  * Computes the requested minimum and natural widths for an actor,
7728  * optionally depending on the specified height, or if they are
7729  * already computed, returns the cached values.
7730  *
7731  * An actor may not get its request - depending on the layout
7732  * manager that's in effect.
7733  *
7734  * A request should not incorporate the actor's scale or anchor point;
7735  * those transformations do not affect layout, only rendering.
7736  *
7737  * Since: 0.8
7738  */
7739 void
7740 clutter_actor_get_preferred_width (ClutterActor *self,
7741                                    gfloat        for_height,
7742                                    gfloat       *min_width_p,
7743                                    gfloat       *natural_width_p)
7744 {
7745   float request_min_width, request_natural_width;
7746   SizeRequest *cached_size_request;
7747   const ClutterLayoutInfo *info;
7748   ClutterActorPrivate *priv;
7749   gboolean found_in_cache;
7750
7751   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7752
7753   priv = self->priv;
7754
7755   info = _clutter_actor_get_layout_info_or_defaults (self);
7756
7757   /* we shortcircuit the case of a fixed size set using set_width() */
7758   if (priv->min_width_set && priv->natural_width_set)
7759     {
7760       if (min_width_p != NULL)
7761         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7762
7763       if (natural_width_p != NULL)
7764         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7765
7766       return;
7767     }
7768
7769   /* the remaining cases are:
7770    *
7771    *   - either min_width or natural_width have been set
7772    *   - neither min_width or natural_width have been set
7773    *
7774    * in both cases, we go through the cache (and through the actor in case
7775    * of cache misses) and determine the authoritative value depending on
7776    * the *_set flags.
7777    */
7778
7779   if (!priv->needs_width_request)
7780     {
7781       found_in_cache =
7782         _clutter_actor_get_cached_size_request (for_height,
7783                                                 priv->width_requests,
7784                                                 &cached_size_request);
7785     }
7786   else
7787     {
7788       /* if the actor needs a width request we use the first slot */
7789       found_in_cache = FALSE;
7790       cached_size_request = &priv->width_requests[0];
7791     }
7792
7793   if (!found_in_cache)
7794     {
7795       gfloat minimum_width, natural_width;
7796       ClutterActorClass *klass;
7797
7798       minimum_width = natural_width = 0;
7799
7800       /* adjust for the margin */
7801       if (for_height >= 0)
7802         {
7803           for_height -= (info->margin.top + info->margin.bottom);
7804           if (for_height < 0)
7805             for_height = 0;
7806         }
7807
7808       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7809
7810       klass = CLUTTER_ACTOR_GET_CLASS (self);
7811       klass->get_preferred_width (self, for_height,
7812                                   &minimum_width,
7813                                   &natural_width);
7814
7815       /* adjust for the margin */
7816       minimum_width += (info->margin.left + info->margin.right);
7817       natural_width += (info->margin.left + info->margin.right);
7818
7819       /* Due to accumulated float errors, it's better not to warn
7820        * on this, but just fix it.
7821        */
7822       if (natural_width < minimum_width)
7823         natural_width = minimum_width;
7824
7825       cached_size_request->min_size = minimum_width;
7826       cached_size_request->natural_size = natural_width;
7827       cached_size_request->for_size = for_height;
7828       cached_size_request->age = priv->cached_width_age;
7829
7830       priv->cached_width_age += 1;
7831       priv->needs_width_request = FALSE;
7832     }
7833
7834   if (!priv->min_width_set)
7835     request_min_width = cached_size_request->min_size;
7836   else
7837     request_min_width = info->min_width;
7838
7839   if (!priv->natural_width_set)
7840     request_natural_width = cached_size_request->natural_size;
7841   else
7842     request_natural_width = info->natural_width;
7843
7844   if (min_width_p)
7845     *min_width_p = request_min_width;
7846
7847   if (natural_width_p)
7848     *natural_width_p = request_natural_width;
7849 }
7850
7851 /**
7852  * clutter_actor_get_preferred_height:
7853  * @self: A #ClutterActor
7854  * @for_width: available width to assume in computing desired height,
7855  *   or a negative value to indicate that no width is defined
7856  * @min_height_p: (out) (allow-none): return location for minimum height,
7857  *   or %NULL
7858  * @natural_height_p: (out) (allow-none): return location for natural
7859  *   height, or %NULL
7860  *
7861  * Computes the requested minimum and natural heights for an actor,
7862  * or if they are already computed, returns the cached values.
7863  *
7864  * An actor may not get its request - depending on the layout
7865  * manager that's in effect.
7866  *
7867  * A request should not incorporate the actor's scale or anchor point;
7868  * those transformations do not affect layout, only rendering.
7869  *
7870  * Since: 0.8
7871  */
7872 void
7873 clutter_actor_get_preferred_height (ClutterActor *self,
7874                                     gfloat        for_width,
7875                                     gfloat       *min_height_p,
7876                                     gfloat       *natural_height_p)
7877 {
7878   float request_min_height, request_natural_height;
7879   SizeRequest *cached_size_request;
7880   const ClutterLayoutInfo *info;
7881   ClutterActorPrivate *priv;
7882   gboolean found_in_cache;
7883
7884   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7885
7886   priv = self->priv;
7887
7888   info = _clutter_actor_get_layout_info_or_defaults (self);
7889
7890   /* we shortcircuit the case of a fixed size set using set_height() */
7891   if (priv->min_height_set && priv->natural_height_set)
7892     {
7893       if (min_height_p != NULL)
7894         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7895
7896       if (natural_height_p != NULL)
7897         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7898
7899       return;
7900     }
7901
7902   /* the remaining cases are:
7903    *
7904    *   - either min_height or natural_height have been set
7905    *   - neither min_height or natural_height have been set
7906    *
7907    * in both cases, we go through the cache (and through the actor in case
7908    * of cache misses) and determine the authoritative value depending on
7909    * the *_set flags.
7910    */
7911
7912   if (!priv->needs_height_request)
7913     {
7914       found_in_cache =
7915         _clutter_actor_get_cached_size_request (for_width,
7916                                                 priv->height_requests,
7917                                                 &cached_size_request);
7918     }
7919   else
7920     {
7921       found_in_cache = FALSE;
7922       cached_size_request = &priv->height_requests[0];
7923     }
7924
7925   if (!found_in_cache)
7926     {
7927       gfloat minimum_height, natural_height;
7928       ClutterActorClass *klass;
7929
7930       minimum_height = natural_height = 0;
7931
7932       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7933
7934       /* adjust for margin */
7935       if (for_width >= 0)
7936         {
7937           for_width -= (info->margin.left + info->margin.right);
7938           if (for_width < 0)
7939             for_width = 0;
7940         }
7941
7942       klass = CLUTTER_ACTOR_GET_CLASS (self);
7943       klass->get_preferred_height (self, for_width,
7944                                    &minimum_height,
7945                                    &natural_height);
7946
7947       /* adjust for margin */
7948       minimum_height += (info->margin.top + info->margin.bottom);
7949       natural_height += (info->margin.top + info->margin.bottom);
7950
7951       /* Due to accumulated float errors, it's better not to warn
7952        * on this, but just fix it.
7953        */
7954       if (natural_height < minimum_height)
7955         natural_height = minimum_height;
7956
7957       cached_size_request->min_size = minimum_height;
7958       cached_size_request->natural_size = natural_height;
7959       cached_size_request->for_size = for_width;
7960       cached_size_request->age = priv->cached_height_age;
7961
7962       priv->cached_height_age += 1;
7963       priv->needs_height_request = FALSE;
7964     }
7965
7966   if (!priv->min_height_set)
7967     request_min_height = cached_size_request->min_size;
7968   else
7969     request_min_height = info->min_height;
7970
7971   if (!priv->natural_height_set)
7972     request_natural_height = cached_size_request->natural_size;
7973   else
7974     request_natural_height = info->natural_height;
7975
7976   if (min_height_p)
7977     *min_height_p = request_min_height;
7978
7979   if (natural_height_p)
7980     *natural_height_p = request_natural_height;
7981 }
7982
7983 /**
7984  * clutter_actor_get_allocation_box:
7985  * @self: A #ClutterActor
7986  * @box: (out): the function fills this in with the actor's allocation
7987  *
7988  * Gets the layout box an actor has been assigned. The allocation can
7989  * only be assumed valid inside a paint() method; anywhere else, it
7990  * may be out-of-date.
7991  *
7992  * An allocation does not incorporate the actor's scale or anchor point;
7993  * those transformations do not affect layout, only rendering.
7994  *
7995  * <note>Do not call any of the clutter_actor_get_allocation_*() family
7996  * of functions inside the implementation of the get_preferred_width()
7997  * or get_preferred_height() virtual functions.</note>
7998  *
7999  * Since: 0.8
8000  */
8001 void
8002 clutter_actor_get_allocation_box (ClutterActor    *self,
8003                                   ClutterActorBox *box)
8004 {
8005   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8006
8007   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8008    * which limits calling get_allocation to inside paint() basically; or
8009    * we can 2) force a layout, which could be expensive if someone calls
8010    * get_allocation somewhere silly; or we can 3) just return the latest
8011    * value, allowing it to be out-of-date, and assume people know what
8012    * they are doing.
8013    *
8014    * The least-surprises approach that keeps existing code working is
8015    * likely to be 2). People can end up doing some inefficient things,
8016    * though, and in general code that requires 2) is probably broken.
8017    */
8018
8019   /* this implements 2) */
8020   if (G_UNLIKELY (self->priv->needs_allocation))
8021     {
8022       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8023
8024       /* do not queue a relayout on an unparented actor */
8025       if (stage)
8026         _clutter_stage_maybe_relayout (stage);
8027     }
8028
8029   /* commenting out the code above and just keeping this assigment
8030    * implements 3)
8031    */
8032   *box = self->priv->allocation;
8033 }
8034
8035 /**
8036  * clutter_actor_get_allocation_geometry:
8037  * @self: A #ClutterActor
8038  * @geom: (out): allocation geometry in pixels
8039  *
8040  * Gets the layout box an actor has been assigned.  The allocation can
8041  * only be assumed valid inside a paint() method; anywhere else, it
8042  * may be out-of-date.
8043  *
8044  * An allocation does not incorporate the actor's scale or anchor point;
8045  * those transformations do not affect layout, only rendering.
8046  *
8047  * The returned rectangle is in pixels.
8048  *
8049  * Since: 0.8
8050  */
8051 void
8052 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8053                                        ClutterGeometry *geom)
8054 {
8055   ClutterActorBox box;
8056
8057   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8058   g_return_if_fail (geom != NULL);
8059
8060   clutter_actor_get_allocation_box (self, &box);
8061
8062   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8063   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8064   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8065   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8066 }
8067
8068 static void
8069 clutter_actor_update_constraints (ClutterActor    *self,
8070                                   ClutterActorBox *allocation)
8071 {
8072   ClutterActorPrivate *priv = self->priv;
8073   const GList *constraints, *l;
8074
8075   if (priv->constraints == NULL)
8076     return;
8077
8078   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8079   for (l = constraints; l != NULL; l = l->next)
8080     {
8081       ClutterConstraint *constraint = l->data;
8082       ClutterActorMeta *meta = l->data;
8083
8084       if (clutter_actor_meta_get_enabled (meta))
8085         {
8086           _clutter_constraint_update_allocation (constraint,
8087                                                  self,
8088                                                  allocation);
8089         }
8090     }
8091 }
8092
8093 /*< private >
8094  * clutter_actor_adjust_allocation:
8095  * @self: a #ClutterActor
8096  * @allocation: (inout): the allocation to adjust
8097  *
8098  * Adjusts the passed allocation box taking into account the actor's
8099  * layout information, like alignment, expansion, and margin.
8100  */
8101 static void
8102 clutter_actor_adjust_allocation (ClutterActor    *self,
8103                                  ClutterActorBox *allocation)
8104 {
8105   ClutterActorBox adj_allocation;
8106   float alloc_width, alloc_height;
8107   float min_width, min_height;
8108   float nat_width, nat_height;
8109   ClutterRequestMode req_mode;
8110
8111   adj_allocation = *allocation;
8112
8113   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8114
8115   /* we want to hit the cache, so we use the public API */
8116   req_mode = clutter_actor_get_request_mode (self);
8117
8118   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8119     {
8120       clutter_actor_get_preferred_width (self, -1,
8121                                          &min_width,
8122                                          &nat_width);
8123       clutter_actor_get_preferred_height (self, alloc_width,
8124                                           &min_height,
8125                                           &nat_height);
8126     }
8127   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8128     {
8129       clutter_actor_get_preferred_height (self, -1,
8130                                           &min_height,
8131                                           &nat_height);
8132       clutter_actor_get_preferred_height (self, alloc_height,
8133                                           &min_width,
8134                                           &nat_width);
8135     }
8136
8137 #ifdef CLUTTER_ENABLE_DEBUG
8138   /* warn about underallocations */
8139   if (_clutter_diagnostic_enabled () &&
8140       (floorf (min_width - alloc_width) > 0 ||
8141        floorf (min_height - alloc_height) > 0))
8142     {
8143       ClutterActor *parent = clutter_actor_get_parent (self);
8144
8145       /* the only actors that are allowed to be underallocated are the Stage,
8146        * as it doesn't have an implicit size, and Actors that specifically
8147        * told us that they want to opt-out from layout control mechanisms
8148        * through the NO_LAYOUT escape hatch.
8149        */
8150       if (parent != NULL &&
8151           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8152         {
8153           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8154                      "of %.2f x %.2f from its parent actor '%s', but its "
8155                      "requested minimum size is of %.2f x %.2f",
8156                      _clutter_actor_get_debug_name (self),
8157                      alloc_width, alloc_height,
8158                      _clutter_actor_get_debug_name (parent),
8159                      min_width, min_height);
8160         }
8161     }
8162 #endif
8163
8164   clutter_actor_adjust_width (self,
8165                               &min_width,
8166                               &nat_width,
8167                               &adj_allocation.x1,
8168                               &adj_allocation.x2);
8169
8170   clutter_actor_adjust_height (self,
8171                                &min_height,
8172                                &nat_height,
8173                                &adj_allocation.y1,
8174                                &adj_allocation.y2);
8175
8176   /* we maintain the invariant that an allocation cannot be adjusted
8177    * to be outside the parent-given box
8178    */
8179   if (adj_allocation.x1 < allocation->x1 ||
8180       adj_allocation.y1 < allocation->y1 ||
8181       adj_allocation.x2 > allocation->x2 ||
8182       adj_allocation.y2 > allocation->y2)
8183     {
8184       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8185                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8186                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8187                  _clutter_actor_get_debug_name (self),
8188                  adj_allocation.x1, adj_allocation.y1,
8189                  adj_allocation.x2 - adj_allocation.x1,
8190                  adj_allocation.y2 - adj_allocation.y1,
8191                  allocation->x1, allocation->y1,
8192                  allocation->x2 - allocation->x1,
8193                  allocation->y2 - allocation->y1);
8194       return;
8195     }
8196
8197   *allocation = adj_allocation;
8198 }
8199
8200 /**
8201  * clutter_actor_allocate:
8202  * @self: A #ClutterActor
8203  * @box: new allocation of the actor, in parent-relative coordinates
8204  * @flags: flags that control the allocation
8205  *
8206  * Called by the parent of an actor to assign the actor its size.
8207  * Should never be called by applications (except when implementing
8208  * a container or layout manager).
8209  *
8210  * Actors can know from their allocation box whether they have moved
8211  * with respect to their parent actor. The @flags parameter describes
8212  * additional information about the allocation, for instance whether
8213  * the parent has moved with respect to the stage, for example because
8214  * a grandparent's origin has moved.
8215  *
8216  * Since: 0.8
8217  */
8218 void
8219 clutter_actor_allocate (ClutterActor           *self,
8220                         const ClutterActorBox  *box,
8221                         ClutterAllocationFlags  flags)
8222 {
8223   ClutterActorPrivate *priv;
8224   ClutterActorClass *klass;
8225   ClutterActorBox old_allocation, real_allocation;
8226   gboolean origin_changed, child_moved, size_changed;
8227   gboolean stage_allocation_changed;
8228
8229   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8230   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8231     {
8232       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8233                  "which isn't a descendent of the stage!\n",
8234                  self, _clutter_actor_get_debug_name (self));
8235       return;
8236     }
8237
8238   priv = self->priv;
8239
8240   old_allocation = priv->allocation;
8241   real_allocation = *box;
8242
8243   /* constraints are allowed to modify the allocation only here; we do
8244    * this prior to all the other checks so that we can bail out if the
8245    * allocation did not change
8246    */
8247   clutter_actor_update_constraints (self, &real_allocation);
8248
8249   /* adjust the allocation depending on the align/margin properties */
8250   clutter_actor_adjust_allocation (self, &real_allocation);
8251
8252   if (real_allocation.x2 < real_allocation.x1 ||
8253       real_allocation.y2 < real_allocation.y1)
8254     {
8255       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8256                  _clutter_actor_get_debug_name (self),
8257                  real_allocation.x2 - real_allocation.x1,
8258                  real_allocation.y2 - real_allocation.y1);
8259     }
8260
8261   /* we allow 0-sized actors, but not negative-sized ones */
8262   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8263   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8264
8265   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8266
8267   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8268                  real_allocation.y1 != old_allocation.y1);
8269
8270   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8271                   real_allocation.y2 != old_allocation.y2);
8272
8273   if (origin_changed || child_moved || size_changed)
8274     stage_allocation_changed = TRUE;
8275   else
8276     stage_allocation_changed = FALSE;
8277
8278   /* If we get an allocation "out of the blue"
8279    * (we did not queue relayout), then we want to
8280    * ignore it. But if we have needs_allocation set,
8281    * we want to guarantee that allocate() virtual
8282    * method is always called, i.e. that queue_relayout()
8283    * always results in an allocate() invocation on
8284    * an actor.
8285    *
8286    * The optimization here is to avoid re-allocating
8287    * actors that did not queue relayout and were
8288    * not moved.
8289    */
8290   if (!priv->needs_allocation && !stage_allocation_changed)
8291     {
8292       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8293       return;
8294     }
8295
8296   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8297    * clutter_actor_allocate(), it indicates whether the parent has its
8298    * absolute origin moved; when passed in to ClutterActor::allocate()
8299    * virtual method though, it indicates whether the child has its
8300    * absolute origin moved.  So we set it when child_moved is TRUE
8301    */
8302   if (child_moved)
8303     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8304
8305   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8306
8307   klass = CLUTTER_ACTOR_GET_CLASS (self);
8308   klass->allocate (self, &real_allocation, flags);
8309
8310   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8311
8312   if (stage_allocation_changed)
8313     clutter_actor_queue_redraw (self);
8314 }
8315
8316 /**
8317  * clutter_actor_set_allocation:
8318  * @self: a #ClutterActor
8319  * @box: a #ClutterActorBox
8320  * @flags: allocation flags
8321  *
8322  * Stores the allocation of @self as defined by @box.
8323  *
8324  * This function can only be called from within the implementation of
8325  * the #ClutterActorClass.allocate() virtual function.
8326  *
8327  * The allocation should have been adjusted to take into account constraints,
8328  * alignment, and margin properties. If you are implementing a #ClutterActor
8329  * subclass that provides its own layout management policy for its children
8330  * instead of using a #ClutterLayoutManager delegate, you should not call
8331  * this function on the children of @self; instead, you should call
8332  * clutter_actor_allocate(), which will adjust the allocation box for
8333  * you.
8334  *
8335  * This function should only be used by subclasses of #ClutterActor
8336  * that wish to store their allocation but cannot chain up to the
8337  * parent's implementation; the default implementation of the
8338  * #ClutterActorClass.allocate() virtual function will call this
8339  * function.
8340  *
8341  * It is important to note that, while chaining up was the recommended
8342  * behaviour for #ClutterActor subclasses prior to the introduction of
8343  * this function, it is recommended to call clutter_actor_set_allocation()
8344  * instead.
8345  *
8346  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8347  * to handle the allocation of its children, this function will call
8348  * the clutter_layout_manager_allocate() function only if the
8349  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8350  * expected that the subclass will call clutter_layout_manager_allocate()
8351  * by itself. For instance, the following code:
8352  *
8353  * |[
8354  * static void
8355  * my_actor_allocate (ClutterActor *actor,
8356  *                    const ClutterActorBox *allocation,
8357  *                    ClutterAllocationFlags flags)
8358  * {
8359  *   ClutterActorBox new_alloc;
8360  *   ClutterAllocationFlags new_flags;
8361  *
8362  *   adjust_allocation (allocation, &amp;new_alloc);
8363  *
8364  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8365  *
8366  *   /&ast; this will use the layout manager set on the actor &ast;/
8367  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8368  * }
8369  * ]|
8370  *
8371  * is equivalent to this:
8372  *
8373  * |[
8374  * static void
8375  * my_actor_allocate (ClutterActor *actor,
8376  *                    const ClutterActorBox *allocation,
8377  *                    ClutterAllocationFlags flags)
8378  * {
8379  *   ClutterLayoutManager *layout;
8380  *   ClutterActorBox new_alloc;
8381  *
8382  *   adjust_allocation (allocation, &amp;new_alloc);
8383  *
8384  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8385  *
8386  *   layout = clutter_actor_get_layout_manager (actor);
8387  *   clutter_layout_manager_allocate (layout,
8388  *                                    CLUTTER_CONTAINER (actor),
8389  *                                    &amp;new_alloc,
8390  *                                    flags);
8391  * }
8392  * ]|
8393  *
8394  * Since: 1.10
8395  */
8396 void
8397 clutter_actor_set_allocation (ClutterActor           *self,
8398                               const ClutterActorBox  *box,
8399                               ClutterAllocationFlags  flags)
8400 {
8401   ClutterActorPrivate *priv;
8402   gboolean changed;
8403
8404   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8405   g_return_if_fail (box != NULL);
8406
8407   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8408     {
8409       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8410                   "can only be called from within the implementation of "
8411                   "the ClutterActor::allocate() virtual function.");
8412       return;
8413     }
8414
8415   priv = self->priv;
8416
8417   g_object_freeze_notify (G_OBJECT (self));
8418
8419   changed = clutter_actor_set_allocation_internal (self, box, flags);
8420
8421   /* we allocate our children before we notify changes in our geometry,
8422    * so that people connecting to properties will be able to get valid
8423    * data out of the sub-tree of the scene graph that has this actor at
8424    * the root.
8425    */
8426   clutter_actor_maybe_layout_children (self, box, flags);
8427
8428   if (changed)
8429     {
8430       ClutterActorBox signal_box = priv->allocation;
8431       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8432
8433       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8434                      &signal_box,
8435                      signal_flags);
8436     }
8437
8438   g_object_thaw_notify (G_OBJECT (self));
8439 }
8440
8441 /**
8442  * clutter_actor_set_geometry:
8443  * @self: A #ClutterActor
8444  * @geometry: A #ClutterGeometry
8445  *
8446  * Sets the actor's fixed position and forces its minimum and natural
8447  * size, in pixels. This means the untransformed actor will have the
8448  * given geometry. This is the same as calling clutter_actor_set_position()
8449  * and clutter_actor_set_size().
8450  *
8451  * Deprecated: 1.10: Use clutter_actor_set_position() and
8452  *   clutter_actor_set_size() instead.
8453  */
8454 void
8455 clutter_actor_set_geometry (ClutterActor          *self,
8456                             const ClutterGeometry *geometry)
8457 {
8458   g_object_freeze_notify (G_OBJECT (self));
8459
8460   clutter_actor_set_position (self, geometry->x, geometry->y);
8461   clutter_actor_set_size (self, geometry->width, geometry->height);
8462
8463   g_object_thaw_notify (G_OBJECT (self));
8464 }
8465
8466 /**
8467  * clutter_actor_get_geometry:
8468  * @self: A #ClutterActor
8469  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8470  *
8471  * Gets the size and position of an actor relative to its parent
8472  * actor. This is the same as calling clutter_actor_get_position() and
8473  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8474  * requested size and position if the actor's allocation is invalid.
8475  *
8476  * Deprecated: 1.10: Use clutter_actor_get_position() and
8477  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8478  *   instead.
8479  */
8480 void
8481 clutter_actor_get_geometry (ClutterActor    *self,
8482                             ClutterGeometry *geometry)
8483 {
8484   gfloat x, y, width, height;
8485
8486   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8487   g_return_if_fail (geometry != NULL);
8488
8489   clutter_actor_get_position (self, &x, &y);
8490   clutter_actor_get_size (self, &width, &height);
8491
8492   geometry->x = (int) x;
8493   geometry->y = (int) y;
8494   geometry->width = (int) width;
8495   geometry->height = (int) height;
8496 }
8497
8498 /**
8499  * clutter_actor_set_position:
8500  * @self: A #ClutterActor
8501  * @x: New left position of actor in pixels.
8502  * @y: New top position of actor in pixels.
8503  *
8504  * Sets the actor's fixed position in pixels relative to any parent
8505  * actor.
8506  *
8507  * If a layout manager is in use, this position will override the
8508  * layout manager and force a fixed position.
8509  */
8510 void
8511 clutter_actor_set_position (ClutterActor *self,
8512                             gfloat        x,
8513                             gfloat        y)
8514 {
8515   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8516
8517   g_object_freeze_notify (G_OBJECT (self));
8518
8519   clutter_actor_set_x (self, x);
8520   clutter_actor_set_y (self, y);
8521
8522   g_object_thaw_notify (G_OBJECT (self));
8523 }
8524
8525 /**
8526  * clutter_actor_get_fixed_position_set:
8527  * @self: A #ClutterActor
8528  *
8529  * Checks whether an actor has a fixed position set (and will thus be
8530  * unaffected by any layout manager).
8531  *
8532  * Return value: %TRUE if the fixed position is set on the actor
8533  *
8534  * Since: 0.8
8535  */
8536 gboolean
8537 clutter_actor_get_fixed_position_set (ClutterActor *self)
8538 {
8539   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8540
8541   return self->priv->position_set;
8542 }
8543
8544 /**
8545  * clutter_actor_set_fixed_position_set:
8546  * @self: A #ClutterActor
8547  * @is_set: whether to use fixed position
8548  *
8549  * Sets whether an actor has a fixed position set (and will thus be
8550  * unaffected by any layout manager).
8551  *
8552  * Since: 0.8
8553  */
8554 void
8555 clutter_actor_set_fixed_position_set (ClutterActor *self,
8556                                       gboolean      is_set)
8557 {
8558   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8559
8560   if (self->priv->position_set == (is_set != FALSE))
8561     return;
8562
8563   self->priv->position_set = is_set != FALSE;
8564   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8565
8566   clutter_actor_queue_relayout (self);
8567 }
8568
8569 /**
8570  * clutter_actor_move_by:
8571  * @self: A #ClutterActor
8572  * @dx: Distance to move Actor on X axis.
8573  * @dy: Distance to move Actor on Y axis.
8574  *
8575  * Moves an actor by the specified distance relative to its current
8576  * position in pixels.
8577  *
8578  * This function modifies the fixed position of an actor and thus removes
8579  * it from any layout management. Another way to move an actor is with an
8580  * anchor point, see clutter_actor_set_anchor_point().
8581  *
8582  * Since: 0.2
8583  */
8584 void
8585 clutter_actor_move_by (ClutterActor *self,
8586                        gfloat        dx,
8587                        gfloat        dy)
8588 {
8589   const ClutterLayoutInfo *info;
8590   gfloat x, y;
8591
8592   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8593
8594   info = _clutter_actor_get_layout_info_or_defaults (self);
8595   x = info->fixed_x;
8596   y = info->fixed_y;
8597
8598   clutter_actor_set_position (self, x + dx, y + dy);
8599 }
8600
8601 static void
8602 clutter_actor_set_min_width (ClutterActor *self,
8603                              gfloat        min_width)
8604 {
8605   ClutterActorPrivate *priv = self->priv;
8606   ClutterActorBox old = { 0, };
8607   ClutterLayoutInfo *info;
8608
8609   /* if we are setting the size on a top-level actor and the
8610    * backend only supports static top-levels (e.g. framebuffers)
8611    * then we ignore the passed value and we override it with
8612    * the stage implementation's preferred size.
8613    */
8614   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8615       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8616     return;
8617
8618   info = _clutter_actor_get_layout_info (self);
8619
8620   if (priv->min_width_set && min_width == info->min_width)
8621     return;
8622
8623   g_object_freeze_notify (G_OBJECT (self));
8624
8625   clutter_actor_store_old_geometry (self, &old);
8626
8627   info->min_width = min_width;
8628   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8629   clutter_actor_set_min_width_set (self, TRUE);
8630
8631   clutter_actor_notify_if_geometry_changed (self, &old);
8632
8633   g_object_thaw_notify (G_OBJECT (self));
8634
8635   clutter_actor_queue_relayout (self);
8636 }
8637
8638 static void
8639 clutter_actor_set_min_height (ClutterActor *self,
8640                               gfloat        min_height)
8641
8642 {
8643   ClutterActorPrivate *priv = self->priv;
8644   ClutterActorBox old = { 0, };
8645   ClutterLayoutInfo *info;
8646
8647   /* if we are setting the size on a top-level actor and the
8648    * backend only supports static top-levels (e.g. framebuffers)
8649    * then we ignore the passed value and we override it with
8650    * the stage implementation's preferred size.
8651    */
8652   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8653       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8654     return;
8655
8656   info = _clutter_actor_get_layout_info (self);
8657
8658   if (priv->min_height_set && min_height == info->min_height)
8659     return;
8660
8661   g_object_freeze_notify (G_OBJECT (self));
8662
8663   clutter_actor_store_old_geometry (self, &old);
8664
8665   info->min_height = min_height;
8666   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8667   clutter_actor_set_min_height_set (self, TRUE);
8668
8669   clutter_actor_notify_if_geometry_changed (self, &old);
8670
8671   g_object_thaw_notify (G_OBJECT (self));
8672
8673   clutter_actor_queue_relayout (self);
8674 }
8675
8676 static void
8677 clutter_actor_set_natural_width (ClutterActor *self,
8678                                  gfloat        natural_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->natural_width_set && natural_width == info->natural_width)
8696     return;
8697
8698   g_object_freeze_notify (G_OBJECT (self));
8699
8700   clutter_actor_store_old_geometry (self, &old);
8701
8702   info->natural_width = natural_width;
8703   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8704   clutter_actor_set_natural_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_natural_height (ClutterActor *self,
8715                                   gfloat        natural_height)
8716 {
8717   ClutterActorPrivate *priv = self->priv;
8718   ClutterActorBox old = { 0, };
8719   ClutterLayoutInfo *info;
8720
8721   /* if we are setting the size on a top-level actor and the
8722    * backend only supports static top-levels (e.g. framebuffers)
8723    * then we ignore the passed value and we override it with
8724    * the stage implementation's preferred size.
8725    */
8726   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8727       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8728     return;
8729
8730   info = _clutter_actor_get_layout_info (self);
8731
8732   if (priv->natural_height_set && natural_height == info->natural_height)
8733     return;
8734
8735   g_object_freeze_notify (G_OBJECT (self));
8736
8737   clutter_actor_store_old_geometry (self, &old);
8738
8739   info->natural_height = natural_height;
8740   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8741   clutter_actor_set_natural_height_set (self, TRUE);
8742
8743   clutter_actor_notify_if_geometry_changed (self, &old);
8744
8745   g_object_thaw_notify (G_OBJECT (self));
8746
8747   clutter_actor_queue_relayout (self);
8748 }
8749
8750 static void
8751 clutter_actor_set_min_width_set (ClutterActor *self,
8752                                  gboolean      use_min_width)
8753 {
8754   ClutterActorPrivate *priv = self->priv;
8755   ClutterActorBox old = { 0, };
8756
8757   if (priv->min_width_set == (use_min_width != FALSE))
8758     return;
8759
8760   clutter_actor_store_old_geometry (self, &old);
8761
8762   priv->min_width_set = use_min_width != FALSE;
8763   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8764
8765   clutter_actor_notify_if_geometry_changed (self, &old);
8766
8767   clutter_actor_queue_relayout (self);
8768 }
8769
8770 static void
8771 clutter_actor_set_min_height_set (ClutterActor *self,
8772                                   gboolean      use_min_height)
8773 {
8774   ClutterActorPrivate *priv = self->priv;
8775   ClutterActorBox old = { 0, };
8776
8777   if (priv->min_height_set == (use_min_height != FALSE))
8778     return;
8779
8780   clutter_actor_store_old_geometry (self, &old);
8781
8782   priv->min_height_set = use_min_height != FALSE;
8783   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8784
8785   clutter_actor_notify_if_geometry_changed (self, &old);
8786
8787   clutter_actor_queue_relayout (self);
8788 }
8789
8790 static void
8791 clutter_actor_set_natural_width_set (ClutterActor *self,
8792                                      gboolean      use_natural_width)
8793 {
8794   ClutterActorPrivate *priv = self->priv;
8795   ClutterActorBox old = { 0, };
8796
8797   if (priv->natural_width_set == (use_natural_width != FALSE))
8798     return;
8799
8800   clutter_actor_store_old_geometry (self, &old);
8801
8802   priv->natural_width_set = use_natural_width != FALSE;
8803   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8804
8805   clutter_actor_notify_if_geometry_changed (self, &old);
8806
8807   clutter_actor_queue_relayout (self);
8808 }
8809
8810 static void
8811 clutter_actor_set_natural_height_set (ClutterActor *self,
8812                                       gboolean      use_natural_height)
8813 {
8814   ClutterActorPrivate *priv = self->priv;
8815   ClutterActorBox old = { 0, };
8816
8817   if (priv->natural_height_set == (use_natural_height != FALSE))
8818     return;
8819
8820   clutter_actor_store_old_geometry (self, &old);
8821
8822   priv->natural_height_set = use_natural_height != FALSE;
8823   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8824
8825   clutter_actor_notify_if_geometry_changed (self, &old);
8826
8827   clutter_actor_queue_relayout (self);
8828 }
8829
8830 /**
8831  * clutter_actor_set_request_mode:
8832  * @self: a #ClutterActor
8833  * @mode: the request mode
8834  *
8835  * Sets the geometry request mode of @self.
8836  *
8837  * The @mode determines the order for invoking
8838  * clutter_actor_get_preferred_width() and
8839  * clutter_actor_get_preferred_height()
8840  *
8841  * Since: 1.2
8842  */
8843 void
8844 clutter_actor_set_request_mode (ClutterActor       *self,
8845                                 ClutterRequestMode  mode)
8846 {
8847   ClutterActorPrivate *priv;
8848
8849   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8850
8851   priv = self->priv;
8852
8853   if (priv->request_mode == mode)
8854     return;
8855
8856   priv->request_mode = mode;
8857
8858   priv->needs_width_request = TRUE;
8859   priv->needs_height_request = TRUE;
8860
8861   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8862
8863   clutter_actor_queue_relayout (self);
8864 }
8865
8866 /**
8867  * clutter_actor_get_request_mode:
8868  * @self: a #ClutterActor
8869  *
8870  * Retrieves the geometry request mode of @self
8871  *
8872  * Return value: the request mode for the actor
8873  *
8874  * Since: 1.2
8875  */
8876 ClutterRequestMode
8877 clutter_actor_get_request_mode (ClutterActor *self)
8878 {
8879   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8880                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8881
8882   return self->priv->request_mode;
8883 }
8884
8885 /* variant of set_width() without checks and without notification
8886  * freeze+thaw, for internal usage only
8887  */
8888 static inline void
8889 clutter_actor_set_width_internal (ClutterActor *self,
8890                                   gfloat        width)
8891 {
8892   if (width >= 0)
8893     {
8894       /* the Stage will use the :min-width to control the minimum
8895        * width to be resized to, so we should not be setting it
8896        * along with the :natural-width
8897        */
8898       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8899         clutter_actor_set_min_width (self, width);
8900
8901       clutter_actor_set_natural_width (self, width);
8902     }
8903   else
8904     {
8905       /* we only unset the :natural-width for the Stage */
8906       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8907         clutter_actor_set_min_width_set (self, FALSE);
8908
8909       clutter_actor_set_natural_width_set (self, FALSE);
8910     }
8911 }
8912
8913 /* variant of set_height() without checks and without notification
8914  * freeze+thaw, for internal usage only
8915  */
8916 static inline void
8917 clutter_actor_set_height_internal (ClutterActor *self,
8918                                    gfloat        height)
8919 {
8920   if (height >= 0)
8921     {
8922       /* see the comment above in set_width_internal() */
8923       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8924         clutter_actor_set_min_height (self, height);
8925
8926       clutter_actor_set_natural_height (self, height);
8927     }
8928   else
8929     {
8930       /* see the comment above in set_width_internal() */
8931       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8932         clutter_actor_set_min_height_set (self, FALSE);
8933
8934       clutter_actor_set_natural_height_set (self, FALSE);
8935     }
8936 }
8937
8938 /**
8939  * clutter_actor_set_size:
8940  * @self: A #ClutterActor
8941  * @width: New width of actor in pixels, or -1
8942  * @height: New height of actor in pixels, or -1
8943  *
8944  * Sets the actor's size request in pixels. This overrides any
8945  * "normal" size request the actor would have. For example
8946  * a text actor might normally request the size of the text;
8947  * this function would force a specific size instead.
8948  *
8949  * If @width and/or @height are -1 the actor will use its
8950  * "normal" size request instead of overriding it, i.e.
8951  * you can "unset" the size with -1.
8952  *
8953  * This function sets or unsets both the minimum and natural size.
8954  */
8955 void
8956 clutter_actor_set_size (ClutterActor *self,
8957                         gfloat        width,
8958                         gfloat        height)
8959 {
8960   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8961
8962   g_object_freeze_notify (G_OBJECT (self));
8963
8964   clutter_actor_set_width (self, width);
8965   clutter_actor_set_height (self, height);
8966
8967   g_object_thaw_notify (G_OBJECT (self));
8968 }
8969
8970 /**
8971  * clutter_actor_get_size:
8972  * @self: A #ClutterActor
8973  * @width: (out) (allow-none): return location for the width, or %NULL.
8974  * @height: (out) (allow-none): return location for the height, or %NULL.
8975  *
8976  * This function tries to "do what you mean" and return
8977  * the size an actor will have. If the actor has a valid
8978  * allocation, the allocation will be returned; otherwise,
8979  * the actors natural size request will be returned.
8980  *
8981  * If you care whether you get the request vs. the allocation, you
8982  * should probably call a different function like
8983  * clutter_actor_get_allocation_box() or
8984  * clutter_actor_get_preferred_width().
8985  *
8986  * Since: 0.2
8987  */
8988 void
8989 clutter_actor_get_size (ClutterActor *self,
8990                         gfloat       *width,
8991                         gfloat       *height)
8992 {
8993   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8994
8995   if (width)
8996     *width = clutter_actor_get_width (self);
8997
8998   if (height)
8999     *height = clutter_actor_get_height (self);
9000 }
9001
9002 /**
9003  * clutter_actor_get_position:
9004  * @self: a #ClutterActor
9005  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9006  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9007  *
9008  * This function tries to "do what you mean" and tell you where the
9009  * actor is, prior to any transformations. Retrieves the fixed
9010  * position of an actor in pixels, if one has been set; otherwise, if
9011  * the allocation is valid, returns the actor's allocated position;
9012  * otherwise, returns 0,0.
9013  *
9014  * The returned position is in pixels.
9015  *
9016  * Since: 0.6
9017  */
9018 void
9019 clutter_actor_get_position (ClutterActor *self,
9020                             gfloat       *x,
9021                             gfloat       *y)
9022 {
9023   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9024
9025   if (x)
9026     *x = clutter_actor_get_x (self);
9027
9028   if (y)
9029     *y = clutter_actor_get_y (self);
9030 }
9031
9032 /**
9033  * clutter_actor_get_transformed_position:
9034  * @self: A #ClutterActor
9035  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9036  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9037  *
9038  * Gets the absolute position of an actor, in pixels relative to the stage.
9039  *
9040  * Since: 0.8
9041  */
9042 void
9043 clutter_actor_get_transformed_position (ClutterActor *self,
9044                                         gfloat       *x,
9045                                         gfloat       *y)
9046 {
9047   ClutterVertex v1;
9048   ClutterVertex v2;
9049
9050   v1.x = v1.y = v1.z = 0;
9051   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9052
9053   if (x)
9054     *x = v2.x;
9055
9056   if (y)
9057     *y = v2.y;
9058 }
9059
9060 /**
9061  * clutter_actor_get_transformed_size:
9062  * @self: A #ClutterActor
9063  * @width: (out) (allow-none): return location for the width, or %NULL
9064  * @height: (out) (allow-none): return location for the height, or %NULL
9065  *
9066  * Gets the absolute size of an actor in pixels, taking into account the
9067  * scaling factors.
9068  *
9069  * If the actor has a valid allocation, the allocated size will be used.
9070  * If the actor has not a valid allocation then the preferred size will
9071  * be transformed and returned.
9072  *
9073  * If you want the transformed allocation, see
9074  * clutter_actor_get_abs_allocation_vertices() instead.
9075  *
9076  * <note>When the actor (or one of its ancestors) is rotated around the
9077  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9078  * as a generic quadrangle; in that case this function returns the size
9079  * of the smallest rectangle that encapsulates the entire quad. Please
9080  * note that in this case no assumptions can be made about the relative
9081  * position of this envelope to the absolute position of the actor, as
9082  * returned by clutter_actor_get_transformed_position(); if you need this
9083  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9084  * to get the coords of the actual quadrangle.</note>
9085  *
9086  * Since: 0.8
9087  */
9088 void
9089 clutter_actor_get_transformed_size (ClutterActor *self,
9090                                     gfloat       *width,
9091                                     gfloat       *height)
9092 {
9093   ClutterActorPrivate *priv;
9094   ClutterVertex v[4];
9095   gfloat x_min, x_max, y_min, y_max;
9096   gint i;
9097
9098   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9099
9100   priv = self->priv;
9101
9102   /* if the actor hasn't been allocated yet, get the preferred
9103    * size and transform that
9104    */
9105   if (priv->needs_allocation)
9106     {
9107       gfloat natural_width, natural_height;
9108       ClutterActorBox box;
9109
9110       /* Make a fake allocation to transform.
9111        *
9112        * NB: _clutter_actor_transform_and_project_box expects a box in
9113        * the actor's coordinate space... */
9114
9115       box.x1 = 0;
9116       box.y1 = 0;
9117
9118       natural_width = natural_height = 0;
9119       clutter_actor_get_preferred_size (self, NULL, NULL,
9120                                         &natural_width,
9121                                         &natural_height);
9122
9123       box.x2 = natural_width;
9124       box.y2 = natural_height;
9125
9126       _clutter_actor_transform_and_project_box (self, &box, v);
9127     }
9128   else
9129     clutter_actor_get_abs_allocation_vertices (self, v);
9130
9131   x_min = x_max = v[0].x;
9132   y_min = y_max = v[0].y;
9133
9134   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9135     {
9136       if (v[i].x < x_min)
9137         x_min = v[i].x;
9138
9139       if (v[i].x > x_max)
9140         x_max = v[i].x;
9141
9142       if (v[i].y < y_min)
9143         y_min = v[i].y;
9144
9145       if (v[i].y > y_max)
9146         y_max = v[i].y;
9147     }
9148
9149   if (width)
9150     *width  = x_max - x_min;
9151
9152   if (height)
9153     *height = y_max - y_min;
9154 }
9155
9156 /**
9157  * clutter_actor_get_width:
9158  * @self: A #ClutterActor
9159  *
9160  * Retrieves the width of a #ClutterActor.
9161  *
9162  * If the actor has a valid allocation, this function will return the
9163  * width of the allocated area given to the actor.
9164  *
9165  * If the actor does not have a valid allocation, this function will
9166  * return the actor's natural width, that is the preferred width of
9167  * the actor.
9168  *
9169  * If you care whether you get the preferred width or the width that
9170  * has been assigned to the actor, you should probably call a different
9171  * function like clutter_actor_get_allocation_box() to retrieve the
9172  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9173  * preferred width.
9174  *
9175  * If an actor has a fixed width, for instance a width that has been
9176  * assigned using clutter_actor_set_width(), the width returned will
9177  * be the same value.
9178  *
9179  * Return value: the width of the actor, in pixels
9180  */
9181 gfloat
9182 clutter_actor_get_width (ClutterActor *self)
9183 {
9184   ClutterActorPrivate *priv;
9185
9186   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9187
9188   priv = self->priv;
9189
9190   if (priv->needs_allocation)
9191     {
9192       gfloat natural_width = 0;
9193
9194       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9195         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9196       else
9197         {
9198           gfloat natural_height = 0;
9199
9200           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9201           clutter_actor_get_preferred_width (self, natural_height,
9202                                              NULL,
9203                                              &natural_width);
9204         }
9205
9206       return natural_width;
9207     }
9208   else
9209     return priv->allocation.x2 - priv->allocation.x1;
9210 }
9211
9212 /**
9213  * clutter_actor_get_height:
9214  * @self: A #ClutterActor
9215  *
9216  * Retrieves the height of a #ClutterActor.
9217  *
9218  * If the actor has a valid allocation, this function will return the
9219  * height of the allocated area given to the actor.
9220  *
9221  * If the actor does not have a valid allocation, this function will
9222  * return the actor's natural height, that is the preferred height of
9223  * the actor.
9224  *
9225  * If you care whether you get the preferred height or the height that
9226  * has been assigned to the actor, you should probably call a different
9227  * function like clutter_actor_get_allocation_box() to retrieve the
9228  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9229  * preferred height.
9230  *
9231  * If an actor has a fixed height, for instance a height that has been
9232  * assigned using clutter_actor_set_height(), the height returned will
9233  * be the same value.
9234  *
9235  * Return value: the height of the actor, in pixels
9236  */
9237 gfloat
9238 clutter_actor_get_height (ClutterActor *self)
9239 {
9240   ClutterActorPrivate *priv;
9241
9242   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9243
9244   priv = self->priv;
9245
9246   if (priv->needs_allocation)
9247     {
9248       gfloat natural_height = 0;
9249
9250       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9251         {
9252           gfloat natural_width = 0;
9253
9254           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9255           clutter_actor_get_preferred_height (self, natural_width,
9256                                               NULL, &natural_height);
9257         }
9258       else
9259         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9260
9261       return natural_height;
9262     }
9263   else
9264     return priv->allocation.y2 - priv->allocation.y1;
9265 }
9266
9267 /**
9268  * clutter_actor_set_width:
9269  * @self: A #ClutterActor
9270  * @width: Requested new width for the actor, in pixels, or -1
9271  *
9272  * Forces a width on an actor, causing the actor's preferred width
9273  * and height (if any) to be ignored.
9274  *
9275  * If @width is -1 the actor will use its preferred width request
9276  * instead of overriding it, i.e. you can "unset" the width with -1.
9277  *
9278  * This function sets both the minimum and natural size of the actor.
9279  *
9280  * since: 0.2
9281  */
9282 void
9283 clutter_actor_set_width (ClutterActor *self,
9284                          gfloat        width)
9285 {
9286   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9287
9288   if (clutter_actor_get_easing_duration (self) != 0)
9289     {
9290       ClutterTransition *transition;
9291
9292       transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9293       if (transition == NULL)
9294         {
9295           float old_width = clutter_actor_get_width (self);
9296
9297           transition = _clutter_actor_create_transition (self,
9298                                                          obj_props[PROP_WIDTH],
9299                                                          old_width,
9300                                                          width);
9301           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9302         }
9303       else
9304         _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9305
9306       clutter_actor_queue_relayout (self);
9307     }
9308   else
9309     {
9310       g_object_freeze_notify (G_OBJECT (self));
9311
9312       clutter_actor_set_width_internal (self, width);
9313
9314       g_object_thaw_notify (G_OBJECT (self));
9315     }
9316 }
9317
9318 /**
9319  * clutter_actor_set_height:
9320  * @self: A #ClutterActor
9321  * @height: Requested new height for the actor, in pixels, or -1
9322  *
9323  * Forces a height on an actor, causing the actor's preferred width
9324  * and height (if any) to be ignored.
9325  *
9326  * If @height is -1 the actor will use its preferred height instead of
9327  * overriding it, i.e. you can "unset" the height with -1.
9328  *
9329  * This function sets both the minimum and natural size of the actor.
9330  *
9331  * since: 0.2
9332  */
9333 void
9334 clutter_actor_set_height (ClutterActor *self,
9335                           gfloat        height)
9336 {
9337   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9338
9339   if (clutter_actor_get_easing_duration (self) != 0)
9340     {
9341       ClutterTransition *transition;
9342
9343       transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9344       if (transition ==  NULL)
9345         {
9346           float old_height = clutter_actor_get_height (self);
9347
9348           transition = _clutter_actor_create_transition (self,
9349                                                          obj_props[PROP_HEIGHT],
9350                                                          old_height,
9351                                                          height);
9352           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9353         }
9354       else
9355         _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9356
9357       clutter_actor_queue_relayout (self);
9358     }
9359   else
9360     {
9361       g_object_freeze_notify (G_OBJECT (self));
9362
9363       clutter_actor_set_height_internal (self, height);
9364
9365       g_object_thaw_notify (G_OBJECT (self));
9366     }
9367 }
9368
9369 static inline void
9370 clutter_actor_set_x_internal (ClutterActor *self,
9371                               float         x)
9372 {
9373   ClutterActorPrivate *priv = self->priv;
9374   ClutterLayoutInfo *linfo;
9375   ClutterActorBox old = { 0, };
9376
9377   linfo = _clutter_actor_get_layout_info (self);
9378
9379   if (priv->position_set && linfo->fixed_x == x)
9380     return;
9381
9382   clutter_actor_store_old_geometry (self, &old);
9383
9384   linfo->fixed_x = x;
9385   clutter_actor_set_fixed_position_set (self, TRUE);
9386
9387   clutter_actor_notify_if_geometry_changed (self, &old);
9388
9389   clutter_actor_queue_relayout (self);
9390 }
9391
9392 static inline void
9393 clutter_actor_set_y_internal (ClutterActor *self,
9394                               float         y)
9395 {
9396   ClutterActorPrivate *priv = self->priv;
9397   ClutterLayoutInfo *linfo;
9398   ClutterActorBox old = { 0, };
9399
9400   linfo = _clutter_actor_get_layout_info (self);
9401
9402   if (priv->position_set && linfo->fixed_y == y)
9403     return;
9404
9405   clutter_actor_store_old_geometry (self, &old);
9406
9407   linfo->fixed_y = y;
9408   clutter_actor_set_fixed_position_set (self, TRUE);
9409
9410   clutter_actor_notify_if_geometry_changed (self, &old);
9411 }
9412
9413 /**
9414  * clutter_actor_set_x:
9415  * @self: a #ClutterActor
9416  * @x: the actor's position on the X axis
9417  *
9418  * Sets the actor's X coordinate, relative to its parent, in pixels.
9419  *
9420  * Overrides any layout manager and forces a fixed position for
9421  * the actor.
9422  *
9423  * The #ClutterActor:x property is animatable.
9424  *
9425  * Since: 0.6
9426  */
9427 void
9428 clutter_actor_set_x (ClutterActor *self,
9429                      gfloat        x)
9430 {
9431   const ClutterLayoutInfo *linfo;
9432
9433   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9434
9435   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9436
9437   if (clutter_actor_get_easing_duration (self) != 0)
9438     {
9439       ClutterTransition *transition;
9440
9441       transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9442       if (transition == NULL)
9443         {
9444           transition = _clutter_actor_create_transition (self,
9445                                                          obj_props[PROP_X],
9446                                                          linfo->fixed_x,
9447                                                          x);
9448
9449           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9450         }
9451       else
9452         _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9453
9454       clutter_actor_queue_relayout (self);
9455     }
9456   else
9457     clutter_actor_set_x_internal (self, x);
9458 }
9459
9460 /**
9461  * clutter_actor_set_y:
9462  * @self: a #ClutterActor
9463  * @y: the actor's position on the Y axis
9464  *
9465  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9466  *
9467  * Overrides any layout manager and forces a fixed position for
9468  * the actor.
9469  *
9470  * The #ClutterActor:y property is animatable.
9471  *
9472  * Since: 0.6
9473  */
9474 void
9475 clutter_actor_set_y (ClutterActor *self,
9476                      gfloat        y)
9477 {
9478   const ClutterLayoutInfo *linfo;
9479
9480   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9481
9482   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9483
9484   if (clutter_actor_get_easing_duration (self) != 0)
9485     {
9486       ClutterTransition *transition;
9487
9488       transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9489       if (transition == NULL)
9490         {
9491           transition = _clutter_actor_create_transition (self,
9492                                                          obj_props[PROP_Y],
9493                                                          linfo->fixed_y,
9494                                                          y);
9495
9496           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9497         }
9498       else
9499         _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9500
9501       clutter_actor_queue_relayout (self);
9502     }
9503   else
9504     clutter_actor_set_y_internal (self, y);
9505
9506   clutter_actor_queue_relayout (self);
9507 }
9508
9509 /**
9510  * clutter_actor_get_x:
9511  * @self: A #ClutterActor
9512  *
9513  * Retrieves the X coordinate of a #ClutterActor.
9514  *
9515  * This function tries to "do what you mean", by returning the
9516  * correct value depending on the actor's state.
9517  *
9518  * If the actor has a valid allocation, this function will return
9519  * the X coordinate of the origin of the allocation box.
9520  *
9521  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9522  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9523  * function will return that coordinate.
9524  *
9525  * If both the allocation and a fixed position are missing, this function
9526  * will return 0.
9527  *
9528  * Return value: the X coordinate, in pixels, ignoring any
9529  *   transformation (i.e. scaling, rotation)
9530  */
9531 gfloat
9532 clutter_actor_get_x (ClutterActor *self)
9533 {
9534   ClutterActorPrivate *priv;
9535
9536   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9537
9538   priv = self->priv;
9539
9540   if (priv->needs_allocation)
9541     {
9542       if (priv->position_set)
9543         {
9544           const ClutterLayoutInfo *info;
9545
9546           info = _clutter_actor_get_layout_info_or_defaults (self);
9547
9548           return info->fixed_x;
9549         }
9550       else
9551         return 0;
9552     }
9553   else
9554     return priv->allocation.x1;
9555 }
9556
9557 /**
9558  * clutter_actor_get_y:
9559  * @self: A #ClutterActor
9560  *
9561  * Retrieves the Y coordinate of a #ClutterActor.
9562  *
9563  * This function tries to "do what you mean", by returning the
9564  * correct value depending on the actor's state.
9565  *
9566  * If the actor has a valid allocation, this function will return
9567  * the Y coordinate of the origin of the allocation box.
9568  *
9569  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9570  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9571  * function will return that coordinate.
9572  *
9573  * If both the allocation and a fixed position are missing, this function
9574  * will return 0.
9575  *
9576  * Return value: the Y coordinate, in pixels, ignoring any
9577  *   transformation (i.e. scaling, rotation)
9578  */
9579 gfloat
9580 clutter_actor_get_y (ClutterActor *self)
9581 {
9582   ClutterActorPrivate *priv;
9583
9584   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9585
9586   priv = self->priv;
9587
9588   if (priv->needs_allocation)
9589     {
9590       if (priv->position_set)
9591         {
9592           const ClutterLayoutInfo *info;
9593
9594           info = _clutter_actor_get_layout_info_or_defaults (self);
9595
9596           return info->fixed_y;
9597         }
9598       else
9599         return 0;
9600     }
9601   else
9602     return priv->allocation.y1;
9603 }
9604
9605 /**
9606  * clutter_actor_set_scale:
9607  * @self: A #ClutterActor
9608  * @scale_x: double factor to scale actor by horizontally.
9609  * @scale_y: double factor to scale actor by vertically.
9610  *
9611  * Scales an actor with the given factors. The scaling is relative to
9612  * the scale center and the anchor point. The scale center is
9613  * unchanged by this function and defaults to 0,0.
9614  *
9615  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9616  * animatable.
9617  *
9618  * Since: 0.2
9619  */
9620 void
9621 clutter_actor_set_scale (ClutterActor *self,
9622                          gdouble       scale_x,
9623                          gdouble       scale_y)
9624 {
9625   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9626
9627   g_object_freeze_notify (G_OBJECT (self));
9628
9629   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9630   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9631
9632   g_object_thaw_notify (G_OBJECT (self));
9633 }
9634
9635 /**
9636  * clutter_actor_set_scale_full:
9637  * @self: A #ClutterActor
9638  * @scale_x: double factor to scale actor by horizontally.
9639  * @scale_y: double factor to scale actor by vertically.
9640  * @center_x: X coordinate of the center of the scale.
9641  * @center_y: Y coordinate of the center of the scale
9642  *
9643  * Scales an actor with the given factors around the given center
9644  * point. The center point is specified in pixels relative to the
9645  * anchor point (usually the top left corner of the actor).
9646  *
9647  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9648  * are animatable.
9649  *
9650  * Since: 1.0
9651  */
9652 void
9653 clutter_actor_set_scale_full (ClutterActor *self,
9654                               gdouble       scale_x,
9655                               gdouble       scale_y,
9656                               gfloat        center_x,
9657                               gfloat        center_y)
9658 {
9659   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9660
9661   g_object_freeze_notify (G_OBJECT (self));
9662
9663   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9664   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9665   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9666   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9667
9668   g_object_thaw_notify (G_OBJECT (self));
9669 }
9670
9671 /**
9672  * clutter_actor_set_scale_with_gravity:
9673  * @self: A #ClutterActor
9674  * @scale_x: double factor to scale actor by horizontally.
9675  * @scale_y: double factor to scale actor by vertically.
9676  * @gravity: the location of the scale center expressed as a compass
9677  * direction.
9678  *
9679  * Scales an actor with the given factors around the given
9680  * center point. The center point is specified as one of the compass
9681  * directions in #ClutterGravity. For example, setting it to north
9682  * will cause the top of the actor to remain unchanged and the rest of
9683  * the actor to expand left, right and downwards.
9684  *
9685  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9686  * animatable.
9687  *
9688  * Since: 1.0
9689  */
9690 void
9691 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9692                                       gdouble         scale_x,
9693                                       gdouble         scale_y,
9694                                       ClutterGravity  gravity)
9695 {
9696   ClutterTransformInfo *info;
9697   GObject *obj;
9698
9699   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9700
9701   obj = G_OBJECT (self);
9702
9703   g_object_freeze_notify (obj);
9704
9705   info = _clutter_actor_get_transform_info (self);
9706   info->scale_x = scale_x;
9707   info->scale_y = scale_y;
9708
9709   if (gravity == CLUTTER_GRAVITY_NONE)
9710     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9711   else
9712     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9713
9714   self->priv->transform_valid = FALSE;
9715
9716   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9717   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9718   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9719   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9720   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9721
9722   clutter_actor_queue_redraw (self);
9723
9724   g_object_thaw_notify (obj);
9725 }
9726
9727 /**
9728  * clutter_actor_get_scale:
9729  * @self: A #ClutterActor
9730  * @scale_x: (out) (allow-none): Location to store horizonal
9731  *   scale factor, or %NULL.
9732  * @scale_y: (out) (allow-none): Location to store vertical
9733  *   scale factor, or %NULL.
9734  *
9735  * Retrieves an actors scale factors.
9736  *
9737  * Since: 0.2
9738  */
9739 void
9740 clutter_actor_get_scale (ClutterActor *self,
9741                          gdouble      *scale_x,
9742                          gdouble      *scale_y)
9743 {
9744   const ClutterTransformInfo *info;
9745
9746   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9747
9748   info = _clutter_actor_get_transform_info_or_defaults (self);
9749
9750   if (scale_x)
9751     *scale_x = info->scale_x;
9752
9753   if (scale_y)
9754     *scale_y = info->scale_y;
9755 }
9756
9757 /**
9758  * clutter_actor_get_scale_center:
9759  * @self: A #ClutterActor
9760  * @center_x: (out) (allow-none): Location to store the X position
9761  *   of the scale center, or %NULL.
9762  * @center_y: (out) (allow-none): Location to store the Y position
9763  *   of the scale center, or %NULL.
9764  *
9765  * Retrieves the scale center coordinate in pixels relative to the top
9766  * left corner of the actor. If the scale center was specified using a
9767  * #ClutterGravity this will calculate the pixel offset using the
9768  * current size of the actor.
9769  *
9770  * Since: 1.0
9771  */
9772 void
9773 clutter_actor_get_scale_center (ClutterActor *self,
9774                                 gfloat       *center_x,
9775                                 gfloat       *center_y)
9776 {
9777   const ClutterTransformInfo *info;
9778
9779   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9780
9781   info = _clutter_actor_get_transform_info_or_defaults (self);
9782
9783   clutter_anchor_coord_get_units (self, &info->scale_center,
9784                                   center_x,
9785                                   center_y,
9786                                   NULL);
9787 }
9788
9789 /**
9790  * clutter_actor_get_scale_gravity:
9791  * @self: A #ClutterActor
9792  *
9793  * Retrieves the scale center as a compass direction. If the scale
9794  * center was specified in pixels or units this will return
9795  * %CLUTTER_GRAVITY_NONE.
9796  *
9797  * Return value: the scale gravity
9798  *
9799  * Since: 1.0
9800  */
9801 ClutterGravity
9802 clutter_actor_get_scale_gravity (ClutterActor *self)
9803 {
9804   const ClutterTransformInfo *info;
9805
9806   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9807
9808   info = _clutter_actor_get_transform_info_or_defaults (self);
9809
9810   return clutter_anchor_coord_get_gravity (&info->scale_center);
9811 }
9812
9813 static inline void
9814 clutter_actor_set_opacity_internal (ClutterActor *self,
9815                                     guint8        opacity)
9816 {
9817   ClutterActorPrivate *priv = self->priv;
9818
9819   if (priv->opacity != opacity)
9820     {
9821       priv->opacity = opacity;
9822
9823       /* Queue a redraw from the flatten effect so that it can use
9824          its cached image if available instead of having to redraw the
9825          actual actor. If it doesn't end up using the FBO then the
9826          effect is still able to continue the paint anyway. If there
9827          is no flatten effect yet then this is equivalent to queueing
9828          a full redraw */
9829       _clutter_actor_queue_redraw_full (self,
9830                                         0, /* flags */
9831                                         NULL, /* clip */
9832                                         priv->flatten_effect);
9833
9834       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9835     }
9836 }
9837
9838 /**
9839  * clutter_actor_set_opacity:
9840  * @self: A #ClutterActor
9841  * @opacity: New opacity value for the actor.
9842  *
9843  * Sets the actor's opacity, with zero being completely transparent and
9844  * 255 (0xff) being fully opaque.
9845  *
9846  * The #ClutterActor:opacity property is animatable.
9847  */
9848 void
9849 clutter_actor_set_opacity (ClutterActor *self,
9850                            guint8        opacity)
9851 {
9852   ClutterActorPrivate *priv;
9853
9854   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9855
9856   priv = self->priv;
9857
9858   if (clutter_actor_get_easing_duration (self) != 0)
9859     {
9860       ClutterTransition *transition;
9861
9862       transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9863       if (transition == NULL)
9864         {
9865           transition = _clutter_actor_create_transition (self,
9866                                                          obj_props[PROP_OPACITY],
9867                                                          priv->opacity,
9868                                                          opacity);
9869           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9870         }
9871       else
9872         _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9873
9874       clutter_actor_queue_redraw (self);
9875     }
9876   else
9877     clutter_actor_set_opacity_internal (self, opacity);
9878 }
9879
9880 /*
9881  * clutter_actor_get_paint_opacity_internal:
9882  * @self: a #ClutterActor
9883  *
9884  * Retrieves the absolute opacity of the actor, as it appears on the stage
9885  *
9886  * This function does not do type checks
9887  *
9888  * Return value: the absolute opacity of the actor
9889  */
9890 static guint8
9891 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9892 {
9893   ClutterActorPrivate *priv = self->priv;
9894   ClutterActor *parent;
9895
9896   /* override the top-level opacity to always be 255; even in
9897    * case of ClutterStage:use-alpha being TRUE we want the rest
9898    * of the scene to be painted
9899    */
9900   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9901     return 255;
9902
9903   if (priv->opacity_override >= 0)
9904     return priv->opacity_override;
9905
9906   parent = priv->parent;
9907
9908   /* Factor in the actual actors opacity with parents */
9909   if (parent != NULL)
9910     {
9911       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9912
9913       if (opacity != 0xff)
9914         return (opacity * priv->opacity) / 0xff;
9915     }
9916
9917   return priv->opacity;
9918
9919 }
9920
9921 /**
9922  * clutter_actor_get_paint_opacity:
9923  * @self: A #ClutterActor
9924  *
9925  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9926  *
9927  * This function traverses the hierarchy chain and composites the opacity of
9928  * the actor with that of its parents.
9929  *
9930  * This function is intended for subclasses to use in the paint virtual
9931  * function, to paint themselves with the correct opacity.
9932  *
9933  * Return value: The actor opacity value.
9934  *
9935  * Since: 0.8
9936  */
9937 guint8
9938 clutter_actor_get_paint_opacity (ClutterActor *self)
9939 {
9940   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9941
9942   return clutter_actor_get_paint_opacity_internal (self);
9943 }
9944
9945 /**
9946  * clutter_actor_get_opacity:
9947  * @self: a #ClutterActor
9948  *
9949  * Retrieves the opacity value of an actor, as set by
9950  * clutter_actor_set_opacity().
9951  *
9952  * For retrieving the absolute opacity of the actor inside a paint
9953  * virtual function, see clutter_actor_get_paint_opacity().
9954  *
9955  * Return value: the opacity of the actor
9956  */
9957 guint8
9958 clutter_actor_get_opacity (ClutterActor *self)
9959 {
9960   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9961
9962   return self->priv->opacity;
9963 }
9964
9965 /**
9966  * clutter_actor_set_offscreen_redirect:
9967  * @self: A #ClutterActor
9968  * @redirect: New offscreen redirect flags for the actor.
9969  *
9970  * Defines the circumstances where the actor should be redirected into
9971  * an offscreen image. The offscreen image is used to flatten the
9972  * actor into a single image while painting for two main reasons.
9973  * Firstly, when the actor is painted a second time without any of its
9974  * contents changing it can simply repaint the cached image without
9975  * descending further down the actor hierarchy. Secondly, it will make
9976  * the opacity look correct even if there are overlapping primitives
9977  * in the actor.
9978  *
9979  * Caching the actor could in some cases be a performance win and in
9980  * some cases be a performance lose so it is important to determine
9981  * which value is right for an actor before modifying this value. For
9982  * example, there is never any reason to flatten an actor that is just
9983  * a single texture (such as a #ClutterTexture) because it is
9984  * effectively already cached in an image so the offscreen would be
9985  * redundant. Also if the actor contains primitives that are far apart
9986  * with a large transparent area in the middle (such as a large
9987  * CluterGroup with a small actor in the top left and a small actor in
9988  * the bottom right) then the cached image will contain the entire
9989  * image of the large area and the paint will waste time blending all
9990  * of the transparent pixels in the middle.
9991  *
9992  * The default method of implementing opacity on a container simply
9993  * forwards on the opacity to all of the children. If the children are
9994  * overlapping then it will appear as if they are two separate glassy
9995  * objects and there will be a break in the color where they
9996  * overlap. By redirecting to an offscreen buffer it will be as if the
9997  * two opaque objects are combined into one and then made transparent
9998  * which is usually what is expected.
9999  *
10000  * The image below demonstrates the difference between redirecting and
10001  * not. The image shows two Clutter groups, each containing a red and
10002  * a green rectangle which overlap. The opacity on the group is set to
10003  * 128 (which is 50%). When the offscreen redirect is not used, the
10004  * red rectangle can be seen through the blue rectangle as if the two
10005  * rectangles were separately transparent. When the redirect is used
10006  * the group as a whole is transparent instead so the red rectangle is
10007  * not visible where they overlap.
10008  *
10009  * <figure id="offscreen-redirect">
10010  *   <title>Sample of using an offscreen redirect for transparency</title>
10011  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10012  * </figure>
10013  *
10014  * The default value for this property is 0, so we effectively will
10015  * never redirect an actor offscreen by default. This means that there
10016  * are times that transparent actors may look glassy as described
10017  * above. The reason this is the default is because there is a
10018  * performance trade off between quality and performance here. In many
10019  * cases the default form of glassy opacity looks good enough, but if
10020  * it's not you will need to set the
10021  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10022  * redirection for opacity.
10023  *
10024  * Custom actors that don't contain any overlapping primitives are
10025  * recommended to override the has_overlaps() virtual to return %FALSE
10026  * for maximum efficiency.
10027  *
10028  * Since: 1.8
10029  */
10030 void
10031 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10032                                       ClutterOffscreenRedirect redirect)
10033 {
10034   ClutterActorPrivate *priv;
10035
10036   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10037
10038   priv = self->priv;
10039
10040   if (priv->offscreen_redirect != redirect)
10041     {
10042       priv->offscreen_redirect = redirect;
10043
10044       /* Queue a redraw from the effect so that it can use its cached
10045          image if available instead of having to redraw the actual
10046          actor. If it doesn't end up using the FBO then the effect is
10047          still able to continue the paint anyway. If there is no
10048          effect then this is equivalent to queuing a full redraw */
10049       _clutter_actor_queue_redraw_full (self,
10050                                         0, /* flags */
10051                                         NULL, /* clip */
10052                                         priv->flatten_effect);
10053
10054       g_object_notify_by_pspec (G_OBJECT (self),
10055                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10056     }
10057 }
10058
10059 /**
10060  * clutter_actor_get_offscreen_redirect:
10061  * @self: a #ClutterActor
10062  *
10063  * Retrieves whether to redirect the actor to an offscreen buffer, as
10064  * set by clutter_actor_set_offscreen_redirect().
10065  *
10066  * Return value: the value of the offscreen-redirect property of the actor
10067  *
10068  * Since: 1.8
10069  */
10070 ClutterOffscreenRedirect
10071 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10072 {
10073   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10074
10075   return self->priv->offscreen_redirect;
10076 }
10077
10078 /**
10079  * clutter_actor_set_name:
10080  * @self: A #ClutterActor
10081  * @name: Textual tag to apply to actor
10082  *
10083  * Sets the given name to @self. The name can be used to identify
10084  * a #ClutterActor.
10085  */
10086 void
10087 clutter_actor_set_name (ClutterActor *self,
10088                         const gchar  *name)
10089 {
10090   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10091
10092   g_free (self->priv->name);
10093   self->priv->name = g_strdup (name);
10094
10095   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10096 }
10097
10098 /**
10099  * clutter_actor_get_name:
10100  * @self: A #ClutterActor
10101  *
10102  * Retrieves the name of @self.
10103  *
10104  * Return value: the name of the actor, or %NULL. The returned string is
10105  *   owned by the actor and should not be modified or freed.
10106  */
10107 const gchar *
10108 clutter_actor_get_name (ClutterActor *self)
10109 {
10110   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10111
10112   return self->priv->name;
10113 }
10114
10115 /**
10116  * clutter_actor_get_gid:
10117  * @self: A #ClutterActor
10118  *
10119  * Retrieves the unique id for @self.
10120  *
10121  * Return value: Globally unique value for this object instance.
10122  *
10123  * Since: 0.6
10124  *
10125  * Deprecated: 1.8: The id is not used any longer.
10126  */
10127 guint32
10128 clutter_actor_get_gid (ClutterActor *self)
10129 {
10130   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10131
10132   return self->priv->id;
10133 }
10134
10135 static inline void
10136 clutter_actor_set_depth_internal (ClutterActor *self,
10137                                   float         depth)
10138 {
10139   ClutterTransformInfo *info;
10140
10141   info = _clutter_actor_get_transform_info (self);
10142
10143   if (info->depth != depth)
10144     {
10145       /* Sets Z value - XXX 2.0: should we invert? */
10146       info->depth = depth;
10147
10148       self->priv->transform_valid = FALSE;
10149
10150       /* FIXME - remove this crap; sadly, there are still containers
10151        * in Clutter that depend on this utter brain damage
10152        */
10153       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10154
10155       clutter_actor_queue_redraw (self);
10156
10157       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10158     }
10159 }
10160
10161 /**
10162  * clutter_actor_set_depth:
10163  * @self: a #ClutterActor
10164  * @depth: Z co-ord
10165  *
10166  * Sets the Z coordinate of @self to @depth.
10167  *
10168  * The unit used by @depth is dependant on the perspective setup. See
10169  * also clutter_stage_set_perspective().
10170  */
10171 void
10172 clutter_actor_set_depth (ClutterActor *self,
10173                          gfloat        depth)
10174 {
10175   const ClutterTransformInfo *tinfo;
10176
10177   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10178
10179   tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10180
10181   if (clutter_actor_get_easing_duration (self) != 0)
10182     {
10183       ClutterTransition *transition;
10184
10185       transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10186       if (transition == NULL)
10187         {
10188           transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10189                                                          tinfo->depth,
10190                                                          depth);
10191           clutter_timeline_start (CLUTTER_TIMELINE (transition));
10192         }
10193       else
10194         _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10195
10196       clutter_actor_queue_redraw (self);
10197     }
10198   else
10199     clutter_actor_set_depth_internal (self, depth);
10200 }
10201
10202 /**
10203  * clutter_actor_get_depth:
10204  * @self: a #ClutterActor
10205  *
10206  * Retrieves the depth of @self.
10207  *
10208  * Return value: the depth of the actor
10209  */
10210 gfloat
10211 clutter_actor_get_depth (ClutterActor *self)
10212 {
10213   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10214
10215   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10216 }
10217
10218 /**
10219  * clutter_actor_set_rotation:
10220  * @self: a #ClutterActor
10221  * @axis: the axis of rotation
10222  * @angle: the angle of rotation
10223  * @x: X coordinate of the rotation center
10224  * @y: Y coordinate of the rotation center
10225  * @z: Z coordinate of the rotation center
10226  *
10227  * Sets the rotation angle of @self around the given axis.
10228  *
10229  * The rotation center coordinates used depend on the value of @axis:
10230  * <itemizedlist>
10231  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10232  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10233  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10234  * </itemizedlist>
10235  *
10236  * The rotation coordinates are relative to the anchor point of the
10237  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10238  * point is set, the upper left corner is assumed as the origin.
10239  *
10240  * Since: 0.8
10241  */
10242 void
10243 clutter_actor_set_rotation (ClutterActor      *self,
10244                             ClutterRotateAxis  axis,
10245                             gdouble            angle,
10246                             gfloat             x,
10247                             gfloat             y,
10248                             gfloat             z)
10249 {
10250   ClutterVertex v;
10251
10252   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10253
10254   v.x = x;
10255   v.y = y;
10256   v.z = z;
10257
10258   g_object_freeze_notify (G_OBJECT (self));
10259
10260   clutter_actor_set_rotation_angle (self, axis, angle);
10261   clutter_actor_set_rotation_center_internal (self, axis, &v);
10262
10263   g_object_thaw_notify (G_OBJECT (self));
10264 }
10265
10266 /**
10267  * clutter_actor_set_z_rotation_from_gravity:
10268  * @self: a #ClutterActor
10269  * @angle: the angle of rotation
10270  * @gravity: the center point of the rotation
10271  *
10272  * Sets the rotation angle of @self around the Z axis using the center
10273  * point specified as a compass point. For example to rotate such that
10274  * the center of the actor remains static you can use
10275  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10276  * will move accordingly.
10277  *
10278  * Since: 1.0
10279  */
10280 void
10281 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10282                                            gdouble         angle,
10283                                            ClutterGravity  gravity)
10284 {
10285   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10286
10287   if (gravity == CLUTTER_GRAVITY_NONE)
10288     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10289   else
10290     {
10291       GObject *obj = G_OBJECT (self);
10292       ClutterTransformInfo *info;
10293
10294       info = _clutter_actor_get_transform_info (self);
10295
10296       g_object_freeze_notify (obj);
10297
10298       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10299
10300       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10301       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10302       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10303
10304       g_object_thaw_notify (obj);
10305     }
10306 }
10307
10308 /**
10309  * clutter_actor_get_rotation:
10310  * @self: a #ClutterActor
10311  * @axis: the axis of rotation
10312  * @x: (out): return value for the X coordinate of the center of rotation
10313  * @y: (out): return value for the Y coordinate of the center of rotation
10314  * @z: (out): return value for the Z coordinate of the center of rotation
10315  *
10316  * Retrieves the angle and center of rotation on the given axis,
10317  * set using clutter_actor_set_rotation().
10318  *
10319  * Return value: the angle of rotation
10320  *
10321  * Since: 0.8
10322  */
10323 gdouble
10324 clutter_actor_get_rotation (ClutterActor      *self,
10325                             ClutterRotateAxis  axis,
10326                             gfloat            *x,
10327                             gfloat            *y,
10328                             gfloat            *z)
10329 {
10330   const ClutterTransformInfo *info;
10331   const AnchorCoord *anchor_coord;
10332   gdouble retval = 0;
10333
10334   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10335
10336   info = _clutter_actor_get_transform_info_or_defaults (self);
10337
10338   switch (axis)
10339     {
10340     case CLUTTER_X_AXIS:
10341       anchor_coord = &info->rx_center;
10342       retval = info->rx_angle;
10343       break;
10344
10345     case CLUTTER_Y_AXIS:
10346       anchor_coord = &info->ry_center;
10347       retval = info->ry_angle;
10348       break;
10349
10350     case CLUTTER_Z_AXIS:
10351       anchor_coord = &info->rz_center;
10352       retval = info->rz_angle;
10353       break;
10354
10355     default:
10356       anchor_coord = NULL;
10357       retval = 0.0;
10358       break;
10359     }
10360
10361   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10362
10363   return retval;
10364 }
10365
10366 /**
10367  * clutter_actor_get_z_rotation_gravity:
10368  * @self: A #ClutterActor
10369  *
10370  * Retrieves the center for the rotation around the Z axis as a
10371  * compass direction. If the center was specified in pixels or units
10372  * this will return %CLUTTER_GRAVITY_NONE.
10373  *
10374  * Return value: the Z rotation center
10375  *
10376  * Since: 1.0
10377  */
10378 ClutterGravity
10379 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10380 {
10381   const ClutterTransformInfo *info;
10382
10383   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10384
10385   info = _clutter_actor_get_transform_info_or_defaults (self);
10386
10387   return clutter_anchor_coord_get_gravity (&info->rz_center);
10388 }
10389
10390 /**
10391  * clutter_actor_set_clip:
10392  * @self: A #ClutterActor
10393  * @xoff: X offset of the clip rectangle
10394  * @yoff: Y offset of the clip rectangle
10395  * @width: Width of the clip rectangle
10396  * @height: Height of the clip rectangle
10397  *
10398  * Sets clip area for @self. The clip area is always computed from the
10399  * upper left corner of the actor, even if the anchor point is set
10400  * otherwise.
10401  *
10402  * Since: 0.6
10403  */
10404 void
10405 clutter_actor_set_clip (ClutterActor *self,
10406                         gfloat        xoff,
10407                         gfloat        yoff,
10408                         gfloat        width,
10409                         gfloat        height)
10410 {
10411   ClutterActorPrivate *priv;
10412
10413   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10414
10415   priv = self->priv;
10416
10417   if (priv->has_clip &&
10418       priv->clip.x == xoff &&
10419       priv->clip.y == yoff &&
10420       priv->clip.width == width &&
10421       priv->clip.height == height)
10422     return;
10423
10424   priv->clip.x = xoff;
10425   priv->clip.y = yoff;
10426   priv->clip.width = width;
10427   priv->clip.height = height;
10428
10429   priv->has_clip = TRUE;
10430
10431   clutter_actor_queue_redraw (self);
10432
10433   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10434   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10435 }
10436
10437 /**
10438  * clutter_actor_remove_clip:
10439  * @self: A #ClutterActor
10440  *
10441  * Removes clip area from @self.
10442  */
10443 void
10444 clutter_actor_remove_clip (ClutterActor *self)
10445 {
10446   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10447
10448   if (!self->priv->has_clip)
10449     return;
10450
10451   self->priv->has_clip = FALSE;
10452
10453   clutter_actor_queue_redraw (self);
10454
10455   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10456 }
10457
10458 /**
10459  * clutter_actor_has_clip:
10460  * @self: a #ClutterActor
10461  *
10462  * Determines whether the actor has a clip area set or not.
10463  *
10464  * Return value: %TRUE if the actor has a clip area set.
10465  *
10466  * Since: 0.1.1
10467  */
10468 gboolean
10469 clutter_actor_has_clip (ClutterActor *self)
10470 {
10471   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10472
10473   return self->priv->has_clip;
10474 }
10475
10476 /**
10477  * clutter_actor_get_clip:
10478  * @self: a #ClutterActor
10479  * @xoff: (out) (allow-none): return location for the X offset of
10480  *   the clip rectangle, or %NULL
10481  * @yoff: (out) (allow-none): return location for the Y offset of
10482  *   the clip rectangle, or %NULL
10483  * @width: (out) (allow-none): return location for the width of
10484  *   the clip rectangle, or %NULL
10485  * @height: (out) (allow-none): return location for the height of
10486  *   the clip rectangle, or %NULL
10487  *
10488  * Gets the clip area for @self, if any is set
10489  *
10490  * Since: 0.6
10491  */
10492 void
10493 clutter_actor_get_clip (ClutterActor *self,
10494                         gfloat       *xoff,
10495                         gfloat       *yoff,
10496                         gfloat       *width,
10497                         gfloat       *height)
10498 {
10499   ClutterActorPrivate *priv;
10500
10501   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10502
10503   priv = self->priv;
10504
10505   if (!priv->has_clip)
10506     return;
10507
10508   if (xoff != NULL)
10509     *xoff = priv->clip.x;
10510
10511   if (yoff != NULL)
10512     *yoff = priv->clip.y;
10513
10514   if (width != NULL)
10515     *width = priv->clip.width;
10516
10517   if (height != NULL)
10518     *height = priv->clip.height;
10519 }
10520
10521 /**
10522  * clutter_actor_get_children:
10523  * @self: a #ClutterActor
10524  *
10525  * Retrieves the list of children of @self.
10526  *
10527  * Return value: (transfer container) (element-type ClutterActor): A newly
10528  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10529  *   done.
10530  *
10531  * Since: 1.10
10532  */
10533 GList *
10534 clutter_actor_get_children (ClutterActor *self)
10535 {
10536   ClutterActor *iter;
10537   GList *res;
10538
10539   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10540
10541   /* we walk the list backward so that we can use prepend(),
10542    * which is O(1)
10543    */
10544   for (iter = self->priv->last_child, res = NULL;
10545        iter != NULL;
10546        iter = iter->priv->prev_sibling)
10547     {
10548       res = g_list_prepend (res, iter);
10549     }
10550
10551   return res;
10552 }
10553
10554 /*< private >
10555  * insert_child_at_depth:
10556  * @self: a #ClutterActor
10557  * @child: a #ClutterActor
10558  *
10559  * Inserts @child inside the list of children held by @self, using
10560  * the depth as the insertion criteria.
10561  *
10562  * This sadly makes the insertion not O(1), but we can keep the
10563  * list sorted so that the painters algorithm we use for painting
10564  * the children will work correctly.
10565  */
10566 static void
10567 insert_child_at_depth (ClutterActor *self,
10568                        ClutterActor *child,
10569                        gpointer      dummy G_GNUC_UNUSED)
10570 {
10571   ClutterActor *iter;
10572   float child_depth;
10573
10574   child->priv->parent = self;
10575
10576   child_depth =
10577     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10578
10579   /* special-case the first child */
10580   if (self->priv->n_children == 0)
10581     {
10582       self->priv->first_child = child;
10583       self->priv->last_child = child;
10584
10585       child->priv->next_sibling = NULL;
10586       child->priv->prev_sibling = NULL;
10587
10588       return;
10589     }
10590
10591   /* Find the right place to insert the child so that it will still be
10592      sorted and the child will be after all of the actors at the same
10593      dept */
10594   for (iter = self->priv->first_child;
10595        iter != NULL;
10596        iter = iter->priv->next_sibling)
10597     {
10598       float iter_depth;
10599
10600       iter_depth =
10601         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10602
10603       if (iter_depth > child_depth)
10604         break;
10605     }
10606
10607   if (iter != NULL)
10608     {
10609       ClutterActor *tmp = iter->priv->prev_sibling;
10610
10611       if (tmp != NULL)
10612         tmp->priv->next_sibling = child;
10613
10614       /* Insert the node before the found one */
10615       child->priv->prev_sibling = iter->priv->prev_sibling;
10616       child->priv->next_sibling = iter;
10617       iter->priv->prev_sibling = child;
10618     }
10619   else
10620     {
10621       ClutterActor *tmp = self->priv->last_child;
10622
10623       if (tmp != NULL)
10624         tmp->priv->next_sibling = child;
10625
10626       /* insert the node at the end of the list */
10627       child->priv->prev_sibling = self->priv->last_child;
10628       child->priv->next_sibling = NULL;
10629     }
10630
10631   if (child->priv->prev_sibling == NULL)
10632     self->priv->first_child = child;
10633
10634   if (child->priv->next_sibling == NULL)
10635     self->priv->last_child = child;
10636 }
10637
10638 static void
10639 insert_child_at_index (ClutterActor *self,
10640                        ClutterActor *child,
10641                        gpointer      data_)
10642 {
10643   gint index_ = GPOINTER_TO_INT (data_);
10644
10645   child->priv->parent = self;
10646
10647   if (index_ == 0)
10648     {
10649       ClutterActor *tmp = self->priv->first_child;
10650
10651       if (tmp != NULL)
10652         tmp->priv->prev_sibling = child;
10653
10654       child->priv->prev_sibling = NULL;
10655       child->priv->next_sibling = tmp;
10656     }
10657   else if (index_ < 0 || index_ >= self->priv->n_children)
10658     {
10659       ClutterActor *tmp = self->priv->last_child;
10660
10661       if (tmp != NULL)
10662         tmp->priv->next_sibling = child;
10663
10664       child->priv->prev_sibling = tmp;
10665       child->priv->next_sibling = NULL;
10666     }
10667   else
10668     {
10669       ClutterActor *iter;
10670       int i;
10671
10672       for (iter = self->priv->first_child, i = 0;
10673            iter != NULL;
10674            iter = iter->priv->next_sibling, i += 1)
10675         {
10676           if (index_ == i)
10677             {
10678               ClutterActor *tmp = iter->priv->prev_sibling;
10679
10680               child->priv->prev_sibling = tmp;
10681               child->priv->next_sibling = iter;
10682
10683               iter->priv->prev_sibling = child;
10684
10685               if (tmp != NULL)
10686                 tmp->priv->next_sibling = child;
10687
10688               break;
10689             }
10690         }
10691     }
10692
10693   if (child->priv->prev_sibling == NULL)
10694     self->priv->first_child = child;
10695
10696   if (child->priv->next_sibling == NULL)
10697     self->priv->last_child = child;
10698 }
10699
10700 static void
10701 insert_child_above (ClutterActor *self,
10702                     ClutterActor *child,
10703                     gpointer      data)
10704 {
10705   ClutterActor *sibling = data;
10706
10707   child->priv->parent = self;
10708
10709   if (sibling == NULL)
10710     sibling = self->priv->last_child;
10711
10712   child->priv->prev_sibling = sibling;
10713
10714   if (sibling != NULL)
10715     {
10716       ClutterActor *tmp = sibling->priv->next_sibling;
10717
10718       child->priv->next_sibling = tmp;
10719
10720       if (tmp != NULL)
10721         tmp->priv->prev_sibling = child;
10722
10723       sibling->priv->next_sibling = child;
10724     }
10725   else
10726     child->priv->next_sibling = NULL;
10727
10728   if (child->priv->prev_sibling == NULL)
10729     self->priv->first_child = child;
10730
10731   if (child->priv->next_sibling == NULL)
10732     self->priv->last_child = child;
10733 }
10734
10735 static void
10736 insert_child_below (ClutterActor *self,
10737                     ClutterActor *child,
10738                     gpointer      data)
10739 {
10740   ClutterActor *sibling = data;
10741
10742   child->priv->parent = self;
10743
10744   if (sibling == NULL)
10745     sibling = self->priv->first_child;
10746
10747   child->priv->next_sibling = sibling;
10748
10749   if (sibling != NULL)
10750     {
10751       ClutterActor *tmp = sibling->priv->prev_sibling;
10752
10753       child->priv->prev_sibling = tmp;
10754
10755       if (tmp != NULL)
10756         tmp->priv->next_sibling = child;
10757
10758       sibling->priv->prev_sibling = child;
10759     }
10760   else
10761     child->priv->prev_sibling = NULL;
10762
10763   if (child->priv->prev_sibling == NULL)
10764     self->priv->first_child = child;
10765
10766   if (child->priv->next_sibling == NULL)
10767     self->priv->last_child = child;
10768 }
10769
10770 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10771                                            ClutterActor *child,
10772                                            gpointer      data);
10773
10774 typedef enum {
10775   ADD_CHILD_CREATE_META       = 1 << 0,
10776   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10777   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10778   ADD_CHILD_CHECK_STATE       = 1 << 3,
10779   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10780
10781   /* default flags for public API */
10782   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10783                                ADD_CHILD_EMIT_PARENT_SET |
10784                                ADD_CHILD_EMIT_ACTOR_ADDED |
10785                                ADD_CHILD_CHECK_STATE |
10786                                ADD_CHILD_NOTIFY_FIRST_LAST,
10787
10788   /* flags for legacy/deprecated API */
10789   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10790                                ADD_CHILD_CHECK_STATE |
10791                                ADD_CHILD_NOTIFY_FIRST_LAST
10792 } ClutterActorAddChildFlags;
10793
10794 /*< private >
10795  * clutter_actor_add_child_internal:
10796  * @self: a #ClutterActor
10797  * @child: a #ClutterActor
10798  * @flags: control flags for actions
10799  * @add_func: delegate function
10800  * @data: (closure): data to pass to @add_func
10801  *
10802  * Adds @child to the list of children of @self.
10803  *
10804  * The actual insertion inside the list is delegated to @add_func: this
10805  * function will just set up the state, perform basic checks, and emit
10806  * signals.
10807  *
10808  * The @flags argument is used to perform additional operations.
10809  */
10810 static inline void
10811 clutter_actor_add_child_internal (ClutterActor              *self,
10812                                   ClutterActor              *child,
10813                                   ClutterActorAddChildFlags  flags,
10814                                   ClutterActorAddChildFunc   add_func,
10815                                   gpointer                   data)
10816 {
10817   ClutterTextDirection text_dir;
10818   gboolean create_meta;
10819   gboolean emit_parent_set, emit_actor_added;
10820   gboolean check_state;
10821   gboolean notify_first_last;
10822   ClutterActor *old_first_child, *old_last_child;
10823
10824   if (child->priv->parent != NULL)
10825     {
10826       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10827                  "use clutter_actor_remove_child() first.",
10828                  _clutter_actor_get_debug_name (child),
10829                  _clutter_actor_get_debug_name (child->priv->parent));
10830       return;
10831     }
10832
10833   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10834     {
10835       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10836                  "a child of another actor.",
10837                  _clutter_actor_get_debug_name (child));
10838       return;
10839     }
10840
10841 #if 0
10842   /* XXX - this check disallows calling methods that change the stacking
10843    * order within the destruction sequence, by triggering a critical
10844    * warning first, and leaving the actor in an undefined state, which
10845    * then ends up being caught by an assertion.
10846    *
10847    * the reproducible sequence is:
10848    *
10849    *   - actor gets destroyed;
10850    *   - another actor, linked to the first, will try to change the
10851    *     stacking order of the first actor;
10852    *   - changing the stacking order is a composite operation composed
10853    *     by the following steps:
10854    *     1. ref() the child;
10855    *     2. remove_child_internal(), which removes the reference;
10856    *     3. add_child_internal(), which adds a reference;
10857    *   - the state of the actor is not changed between (2) and (3), as
10858    *     it could be an expensive recomputation;
10859    *   - if (3) bails out, then the actor is in an undefined state, but
10860    *     still alive;
10861    *   - the destruction sequence terminates, but the actor is unparented
10862    *     while its state indicates being parented instead.
10863    *   - assertion failure.
10864    *
10865    * the obvious fix would be to decompose each set_child_*_sibling()
10866    * method into proper remove_child()/add_child(), with state validation;
10867    * this may cause excessive work, though, and trigger a cascade of other
10868    * bugs in code that assumes that a change in the stacking order is an
10869    * atomic operation.
10870    *
10871    * another potential fix is to just remove this check here, and let
10872    * code doing stacking order changes inside the destruction sequence
10873    * of an actor continue doing the work.
10874    *
10875    * the third fix is to silently bail out early from every
10876    * set_child_*_sibling() and set_child_at_index() method, and avoid
10877    * doing work.
10878    *
10879    * I have a preference for the second solution, since it involves the
10880    * least amount of work, and the least amount of code duplication.
10881    *
10882    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10883    */
10884   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10885     {
10886       g_warning ("The actor '%s' is currently being destroyed, and "
10887                  "cannot be added as a child of another actor.",
10888                  _clutter_actor_get_debug_name (child));
10889       return;
10890     }
10891 #endif
10892
10893   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10894   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10895   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10896   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10897   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10898
10899   old_first_child = self->priv->first_child;
10900   old_last_child = self->priv->last_child;
10901
10902   g_object_freeze_notify (G_OBJECT (self));
10903
10904   if (create_meta)
10905     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10906
10907   g_object_ref_sink (child);
10908   child->priv->parent = NULL;
10909   child->priv->next_sibling = NULL;
10910   child->priv->prev_sibling = NULL;
10911
10912   /* delegate the actual insertion */
10913   add_func (self, child, data);
10914
10915   g_assert (child->priv->parent == self);
10916
10917   self->priv->n_children += 1;
10918
10919   self->priv->age += 1;
10920
10921   /* if push_internal() has been called then we automatically set
10922    * the flag on the actor
10923    */
10924   if (self->priv->internal_child)
10925     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10926
10927   /* clutter_actor_reparent() will emit ::parent-set for us */
10928   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10929     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10930
10931   if (check_state)
10932     {
10933       /* If parent is mapped or realized, we need to also be mapped or
10934        * realized once we're inside the parent.
10935        */
10936       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10937
10938       /* propagate the parent's text direction to the child */
10939       text_dir = clutter_actor_get_text_direction (self);
10940       clutter_actor_set_text_direction (child, text_dir);
10941     }
10942
10943   if (child->priv->show_on_set_parent)
10944     clutter_actor_show (child);
10945
10946   if (CLUTTER_ACTOR_IS_MAPPED (child))
10947     clutter_actor_queue_redraw (child);
10948
10949   /* maintain the invariant that if an actor needs layout,
10950    * its parents do as well
10951    */
10952   if (child->priv->needs_width_request ||
10953       child->priv->needs_height_request ||
10954       child->priv->needs_allocation)
10955     {
10956       /* we work around the short-circuiting we do
10957        * in clutter_actor_queue_relayout() since we
10958        * want to force a relayout
10959        */
10960       child->priv->needs_width_request = TRUE;
10961       child->priv->needs_height_request = TRUE;
10962       child->priv->needs_allocation = TRUE;
10963
10964       clutter_actor_queue_relayout (child->priv->parent);
10965     }
10966
10967   if (emit_actor_added)
10968     g_signal_emit_by_name (self, "actor-added", child);
10969
10970   if (notify_first_last)
10971     {
10972       if (old_first_child != self->priv->first_child)
10973         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10974
10975       if (old_last_child != self->priv->last_child)
10976         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10977     }
10978
10979   g_object_thaw_notify (G_OBJECT (self));
10980 }
10981
10982 /**
10983  * clutter_actor_add_child:
10984  * @self: a #ClutterActor
10985  * @child: a #ClutterActor
10986  *
10987  * Adds @child to the children of @self.
10988  *
10989  * This function will acquire a reference on @child that will only
10990  * be released when calling clutter_actor_remove_child().
10991  *
10992  * This function will take into consideration the #ClutterActor:depth
10993  * of @child, and will keep the list of children sorted.
10994  *
10995  * This function will emit the #ClutterContainer::actor-added signal
10996  * on @self.
10997  *
10998  * Since: 1.10
10999  */
11000 void
11001 clutter_actor_add_child (ClutterActor *self,
11002                          ClutterActor *child)
11003 {
11004   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11005   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11006   g_return_if_fail (self != child);
11007   g_return_if_fail (child->priv->parent == NULL);
11008
11009   clutter_actor_add_child_internal (self, child,
11010                                     ADD_CHILD_DEFAULT_FLAGS,
11011                                     insert_child_at_depth,
11012                                     NULL);
11013 }
11014
11015 /**
11016  * clutter_actor_insert_child_at_index:
11017  * @self: a #ClutterActor
11018  * @child: a #ClutterActor
11019  * @index_: the index
11020  *
11021  * Inserts @child into the list of children of @self, using the
11022  * given @index_. If @index_ is greater than the number of children
11023  * in @self, or is less than 0, then the new child is added at the end.
11024  *
11025  * This function will acquire a reference on @child that will only
11026  * be released when calling clutter_actor_remove_child().
11027  *
11028  * This function will not take into consideration the #ClutterActor:depth
11029  * of @child.
11030  *
11031  * This function will emit the #ClutterContainer::actor-added signal
11032  * on @self.
11033  *
11034  * Since: 1.10
11035  */
11036 void
11037 clutter_actor_insert_child_at_index (ClutterActor *self,
11038                                      ClutterActor *child,
11039                                      gint          index_)
11040 {
11041   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11042   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11043   g_return_if_fail (self != child);
11044   g_return_if_fail (child->priv->parent == NULL);
11045
11046   clutter_actor_add_child_internal (self, child,
11047                                     ADD_CHILD_DEFAULT_FLAGS,
11048                                     insert_child_at_index,
11049                                     GINT_TO_POINTER (index_));
11050 }
11051
11052 /**
11053  * clutter_actor_insert_child_above:
11054  * @self: a #ClutterActor
11055  * @child: a #ClutterActor
11056  * @sibling: (allow-none): a child of @self, or %NULL
11057  *
11058  * Inserts @child into the list of children of @self, above another
11059  * child of @self or, if @sibling is %NULL, above all the children
11060  * of @self.
11061  *
11062  * This function will acquire a reference on @child that will only
11063  * be released when calling clutter_actor_remove_child().
11064  *
11065  * This function will not take into consideration the #ClutterActor:depth
11066  * of @child.
11067  *
11068  * This function will emit the #ClutterContainer::actor-added signal
11069  * on @self.
11070  *
11071  * Since: 1.10
11072  */
11073 void
11074 clutter_actor_insert_child_above (ClutterActor *self,
11075                                   ClutterActor *child,
11076                                   ClutterActor *sibling)
11077 {
11078   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11079   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11080   g_return_if_fail (self != child);
11081   g_return_if_fail (child != sibling);
11082   g_return_if_fail (child->priv->parent == NULL);
11083   g_return_if_fail (sibling == NULL ||
11084                     (CLUTTER_IS_ACTOR (sibling) &&
11085                      sibling->priv->parent == self));
11086
11087   clutter_actor_add_child_internal (self, child,
11088                                     ADD_CHILD_DEFAULT_FLAGS,
11089                                     insert_child_above,
11090                                     sibling);
11091 }
11092
11093 /**
11094  * clutter_actor_insert_child_below:
11095  * @self: a #ClutterActor
11096  * @child: a #ClutterActor
11097  * @sibling: (allow-none): a child of @self, or %NULL
11098  *
11099  * Inserts @child into the list of children of @self, below another
11100  * child of @self or, if @sibling is %NULL, below all the children
11101  * of @self.
11102  *
11103  * This function will acquire a reference on @child that will only
11104  * be released when calling clutter_actor_remove_child().
11105  *
11106  * This function will not take into consideration the #ClutterActor:depth
11107  * of @child.
11108  *
11109  * This function will emit the #ClutterContainer::actor-added signal
11110  * on @self.
11111  *
11112  * Since: 1.10
11113  */
11114 void
11115 clutter_actor_insert_child_below (ClutterActor *self,
11116                                   ClutterActor *child,
11117                                   ClutterActor *sibling)
11118 {
11119   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11120   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11121   g_return_if_fail (self != child);
11122   g_return_if_fail (child != sibling);
11123   g_return_if_fail (child->priv->parent == NULL);
11124   g_return_if_fail (sibling == NULL ||
11125                     (CLUTTER_IS_ACTOR (sibling) &&
11126                      sibling->priv->parent == self));
11127
11128   clutter_actor_add_child_internal (self, child,
11129                                     ADD_CHILD_DEFAULT_FLAGS,
11130                                     insert_child_below,
11131                                     sibling);
11132 }
11133
11134 /**
11135  * clutter_actor_set_parent:
11136  * @self: A #ClutterActor
11137  * @parent: A new #ClutterActor parent
11138  *
11139  * Sets the parent of @self to @parent.
11140  *
11141  * This function will result in @parent acquiring a reference on @self,
11142  * eventually by sinking its floating reference first. The reference
11143  * will be released by clutter_actor_unparent().
11144  *
11145  * This function should only be called by legacy #ClutterActor<!-- -->s
11146  * implementing the #ClutterContainer interface.
11147  *
11148  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11149  */
11150 void
11151 clutter_actor_set_parent (ClutterActor *self,
11152                           ClutterActor *parent)
11153 {
11154   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11155   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11156   g_return_if_fail (self != parent);
11157   g_return_if_fail (self->priv->parent == NULL);
11158
11159   /* as this function will be called inside ClutterContainer::add
11160    * implementations or when building up a composite actor, we have
11161    * to preserve the old behaviour, and not create child meta or
11162    * emit the ::actor-added signal, to avoid recursion or double
11163    * emissions
11164    */
11165   clutter_actor_add_child_internal (parent, self,
11166                                     ADD_CHILD_LEGACY_FLAGS,
11167                                     insert_child_at_depth,
11168                                     NULL);
11169 }
11170
11171 /**
11172  * clutter_actor_get_parent:
11173  * @self: A #ClutterActor
11174  *
11175  * Retrieves the parent of @self.
11176  *
11177  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11178  *  if no parent is set
11179  */
11180 ClutterActor *
11181 clutter_actor_get_parent (ClutterActor *self)
11182 {
11183   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11184
11185   return self->priv->parent;
11186 }
11187
11188 /**
11189  * clutter_actor_get_paint_visibility:
11190  * @self: A #ClutterActor
11191  *
11192  * Retrieves the 'paint' visibility of an actor recursively checking for non
11193  * visible parents.
11194  *
11195  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11196  *
11197  * Return Value: %TRUE if the actor is visibile and will be painted.
11198  *
11199  * Since: 0.8.4
11200  */
11201 gboolean
11202 clutter_actor_get_paint_visibility (ClutterActor *actor)
11203 {
11204   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11205
11206   return CLUTTER_ACTOR_IS_MAPPED (actor);
11207 }
11208
11209 /**
11210  * clutter_actor_remove_child:
11211  * @self: a #ClutterActor
11212  * @child: a #ClutterActor
11213  *
11214  * Removes @child from the children of @self.
11215  *
11216  * This function will release the reference added by
11217  * clutter_actor_add_child(), so if you want to keep using @child
11218  * you will have to acquire a referenced on it before calling this
11219  * function.
11220  *
11221  * This function will emit the #ClutterContainer::actor-removed
11222  * signal on @self.
11223  *
11224  * Since: 1.10
11225  */
11226 void
11227 clutter_actor_remove_child (ClutterActor *self,
11228                             ClutterActor *child)
11229 {
11230   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11231   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11232   g_return_if_fail (self != child);
11233   g_return_if_fail (child->priv->parent != NULL);
11234   g_return_if_fail (child->priv->parent == self);
11235
11236   clutter_actor_remove_child_internal (self, child,
11237                                        REMOVE_CHILD_DEFAULT_FLAGS);
11238 }
11239
11240 /**
11241  * clutter_actor_remove_all_children:
11242  * @self: a #ClutterActor
11243  *
11244  * Removes all children of @self.
11245  *
11246  * This function releases the reference added by inserting a child actor
11247  * in the list of children of @self.
11248  *
11249  * If the reference count of a child drops to zero, the child will be
11250  * destroyed. If you want to ensure the destruction of all the children
11251  * of @self, use clutter_actor_destroy_all_children().
11252  *
11253  * Since: 1.10
11254  */
11255 void
11256 clutter_actor_remove_all_children (ClutterActor *self)
11257 {
11258   ClutterActorIter iter;
11259
11260   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11261
11262   if (self->priv->n_children == 0)
11263     return;
11264
11265   g_object_freeze_notify (G_OBJECT (self));
11266
11267   clutter_actor_iter_init (&iter, self);
11268   while (clutter_actor_iter_next (&iter, NULL))
11269     clutter_actor_iter_remove (&iter);
11270
11271   g_object_thaw_notify (G_OBJECT (self));
11272
11273   /* sanity check */
11274   g_assert (self->priv->first_child == NULL);
11275   g_assert (self->priv->last_child == NULL);
11276   g_assert (self->priv->n_children == 0);
11277 }
11278
11279 /**
11280  * clutter_actor_destroy_all_children:
11281  * @self: a #ClutterActor
11282  *
11283  * Destroys all children of @self.
11284  *
11285  * This function releases the reference added by inserting a child
11286  * actor in the list of children of @self, and ensures that the
11287  * #ClutterActor::destroy signal is emitted on each child of the
11288  * actor.
11289  *
11290  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11291  * when its reference count drops to 0; the default handler of the
11292  * #ClutterActor::destroy signal will destroy all the children of an
11293  * actor. This function ensures that all children are destroyed, instead
11294  * of just removed from @self, unlike clutter_actor_remove_all_children()
11295  * which will merely release the reference and remove each child.
11296  *
11297  * Unless you acquired an additional reference on each child of @self
11298  * prior to calling clutter_actor_remove_all_children() and want to reuse
11299  * the actors, you should use clutter_actor_destroy_all_children() in
11300  * order to make sure that children are destroyed and signal handlers
11301  * are disconnected even in cases where circular references prevent this
11302  * from automatically happening through reference counting alone.
11303  *
11304  * Since: 1.10
11305  */
11306 void
11307 clutter_actor_destroy_all_children (ClutterActor *self)
11308 {
11309   ClutterActorIter iter;
11310
11311   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11312
11313   if (self->priv->n_children == 0)
11314     return;
11315
11316   g_object_freeze_notify (G_OBJECT (self));
11317
11318   clutter_actor_iter_init (&iter, self);
11319   while (clutter_actor_iter_next (&iter, NULL))
11320     clutter_actor_iter_destroy (&iter);
11321
11322   g_object_thaw_notify (G_OBJECT (self));
11323
11324   /* sanity check */
11325   g_assert (self->priv->first_child == NULL);
11326   g_assert (self->priv->last_child == NULL);
11327   g_assert (self->priv->n_children == 0);
11328 }
11329
11330 typedef struct _InsertBetweenData {
11331   ClutterActor *prev_sibling;
11332   ClutterActor *next_sibling;
11333 } InsertBetweenData;
11334
11335 static void
11336 insert_child_between (ClutterActor *self,
11337                       ClutterActor *child,
11338                       gpointer      data_)
11339 {
11340   InsertBetweenData *data = data_;
11341   ClutterActor *prev_sibling = data->prev_sibling;
11342   ClutterActor *next_sibling = data->next_sibling;
11343
11344   child->priv->parent = self;
11345   child->priv->prev_sibling = prev_sibling;
11346   child->priv->next_sibling = next_sibling;
11347
11348   if (prev_sibling != NULL)
11349     prev_sibling->priv->next_sibling = child;
11350
11351   if (next_sibling != NULL)
11352     next_sibling->priv->prev_sibling = child;
11353
11354   if (child->priv->prev_sibling == NULL)
11355     self->priv->first_child = child;
11356
11357   if (child->priv->next_sibling == NULL)
11358     self->priv->last_child = child;
11359 }
11360
11361 /**
11362  * clutter_actor_replace_child:
11363  * @self: a #ClutterActor
11364  * @old_child: the child of @self to replace
11365  * @new_child: the #ClutterActor to replace @old_child
11366  *
11367  * Replaces @old_child with @new_child in the list of children of @self.
11368  *
11369  * Since: 1.10
11370  */
11371 void
11372 clutter_actor_replace_child (ClutterActor *self,
11373                              ClutterActor *old_child,
11374                              ClutterActor *new_child)
11375 {
11376   ClutterActor *prev_sibling, *next_sibling;
11377   InsertBetweenData clos;
11378
11379   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11380   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11381   g_return_if_fail (old_child->priv->parent == self);
11382   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11383   g_return_if_fail (old_child != new_child);
11384   g_return_if_fail (new_child != self);
11385   g_return_if_fail (new_child->priv->parent == NULL);
11386
11387   prev_sibling = old_child->priv->prev_sibling;
11388   next_sibling = old_child->priv->next_sibling;
11389   clutter_actor_remove_child_internal (self, old_child,
11390                                        REMOVE_CHILD_DEFAULT_FLAGS);
11391
11392   clos.prev_sibling = prev_sibling;
11393   clos.next_sibling = next_sibling;
11394   clutter_actor_add_child_internal (self, new_child,
11395                                     ADD_CHILD_DEFAULT_FLAGS,
11396                                     insert_child_between,
11397                                     &clos);
11398 }
11399
11400 /**
11401  * clutter_actor_unparent:
11402  * @self: a #ClutterActor
11403  *
11404  * Removes the parent of @self.
11405  *
11406  * This will cause the parent of @self to release the reference
11407  * acquired when calling clutter_actor_set_parent(), so if you
11408  * want to keep @self you will have to acquire a reference of
11409  * your own, through g_object_ref().
11410  *
11411  * This function should only be called by legacy #ClutterActor<!-- -->s
11412  * implementing the #ClutterContainer interface.
11413  *
11414  * Since: 0.1.1
11415  *
11416  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11417  */
11418 void
11419 clutter_actor_unparent (ClutterActor *self)
11420 {
11421   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11422
11423   if (self->priv->parent == NULL)
11424     return;
11425
11426   clutter_actor_remove_child_internal (self->priv->parent, self,
11427                                        REMOVE_CHILD_LEGACY_FLAGS);
11428 }
11429
11430 /**
11431  * clutter_actor_reparent:
11432  * @self: a #ClutterActor
11433  * @new_parent: the new #ClutterActor parent
11434  *
11435  * Resets the parent actor of @self.
11436  *
11437  * This function is logically equivalent to calling clutter_actor_unparent()
11438  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11439  * ensures the child is not finalized when unparented, and emits the
11440  * #ClutterActor::parent-set signal only once.
11441  *
11442  * In reality, calling this function is less useful than it sounds, as some
11443  * application code may rely on changes in the intermediate state between
11444  * removal and addition of the actor from its old parent to the @new_parent.
11445  * Thus, it is strongly encouraged to avoid using this function in application
11446  * code.
11447  *
11448  * Since: 0.2
11449  *
11450  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11451  *   clutter_actor_add_child() instead; remember to take a reference on
11452  *   the actor being removed before calling clutter_actor_remove_child()
11453  *   to avoid the reference count dropping to zero and the actor being
11454  *   destroyed.
11455  */
11456 void
11457 clutter_actor_reparent (ClutterActor *self,
11458                         ClutterActor *new_parent)
11459 {
11460   ClutterActorPrivate *priv;
11461
11462   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11463   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11464   g_return_if_fail (self != new_parent);
11465
11466   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11467     {
11468       g_warning ("Cannot set a parent on a toplevel actor");
11469       return;
11470     }
11471
11472   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11473     {
11474       g_warning ("Cannot set a parent currently being destroyed");
11475       return;
11476     }
11477
11478   priv = self->priv;
11479
11480   if (priv->parent != new_parent)
11481     {
11482       ClutterActor *old_parent;
11483
11484       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11485
11486       old_parent = priv->parent;
11487
11488       g_object_ref (self);
11489
11490       if (old_parent != NULL)
11491         {
11492          /* go through the Container implementation if this is a regular
11493           * child and not an internal one
11494           */
11495          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11496            {
11497              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11498
11499              /* this will have to call unparent() */
11500              clutter_container_remove_actor (parent, self);
11501            }
11502          else
11503            clutter_actor_remove_child_internal (old_parent, self,
11504                                                 REMOVE_CHILD_LEGACY_FLAGS);
11505         }
11506
11507       /* Note, will call set_parent() */
11508       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11509         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11510       else
11511         clutter_actor_add_child_internal (new_parent, self,
11512                                           ADD_CHILD_LEGACY_FLAGS,
11513                                           insert_child_at_depth,
11514                                           NULL);
11515
11516       /* we emit the ::parent-set signal once */
11517       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11518
11519       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11520
11521       /* the IN_REPARENT flag suspends state updates */
11522       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11523
11524       g_object_unref (self);
11525    }
11526 }
11527
11528 /**
11529  * clutter_actor_contains:
11530  * @self: A #ClutterActor
11531  * @descendant: A #ClutterActor, possibly contained in @self
11532  *
11533  * Determines if @descendant is contained inside @self (either as an
11534  * immediate child, or as a deeper descendant). If @self and
11535  * @descendant point to the same actor then it will also return %TRUE.
11536  *
11537  * Return value: whether @descendent is contained within @self
11538  *
11539  * Since: 1.4
11540  */
11541 gboolean
11542 clutter_actor_contains (ClutterActor *self,
11543                         ClutterActor *descendant)
11544 {
11545   ClutterActor *actor;
11546
11547   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11548   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11549
11550   for (actor = descendant; actor; actor = actor->priv->parent)
11551     if (actor == self)
11552       return TRUE;
11553
11554   return FALSE;
11555 }
11556
11557 /**
11558  * clutter_actor_set_child_above_sibling:
11559  * @self: a #ClutterActor
11560  * @child: a #ClutterActor child of @self
11561  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11562  *
11563  * Sets @child to be above @sibling in the list of children of @self.
11564  *
11565  * If @sibling is %NULL, @child will be the new last child of @self.
11566  *
11567  * This function is logically equivalent to removing @child and using
11568  * clutter_actor_insert_child_above(), but it will not emit signals
11569  * or change state on @child.
11570  *
11571  * Since: 1.10
11572  */
11573 void
11574 clutter_actor_set_child_above_sibling (ClutterActor *self,
11575                                        ClutterActor *child,
11576                                        ClutterActor *sibling)
11577 {
11578   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11579   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11580   g_return_if_fail (child->priv->parent == self);
11581   g_return_if_fail (child != sibling);
11582   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11583
11584   if (sibling != NULL)
11585     g_return_if_fail (sibling->priv->parent == self);
11586
11587   /* we don't want to change the state of child, or emit signals, or
11588    * regenerate ChildMeta instances here, but we still want to follow
11589    * the correct sequence of steps encoded in remove_child() and
11590    * add_child(), so that correctness is ensured, and we only go
11591    * through one known code path.
11592    */
11593   g_object_ref (child);
11594   clutter_actor_remove_child_internal (self, child, 0);
11595   clutter_actor_add_child_internal (self, child,
11596                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11597                                     insert_child_above,
11598                                     sibling);
11599
11600   clutter_actor_queue_relayout (self);
11601 }
11602
11603 /**
11604  * clutter_actor_set_child_below_sibling:
11605  * @self: a #ClutterActor
11606  * @child: a #ClutterActor child of @self
11607  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11608  *
11609  * Sets @child to be below @sibling in the list of children of @self.
11610  *
11611  * If @sibling is %NULL, @child will be the new first child of @self.
11612  *
11613  * This function is logically equivalent to removing @self and using
11614  * clutter_actor_insert_child_below(), but it will not emit signals
11615  * or change state on @child.
11616  *
11617  * Since: 1.10
11618  */
11619 void
11620 clutter_actor_set_child_below_sibling (ClutterActor *self,
11621                                        ClutterActor *child,
11622                                        ClutterActor *sibling)
11623 {
11624   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11625   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11626   g_return_if_fail (child->priv->parent == self);
11627   g_return_if_fail (child != sibling);
11628   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11629
11630   if (sibling != NULL)
11631     g_return_if_fail (sibling->priv->parent == self);
11632
11633   /* see the comment in set_child_above_sibling() */
11634   g_object_ref (child);
11635   clutter_actor_remove_child_internal (self, child, 0);
11636   clutter_actor_add_child_internal (self, child,
11637                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11638                                     insert_child_below,
11639                                     sibling);
11640
11641   clutter_actor_queue_relayout (self);
11642 }
11643
11644 /**
11645  * clutter_actor_set_child_at_index:
11646  * @self: a #ClutterActor
11647  * @child: a #ClutterActor child of @self
11648  * @index_: the new index for @child
11649  *
11650  * Changes the index of @child in the list of children of @self.
11651  *
11652  * This function is logically equivalent to removing @child and
11653  * calling clutter_actor_insert_child_at_index(), but it will not
11654  * emit signals or change state on @child.
11655  *
11656  * Since: 1.10
11657  */
11658 void
11659 clutter_actor_set_child_at_index (ClutterActor *self,
11660                                   ClutterActor *child,
11661                                   gint          index_)
11662 {
11663   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11664   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11665   g_return_if_fail (child->priv->parent == self);
11666   g_return_if_fail (index_ <= self->priv->n_children);
11667
11668   g_object_ref (child);
11669   clutter_actor_remove_child_internal (self, child, 0);
11670   clutter_actor_add_child_internal (self, child,
11671                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11672                                     insert_child_at_index,
11673                                     GINT_TO_POINTER (index_));
11674
11675   clutter_actor_queue_relayout (self);
11676 }
11677
11678 /**
11679  * clutter_actor_raise:
11680  * @self: A #ClutterActor
11681  * @below: (allow-none): A #ClutterActor to raise above.
11682  *
11683  * Puts @self above @below.
11684  *
11685  * Both actors must have the same parent, and the parent must implement
11686  * the #ClutterContainer interface
11687  *
11688  * This function calls clutter_container_raise_child() internally.
11689  *
11690  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11691  */
11692 void
11693 clutter_actor_raise (ClutterActor *self,
11694                      ClutterActor *below)
11695 {
11696   ClutterActor *parent;
11697
11698   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11699
11700   parent = clutter_actor_get_parent (self);
11701   if (parent == NULL)
11702     {
11703       g_warning ("%s: Actor '%s' is not inside a container",
11704                  G_STRFUNC,
11705                  _clutter_actor_get_debug_name (self));
11706       return;
11707     }
11708
11709   if (below != NULL)
11710     {
11711       if (parent != clutter_actor_get_parent (below))
11712         {
11713           g_warning ("%s Actor '%s' is not in the same container as "
11714                      "actor '%s'",
11715                      G_STRFUNC,
11716                      _clutter_actor_get_debug_name (self),
11717                      _clutter_actor_get_debug_name (below));
11718           return;
11719         }
11720     }
11721
11722   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11723 }
11724
11725 /**
11726  * clutter_actor_lower:
11727  * @self: A #ClutterActor
11728  * @above: (allow-none): A #ClutterActor to lower below
11729  *
11730  * Puts @self below @above.
11731  *
11732  * Both actors must have the same parent, and the parent must implement
11733  * the #ClutterContainer interface.
11734  *
11735  * This function calls clutter_container_lower_child() internally.
11736  *
11737  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11738  */
11739 void
11740 clutter_actor_lower (ClutterActor *self,
11741                      ClutterActor *above)
11742 {
11743   ClutterActor *parent;
11744
11745   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11746
11747   parent = clutter_actor_get_parent (self);
11748   if (parent == NULL)
11749     {
11750       g_warning ("%s: Actor of type %s is not inside a container",
11751                  G_STRFUNC,
11752                  _clutter_actor_get_debug_name (self));
11753       return;
11754     }
11755
11756   if (above)
11757     {
11758       if (parent != clutter_actor_get_parent (above))
11759         {
11760           g_warning ("%s: Actor '%s' is not in the same container as "
11761                      "actor '%s'",
11762                      G_STRFUNC,
11763                      _clutter_actor_get_debug_name (self),
11764                      _clutter_actor_get_debug_name (above));
11765           return;
11766         }
11767     }
11768
11769   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11770 }
11771
11772 /**
11773  * clutter_actor_raise_top:
11774  * @self: A #ClutterActor
11775  *
11776  * Raises @self to the top.
11777  *
11778  * This function calls clutter_actor_raise() internally.
11779  *
11780  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11781  *   a %NULL sibling, instead.
11782  */
11783 void
11784 clutter_actor_raise_top (ClutterActor *self)
11785 {
11786   clutter_actor_raise (self, NULL);
11787 }
11788
11789 /**
11790  * clutter_actor_lower_bottom:
11791  * @self: A #ClutterActor
11792  *
11793  * Lowers @self to the bottom.
11794  *
11795  * This function calls clutter_actor_lower() internally.
11796  *
11797  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11798  *   a %NULL sibling, instead.
11799  */
11800 void
11801 clutter_actor_lower_bottom (ClutterActor *self)
11802 {
11803   clutter_actor_lower (self, NULL);
11804 }
11805
11806 /*
11807  * Event handling
11808  */
11809
11810 /**
11811  * clutter_actor_event:
11812  * @actor: a #ClutterActor
11813  * @event: a #ClutterEvent
11814  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11815  *
11816  * This function is used to emit an event on the main stage.
11817  * You should rarely need to use this function, except for
11818  * synthetising events.
11819  *
11820  * Return value: the return value from the signal emission: %TRUE
11821  *   if the actor handled the event, or %FALSE if the event was
11822  *   not handled
11823  *
11824  * Since: 0.6
11825  */
11826 gboolean
11827 clutter_actor_event (ClutterActor *actor,
11828                      ClutterEvent *event,
11829                      gboolean      capture)
11830 {
11831   gboolean retval = FALSE;
11832   gint signal_num = -1;
11833
11834   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11835   g_return_val_if_fail (event != NULL, FALSE);
11836
11837   g_object_ref (actor);
11838
11839   if (capture)
11840     {
11841       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11842                      event,
11843                      &retval);
11844       goto out;
11845     }
11846
11847   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11848
11849   if (!retval)
11850     {
11851       switch (event->type)
11852         {
11853         case CLUTTER_NOTHING:
11854           break;
11855         case CLUTTER_BUTTON_PRESS:
11856           signal_num = BUTTON_PRESS_EVENT;
11857           break;
11858         case CLUTTER_BUTTON_RELEASE:
11859           signal_num = BUTTON_RELEASE_EVENT;
11860           break;
11861         case CLUTTER_SCROLL:
11862           signal_num = SCROLL_EVENT;
11863           break;
11864         case CLUTTER_KEY_PRESS:
11865           signal_num = KEY_PRESS_EVENT;
11866           break;
11867         case CLUTTER_KEY_RELEASE:
11868           signal_num = KEY_RELEASE_EVENT;
11869           break;
11870         case CLUTTER_MOTION:
11871           signal_num = MOTION_EVENT;
11872           break;
11873         case CLUTTER_ENTER:
11874           signal_num = ENTER_EVENT;
11875           break;
11876         case CLUTTER_LEAVE:
11877           signal_num = LEAVE_EVENT;
11878           break;
11879         case CLUTTER_DELETE:
11880         case CLUTTER_DESTROY_NOTIFY:
11881         case CLUTTER_CLIENT_MESSAGE:
11882         default:
11883           signal_num = -1;
11884           break;
11885         }
11886
11887       if (signal_num != -1)
11888         g_signal_emit (actor, actor_signals[signal_num], 0,
11889                        event, &retval);
11890     }
11891
11892 out:
11893   g_object_unref (actor);
11894
11895   return retval;
11896 }
11897
11898 /**
11899  * clutter_actor_set_reactive:
11900  * @actor: a #ClutterActor
11901  * @reactive: whether the actor should be reactive to events
11902  *
11903  * Sets @actor as reactive. Reactive actors will receive events.
11904  *
11905  * Since: 0.6
11906  */
11907 void
11908 clutter_actor_set_reactive (ClutterActor *actor,
11909                             gboolean      reactive)
11910 {
11911   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11912
11913   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11914     return;
11915
11916   if (reactive)
11917     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11918   else
11919     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11920
11921   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11922 }
11923
11924 /**
11925  * clutter_actor_get_reactive:
11926  * @actor: a #ClutterActor
11927  *
11928  * Checks whether @actor is marked as reactive.
11929  *
11930  * Return value: %TRUE if the actor is reactive
11931  *
11932  * Since: 0.6
11933  */
11934 gboolean
11935 clutter_actor_get_reactive (ClutterActor *actor)
11936 {
11937   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11938
11939   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11940 }
11941
11942 /**
11943  * clutter_actor_get_anchor_point:
11944  * @self: a #ClutterActor
11945  * @anchor_x: (out): return location for the X coordinate of the anchor point
11946  * @anchor_y: (out): return location for the Y coordinate of the anchor point
11947  *
11948  * Gets the current anchor point of the @actor in pixels.
11949  *
11950  * Since: 0.6
11951  */
11952 void
11953 clutter_actor_get_anchor_point (ClutterActor *self,
11954                                 gfloat       *anchor_x,
11955                                 gfloat       *anchor_y)
11956 {
11957   const ClutterTransformInfo *info;
11958
11959   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11960
11961   info = _clutter_actor_get_transform_info_or_defaults (self);
11962   clutter_anchor_coord_get_units (self, &info->anchor,
11963                                   anchor_x,
11964                                   anchor_y,
11965                                   NULL);
11966 }
11967
11968 /**
11969  * clutter_actor_set_anchor_point:
11970  * @self: a #ClutterActor
11971  * @anchor_x: X coordinate of the anchor point
11972  * @anchor_y: Y coordinate of the anchor point
11973  *
11974  * Sets an anchor point for @self. The anchor point is a point in the
11975  * coordinate space of an actor to which the actor position within its
11976  * parent is relative; the default is (0, 0), i.e. the top-left corner
11977  * of the actor.
11978  *
11979  * Since: 0.6
11980  */
11981 void
11982 clutter_actor_set_anchor_point (ClutterActor *self,
11983                                 gfloat        anchor_x,
11984                                 gfloat        anchor_y)
11985 {
11986   ClutterTransformInfo *info;
11987   ClutterActorPrivate *priv;
11988   gboolean changed = FALSE;
11989   gfloat old_anchor_x, old_anchor_y;
11990   GObject *obj;
11991
11992   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11993
11994   obj = G_OBJECT (self);
11995   priv = self->priv;
11996   info = _clutter_actor_get_transform_info (self);
11997
11998   g_object_freeze_notify (obj);
11999
12000   clutter_anchor_coord_get_units (self, &info->anchor,
12001                                   &old_anchor_x,
12002                                   &old_anchor_y,
12003                                   NULL);
12004
12005   if (info->anchor.is_fractional)
12006     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12007
12008   if (old_anchor_x != anchor_x)
12009     {
12010       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12011       changed = TRUE;
12012     }
12013
12014   if (old_anchor_y != anchor_y)
12015     {
12016       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12017       changed = TRUE;
12018     }
12019
12020   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12021
12022   if (changed)
12023     {
12024       priv->transform_valid = FALSE;
12025       clutter_actor_queue_redraw (self);
12026     }
12027
12028   g_object_thaw_notify (obj);
12029 }
12030
12031 /**
12032  * clutter_actor_get_anchor_point_gravity:
12033  * @self: a #ClutterActor
12034  *
12035  * Retrieves the anchor position expressed as a #ClutterGravity. If
12036  * the anchor point was specified using pixels or units this will
12037  * return %CLUTTER_GRAVITY_NONE.
12038  *
12039  * Return value: the #ClutterGravity used by the anchor point
12040  *
12041  * Since: 1.0
12042  */
12043 ClutterGravity
12044 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12045 {
12046   const ClutterTransformInfo *info;
12047
12048   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12049
12050   info = _clutter_actor_get_transform_info_or_defaults (self);
12051
12052   return clutter_anchor_coord_get_gravity (&info->anchor);
12053 }
12054
12055 /**
12056  * clutter_actor_move_anchor_point:
12057  * @self: a #ClutterActor
12058  * @anchor_x: X coordinate of the anchor point
12059  * @anchor_y: Y coordinate of the anchor point
12060  *
12061  * Sets an anchor point for the actor, and adjusts the actor postion so that
12062  * the relative position of the actor toward its parent remains the same.
12063  *
12064  * Since: 0.6
12065  */
12066 void
12067 clutter_actor_move_anchor_point (ClutterActor *self,
12068                                  gfloat        anchor_x,
12069                                  gfloat        anchor_y)
12070 {
12071   gfloat old_anchor_x, old_anchor_y;
12072   const ClutterTransformInfo *info;
12073
12074   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12075
12076   info = _clutter_actor_get_transform_info (self);
12077   clutter_anchor_coord_get_units (self, &info->anchor,
12078                                   &old_anchor_x,
12079                                   &old_anchor_y,
12080                                   NULL);
12081
12082   g_object_freeze_notify (G_OBJECT (self));
12083
12084   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12085
12086   if (self->priv->position_set)
12087     clutter_actor_move_by (self,
12088                            anchor_x - old_anchor_x,
12089                            anchor_y - old_anchor_y);
12090
12091   g_object_thaw_notify (G_OBJECT (self));
12092 }
12093
12094 /**
12095  * clutter_actor_move_anchor_point_from_gravity:
12096  * @self: a #ClutterActor
12097  * @gravity: #ClutterGravity.
12098  *
12099  * Sets an anchor point on the actor based on the given gravity, adjusting the
12100  * actor postion so that its relative position within its parent remains
12101  * unchanged.
12102  *
12103  * Since version 1.0 the anchor point will be stored as a gravity so
12104  * that if the actor changes size then the anchor point will move. For
12105  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12106  * and later double the size of the actor, the anchor point will move
12107  * to the bottom right.
12108  *
12109  * Since: 0.6
12110  */
12111 void
12112 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12113                                               ClutterGravity  gravity)
12114 {
12115   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12116   const ClutterTransformInfo *info;
12117   ClutterActorPrivate *priv;
12118
12119   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12120
12121   priv = self->priv;
12122   info = _clutter_actor_get_transform_info (self);
12123
12124   g_object_freeze_notify (G_OBJECT (self));
12125
12126   clutter_anchor_coord_get_units (self, &info->anchor,
12127                                   &old_anchor_x,
12128                                   &old_anchor_y,
12129                                   NULL);
12130   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12131   clutter_anchor_coord_get_units (self, &info->anchor,
12132                                   &new_anchor_x,
12133                                   &new_anchor_y,
12134                                   NULL);
12135
12136   if (priv->position_set)
12137     clutter_actor_move_by (self,
12138                            new_anchor_x - old_anchor_x,
12139                            new_anchor_y - old_anchor_y);
12140
12141   g_object_thaw_notify (G_OBJECT (self));
12142 }
12143
12144 /**
12145  * clutter_actor_set_anchor_point_from_gravity:
12146  * @self: a #ClutterActor
12147  * @gravity: #ClutterGravity.
12148  *
12149  * Sets an anchor point on the actor, based on the given gravity (this is a
12150  * convenience function wrapping clutter_actor_set_anchor_point()).
12151  *
12152  * Since version 1.0 the anchor point will be stored as a gravity so
12153  * that if the actor changes size then the anchor point will move. For
12154  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12155  * and later double the size of the actor, the anchor point will move
12156  * to the bottom right.
12157  *
12158  * Since: 0.6
12159  */
12160 void
12161 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12162                                              ClutterGravity  gravity)
12163 {
12164   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12165
12166   if (gravity == CLUTTER_GRAVITY_NONE)
12167     clutter_actor_set_anchor_point (self, 0, 0);
12168   else
12169     {
12170       GObject *obj = G_OBJECT (self);
12171       ClutterTransformInfo *info;
12172
12173       g_object_freeze_notify (obj);
12174
12175       info = _clutter_actor_get_transform_info (self);
12176       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12177
12178       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12179       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12180       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12181
12182       self->priv->transform_valid = FALSE;
12183
12184       clutter_actor_queue_redraw (self);
12185
12186       g_object_thaw_notify (obj);
12187     }
12188 }
12189
12190 static void
12191 clutter_container_iface_init (ClutterContainerIface *iface)
12192 {
12193   /* we don't override anything, as ClutterContainer already has a default
12194    * implementation that we can use, and which calls into our own API.
12195    */
12196 }
12197
12198 typedef enum
12199 {
12200   PARSE_X,
12201   PARSE_Y,
12202   PARSE_WIDTH,
12203   PARSE_HEIGHT,
12204   PARSE_ANCHOR_X,
12205   PARSE_ANCHOR_Y
12206 } ParseDimension;
12207
12208 static gfloat
12209 parse_units (ClutterActor   *self,
12210              ParseDimension  dimension,
12211              JsonNode       *node)
12212 {
12213   GValue value = { 0, };
12214   gfloat retval = 0;
12215
12216   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12217     return 0;
12218
12219   json_node_get_value (node, &value);
12220
12221   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12222     {
12223       retval = (gfloat) g_value_get_int64 (&value);
12224     }
12225   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12226     {
12227       retval = g_value_get_double (&value);
12228     }
12229   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12230     {
12231       ClutterUnits units;
12232       gboolean res;
12233
12234       res = clutter_units_from_string (&units, g_value_get_string (&value));
12235       if (res)
12236         retval = clutter_units_to_pixels (&units);
12237       else
12238         {
12239           g_warning ("Invalid value '%s': integers, strings or floating point "
12240                      "values can be used for the x, y, width and height "
12241                      "properties. Valid modifiers for strings are 'px', 'mm', "
12242                      "'pt' and 'em'.",
12243                      g_value_get_string (&value));
12244           retval = 0;
12245         }
12246     }
12247   else
12248     {
12249       g_warning ("Invalid value of type '%s': integers, strings of floating "
12250                  "point values can be used for the x, y, width, height "
12251                  "anchor-x and anchor-y properties.",
12252                  g_type_name (G_VALUE_TYPE (&value)));
12253     }
12254
12255   g_value_unset (&value);
12256
12257   return retval;
12258 }
12259
12260 typedef struct {
12261   ClutterRotateAxis axis;
12262
12263   gdouble angle;
12264
12265   gfloat center_x;
12266   gfloat center_y;
12267   gfloat center_z;
12268 } RotationInfo;
12269
12270 static inline gboolean
12271 parse_rotation_array (ClutterActor *actor,
12272                       JsonArray    *array,
12273                       RotationInfo *info)
12274 {
12275   JsonNode *element;
12276
12277   if (json_array_get_length (array) != 2)
12278     return FALSE;
12279
12280   /* angle */
12281   element = json_array_get_element (array, 0);
12282   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12283     info->angle = json_node_get_double (element);
12284   else
12285     return FALSE;
12286
12287   /* center */
12288   element = json_array_get_element (array, 1);
12289   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12290     {
12291       JsonArray *center = json_node_get_array (element);
12292
12293       if (json_array_get_length (center) != 2)
12294         return FALSE;
12295
12296       switch (info->axis)
12297         {
12298         case CLUTTER_X_AXIS:
12299           info->center_y = parse_units (actor, PARSE_Y,
12300                                         json_array_get_element (center, 0));
12301           info->center_z = parse_units (actor, PARSE_Y,
12302                                         json_array_get_element (center, 1));
12303           return TRUE;
12304
12305         case CLUTTER_Y_AXIS:
12306           info->center_x = parse_units (actor, PARSE_X,
12307                                         json_array_get_element (center, 0));
12308           info->center_z = parse_units (actor, PARSE_X,
12309                                         json_array_get_element (center, 1));
12310           return TRUE;
12311
12312         case CLUTTER_Z_AXIS:
12313           info->center_x = parse_units (actor, PARSE_X,
12314                                         json_array_get_element (center, 0));
12315           info->center_y = parse_units (actor, PARSE_Y,
12316                                         json_array_get_element (center, 1));
12317           return TRUE;
12318         }
12319     }
12320
12321   return FALSE;
12322 }
12323
12324 static gboolean
12325 parse_rotation (ClutterActor *actor,
12326                 JsonNode     *node,
12327                 RotationInfo *info)
12328 {
12329   JsonArray *array;
12330   guint len, i;
12331   gboolean retval = FALSE;
12332
12333   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12334     {
12335       g_warning ("Invalid node of type '%s' found, expecting an array",
12336                  json_node_type_name (node));
12337       return FALSE;
12338     }
12339
12340   array = json_node_get_array (node);
12341   len = json_array_get_length (array);
12342
12343   for (i = 0; i < len; i++)
12344     {
12345       JsonNode *element = json_array_get_element (array, i);
12346       JsonObject *object;
12347       JsonNode *member;
12348
12349       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12350         {
12351           g_warning ("Invalid node of type '%s' found, expecting an object",
12352                      json_node_type_name (element));
12353           return FALSE;
12354         }
12355
12356       object = json_node_get_object (element);
12357
12358       if (json_object_has_member (object, "x-axis"))
12359         {
12360           member = json_object_get_member (object, "x-axis");
12361
12362           info->axis = CLUTTER_X_AXIS;
12363
12364           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12365             {
12366               info->angle = json_node_get_double (member);
12367               retval = TRUE;
12368             }
12369           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12370             retval = parse_rotation_array (actor,
12371                                            json_node_get_array (member),
12372                                            info);
12373           else
12374             retval = FALSE;
12375         }
12376       else if (json_object_has_member (object, "y-axis"))
12377         {
12378           member = json_object_get_member (object, "y-axis");
12379
12380           info->axis = CLUTTER_Y_AXIS;
12381
12382           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12383             {
12384               info->angle = json_node_get_double (member);
12385               retval = TRUE;
12386             }
12387           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12388             retval = parse_rotation_array (actor,
12389                                            json_node_get_array (member),
12390                                            info);
12391           else
12392             retval = FALSE;
12393         }
12394       else if (json_object_has_member (object, "z-axis"))
12395         {
12396           member = json_object_get_member (object, "z-axis");
12397
12398           info->axis = CLUTTER_Z_AXIS;
12399
12400           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12401             {
12402               info->angle = json_node_get_double (member);
12403               retval = TRUE;
12404             }
12405           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12406             retval = parse_rotation_array (actor,
12407                                            json_node_get_array (member),
12408                                            info);
12409           else
12410             retval = FALSE;
12411         }
12412     }
12413
12414   return retval;
12415 }
12416
12417 static GSList *
12418 parse_actor_metas (ClutterScript *script,
12419                    ClutterActor  *actor,
12420                    JsonNode      *node)
12421 {
12422   GList *elements, *l;
12423   GSList *retval = NULL;
12424
12425   if (!JSON_NODE_HOLDS_ARRAY (node))
12426     return NULL;
12427
12428   elements = json_array_get_elements (json_node_get_array (node));
12429
12430   for (l = elements; l != NULL; l = l->next)
12431     {
12432       JsonNode *element = l->data;
12433       const gchar *id_ = _clutter_script_get_id_from_node (element);
12434       GObject *meta;
12435
12436       if (id_ == NULL || *id_ == '\0')
12437         continue;
12438
12439       meta = clutter_script_get_object (script, id_);
12440       if (meta == NULL)
12441         continue;
12442
12443       retval = g_slist_prepend (retval, meta);
12444     }
12445
12446   g_list_free (elements);
12447
12448   return g_slist_reverse (retval);
12449 }
12450
12451 static GSList *
12452 parse_behaviours (ClutterScript *script,
12453                   ClutterActor  *actor,
12454                   JsonNode      *node)
12455 {
12456   GList *elements, *l;
12457   GSList *retval = NULL;
12458
12459   if (!JSON_NODE_HOLDS_ARRAY (node))
12460     return NULL;
12461
12462   elements = json_array_get_elements (json_node_get_array (node));
12463
12464   for (l = elements; l != NULL; l = l->next)
12465     {
12466       JsonNode *element = l->data;
12467       const gchar *id_ = _clutter_script_get_id_from_node (element);
12468       GObject *behaviour;
12469
12470       if (id_ == NULL || *id_ == '\0')
12471         continue;
12472
12473       behaviour = clutter_script_get_object (script, id_);
12474       if (behaviour == NULL)
12475         continue;
12476
12477       retval = g_slist_prepend (retval, behaviour);
12478     }
12479
12480   g_list_free (elements);
12481
12482   return g_slist_reverse (retval);
12483 }
12484
12485 static gboolean
12486 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12487                                  ClutterScript     *script,
12488                                  GValue            *value,
12489                                  const gchar       *name,
12490                                  JsonNode          *node)
12491 {
12492   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12493   gboolean retval = FALSE;
12494
12495   if ((name[0] == 'x' && name[1] == '\0') ||
12496       (name[0] == 'y' && name[1] == '\0') ||
12497       (strcmp (name, "width") == 0) ||
12498       (strcmp (name, "height") == 0) ||
12499       (strcmp (name, "anchor_x") == 0) ||
12500       (strcmp (name, "anchor_y") == 0))
12501     {
12502       ParseDimension dimension;
12503       gfloat units;
12504
12505       if (name[0] == 'x')
12506         dimension = PARSE_X;
12507       else if (name[0] == 'y')
12508         dimension = PARSE_Y;
12509       else if (name[0] == 'w')
12510         dimension = PARSE_WIDTH;
12511       else if (name[0] == 'h')
12512         dimension = PARSE_HEIGHT;
12513       else if (name[0] == 'a' && name[7] == 'x')
12514         dimension = PARSE_ANCHOR_X;
12515       else if (name[0] == 'a' && name[7] == 'y')
12516         dimension = PARSE_ANCHOR_Y;
12517       else
12518         return FALSE;
12519
12520       units = parse_units (actor, dimension, node);
12521
12522       /* convert back to pixels: all properties are pixel-based */
12523       g_value_init (value, G_TYPE_FLOAT);
12524       g_value_set_float (value, units);
12525
12526       retval = TRUE;
12527     }
12528   else if (strcmp (name, "rotation") == 0)
12529     {
12530       RotationInfo *info;
12531
12532       info = g_slice_new0 (RotationInfo);
12533       retval = parse_rotation (actor, node, info);
12534
12535       if (retval)
12536         {
12537           g_value_init (value, G_TYPE_POINTER);
12538           g_value_set_pointer (value, info);
12539         }
12540       else
12541         g_slice_free (RotationInfo, info);
12542     }
12543   else if (strcmp (name, "behaviours") == 0)
12544     {
12545       GSList *l;
12546
12547 #ifdef CLUTTER_ENABLE_DEBUG
12548       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12549         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12550                                      "and it should not be used in newly "
12551                                      "written ClutterScript definitions.");
12552 #endif
12553
12554       l = parse_behaviours (script, actor, node);
12555
12556       g_value_init (value, G_TYPE_POINTER);
12557       g_value_set_pointer (value, l);
12558
12559       retval = TRUE;
12560     }
12561   else if (strcmp (name, "actions") == 0 ||
12562            strcmp (name, "constraints") == 0 ||
12563            strcmp (name, "effects") == 0)
12564     {
12565       GSList *l;
12566
12567       l = parse_actor_metas (script, actor, node);
12568
12569       g_value_init (value, G_TYPE_POINTER);
12570       g_value_set_pointer (value, l);
12571
12572       retval = TRUE;
12573     }
12574
12575   return retval;
12576 }
12577
12578 static void
12579 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12580                                    ClutterScript     *script,
12581                                    const gchar       *name,
12582                                    const GValue      *value)
12583 {
12584   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12585
12586 #ifdef CLUTTER_ENABLE_DEBUG
12587   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12588     {
12589       gchar *tmp = g_strdup_value_contents (value);
12590
12591       CLUTTER_NOTE (SCRIPT,
12592                     "in ClutterActor::set_custom_property('%s') = %s",
12593                     name,
12594                     tmp);
12595
12596       g_free (tmp);
12597     }
12598 #endif /* CLUTTER_ENABLE_DEBUG */
12599
12600   if (strcmp (name, "rotation") == 0)
12601     {
12602       RotationInfo *info;
12603
12604       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12605         return;
12606
12607       info = g_value_get_pointer (value);
12608
12609       clutter_actor_set_rotation (actor,
12610                                   info->axis, info->angle,
12611                                   info->center_x,
12612                                   info->center_y,
12613                                   info->center_z);
12614
12615       g_slice_free (RotationInfo, info);
12616
12617       return;
12618     }
12619
12620   if (strcmp (name, "behaviours") == 0)
12621     {
12622       GSList *behaviours, *l;
12623
12624       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12625         return;
12626
12627       behaviours = g_value_get_pointer (value);
12628       for (l = behaviours; l != NULL; l = l->next)
12629         {
12630           ClutterBehaviour *behaviour = l->data;
12631
12632           clutter_behaviour_apply (behaviour, actor);
12633         }
12634
12635       g_slist_free (behaviours);
12636
12637       return;
12638     }
12639
12640   if (strcmp (name, "actions") == 0 ||
12641       strcmp (name, "constraints") == 0 ||
12642       strcmp (name, "effects") == 0)
12643     {
12644       GSList *metas, *l;
12645
12646       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12647         return;
12648
12649       metas = g_value_get_pointer (value);
12650       for (l = metas; l != NULL; l = l->next)
12651         {
12652           if (name[0] == 'a')
12653             clutter_actor_add_action (actor, l->data);
12654
12655           if (name[0] == 'c')
12656             clutter_actor_add_constraint (actor, l->data);
12657
12658           if (name[0] == 'e')
12659             clutter_actor_add_effect (actor, l->data);
12660         }
12661
12662       g_slist_free (metas);
12663
12664       return;
12665     }
12666
12667   g_object_set_property (G_OBJECT (scriptable), name, value);
12668 }
12669
12670 static void
12671 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12672 {
12673   iface->parse_custom_node = clutter_actor_parse_custom_node;
12674   iface->set_custom_property = clutter_actor_set_custom_property;
12675 }
12676
12677 static ClutterActorMeta *
12678 get_meta_from_animation_property (ClutterActor  *actor,
12679                                   const gchar   *name,
12680                                   gchar        **name_p)
12681 {
12682   ClutterActorPrivate *priv = actor->priv;
12683   ClutterActorMeta *meta = NULL;
12684   gchar **tokens;
12685
12686   /* if this is not a special property, fall through */
12687   if (name[0] != '@')
12688     return NULL;
12689
12690   /* detect the properties named using the following spec:
12691    *
12692    *   @<section>.<meta-name>.<property-name>
12693    *
12694    * where <section> can be one of the following:
12695    *
12696    *   - actions
12697    *   - constraints
12698    *   - effects
12699    *
12700    * and <meta-name> is the name set on a specific ActorMeta
12701    */
12702
12703   tokens = g_strsplit (name + 1, ".", -1);
12704   if (tokens == NULL || g_strv_length (tokens) != 3)
12705     {
12706       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12707                     name + 1);
12708       g_strfreev (tokens);
12709       return NULL;
12710     }
12711
12712   if (strcmp (tokens[0], "actions") == 0)
12713     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12714
12715   if (strcmp (tokens[0], "constraints") == 0)
12716     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12717
12718   if (strcmp (tokens[0], "effects") == 0)
12719     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12720
12721   if (name_p != NULL)
12722     *name_p = g_strdup (tokens[2]);
12723
12724   CLUTTER_NOTE (ANIMATION,
12725                 "Looking for property '%s' of object '%s' in section '%s'",
12726                 tokens[2],
12727                 tokens[1],
12728                 tokens[0]);
12729
12730   g_strfreev (tokens);
12731
12732   return meta;
12733 }
12734
12735 static GParamSpec *
12736 clutter_actor_find_property (ClutterAnimatable *animatable,
12737                              const gchar       *property_name)
12738 {
12739   ClutterActorMeta *meta = NULL;
12740   GObjectClass *klass = NULL;
12741   GParamSpec *pspec = NULL;
12742   gchar *p_name = NULL;
12743
12744   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12745                                            property_name,
12746                                            &p_name);
12747
12748   if (meta != NULL)
12749     {
12750       klass = G_OBJECT_GET_CLASS (meta);
12751
12752       pspec = g_object_class_find_property (klass, p_name);
12753     }
12754   else
12755     {
12756       klass = G_OBJECT_GET_CLASS (animatable);
12757
12758       pspec = g_object_class_find_property (klass, property_name);
12759     }
12760
12761   g_free (p_name);
12762
12763   return pspec;
12764 }
12765
12766 static void
12767 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12768                                  const gchar       *property_name,
12769                                  GValue            *initial)
12770 {
12771   ClutterActorMeta *meta = NULL;
12772   gchar *p_name = NULL;
12773
12774   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12775                                            property_name,
12776                                            &p_name);
12777
12778   if (meta != NULL)
12779     g_object_get_property (G_OBJECT (meta), p_name, initial);
12780   else
12781     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12782
12783   g_free (p_name);
12784 }
12785
12786 /*
12787  * clutter_actor_set_animatable_property:
12788  * @actor: a #ClutterActor
12789  * @prop_id: the paramspec id
12790  * @value: the value to set
12791  * @pspec: the paramspec
12792  *
12793  * Sets values of animatable properties.
12794  *
12795  * This is a variant of clutter_actor_set_property() that gets called
12796  * by the #ClutterAnimatable implementation of #ClutterActor for the
12797  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12798  * #GParamSpec.
12799  *
12800  * Unlike the implementation of #GObjectClass.set_property(), this
12801  * function will not update the interval if a transition involving an
12802  * animatable property is in progress - this avoids cycles with the
12803  * transition API calling the public API.
12804  */
12805 static void
12806 clutter_actor_set_animatable_property (ClutterActor *actor,
12807                                        guint         prop_id,
12808                                        const GValue *value,
12809                                        GParamSpec   *pspec)
12810 {
12811   switch (prop_id)
12812     {
12813     case PROP_X:
12814       clutter_actor_set_x_internal (actor, g_value_get_float (value));
12815       break;
12816
12817     case PROP_Y:
12818       clutter_actor_set_y_internal (actor, g_value_get_float (value));
12819       break;
12820
12821     case PROP_WIDTH:
12822       clutter_actor_set_width_internal (actor, g_value_get_float (value));
12823       break;
12824
12825     case PROP_HEIGHT:
12826       clutter_actor_set_height_internal (actor, g_value_get_float (value));
12827       break;
12828
12829     case PROP_DEPTH:
12830       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12831       break;
12832
12833     case PROP_OPACITY:
12834       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12835       break;
12836
12837     case PROP_BACKGROUND_COLOR:
12838       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12839       break;
12840
12841     case PROP_SCALE_X:
12842       clutter_actor_set_scale_factor_internal (actor,
12843                                                g_value_get_double (value),
12844                                                pspec);
12845       break;
12846
12847     case PROP_SCALE_Y:
12848       clutter_actor_set_scale_factor_internal (actor,
12849                                                g_value_get_double (value),
12850                                                pspec);
12851       break;
12852
12853     case PROP_ROTATION_ANGLE_X:
12854       clutter_actor_set_rotation_angle_internal (actor,
12855                                                  CLUTTER_X_AXIS,
12856                                                  g_value_get_double (value));
12857       break;
12858
12859     case PROP_ROTATION_ANGLE_Y:
12860       clutter_actor_set_rotation_angle_internal (actor,
12861                                                  CLUTTER_Y_AXIS,
12862                                                  g_value_get_double (value));
12863       break;
12864
12865     case PROP_ROTATION_ANGLE_Z:
12866       clutter_actor_set_rotation_angle_internal (actor,
12867                                                  CLUTTER_Z_AXIS,
12868                                                  g_value_get_double (value));
12869       break;
12870
12871     default:
12872       g_object_set_property (G_OBJECT (actor), pspec->name, value);
12873       break;
12874     }
12875 }
12876
12877 static void
12878 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12879                                const gchar       *property_name,
12880                                const GValue      *final)
12881 {
12882   ClutterActor *actor = CLUTTER_ACTOR (animatable);
12883   ClutterActorMeta *meta = NULL;
12884   gchar *p_name = NULL;
12885
12886   meta = get_meta_from_animation_property (actor,
12887                                            property_name,
12888                                            &p_name);
12889   if (meta != NULL)
12890     g_object_set_property (G_OBJECT (meta), p_name, final);
12891   else
12892     {
12893       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12894       GParamSpec *pspec;
12895
12896       pspec = g_object_class_find_property (obj_class, property_name);
12897
12898       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12899         {
12900           /* XXX - I'm going to the special hell for this */
12901           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12902         }
12903       else
12904         g_object_set_property (G_OBJECT (animatable), property_name, final);
12905     }
12906
12907   g_free (p_name);
12908 }
12909
12910 static void
12911 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12912 {
12913   iface->find_property = clutter_actor_find_property;
12914   iface->get_initial_state = clutter_actor_get_initial_state;
12915   iface->set_final_state = clutter_actor_set_final_state;
12916 }
12917
12918 /**
12919  * clutter_actor_transform_stage_point:
12920  * @self: A #ClutterActor
12921  * @x: (in): x screen coordinate of the point to unproject
12922  * @y: (in): y screen coordinate of the point to unproject
12923  * @x_out: (out): return location for the unprojected x coordinance
12924  * @y_out: (out): return location for the unprojected y coordinance
12925  *
12926  * This function translates screen coordinates (@x, @y) to
12927  * coordinates relative to the actor. For example, it can be used to translate
12928  * screen events from global screen coordinates into actor-local coordinates.
12929  *
12930  * The conversion can fail, notably if the transform stack results in the
12931  * actor being projected on the screen as a mere line.
12932  *
12933  * The conversion should not be expected to be pixel-perfect due to the
12934  * nature of the operation. In general the error grows when the skewing
12935  * of the actor rectangle on screen increases.
12936  *
12937  * <note><para>This function can be computationally intensive.</para></note>
12938  *
12939  * <note><para>This function only works when the allocation is up-to-date,
12940  * i.e. inside of paint().</para></note>
12941  *
12942  * Return value: %TRUE if conversion was successful.
12943  *
12944  * Since: 0.6
12945  */
12946 gboolean
12947 clutter_actor_transform_stage_point (ClutterActor *self,
12948                                      gfloat        x,
12949                                      gfloat        y,
12950                                      gfloat       *x_out,
12951                                      gfloat       *y_out)
12952 {
12953   ClutterVertex v[4];
12954   float ST[3][3];
12955   float RQ[3][3];
12956   int du, dv, xi, yi;
12957   float px, py;
12958   float xf, yf, wf, det;
12959   ClutterActorPrivate *priv;
12960
12961   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12962
12963   priv = self->priv;
12964
12965   /* This implementation is based on the quad -> quad projection algorithm
12966    * described by Paul Heckbert in:
12967    *
12968    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12969    *
12970    * and the sample implementation at:
12971    *
12972    *   http://www.cs.cmu.edu/~ph/src/texfund/
12973    *
12974    * Our texture is a rectangle with origin [0, 0], so we are mapping from
12975    * quad to rectangle only, which significantly simplifies things; the
12976    * function calls have been unrolled, and most of the math is done in fixed
12977    * point.
12978    */
12979
12980   clutter_actor_get_abs_allocation_vertices (self, v);
12981
12982   /* Keeping these as ints simplifies the multiplication (no significant
12983    * loss of precision here).
12984    */
12985   du = (int) (priv->allocation.x2 - priv->allocation.x1);
12986   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12987
12988   if (!du || !dv)
12989     return FALSE;
12990
12991 #define UX2FP(x)        (x)
12992 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12993
12994   /* First, find mapping from unit uv square to xy quadrilateral; this
12995    * equivalent to the pmap_square_quad() functions in the sample
12996    * implementation, which we can simplify, since our target is always
12997    * a rectangle.
12998    */
12999   px = v[0].x - v[1].x + v[3].x - v[2].x;
13000   py = v[0].y - v[1].y + v[3].y - v[2].y;
13001
13002   if (!px && !py)
13003     {
13004       /* affine transform */
13005       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13006       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13007       RQ[2][0] = UX2FP (v[0].x);
13008       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13009       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13010       RQ[2][1] = UX2FP (v[0].y);
13011       RQ[0][2] = 0;
13012       RQ[1][2] = 0;
13013       RQ[2][2] = 1.0;
13014     }
13015   else
13016     {
13017       /* projective transform */
13018       double dx1, dx2, dy1, dy2, del;
13019
13020       dx1 = UX2FP (v[1].x - v[3].x);
13021       dx2 = UX2FP (v[2].x - v[3].x);
13022       dy1 = UX2FP (v[1].y - v[3].y);
13023       dy2 = UX2FP (v[2].y - v[3].y);
13024
13025       del = DET2FP (dx1, dx2, dy1, dy2);
13026       if (!del)
13027         return FALSE;
13028
13029       /*
13030        * The division here needs to be done in floating point for
13031        * precisions reasons.
13032        */
13033       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13034       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13035       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13036       RQ[2][2] = 1.0;
13037       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13038       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13039       RQ[2][0] = UX2FP (v[0].x);
13040       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13041       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13042       RQ[2][1] = UX2FP (v[0].y);
13043     }
13044
13045   /*
13046    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13047    * square. Since our rectangle is based at 0,0 we only need to scale.
13048    */
13049   RQ[0][0] /= du;
13050   RQ[1][0] /= dv;
13051   RQ[0][1] /= du;
13052   RQ[1][1] /= dv;
13053   RQ[0][2] /= du;
13054   RQ[1][2] /= dv;
13055
13056   /*
13057    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13058    * inverse of that.
13059    */
13060   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13061   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13062   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13063   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13064   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13065   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13066   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13067   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13068   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13069
13070   /*
13071    * Check the resulting matrix is OK.
13072    */
13073   det = (RQ[0][0] * ST[0][0])
13074       + (RQ[0][1] * ST[0][1])
13075       + (RQ[0][2] * ST[0][2]);
13076   if (!det)
13077     return FALSE;
13078
13079   /*
13080    * Now transform our point with the ST matrix; the notional w
13081    * coordinate is 1, hence the last part is simply added.
13082    */
13083   xi = (int) x;
13084   yi = (int) y;
13085
13086   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13087   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13088   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13089
13090   if (x_out)
13091     *x_out = xf / wf;
13092
13093   if (y_out)
13094     *y_out = yf / wf;
13095
13096 #undef UX2FP
13097 #undef DET2FP
13098
13099   return TRUE;
13100 }
13101
13102 /*
13103  * ClutterGeometry
13104  */
13105
13106 static ClutterGeometry*
13107 clutter_geometry_copy (const ClutterGeometry *geometry)
13108 {
13109   return g_slice_dup (ClutterGeometry, geometry);
13110 }
13111
13112 static void
13113 clutter_geometry_free (ClutterGeometry *geometry)
13114 {
13115   if (G_LIKELY (geometry != NULL))
13116     g_slice_free (ClutterGeometry, geometry);
13117 }
13118
13119 /**
13120  * clutter_geometry_union:
13121  * @geometry_a: a #ClutterGeometry
13122  * @geometry_b: another #ClutterGeometry
13123  * @result: (out): location to store the result
13124  *
13125  * Find the union of two rectangles represented as #ClutterGeometry.
13126  *
13127  * Since: 1.4
13128  */
13129 void
13130 clutter_geometry_union (const ClutterGeometry *geometry_a,
13131                         const ClutterGeometry *geometry_b,
13132                         ClutterGeometry       *result)
13133 {
13134   /* We don't try to handle rectangles that can't be represented
13135    * as a signed integer box */
13136   gint x_1 = MIN (geometry_a->x, geometry_b->x);
13137   gint y_1 = MIN (geometry_a->y, geometry_b->y);
13138   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13139                   geometry_b->x + (gint)geometry_b->width);
13140   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13141                   geometry_b->y + (gint)geometry_b->height);
13142   result->x = x_1;
13143   result->y = y_1;
13144   result->width = x_2 - x_1;
13145   result->height = y_2 - y_1;
13146 }
13147
13148 /**
13149  * clutter_geometry_intersects:
13150  * @geometry0: The first geometry to test
13151  * @geometry1: The second geometry to test
13152  *
13153  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13154  * they do else %FALSE.
13155  *
13156  * Return value: %TRUE of @geometry0 and geometry1 intersect else
13157  * %FALSE.
13158  *
13159  * Since: 1.4
13160  */
13161 gboolean
13162 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13163                              const ClutterGeometry *geometry1)
13164 {
13165   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13166       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13167       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13168       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13169     return FALSE;
13170   else
13171     return TRUE;
13172 }
13173
13174 static gboolean
13175 clutter_geometry_progress (const GValue *a,
13176                            const GValue *b,
13177                            gdouble       progress,
13178                            GValue       *retval)
13179 {
13180   const ClutterGeometry *a_geom = g_value_get_boxed (a);
13181   const ClutterGeometry *b_geom = g_value_get_boxed (b);
13182   ClutterGeometry res = { 0, };
13183   gint a_width = a_geom->width;
13184   gint b_width = b_geom->width;
13185   gint a_height = a_geom->height;
13186   gint b_height = b_geom->height;
13187
13188   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13189   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13190
13191   res.width = a_width + (b_width - a_width) * progress;
13192   res.height = a_height + (b_height - a_height) * progress;
13193
13194   g_value_set_boxed (retval, &res);
13195
13196   return TRUE;
13197 }
13198
13199 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13200                                clutter_geometry_copy,
13201                                clutter_geometry_free,
13202                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13203
13204 /*
13205  * ClutterVertices
13206  */
13207
13208 /**
13209  * clutter_vertex_new:
13210  * @x: X coordinate
13211  * @y: Y coordinate
13212  * @z: Z coordinate
13213  *
13214  * Creates a new #ClutterVertex for the point in 3D space
13215  * identified by the 3 coordinates @x, @y, @z
13216  *
13217  * Return value: the newly allocate #ClutterVertex. Use
13218  *   clutter_vertex_free() to free the resources
13219  *
13220  * Since: 1.0
13221  */
13222 ClutterVertex *
13223 clutter_vertex_new (gfloat x,
13224                     gfloat y,
13225                     gfloat z)
13226 {
13227   ClutterVertex *vertex;
13228
13229   vertex = g_slice_new (ClutterVertex);
13230   vertex->x = x;
13231   vertex->y = y;
13232   vertex->z = z;
13233
13234   return vertex;
13235 }
13236
13237 /**
13238  * clutter_vertex_copy:
13239  * @vertex: a #ClutterVertex
13240  *
13241  * Copies @vertex
13242  *
13243  * Return value: a newly allocated copy of #ClutterVertex. Use
13244  *   clutter_vertex_free() to free the allocated resources
13245  *
13246  * Since: 1.0
13247  */
13248 ClutterVertex *
13249 clutter_vertex_copy (const ClutterVertex *vertex)
13250 {
13251   if (G_LIKELY (vertex != NULL))
13252     return g_slice_dup (ClutterVertex, vertex);
13253
13254   return NULL;
13255 }
13256
13257 /**
13258  * clutter_vertex_free:
13259  * @vertex: a #ClutterVertex
13260  *
13261  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13262  *
13263  * Since: 1.0
13264  */
13265 void
13266 clutter_vertex_free (ClutterVertex *vertex)
13267 {
13268   if (G_UNLIKELY (vertex != NULL))
13269     g_slice_free (ClutterVertex, vertex);
13270 }
13271
13272 /**
13273  * clutter_vertex_equal:
13274  * @vertex_a: a #ClutterVertex
13275  * @vertex_b: a #ClutterVertex
13276  *
13277  * Compares @vertex_a and @vertex_b for equality
13278  *
13279  * Return value: %TRUE if the passed #ClutterVertex are equal
13280  *
13281  * Since: 1.0
13282  */
13283 gboolean
13284 clutter_vertex_equal (const ClutterVertex *vertex_a,
13285                       const ClutterVertex *vertex_b)
13286 {
13287   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13288
13289   if (vertex_a == vertex_b)
13290     return TRUE;
13291
13292   return vertex_a->x == vertex_b->x &&
13293          vertex_a->y == vertex_b->y &&
13294          vertex_a->z == vertex_b->z;
13295 }
13296
13297 static gboolean
13298 clutter_vertex_progress (const GValue *a,
13299                          const GValue *b,
13300                          gdouble       progress,
13301                          GValue       *retval)
13302 {
13303   const ClutterVertex *av = g_value_get_boxed (a);
13304   const ClutterVertex *bv = g_value_get_boxed (b);
13305   ClutterVertex res = { 0, };
13306
13307   res.x = av->x + (bv->x - av->x) * progress;
13308   res.y = av->y + (bv->y - av->y) * progress;
13309   res.z = av->z + (bv->z - av->z) * progress;
13310
13311   g_value_set_boxed (retval, &res);
13312
13313   return TRUE;
13314 }
13315
13316 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13317                                clutter_vertex_copy,
13318                                clutter_vertex_free,
13319                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13320
13321 /**
13322  * clutter_actor_is_rotated:
13323  * @self: a #ClutterActor
13324  *
13325  * Checks whether any rotation is applied to the actor.
13326  *
13327  * Return value: %TRUE if the actor is rotated.
13328  *
13329  * Since: 0.6
13330  */
13331 gboolean
13332 clutter_actor_is_rotated (ClutterActor *self)
13333 {
13334   const ClutterTransformInfo *info;
13335
13336   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13337
13338   info = _clutter_actor_get_transform_info_or_defaults (self);
13339
13340   if (info->rx_angle || info->ry_angle || info->rz_angle)
13341     return TRUE;
13342
13343   return FALSE;
13344 }
13345
13346 /**
13347  * clutter_actor_is_scaled:
13348  * @self: a #ClutterActor
13349  *
13350  * Checks whether the actor is scaled in either dimension.
13351  *
13352  * Return value: %TRUE if the actor is scaled.
13353  *
13354  * Since: 0.6
13355  */
13356 gboolean
13357 clutter_actor_is_scaled (ClutterActor *self)
13358 {
13359   const ClutterTransformInfo *info;
13360
13361   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13362
13363   info = _clutter_actor_get_transform_info_or_defaults (self);
13364
13365   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13366     return TRUE;
13367
13368   return FALSE;
13369 }
13370
13371 ClutterActor *
13372 _clutter_actor_get_stage_internal (ClutterActor *actor)
13373 {
13374   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13375     actor = actor->priv->parent;
13376
13377   return actor;
13378 }
13379
13380 /**
13381  * clutter_actor_get_stage:
13382  * @actor: a #ClutterActor
13383  *
13384  * Retrieves the #ClutterStage where @actor is contained.
13385  *
13386  * Return value: (transfer none) (type Clutter.Stage): the stage
13387  *   containing the actor, or %NULL
13388  *
13389  * Since: 0.8
13390  */
13391 ClutterActor *
13392 clutter_actor_get_stage (ClutterActor *actor)
13393 {
13394   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13395
13396   return _clutter_actor_get_stage_internal (actor);
13397 }
13398
13399 /**
13400  * clutter_actor_allocate_available_size:
13401  * @self: a #ClutterActor
13402  * @x: the actor's X coordinate
13403  * @y: the actor's Y coordinate
13404  * @available_width: the maximum available width, or -1 to use the
13405  *   actor's natural width
13406  * @available_height: the maximum available height, or -1 to use the
13407  *   actor's natural height
13408  * @flags: flags controlling the allocation
13409  *
13410  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13411  * preferred size, but limiting it to the maximum available width
13412  * and height provided.
13413  *
13414  * This function will do the right thing when dealing with the
13415  * actor's request mode.
13416  *
13417  * The implementation of this function is equivalent to:
13418  *
13419  * |[
13420  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13421  *     {
13422  *       clutter_actor_get_preferred_width (self, available_height,
13423  *                                          &amp;min_width,
13424  *                                          &amp;natural_width);
13425  *       width = CLAMP (natural_width, min_width, available_width);
13426  *
13427  *       clutter_actor_get_preferred_height (self, width,
13428  *                                           &amp;min_height,
13429  *                                           &amp;natural_height);
13430  *       height = CLAMP (natural_height, min_height, available_height);
13431  *     }
13432  *   else
13433  *     {
13434  *       clutter_actor_get_preferred_height (self, available_width,
13435  *                                           &amp;min_height,
13436  *                                           &amp;natural_height);
13437  *       height = CLAMP (natural_height, min_height, available_height);
13438  *
13439  *       clutter_actor_get_preferred_width (self, height,
13440  *                                          &amp;min_width,
13441  *                                          &amp;natural_width);
13442  *       width = CLAMP (natural_width, min_width, available_width);
13443  *     }
13444  *
13445  *   box.x1 = x; box.y1 = y;
13446  *   box.x2 = box.x1 + available_width;
13447  *   box.y2 = box.y1 + available_height;
13448  *   clutter_actor_allocate (self, &amp;box, flags);
13449  * ]|
13450  *
13451  * This function can be used by fluid layout managers to allocate
13452  * an actor's preferred size without making it bigger than the area
13453  * available for the container.
13454  *
13455  * Since: 1.0
13456  */
13457 void
13458 clutter_actor_allocate_available_size (ClutterActor           *self,
13459                                        gfloat                  x,
13460                                        gfloat                  y,
13461                                        gfloat                  available_width,
13462                                        gfloat                  available_height,
13463                                        ClutterAllocationFlags  flags)
13464 {
13465   ClutterActorPrivate *priv;
13466   gfloat width, height;
13467   gfloat min_width, min_height;
13468   gfloat natural_width, natural_height;
13469   ClutterActorBox box;
13470
13471   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13472
13473   priv = self->priv;
13474
13475   width = height = 0.0;
13476
13477   switch (priv->request_mode)
13478     {
13479     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13480       clutter_actor_get_preferred_width (self, available_height,
13481                                          &min_width,
13482                                          &natural_width);
13483       width  = CLAMP (natural_width, min_width, available_width);
13484
13485       clutter_actor_get_preferred_height (self, width,
13486                                           &min_height,
13487                                           &natural_height);
13488       height = CLAMP (natural_height, min_height, available_height);
13489       break;
13490
13491     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13492       clutter_actor_get_preferred_height (self, available_width,
13493                                           &min_height,
13494                                           &natural_height);
13495       height = CLAMP (natural_height, min_height, available_height);
13496
13497       clutter_actor_get_preferred_width (self, height,
13498                                          &min_width,
13499                                          &natural_width);
13500       width  = CLAMP (natural_width, min_width, available_width);
13501       break;
13502     }
13503
13504
13505   box.x1 = x;
13506   box.y1 = y;
13507   box.x2 = box.x1 + width;
13508   box.y2 = box.y1 + height;
13509   clutter_actor_allocate (self, &box, flags);
13510 }
13511
13512 /**
13513  * clutter_actor_allocate_preferred_size:
13514  * @self: a #ClutterActor
13515  * @flags: flags controlling the allocation
13516  *
13517  * Allocates the natural size of @self.
13518  *
13519  * This function is a utility call for #ClutterActor implementations
13520  * that allocates the actor's preferred natural size. It can be used
13521  * by fixed layout managers (like #ClutterGroup or so called
13522  * 'composite actors') inside the ClutterActor::allocate
13523  * implementation to give each child exactly how much space it
13524  * requires.
13525  *
13526  * This function is not meant to be used by applications. It is also
13527  * not meant to be used outside the implementation of the
13528  * ClutterActor::allocate virtual function.
13529  *
13530  * Since: 0.8
13531  */
13532 void
13533 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13534                                        ClutterAllocationFlags  flags)
13535 {
13536   gfloat actor_x, actor_y;
13537   gfloat natural_width, natural_height;
13538   ClutterActorBox actor_box;
13539
13540   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13541
13542   actor_x = clutter_actor_get_x (self);
13543   actor_y = clutter_actor_get_y (self);
13544
13545   clutter_actor_get_preferred_size (self,
13546                                     NULL, NULL,
13547                                     &natural_width,
13548                                     &natural_height);
13549
13550   actor_box.x1 = actor_x;
13551   actor_box.y1 = actor_y;
13552   actor_box.x2 = actor_box.x1 + natural_width;
13553   actor_box.y2 = actor_box.y1 + natural_height;
13554
13555   clutter_actor_allocate (self, &actor_box, flags);
13556 }
13557
13558 /**
13559  * clutter_actor_allocate_align_fill:
13560  * @self: a #ClutterActor
13561  * @box: a #ClutterActorBox, containing the available width and height
13562  * @x_align: the horizontal alignment, between 0 and 1
13563  * @y_align: the vertical alignment, between 0 and 1
13564  * @x_fill: whether the actor should fill horizontally
13565  * @y_fill: whether the actor should fill vertically
13566  * @flags: allocation flags to be passed to clutter_actor_allocate()
13567  *
13568  * Allocates @self by taking into consideration the available allocation
13569  * area; an alignment factor on either axis; and whether the actor should
13570  * fill the allocation on either axis.
13571  *
13572  * The @box should contain the available allocation width and height;
13573  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13574  * allocation will be offset by their value.
13575  *
13576  * This function takes into consideration the geometry request specified by
13577  * the #ClutterActor:request-mode property, and the text direction.
13578  *
13579  * This function is useful for fluid layout managers, like #ClutterBinLayout
13580  * or #ClutterTableLayout
13581  *
13582  * Since: 1.4
13583  */
13584 void
13585 clutter_actor_allocate_align_fill (ClutterActor           *self,
13586                                    const ClutterActorBox  *box,
13587                                    gdouble                 x_align,
13588                                    gdouble                 y_align,
13589                                    gboolean                x_fill,
13590                                    gboolean                y_fill,
13591                                    ClutterAllocationFlags  flags)
13592 {
13593   ClutterActorPrivate *priv;
13594   ClutterActorBox allocation = { 0, };
13595   gfloat x_offset, y_offset;
13596   gfloat available_width, available_height;
13597   gfloat child_width, child_height;
13598
13599   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13600   g_return_if_fail (box != NULL);
13601   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13602   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13603
13604   priv = self->priv;
13605
13606   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13607   clutter_actor_box_get_size (box, &available_width, &available_height);
13608
13609   if (available_width < 0)
13610     available_width = 0;
13611
13612   if (available_height < 0)
13613     available_height = 0;
13614
13615   if (x_fill)
13616     {
13617       allocation.x1 = x_offset;
13618       allocation.x2 = allocation.x1 + available_width;
13619     }
13620
13621   if (y_fill)
13622     {
13623       allocation.y1 = y_offset;
13624       allocation.y2 = allocation.y1 + available_height;
13625     }
13626
13627   /* if we are filling horizontally and vertically then we're done */
13628   if (x_fill && y_fill)
13629     goto out;
13630
13631   child_width = child_height = 0.0f;
13632
13633   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13634     {
13635       gfloat min_width, natural_width;
13636       gfloat min_height, natural_height;
13637
13638       clutter_actor_get_preferred_width (self, available_height,
13639                                          &min_width,
13640                                          &natural_width);
13641
13642       child_width = CLAMP (natural_width, min_width, available_width);
13643
13644       if (!y_fill)
13645         {
13646           clutter_actor_get_preferred_height (self, child_width,
13647                                               &min_height,
13648                                               &natural_height);
13649
13650           child_height = CLAMP (natural_height, min_height, available_height);
13651         }
13652     }
13653   else
13654     {
13655       gfloat min_width, natural_width;
13656       gfloat min_height, natural_height;
13657
13658       clutter_actor_get_preferred_height (self, available_width,
13659                                           &min_height,
13660                                           &natural_height);
13661
13662       child_height = CLAMP (natural_height, min_height, available_height);
13663
13664       if (!x_fill)
13665         {
13666           clutter_actor_get_preferred_width (self, child_height,
13667                                              &min_width,
13668                                              &natural_width);
13669
13670           child_width = CLAMP (natural_width, min_width, available_width);
13671         }
13672     }
13673
13674   /* invert the horizontal alignment for RTL languages */
13675   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13676     x_align = 1.0 - x_align;
13677
13678   if (!x_fill)
13679     {
13680       allocation.x1 = x_offset
13681                     + ((available_width - child_width) * x_align);
13682       allocation.x2 = allocation.x1 + child_width;
13683     }
13684
13685   if (!y_fill)
13686     {
13687       allocation.y1 = y_offset
13688                     + ((available_height - child_height) * y_align);
13689       allocation.y2 = allocation.y1 + child_height;
13690     }
13691
13692 out:
13693   clutter_actor_box_clamp_to_pixel (&allocation);
13694   clutter_actor_allocate (self, &allocation, flags);
13695 }
13696
13697 /**
13698  * clutter_actor_grab_key_focus:
13699  * @self: a #ClutterActor
13700  *
13701  * Sets the key focus of the #ClutterStage including @self
13702  * to this #ClutterActor.
13703  *
13704  * Since: 1.0
13705  */
13706 void
13707 clutter_actor_grab_key_focus (ClutterActor *self)
13708 {
13709   ClutterActor *stage;
13710
13711   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13712
13713   stage = _clutter_actor_get_stage_internal (self);
13714   if (stage != NULL)
13715     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13716 }
13717
13718 /**
13719  * clutter_actor_get_pango_context:
13720  * @self: a #ClutterActor
13721  *
13722  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13723  * is already configured using the appropriate font map, resolution
13724  * and font options.
13725  *
13726  * Unlike clutter_actor_create_pango_context(), this context is owend
13727  * by the #ClutterActor and it will be updated each time the options
13728  * stored by the #ClutterBackend change.
13729  *
13730  * You can use the returned #PangoContext to create a #PangoLayout
13731  * and render text using cogl_pango_render_layout() to reuse the
13732  * glyphs cache also used by Clutter.
13733  *
13734  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13735  *   The returned #PangoContext is owned by the actor and should not be
13736  *   unreferenced by the application code
13737  *
13738  * Since: 1.0
13739  */
13740 PangoContext *
13741 clutter_actor_get_pango_context (ClutterActor *self)
13742 {
13743   ClutterActorPrivate *priv;
13744
13745   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13746
13747   priv = self->priv;
13748
13749   if (priv->pango_context != NULL)
13750     return priv->pango_context;
13751
13752   priv->pango_context = _clutter_context_get_pango_context ();
13753   g_object_ref (priv->pango_context);
13754
13755   return priv->pango_context;
13756 }
13757
13758 /**
13759  * clutter_actor_create_pango_context:
13760  * @self: a #ClutterActor
13761  *
13762  * Creates a #PangoContext for the given actor. The #PangoContext
13763  * is already configured using the appropriate font map, resolution
13764  * and font options.
13765  *
13766  * See also clutter_actor_get_pango_context().
13767  *
13768  * Return value: (transfer full): the newly created #PangoContext.
13769  *   Use g_object_unref() on the returned value to deallocate its
13770  *   resources
13771  *
13772  * Since: 1.0
13773  */
13774 PangoContext *
13775 clutter_actor_create_pango_context (ClutterActor *self)
13776 {
13777   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13778
13779   return _clutter_context_create_pango_context ();
13780 }
13781
13782 /**
13783  * clutter_actor_create_pango_layout:
13784  * @self: a #ClutterActor
13785  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13786  *
13787  * Creates a new #PangoLayout from the same #PangoContext used
13788  * by the #ClutterActor. The #PangoLayout is already configured
13789  * with the font map, resolution and font options, and the
13790  * given @text.
13791  *
13792  * If you want to keep around a #PangoLayout created by this
13793  * function you will have to connect to the #ClutterBackend::font-changed
13794  * and #ClutterBackend::resolution-changed signals, and call
13795  * pango_layout_context_changed() in response to them.
13796  *
13797  * Return value: (transfer full): the newly created #PangoLayout.
13798  *   Use g_object_unref() when done
13799  *
13800  * Since: 1.0
13801  */
13802 PangoLayout *
13803 clutter_actor_create_pango_layout (ClutterActor *self,
13804                                    const gchar  *text)
13805 {
13806   PangoContext *context;
13807   PangoLayout *layout;
13808
13809   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13810
13811   context = clutter_actor_get_pango_context (self);
13812   layout = pango_layout_new (context);
13813
13814   if (text)
13815     pango_layout_set_text (layout, text, -1);
13816
13817   return layout;
13818 }
13819
13820 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13821  * ClutterOffscreenEffect.
13822  */
13823 void
13824 _clutter_actor_set_opacity_override (ClutterActor *self,
13825                                      gint          opacity)
13826 {
13827   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13828
13829   self->priv->opacity_override = opacity;
13830 }
13831
13832 gint
13833 _clutter_actor_get_opacity_override (ClutterActor *self)
13834 {
13835   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13836
13837   return self->priv->opacity_override;
13838 }
13839
13840 /* Allows you to disable applying the actors model view transform during
13841  * a paint. Used by ClutterClone. */
13842 void
13843 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13844                                                 gboolean      enable)
13845 {
13846   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13847
13848   self->priv->enable_model_view_transform = enable;
13849 }
13850
13851 void
13852 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13853                                           gboolean      enable)
13854 {
13855   ClutterActorPrivate *priv;
13856
13857   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13858
13859   priv = self->priv;
13860
13861   priv->enable_paint_unmapped = enable;
13862
13863   if (priv->enable_paint_unmapped)
13864     {
13865       /* Make sure that the parents of the widget are realized first;
13866        * otherwise checks in clutter_actor_update_map_state() will
13867        * fail.
13868        */
13869       clutter_actor_realize (self);
13870
13871       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13872     }
13873   else
13874     {
13875       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13876     }
13877 }
13878
13879 static void
13880 clutter_anchor_coord_get_units (ClutterActor      *self,
13881                                 const AnchorCoord *coord,
13882                                 gfloat            *x,
13883                                 gfloat            *y,
13884                                 gfloat            *z)
13885 {
13886   if (coord->is_fractional)
13887     {
13888       gfloat actor_width, actor_height;
13889
13890       clutter_actor_get_size (self, &actor_width, &actor_height);
13891
13892       if (x)
13893         *x = actor_width * coord->v.fraction.x;
13894
13895       if (y)
13896         *y = actor_height * coord->v.fraction.y;
13897
13898       if (z)
13899         *z = 0;
13900     }
13901   else
13902     {
13903       if (x)
13904         *x = coord->v.units.x;
13905
13906       if (y)
13907         *y = coord->v.units.y;
13908
13909       if (z)
13910         *z = coord->v.units.z;
13911     }
13912 }
13913
13914 static void
13915 clutter_anchor_coord_set_units (AnchorCoord *coord,
13916                                 gfloat       x,
13917                                 gfloat       y,
13918                                 gfloat       z)
13919 {
13920   coord->is_fractional = FALSE;
13921   coord->v.units.x = x;
13922   coord->v.units.y = y;
13923   coord->v.units.z = z;
13924 }
13925
13926 static ClutterGravity
13927 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13928 {
13929   if (coord->is_fractional)
13930     {
13931       if (coord->v.fraction.x == 0.0)
13932         {
13933           if (coord->v.fraction.y == 0.0)
13934             return CLUTTER_GRAVITY_NORTH_WEST;
13935           else if (coord->v.fraction.y == 0.5)
13936             return CLUTTER_GRAVITY_WEST;
13937           else if (coord->v.fraction.y == 1.0)
13938             return CLUTTER_GRAVITY_SOUTH_WEST;
13939           else
13940             return CLUTTER_GRAVITY_NONE;
13941         }
13942       else if (coord->v.fraction.x == 0.5)
13943         {
13944           if (coord->v.fraction.y == 0.0)
13945             return CLUTTER_GRAVITY_NORTH;
13946           else if (coord->v.fraction.y == 0.5)
13947             return CLUTTER_GRAVITY_CENTER;
13948           else if (coord->v.fraction.y == 1.0)
13949             return CLUTTER_GRAVITY_SOUTH;
13950           else
13951             return CLUTTER_GRAVITY_NONE;
13952         }
13953       else if (coord->v.fraction.x == 1.0)
13954         {
13955           if (coord->v.fraction.y == 0.0)
13956             return CLUTTER_GRAVITY_NORTH_EAST;
13957           else if (coord->v.fraction.y == 0.5)
13958             return CLUTTER_GRAVITY_EAST;
13959           else if (coord->v.fraction.y == 1.0)
13960             return CLUTTER_GRAVITY_SOUTH_EAST;
13961           else
13962             return CLUTTER_GRAVITY_NONE;
13963         }
13964       else
13965         return CLUTTER_GRAVITY_NONE;
13966     }
13967   else
13968     return CLUTTER_GRAVITY_NONE;
13969 }
13970
13971 static void
13972 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
13973                                   ClutterGravity  gravity)
13974 {
13975   switch (gravity)
13976     {
13977     case CLUTTER_GRAVITY_NORTH:
13978       coord->v.fraction.x = 0.5;
13979       coord->v.fraction.y = 0.0;
13980       break;
13981
13982     case CLUTTER_GRAVITY_NORTH_EAST:
13983       coord->v.fraction.x = 1.0;
13984       coord->v.fraction.y = 0.0;
13985       break;
13986
13987     case CLUTTER_GRAVITY_EAST:
13988       coord->v.fraction.x = 1.0;
13989       coord->v.fraction.y = 0.5;
13990       break;
13991
13992     case CLUTTER_GRAVITY_SOUTH_EAST:
13993       coord->v.fraction.x = 1.0;
13994       coord->v.fraction.y = 1.0;
13995       break;
13996
13997     case CLUTTER_GRAVITY_SOUTH:
13998       coord->v.fraction.x = 0.5;
13999       coord->v.fraction.y = 1.0;
14000       break;
14001
14002     case CLUTTER_GRAVITY_SOUTH_WEST:
14003       coord->v.fraction.x = 0.0;
14004       coord->v.fraction.y = 1.0;
14005       break;
14006
14007     case CLUTTER_GRAVITY_WEST:
14008       coord->v.fraction.x = 0.0;
14009       coord->v.fraction.y = 0.5;
14010       break;
14011
14012     case CLUTTER_GRAVITY_NORTH_WEST:
14013       coord->v.fraction.x = 0.0;
14014       coord->v.fraction.y = 0.0;
14015       break;
14016
14017     case CLUTTER_GRAVITY_CENTER:
14018       coord->v.fraction.x = 0.5;
14019       coord->v.fraction.y = 0.5;
14020       break;
14021
14022     default:
14023       coord->v.fraction.x = 0.0;
14024       coord->v.fraction.y = 0.0;
14025       break;
14026     }
14027
14028   coord->is_fractional = TRUE;
14029 }
14030
14031 static gboolean
14032 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14033 {
14034   if (coord->is_fractional)
14035     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14036   else
14037     return (coord->v.units.x == 0.0
14038             && coord->v.units.y == 0.0
14039             && coord->v.units.z == 0.0);
14040 }
14041
14042 /**
14043  * clutter_actor_get_flags:
14044  * @self: a #ClutterActor
14045  *
14046  * Retrieves the flags set on @self
14047  *
14048  * Return value: a bitwise or of #ClutterActorFlags or 0
14049  *
14050  * Since: 1.0
14051  */
14052 ClutterActorFlags
14053 clutter_actor_get_flags (ClutterActor *self)
14054 {
14055   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14056
14057   return self->flags;
14058 }
14059
14060 /**
14061  * clutter_actor_set_flags:
14062  * @self: a #ClutterActor
14063  * @flags: the flags to set
14064  *
14065  * Sets @flags on @self
14066  *
14067  * This function will emit notifications for the changed properties
14068  *
14069  * Since: 1.0
14070  */
14071 void
14072 clutter_actor_set_flags (ClutterActor      *self,
14073                          ClutterActorFlags  flags)
14074 {
14075   ClutterActorFlags old_flags;
14076   GObject *obj;
14077   gboolean was_reactive_set, reactive_set;
14078   gboolean was_realized_set, realized_set;
14079   gboolean was_mapped_set, mapped_set;
14080   gboolean was_visible_set, visible_set;
14081
14082   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14083
14084   if (self->flags == flags)
14085     return;
14086
14087   obj = G_OBJECT (self);
14088   g_object_ref (obj);
14089   g_object_freeze_notify (obj);
14090
14091   old_flags = self->flags;
14092
14093   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14094   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14095   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14096   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14097
14098   self->flags |= flags;
14099
14100   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14101   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14102   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14103   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14104
14105   if (reactive_set != was_reactive_set)
14106     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14107
14108   if (realized_set != was_realized_set)
14109     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14110
14111   if (mapped_set != was_mapped_set)
14112     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14113
14114   if (visible_set != was_visible_set)
14115     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14116
14117   g_object_thaw_notify (obj);
14118   g_object_unref (obj);
14119 }
14120
14121 /**
14122  * clutter_actor_unset_flags:
14123  * @self: a #ClutterActor
14124  * @flags: the flags to unset
14125  *
14126  * Unsets @flags on @self
14127  *
14128  * This function will emit notifications for the changed properties
14129  *
14130  * Since: 1.0
14131  */
14132 void
14133 clutter_actor_unset_flags (ClutterActor      *self,
14134                            ClutterActorFlags  flags)
14135 {
14136   ClutterActorFlags old_flags;
14137   GObject *obj;
14138   gboolean was_reactive_set, reactive_set;
14139   gboolean was_realized_set, realized_set;
14140   gboolean was_mapped_set, mapped_set;
14141   gboolean was_visible_set, visible_set;
14142
14143   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14144
14145   obj = G_OBJECT (self);
14146   g_object_freeze_notify (obj);
14147
14148   old_flags = self->flags;
14149
14150   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14151   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14152   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14153   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14154
14155   self->flags &= ~flags;
14156
14157   if (self->flags == old_flags)
14158     return;
14159
14160   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14161   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14162   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14163   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14164
14165   if (reactive_set != was_reactive_set)
14166     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14167
14168   if (realized_set != was_realized_set)
14169     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14170
14171   if (mapped_set != was_mapped_set)
14172     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14173
14174   if (visible_set != was_visible_set)
14175     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14176
14177   g_object_thaw_notify (obj);
14178 }
14179
14180 /**
14181  * clutter_actor_get_transformation_matrix:
14182  * @self: a #ClutterActor
14183  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14184  *
14185  * Retrieves the transformations applied to @self relative to its
14186  * parent.
14187  *
14188  * Since: 1.0
14189  */
14190 void
14191 clutter_actor_get_transformation_matrix (ClutterActor *self,
14192                                          CoglMatrix   *matrix)
14193 {
14194   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14195
14196   cogl_matrix_init_identity (matrix);
14197
14198   _clutter_actor_apply_modelview_transform (self, matrix);
14199 }
14200
14201 void
14202 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14203                                    gboolean      is_in_clone_paint)
14204 {
14205   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14206   self->priv->in_clone_paint = is_in_clone_paint;
14207 }
14208
14209 /**
14210  * clutter_actor_is_in_clone_paint:
14211  * @self: a #ClutterActor
14212  *
14213  * Checks whether @self is being currently painted by a #ClutterClone
14214  *
14215  * This function is useful only inside the ::paint virtual function
14216  * implementations or within handlers for the #ClutterActor::paint
14217  * signal
14218  *
14219  * This function should not be used by applications
14220  *
14221  * Return value: %TRUE if the #ClutterActor is currently being painted
14222  *   by a #ClutterClone, and %FALSE otherwise
14223  *
14224  * Since: 1.0
14225  */
14226 gboolean
14227 clutter_actor_is_in_clone_paint (ClutterActor *self)
14228 {
14229   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14230
14231   return self->priv->in_clone_paint;
14232 }
14233
14234 static gboolean
14235 set_direction_recursive (ClutterActor *actor,
14236                          gpointer      user_data)
14237 {
14238   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14239
14240   clutter_actor_set_text_direction (actor, text_dir);
14241
14242   return TRUE;
14243 }
14244
14245 /**
14246  * clutter_actor_set_text_direction:
14247  * @self: a #ClutterActor
14248  * @text_dir: the text direction for @self
14249  *
14250  * Sets the #ClutterTextDirection for an actor
14251  *
14252  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14253  *
14254  * If @self implements #ClutterContainer then this function will recurse
14255  * inside all the children of @self (including the internal ones).
14256  *
14257  * Composite actors not implementing #ClutterContainer, or actors requiring
14258  * special handling when the text direction changes, should connect to
14259  * the #GObject::notify signal for the #ClutterActor:text-direction property
14260  *
14261  * Since: 1.2
14262  */
14263 void
14264 clutter_actor_set_text_direction (ClutterActor         *self,
14265                                   ClutterTextDirection  text_dir)
14266 {
14267   ClutterActorPrivate *priv;
14268
14269   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14270   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14271
14272   priv = self->priv;
14273
14274   if (priv->text_direction != text_dir)
14275     {
14276       priv->text_direction = text_dir;
14277
14278       /* we need to emit the notify::text-direction first, so that
14279        * the sub-classes can catch that and do specific handling of
14280        * the text direction; see clutter_text_direction_changed_cb()
14281        * inside clutter-text.c
14282        */
14283       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14284
14285       _clutter_actor_foreach_child (self, set_direction_recursive,
14286                                     GINT_TO_POINTER (text_dir));
14287
14288       clutter_actor_queue_relayout (self);
14289     }
14290 }
14291
14292 void
14293 _clutter_actor_set_has_pointer (ClutterActor *self,
14294                                 gboolean      has_pointer)
14295 {
14296   ClutterActorPrivate *priv = self->priv;
14297
14298   if (priv->has_pointer != has_pointer)
14299     {
14300       priv->has_pointer = has_pointer;
14301
14302       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14303     }
14304 }
14305
14306 /**
14307  * clutter_actor_get_text_direction:
14308  * @self: a #ClutterActor
14309  *
14310  * Retrieves the value set using clutter_actor_set_text_direction()
14311  *
14312  * If no text direction has been previously set, the default text
14313  * direction, as returned by clutter_get_default_text_direction(), will
14314  * be returned instead
14315  *
14316  * Return value: the #ClutterTextDirection for the actor
14317  *
14318  * Since: 1.2
14319  */
14320 ClutterTextDirection
14321 clutter_actor_get_text_direction (ClutterActor *self)
14322 {
14323   ClutterActorPrivate *priv;
14324
14325   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14326                         CLUTTER_TEXT_DIRECTION_LTR);
14327
14328   priv = self->priv;
14329
14330   /* if no direction has been set yet use the default */
14331   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14332     priv->text_direction = clutter_get_default_text_direction ();
14333
14334   return priv->text_direction;
14335 }
14336
14337 /**
14338  * clutter_actor_push_internal:
14339  * @self: a #ClutterActor
14340  *
14341  * Should be used by actors implementing the #ClutterContainer and with
14342  * internal children added through clutter_actor_set_parent(), for instance:
14343  *
14344  * |[
14345  *   static void
14346  *   my_actor_init (MyActor *self)
14347  *   {
14348  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14349  *
14350  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14351  *
14352  *     /&ast; calling clutter_actor_set_parent() now will result in
14353  *      &ast; the internal flag being set on a child of MyActor
14354  *      &ast;/
14355  *
14356  *     /&ast; internal child - a background texture &ast;/
14357  *     self->priv->background_tex = clutter_texture_new ();
14358  *     clutter_actor_set_parent (self->priv->background_tex,
14359  *                               CLUTTER_ACTOR (self));
14360  *
14361  *     /&ast; internal child - a label &ast;/
14362  *     self->priv->label = clutter_text_new ();
14363  *     clutter_actor_set_parent (self->priv->label,
14364  *                               CLUTTER_ACTOR (self));
14365  *
14366  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14367  *
14368  *     /&ast; calling clutter_actor_set_parent() now will not result in
14369  *      &ast; the internal flag being set on a child of MyActor
14370  *      &ast;/
14371  *   }
14372  * ]|
14373  *
14374  * This function will be used by Clutter to toggle an "internal child"
14375  * flag whenever clutter_actor_set_parent() is called; internal children
14376  * are handled differently by Clutter, specifically when destroying their
14377  * parent.
14378  *
14379  * Call clutter_actor_pop_internal() when you finished adding internal
14380  * children.
14381  *
14382  * Nested calls to clutter_actor_push_internal() are allowed, but each
14383  * one must by followed by a clutter_actor_pop_internal() call.
14384  *
14385  * Since: 1.2
14386  *
14387  * Deprecated: 1.10: All children of an actor are accessible through
14388  *   the #ClutterActor API, and #ClutterActor implements the
14389  *   #ClutterContainer interface, so this function is only useful
14390  *   for legacy containers overriding the default implementation.
14391  */
14392 void
14393 clutter_actor_push_internal (ClutterActor *self)
14394 {
14395   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14396
14397   self->priv->internal_child += 1;
14398 }
14399
14400 /**
14401  * clutter_actor_pop_internal:
14402  * @self: a #ClutterActor
14403  *
14404  * Disables the effects of clutter_actor_push_internal().
14405  *
14406  * Since: 1.2
14407  *
14408  * Deprecated: 1.10: All children of an actor are accessible through
14409  *   the #ClutterActor API. This function is only useful for legacy
14410  *   containers overriding the default implementation of the
14411  *   #ClutterContainer interface.
14412  */
14413 void
14414 clutter_actor_pop_internal (ClutterActor *self)
14415 {
14416   ClutterActorPrivate *priv;
14417
14418   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14419
14420   priv = self->priv;
14421
14422   if (priv->internal_child == 0)
14423     {
14424       g_warning ("Mismatched %s: you need to call "
14425                  "clutter_actor_push_composite() at least once before "
14426                  "calling this function", G_STRFUNC);
14427       return;
14428     }
14429
14430   priv->internal_child -= 1;
14431 }
14432
14433 /**
14434  * clutter_actor_has_pointer:
14435  * @self: a #ClutterActor
14436  *
14437  * Checks whether an actor contains the pointer of a
14438  * #ClutterInputDevice
14439  *
14440  * Return value: %TRUE if the actor contains the pointer, and
14441  *   %FALSE otherwise
14442  *
14443  * Since: 1.2
14444  */
14445 gboolean
14446 clutter_actor_has_pointer (ClutterActor *self)
14447 {
14448   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14449
14450   return self->priv->has_pointer;
14451 }
14452
14453 /* XXX: This is a workaround for not being able to break the ABI of
14454  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14455  * clutter_actor_queue_clipped_redraw() for details.
14456  */
14457 ClutterPaintVolume *
14458 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14459 {
14460   return g_object_get_data (G_OBJECT (self),
14461                             "-clutter-actor-queue-redraw-clip");
14462 }
14463
14464 void
14465 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14466                                       ClutterPaintVolume *clip)
14467 {
14468   g_object_set_data (G_OBJECT (self),
14469                      "-clutter-actor-queue-redraw-clip",
14470                      clip);
14471 }
14472
14473 /**
14474  * clutter_actor_has_allocation:
14475  * @self: a #ClutterActor
14476  *
14477  * Checks if the actor has an up-to-date allocation assigned to
14478  * it. This means that the actor should have an allocation: it's
14479  * visible and has a parent. It also means that there is no
14480  * outstanding relayout request in progress for the actor or its
14481  * children (There might be other outstanding layout requests in
14482  * progress that will cause the actor to get a new allocation
14483  * when the stage is laid out, however).
14484  *
14485  * If this function returns %FALSE, then the actor will normally
14486  * be allocated before it is next drawn on the screen.
14487  *
14488  * Return value: %TRUE if the actor has an up-to-date allocation
14489  *
14490  * Since: 1.4
14491  */
14492 gboolean
14493 clutter_actor_has_allocation (ClutterActor *self)
14494 {
14495   ClutterActorPrivate *priv;
14496
14497   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14498
14499   priv = self->priv;
14500
14501   return priv->parent != NULL &&
14502          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14503          !priv->needs_allocation;
14504 }
14505
14506 /**
14507  * clutter_actor_add_action:
14508  * @self: a #ClutterActor
14509  * @action: a #ClutterAction
14510  *
14511  * Adds @action to the list of actions applied to @self
14512  *
14513  * A #ClutterAction can only belong to one actor at a time
14514  *
14515  * The #ClutterActor will hold a reference on @action until either
14516  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14517  * is called
14518  *
14519  * Since: 1.4
14520  */
14521 void
14522 clutter_actor_add_action (ClutterActor  *self,
14523                           ClutterAction *action)
14524 {
14525   ClutterActorPrivate *priv;
14526
14527   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14528   g_return_if_fail (CLUTTER_IS_ACTION (action));
14529
14530   priv = self->priv;
14531
14532   if (priv->actions == NULL)
14533     {
14534       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14535       priv->actions->actor = self;
14536     }
14537
14538   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14539
14540   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14541 }
14542
14543 /**
14544  * clutter_actor_add_action_with_name:
14545  * @self: a #ClutterActor
14546  * @name: the name to set on the action
14547  * @action: a #ClutterAction
14548  *
14549  * A convenience function for setting the name of a #ClutterAction
14550  * while adding it to the list of actions applied to @self
14551  *
14552  * This function is the logical equivalent of:
14553  *
14554  * |[
14555  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14556  *   clutter_actor_add_action (self, action);
14557  * ]|
14558  *
14559  * Since: 1.4
14560  */
14561 void
14562 clutter_actor_add_action_with_name (ClutterActor  *self,
14563                                     const gchar   *name,
14564                                     ClutterAction *action)
14565 {
14566   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14567   g_return_if_fail (name != NULL);
14568   g_return_if_fail (CLUTTER_IS_ACTION (action));
14569
14570   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14571   clutter_actor_add_action (self, action);
14572 }
14573
14574 /**
14575  * clutter_actor_remove_action:
14576  * @self: a #ClutterActor
14577  * @action: a #ClutterAction
14578  *
14579  * Removes @action from the list of actions applied to @self
14580  *
14581  * The reference held by @self on the #ClutterAction will be released
14582  *
14583  * Since: 1.4
14584  */
14585 void
14586 clutter_actor_remove_action (ClutterActor  *self,
14587                              ClutterAction *action)
14588 {
14589   ClutterActorPrivate *priv;
14590
14591   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14592   g_return_if_fail (CLUTTER_IS_ACTION (action));
14593
14594   priv = self->priv;
14595
14596   if (priv->actions == NULL)
14597     return;
14598
14599   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14600
14601   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14602 }
14603
14604 /**
14605  * clutter_actor_remove_action_by_name:
14606  * @self: a #ClutterActor
14607  * @name: the name of the action to remove
14608  *
14609  * Removes the #ClutterAction with the given name from the list
14610  * of actions applied to @self
14611  *
14612  * Since: 1.4
14613  */
14614 void
14615 clutter_actor_remove_action_by_name (ClutterActor *self,
14616                                      const gchar  *name)
14617 {
14618   ClutterActorPrivate *priv;
14619   ClutterActorMeta *meta;
14620
14621   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14622   g_return_if_fail (name != NULL);
14623
14624   priv = self->priv;
14625
14626   if (priv->actions == NULL)
14627     return;
14628
14629   meta = _clutter_meta_group_get_meta (priv->actions, name);
14630   if (meta == NULL)
14631     return;
14632
14633   _clutter_meta_group_remove_meta (priv->actions, meta);
14634
14635   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14636 }
14637
14638 /**
14639  * clutter_actor_get_actions:
14640  * @self: a #ClutterActor
14641  *
14642  * Retrieves the list of actions applied to @self
14643  *
14644  * Return value: (transfer container) (element-type Clutter.Action): a copy
14645  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14646  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14647  *   allocated by the returned #GList
14648  *
14649  * Since: 1.4
14650  */
14651 GList *
14652 clutter_actor_get_actions (ClutterActor *self)
14653 {
14654   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14655
14656   if (self->priv->actions == NULL)
14657     return NULL;
14658
14659   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14660 }
14661
14662 /**
14663  * clutter_actor_get_action:
14664  * @self: a #ClutterActor
14665  * @name: the name of the action to retrieve
14666  *
14667  * Retrieves the #ClutterAction with the given name in the list
14668  * of actions applied to @self
14669  *
14670  * Return value: (transfer none): a #ClutterAction for the given
14671  *   name, or %NULL. The returned #ClutterAction is owned by the
14672  *   actor and it should not be unreferenced directly
14673  *
14674  * Since: 1.4
14675  */
14676 ClutterAction *
14677 clutter_actor_get_action (ClutterActor *self,
14678                           const gchar  *name)
14679 {
14680   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14681   g_return_val_if_fail (name != NULL, NULL);
14682
14683   if (self->priv->actions == NULL)
14684     return NULL;
14685
14686   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14687 }
14688
14689 /**
14690  * clutter_actor_clear_actions:
14691  * @self: a #ClutterActor
14692  *
14693  * Clears the list of actions applied to @self
14694  *
14695  * Since: 1.4
14696  */
14697 void
14698 clutter_actor_clear_actions (ClutterActor *self)
14699 {
14700   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14701
14702   if (self->priv->actions == NULL)
14703     return;
14704
14705   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14706 }
14707
14708 /**
14709  * clutter_actor_add_constraint:
14710  * @self: a #ClutterActor
14711  * @constraint: a #ClutterConstraint
14712  *
14713  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14714  * to @self
14715  *
14716  * The #ClutterActor will hold a reference on the @constraint until
14717  * either clutter_actor_remove_constraint() or
14718  * clutter_actor_clear_constraints() is called.
14719  *
14720  * Since: 1.4
14721  */
14722 void
14723 clutter_actor_add_constraint (ClutterActor      *self,
14724                               ClutterConstraint *constraint)
14725 {
14726   ClutterActorPrivate *priv;
14727
14728   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14729   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14730
14731   priv = self->priv;
14732
14733   if (priv->constraints == NULL)
14734     {
14735       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14736       priv->constraints->actor = self;
14737     }
14738
14739   _clutter_meta_group_add_meta (priv->constraints,
14740                                 CLUTTER_ACTOR_META (constraint));
14741   clutter_actor_queue_relayout (self);
14742
14743   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14744 }
14745
14746 /**
14747  * clutter_actor_add_constraint_with_name:
14748  * @self: a #ClutterActor
14749  * @name: the name to set on the constraint
14750  * @constraint: a #ClutterConstraint
14751  *
14752  * A convenience function for setting the name of a #ClutterConstraint
14753  * while adding it to the list of constraints applied to @self
14754  *
14755  * This function is the logical equivalent of:
14756  *
14757  * |[
14758  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14759  *   clutter_actor_add_constraint (self, constraint);
14760  * ]|
14761  *
14762  * Since: 1.4
14763  */
14764 void
14765 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14766                                         const gchar       *name,
14767                                         ClutterConstraint *constraint)
14768 {
14769   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14770   g_return_if_fail (name != NULL);
14771   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14772
14773   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14774   clutter_actor_add_constraint (self, constraint);
14775 }
14776
14777 /**
14778  * clutter_actor_remove_constraint:
14779  * @self: a #ClutterActor
14780  * @constraint: a #ClutterConstraint
14781  *
14782  * Removes @constraint from the list of constraints applied to @self
14783  *
14784  * The reference held by @self on the #ClutterConstraint will be released
14785  *
14786  * Since: 1.4
14787  */
14788 void
14789 clutter_actor_remove_constraint (ClutterActor      *self,
14790                                  ClutterConstraint *constraint)
14791 {
14792   ClutterActorPrivate *priv;
14793
14794   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14795   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14796
14797   priv = self->priv;
14798
14799   if (priv->constraints == NULL)
14800     return;
14801
14802   _clutter_meta_group_remove_meta (priv->constraints,
14803                                    CLUTTER_ACTOR_META (constraint));
14804   clutter_actor_queue_relayout (self);
14805
14806   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14807 }
14808
14809 /**
14810  * clutter_actor_remove_constraint_by_name:
14811  * @self: a #ClutterActor
14812  * @name: the name of the constraint to remove
14813  *
14814  * Removes the #ClutterConstraint with the given name from the list
14815  * of constraints applied to @self
14816  *
14817  * Since: 1.4
14818  */
14819 void
14820 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14821                                          const gchar  *name)
14822 {
14823   ClutterActorPrivate *priv;
14824   ClutterActorMeta *meta;
14825
14826   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14827   g_return_if_fail (name != NULL);
14828
14829   priv = self->priv;
14830
14831   if (priv->constraints == NULL)
14832     return;
14833
14834   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14835   if (meta == NULL)
14836     return;
14837
14838   _clutter_meta_group_remove_meta (priv->constraints, meta);
14839   clutter_actor_queue_relayout (self);
14840 }
14841
14842 /**
14843  * clutter_actor_get_constraints:
14844  * @self: a #ClutterActor
14845  *
14846  * Retrieves the list of constraints applied to @self
14847  *
14848  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14849  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14850  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14851  *   allocated by the returned #GList
14852  *
14853  * Since: 1.4
14854  */
14855 GList *
14856 clutter_actor_get_constraints (ClutterActor *self)
14857 {
14858   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14859
14860   if (self->priv->constraints == NULL)
14861     return NULL;
14862
14863   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14864 }
14865
14866 /**
14867  * clutter_actor_get_constraint:
14868  * @self: a #ClutterActor
14869  * @name: the name of the constraint to retrieve
14870  *
14871  * Retrieves the #ClutterConstraint with the given name in the list
14872  * of constraints applied to @self
14873  *
14874  * Return value: (transfer none): a #ClutterConstraint for the given
14875  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14876  *   actor and it should not be unreferenced directly
14877  *
14878  * Since: 1.4
14879  */
14880 ClutterConstraint *
14881 clutter_actor_get_constraint (ClutterActor *self,
14882                               const gchar  *name)
14883 {
14884   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14885   g_return_val_if_fail (name != NULL, NULL);
14886
14887   if (self->priv->constraints == NULL)
14888     return NULL;
14889
14890   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14891 }
14892
14893 /**
14894  * clutter_actor_clear_constraints:
14895  * @self: a #ClutterActor
14896  *
14897  * Clears the list of constraints applied to @self
14898  *
14899  * Since: 1.4
14900  */
14901 void
14902 clutter_actor_clear_constraints (ClutterActor *self)
14903 {
14904   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14905
14906   if (self->priv->constraints == NULL)
14907     return;
14908
14909   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14910
14911   clutter_actor_queue_relayout (self);
14912 }
14913
14914 /**
14915  * clutter_actor_set_clip_to_allocation:
14916  * @self: a #ClutterActor
14917  * @clip_set: %TRUE to apply a clip tracking the allocation
14918  *
14919  * Sets whether @self should be clipped to the same size as its
14920  * allocation
14921  *
14922  * Since: 1.4
14923  */
14924 void
14925 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14926                                       gboolean      clip_set)
14927 {
14928   ClutterActorPrivate *priv;
14929
14930   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14931
14932   clip_set = !!clip_set;
14933
14934   priv = self->priv;
14935
14936   if (priv->clip_to_allocation != clip_set)
14937     {
14938       priv->clip_to_allocation = clip_set;
14939
14940       clutter_actor_queue_redraw (self);
14941
14942       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14943     }
14944 }
14945
14946 /**
14947  * clutter_actor_get_clip_to_allocation:
14948  * @self: a #ClutterActor
14949  *
14950  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14951  *
14952  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14953  *
14954  * Since: 1.4
14955  */
14956 gboolean
14957 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14958 {
14959   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14960
14961   return self->priv->clip_to_allocation;
14962 }
14963
14964 /**
14965  * clutter_actor_add_effect:
14966  * @self: a #ClutterActor
14967  * @effect: a #ClutterEffect
14968  *
14969  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14970  *
14971  * The #ClutterActor will hold a reference on the @effect until either
14972  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14973  * called.
14974  *
14975  * Since: 1.4
14976  */
14977 void
14978 clutter_actor_add_effect (ClutterActor  *self,
14979                           ClutterEffect *effect)
14980 {
14981   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14982   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14983
14984   _clutter_actor_add_effect_internal (self, effect);
14985
14986   clutter_actor_queue_redraw (self);
14987
14988   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14989 }
14990
14991 /**
14992  * clutter_actor_add_effect_with_name:
14993  * @self: a #ClutterActor
14994  * @name: the name to set on the effect
14995  * @effect: a #ClutterEffect
14996  *
14997  * A convenience function for setting the name of a #ClutterEffect
14998  * while adding it to the list of effectss applied to @self
14999  *
15000  * This function is the logical equivalent of:
15001  *
15002  * |[
15003  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15004  *   clutter_actor_add_effect (self, effect);
15005  * ]|
15006  *
15007  * Since: 1.4
15008  */
15009 void
15010 clutter_actor_add_effect_with_name (ClutterActor  *self,
15011                                     const gchar   *name,
15012                                     ClutterEffect *effect)
15013 {
15014   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15015   g_return_if_fail (name != NULL);
15016   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15017
15018   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15019   clutter_actor_add_effect (self, effect);
15020 }
15021
15022 /**
15023  * clutter_actor_remove_effect:
15024  * @self: a #ClutterActor
15025  * @effect: a #ClutterEffect
15026  *
15027  * Removes @effect from the list of effects applied to @self
15028  *
15029  * The reference held by @self on the #ClutterEffect will be released
15030  *
15031  * Since: 1.4
15032  */
15033 void
15034 clutter_actor_remove_effect (ClutterActor  *self,
15035                              ClutterEffect *effect)
15036 {
15037   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15038   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15039
15040   _clutter_actor_remove_effect_internal (self, effect);
15041
15042   clutter_actor_queue_redraw (self);
15043
15044   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15045 }
15046
15047 /**
15048  * clutter_actor_remove_effect_by_name:
15049  * @self: a #ClutterActor
15050  * @name: the name of the effect to remove
15051  *
15052  * Removes the #ClutterEffect with the given name from the list
15053  * of effects applied to @self
15054  *
15055  * Since: 1.4
15056  */
15057 void
15058 clutter_actor_remove_effect_by_name (ClutterActor *self,
15059                                      const gchar  *name)
15060 {
15061   ClutterActorPrivate *priv;
15062   ClutterActorMeta *meta;
15063
15064   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15065   g_return_if_fail (name != NULL);
15066
15067   priv = self->priv;
15068
15069   if (priv->effects == NULL)
15070     return;
15071
15072   meta = _clutter_meta_group_get_meta (priv->effects, name);
15073   if (meta == NULL)
15074     return;
15075
15076   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15077 }
15078
15079 /**
15080  * clutter_actor_get_effects:
15081  * @self: a #ClutterActor
15082  *
15083  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15084  *
15085  * Return value: (transfer container) (element-type Clutter.Effect): a list
15086  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15087  *   list are owned by Clutter and they should not be freed. You should
15088  *   free the returned list using g_list_free() when done
15089  *
15090  * Since: 1.4
15091  */
15092 GList *
15093 clutter_actor_get_effects (ClutterActor *self)
15094 {
15095   ClutterActorPrivate *priv;
15096
15097   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15098
15099   priv = self->priv;
15100
15101   if (priv->effects == NULL)
15102     return NULL;
15103
15104   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15105 }
15106
15107 /**
15108  * clutter_actor_get_effect:
15109  * @self: a #ClutterActor
15110  * @name: the name of the effect to retrieve
15111  *
15112  * Retrieves the #ClutterEffect with the given name in the list
15113  * of effects applied to @self
15114  *
15115  * Return value: (transfer none): a #ClutterEffect for the given
15116  *   name, or %NULL. The returned #ClutterEffect is owned by the
15117  *   actor and it should not be unreferenced directly
15118  *
15119  * Since: 1.4
15120  */
15121 ClutterEffect *
15122 clutter_actor_get_effect (ClutterActor *self,
15123                           const gchar  *name)
15124 {
15125   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15126   g_return_val_if_fail (name != NULL, NULL);
15127
15128   if (self->priv->effects == NULL)
15129     return NULL;
15130
15131   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15132 }
15133
15134 /**
15135  * clutter_actor_clear_effects:
15136  * @self: a #ClutterActor
15137  *
15138  * Clears the list of effects applied to @self
15139  *
15140  * Since: 1.4
15141  */
15142 void
15143 clutter_actor_clear_effects (ClutterActor *self)
15144 {
15145   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15146
15147   if (self->priv->effects == NULL)
15148     return;
15149
15150   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15151
15152   clutter_actor_queue_redraw (self);
15153 }
15154
15155 /**
15156  * clutter_actor_has_key_focus:
15157  * @self: a #ClutterActor
15158  *
15159  * Checks whether @self is the #ClutterActor that has key focus
15160  *
15161  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15162  *
15163  * Since: 1.4
15164  */
15165 gboolean
15166 clutter_actor_has_key_focus (ClutterActor *self)
15167 {
15168   ClutterActor *stage;
15169
15170   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15171
15172   stage = _clutter_actor_get_stage_internal (self);
15173   if (stage == NULL)
15174     return FALSE;
15175
15176   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15177 }
15178
15179 static gboolean
15180 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15181                                       ClutterPaintVolume *pv)
15182 {
15183   ClutterActorPrivate *priv = self->priv;
15184
15185   /* Actors are only expected to report a valid paint volume
15186    * while they have a valid allocation. */
15187   if (G_UNLIKELY (priv->needs_allocation))
15188     {
15189       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15190                     "Actor needs allocation",
15191                     _clutter_actor_get_debug_name (self));
15192       return FALSE;
15193     }
15194
15195   /* Check if there are any handlers connected to the paint
15196    * signal. If there are then all bets are off for what the paint
15197    * volume for this actor might possibly be!
15198    *
15199    * XXX: It's expected that this is going to end up being quite a
15200    * costly check to have to do here, but we haven't come up with
15201    * another solution that can reliably catch paint signal handlers at
15202    * the right time to either avoid artefacts due to invalid stage
15203    * clipping or due to incorrect culling.
15204    *
15205    * Previously we checked in clutter_actor_paint(), but at that time
15206    * we may already be using a stage clip that could be derived from
15207    * an invalid paint-volume. We used to try and handle that by
15208    * queuing a follow up, unclipped, redraw but still the previous
15209    * checking wasn't enough to catch invalid volumes involved in
15210    * culling (considering that containers may derive their volume from
15211    * children that haven't yet been painted)
15212    *
15213    * Longer term, improved solutions could be:
15214    * - Disallow painting in the paint signal, only allow using it
15215    *   for tracking when paints happen. We can add another API that
15216    *   allows monkey patching the paint of arbitrary actors but in a
15217    *   more controlled way and that also supports modifying the
15218    *   paint-volume.
15219    * - If we could be notified somehow when signal handlers are
15220    *   connected we wouldn't have to poll for handlers like this.
15221    */
15222   if (g_signal_has_handler_pending (self,
15223                                     actor_signals[PAINT],
15224                                     0,
15225                                     TRUE))
15226     {
15227       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15228                     "Actor has \"paint\" signal handlers",
15229                     _clutter_actor_get_debug_name (self));
15230       return FALSE;
15231     }
15232
15233   _clutter_paint_volume_init_static (pv, self);
15234
15235   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15236     {
15237       clutter_paint_volume_free (pv);
15238       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15239                     "Actor failed to report a volume",
15240                     _clutter_actor_get_debug_name (self));
15241       return FALSE;
15242     }
15243
15244   /* since effects can modify the paint volume, we allow them to actually
15245    * do this by making get_paint_volume() "context sensitive"
15246    */
15247   if (priv->effects != NULL)
15248     {
15249       if (priv->current_effect != NULL)
15250         {
15251           const GList *effects, *l;
15252
15253           /* if we are being called from within the paint sequence of
15254            * an actor, get the paint volume up to the current effect
15255            */
15256           effects = _clutter_meta_group_peek_metas (priv->effects);
15257           for (l = effects;
15258                l != NULL || (l != NULL && l->data != priv->current_effect);
15259                l = l->next)
15260             {
15261               if (!_clutter_effect_get_paint_volume (l->data, pv))
15262                 {
15263                   clutter_paint_volume_free (pv);
15264                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15265                                 "Effect (%s) failed to report a volume",
15266                                 _clutter_actor_get_debug_name (self),
15267                                 _clutter_actor_meta_get_debug_name (l->data));
15268                   return FALSE;
15269                 }
15270             }
15271         }
15272       else
15273         {
15274           const GList *effects, *l;
15275
15276           /* otherwise, get the cumulative volume */
15277           effects = _clutter_meta_group_peek_metas (priv->effects);
15278           for (l = effects; l != NULL; l = l->next)
15279             if (!_clutter_effect_get_paint_volume (l->data, pv))
15280               {
15281                 clutter_paint_volume_free (pv);
15282                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15283                               "Effect (%s) failed to report a volume",
15284                               _clutter_actor_get_debug_name (self),
15285                               _clutter_actor_meta_get_debug_name (l->data));
15286                 return FALSE;
15287               }
15288         }
15289     }
15290
15291   return TRUE;
15292 }
15293
15294 /* The public clutter_actor_get_paint_volume API returns a const
15295  * pointer since we return a pointer directly to the cached
15296  * PaintVolume associated with the actor and don't want the user to
15297  * inadvertently modify it, but for internal uses we sometimes need
15298  * access to the same PaintVolume but need to apply some book-keeping
15299  * modifications to it so we don't want a const pointer.
15300  */
15301 static ClutterPaintVolume *
15302 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15303 {
15304   ClutterActorPrivate *priv;
15305
15306   priv = self->priv;
15307
15308   if (priv->paint_volume_valid)
15309     clutter_paint_volume_free (&priv->paint_volume);
15310
15311   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15312     {
15313       priv->paint_volume_valid = TRUE;
15314       return &priv->paint_volume;
15315     }
15316   else
15317     {
15318       priv->paint_volume_valid = FALSE;
15319       return NULL;
15320     }
15321 }
15322
15323 /**
15324  * clutter_actor_get_paint_volume:
15325  * @self: a #ClutterActor
15326  *
15327  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15328  * when a paint volume can't be determined.
15329  *
15330  * The paint volume is defined as the 3D space occupied by an actor
15331  * when being painted.
15332  *
15333  * This function will call the <function>get_paint_volume()</function>
15334  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15335  * should not usually care about overriding the default implementation,
15336  * unless they are, for instance: painting outside their allocation, or
15337  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15338  * 3D depth).
15339  *
15340  * <note>2D actors overriding <function>get_paint_volume()</function>
15341  * ensure their volume has a depth of 0. (This will be true so long as
15342  * you don't call clutter_paint_volume_set_depth().)</note>
15343  *
15344  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15345  *   or %NULL if no volume could be determined. The returned pointer
15346  *   is not guaranteed to be valid across multiple frames; if you want
15347  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15348  *
15349  * Since: 1.6
15350  */
15351 const ClutterPaintVolume *
15352 clutter_actor_get_paint_volume (ClutterActor *self)
15353 {
15354   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15355
15356   return _clutter_actor_get_paint_volume_mutable (self);
15357 }
15358
15359 /**
15360  * clutter_actor_get_transformed_paint_volume:
15361  * @self: a #ClutterActor
15362  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15363  *    (or %NULL for the stage)
15364  *
15365  * Retrieves the 3D paint volume of an actor like
15366  * clutter_actor_get_paint_volume() does (Please refer to the
15367  * documentation of clutter_actor_get_paint_volume() for more
15368  * details.) and it additionally transforms the paint volume into the
15369  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15370  * is passed for @relative_to_ancestor)
15371  *
15372  * This can be used by containers that base their paint volume on
15373  * the volume of their children. Such containers can query the
15374  * transformed paint volume of all of its children and union them
15375  * together using clutter_paint_volume_union().
15376  *
15377  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15378  *   or %NULL if no volume could be determined. The returned pointer is
15379  *   not guaranteed to be valid across multiple frames; if you wish to
15380  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15381  *
15382  * Since: 1.6
15383  */
15384 const ClutterPaintVolume *
15385 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15386                                             ClutterActor *relative_to_ancestor)
15387 {
15388   const ClutterPaintVolume *volume;
15389   ClutterActor *stage;
15390   ClutterPaintVolume *transformed_volume;
15391
15392   stage = _clutter_actor_get_stage_internal (self);
15393   if (G_UNLIKELY (stage == NULL))
15394     return NULL;
15395
15396   if (relative_to_ancestor == NULL)
15397     relative_to_ancestor = stage;
15398
15399   volume = clutter_actor_get_paint_volume (self);
15400   if (volume == NULL)
15401     return NULL;
15402
15403   transformed_volume =
15404     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15405
15406   _clutter_paint_volume_copy_static (volume, transformed_volume);
15407
15408   _clutter_paint_volume_transform_relative (transformed_volume,
15409                                             relative_to_ancestor);
15410
15411   return transformed_volume;
15412 }
15413
15414 /**
15415  * clutter_actor_get_paint_box:
15416  * @self: a #ClutterActor
15417  * @box: (out): return location for a #ClutterActorBox
15418  *
15419  * Retrieves the paint volume of the passed #ClutterActor, and
15420  * transforms it into a 2D bounding box in stage coordinates.
15421  *
15422  * This function is useful to determine the on screen area occupied by
15423  * the actor. The box is only an approximation and may often be
15424  * considerably larger due to the optimizations used to calculate the
15425  * box. The box is never smaller though, so it can reliably be used
15426  * for culling.
15427  *
15428  * There are times when a 2D paint box can't be determined, e.g.
15429  * because the actor isn't yet parented under a stage or because
15430  * the actor is unable to determine a paint volume.
15431  *
15432  * Return value: %TRUE if a 2D paint box could be determined, else
15433  * %FALSE.
15434  *
15435  * Since: 1.6
15436  */
15437 gboolean
15438 clutter_actor_get_paint_box (ClutterActor    *self,
15439                              ClutterActorBox *box)
15440 {
15441   ClutterActor *stage;
15442   ClutterPaintVolume *pv;
15443
15444   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15445   g_return_val_if_fail (box != NULL, FALSE);
15446
15447   stage = _clutter_actor_get_stage_internal (self);
15448   if (G_UNLIKELY (!stage))
15449     return FALSE;
15450
15451   pv = _clutter_actor_get_paint_volume_mutable (self);
15452   if (G_UNLIKELY (!pv))
15453     return FALSE;
15454
15455   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15456
15457   return TRUE;
15458 }
15459
15460 /**
15461  * clutter_actor_has_overlaps:
15462  * @self: A #ClutterActor
15463  *
15464  * Asks the actor's implementation whether it may contain overlapping
15465  * primitives.
15466  *
15467  * For example; Clutter may use this to determine whether the painting
15468  * should be redirected to an offscreen buffer to correctly implement
15469  * the opacity property.
15470  *
15471  * Custom actors can override the default response by implementing the
15472  * #ClutterActor <function>has_overlaps</function> virtual function. See
15473  * clutter_actor_set_offscreen_redirect() for more information.
15474  *
15475  * Return value: %TRUE if the actor may have overlapping primitives, and
15476  *   %FALSE otherwise
15477  *
15478  * Since: 1.8
15479  */
15480 gboolean
15481 clutter_actor_has_overlaps (ClutterActor *self)
15482 {
15483   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15484
15485   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15486 }
15487
15488 /**
15489  * clutter_actor_has_effects:
15490  * @self: A #ClutterActor
15491  *
15492  * Returns whether the actor has any effects applied.
15493  *
15494  * Return value: %TRUE if the actor has any effects,
15495  *   %FALSE otherwise
15496  *
15497  * Since: 1.10
15498  */
15499 gboolean
15500 clutter_actor_has_effects (ClutterActor *self)
15501 {
15502   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15503
15504   if (self->priv->effects == NULL)
15505     return FALSE;
15506
15507   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15508 }
15509
15510 /**
15511  * clutter_actor_has_constraints:
15512  * @self: A #ClutterActor
15513  *
15514  * Returns whether the actor has any constraints applied.
15515  *
15516  * Return value: %TRUE if the actor has any constraints,
15517  *   %FALSE otherwise
15518  *
15519  * Since: 1.10
15520  */
15521 gboolean
15522 clutter_actor_has_constraints (ClutterActor *self)
15523 {
15524   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15525
15526   return self->priv->constraints != NULL;
15527 }
15528
15529 /**
15530  * clutter_actor_has_actions:
15531  * @self: A #ClutterActor
15532  *
15533  * Returns whether the actor has any actions applied.
15534  *
15535  * Return value: %TRUE if the actor has any actions,
15536  *   %FALSE otherwise
15537  *
15538  * Since: 1.10
15539  */
15540 gboolean
15541 clutter_actor_has_actions (ClutterActor *self)
15542 {
15543   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15544
15545   return self->priv->actions != NULL;
15546 }
15547
15548 /**
15549  * clutter_actor_get_n_children:
15550  * @self: a #ClutterActor
15551  *
15552  * Retrieves the number of children of @self.
15553  *
15554  * Return value: the number of children of an actor
15555  *
15556  * Since: 1.10
15557  */
15558 gint
15559 clutter_actor_get_n_children (ClutterActor *self)
15560 {
15561   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15562
15563   return self->priv->n_children;
15564 }
15565
15566 /**
15567  * clutter_actor_get_child_at_index:
15568  * @self: a #ClutterActor
15569  * @index_: the position in the list of children
15570  *
15571  * Retrieves the actor at the given @index_ inside the list of
15572  * children of @self.
15573  *
15574  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15575  *
15576  * Since: 1.10
15577  */
15578 ClutterActor *
15579 clutter_actor_get_child_at_index (ClutterActor *self,
15580                                   gint          index_)
15581 {
15582   ClutterActor *iter;
15583   int i;
15584
15585   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15586   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15587
15588   for (iter = self->priv->first_child, i = 0;
15589        iter != NULL && i < index_;
15590        iter = iter->priv->next_sibling, i += 1)
15591     ;
15592
15593   return iter;
15594 }
15595
15596 /*< private >
15597  * _clutter_actor_foreach_child:
15598  * @actor: The actor whos children you want to iterate
15599  * @callback: The function to call for each child
15600  * @user_data: Private data to pass to @callback
15601  *
15602  * Calls a given @callback once for each child of the specified @actor and
15603  * passing the @user_data pointer each time.
15604  *
15605  * Return value: returns %TRUE if all children were iterated, else
15606  *    %FALSE if a callback broke out of iteration early.
15607  */
15608 gboolean
15609 _clutter_actor_foreach_child (ClutterActor           *self,
15610                               ClutterForeachCallback  callback,
15611                               gpointer                user_data)
15612 {
15613   ClutterActorPrivate *priv = self->priv;
15614   ClutterActor *iter;
15615   gboolean cont;
15616
15617   for (cont = TRUE, iter = priv->first_child;
15618        cont && iter != NULL;
15619        iter = iter->priv->next_sibling)
15620     {
15621       cont = callback (iter, user_data);
15622     }
15623
15624   return cont;
15625 }
15626
15627 #if 0
15628 /* For debugging purposes this gives us a simple way to print out
15629  * the scenegraph e.g in gdb using:
15630  * [|
15631  *   _clutter_actor_traverse (stage,
15632  *                            0,
15633  *                            clutter_debug_print_actor_cb,
15634  *                            NULL,
15635  *                            NULL);
15636  * |]
15637  */
15638 static ClutterActorTraverseVisitFlags
15639 clutter_debug_print_actor_cb (ClutterActor *actor,
15640                               int depth,
15641                               void *user_data)
15642 {
15643   g_print ("%*s%s:%p\n",
15644            depth * 2, "",
15645            _clutter_actor_get_debug_name (actor),
15646            actor);
15647
15648   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15649 }
15650 #endif
15651
15652 static void
15653 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15654                                  ClutterTraverseCallback callback,
15655                                  gpointer                user_data)
15656 {
15657   GQueue *queue = g_queue_new ();
15658   ClutterActor dummy;
15659   int current_depth = 0;
15660
15661   g_queue_push_tail (queue, actor);
15662   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15663
15664   while ((actor = g_queue_pop_head (queue)))
15665     {
15666       ClutterActorTraverseVisitFlags flags;
15667
15668       if (actor == &dummy)
15669         {
15670           current_depth++;
15671           g_queue_push_tail (queue, &dummy);
15672           continue;
15673         }
15674
15675       flags = callback (actor, current_depth, user_data);
15676       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15677         break;
15678       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15679         {
15680           ClutterActor *iter;
15681
15682           for (iter = actor->priv->first_child;
15683                iter != NULL;
15684                iter = iter->priv->next_sibling)
15685             {
15686               g_queue_push_tail (queue, iter);
15687             }
15688         }
15689     }
15690
15691   g_queue_free (queue);
15692 }
15693
15694 static ClutterActorTraverseVisitFlags
15695 _clutter_actor_traverse_depth (ClutterActor           *actor,
15696                                ClutterTraverseCallback before_children_callback,
15697                                ClutterTraverseCallback after_children_callback,
15698                                int                     current_depth,
15699                                gpointer                user_data)
15700 {
15701   ClutterActorTraverseVisitFlags flags;
15702
15703   flags = before_children_callback (actor, current_depth, user_data);
15704   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15705     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15706
15707   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15708     {
15709       ClutterActor *iter;
15710
15711       for (iter = actor->priv->first_child;
15712            iter != NULL;
15713            iter = iter->priv->next_sibling)
15714         {
15715           flags = _clutter_actor_traverse_depth (iter,
15716                                                  before_children_callback,
15717                                                  after_children_callback,
15718                                                  current_depth + 1,
15719                                                  user_data);
15720
15721           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15722             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15723         }
15724     }
15725
15726   if (after_children_callback)
15727     return after_children_callback (actor, current_depth, user_data);
15728   else
15729     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15730 }
15731
15732 /* _clutter_actor_traverse:
15733  * @actor: The actor to start traversing the graph from
15734  * @flags: These flags may affect how the traversal is done
15735  * @before_children_callback: A function to call before visiting the
15736  *   children of the current actor.
15737  * @after_children_callback: A function to call after visiting the
15738  *   children of the current actor. (Ignored if
15739  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15740  * @user_data: The private data to pass to the callbacks
15741  *
15742  * Traverses the scenegraph starting at the specified @actor and
15743  * descending through all its children and its children's children.
15744  * For each actor traversed @before_children_callback and
15745  * @after_children_callback are called with the specified
15746  * @user_data, before and after visiting that actor's children.
15747  *
15748  * The callbacks can return flags that affect the ongoing traversal
15749  * such as by skipping over an actors children or bailing out of
15750  * any further traversing.
15751  */
15752 void
15753 _clutter_actor_traverse (ClutterActor              *actor,
15754                          ClutterActorTraverseFlags  flags,
15755                          ClutterTraverseCallback    before_children_callback,
15756                          ClutterTraverseCallback    after_children_callback,
15757                          gpointer                   user_data)
15758 {
15759   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15760     _clutter_actor_traverse_breadth (actor,
15761                                      before_children_callback,
15762                                      user_data);
15763   else /* DEPTH_FIRST */
15764     _clutter_actor_traverse_depth (actor,
15765                                    before_children_callback,
15766                                    after_children_callback,
15767                                    0, /* start depth */
15768                                    user_data);
15769 }
15770
15771 static void
15772 on_layout_manager_changed (ClutterLayoutManager *manager,
15773                            ClutterActor         *self)
15774 {
15775   clutter_actor_queue_relayout (self);
15776 }
15777
15778 /**
15779  * clutter_actor_set_layout_manager:
15780  * @self: a #ClutterActor
15781  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15782  *
15783  * Sets the #ClutterLayoutManager delegate object that will be used to
15784  * lay out the children of @self.
15785  *
15786  * The #ClutterActor will take a reference on the passed @manager which
15787  * will be released either when the layout manager is removed, or when
15788  * the actor is destroyed.
15789  *
15790  * Since: 1.10
15791  */
15792 void
15793 clutter_actor_set_layout_manager (ClutterActor         *self,
15794                                   ClutterLayoutManager *manager)
15795 {
15796   ClutterActorPrivate *priv;
15797
15798   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15799   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15800
15801   priv = self->priv;
15802
15803   if (priv->layout_manager != NULL)
15804     {
15805       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15806                                             G_CALLBACK (on_layout_manager_changed),
15807                                             self);
15808       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15809       g_object_unref (priv->layout_manager);
15810     }
15811
15812   priv->layout_manager = manager;
15813
15814   if (priv->layout_manager != NULL)
15815     {
15816       g_object_ref_sink (priv->layout_manager);
15817       clutter_layout_manager_set_container (priv->layout_manager,
15818                                             CLUTTER_CONTAINER (self));
15819       g_signal_connect (priv->layout_manager, "layout-changed",
15820                         G_CALLBACK (on_layout_manager_changed),
15821                         self);
15822     }
15823
15824   clutter_actor_queue_relayout (self);
15825
15826   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15827 }
15828
15829 /**
15830  * clutter_actor_get_layout_manager:
15831  * @self: a #ClutterActor
15832  *
15833  * Retrieves the #ClutterLayoutManager used by @self.
15834  *
15835  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15836  *   or %NULL
15837  *
15838  * Since: 1.10
15839  */
15840 ClutterLayoutManager *
15841 clutter_actor_get_layout_manager (ClutterActor *self)
15842 {
15843   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15844
15845   return self->priv->layout_manager;
15846 }
15847
15848 static const ClutterLayoutInfo default_layout_info = {
15849   0.f,                          /* fixed-x */
15850   0.f,                          /* fixed-y */
15851   { 0, 0, 0, 0 },               /* margin */
15852   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15853   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15854   0.f, 0.f,                     /* min_width, natural_width */
15855   0.f, 0.f,                     /* natual_width, natural_height */
15856 };
15857
15858 static void
15859 layout_info_free (gpointer data)
15860 {
15861   if (G_LIKELY (data != NULL))
15862     g_slice_free (ClutterLayoutInfo, data);
15863 }
15864
15865 /*< private >
15866  * _clutter_actor_get_layout_info:
15867  * @self: a #ClutterActor
15868  *
15869  * Retrieves a pointer to the ClutterLayoutInfo structure.
15870  *
15871  * If the actor does not have a ClutterLayoutInfo associated to it, one
15872  * will be created and initialized to the default values.
15873  *
15874  * This function should be used for setters.
15875  *
15876  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15877  * instead.
15878  *
15879  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15880  */
15881 ClutterLayoutInfo *
15882 _clutter_actor_get_layout_info (ClutterActor *self)
15883 {
15884   ClutterLayoutInfo *retval;
15885
15886   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15887   if (retval == NULL)
15888     {
15889       retval = g_slice_new (ClutterLayoutInfo);
15890
15891       *retval = default_layout_info;
15892
15893       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15894                                retval,
15895                                layout_info_free);
15896     }
15897
15898   return retval;
15899 }
15900
15901 /*< private >
15902  * _clutter_actor_get_layout_info_or_defaults:
15903  * @self: a #ClutterActor
15904  *
15905  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15906  *
15907  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15908  * then the default structure will be returned.
15909  *
15910  * This function should only be used for getters.
15911  *
15912  * Return value: a const pointer to the ClutterLayoutInfo structure
15913  */
15914 const ClutterLayoutInfo *
15915 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15916 {
15917   const ClutterLayoutInfo *info;
15918
15919   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15920   if (info == NULL)
15921     return &default_layout_info;
15922
15923   return info;
15924 }
15925
15926 /**
15927  * clutter_actor_set_x_align:
15928  * @self: a #ClutterActor
15929  * @x_align: the horizontal alignment policy
15930  *
15931  * Sets the horizontal alignment policy of a #ClutterActor, in case the
15932  * actor received extra horizontal space.
15933  *
15934  * See also the #ClutterActor:x-align property.
15935  *
15936  * Since: 1.10
15937  */
15938 void
15939 clutter_actor_set_x_align (ClutterActor      *self,
15940                            ClutterActorAlign  x_align)
15941 {
15942   ClutterLayoutInfo *info;
15943
15944   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15945
15946   info = _clutter_actor_get_layout_info (self);
15947
15948   if (info->x_align != x_align)
15949     {
15950       info->x_align = x_align;
15951
15952       clutter_actor_queue_relayout (self);
15953
15954       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15955     }
15956 }
15957
15958 /**
15959  * clutter_actor_get_x_align:
15960  * @self: a #ClutterActor
15961  *
15962  * Retrieves the horizontal alignment policy set using
15963  * clutter_actor_set_x_align().
15964  *
15965  * Return value: the horizontal alignment policy.
15966  *
15967  * Since: 1.10
15968  */
15969 ClutterActorAlign
15970 clutter_actor_get_x_align (ClutterActor *self)
15971 {
15972   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15973
15974   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15975 }
15976
15977 /**
15978  * clutter_actor_set_y_align:
15979  * @self: a #ClutterActor
15980  * @y_align: the vertical alignment policy
15981  *
15982  * Sets the vertical alignment policy of a #ClutterActor, in case the
15983  * actor received extra vertical space.
15984  *
15985  * See also the #ClutterActor:y-align property.
15986  *
15987  * Since: 1.10
15988  */
15989 void
15990 clutter_actor_set_y_align (ClutterActor      *self,
15991                            ClutterActorAlign  y_align)
15992 {
15993   ClutterLayoutInfo *info;
15994
15995   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15996
15997   info = _clutter_actor_get_layout_info (self);
15998
15999   if (info->y_align != y_align)
16000     {
16001       info->y_align = y_align;
16002
16003       clutter_actor_queue_relayout (self);
16004
16005       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16006     }
16007 }
16008
16009 /**
16010  * clutter_actor_get_y_align:
16011  * @self: a #ClutterActor
16012  *
16013  * Retrieves the vertical alignment policy set using
16014  * clutter_actor_set_y_align().
16015  *
16016  * Return value: the vertical alignment policy.
16017  *
16018  * Since: 1.10
16019  */
16020 ClutterActorAlign
16021 clutter_actor_get_y_align (ClutterActor *self)
16022 {
16023   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16024
16025   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16026 }
16027
16028
16029 /**
16030  * clutter_margin_new:
16031  *
16032  * Creates a new #ClutterMargin.
16033  *
16034  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16035  *   clutter_margin_free() to free the resources associated with it when
16036  *   done.
16037  *
16038  * Since: 1.10
16039  */
16040 ClutterMargin *
16041 clutter_margin_new (void)
16042 {
16043   return g_slice_new0 (ClutterMargin);
16044 }
16045
16046 /**
16047  * clutter_margin_copy:
16048  * @margin_: a #ClutterMargin
16049  *
16050  * Creates a new #ClutterMargin and copies the contents of @margin_ into
16051  * the newly created structure.
16052  *
16053  * Return value: (transfer full): a copy of the #ClutterMargin.
16054  *
16055  * Since: 1.10
16056  */
16057 ClutterMargin *
16058 clutter_margin_copy (const ClutterMargin *margin_)
16059 {
16060   if (G_LIKELY (margin_ != NULL))
16061     return g_slice_dup (ClutterMargin, margin_);
16062
16063   return NULL;
16064 }
16065
16066 /**
16067  * clutter_margin_free:
16068  * @margin_: a #ClutterMargin
16069  *
16070  * Frees the resources allocated by clutter_margin_new() and
16071  * clutter_margin_copy().
16072  *
16073  * Since: 1.10
16074  */
16075 void
16076 clutter_margin_free (ClutterMargin *margin_)
16077 {
16078   if (G_LIKELY (margin_ != NULL))
16079     g_slice_free (ClutterMargin, margin_);
16080 }
16081
16082 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16083                      clutter_margin_copy,
16084                      clutter_margin_free)
16085
16086 /**
16087  * clutter_actor_set_margin:
16088  * @self: a #ClutterActor
16089  * @margin: a #ClutterMargin
16090  *
16091  * Sets all the components of the margin of a #ClutterActor.
16092  *
16093  * Since: 1.10
16094  */
16095 void
16096 clutter_actor_set_margin (ClutterActor        *self,
16097                           const ClutterMargin *margin)
16098 {
16099   ClutterLayoutInfo *info;
16100   gboolean changed;
16101   GObject *obj;
16102
16103   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16104   g_return_if_fail (margin != NULL);
16105
16106   obj = G_OBJECT (self);
16107   changed = FALSE;
16108
16109   g_object_freeze_notify (obj);
16110
16111   info = _clutter_actor_get_layout_info (self);
16112
16113   if (info->margin.top != margin->top)
16114     {
16115       info->margin.top = margin->top;
16116       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16117       changed = TRUE;
16118     }
16119
16120   if (info->margin.right != margin->right)
16121     {
16122       info->margin.right = margin->right;
16123       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16124       changed = TRUE;
16125     }
16126
16127   if (info->margin.bottom != margin->bottom)
16128     {
16129       info->margin.bottom = margin->bottom;
16130       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16131       changed = TRUE;
16132     }
16133
16134   if (info->margin.left != margin->left)
16135     {
16136       info->margin.left = margin->left;
16137       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16138       changed = TRUE;
16139     }
16140
16141   if (changed)
16142     clutter_actor_queue_relayout (self);
16143
16144   g_object_thaw_notify (obj);
16145 }
16146
16147 /**
16148  * clutter_actor_get_margin:
16149  * @self: a #ClutterActor
16150  * @margin: (out caller-allocates): return location for a #ClutterMargin
16151  *
16152  * Retrieves all the components of the margin of a #ClutterActor.
16153  *
16154  * Since: 1.10
16155  */
16156 void
16157 clutter_actor_get_margin (ClutterActor  *self,
16158                           ClutterMargin *margin)
16159 {
16160   const ClutterLayoutInfo *info;
16161
16162   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16163   g_return_if_fail (margin != NULL);
16164
16165   info = _clutter_actor_get_layout_info_or_defaults (self);
16166
16167   *margin = info->margin;
16168 }
16169
16170 /**
16171  * clutter_actor_set_margin_top:
16172  * @self: a #ClutterActor
16173  * @margin: the top margin
16174  *
16175  * Sets the margin from the top of a #ClutterActor.
16176  *
16177  * Since: 1.10
16178  */
16179 void
16180 clutter_actor_set_margin_top (ClutterActor *self,
16181                               gfloat        margin)
16182 {
16183   ClutterLayoutInfo *info;
16184
16185   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16186   g_return_if_fail (margin >= 0.f);
16187
16188   info = _clutter_actor_get_layout_info (self);
16189
16190   if (info->margin.top == margin)
16191     return;
16192
16193   info->margin.top = margin;
16194
16195   clutter_actor_queue_relayout (self);
16196
16197   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16198 }
16199
16200 /**
16201  * clutter_actor_get_margin_top:
16202  * @self: a #ClutterActor
16203  *
16204  * Retrieves the top margin of a #ClutterActor.
16205  *
16206  * Return value: the top margin
16207  *
16208  * Since: 1.10
16209  */
16210 gfloat
16211 clutter_actor_get_margin_top (ClutterActor *self)
16212 {
16213   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16214
16215   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16216 }
16217
16218 /**
16219  * clutter_actor_set_margin_bottom:
16220  * @self: a #ClutterActor
16221  * @margin: the bottom margin
16222  *
16223  * Sets the margin from the bottom of a #ClutterActor.
16224  *
16225  * Since: 1.10
16226  */
16227 void
16228 clutter_actor_set_margin_bottom (ClutterActor *self,
16229                                  gfloat        margin)
16230 {
16231   ClutterLayoutInfo *info;
16232
16233   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16234   g_return_if_fail (margin >= 0.f);
16235
16236   info = _clutter_actor_get_layout_info (self);
16237
16238   if (info->margin.bottom == margin)
16239     return;
16240
16241   info->margin.bottom = margin;
16242
16243   clutter_actor_queue_relayout (self);
16244
16245   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16246 }
16247
16248 /**
16249  * clutter_actor_get_margin_bottom:
16250  * @self: a #ClutterActor
16251  *
16252  * Retrieves the bottom margin of a #ClutterActor.
16253  *
16254  * Return value: the bottom margin
16255  *
16256  * Since: 1.10
16257  */
16258 gfloat
16259 clutter_actor_get_margin_bottom (ClutterActor *self)
16260 {
16261   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16262
16263   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16264 }
16265
16266 /**
16267  * clutter_actor_set_margin_left:
16268  * @self: a #ClutterActor
16269  * @margin: the left margin
16270  *
16271  * Sets the margin from the left of a #ClutterActor.
16272  *
16273  * Since: 1.10
16274  */
16275 void
16276 clutter_actor_set_margin_left (ClutterActor *self,
16277                                gfloat        margin)
16278 {
16279   ClutterLayoutInfo *info;
16280
16281   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16282   g_return_if_fail (margin >= 0.f);
16283
16284   info = _clutter_actor_get_layout_info (self);
16285
16286   if (info->margin.left == margin)
16287     return;
16288
16289   info->margin.left = margin;
16290
16291   clutter_actor_queue_relayout (self);
16292
16293   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16294 }
16295
16296 /**
16297  * clutter_actor_get_margin_left:
16298  * @self: a #ClutterActor
16299  *
16300  * Retrieves the left margin of a #ClutterActor.
16301  *
16302  * Return value: the left margin
16303  *
16304  * Since: 1.10
16305  */
16306 gfloat
16307 clutter_actor_get_margin_left (ClutterActor *self)
16308 {
16309   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16310
16311   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16312 }
16313
16314 /**
16315  * clutter_actor_set_margin_right:
16316  * @self: a #ClutterActor
16317  * @margin: the right margin
16318  *
16319  * Sets the margin from the right of a #ClutterActor.
16320  *
16321  * Since: 1.10
16322  */
16323 void
16324 clutter_actor_set_margin_right (ClutterActor *self,
16325                                 gfloat        margin)
16326 {
16327   ClutterLayoutInfo *info;
16328
16329   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16330   g_return_if_fail (margin >= 0.f);
16331
16332   info = _clutter_actor_get_layout_info (self);
16333
16334   if (info->margin.right == margin)
16335     return;
16336
16337   info->margin.right = margin;
16338
16339   clutter_actor_queue_relayout (self);
16340
16341   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16342 }
16343
16344 /**
16345  * clutter_actor_get_margin_right:
16346  * @self: a #ClutterActor
16347  *
16348  * Retrieves the right margin of a #ClutterActor.
16349  *
16350  * Return value: the right margin
16351  *
16352  * Since: 1.10
16353  */
16354 gfloat
16355 clutter_actor_get_margin_right (ClutterActor *self)
16356 {
16357   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16358
16359   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16360 }
16361
16362 static inline void
16363 clutter_actor_set_background_color_internal (ClutterActor *self,
16364                                              const ClutterColor *color)
16365 {
16366   ClutterActorPrivate *priv = self->priv;
16367   GObject *obj;
16368
16369   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16370     return;
16371
16372   obj = G_OBJECT (self);
16373
16374   priv->bg_color = *color;
16375   priv->bg_color_set = TRUE;
16376
16377   clutter_actor_queue_redraw (self);
16378
16379   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16380   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16381 }
16382
16383 /**
16384  * clutter_actor_set_background_color:
16385  * @self: a #ClutterActor
16386  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16387  *  set color
16388  *
16389  * Sets the background color of a #ClutterActor.
16390  *
16391  * The background color will be used to cover the whole allocation of the
16392  * actor. The default background color of an actor is transparent.
16393  *
16394  * To check whether an actor has a background color, you can use the
16395  * #ClutterActor:background-color-set actor property.
16396  *
16397  * The #ClutterActor:background-color property is animatable.
16398  *
16399  * Since: 1.10
16400  */
16401 void
16402 clutter_actor_set_background_color (ClutterActor       *self,
16403                                     const ClutterColor *color)
16404 {
16405   ClutterActorPrivate *priv;
16406   GObject *obj;
16407   GParamSpec *bg_color_pspec;
16408
16409   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16410
16411   obj = G_OBJECT (self);
16412
16413   priv = self->priv;
16414
16415   if (color == NULL)
16416     {
16417       priv->bg_color_set = FALSE;
16418       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16419       clutter_actor_queue_redraw (self);
16420       return;
16421     }
16422
16423   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16424   if (clutter_actor_get_easing_duration (self) != 0)
16425     {
16426       ClutterTransition *transition;
16427
16428       transition = _clutter_actor_get_transition (self, bg_color_pspec);
16429       if (transition == NULL)
16430         {
16431           transition = _clutter_actor_create_transition (self, bg_color_pspec,
16432                                                          &priv->bg_color,
16433                                                          color);
16434           clutter_timeline_start (CLUTTER_TIMELINE (transition));
16435         }
16436       else
16437         _clutter_actor_update_transition (self, bg_color_pspec, color);
16438
16439       clutter_actor_queue_redraw (self);
16440     }
16441   else
16442     clutter_actor_set_background_color_internal (self, color);
16443 }
16444
16445 /**
16446  * clutter_actor_get_background_color:
16447  * @self: a #ClutterActor
16448  * @color: (out caller-allocates): return location for a #ClutterColor
16449  *
16450  * Retrieves the color set using clutter_actor_set_background_color().
16451  *
16452  * Since: 1.10
16453  */
16454 void
16455 clutter_actor_get_background_color (ClutterActor *self,
16456                                     ClutterColor *color)
16457 {
16458   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16459   g_return_if_fail (color != NULL);
16460
16461   *color = self->priv->bg_color;
16462 }
16463
16464 /**
16465  * clutter_actor_get_previous_sibling:
16466  * @self: a #ClutterActor
16467  *
16468  * Retrieves the sibling of @self that comes before it in the list
16469  * of children of @self's parent.
16470  *
16471  * The returned pointer is only valid until the scene graph changes; it
16472  * is not safe to modify the list of children of @self while iterating
16473  * it.
16474  *
16475  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16476  *
16477  * Since: 1.10
16478  */
16479 ClutterActor *
16480 clutter_actor_get_previous_sibling (ClutterActor *self)
16481 {
16482   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16483
16484   return self->priv->prev_sibling;
16485 }
16486
16487 /**
16488  * clutter_actor_get_next_sibling:
16489  * @self: a #ClutterActor
16490  *
16491  * Retrieves the sibling of @self that comes after it in the list
16492  * of children of @self's parent.
16493  *
16494  * The returned pointer is only valid until the scene graph changes; it
16495  * is not safe to modify the list of children of @self while iterating
16496  * it.
16497  *
16498  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16499  *
16500  * Since: 1.10
16501  */
16502 ClutterActor *
16503 clutter_actor_get_next_sibling (ClutterActor *self)
16504 {
16505   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16506
16507   return self->priv->next_sibling;
16508 }
16509
16510 /**
16511  * clutter_actor_get_first_child:
16512  * @self: a #ClutterActor
16513  *
16514  * Retrieves the first child of @self.
16515  *
16516  * The returned pointer is only valid until the scene graph changes; it
16517  * is not safe to modify the list of children of @self while iterating
16518  * it.
16519  *
16520  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16521  *
16522  * Since: 1.10
16523  */
16524 ClutterActor *
16525 clutter_actor_get_first_child (ClutterActor *self)
16526 {
16527   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16528
16529   return self->priv->first_child;
16530 }
16531
16532 /**
16533  * clutter_actor_get_last_child:
16534  * @self: a #ClutterActor
16535  *
16536  * Retrieves the last child of @self.
16537  *
16538  * The returned pointer is only valid until the scene graph changes; it
16539  * is not safe to modify the list of children of @self while iterating
16540  * it.
16541  *
16542  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16543  *
16544  * Since: 1.10
16545  */
16546 ClutterActor *
16547 clutter_actor_get_last_child (ClutterActor *self)
16548 {
16549   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16550
16551   return self->priv->last_child;
16552 }
16553
16554 /* easy way to have properly named fields instead of the dummy ones
16555  * we use in the public structure
16556  */
16557 typedef struct _RealActorIter
16558 {
16559   ClutterActor *root;           /* dummy1 */
16560   ClutterActor *current;        /* dummy2 */
16561   gpointer padding_1;           /* dummy3 */
16562   gint age;                     /* dummy4 */
16563   gpointer padding_2;           /* dummy5 */
16564 } RealActorIter;
16565
16566 /**
16567  * clutter_actor_iter_init:
16568  * @iter: a #ClutterActorIter
16569  * @root: a #ClutterActor
16570  *
16571  * Initializes a #ClutterActorIter, which can then be used to iterate
16572  * efficiently over a section of the scene graph, and associates it
16573  * with @root.
16574  *
16575  * Modifying the scene graph section that contains @root will invalidate
16576  * the iterator.
16577  *
16578  * |[
16579  *   ClutterActorIter iter;
16580  *   ClutterActor *child;
16581  *
16582  *   clutter_actor_iter_init (&iter, container);
16583  *   while (clutter_actor_iter_next (&iter, &child))
16584  *     {
16585  *       /&ast; do something with child &ast;/
16586  *     }
16587  * ]|
16588  *
16589  * Since: 1.10
16590  */
16591 void
16592 clutter_actor_iter_init (ClutterActorIter *iter,
16593                          ClutterActor     *root)
16594 {
16595   RealActorIter *ri = (RealActorIter *) iter;
16596
16597   g_return_if_fail (iter != NULL);
16598   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16599
16600   ri->root = root;
16601   ri->current = NULL;
16602   ri->age = root->priv->age;
16603 }
16604
16605 /**
16606  * clutter_actor_iter_next:
16607  * @iter: a #ClutterActorIter
16608  * @child: (out): return location for a #ClutterActor
16609  *
16610  * Advances the @iter and retrieves the next child of the root #ClutterActor
16611  * that was used to initialize the #ClutterActorIterator.
16612  *
16613  * If the iterator can advance, this function returns %TRUE and sets the
16614  * @child argument.
16615  *
16616  * If the iterator cannot advance, this function returns %FALSE, and
16617  * the contents of @child are undefined.
16618  *
16619  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16620  *
16621  * Since: 1.10
16622  */
16623 gboolean
16624 clutter_actor_iter_next (ClutterActorIter  *iter,
16625                          ClutterActor     **child)
16626 {
16627   RealActorIter *ri = (RealActorIter *) iter;
16628
16629   g_return_val_if_fail (iter != NULL, FALSE);
16630   g_return_val_if_fail (ri->root != NULL, FALSE);
16631 #ifndef G_DISABLE_ASSERT
16632   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16633 #endif
16634
16635   if (ri->current == NULL)
16636     ri->current = ri->root->priv->first_child;
16637   else
16638     ri->current = ri->current->priv->next_sibling;
16639
16640   if (child != NULL)
16641     *child = ri->current;
16642
16643   return ri->current != NULL;
16644 }
16645
16646 /**
16647  * clutter_actor_iter_prev:
16648  * @iter: a #ClutterActorIter
16649  * @child: (out): return location for a #ClutterActor
16650  *
16651  * Advances the @iter and retrieves the previous child of the root
16652  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16653  *
16654  * If the iterator can advance, this function returns %TRUE and sets the
16655  * @child argument.
16656  *
16657  * If the iterator cannot advance, this function returns %FALSE, and
16658  * the contents of @child are undefined.
16659  *
16660  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16661  *
16662  * Since: 1.10
16663  */
16664 gboolean
16665 clutter_actor_iter_prev (ClutterActorIter  *iter,
16666                          ClutterActor     **child)
16667 {
16668   RealActorIter *ri = (RealActorIter *) iter;
16669
16670   g_return_val_if_fail (iter != NULL, FALSE);
16671   g_return_val_if_fail (ri->root != NULL, FALSE);
16672 #ifndef G_DISABLE_ASSERT
16673   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16674 #endif
16675
16676   if (ri->current == NULL)
16677     ri->current = ri->root->priv->last_child;
16678   else
16679     ri->current = ri->current->priv->prev_sibling;
16680
16681   if (child != NULL)
16682     *child = ri->current;
16683
16684   return ri->current != NULL;
16685 }
16686
16687 /**
16688  * clutter_actor_iter_remove:
16689  * @iter: a #ClutterActorIter
16690  *
16691  * Safely removes the #ClutterActor currently pointer to by the iterator
16692  * from its parent.
16693  *
16694  * This function can only be called after clutter_actor_iter_next() or
16695  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16696  * than once for the same actor.
16697  *
16698  * This function will call clutter_actor_remove_child() internally.
16699  *
16700  * Since: 1.10
16701  */
16702 void
16703 clutter_actor_iter_remove (ClutterActorIter *iter)
16704 {
16705   RealActorIter *ri = (RealActorIter *) iter;
16706   ClutterActor *cur;
16707
16708   g_return_if_fail (iter != NULL);
16709   g_return_if_fail (ri->root != NULL);
16710 #ifndef G_DISABLE_ASSERT
16711   g_return_if_fail (ri->age == ri->root->priv->age);
16712 #endif
16713   g_return_if_fail (ri->current != NULL);
16714
16715   cur = ri->current;
16716
16717   if (cur != NULL)
16718     {
16719       ri->current = cur->priv->prev_sibling;
16720
16721       clutter_actor_remove_child_internal (ri->root, cur,
16722                                            REMOVE_CHILD_DEFAULT_FLAGS);
16723
16724       ri->age += 1;
16725     }
16726 }
16727
16728 /**
16729  * clutter_actor_iter_destroy:
16730  * @iter: a #ClutterActorIter
16731  *
16732  * Safely destroys the #ClutterActor currently pointer to by the iterator
16733  * from its parent.
16734  *
16735  * This function can only be called after clutter_actor_iter_next() or
16736  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16737  * than once for the same actor.
16738  *
16739  * This function will call clutter_actor_destroy() internally.
16740  *
16741  * Since: 1.10
16742  */
16743 void
16744 clutter_actor_iter_destroy (ClutterActorIter *iter)
16745 {
16746   RealActorIter *ri = (RealActorIter *) iter;
16747   ClutterActor *cur;
16748
16749   g_return_if_fail (iter != NULL);
16750   g_return_if_fail (ri->root != NULL);
16751 #ifndef G_DISABLE_ASSERT
16752   g_return_if_fail (ri->age == ri->root->priv->age);
16753 #endif
16754   g_return_if_fail (ri->current != NULL);
16755
16756   cur = ri->current;
16757
16758   if (cur != NULL)
16759     {
16760       ri->current = cur->priv->prev_sibling;
16761
16762       clutter_actor_destroy (cur);
16763
16764       ri->age += 1;
16765     }
16766 }
16767
16768 static const ClutterAnimationInfo default_animation_info = {
16769   NULL,         /* transitions */
16770   NULL,         /* states */
16771   NULL,         /* cur_state */
16772 };
16773
16774 static void
16775 clutter_animation_info_free (gpointer data)
16776 {
16777   if (data != NULL)
16778     {
16779       ClutterAnimationInfo *info = data;
16780
16781       if (info->transitions != NULL)
16782         g_hash_table_unref (info->transitions);
16783
16784       if (info->states != NULL)
16785         g_array_unref (info->states);
16786
16787       g_slice_free (ClutterAnimationInfo, info);
16788     }
16789 }
16790
16791 const ClutterAnimationInfo *
16792 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16793 {
16794   const ClutterAnimationInfo *res;
16795   GObject *obj = G_OBJECT (self);
16796
16797   res = g_object_get_qdata (obj, quark_actor_animation_info);
16798   if (res != NULL)
16799     return res;
16800
16801   return &default_animation_info;
16802 }
16803
16804 ClutterAnimationInfo *
16805 _clutter_actor_get_animation_info (ClutterActor *self)
16806 {
16807   GObject *obj = G_OBJECT (self);
16808   ClutterAnimationInfo *res;
16809
16810   res = g_object_get_qdata (obj, quark_actor_animation_info);
16811   if (res == NULL)
16812     {
16813       res = g_slice_new (ClutterAnimationInfo);
16814
16815       *res = default_animation_info;
16816
16817       g_object_set_qdata_full (obj, quark_actor_animation_info,
16818                                res,
16819                                clutter_animation_info_free);
16820     }
16821
16822   return res;
16823 }
16824
16825 ClutterTransition *
16826 _clutter_actor_get_transition (ClutterActor *actor,
16827                                GParamSpec   *pspec)
16828 {
16829   const ClutterAnimationInfo *info;
16830
16831   info = _clutter_actor_get_animation_info_or_defaults (actor);
16832
16833   if (info->transitions == NULL)
16834     return NULL;
16835
16836   return g_hash_table_lookup (info->transitions, pspec->name);
16837 }
16838
16839 typedef struct _TransitionClosure
16840 {
16841   ClutterActor *actor;
16842   ClutterTransition *transition;
16843   gchar *name;
16844   gulong completed_id;
16845 } TransitionClosure;
16846
16847 static void
16848 transition_closure_free (gpointer data)
16849 {
16850   if (G_LIKELY (data != NULL))
16851     {
16852       TransitionClosure *clos = data;
16853
16854       g_signal_handler_disconnect (clos->transition, clos->completed_id);
16855       g_free (clos->name);
16856
16857       g_slice_free (TransitionClosure, clos);
16858     }
16859 }
16860
16861 static void
16862 on_transition_completed (ClutterTransition *transition,
16863                          TransitionClosure *clos)
16864 {
16865   ClutterAnimationInfo *info;
16866
16867   info = _clutter_actor_get_animation_info (clos->actor);
16868
16869   /* this will take care of cleaning clos for us */
16870   g_hash_table_remove (info->transitions, clos->name);
16871 }
16872
16873 void
16874 _clutter_actor_update_transition (ClutterActor *actor,
16875                                   GParamSpec   *pspec,
16876                                   ...)
16877 {
16878   TransitionClosure *clos;
16879   ClutterInterval *interval;
16880   const ClutterAnimationInfo *info;
16881   va_list var_args;
16882   GType ptype;
16883   GValue initial = G_VALUE_INIT;
16884   GValue final = G_VALUE_INIT;
16885   char *error = NULL;
16886
16887   info = _clutter_actor_get_animation_info_or_defaults (actor);
16888
16889   if (info->transitions == NULL)
16890     return;
16891
16892   clos = g_hash_table_lookup (info->transitions, pspec->name);
16893   if (clos == NULL)
16894     return;
16895
16896   va_start (var_args, pspec);
16897
16898   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16899
16900   g_value_init (&initial, ptype);
16901   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
16902                                         pspec->name,
16903                                         &initial);
16904
16905   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
16906   if (error != NULL)
16907     {
16908       g_critical ("%s: %s", G_STRLOC, error);
16909       g_free (error);
16910       goto out;
16911     }
16912
16913   interval = clutter_transition_get_interval (clos->transition);
16914   clutter_interval_set_initial_value (interval, &initial);
16915   clutter_interval_set_final_value (interval, &final);
16916
16917   clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
16918
16919 out:
16920   g_value_unset (&initial);
16921   g_value_unset (&final);
16922
16923   va_end (var_args);
16924 }
16925
16926 /*< private >*
16927  * _clutter_actor_create_transition:
16928  * @actor: a #ClutterActor
16929  * @pspec: the property used for the transition
16930  * @...: initial and final state
16931  *
16932  * Creates a #ClutterTransition for the property represented by @pspec.
16933  *
16934  * Return value: a #ClutterTransition
16935  */
16936 ClutterTransition *
16937 _clutter_actor_create_transition (ClutterActor *actor,
16938                                   GParamSpec   *pspec,
16939                                   ...)
16940 {
16941   ClutterAnimationInfo *info;
16942   ClutterTransition *res = NULL;
16943   gboolean call_restore = FALSE;
16944   TransitionClosure *clos;
16945   va_list var_args;
16946
16947   info = _clutter_actor_get_animation_info (actor);
16948
16949   if (info->states == NULL)
16950     {
16951       clutter_actor_save_easing_state (actor);
16952       call_restore = TRUE;
16953     }
16954
16955   if (info->transitions == NULL)
16956     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
16957                                                NULL,
16958                                                transition_closure_free);
16959
16960   va_start (var_args, pspec);
16961
16962   clos = g_hash_table_lookup (info->transitions, pspec->name);
16963   if (clos == NULL)
16964     {
16965       ClutterInterval *interval;
16966       GValue initial = G_VALUE_INIT;
16967       GValue final = G_VALUE_INIT;
16968       GType ptype;
16969       char *error;
16970
16971       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16972
16973       G_VALUE_COLLECT_INIT (&initial, ptype,
16974                             var_args, 0,
16975                             &error);
16976       if (error != NULL)
16977         {
16978           g_critical ("%s: %s", G_STRLOC, error);
16979           g_free (error);
16980           goto out;
16981         }
16982
16983       G_VALUE_COLLECT_INIT (&final, ptype,
16984                             var_args, 0,
16985                             &error);
16986
16987       if (error != NULL)
16988         {
16989           g_critical ("%s: %s", G_STRLOC, error);
16990           g_value_unset (&initial);
16991           g_free (error);
16992           goto out;
16993         }
16994
16995       interval = clutter_interval_new_with_values (ptype, &initial, &final);
16996
16997       g_value_unset (&initial);
16998       g_value_unset (&final);
16999
17000       res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
17001                                              pspec->name);
17002
17003       clutter_transition_set_interval (res, interval);
17004       clutter_transition_set_remove_on_complete (res, TRUE);
17005
17006       clutter_actor_add_transition (actor, pspec->name, res);
17007     }
17008   else
17009     res = clos->transition;
17010
17011 out:
17012   if (call_restore)
17013     clutter_actor_restore_easing_state (actor);
17014
17015   va_end (var_args);
17016
17017   return res;
17018 }
17019
17020 /**
17021  * clutter_actor_add_transition:
17022  * @self: a #ClutterActor
17023  * @name: the name of the transition to add
17024  * @transition: the #ClutterTransition to add
17025  *
17026  * Adds a @transition to the #ClutterActor's list of animations.
17027  *
17028  * The @name string is a per-actor unique identifier of the @transition: only
17029  * one #ClutterTransition can be associated to the specified @name.
17030  *
17031  * The @transition will be given the easing duration, mode, and delay
17032  * associated to the actor's current easing state; it is possible to modify
17033  * these values after calling clutter_actor_add_transition().
17034  *
17035  * This function is usually called implicitly when modifying an animatable
17036  * property.
17037  *
17038  * Since: 1.10
17039  */
17040 void
17041 clutter_actor_add_transition (ClutterActor      *self,
17042                               const char        *name,
17043                               ClutterTransition *transition)
17044 {
17045   ClutterTimeline *timeline;
17046   TransitionClosure *clos;
17047   ClutterAnimationInfo *info;
17048
17049   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17050   g_return_if_fail (name != NULL);
17051   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17052
17053   info = _clutter_actor_get_animation_info (self);
17054
17055   if (info->cur_state == NULL)
17056     {
17057       g_warning ("No easing state is defined for the actor '%s'; you "
17058                  "must call clutter_actor_save_easing_state() before "
17059                  "calling clutter_actor_add_transition().",
17060                  _clutter_actor_get_debug_name (self));
17061       return;
17062     }
17063
17064   if (info->transitions == NULL)
17065     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17066                                                NULL,
17067                                                transition_closure_free);
17068
17069   if (g_hash_table_lookup (info->transitions, name) != NULL)
17070     {
17071       g_warning ("A transition with name '%s' already exists for "
17072                  "the actor '%s'",
17073                  name,
17074                  _clutter_actor_get_debug_name (self));
17075       return;
17076     }
17077
17078   timeline = CLUTTER_TIMELINE (transition);
17079
17080   clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17081   clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17082   clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17083
17084   clos = g_slice_new (TransitionClosure);
17085   clos->actor = self;
17086   clos->transition = transition;
17087   clos->name = g_strdup (name);
17088   clos->completed_id = g_signal_connect (timeline, "completed",
17089                                          G_CALLBACK (on_transition_completed),
17090                                          clos);
17091
17092   g_hash_table_insert (info->transitions, clos->name, clos);
17093 }
17094
17095 /**
17096  * clutter_actor_remove_transition:
17097  * @self: a #ClutterActor
17098  * @name: the name of the transition to remove
17099  *
17100  * Removes the transition stored inside a #ClutterActor using @name
17101  * identifier.
17102  *
17103  * Since: 1.10
17104  */
17105 void
17106 clutter_actor_remove_transition (ClutterActor *self,
17107                                  const char   *name)
17108 {
17109   const ClutterAnimationInfo *info;
17110
17111   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17112   g_return_if_fail (name != NULL);
17113
17114   info = _clutter_actor_get_animation_info_or_defaults (self);
17115
17116   if (info->transitions == NULL)
17117     return;
17118
17119   g_hash_table_remove (info->transitions, name);
17120 }
17121
17122 /**
17123  * clutter_actor_remove_all_transitions:
17124  * @self: a #ClutterActor
17125  *
17126  * Removes all transitions associated to @self.
17127  *
17128  * Since: 1.10
17129  */
17130 void
17131 clutter_actor_remove_all_transitions (ClutterActor *self)
17132 {
17133   const ClutterAnimationInfo *info;
17134
17135   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17136
17137   info = _clutter_actor_get_animation_info_or_defaults (self);
17138   if (info->transitions == NULL)
17139     return;
17140
17141   g_hash_table_remove_all (info->transitions);
17142 }
17143
17144 /**
17145  * clutter_actor_set_easing_duration:
17146  * @self: a #ClutterActor
17147  * @msecs: the duration of the easing, or %NULL
17148  *
17149  * Sets the duration of the tweening for animatable properties
17150  * of @self for the current easing state.
17151  *
17152  * Calling this function will implicitly call
17153  * clutter_actor_save_easing_state() if no previous call to
17154  * that function was made.
17155  *
17156  * Since: 1.10
17157  */
17158 void
17159 clutter_actor_set_easing_duration (ClutterActor *self,
17160                                    guint         msecs)
17161 {
17162   ClutterAnimationInfo *info;
17163
17164   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17165
17166   info = _clutter_actor_get_animation_info (self);
17167
17168   if (info->states == NULL)
17169     clutter_actor_save_easing_state (self);
17170
17171   if (info->cur_state->easing_duration != msecs)
17172     info->cur_state->easing_duration = msecs;
17173 }
17174
17175 /**
17176  * clutter_actor_get_easing_duration:
17177  * @self: a #ClutterActor
17178  *
17179  * Retrieves the duration of the tweening for animatable
17180  * properties of @self for the current easing state.
17181  *
17182  * Return value: the duration of the tweening, in milliseconds
17183  *
17184  * Since: 1.10
17185  */
17186 guint
17187 clutter_actor_get_easing_duration (ClutterActor *self)
17188 {
17189   const ClutterAnimationInfo *info;
17190
17191   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17192
17193   info = _clutter_actor_get_animation_info_or_defaults (self);
17194
17195   if (info->cur_state != NULL)
17196     return info->cur_state->easing_duration;
17197
17198   return 0;
17199 }
17200
17201 /**
17202  * clutter_actor_set_easing_mode:
17203  * @self: a #ClutterActor
17204  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17205  *
17206  * Sets the easing mode for the tweening of animatable properties
17207  * of @self.
17208  *
17209  * Calling this function will implicitly call
17210  * clutter_actor_save_easing_state() if no previous calls to
17211  * that function were made.
17212  *
17213  * Since: 1.10
17214  */
17215 void
17216 clutter_actor_set_easing_mode (ClutterActor         *self,
17217                                ClutterAnimationMode  mode)
17218 {
17219   ClutterAnimationInfo *info;
17220
17221   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17222   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17223   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17224
17225   info = _clutter_actor_get_animation_info (self);
17226
17227   if (info->states == NULL)
17228     clutter_actor_save_easing_state (self);
17229
17230   if (info->cur_state->easing_mode != mode)
17231     info->cur_state->easing_mode = mode;
17232 }
17233
17234 /**
17235  * clutter_actor_get_easing_mode:
17236  * @self: a #ClutterActor
17237  *
17238  * Retrieves the easing mode for the tweening of animatable properties
17239  * of @self for the current easing state.
17240  *
17241  * Return value: an easing mode
17242  *
17243  * Since: 1.10
17244  */
17245 ClutterAnimationMode
17246 clutter_actor_get_easing_mode (ClutterActor *self)
17247 {
17248   const ClutterAnimationInfo *info;
17249
17250   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17251
17252   info = _clutter_actor_get_animation_info_or_defaults (self);
17253
17254   if (info->cur_state != NULL)
17255     return info->cur_state->easing_mode;
17256
17257   return CLUTTER_EASE_OUT_CUBIC;
17258 }
17259
17260 /**
17261  * clutter_actor_set_easing_delay:
17262  * @self: a #ClutterActor
17263  * @msecs: the delay before the start of the tweening, in milliseconds
17264  *
17265  * Sets the delay that should be applied before tweening animatable
17266  * properties.
17267  *
17268  * Calling this function will implicitly call
17269  * clutter_actor_save_easing_state() if no previous calls to
17270  * that function were made.
17271  *
17272  * Since: 1.10
17273  */
17274 void
17275 clutter_actor_set_easing_delay (ClutterActor *self,
17276                                 guint         msecs)
17277 {
17278   ClutterAnimationInfo *info;
17279
17280   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17281
17282   info = _clutter_actor_get_animation_info (self);
17283
17284   if (info->states == NULL)
17285     clutter_actor_save_easing_state (self);
17286
17287   if (info->cur_state->easing_delay != msecs)
17288     info->cur_state->easing_delay = msecs;
17289 }
17290
17291 /**
17292  * clutter_actor_get_easing_delay:
17293  * @self: a #ClutterActor
17294  *
17295  * Retrieves the delay that should be applied when tweening animatable
17296  * properties.
17297  *
17298  * Return value: a delay, in milliseconds
17299  *
17300  * Since: 1.10
17301  */
17302 guint
17303 clutter_actor_get_easing_delay (ClutterActor *self)
17304 {
17305   const ClutterAnimationInfo *info;
17306
17307   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17308
17309   info = _clutter_actor_get_animation_info_or_defaults (self);
17310
17311   if (info->cur_state != NULL)
17312     return info->cur_state->easing_delay;
17313
17314   return 0;
17315 }
17316
17317 /**
17318  * clutter_actor_get_transition:
17319  * @self: a #ClutterActor
17320  * @name: the name of the transition
17321  *
17322  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17323  * transition @name.
17324  *
17325  * Transitions created for animatable properties use the name of the
17326  * property itself, for instance the code below:
17327  *
17328  * |[
17329  *   clutter_actor_set_easing_duration (actor, 1000);
17330  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17331  *
17332  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17333  *   g_signal_connect (transition, "completed",
17334  *                     G_CALLBACK (on_transition_complete),
17335  *                     actor);
17336  * ]|
17337  *
17338  * will call the <function>on_transition_complete</function> callback when
17339  * the transition is complete.
17340  *
17341  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17342  *   was found to match the passed name; the returned instance is owned
17343  *   by Clutter and it should not be freed
17344  *
17345  * Since: 1.10
17346  */
17347 ClutterTransition *
17348 clutter_actor_get_transition (ClutterActor *self,
17349                               const char   *name)
17350 {
17351   TransitionClosure *clos;
17352   const ClutterAnimationInfo *info;
17353
17354   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17355   g_return_val_if_fail (name != NULL, NULL);
17356
17357   info = _clutter_actor_get_animation_info_or_defaults (self);
17358
17359   if (info->transitions == NULL)
17360     return NULL;
17361
17362   clos = g_hash_table_lookup (info->transitions, name);
17363   if (clos == NULL)
17364     return NULL;
17365
17366   return clos->transition;
17367 }
17368
17369 /**
17370  * clutter_actor_save_easing_state:
17371  * @self: a #ClutterActor
17372  *
17373  * Saves the current easing state for animatable properties, and creates
17374  * a new state with the default values for easing mode and duration.
17375  *
17376  * Since: 1.10
17377  */
17378 void
17379 clutter_actor_save_easing_state (ClutterActor *self)
17380 {
17381   ClutterAnimationInfo *info;
17382   AState new_state;
17383
17384   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17385
17386   info = _clutter_actor_get_animation_info (self);
17387
17388   if (info->states == NULL)
17389     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17390
17391   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17392   new_state.easing_duration = 250;
17393   new_state.easing_delay = 0;
17394
17395   g_array_append_val (info->states, new_state);
17396
17397   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17398 }
17399
17400 /**
17401  * clutter_actor_restore_easing_state:
17402  * @self: a #ClutterActor
17403  *
17404  * Restores the easing state as it was prior to a call to
17405  * clutter_actor_save_easing_state().
17406  *
17407  * Since: 1.10
17408  */
17409 void
17410 clutter_actor_restore_easing_state (ClutterActor *self)
17411 {
17412   ClutterAnimationInfo *info;
17413
17414   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17415
17416   info = _clutter_actor_get_animation_info (self);
17417
17418   if (info->states == NULL)
17419     {
17420       g_critical ("The function clutter_actor_restore_easing_state() has "
17421                   "called without a previous call to "
17422                   "clutter_actor_save_easing_state().");
17423       return;
17424     }
17425
17426   g_array_remove_index (info->states, info->states->len - 1);
17427   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17428 }
17429
17430 /**
17431  * clutter_actor_set_content:
17432  * @self: a #ClutterActor
17433  * @content: (allow-none): a #ClutterContent, or %NULL
17434  *
17435  * Sets the contents of a #ClutterActor.
17436  *
17437  * Since: 1.10
17438  */
17439 void
17440 clutter_actor_set_content (ClutterActor   *self,
17441                            ClutterContent *content)
17442 {
17443   ClutterActorPrivate *priv;
17444
17445   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17446   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17447
17448   priv = self->priv;
17449
17450   if (priv->content != NULL)
17451     {
17452       _clutter_content_detached (priv->content, self);
17453       g_object_unref (priv->content);
17454     }
17455
17456   priv->content = content;
17457
17458   if (priv->content != NULL)
17459     {
17460       g_object_ref (priv->content);
17461       _clutter_content_attached (priv->content, self);
17462     }
17463
17464   /* given that the content is always painted within the allocation,
17465    * we only need to queue a redraw here
17466    */
17467   clutter_actor_queue_redraw (self);
17468
17469   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17470
17471   /* if the content gravity is not resize-fill, and the new content has a
17472    * different preferred size than the previous one, then the content box
17473    * may have been changed. since we compute that lazily, we just notify
17474    * here, and let whomever watches :content-box do whatever they need to
17475    * do.
17476    */
17477   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17478     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17479 }
17480
17481 /**
17482  * clutter_actor_get_content:
17483  * @self: a #ClutterActor
17484  *
17485  * Retrieves the contents of @self.
17486  *
17487  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17488  *   or %NULL if none was set
17489  *
17490  * Since: 1.10
17491  */
17492 ClutterContent *
17493 clutter_actor_get_content (ClutterActor *self)
17494 {
17495   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17496
17497   return self->priv->content;
17498 }
17499
17500 /**
17501  * clutter_actor_set_content_gravity:
17502  * @self: a #ClutterActor
17503  * @gravity: the #ClutterContentGravity
17504  *
17505  * Sets the gravity of the #ClutterContent used by @self.
17506  *
17507  * See the description of the #ClutterActor:content-gravity property for
17508  * more information.
17509  *
17510  * Since: 1.10
17511  */
17512 void
17513 clutter_actor_set_content_gravity (ClutterActor *self,
17514                                    ClutterContentGravity  gravity)
17515 {
17516   ClutterActorPrivate *priv;
17517
17518   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17519
17520   priv = self->priv;
17521
17522   if (priv->content_gravity == gravity)
17523     return;
17524
17525   priv->content_gravity = gravity;
17526
17527   clutter_actor_queue_redraw (self);
17528
17529   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17530   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17531 }
17532
17533 /**
17534  * clutter_actor_get_content_gravity:
17535  * @self: a #ClutterActor
17536  *
17537  * Retrieves the content gravity as set using
17538  * clutter_actor_get_content_gravity().
17539  *
17540  * Return value: the content gravity
17541  *
17542  * Since: 1.10
17543  */
17544 ClutterContentGravity
17545 clutter_actor_get_content_gravity (ClutterActor *self)
17546 {
17547   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17548                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17549
17550   return self->priv->content_gravity;
17551 }
17552
17553 /**
17554  * clutter_actor_get_content_box:
17555  * @self: a #ClutterActor
17556  * @box: (out caller-allocates): the return location for the bounding
17557  *   box for the #ClutterContent
17558  *
17559  * Retrieves the bounding box for the #ClutterContent of @self.
17560  *
17561  * If no #ClutterContent is set for @self, or if @self has not been
17562  * allocated yet, then the result is undefined.
17563  *
17564  * The content box is guaranteed to be, at most, as big as the allocation
17565  * of the #ClutterActor.
17566  *
17567  * If the #ClutterContent used by the actor has a preferred size, then
17568  * it is possible to modify the content box by using the
17569  * #ClutterActor:content-gravity property.
17570  *
17571  * Since: 1.10
17572  */
17573 void
17574 clutter_actor_get_content_box (ClutterActor    *self,
17575                                ClutterActorBox *box)
17576 {
17577   ClutterActorPrivate *priv;
17578   gfloat content_w, content_h;
17579   gfloat alloc_w, alloc_h;
17580
17581   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17582   g_return_if_fail (box != NULL);
17583
17584   priv = self->priv;
17585
17586   if (!clutter_actor_has_allocation (self))
17587     return;
17588
17589   if (priv->content == NULL)
17590     return;
17591
17592   *box = priv->allocation;
17593
17594   /* no need to do any more work */
17595   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17596     return;
17597
17598   /* if the content does not have a preferred size then there is
17599    * no point in computing the content box
17600    */
17601   if (!_clutter_content_get_preferred_size (priv->content,
17602                                             &content_w,
17603                                             &content_h))
17604     return;
17605
17606   clutter_actor_box_get_size (&priv->allocation, &alloc_w, &alloc_h);
17607
17608   switch (priv->content_gravity)
17609     {
17610     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17611       box->x2 = box->x1 + MIN (content_w, alloc_w);
17612       box->y2 = box->y1 + MIN (content_h, alloc_h);
17613       break;
17614
17615     case CLUTTER_CONTENT_GRAVITY_TOP:
17616       if (alloc_w > content_w)
17617         {
17618           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17619           box->x2 = box->x1 + content_w;
17620         }
17621       box->y2 = box->y1 + MIN (content_h, alloc_h);
17622       break;
17623
17624     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17625       if (alloc_w > content_w)
17626         {
17627           box->x1 += (alloc_w - content_w);
17628           box->x2 = box->x1 + content_w;
17629         }
17630       box->y2 = box->y1 + MIN (content_h, alloc_h);
17631       break;
17632
17633     case CLUTTER_CONTENT_GRAVITY_LEFT:
17634       box->x2 = box->x1 + MIN (content_w, alloc_w);
17635       if (alloc_h > content_h)
17636         {
17637           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17638           box->y2 = box->y1 + content_h;
17639         }
17640       break;
17641
17642     case CLUTTER_CONTENT_GRAVITY_CENTER:
17643       if (alloc_w > content_w)
17644         {
17645           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17646           box->x2 = box->x1 + content_w;
17647         }
17648       if (alloc_h > content_h)
17649         {
17650           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17651           box->y2 = box->y1 + content_h;
17652         }
17653       break;
17654
17655     case CLUTTER_CONTENT_GRAVITY_RIGHT:
17656       if (alloc_w > content_w)
17657         {
17658           box->x1 += (alloc_w - content_w);
17659           box->x2 = box->x1 + content_w;
17660         }
17661       if (alloc_h > content_h)
17662         {
17663           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17664           box->y2 = box->y1 + content_h;
17665         }
17666       break;
17667
17668     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17669       box->x2 = box->x1 + MIN (content_w, alloc_w);
17670       if (alloc_h > content_h)
17671         {
17672           box->y1 += (alloc_h - content_h);
17673           box->y2 = box->y1 + content_h;
17674         }
17675       break;
17676
17677     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17678       if (alloc_w > content_w)
17679         {
17680           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17681           box->x2 = box->x1 + content_w;
17682         }
17683       if (alloc_h > content_h)
17684         {
17685           box->y1 += (alloc_h - content_h);
17686           box->y2 = box->y1 + content_h;
17687         }
17688       break;
17689
17690     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17691       if (alloc_w > content_w)
17692         {
17693           box->x1 += (alloc_w - content_w);
17694           box->x2 = box->x1 + content_w;
17695         }
17696       if (alloc_h > content_h)
17697         {
17698           box->y1 += (alloc_h - content_h);
17699           box->y2 = box->y1 + content_h;
17700         }
17701       break;
17702
17703     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17704       g_assert_not_reached ();
17705       break;
17706
17707     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17708       if (content_w >= content_h && content_h > 0)
17709         {
17710           double ratio = content_w / content_h;
17711
17712           box->x2 = box->x1 + alloc_w;
17713
17714           box->y1 += ceilf ((alloc_h - (alloc_h / ratio)) / 2.0);
17715           box->y2 = box->y1 + (alloc_h / ratio);
17716         }
17717       else if (content_h > content_w && content_w > 0)
17718         {
17719           double ratio = content_h / content_w;
17720
17721           box->x1 += ceilf ((alloc_w - (alloc_w / ratio)) / 2.0);
17722           box->x2 = box->x2 + (alloc_w / ratio);
17723
17724           box->y2 = box->x1 + alloc_h;
17725         }
17726       break;
17727     }
17728 }