actor: Fix RESIZE_ASPECT mode for the content box
[profile/ivi/clutter.git] / clutter / clutter-actor.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9  * Copyright (C) 2009, 2010, 2011, 2012 Intel Corp
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /**
26  * SECTION:clutter-actor
27  * @short_description: Base abstract class for all visual stage actors.
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="actor-example-image">
113  *     <title>Actors</title>
114  *     <graphic fileref="actor-example.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-painting">
119  *   <title>Painting an actor</title>
120  *   <para>There are three ways to paint an actor:</para>
121  *   <itemizedlist>
122  *     <listitem><para>set a delegate #ClutterContent as the value for the
123  *     #ClutterActor:content property of the actor;</para></listitem>
124  *     <listitem><para>subclass #ClutterActor and override the
125  *     #ClutterActorClass.paint_node() virtual function;</para></listitem>
126  *     <listitem><para>subclass #ClutterActor and override the
127  *     #ClutterActorClass.paint() virtual function.</para></listitem>
128  *   </itemizedlist>
129  *   <formalpara>
130  *     <title>Setting the Content property</title>
131  *     <para>A #ClutterContent is a delegate object that takes over the
132  *     painting operation of one, or more actors. The #ClutterContent
133  *     painting will be performed on top of the #ClutterActor:background-color
134  *     of the actor, and before calling the #ClutterActorClass.paint_node()
135  *     virtual function.</para>
136  *     <informalexample><programlisting>
137  * ClutterActor *actor = clutter_actor_new ();
138  *
139  * /&ast; set the bounding box &ast;/
140  * clutter_actor_set_position (actor, 50, 50);
141  * clutter_actor_set_size (actor, 100, 100);
142  *
143  * /&ast; set the content; the image_content variable is set elsewhere &ast;/
144  * clutter_actor_set_content (actor, image_content);
145  *     </programlisting></informalexample>
146  *   </formalpara>
147  *   <formalpara>
148  *     <title>Overriding the paint_node virtual function</title>
149  *     <para>The #ClutterActorClass.paint_node() virtual function is invoked
150  *     whenever an actor needs to be painted. The implementation of the
151  *     virtual function must only paint the contents of the actor itself,
152  *     and not the contents of its children, if the actor has any.</para>
153  *     <para>The #ClutterPaintNode passed to the virtual function is the
154  *     local root of the render tree; any node added to it will be
155  *     rendered at the correct position, as defined by the actor's
156  *     #ClutterActor:allocation.</para>
157  *     <informalexample><programlisting>
158  * static void
159  * my_actor_paint_node (ClutterActor     *actor,
160  *                      ClutterPaintNode *root)
161  * {
162  *   ClutterPaintNode *node;
163  *   ClutterActorBox box;
164  *
165  *   /&ast; where the content of the actor should be painted &ast;/
166  *   clutter_actor_get_allocation_box (actor, &box);
167  *
168  *   /&ast; the cogl_texture variable is set elsewhere &ast;/
169  *   node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White,
170  *                                    CLUTTER_SCALING_FILTER_BILINEAR,
171  *                                    CLUTTER_SCALING_FILTER_LINEAR);
172  *
173  *   /&ast; paint the content of the node using the allocation &ast;/
174  *   clutter_paint_node_add_rectangle (node, &box);
175  *
176  *   /&ast; add the node, and transfer ownership &ast;/
177  *   clutter_paint_node_add_child (root, node);
178  *   clutter_paint_node_unref (node);
179  * }
180  *     </programlisting></informalexample>
181  *   </formalpara>
182  *   <formalpara>
183  *     <title>Overriding the paint virtual function</title>
184  *     <para>The #ClutterActorClass.paint() virtual function is invoked
185  *     when the #ClutterActor::paint signal is emitted, and after the other
186  *     signal handlers have been invoked. Overriding the paint virtual
187  *     function gives total control to the paint sequence of the actor
188  *     itself, including the children of the actor, if any.</para>
189  *     <warning><para>It is strongly discouraged to override the
190  *     #ClutterActorClass.paint() virtual function, as well as connecting
191  *     to the #ClutterActor::paint signal. These hooks into the paint
192  *     sequence are considered legacy, and will be removed when the Clutter
193  *     API changes.</para></warning>
194  *   </formalpara>
195  * </refsect2>
196  *
197  * <refsect2 id="ClutterActor-events">
198  *   <title>Handling events on an actor</title>
199  *   <para>A #ClutterActor can receive and handle input device events, for
200  *   instance pointer events and key events, as long as its
201  *   #ClutterActor:reactive property is set to %TRUE.</para>
202  *   <para>Once an actor has been determined to be the source of an event,
203  *   Clutter will traverse the scene graph from the top-level actor towards the
204  *   event source, emitting the #ClutterActor::captured-event signal on each
205  *   ancestor until it reaches the source; this phase is also called
206  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
207  *   stopped, the graph is walked backwards, from the source actor to the
208  *   top-level, and the #ClutterActor::event signal, along with other event
209  *   signals if needed, is emitted; this phase is also called <emphasis>the
210  *   bubble phase</emphasis>. At any point of the signal emission, signal
211  *   handlers can stop the propagation through the scene graph by returning
212  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
213  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
214  * </refsect2>
215  *
216  * <refsect2 id="ClutterActor-subclassing">
217  *   <title>Implementing an actor</title>
218  *   <para>Careful consideration should be given when deciding to implement
219  *   a #ClutterActor sub-class. It is generally recommended to implement a
220  *   sub-class of #ClutterActor only for actors that should be used as leaf
221  *   nodes of a scene graph.</para>
222  *   <para>If your actor should be painted in a custom way, you should
223  *   override the #ClutterActor::paint signal class handler. You can either
224  *   opt to chain up to the parent class implementation or decide to fully
225  *   override the default paint implementation; Clutter will set up the
226  *   transformations and clip regions prior to emitting the #ClutterActor::paint
227  *   signal.</para>
228  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
229  *   #ClutterActorClass.get_preferred_height() virtual functions it is
230  *   possible to change or provide the preferred size of an actor; similarly,
231  *   by overriding the #ClutterActorClass.allocate() virtual function it is
232  *   possible to control the layout of the children of an actor. Make sure to
233  *   always chain up to the parent implementation of the
234  *   #ClutterActorClass.allocate() virtual function.</para>
235  *   <para>In general, it is strongly encouraged to use delegation and
236  *   composition instead of direct subclassing.</para>
237  * </refsect2>
238  *
239  * <refsect2 id="ClutterActor-script">
240  *   <title>ClutterActor custom properties for #ClutterScript</title>
241  *   <para>#ClutterActor defines a custom "rotation" property which
242  *   allows a short-hand description of the rotations to be applied
243  *   to an actor.</para>
244  *   <para>The syntax of the "rotation" property is the following:</para>
245  *   <informalexample>
246  *     <programlisting>
247  * "rotation" : [
248  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
249  * ]
250  *     </programlisting>
251  *   </informalexample>
252  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
253  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
254  *   floating point value representing the rotation angle on the given axis,
255  *   in degrees.</para>
256  *   <para>The <emphasis>center</emphasis> array is optional, and if present
257  *   it must contain the center of rotation as described by two coordinates:
258  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
259  *   "z-axis".</para>
260  *   <para>#ClutterActor will also parse every positional and dimensional
261  *   property defined as a string through clutter_units_from_string(); you
262  *   should read the documentation for the #ClutterUnits parser format for
263  *   the valid units and syntax.</para>
264  * </refsect2>
265  *
266  * <refsect2 id="ClutterActor-animating">
267  *   <title>Custom animatable properties</title>
268  *   <para>#ClutterActor allows accessing properties of #ClutterAction
269  *   and #ClutterConstraint instances associated to an actor instance
270  *   for animation purposes.</para>
271  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
272  *   property it is necessary to set the #ClutterActorMeta:name property on the
273  *   given action or constraint.</para>
274  *   <para>The property can be accessed using the following syntax:</para>
275  *   <informalexample>
276  *     <programlisting>
277  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
278  *     </programlisting>
279  *   </informalexample>
280  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
281  *   <para>The <emphasis>section</emphasis> fragment can be one between
282  *   "actions", "constraints" and "effects".</para>
283  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
284  *   action or constraint, as specified by the #ClutterActorMeta:name
285  *   property.</para>
286  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
287  *   action or constraint property to be animated.</para>
288  *   <para>The example below animates a #ClutterBindConstraint applied to an
289  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
290  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
291  *   its initial state is fully transparent and overlapping the actor to
292  *   which is bound to. </para>
293  *   <informalexample><programlisting>
294  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
295  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
296  * clutter_actor_add_constraint (rect, constraint);
297  *
298  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
299  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
300  * clutter_actor_add_constraint (rect, constraint);
301  *
302  * clutter_actor_set_reactive (rect, TRUE);
303  * clutter_actor_set_opacity (rect, 0);
304  *
305  * g_signal_connect (rect, "button-press-event",
306  *                   G_CALLBACK (on_button_press),
307  *                   NULL);
308  *   </programlisting></informalexample>
309  *   <para>On button press, the rectangle "slides" from behind the actor to
310  *   which is bound to, using the #ClutterBindConstraint:offset property and
311  *   the #ClutterActor:opacity property.</para>
312  *   <informalexample><programlisting>
313  * float new_offset = clutter_actor_get_width (origin) + h_padding;
314  *
315  * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
316  *                        "opacity", 255,
317  *                        "@constraints.bind-x.offset", new_offset,
318  *                        NULL);
319  *   </programlisting></informalexample>
320  * </refsect2>
321  *
322  * <refsect2 id="ClutterActor-animatable-properties">
323  *   <title>Animatable properties</title>
324  *   <para>Certain properties on #ClutterActor are marked as "animatable";
325  *   these properties will be automatically tweened between the current
326  *   value and the new value when one is set.</para>
327  *   <para>For backward compatibility, animatable properties will only be
328  *   tweened if the easing duration is greater than 0, or if a new easing
329  *   state is set, for instance the following example:</para>
330  *   <informalexample><programlisting>
331  * clutter_actor_save_easing_state (actor);
332  * clutter_actor_set_position (actor, 200, 200);
333  * clutter_actor_restore_easing_state (actor);
334  *   </programlisting></informalexample>
335  *   <para>will tween the actor to the (200, 200) coordinates using the default
336  *   easing mode and duration of a new easing state. The example above is
337  *   equivalent to the following code:</para>
338  *   <informalexample><programlisting>
339  * clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC);
340  * clutter_actor_set_easing_duration (actor, 250);
341  * clutter_actor_set_position (actor, 200, 200);
342  * clutter_actor_restore_easing_state (actor);
343  *   </programlisting></informalexample>
344  *   <para>It is possible to nest easing states to tween animatable
345  *   properties using different modes and durations, for instance:</para>
346  *   <informalexample><programlisting>
347  * clutter_actor_save_easing_state (actor); /&ast; outer state &ast;/
348  *
349  * /&ast; set the duration of the animation to 2 seconds and change position &ast;/
350  * clutter_actor_set_easing_duration (actor, 2000);
351  * clutter_actor_set_position (actor, 0, 0);
352  *
353  * clutter_actor_save_easing_state (actor); /&ast; inner state &ast;/
354  *
355  * /&ast; set the duration of the animation to 5 seconds and change depth and opacity &ast;/
356  * clutter_actor_set_easing_duration (actor, 5000);
357  * clutter_actor_set_depth (actor, 200);
358  * clutter_actor_set_opacity (actor, 0);
359  *
360  * clutter_actor_restore_easing_state (actor);
361  *
362  * clutter_actor_restore_easing_state (actor);
363  *   </programlisting></informalexample>
364  * </refsect2>
365  */
366
367 /**
368  * CLUTTER_ACTOR_IS_MAPPED:
369  * @a: a #ClutterActor
370  *
371  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
372  *
373  * The mapped state is set when the actor is visible and all its parents up
374  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
375  *
376  * This check can be used to see if an actor is going to be painted, as only
377  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
378  *
379  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
380  * not be checked directly; instead, the recommended usage is to connect a
381  * handler on the #GObject::notify signal for the #ClutterActor:mapped
382  * property of #ClutterActor, and check the presence of
383  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
384  *
385  * It is also important to note that Clutter may delay the changes of
386  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
387  * limitations, or during the reparenting of an actor, to optimize
388  * unnecessary (and potentially expensive) state changes.
389  *
390  * Since: 0.2
391  */
392
393 /**
394  * CLUTTER_ACTOR_IS_REALIZED:
395  * @a: a #ClutterActor
396  *
397  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
398  *
399  * The realized state has an actor-dependant interpretation. If an
400  * actor wants to delay allocating resources until it is attached to a
401  * stage, it may use the realize state to do so. However it is
402  * perfectly acceptable for an actor to allocate Cogl resources before
403  * being realized because there is only one drawing context used by Clutter
404  * so any resources will work on any stage.  If an actor is mapped it
405  * must also be realized, but an actor can be realized and unmapped
406  * (this is so hiding an actor temporarily doesn't do an expensive
407  * unrealize/realize).
408  *
409  * To be realized an actor must be inside a stage, and all its parents
410  * must be realized.
411  *
412  * Since: 0.2
413  */
414
415 /**
416  * CLUTTER_ACTOR_IS_VISIBLE:
417  * @a: a #ClutterActor
418  *
419  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
420  * Equivalent to the ClutterActor::visible object property.
421  *
422  * Note that an actor is only painted onscreen if it's mapped, which
423  * means it's visible, and all its parents are visible, and one of the
424  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
425  *
426  * Since: 0.2
427  */
428
429 /**
430  * CLUTTER_ACTOR_IS_REACTIVE:
431  * @a: a #ClutterActor
432  *
433  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
434  *
435  * Only reactive actors will receive event-related signals.
436  *
437  * Since: 0.6
438  */
439
440 #ifdef HAVE_CONFIG_H
441 #include "config.h"
442 #endif
443
444 #include <math.h>
445
446 #include <gobject/gvaluecollector.h>
447
448 #include <cogl/cogl.h>
449
450 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
451 #define CLUTTER_ENABLE_EXPERIMENTAL_API
452
453 #include "clutter-actor-private.h"
454
455 #include "clutter-action.h"
456 #include "clutter-actor-meta-private.h"
457 #include "clutter-animatable.h"
458 #include "clutter-color-static.h"
459 #include "clutter-color.h"
460 #include "clutter-constraint.h"
461 #include "clutter-container.h"
462 #include "clutter-content-private.h"
463 #include "clutter-debug.h"
464 #include "clutter-effect-private.h"
465 #include "clutter-enum-types.h"
466 #include "clutter-fixed-layout.h"
467 #include "clutter-flatten-effect.h"
468 #include "clutter-interval.h"
469 #include "clutter-main.h"
470 #include "clutter-marshal.h"
471 #include "clutter-paint-nodes.h"
472 #include "clutter-paint-node-private.h"
473 #include "clutter-paint-volume-private.h"
474 #include "clutter-private.h"
475 #include "clutter-profile.h"
476 #include "clutter-property-transition.h"
477 #include "clutter-scriptable.h"
478 #include "clutter-script-private.h"
479 #include "clutter-stage-private.h"
480 #include "clutter-timeline.h"
481 #include "clutter-transition.h"
482 #include "clutter-units.h"
483
484 #include "deprecated/clutter-actor.h"
485 #include "deprecated/clutter-behaviour.h"
486 #include "deprecated/clutter-container.h"
487
488 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
489 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
490
491 /* Internal enum used to control mapped state update.  This is a hint
492  * which indicates when to do something other than just enforce
493  * invariants.
494  */
495 typedef enum {
496   MAP_STATE_CHECK,           /* just enforce invariants. */
497   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
498                               * used when about to unparent.
499                               */
500   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
501                               * used to set mapped on toplevels.
502                               */
503   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
504                               * used just before unmapping parent.
505                               */
506 } MapStateChange;
507
508 /* 3 entries should be a good compromise, few layout managers
509  * will ask for 3 different preferred size in each allocation cycle */
510 #define N_CACHED_SIZE_REQUESTS 3
511
512 struct _ClutterActorPrivate
513 {
514   /* request mode */
515   ClutterRequestMode request_mode;
516
517   /* our cached size requests for different width / height */
518   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
519   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
520
521   /* An age of 0 means the entry is not set */
522   guint cached_height_age;
523   guint cached_width_age;
524
525   /* the bounding box of the actor, relative to the parent's
526    * allocation
527    */
528   ClutterActorBox allocation;
529   ClutterAllocationFlags allocation_flags;
530
531   /* clip, in actor coordinates */
532   cairo_rectangle_t clip;
533
534   /* the cached transformation matrix; see apply_transform() */
535   CoglMatrix transform;
536
537   guint8 opacity;
538   gint opacity_override;
539
540   ClutterOffscreenRedirect offscreen_redirect;
541
542   /* This is an internal effect used to implement the
543      offscreen-redirect property */
544   ClutterEffect *flatten_effect;
545
546   /* scene graph */
547   ClutterActor *parent;
548   ClutterActor *prev_sibling;
549   ClutterActor *next_sibling;
550   ClutterActor *first_child;
551   ClutterActor *last_child;
552
553   gint n_children;
554
555   /* tracks whenever the children of an actor are changed; the
556    * age is incremented by 1 whenever an actor is added or
557    * removed. the age is not incremented when the first or the
558    * last child pointers are changed, or when grandchildren of
559    * an actor are changed.
560    */
561   gint age;
562
563   gchar *name; /* a non-unique name, used for debugging */
564   guint32 id; /* unique id, used for backward compatibility */
565
566   gint32 pick_id; /* per-stage unique id, used for picking */
567
568   /* a back-pointer to the Pango context that we can use
569    * to create pre-configured PangoLayout
570    */
571   PangoContext *pango_context;
572
573   /* the text direction configured for this child - either by
574    * application code, or by the actor's parent
575    */
576   ClutterTextDirection text_direction;
577
578   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
579   gint internal_child;
580
581   /* meta classes */
582   ClutterMetaGroup *actions;
583   ClutterMetaGroup *constraints;
584   ClutterMetaGroup *effects;
585
586   /* delegate object used to allocate the children of this actor */
587   ClutterLayoutManager *layout_manager;
588
589   /* delegate object used to paint the contents of this actor */
590   ClutterContent *content;
591
592   ClutterContentGravity content_gravity;
593   ClutterScalingFilter min_filter;
594   ClutterScalingFilter mag_filter;
595
596   /* used when painting, to update the paint volume */
597   ClutterEffect *current_effect;
598
599   /* This is used to store an effect which needs to be redrawn. A
600      redraw can be queued to start from a particular effect. This is
601      used by parametrised effects that can cache an image of the
602      actor. If a parameter of the effect changes then it only needs to
603      redraw the cached image, not the actual actor. The pointer is
604      only valid if is_dirty == TRUE. If the pointer is NULL then the
605      whole actor is dirty. */
606   ClutterEffect *effect_to_redraw;
607
608   /* This is used when painting effects to implement the
609      clutter_actor_continue_paint() function. It points to the node in
610      the list of effects that is next in the chain */
611   const GList *next_effect_to_paint;
612
613   ClutterPaintVolume paint_volume;
614
615   /* NB: This volume isn't relative to this actor, it is in eye
616    * coordinates so that it can remain valid after the actor changes.
617    */
618   ClutterPaintVolume last_paint_volume;
619
620   ClutterStageQueueRedrawEntry *queue_redraw_entry;
621
622   ClutterColor bg_color;
623
624   /* bitfields */
625
626   /* fixed position and sizes */
627   guint position_set                : 1;
628   guint min_width_set               : 1;
629   guint min_height_set              : 1;
630   guint natural_width_set           : 1;
631   guint natural_height_set          : 1;
632   /* cached request is invalid (implies allocation is too) */
633   guint needs_width_request         : 1;
634   /* cached request is invalid (implies allocation is too) */
635   guint needs_height_request        : 1;
636   /* cached allocation is invalid (request has changed, probably) */
637   guint needs_allocation            : 1;
638   guint show_on_set_parent          : 1;
639   guint has_clip                    : 1;
640   guint clip_to_allocation          : 1;
641   guint enable_model_view_transform : 1;
642   guint enable_paint_unmapped       : 1;
643   guint has_pointer                 : 1;
644   guint propagated_one_redraw       : 1;
645   guint paint_volume_valid          : 1;
646   guint last_paint_volume_valid     : 1;
647   guint in_clone_paint              : 1;
648   guint transform_valid             : 1;
649   /* This is TRUE if anything has queued a redraw since we were last
650      painted. In this case effect_to_redraw will point to an effect
651      the redraw was queued from or it will be NULL if the redraw was
652      queued without an effect. */
653   guint is_dirty                    : 1;
654   guint bg_color_set                : 1;
655 };
656
657 enum
658 {
659   PROP_0,
660
661   PROP_NAME,
662
663   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
664    * when set they force a size request, when gotten they
665    * get the allocation if the allocation is valid, and the
666    * request otherwise
667    */
668   PROP_X,
669   PROP_Y,
670   PROP_WIDTH,
671   PROP_HEIGHT,
672
673   /* Then the rest of these size-related properties are the "actual"
674    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
675    */
676   PROP_FIXED_X,
677   PROP_FIXED_Y,
678
679   PROP_FIXED_POSITION_SET,
680
681   PROP_MIN_WIDTH,
682   PROP_MIN_WIDTH_SET,
683
684   PROP_MIN_HEIGHT,
685   PROP_MIN_HEIGHT_SET,
686
687   PROP_NATURAL_WIDTH,
688   PROP_NATURAL_WIDTH_SET,
689
690   PROP_NATURAL_HEIGHT,
691   PROP_NATURAL_HEIGHT_SET,
692
693   PROP_REQUEST_MODE,
694
695   /* Allocation properties are read-only */
696   PROP_ALLOCATION,
697
698   PROP_DEPTH,
699
700   PROP_CLIP,
701   PROP_HAS_CLIP,
702   PROP_CLIP_TO_ALLOCATION,
703
704   PROP_OPACITY,
705
706   PROP_OFFSCREEN_REDIRECT,
707
708   PROP_VISIBLE,
709   PROP_MAPPED,
710   PROP_REALIZED,
711   PROP_REACTIVE,
712
713   PROP_SCALE_X,
714   PROP_SCALE_Y,
715   PROP_SCALE_CENTER_X,
716   PROP_SCALE_CENTER_Y,
717   PROP_SCALE_GRAVITY,
718
719   PROP_ROTATION_ANGLE_X,
720   PROP_ROTATION_ANGLE_Y,
721   PROP_ROTATION_ANGLE_Z,
722   PROP_ROTATION_CENTER_X,
723   PROP_ROTATION_CENTER_Y,
724   PROP_ROTATION_CENTER_Z,
725   /* This property only makes sense for the z rotation because the
726      others would depend on the actor having a size along the
727      z-axis */
728   PROP_ROTATION_CENTER_Z_GRAVITY,
729
730   PROP_ANCHOR_X,
731   PROP_ANCHOR_Y,
732   PROP_ANCHOR_GRAVITY,
733
734   PROP_SHOW_ON_SET_PARENT,
735
736   PROP_TEXT_DIRECTION,
737   PROP_HAS_POINTER,
738
739   PROP_ACTIONS,
740   PROP_CONSTRAINTS,
741   PROP_EFFECT,
742
743   PROP_LAYOUT_MANAGER,
744
745   PROP_X_ALIGN,
746   PROP_Y_ALIGN,
747   PROP_MARGIN_TOP,
748   PROP_MARGIN_BOTTOM,
749   PROP_MARGIN_LEFT,
750   PROP_MARGIN_RIGHT,
751
752   PROP_BACKGROUND_COLOR,
753   PROP_BACKGROUND_COLOR_SET,
754
755   PROP_FIRST_CHILD,
756   PROP_LAST_CHILD,
757
758   PROP_CONTENT,
759   PROP_CONTENT_GRAVITY,
760   PROP_CONTENT_BOX,
761   PROP_MINIFICATION_FILTER,
762   PROP_MAGNIFICATION_FILTER,
763
764   PROP_LAST
765 };
766
767 static GParamSpec *obj_props[PROP_LAST];
768
769 enum
770 {
771   SHOW,
772   HIDE,
773   DESTROY,
774   PARENT_SET,
775   KEY_FOCUS_IN,
776   KEY_FOCUS_OUT,
777   PAINT,
778   PICK,
779   REALIZE,
780   UNREALIZE,
781   QUEUE_REDRAW,
782   QUEUE_RELAYOUT,
783   EVENT,
784   CAPTURED_EVENT,
785   BUTTON_PRESS_EVENT,
786   BUTTON_RELEASE_EVENT,
787   SCROLL_EVENT,
788   KEY_PRESS_EVENT,
789   KEY_RELEASE_EVENT,
790   MOTION_EVENT,
791   ENTER_EVENT,
792   LEAVE_EVENT,
793   ALLOCATION_CHANGED,
794
795   LAST_SIGNAL
796 };
797
798 static guint actor_signals[LAST_SIGNAL] = { 0, };
799
800 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
801 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
802 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
803 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
804
805 /* These setters are all static for now, maybe they should be in the
806  * public API, but they are perhaps obscure enough to leave only as
807  * properties
808  */
809 static void clutter_actor_set_min_width          (ClutterActor *self,
810                                                   gfloat        min_width);
811 static void clutter_actor_set_min_height         (ClutterActor *self,
812                                                   gfloat        min_height);
813 static void clutter_actor_set_natural_width      (ClutterActor *self,
814                                                   gfloat        natural_width);
815 static void clutter_actor_set_natural_height     (ClutterActor *self,
816                                                   gfloat        natural_height);
817 static void clutter_actor_set_min_width_set      (ClutterActor *self,
818                                                   gboolean      use_min_width);
819 static void clutter_actor_set_min_height_set     (ClutterActor *self,
820                                                   gboolean      use_min_height);
821 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
822                                                   gboolean  use_natural_width);
823 static void clutter_actor_set_natural_height_set (ClutterActor *self,
824                                                   gboolean  use_natural_height);
825 static void clutter_actor_update_map_state       (ClutterActor  *self,
826                                                   MapStateChange change);
827 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
828
829 /* Helper routines for managing anchor coords */
830 static void clutter_anchor_coord_get_units (ClutterActor      *self,
831                                             const AnchorCoord *coord,
832                                             gfloat            *x,
833                                             gfloat            *y,
834                                             gfloat            *z);
835 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
836                                             gfloat             x,
837                                             gfloat             y,
838                                             gfloat             z);
839
840 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
841 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
842                                                         ClutterGravity     gravity);
843
844 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
845
846 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
847
848 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
849                                                                ClutterActor *ancestor,
850                                                                CoglMatrix *matrix);
851
852 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
853
854 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
855
856 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
857                                                                 const ClutterColor *color);
858
859 static void on_layout_manager_changed (ClutterLayoutManager *manager,
860                                        ClutterActor         *self);
861
862 /* Helper macro which translates by the anchor coord, applies the
863    given transformation and then translates back */
864 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
865   gfloat _tx, _ty, _tz;                                                \
866   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
867   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
868   { _transform; }                                                      \
869   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
870
871 static GQuark quark_shader_data = 0;
872 static GQuark quark_actor_layout_info = 0;
873 static GQuark quark_actor_transform_info = 0;
874 static GQuark quark_actor_animation_info = 0;
875
876 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
877                          clutter_actor,
878                          G_TYPE_INITIALLY_UNOWNED,
879                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
880                                                 clutter_container_iface_init)
881                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
882                                                 clutter_scriptable_iface_init)
883                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
884                                                 clutter_animatable_iface_init)
885                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
886                                                 atk_implementor_iface_init));
887
888 /*< private >
889  * clutter_actor_get_debug_name:
890  * @actor: a #ClutterActor
891  *
892  * Retrieves a printable name of @actor for debugging messages
893  *
894  * Return value: a string with a printable name
895  */
896 const gchar *
897 _clutter_actor_get_debug_name (ClutterActor *actor)
898 {
899   return actor->priv->name != NULL ? actor->priv->name
900                                    : G_OBJECT_TYPE_NAME (actor);
901 }
902
903 #ifdef CLUTTER_ENABLE_DEBUG
904 /* XXX - this is for debugging only, remove once working (or leave
905  * in only in some debug mode). Should leave it for a little while
906  * until we're confident in the new map/realize/visible handling.
907  */
908 static inline void
909 clutter_actor_verify_map_state (ClutterActor *self)
910 {
911   ClutterActorPrivate *priv = self->priv;
912
913   if (CLUTTER_ACTOR_IS_REALIZED (self))
914     {
915       /* all bets are off during reparent when we're potentially realized,
916        * but should not be according to invariants
917        */
918       if (!CLUTTER_ACTOR_IN_REPARENT (self))
919         {
920           if (priv->parent == NULL)
921             {
922               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
923                 {
924                 }
925               else
926                 g_warning ("Realized non-toplevel actor '%s' should "
927                            "have a parent",
928                            _clutter_actor_get_debug_name (self));
929             }
930           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
931             {
932               g_warning ("Realized actor %s has an unrealized parent %s",
933                          _clutter_actor_get_debug_name (self),
934                          _clutter_actor_get_debug_name (priv->parent));
935             }
936         }
937     }
938
939   if (CLUTTER_ACTOR_IS_MAPPED (self))
940     {
941       if (!CLUTTER_ACTOR_IS_REALIZED (self))
942         g_warning ("Actor '%s' is mapped but not realized",
943                    _clutter_actor_get_debug_name (self));
944
945       /* remaining bets are off during reparent when we're potentially
946        * mapped, but should not be according to invariants
947        */
948       if (!CLUTTER_ACTOR_IN_REPARENT (self))
949         {
950           if (priv->parent == NULL)
951             {
952               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
953                 {
954                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
955                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
956                     {
957                       g_warning ("Toplevel actor '%s' is mapped "
958                                  "but not visible",
959                                  _clutter_actor_get_debug_name (self));
960                     }
961                 }
962               else
963                 {
964                   g_warning ("Mapped actor '%s' should have a parent",
965                              _clutter_actor_get_debug_name (self));
966                 }
967             }
968           else
969             {
970               ClutterActor *iter = self;
971
972               /* check for the enable_paint_unmapped flag on the actor
973                * and parents; if the flag is enabled at any point of this
974                * branch of the scene graph then all the later checks
975                * become pointless
976                */
977               while (iter != NULL)
978                 {
979                   if (iter->priv->enable_paint_unmapped)
980                     return;
981
982                   iter = iter->priv->parent;
983                 }
984
985               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
986                 {
987                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
988                              "is not visible",
989                              _clutter_actor_get_debug_name (self),
990                              _clutter_actor_get_debug_name (priv->parent));
991                 }
992
993               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
994                 {
995                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
996                              "is not realized",
997                              _clutter_actor_get_debug_name (self),
998                              _clutter_actor_get_debug_name (priv->parent));
999                 }
1000
1001               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1002                 {
1003                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1004                     g_warning ("Actor '%s' is mapped but its non-toplevel "
1005                                "parent '%s' is not mapped",
1006                                _clutter_actor_get_debug_name (self),
1007                                _clutter_actor_get_debug_name (priv->parent));
1008                 }
1009             }
1010         }
1011     }
1012 }
1013
1014 #endif /* CLUTTER_ENABLE_DEBUG */
1015
1016 static void
1017 clutter_actor_set_mapped (ClutterActor *self,
1018                           gboolean      mapped)
1019 {
1020   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1021     return;
1022
1023   if (mapped)
1024     {
1025       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1026       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1027     }
1028   else
1029     {
1030       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1031       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1032     }
1033 }
1034
1035 /* this function updates the mapped and realized states according to
1036  * invariants, in the appropriate order.
1037  */
1038 static void
1039 clutter_actor_update_map_state (ClutterActor  *self,
1040                                 MapStateChange change)
1041 {
1042   gboolean was_mapped;
1043
1044   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1045
1046   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1047     {
1048       /* the mapped flag on top-level actors must be set by the
1049        * per-backend implementation because it might be asynchronous.
1050        *
1051        * That is, the MAPPED flag on toplevels currently tracks the X
1052        * server mapped-ness of the window, while the expected behavior
1053        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1054        * This creates some weird complexity by breaking the invariant
1055        * that if we're visible and all ancestors shown then we are
1056        * also mapped - instead, we are mapped if all ancestors
1057        * _possibly excepting_ the stage are mapped. The stage
1058        * will map/unmap for example when it is minimized or
1059        * moved to another workspace.
1060        *
1061        * So, the only invariant on the stage is that if visible it
1062        * should be realized, and that it has to be visible to be
1063        * mapped.
1064        */
1065       if (CLUTTER_ACTOR_IS_VISIBLE (self))
1066         clutter_actor_realize (self);
1067
1068       switch (change)
1069         {
1070         case MAP_STATE_CHECK:
1071           break;
1072
1073         case MAP_STATE_MAKE_MAPPED:
1074           g_assert (!was_mapped);
1075           clutter_actor_set_mapped (self, TRUE);
1076           break;
1077
1078         case MAP_STATE_MAKE_UNMAPPED:
1079           g_assert (was_mapped);
1080           clutter_actor_set_mapped (self, FALSE);
1081           break;
1082
1083         case MAP_STATE_MAKE_UNREALIZED:
1084           /* we only use MAKE_UNREALIZED in unparent,
1085            * and unparenting a stage isn't possible.
1086            * If someone wants to just unrealize a stage
1087            * then clutter_actor_unrealize() doesn't
1088            * go through this codepath.
1089            */
1090           g_warning ("Trying to force unrealize stage is not allowed");
1091           break;
1092         }
1093
1094       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1095           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1096           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1097         {
1098           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1099                      "it is somehow still mapped",
1100                      _clutter_actor_get_debug_name (self));
1101         }
1102     }
1103   else
1104     {
1105       ClutterActorPrivate *priv = self->priv;
1106       ClutterActor *parent = priv->parent;
1107       gboolean should_be_mapped;
1108       gboolean may_be_realized;
1109       gboolean must_be_realized;
1110
1111       should_be_mapped = FALSE;
1112       may_be_realized = TRUE;
1113       must_be_realized = FALSE;
1114
1115       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1116         {
1117           may_be_realized = FALSE;
1118         }
1119       else
1120         {
1121           /* Maintain invariant that if parent is mapped, and we are
1122            * visible, then we are mapped ...  unless parent is a
1123            * stage, in which case we map regardless of parent's map
1124            * state but do require stage to be visible and realized.
1125            *
1126            * If parent is realized, that does not force us to be
1127            * realized; but if parent is unrealized, that does force
1128            * us to be unrealized.
1129            *
1130            * The reason we don't force children to realize with
1131            * parents is _clutter_actor_rerealize(); if we require that
1132            * a realized parent means children are realized, then to
1133            * unrealize an actor we would have to unrealize its
1134            * parents, which would end up meaning unrealizing and
1135            * hiding the entire stage. So we allow unrealizing a
1136            * child (as long as that child is not mapped) while that
1137            * child still has a realized parent.
1138            *
1139            * Also, if we unrealize from leaf nodes to root, and
1140            * realize from root to leaf, the invariants are never
1141            * violated if we allow children to be unrealized
1142            * while parents are realized.
1143            *
1144            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1145            * to force us to unmap, even though parent is still
1146            * mapped. This is because we're unmapping from leaf nodes
1147            * up to root nodes.
1148            */
1149           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1150               change != MAP_STATE_MAKE_UNMAPPED)
1151             {
1152               gboolean parent_is_visible_realized_toplevel;
1153
1154               parent_is_visible_realized_toplevel =
1155                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1156                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1157                  CLUTTER_ACTOR_IS_REALIZED (parent));
1158
1159               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1160                   parent_is_visible_realized_toplevel)
1161                 {
1162                   must_be_realized = TRUE;
1163                   should_be_mapped = TRUE;
1164                 }
1165             }
1166
1167           /* if the actor has been set to be painted even if unmapped
1168            * then we should map it and check for realization as well;
1169            * this is an override for the branch of the scene graph
1170            * which begins with this node
1171            */
1172           if (priv->enable_paint_unmapped)
1173             {
1174               if (priv->parent == NULL)
1175                 g_warning ("Attempting to map an unparented actor '%s'",
1176                            _clutter_actor_get_debug_name (self));
1177
1178               should_be_mapped = TRUE;
1179               must_be_realized = TRUE;
1180             }
1181
1182           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1183             may_be_realized = FALSE;
1184         }
1185
1186       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1187         {
1188           if (parent == NULL)
1189             g_warning ("Attempting to map a child that does not "
1190                        "meet the necessary invariants: the actor '%s' "
1191                        "has no parent",
1192                        _clutter_actor_get_debug_name (self));
1193           else
1194             g_warning ("Attempting to map a child that does not "
1195                        "meet the necessary invariants: the actor '%s' "
1196                        "is parented to an unmapped actor '%s'",
1197                        _clutter_actor_get_debug_name (self),
1198                        _clutter_actor_get_debug_name (priv->parent));
1199         }
1200
1201       /* If in reparent, we temporarily suspend unmap and unrealize.
1202        *
1203        * We want to go in the order "realize, map" and "unmap, unrealize"
1204        */
1205
1206       /* Unmap */
1207       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1208         clutter_actor_set_mapped (self, FALSE);
1209
1210       /* Realize */
1211       if (must_be_realized)
1212         clutter_actor_realize (self);
1213
1214       /* if we must be realized then we may be, presumably */
1215       g_assert (!(must_be_realized && !may_be_realized));
1216
1217       /* Unrealize */
1218       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1219         clutter_actor_unrealize_not_hiding (self);
1220
1221       /* Map */
1222       if (should_be_mapped)
1223         {
1224           if (!must_be_realized)
1225             g_warning ("Somehow we think actor '%s' should be mapped but "
1226                        "not realized, which isn't allowed",
1227                        _clutter_actor_get_debug_name (self));
1228
1229           /* realization is allowed to fail (though I don't know what
1230            * an app is supposed to do about that - shouldn't it just
1231            * be a g_error? anyway, we have to avoid mapping if this
1232            * happens)
1233            */
1234           if (CLUTTER_ACTOR_IS_REALIZED (self))
1235             clutter_actor_set_mapped (self, TRUE);
1236         }
1237     }
1238
1239 #ifdef CLUTTER_ENABLE_DEBUG
1240   /* check all invariants were kept */
1241   clutter_actor_verify_map_state (self);
1242 #endif
1243 }
1244
1245 static void
1246 clutter_actor_real_map (ClutterActor *self)
1247 {
1248   ClutterActorPrivate *priv = self->priv;
1249   ClutterActor *stage, *iter;
1250
1251   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1252
1253   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1254                 _clutter_actor_get_debug_name (self));
1255
1256   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1257
1258   stage = _clutter_actor_get_stage_internal (self);
1259   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1260
1261   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1262                 priv->pick_id,
1263                 _clutter_actor_get_debug_name (self));
1264
1265   /* notify on parent mapped before potentially mapping
1266    * children, so apps see a top-down notification.
1267    */
1268   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1269
1270   for (iter = self->priv->first_child;
1271        iter != NULL;
1272        iter = iter->priv->next_sibling)
1273     {
1274       clutter_actor_map (iter);
1275     }
1276 }
1277
1278 /**
1279  * clutter_actor_map:
1280  * @self: A #ClutterActor
1281  *
1282  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1283  * and realizes its children if they are visible. Does nothing if the
1284  * actor is not visible.
1285  *
1286  * Calling this function is strongly disencouraged: the default
1287  * implementation of #ClutterActorClass.map() will map all the children
1288  * of an actor when mapping its parent.
1289  *
1290  * When overriding map, it is mandatory to chain up to the parent
1291  * implementation.
1292  *
1293  * Since: 1.0
1294  */
1295 void
1296 clutter_actor_map (ClutterActor *self)
1297 {
1298   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1299
1300   if (CLUTTER_ACTOR_IS_MAPPED (self))
1301     return;
1302
1303   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1304     return;
1305
1306   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1307 }
1308
1309 static void
1310 clutter_actor_real_unmap (ClutterActor *self)
1311 {
1312   ClutterActorPrivate *priv = self->priv;
1313   ClutterActor *iter;
1314
1315   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1316
1317   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1318                 _clutter_actor_get_debug_name (self));
1319
1320   for (iter = self->priv->first_child;
1321        iter != NULL;
1322        iter = iter->priv->next_sibling)
1323     {
1324       clutter_actor_unmap (iter);
1325     }
1326
1327   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1328
1329   /* clear the contents of the last paint volume, so that hiding + moving +
1330    * showing will not result in the wrong area being repainted
1331    */
1332   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1333   priv->last_paint_volume_valid = TRUE;
1334
1335   /* notify on parent mapped after potentially unmapping
1336    * children, so apps see a bottom-up notification.
1337    */
1338   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1339
1340   /* relinquish keyboard focus if we were unmapped while owning it */
1341   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1342     {
1343       ClutterStage *stage;
1344
1345       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1346
1347       if (stage != NULL)
1348         _clutter_stage_release_pick_id (stage, priv->pick_id);
1349
1350       priv->pick_id = -1;
1351
1352       if (stage != NULL &&
1353           clutter_stage_get_key_focus (stage) == self)
1354         {
1355           clutter_stage_set_key_focus (stage, NULL);
1356         }
1357     }
1358 }
1359
1360 /**
1361  * clutter_actor_unmap:
1362  * @self: A #ClutterActor
1363  *
1364  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1365  * unmaps its children if they were mapped.
1366  *
1367  * Calling this function is not encouraged: the default #ClutterActor
1368  * implementation of #ClutterActorClass.unmap() will also unmap any
1369  * eventual children by default when their parent is unmapped.
1370  *
1371  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1372  * chain up to the parent implementation.
1373  *
1374  * <note>It is important to note that the implementation of the
1375  * #ClutterActorClass.unmap() virtual function may be called after
1376  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1377  * implementation, but it is guaranteed to be called before the
1378  * #GObjectClass.finalize() implementation.</note>
1379  *
1380  * Since: 1.0
1381  */
1382 void
1383 clutter_actor_unmap (ClutterActor *self)
1384 {
1385   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1386
1387   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1388     return;
1389
1390   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1391 }
1392
1393 static void
1394 clutter_actor_real_show (ClutterActor *self)
1395 {
1396   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1397     {
1398       ClutterActorPrivate *priv = self->priv;
1399
1400       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1401
1402       /* we notify on the "visible" flag in the clutter_actor_show()
1403        * wrapper so the entire show signal emission completes first
1404        * (?)
1405        */
1406       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1407
1408       /* we queue a relayout unless the actor is inside a
1409        * container that explicitly told us not to
1410        */
1411       if (priv->parent != NULL &&
1412           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1413         {
1414           /* While an actor is hidden the parent may not have
1415            * allocated/requested so we need to start from scratch
1416            * and avoid the short-circuiting in
1417            * clutter_actor_queue_relayout().
1418            */
1419           priv->needs_width_request  = FALSE;
1420           priv->needs_height_request = FALSE;
1421           priv->needs_allocation     = FALSE;
1422           clutter_actor_queue_relayout (self);
1423         }
1424     }
1425 }
1426
1427 static inline void
1428 set_show_on_set_parent (ClutterActor *self,
1429                         gboolean      set_show)
1430 {
1431   ClutterActorPrivate *priv = self->priv;
1432
1433   set_show = !!set_show;
1434
1435   if (priv->show_on_set_parent == set_show)
1436     return;
1437
1438   if (priv->parent == NULL)
1439     {
1440       priv->show_on_set_parent = set_show;
1441       g_object_notify_by_pspec (G_OBJECT (self),
1442                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1443     }
1444 }
1445
1446 /**
1447  * clutter_actor_show:
1448  * @self: A #ClutterActor
1449  *
1450  * Flags an actor to be displayed. An actor that isn't shown will not
1451  * be rendered on the stage.
1452  *
1453  * Actors are visible by default.
1454  *
1455  * If this function is called on an actor without a parent, the
1456  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1457  * effect.
1458  */
1459 void
1460 clutter_actor_show (ClutterActor *self)
1461 {
1462   ClutterActorPrivate *priv;
1463
1464   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1465
1466   /* simple optimization */
1467   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1468     {
1469       /* we still need to set the :show-on-set-parent property, in
1470        * case show() is called on an unparented actor
1471        */
1472       set_show_on_set_parent (self, TRUE);
1473       return;
1474     }
1475
1476 #ifdef CLUTTER_ENABLE_DEBUG
1477   clutter_actor_verify_map_state (self);
1478 #endif
1479
1480   priv = self->priv;
1481
1482   g_object_freeze_notify (G_OBJECT (self));
1483
1484   set_show_on_set_parent (self, TRUE);
1485
1486   g_signal_emit (self, actor_signals[SHOW], 0);
1487   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1488
1489   if (priv->parent != NULL)
1490     clutter_actor_queue_redraw (priv->parent);
1491
1492   g_object_thaw_notify (G_OBJECT (self));
1493 }
1494
1495 /**
1496  * clutter_actor_show_all:
1497  * @self: a #ClutterActor
1498  *
1499  * Calls clutter_actor_show() on all children of an actor (if any).
1500  *
1501  * Since: 0.2
1502  *
1503  * Deprecated: 1.10: Actors are visible by default
1504  */
1505 void
1506 clutter_actor_show_all (ClutterActor *self)
1507 {
1508   ClutterActorClass *klass;
1509
1510   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1511
1512   klass = CLUTTER_ACTOR_GET_CLASS (self);
1513   if (klass->show_all)
1514     klass->show_all (self);
1515 }
1516
1517 static void
1518 clutter_actor_real_hide (ClutterActor *self)
1519 {
1520   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1521     {
1522       ClutterActorPrivate *priv = self->priv;
1523
1524       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1525
1526       /* we notify on the "visible" flag in the clutter_actor_hide()
1527        * wrapper so the entire hide signal emission completes first
1528        * (?)
1529        */
1530       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1531
1532       /* we queue a relayout unless the actor is inside a
1533        * container that explicitly told us not to
1534        */
1535       if (priv->parent != NULL &&
1536           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1537         clutter_actor_queue_relayout (priv->parent);
1538     }
1539 }
1540
1541 /**
1542  * clutter_actor_hide:
1543  * @self: A #ClutterActor
1544  *
1545  * Flags an actor to be hidden. A hidden actor will not be
1546  * rendered on the stage.
1547  *
1548  * Actors are visible by default.
1549  *
1550  * If this function is called on an actor without a parent, the
1551  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1552  * as a side-effect.
1553  */
1554 void
1555 clutter_actor_hide (ClutterActor *self)
1556 {
1557   ClutterActorPrivate *priv;
1558
1559   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1560
1561   /* simple optimization */
1562   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1563     {
1564       /* we still need to set the :show-on-set-parent property, in
1565        * case hide() is called on an unparented actor
1566        */
1567       set_show_on_set_parent (self, FALSE);
1568       return;
1569     }
1570
1571 #ifdef CLUTTER_ENABLE_DEBUG
1572   clutter_actor_verify_map_state (self);
1573 #endif
1574
1575   priv = self->priv;
1576
1577   g_object_freeze_notify (G_OBJECT (self));
1578
1579   set_show_on_set_parent (self, FALSE);
1580
1581   g_signal_emit (self, actor_signals[HIDE], 0);
1582   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1583
1584   if (priv->parent != NULL)
1585     clutter_actor_queue_redraw (priv->parent);
1586
1587   g_object_thaw_notify (G_OBJECT (self));
1588 }
1589
1590 /**
1591  * clutter_actor_hide_all:
1592  * @self: a #ClutterActor
1593  *
1594  * Calls clutter_actor_hide() on all child actors (if any).
1595  *
1596  * Since: 0.2
1597  *
1598  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1599  *   prevent its children from being painted as well.
1600  */
1601 void
1602 clutter_actor_hide_all (ClutterActor *self)
1603 {
1604   ClutterActorClass *klass;
1605
1606   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1607
1608   klass = CLUTTER_ACTOR_GET_CLASS (self);
1609   if (klass->hide_all)
1610     klass->hide_all (self);
1611 }
1612
1613 /**
1614  * clutter_actor_realize:
1615  * @self: A #ClutterActor
1616  *
1617  * Realization informs the actor that it is attached to a stage. It
1618  * can use this to allocate resources if it wanted to delay allocation
1619  * until it would be rendered. However it is perfectly acceptable for
1620  * an actor to create resources before being realized because Clutter
1621  * only ever has a single rendering context so that actor is free to
1622  * be moved from one stage to another.
1623  *
1624  * This function does nothing if the actor is already realized.
1625  *
1626  * Because a realized actor must have realized parent actors, calling
1627  * clutter_actor_realize() will also realize all parents of the actor.
1628  *
1629  * This function does not realize child actors, except in the special
1630  * case that realizing the stage, when the stage is visible, will
1631  * suddenly map (and thus realize) the children of the stage.
1632  **/
1633 void
1634 clutter_actor_realize (ClutterActor *self)
1635 {
1636   ClutterActorPrivate *priv;
1637
1638   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1639
1640   priv = self->priv;
1641
1642 #ifdef CLUTTER_ENABLE_DEBUG
1643   clutter_actor_verify_map_state (self);
1644 #endif
1645
1646   if (CLUTTER_ACTOR_IS_REALIZED (self))
1647     return;
1648
1649   /* To be realized, our parent actors must be realized first.
1650    * This will only succeed if we're inside a toplevel.
1651    */
1652   if (priv->parent != NULL)
1653     clutter_actor_realize (priv->parent);
1654
1655   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1656     {
1657       /* toplevels can be realized at any time */
1658     }
1659   else
1660     {
1661       /* "Fail" the realization if parent is missing or unrealized;
1662        * this should really be a g_warning() not some kind of runtime
1663        * failure; how can an app possibly recover? Instead it's a bug
1664        * in the app and the app should get an explanatory warning so
1665        * someone can fix it. But for now it's too hard to fix this
1666        * because e.g. ClutterTexture needs reworking.
1667        */
1668       if (priv->parent == NULL ||
1669           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1670         return;
1671     }
1672
1673   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1674
1675   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1676   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1677
1678   g_signal_emit (self, actor_signals[REALIZE], 0);
1679
1680   /* Stage actor is allowed to unset the realized flag again in its
1681    * default signal handler, though that is a pathological situation.
1682    */
1683
1684   /* If realization "failed" we'll have to update child state. */
1685   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1686 }
1687
1688 static void
1689 clutter_actor_real_unrealize (ClutterActor *self)
1690 {
1691   /* we must be unmapped (implying our children are also unmapped) */
1692   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1693 }
1694
1695 /**
1696  * clutter_actor_unrealize:
1697  * @self: A #ClutterActor
1698  *
1699  * Unrealization informs the actor that it may be being destroyed or
1700  * moved to another stage. The actor may want to destroy any
1701  * underlying graphics resources at this point. However it is
1702  * perfectly acceptable for it to retain the resources until the actor
1703  * is destroyed because Clutter only ever uses a single rendering
1704  * context and all of the graphics resources are valid on any stage.
1705  *
1706  * Because mapped actors must be realized, actors may not be
1707  * unrealized if they are mapped. This function hides the actor to be
1708  * sure it isn't mapped, an application-visible side effect that you
1709  * may not be expecting.
1710  *
1711  * This function should not be called by application code.
1712  */
1713 void
1714 clutter_actor_unrealize (ClutterActor *self)
1715 {
1716   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1717   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1718
1719 /* This function should not really be in the public API, because
1720  * there isn't a good reason to call it. ClutterActor will already
1721  * unrealize things for you when it's important to do so.
1722  *
1723  * If you were using clutter_actor_unrealize() in a dispose
1724  * implementation, then don't, just chain up to ClutterActor's
1725  * dispose.
1726  *
1727  * If you were using clutter_actor_unrealize() to implement
1728  * unrealizing children of your container, then don't, ClutterActor
1729  * will already take care of that.
1730  *
1731  * If you were using clutter_actor_unrealize() to re-realize to
1732  * create your resources in a different way, then use
1733  * _clutter_actor_rerealize() (inside Clutter) or just call your
1734  * code that recreates your resources directly (outside Clutter).
1735  */
1736
1737 #ifdef CLUTTER_ENABLE_DEBUG
1738   clutter_actor_verify_map_state (self);
1739 #endif
1740
1741   clutter_actor_hide (self);
1742
1743   clutter_actor_unrealize_not_hiding (self);
1744 }
1745
1746 static ClutterActorTraverseVisitFlags
1747 unrealize_actor_before_children_cb (ClutterActor *self,
1748                                     int depth,
1749                                     void *user_data)
1750 {
1751   /* If an actor is already unrealized we know its children have also
1752    * already been unrealized... */
1753   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1754     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1755
1756   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1757
1758   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1759 }
1760
1761 static ClutterActorTraverseVisitFlags
1762 unrealize_actor_after_children_cb (ClutterActor *self,
1763                                    int depth,
1764                                    void *user_data)
1765 {
1766   /* We want to unset the realized flag only _after_
1767    * child actors are unrealized, to maintain invariants.
1768    */
1769   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1770   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1771   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1772 }
1773
1774 /*
1775  * clutter_actor_unrealize_not_hiding:
1776  * @self: A #ClutterActor
1777  *
1778  * Unrealization informs the actor that it may be being destroyed or
1779  * moved to another stage. The actor may want to destroy any
1780  * underlying graphics resources at this point. However it is
1781  * perfectly acceptable for it to retain the resources until the actor
1782  * is destroyed because Clutter only ever uses a single rendering
1783  * context and all of the graphics resources are valid on any stage.
1784  *
1785  * Because mapped actors must be realized, actors may not be
1786  * unrealized if they are mapped. You must hide the actor or one of
1787  * its parents before attempting to unrealize.
1788  *
1789  * This function is separate from clutter_actor_unrealize() because it
1790  * does not automatically hide the actor.
1791  * Actors need not be hidden to be unrealized, they just need to
1792  * be unmapped. In fact we don't want to mess up the application's
1793  * setting of the "visible" flag, so hiding is very undesirable.
1794  *
1795  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1796  * backward compatibility.
1797  */
1798 static void
1799 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1800 {
1801   _clutter_actor_traverse (self,
1802                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1803                            unrealize_actor_before_children_cb,
1804                            unrealize_actor_after_children_cb,
1805                            NULL);
1806 }
1807
1808 /*
1809  * _clutter_actor_rerealize:
1810  * @self: A #ClutterActor
1811  * @callback: Function to call while unrealized
1812  * @data: data for callback
1813  *
1814  * If an actor is already unrealized, this just calls the callback.
1815  *
1816  * If it is realized, it unrealizes temporarily, calls the callback,
1817  * and then re-realizes the actor.
1818  *
1819  * As a side effect, leaves all children of the actor unrealized if
1820  * the actor was realized but not showing.  This is because when we
1821  * unrealize the actor temporarily we must unrealize its children
1822  * (e.g. children of a stage can't be realized if stage window is
1823  * gone). And we aren't clever enough to save the realization state of
1824  * all children. In most cases this should not matter, because
1825  * the children will automatically realize when they next become mapped.
1826  */
1827 void
1828 _clutter_actor_rerealize (ClutterActor    *self,
1829                           ClutterCallback  callback,
1830                           void            *data)
1831 {
1832   gboolean was_mapped;
1833   gboolean was_showing;
1834   gboolean was_realized;
1835
1836   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1837
1838 #ifdef CLUTTER_ENABLE_DEBUG
1839   clutter_actor_verify_map_state (self);
1840 #endif
1841
1842   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1843   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1844   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1845
1846   /* Must be unmapped to unrealize. Note we only have to hide this
1847    * actor if it was mapped (if all parents were showing).  If actor
1848    * is merely visible (but not mapped), then that's fine, we can
1849    * leave it visible.
1850    */
1851   if (was_mapped)
1852     clutter_actor_hide (self);
1853
1854   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1855
1856   /* unrealize self and all children */
1857   clutter_actor_unrealize_not_hiding (self);
1858
1859   if (callback != NULL)
1860     {
1861       (* callback) (self, data);
1862     }
1863
1864   if (was_showing)
1865     clutter_actor_show (self); /* will realize only if mapping implies it */
1866   else if (was_realized)
1867     clutter_actor_realize (self); /* realize self and all parents */
1868 }
1869
1870 static void
1871 clutter_actor_real_pick (ClutterActor       *self,
1872                          const ClutterColor *color)
1873 {
1874   /* the default implementation is just to paint a rectangle
1875    * with the same size of the actor using the passed color
1876    */
1877   if (clutter_actor_should_pick_paint (self))
1878     {
1879       ClutterActorBox box = { 0, };
1880       float width, height;
1881
1882       clutter_actor_get_allocation_box (self, &box);
1883
1884       width = box.x2 - box.x1;
1885       height = box.y2 - box.y1;
1886
1887       cogl_set_source_color4ub (color->red,
1888                                 color->green,
1889                                 color->blue,
1890                                 color->alpha);
1891
1892       cogl_rectangle (0, 0, width, height);
1893     }
1894
1895   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1896    * with existing container classes that override the pick() virtual
1897    * and chain up to the default implementation - otherwise we'll end up
1898    * painting our children twice.
1899    *
1900    * this has to go away for 2.0; hopefully along the pick() itself.
1901    */
1902   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1903     {
1904       ClutterActor *iter;
1905
1906       for (iter = self->priv->first_child;
1907            iter != NULL;
1908            iter = iter->priv->next_sibling)
1909         clutter_actor_paint (iter);
1910     }
1911 }
1912
1913 /**
1914  * clutter_actor_should_pick_paint:
1915  * @self: A #ClutterActor
1916  *
1917  * Should be called inside the implementation of the
1918  * #ClutterActor::pick virtual function in order to check whether
1919  * the actor should paint itself in pick mode or not.
1920  *
1921  * This function should never be called directly by applications.
1922  *
1923  * Return value: %TRUE if the actor should paint its silhouette,
1924  *   %FALSE otherwise
1925  */
1926 gboolean
1927 clutter_actor_should_pick_paint (ClutterActor *self)
1928 {
1929   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1930
1931   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1932       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1933        CLUTTER_ACTOR_IS_REACTIVE (self)))
1934     return TRUE;
1935
1936   return FALSE;
1937 }
1938
1939 static void
1940 clutter_actor_real_get_preferred_width (ClutterActor *self,
1941                                         gfloat        for_height,
1942                                         gfloat       *min_width_p,
1943                                         gfloat       *natural_width_p)
1944 {
1945   ClutterActorPrivate *priv = self->priv;
1946
1947   if (priv->n_children != 0 &&
1948       priv->layout_manager != NULL)
1949     {
1950       ClutterContainer *container = CLUTTER_CONTAINER (self);
1951
1952       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1953                     "for the preferred width",
1954                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1955                     priv->layout_manager);
1956
1957       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1958                                                   container,
1959                                                   for_height,
1960                                                   min_width_p,
1961                                                   natural_width_p);
1962
1963       return;
1964     }
1965
1966   /* Default implementation is always 0x0, usually an actor
1967    * using this default is relying on someone to set the
1968    * request manually
1969    */
1970   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1971
1972   if (min_width_p)
1973     *min_width_p = 0;
1974
1975   if (natural_width_p)
1976     *natural_width_p = 0;
1977 }
1978
1979 static void
1980 clutter_actor_real_get_preferred_height (ClutterActor *self,
1981                                          gfloat        for_width,
1982                                          gfloat       *min_height_p,
1983                                          gfloat       *natural_height_p)
1984 {
1985   ClutterActorPrivate *priv = self->priv;
1986
1987   if (priv->n_children != 0 &&
1988       priv->layout_manager != NULL)
1989     {
1990       ClutterContainer *container = CLUTTER_CONTAINER (self);
1991
1992       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1993                     "for the preferred height",
1994                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1995                     priv->layout_manager);
1996
1997       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1998                                                    container,
1999                                                    for_width,
2000                                                    min_height_p,
2001                                                    natural_height_p);
2002
2003       return;
2004     }
2005   /* Default implementation is always 0x0, usually an actor
2006    * using this default is relying on someone to set the
2007    * request manually
2008    */
2009   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2010
2011   if (min_height_p)
2012     *min_height_p = 0;
2013
2014   if (natural_height_p)
2015     *natural_height_p = 0;
2016 }
2017
2018 static void
2019 clutter_actor_store_old_geometry (ClutterActor    *self,
2020                                   ClutterActorBox *box)
2021 {
2022   *box = self->priv->allocation;
2023 }
2024
2025 static inline void
2026 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2027                                           const ClutterActorBox *old)
2028 {
2029   ClutterActorPrivate *priv = self->priv;
2030   GObject *obj = G_OBJECT (self);
2031
2032   g_object_freeze_notify (obj);
2033
2034   /* to avoid excessive requisition or allocation cycles we
2035    * use the cached values.
2036    *
2037    * - if we don't have an allocation we assume that we need
2038    *   to notify anyway
2039    * - if we don't have a width or a height request we notify
2040    *   width and height
2041    * - if we have a valid allocation then we check the old
2042    *   bounding box with the current allocation and we notify
2043    *   the changes
2044    */
2045   if (priv->needs_allocation)
2046     {
2047       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2048       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2049       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2050       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2051     }
2052   else if (priv->needs_width_request || priv->needs_height_request)
2053     {
2054       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2055       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2056     }
2057   else
2058     {
2059       gfloat xu, yu;
2060       gfloat widthu, heightu;
2061
2062       xu = priv->allocation.x1;
2063       yu = priv->allocation.y1;
2064       widthu = priv->allocation.x2 - priv->allocation.x1;
2065       heightu = priv->allocation.y2 - priv->allocation.y1;
2066
2067       if (xu != old->x1)
2068         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2069
2070       if (yu != old->y1)
2071         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2072
2073       if (widthu != (old->x2 - old->x1))
2074         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2075
2076       if (heightu != (old->y2 - old->y1))
2077         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2078     }
2079
2080   g_object_thaw_notify (obj);
2081 }
2082
2083 /*< private >
2084  * clutter_actor_set_allocation_internal:
2085  * @self: a #ClutterActor
2086  * @box: a #ClutterActorBox
2087  * @flags: allocation flags
2088  *
2089  * Stores the allocation of @self.
2090  *
2091  * This function only performs basic storage and property notification.
2092  *
2093  * This function should be called by clutter_actor_set_allocation()
2094  * and by the default implementation of #ClutterActorClass.allocate().
2095  *
2096  * Return value: %TRUE if the allocation of the #ClutterActor has been
2097  *   changed, and %FALSE otherwise
2098  */
2099 static inline gboolean
2100 clutter_actor_set_allocation_internal (ClutterActor           *self,
2101                                        const ClutterActorBox  *box,
2102                                        ClutterAllocationFlags  flags)
2103 {
2104   ClutterActorPrivate *priv = self->priv;
2105   GObject *obj;
2106   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2107   gboolean flags_changed;
2108   gboolean retval;
2109   ClutterActorBox old_alloc = { 0, };
2110
2111   obj = G_OBJECT (self);
2112
2113   g_object_freeze_notify (obj);
2114
2115   clutter_actor_store_old_geometry (self, &old_alloc);
2116
2117   x1_changed = priv->allocation.x1 != box->x1;
2118   y1_changed = priv->allocation.y1 != box->y1;
2119   x2_changed = priv->allocation.x2 != box->x2;
2120   y2_changed = priv->allocation.y2 != box->y2;
2121
2122   flags_changed = priv->allocation_flags != flags;
2123
2124   priv->allocation = *box;
2125   priv->allocation_flags = flags;
2126
2127   /* allocation is authoritative */
2128   priv->needs_width_request = FALSE;
2129   priv->needs_height_request = FALSE;
2130   priv->needs_allocation = FALSE;
2131
2132   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
2133     {
2134       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2135                     _clutter_actor_get_debug_name (self));
2136
2137       priv->transform_valid = FALSE;
2138
2139       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2140
2141       /* if the allocation changes, so does the content box */
2142       if (priv->content != NULL)
2143         g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2144
2145       retval = TRUE;
2146     }
2147   else
2148     retval = FALSE;
2149
2150   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2151
2152   g_object_thaw_notify (obj);
2153
2154   return retval;
2155 }
2156
2157 static void clutter_actor_real_allocate (ClutterActor           *self,
2158                                          const ClutterActorBox  *box,
2159                                          ClutterAllocationFlags  flags);
2160
2161 static inline void
2162 clutter_actor_maybe_layout_children (ClutterActor           *self,
2163                                      const ClutterActorBox  *allocation,
2164                                      ClutterAllocationFlags  flags)
2165 {
2166   ClutterActorPrivate *priv = self->priv;
2167
2168   /* this is going to be a bit hard to follow, so let's put an explanation
2169    * here.
2170    *
2171    * we want ClutterActor to have a default layout manager if the actor was
2172    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2173    *
2174    * we also want any subclass of ClutterActor that does not override the
2175    * ::allocate() virtual function to delegate to a layout manager.
2176    *
2177    * finally, we want to allow people subclassing ClutterActor and overriding
2178    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2179    *
2180    * on the other hand, we want existing actor subclasses overriding the
2181    * ::allocate() virtual function and chaining up to the parent's
2182    * implementation to continue working without allocating their children
2183    * twice, or without entering an allocation loop.
2184    *
2185    * for the first two points, we check if the class of the actor is
2186    * overridding the ::allocate() virtual function; if it isn't, then we
2187    * follow through with checking whether we have children and a layout
2188    * manager, and eventually calling clutter_layout_manager_allocate().
2189    *
2190    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2191    * allocation flags that we got passed, and if it is present, we continue
2192    * with the check above.
2193    *
2194    * if neither of these two checks yields a positive result, we just
2195    * assume that the ::allocate() virtual function that resulted in this
2196    * function being called will also allocate the children of the actor.
2197    */
2198
2199   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2200     goto check_layout;
2201
2202   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2203     goto check_layout;
2204
2205   return;
2206
2207 check_layout:
2208   if (priv->n_children != 0 &&
2209       priv->layout_manager != NULL)
2210     {
2211       ClutterContainer *container = CLUTTER_CONTAINER (self);
2212       ClutterAllocationFlags children_flags;
2213       ClutterActorBox children_box;
2214
2215       /* normalize the box passed to the layout manager */
2216       children_box.x1 = children_box.y1 = 0.f;
2217       children_box.x2 = (allocation->x2 - allocation->x1);
2218       children_box.y2 = (allocation->y2 - allocation->y1);
2219
2220       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2221        * the actor's children, since it refers only to the current
2222        * actor's allocation.
2223        */
2224       children_flags = flags;
2225       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2226
2227       CLUTTER_NOTE (LAYOUT,
2228                     "Allocating %d children of %s "
2229                     "at { %.2f, %.2f - %.2f x %.2f } "
2230                     "using %s",
2231                     priv->n_children,
2232                     _clutter_actor_get_debug_name (self),
2233                     allocation->x1,
2234                     allocation->y1,
2235                     (allocation->x2 - allocation->x1),
2236                     (allocation->y2 - allocation->y1),
2237                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2238
2239       clutter_layout_manager_allocate (priv->layout_manager,
2240                                        container,
2241                                        &children_box,
2242                                        children_flags);
2243     }
2244 }
2245
2246 static void
2247 clutter_actor_real_allocate (ClutterActor           *self,
2248                              const ClutterActorBox  *box,
2249                              ClutterAllocationFlags  flags)
2250 {
2251   ClutterActorPrivate *priv = self->priv;
2252   gboolean changed;
2253
2254   g_object_freeze_notify (G_OBJECT (self));
2255
2256   changed = clutter_actor_set_allocation_internal (self, box, flags);
2257
2258   /* we allocate our children before we notify changes in our geometry,
2259    * so that people connecting to properties will be able to get valid
2260    * data out of the sub-tree of the scene graph that has this actor at
2261    * the root.
2262    */
2263   clutter_actor_maybe_layout_children (self, box, flags);
2264
2265   if (changed)
2266     {
2267       ClutterActorBox signal_box = priv->allocation;
2268       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2269
2270       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2271                      &signal_box,
2272                      signal_flags);
2273     }
2274
2275   g_object_thaw_notify (G_OBJECT (self));
2276 }
2277
2278 static void
2279 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2280                                     ClutterActor *origin)
2281 {
2282   /* no point in queuing a redraw on a destroyed actor */
2283   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2284     return;
2285
2286   /* NB: We can't bail out early here if the actor is hidden in case
2287    * the actor bas been cloned. In this case the clone will need to
2288    * receive the signal so it can queue its own redraw.
2289    */
2290
2291   /* calls klass->queue_redraw in default handler */
2292   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2293 }
2294
2295 static void
2296 clutter_actor_real_queue_redraw (ClutterActor *self,
2297                                  ClutterActor *origin)
2298 {
2299   ClutterActor *parent;
2300
2301   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2302                 _clutter_actor_get_debug_name (self),
2303                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2304                                : "same actor");
2305
2306   /* no point in queuing a redraw on a destroyed actor */
2307   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2308     return;
2309
2310   /* If the queue redraw is coming from a child then the actor has
2311      become dirty and any queued effect is no longer valid */
2312   if (self != origin)
2313     {
2314       self->priv->is_dirty = TRUE;
2315       self->priv->effect_to_redraw = NULL;
2316     }
2317
2318   /* If the actor isn't visible, we still had to emit the signal
2319    * to allow for a ClutterClone, but the appearance of the parent
2320    * won't change so we don't have to propagate up the hierarchy.
2321    */
2322   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2323     return;
2324
2325   /* Although we could determine here that a full stage redraw
2326    * has already been queued and immediately bail out, we actually
2327    * guarantee that we will propagate a queue-redraw signal to our
2328    * parent at least once so that it's possible to implement a
2329    * container that tracks which of its children have queued a
2330    * redraw.
2331    */
2332   if (self->priv->propagated_one_redraw)
2333     {
2334       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2335       if (stage != NULL &&
2336           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2337         return;
2338     }
2339
2340   self->priv->propagated_one_redraw = TRUE;
2341
2342   /* notify parents, if they are all visible eventually we'll
2343    * queue redraw on the stage, which queues the redraw idle.
2344    */
2345   parent = clutter_actor_get_parent (self);
2346   if (parent != NULL)
2347     {
2348       /* this will go up recursively */
2349       _clutter_actor_signal_queue_redraw (parent, origin);
2350     }
2351 }
2352
2353 static void
2354 clutter_actor_real_queue_relayout (ClutterActor *self)
2355 {
2356   ClutterActorPrivate *priv = self->priv;
2357
2358   /* no point in queueing a redraw on a destroyed actor */
2359   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2360     return;
2361
2362   priv->needs_width_request  = TRUE;
2363   priv->needs_height_request = TRUE;
2364   priv->needs_allocation     = TRUE;
2365
2366   /* reset the cached size requests */
2367   memset (priv->width_requests, 0,
2368           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2369   memset (priv->height_requests, 0,
2370           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2371
2372   /* We need to go all the way up the hierarchy */
2373   if (priv->parent != NULL)
2374     _clutter_actor_queue_only_relayout (priv->parent);
2375 }
2376
2377 /**
2378  * clutter_actor_apply_relative_transform_to_point:
2379  * @self: A #ClutterActor
2380  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2381  *   default #ClutterStage
2382  * @point: A point as #ClutterVertex
2383  * @vertex: (out caller-allocates): The translated #ClutterVertex
2384  *
2385  * Transforms @point in coordinates relative to the actor into
2386  * ancestor-relative coordinates using the relevant transform
2387  * stack (i.e. scale, rotation, etc).
2388  *
2389  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2390  * this case, the coordinates returned will be the coordinates on
2391  * the stage before the projection is applied. This is different from
2392  * the behaviour of clutter_actor_apply_transform_to_point().
2393  *
2394  * Since: 0.6
2395  */
2396 void
2397 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2398                                                  ClutterActor        *ancestor,
2399                                                  const ClutterVertex *point,
2400                                                  ClutterVertex       *vertex)
2401 {
2402   gfloat w;
2403   CoglMatrix matrix;
2404
2405   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2406   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2407   g_return_if_fail (point != NULL);
2408   g_return_if_fail (vertex != NULL);
2409
2410   *vertex = *point;
2411   w = 1.0;
2412
2413   if (ancestor == NULL)
2414     ancestor = _clutter_actor_get_stage_internal (self);
2415
2416   if (ancestor == NULL)
2417     {
2418       *vertex = *point;
2419       return;
2420     }
2421
2422   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2423   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2424 }
2425
2426 static gboolean
2427 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2428                                          const ClutterVertex *vertices_in,
2429                                          ClutterVertex *vertices_out,
2430                                          int n_vertices)
2431 {
2432   ClutterActor *stage;
2433   CoglMatrix modelview;
2434   CoglMatrix projection;
2435   float viewport[4];
2436
2437   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2438
2439   stage = _clutter_actor_get_stage_internal (self);
2440
2441   /* We really can't do anything meaningful in this case so don't try
2442    * to do any transform */
2443   if (stage == NULL)
2444     return FALSE;
2445
2446   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2447    * that gets us to stage coordinates, we want to go all the way to eye
2448    * coordinates */
2449   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2450
2451   /* Fetch the projection and viewport */
2452   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2453   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2454                                &viewport[0],
2455                                &viewport[1],
2456                                &viewport[2],
2457                                &viewport[3]);
2458
2459   _clutter_util_fully_transform_vertices (&modelview,
2460                                           &projection,
2461                                           viewport,
2462                                           vertices_in,
2463                                           vertices_out,
2464                                           n_vertices);
2465
2466   return TRUE;
2467 }
2468
2469 /**
2470  * clutter_actor_apply_transform_to_point:
2471  * @self: A #ClutterActor
2472  * @point: A point as #ClutterVertex
2473  * @vertex: (out caller-allocates): The translated #ClutterVertex
2474  *
2475  * Transforms @point in coordinates relative to the actor
2476  * into screen-relative coordinates with the current actor
2477  * transformation (i.e. scale, rotation, etc)
2478  *
2479  * Since: 0.4
2480  **/
2481 void
2482 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2483                                         const ClutterVertex *point,
2484                                         ClutterVertex       *vertex)
2485 {
2486   g_return_if_fail (point != NULL);
2487   g_return_if_fail (vertex != NULL);
2488   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2489 }
2490
2491 /*
2492  * _clutter_actor_get_relative_transformation_matrix:
2493  * @self: The actor whose coordinate space you want to transform from.
2494  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2495  *            or %NULL if you want to transform all the way to eye coordinates.
2496  * @matrix: A #CoglMatrix to store the transformation
2497  *
2498  * This gets a transformation @matrix that will transform coordinates from the
2499  * coordinate space of @self into the coordinate space of @ancestor.
2500  *
2501  * For example if you need a matrix that can transform the local actor
2502  * coordinates of @self into stage coordinates you would pass the actor's stage
2503  * pointer as the @ancestor.
2504  *
2505  * If you pass %NULL then the transformation will take you all the way through
2506  * to eye coordinates. This can be useful if you want to extract the entire
2507  * modelview transform that Clutter applies before applying the projection
2508  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2509  * using cogl_set_modelview_matrix() for example then you would want a matrix
2510  * that transforms into eye coordinates.
2511  *
2512  * <note><para>This function explicitly initializes the given @matrix. If you just
2513  * want clutter to multiply a relative transformation with an existing matrix
2514  * you can use clutter_actor_apply_relative_transformation_matrix()
2515  * instead.</para></note>
2516  *
2517  */
2518 /* XXX: We should consider caching the stage relative modelview along with
2519  * the actor itself */
2520 static void
2521 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2522                                                    ClutterActor *ancestor,
2523                                                    CoglMatrix *matrix)
2524 {
2525   cogl_matrix_init_identity (matrix);
2526
2527   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2528 }
2529
2530 /* Project the given @box into stage window coordinates, writing the
2531  * transformed vertices to @verts[]. */
2532 static gboolean
2533 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2534                                           const ClutterActorBox *box,
2535                                           ClutterVertex          verts[])
2536 {
2537   ClutterVertex box_vertices[4];
2538
2539   box_vertices[0].x = box->x1;
2540   box_vertices[0].y = box->y1;
2541   box_vertices[0].z = 0;
2542   box_vertices[1].x = box->x2;
2543   box_vertices[1].y = box->y1;
2544   box_vertices[1].z = 0;
2545   box_vertices[2].x = box->x1;
2546   box_vertices[2].y = box->y2;
2547   box_vertices[2].z = 0;
2548   box_vertices[3].x = box->x2;
2549   box_vertices[3].y = box->y2;
2550   box_vertices[3].z = 0;
2551
2552   return
2553     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2554 }
2555
2556 /**
2557  * clutter_actor_get_allocation_vertices:
2558  * @self: A #ClutterActor
2559  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2560  *   against, or %NULL to use the #ClutterStage
2561  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2562  *   location for an array of 4 #ClutterVertex in which to store the result
2563  *
2564  * Calculates the transformed coordinates of the four corners of the
2565  * actor in the plane of @ancestor. The returned vertices relate to
2566  * the #ClutterActorBox coordinates as follows:
2567  * <itemizedlist>
2568  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2569  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2570  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2571  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2572  * </itemizedlist>
2573  *
2574  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2575  * this case, the coordinates returned will be the coordinates on
2576  * the stage before the projection is applied. This is different from
2577  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2578  *
2579  * Since: 0.6
2580  */
2581 void
2582 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2583                                        ClutterActor  *ancestor,
2584                                        ClutterVertex  verts[])
2585 {
2586   ClutterActorPrivate *priv;
2587   ClutterActorBox box;
2588   ClutterVertex vertices[4];
2589   CoglMatrix modelview;
2590
2591   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2592   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2593
2594   if (ancestor == NULL)
2595     ancestor = _clutter_actor_get_stage_internal (self);
2596
2597   /* Fallback to a NOP transform if the actor isn't parented under a
2598    * stage. */
2599   if (ancestor == NULL)
2600     ancestor = self;
2601
2602   priv = self->priv;
2603
2604   /* if the actor needs to be allocated we force a relayout, so that
2605    * we will have valid values to use in the transformations */
2606   if (priv->needs_allocation)
2607     {
2608       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2609       if (stage)
2610         _clutter_stage_maybe_relayout (stage);
2611       else
2612         {
2613           box.x1 = box.y1 = 0;
2614           /* The result isn't really meaningful in this case but at
2615            * least try to do something *vaguely* reasonable... */
2616           clutter_actor_get_size (self, &box.x2, &box.y2);
2617         }
2618     }
2619
2620   clutter_actor_get_allocation_box (self, &box);
2621
2622   vertices[0].x = box.x1;
2623   vertices[0].y = box.y1;
2624   vertices[0].z = 0;
2625   vertices[1].x = box.x2;
2626   vertices[1].y = box.y1;
2627   vertices[1].z = 0;
2628   vertices[2].x = box.x1;
2629   vertices[2].y = box.y2;
2630   vertices[2].z = 0;
2631   vertices[3].x = box.x2;
2632   vertices[3].y = box.y2;
2633   vertices[3].z = 0;
2634
2635   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2636                                                      &modelview);
2637
2638   cogl_matrix_transform_points (&modelview,
2639                                 3,
2640                                 sizeof (ClutterVertex),
2641                                 vertices,
2642                                 sizeof (ClutterVertex),
2643                                 vertices,
2644                                 4);
2645 }
2646
2647 /**
2648  * clutter_actor_get_abs_allocation_vertices:
2649  * @self: A #ClutterActor
2650  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2651  *   of 4 #ClutterVertex where to store the result.
2652  *
2653  * Calculates the transformed screen coordinates of the four corners of
2654  * the actor; the returned vertices relate to the #ClutterActorBox
2655  * coordinates  as follows:
2656  * <itemizedlist>
2657  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2658  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2659  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2660  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2661  * </itemizedlist>
2662  *
2663  * Since: 0.4
2664  */
2665 void
2666 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2667                                            ClutterVertex  verts[])
2668 {
2669   ClutterActorPrivate *priv;
2670   ClutterActorBox actor_space_allocation;
2671
2672   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2673
2674   priv = self->priv;
2675
2676   /* if the actor needs to be allocated we force a relayout, so that
2677    * the actor allocation box will be valid for
2678    * _clutter_actor_transform_and_project_box()
2679    */
2680   if (priv->needs_allocation)
2681     {
2682       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2683       /* There's nothing meaningful we can do now */
2684       if (!stage)
2685         return;
2686
2687       _clutter_stage_maybe_relayout (stage);
2688     }
2689
2690   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2691    * own coordinate space... */
2692   actor_space_allocation.x1 = 0;
2693   actor_space_allocation.y1 = 0;
2694   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2695   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2696   _clutter_actor_transform_and_project_box (self,
2697                                             &actor_space_allocation,
2698                                             verts);
2699 }
2700
2701 static void
2702 clutter_actor_real_apply_transform (ClutterActor *self,
2703                                     CoglMatrix   *matrix)
2704 {
2705   ClutterActorPrivate *priv = self->priv;
2706
2707   if (!priv->transform_valid)
2708     {
2709       CoglMatrix *transform = &priv->transform;
2710       const ClutterTransformInfo *info;
2711
2712       info = _clutter_actor_get_transform_info_or_defaults (self);
2713
2714       cogl_matrix_init_identity (transform);
2715
2716       cogl_matrix_translate (transform,
2717                              priv->allocation.x1,
2718                              priv->allocation.y1,
2719                              0.0);
2720
2721       if (info->depth)
2722         cogl_matrix_translate (transform, 0, 0, info->depth);
2723
2724       /*
2725        * because the rotation involves translations, we must scale
2726        * before applying the rotations (if we apply the scale after
2727        * the rotations, the translations included in the rotation are
2728        * not scaled and so the entire object will move on the screen
2729        * as a result of rotating it).
2730        */
2731       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2732         {
2733           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2734                                         &info->scale_center,
2735                                         cogl_matrix_scale (transform,
2736                                                            info->scale_x,
2737                                                            info->scale_y,
2738                                                            1.0));
2739         }
2740
2741       if (info->rz_angle)
2742         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2743                                       &info->rz_center,
2744                                       cogl_matrix_rotate (transform,
2745                                                           info->rz_angle,
2746                                                           0, 0, 1.0));
2747
2748       if (info->ry_angle)
2749         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2750                                       &info->ry_center,
2751                                       cogl_matrix_rotate (transform,
2752                                                           info->ry_angle,
2753                                                           0, 1.0, 0));
2754
2755       if (info->rx_angle)
2756         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2757                                       &info->rx_center,
2758                                       cogl_matrix_rotate (transform,
2759                                                           info->rx_angle,
2760                                                           1.0, 0, 0));
2761
2762       if (!clutter_anchor_coord_is_zero (&info->anchor))
2763         {
2764           gfloat x, y, z;
2765
2766           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2767           cogl_matrix_translate (transform, -x, -y, -z);
2768         }
2769
2770       priv->transform_valid = TRUE;
2771     }
2772
2773   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2774 }
2775
2776 /* Applies the transforms associated with this actor to the given
2777  * matrix. */
2778 void
2779 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2780                                           CoglMatrix *matrix)
2781 {
2782   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2783 }
2784
2785 /*
2786  * clutter_actor_apply_relative_transformation_matrix:
2787  * @self: The actor whose coordinate space you want to transform from.
2788  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2789  *            or %NULL if you want to transform all the way to eye coordinates.
2790  * @matrix: A #CoglMatrix to apply the transformation too.
2791  *
2792  * This multiplies a transform with @matrix that will transform coordinates
2793  * from the coordinate space of @self into the coordinate space of @ancestor.
2794  *
2795  * For example if you need a matrix that can transform the local actor
2796  * coordinates of @self into stage coordinates you would pass the actor's stage
2797  * pointer as the @ancestor.
2798  *
2799  * If you pass %NULL then the transformation will take you all the way through
2800  * to eye coordinates. This can be useful if you want to extract the entire
2801  * modelview transform that Clutter applies before applying the projection
2802  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2803  * using cogl_set_modelview_matrix() for example then you would want a matrix
2804  * that transforms into eye coordinates.
2805  *
2806  * <note>This function doesn't initialize the given @matrix, it simply
2807  * multiplies the requested transformation matrix with the existing contents of
2808  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2809  * before calling this function, or you can use
2810  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2811  */
2812 void
2813 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2814                                                      ClutterActor *ancestor,
2815                                                      CoglMatrix *matrix)
2816 {
2817   ClutterActor *parent;
2818
2819   /* Note we terminate before ever calling stage->apply_transform()
2820    * since that would conceptually be relative to the underlying
2821    * window OpenGL coordinates so we'd need a special @ancestor
2822    * value to represent the fake parent of the stage. */
2823   if (self == ancestor)
2824     return;
2825
2826   parent = clutter_actor_get_parent (self);
2827
2828   if (parent != NULL)
2829     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2830                                                          matrix);
2831
2832   _clutter_actor_apply_modelview_transform (self, matrix);
2833 }
2834
2835 static void
2836 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2837                                        ClutterPaintVolume *pv,
2838                                        const char *label,
2839                                        const CoglColor *color)
2840 {
2841   static CoglPipeline *outline = NULL;
2842   CoglPrimitive *prim;
2843   ClutterVertex line_ends[12 * 2];
2844   int n_vertices;
2845   CoglContext *ctx =
2846     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2847   /* XXX: at some point we'll query this from the stage but we can't
2848    * do that until the osx backend uses Cogl natively. */
2849   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2850
2851   if (outline == NULL)
2852     outline = cogl_pipeline_new (ctx);
2853
2854   _clutter_paint_volume_complete (pv);
2855
2856   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2857
2858   /* Front face */
2859   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2860   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2861   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2862   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2863
2864   if (!pv->is_2d)
2865     {
2866       /* Back face */
2867       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2868       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2869       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2870       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2871
2872       /* Lines connecting front face to back face */
2873       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2874       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2875       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2876       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2877     }
2878
2879   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2880                                 n_vertices,
2881                                 (CoglVertexP3 *)line_ends);
2882
2883   cogl_pipeline_set_color (outline, color);
2884   cogl_framebuffer_draw_primitive (fb, outline, prim);
2885   cogl_object_unref (prim);
2886
2887   if (label)
2888     {
2889       PangoLayout *layout;
2890       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2891       pango_layout_set_text (layout, label, -1);
2892       cogl_pango_render_layout (layout,
2893                                 pv->vertices[0].x,
2894                                 pv->vertices[0].y,
2895                                 color,
2896                                 0);
2897       g_object_unref (layout);
2898     }
2899 }
2900
2901 static void
2902 _clutter_actor_draw_paint_volume (ClutterActor *self)
2903 {
2904   ClutterPaintVolume *pv;
2905   CoglColor color;
2906
2907   pv = _clutter_actor_get_paint_volume_mutable (self);
2908   if (!pv)
2909     {
2910       gfloat width, height;
2911       ClutterPaintVolume fake_pv;
2912
2913       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2914       _clutter_paint_volume_init_static (&fake_pv, stage);
2915
2916       clutter_actor_get_size (self, &width, &height);
2917       clutter_paint_volume_set_width (&fake_pv, width);
2918       clutter_paint_volume_set_height (&fake_pv, height);
2919
2920       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2921       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2922                                              _clutter_actor_get_debug_name (self),
2923                                              &color);
2924
2925       clutter_paint_volume_free (&fake_pv);
2926     }
2927   else
2928     {
2929       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2930       _clutter_actor_draw_paint_volume_full (self, pv,
2931                                              _clutter_actor_get_debug_name (self),
2932                                              &color);
2933     }
2934 }
2935
2936 static void
2937 _clutter_actor_paint_cull_result (ClutterActor *self,
2938                                   gboolean success,
2939                                   ClutterCullResult result)
2940 {
2941   ClutterPaintVolume *pv;
2942   CoglColor color;
2943
2944   if (success)
2945     {
2946       if (result == CLUTTER_CULL_RESULT_IN)
2947         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2948       else if (result == CLUTTER_CULL_RESULT_OUT)
2949         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2950       else
2951         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2952     }
2953   else
2954     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2955
2956   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2957     _clutter_actor_draw_paint_volume_full (self, pv,
2958                                            _clutter_actor_get_debug_name (self),
2959                                            &color);
2960   else
2961     {
2962       PangoLayout *layout;
2963       char *label =
2964         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2965       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2966       cogl_set_source_color (&color);
2967
2968       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2969       pango_layout_set_text (layout, label, -1);
2970       cogl_pango_render_layout (layout,
2971                                 0,
2972                                 0,
2973                                 &color,
2974                                 0);
2975       g_free (label);
2976       g_object_unref (layout);
2977     }
2978 }
2979
2980 static int clone_paint_level = 0;
2981
2982 void
2983 _clutter_actor_push_clone_paint (void)
2984 {
2985   clone_paint_level++;
2986 }
2987
2988 void
2989 _clutter_actor_pop_clone_paint (void)
2990 {
2991   clone_paint_level--;
2992 }
2993
2994 static gboolean
2995 in_clone_paint (void)
2996 {
2997   return clone_paint_level > 0;
2998 }
2999
3000 /* Returns TRUE if the actor can be ignored */
3001 /* FIXME: we should return a ClutterCullResult, and
3002  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3003  * means there's no point in trying to cull descendants of the current
3004  * node. */
3005 static gboolean
3006 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3007 {
3008   ClutterActorPrivate *priv = self->priv;
3009   ClutterActor *stage;
3010   const ClutterPlane *stage_clip;
3011
3012   if (!priv->last_paint_volume_valid)
3013     {
3014       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3015                     "->last_paint_volume_valid == FALSE",
3016                     _clutter_actor_get_debug_name (self));
3017       return FALSE;
3018     }
3019
3020   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3021     return FALSE;
3022
3023   stage = _clutter_actor_get_stage_internal (self);
3024   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3025   if (G_UNLIKELY (!stage_clip))
3026     {
3027       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3028                     "No stage clip set",
3029                     _clutter_actor_get_debug_name (self));
3030       return FALSE;
3031     }
3032
3033   if (cogl_get_draw_framebuffer () !=
3034       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3035     {
3036       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3037                     "Current framebuffer doesn't correspond to stage",
3038                     _clutter_actor_get_debug_name (self));
3039       return FALSE;
3040     }
3041
3042   *result_out =
3043     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3044   return TRUE;
3045 }
3046
3047 static void
3048 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3049 {
3050   ClutterActorPrivate *priv = self->priv;
3051   const ClutterPaintVolume *pv;
3052
3053   if (priv->last_paint_volume_valid)
3054     {
3055       clutter_paint_volume_free (&priv->last_paint_volume);
3056       priv->last_paint_volume_valid = FALSE;
3057     }
3058
3059   pv = clutter_actor_get_paint_volume (self);
3060   if (!pv)
3061     {
3062       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3063                     "Actor failed to report a paint volume",
3064                     _clutter_actor_get_debug_name (self));
3065       return;
3066     }
3067
3068   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3069
3070   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3071                                             NULL); /* eye coordinates */
3072
3073   priv->last_paint_volume_valid = TRUE;
3074 }
3075
3076 static inline gboolean
3077 actor_has_shader_data (ClutterActor *self)
3078 {
3079   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3080 }
3081
3082 guint32
3083 _clutter_actor_get_pick_id (ClutterActor *self)
3084 {
3085   if (self->priv->pick_id < 0)
3086     return 0;
3087
3088   return self->priv->pick_id;
3089 }
3090
3091 /* This is the same as clutter_actor_add_effect except that it doesn't
3092    queue a redraw and it doesn't notify on the effect property */
3093 static void
3094 _clutter_actor_add_effect_internal (ClutterActor  *self,
3095                                     ClutterEffect *effect)
3096 {
3097   ClutterActorPrivate *priv = self->priv;
3098
3099   if (priv->effects == NULL)
3100     {
3101       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3102       priv->effects->actor = self;
3103     }
3104
3105   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3106 }
3107
3108 /* This is the same as clutter_actor_remove_effect except that it doesn't
3109    queue a redraw and it doesn't notify on the effect property */
3110 static void
3111 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3112                                        ClutterEffect *effect)
3113 {
3114   ClutterActorPrivate *priv = self->priv;
3115
3116   if (priv->effects == NULL)
3117     return;
3118
3119   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3120 }
3121
3122 static gboolean
3123 needs_flatten_effect (ClutterActor *self)
3124 {
3125   ClutterActorPrivate *priv = self->priv;
3126
3127   if (G_UNLIKELY (clutter_paint_debug_flags &
3128                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3129     return FALSE;
3130
3131   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3132     return TRUE;
3133   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3134     {
3135       if (clutter_actor_get_paint_opacity (self) < 255 &&
3136           clutter_actor_has_overlaps (self))
3137         return TRUE;
3138     }
3139
3140   return FALSE;
3141 }
3142
3143 static void
3144 add_or_remove_flatten_effect (ClutterActor *self)
3145 {
3146   ClutterActorPrivate *priv = self->priv;
3147
3148   /* Add or remove the flatten effect depending on the
3149      offscreen-redirect property. */
3150   if (needs_flatten_effect (self))
3151     {
3152       if (priv->flatten_effect == NULL)
3153         {
3154           ClutterActorMeta *actor_meta;
3155           gint priority;
3156
3157           priv->flatten_effect = _clutter_flatten_effect_new ();
3158           /* Keep a reference to the effect so that we can queue
3159              redraws from it */
3160           g_object_ref_sink (priv->flatten_effect);
3161
3162           /* Set the priority of the effect to high so that it will
3163              always be applied to the actor first. It uses an internal
3164              priority so that it won't be visible to applications */
3165           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3166           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3167           _clutter_actor_meta_set_priority (actor_meta, priority);
3168
3169           /* This will add the effect without queueing a redraw */
3170           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3171         }
3172     }
3173   else
3174     {
3175       if (priv->flatten_effect != NULL)
3176         {
3177           /* Destroy the effect so that it will lose its fbo cache of
3178              the actor */
3179           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3180           g_object_unref (priv->flatten_effect);
3181           priv->flatten_effect = NULL;
3182         }
3183     }
3184 }
3185
3186 static void
3187 clutter_actor_real_paint (ClutterActor *actor)
3188 {
3189   ClutterActorPrivate *priv = actor->priv;
3190   ClutterActor *iter;
3191
3192   for (iter = priv->first_child;
3193        iter != NULL;
3194        iter = iter->priv->next_sibling)
3195     {
3196       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3197                     _clutter_actor_get_debug_name (iter),
3198                     _clutter_actor_get_debug_name (actor),
3199                     iter->priv->allocation.x1,
3200                     iter->priv->allocation.y1,
3201                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3202                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3203
3204       clutter_actor_paint (iter);
3205     }
3206 }
3207
3208 static gboolean
3209 clutter_actor_paint_node (ClutterActor     *actor,
3210                           ClutterPaintNode *root)
3211 {
3212   ClutterActorPrivate *priv = actor->priv;
3213
3214   if (root == NULL)
3215     return FALSE;
3216
3217   if (priv->bg_color_set &&
3218       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3219     {
3220       ClutterPaintNode *node;
3221       ClutterColor bg_color;
3222       ClutterActorBox box;
3223
3224       box.x1 = 0.f;
3225       box.y1 = 0.f;
3226       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3227       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3228
3229       bg_color = priv->bg_color;
3230       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3231                      * priv->bg_color.alpha
3232                      / 255;
3233
3234       node = clutter_color_node_new (&bg_color);
3235       clutter_paint_node_set_name (node, "backgroundColor");
3236       clutter_paint_node_add_rectangle (node, &box);
3237       clutter_paint_node_add_child (root, node);
3238       clutter_paint_node_unref (node);
3239     }
3240
3241   if (priv->content != NULL)
3242     _clutter_content_paint_content (priv->content, actor, root);
3243
3244   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3245     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3246
3247   if (clutter_paint_node_get_n_children (root) == 0)
3248     return FALSE;
3249
3250 #ifdef CLUTTER_ENABLE_DEBUG
3251   if (CLUTTER_HAS_DEBUG (PAINT))
3252     {
3253       /* dump the tree only if we have one */
3254       _clutter_paint_node_dump_tree (root);
3255     }
3256 #endif /* CLUTTER_ENABLE_DEBUG */
3257
3258   _clutter_paint_node_paint (root);
3259
3260   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3261
3262   return TRUE;
3263 }
3264
3265 /**
3266  * clutter_actor_paint:
3267  * @self: A #ClutterActor
3268  *
3269  * Renders the actor to display.
3270  *
3271  * This function should not be called directly by applications.
3272  * Call clutter_actor_queue_redraw() to queue paints, instead.
3273  *
3274  * This function is context-aware, and will either cause a
3275  * regular paint or a pick paint.
3276  *
3277  * This function will emit the #ClutterActor::paint signal or
3278  * the #ClutterActor::pick signal, depending on the context.
3279  *
3280  * This function does not paint the actor if the actor is set to 0,
3281  * unless it is performing a pick paint.
3282  */
3283 void
3284 clutter_actor_paint (ClutterActor *self)
3285 {
3286   ClutterActorPrivate *priv;
3287   ClutterPickMode pick_mode;
3288   gboolean clip_set = FALSE;
3289   gboolean shader_applied = FALSE;
3290
3291   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3292                           "Actor real-paint counter",
3293                           "Increments each time any actor is painted",
3294                           0 /* no application private data */);
3295   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3296                           "Actor pick-paint counter",
3297                           "Increments each time any actor is painted "
3298                           "for picking",
3299                           0 /* no application private data */);
3300
3301   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3302
3303   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3304     return;
3305
3306   priv = self->priv;
3307
3308   pick_mode = _clutter_context_get_pick_mode ();
3309
3310   if (pick_mode == CLUTTER_PICK_NONE)
3311     priv->propagated_one_redraw = FALSE;
3312
3313   /* It's an important optimization that we consider painting of
3314    * actors with 0 opacity to be a NOP... */
3315   if (pick_mode == CLUTTER_PICK_NONE &&
3316       /* ignore top-levels, since they might be transparent */
3317       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3318       /* Use the override opacity if its been set */
3319       ((priv->opacity_override >= 0) ?
3320        priv->opacity_override : priv->opacity) == 0)
3321     return;
3322
3323   /* if we aren't paintable (not in a toplevel with all
3324    * parents paintable) then do nothing.
3325    */
3326   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3327     return;
3328
3329   /* mark that we are in the paint process */
3330   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3331
3332   cogl_push_matrix();
3333
3334   if (priv->enable_model_view_transform)
3335     {
3336       CoglMatrix matrix;
3337
3338       /* XXX: It could be better to cache the modelview with the actor
3339        * instead of progressively building up the transformations on
3340        * the matrix stack every time we paint. */
3341       cogl_get_modelview_matrix (&matrix);
3342       _clutter_actor_apply_modelview_transform (self, &matrix);
3343
3344 #ifdef CLUTTER_ENABLE_DEBUG
3345       /* Catch when out-of-band transforms have been made by actors not as part
3346        * of an apply_transform vfunc... */
3347       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3348         {
3349           CoglMatrix expected_matrix;
3350
3351           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3352                                                              &expected_matrix);
3353
3354           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3355             {
3356               GString *buf = g_string_sized_new (1024);
3357               ClutterActor *parent;
3358
3359               parent = self;
3360               while (parent != NULL)
3361                 {
3362                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3363
3364                   if (parent->priv->parent != NULL)
3365                     g_string_append (buf, "->");
3366
3367                   parent = parent->priv->parent;
3368                 }
3369
3370               g_warning ("Unexpected transform found when painting actor "
3371                          "\"%s\". This will be caused by one of the actor's "
3372                          "ancestors (%s) using the Cogl API directly to transform "
3373                          "children instead of using ::apply_transform().",
3374                          _clutter_actor_get_debug_name (self),
3375                          buf->str);
3376
3377               g_string_free (buf, TRUE);
3378             }
3379         }
3380 #endif /* CLUTTER_ENABLE_DEBUG */
3381
3382       cogl_set_modelview_matrix (&matrix);
3383     }
3384
3385   if (priv->has_clip)
3386     {
3387       cogl_clip_push_rectangle (priv->clip.x,
3388                                 priv->clip.y,
3389                                 priv->clip.x + priv->clip.width,
3390                                 priv->clip.y + priv->clip.height);
3391       clip_set = TRUE;
3392     }
3393   else if (priv->clip_to_allocation)
3394     {
3395       gfloat width, height;
3396
3397       width  = priv->allocation.x2 - priv->allocation.x1;
3398       height = priv->allocation.y2 - priv->allocation.y1;
3399
3400       cogl_clip_push_rectangle (0, 0, width, height);
3401       clip_set = TRUE;
3402     }
3403
3404   if (pick_mode == CLUTTER_PICK_NONE)
3405     {
3406       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3407
3408       /* We check whether we need to add the flatten effect before
3409          each paint so that we can avoid having a mechanism for
3410          applications to notify when the value of the
3411          has_overlaps virtual changes. */
3412       add_or_remove_flatten_effect (self);
3413     }
3414   else
3415     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3416
3417   /* We save the current paint volume so that the next time the
3418    * actor queues a redraw we can constrain the redraw to just
3419    * cover the union of the new bounding box and the old.
3420    *
3421    * We also fetch the current paint volume to perform culling so
3422    * we can avoid painting actors outside the current clip region.
3423    *
3424    * If we are painting inside a clone, we should neither update
3425    * the paint volume or use it to cull painting, since the paint
3426    * box represents the location of the source actor on the
3427    * screen.
3428    *
3429    * XXX: We are starting to do a lot of vertex transforms on
3430    * the CPU in a typical paint, so at some point we should
3431    * audit these and consider caching some things.
3432    *
3433    * NB: We don't perform culling while picking at this point because
3434    * clutter-stage.c doesn't setup the clipping planes appropriately.
3435    *
3436    * NB: We don't want to update the last-paint-volume during picking
3437    * because the last-paint-volume is used to determine the old screen
3438    * space location of an actor that has moved so we can know the
3439    * minimal region to redraw to clear an old view of the actor. If we
3440    * update this during picking then by the time we come around to
3441    * paint then the last-paint-volume would likely represent the new
3442    * actor position not the old.
3443    */
3444   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3445     {
3446       gboolean success;
3447       /* annoyingly gcc warns if uninitialized even though
3448        * the initialization is redundant :-( */
3449       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3450
3451       if (G_LIKELY ((clutter_paint_debug_flags &
3452                      (CLUTTER_DEBUG_DISABLE_CULLING |
3453                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3454                     (CLUTTER_DEBUG_DISABLE_CULLING |
3455                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3456         _clutter_actor_update_last_paint_volume (self);
3457
3458       success = cull_actor (self, &result);
3459
3460       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3461         _clutter_actor_paint_cull_result (self, success, result);
3462       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3463         goto done;
3464     }
3465
3466   if (priv->effects == NULL)
3467     {
3468       if (pick_mode == CLUTTER_PICK_NONE &&
3469           actor_has_shader_data (self))
3470         {
3471           _clutter_actor_shader_pre_paint (self, FALSE);
3472           shader_applied = TRUE;
3473         }
3474
3475       priv->next_effect_to_paint = NULL;
3476     }
3477   else
3478     priv->next_effect_to_paint =
3479       _clutter_meta_group_peek_metas (priv->effects);
3480
3481   clutter_actor_continue_paint (self);
3482
3483   if (shader_applied)
3484     _clutter_actor_shader_post_paint (self);
3485
3486   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3487                   pick_mode == CLUTTER_PICK_NONE))
3488     _clutter_actor_draw_paint_volume (self);
3489
3490 done:
3491   /* If we make it here then the actor has run through a complete
3492      paint run including all the effects so it's no longer dirty */
3493   if (pick_mode == CLUTTER_PICK_NONE)
3494     priv->is_dirty = FALSE;
3495
3496   if (clip_set)
3497     cogl_clip_pop();
3498
3499   cogl_pop_matrix();
3500
3501   /* paint sequence complete */
3502   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3503 }
3504
3505 /**
3506  * clutter_actor_continue_paint:
3507  * @self: A #ClutterActor
3508  *
3509  * Run the next stage of the paint sequence. This function should only
3510  * be called within the implementation of the ‘run’ virtual of a
3511  * #ClutterEffect. It will cause the run method of the next effect to
3512  * be applied, or it will paint the actual actor if the current effect
3513  * is the last effect in the chain.
3514  *
3515  * Since: 1.8
3516  */
3517 void
3518 clutter_actor_continue_paint (ClutterActor *self)
3519 {
3520   ClutterActorPrivate *priv;
3521
3522   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3523   /* This should only be called from with in the ‘run’ implementation
3524      of a ClutterEffect */
3525   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3526
3527   priv = self->priv;
3528
3529   /* Skip any effects that are disabled */
3530   while (priv->next_effect_to_paint &&
3531          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3532     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3533
3534   /* If this has come from the last effect then we'll just paint the
3535      actual actor */
3536   if (priv->next_effect_to_paint == NULL)
3537     {
3538       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3539         {
3540           ClutterPaintNode *dummy;
3541           gboolean emit_paint;
3542
3543           /* XXX - this will go away in 2.0, when we can get rid of this
3544            * stuff and switch to a pure retained render tree of PaintNodes
3545            * for the entire frame, starting from the Stage.
3546            */
3547           dummy = _clutter_dummy_node_new ();
3548           clutter_paint_node_set_name (dummy, "Root");
3549           emit_paint = !clutter_actor_paint_node (self, dummy);
3550           clutter_paint_node_unref (dummy);
3551
3552           if (emit_paint || CLUTTER_ACTOR_IS_TOPLEVEL (self))
3553             g_signal_emit (self, actor_signals[PAINT], 0);
3554           else
3555             {
3556               CLUTTER_NOTE (PAINT, "The actor '%s' painted using PaintNodes, "
3557                                    "skipping the emission of the paint signal.",
3558                                    _clutter_actor_get_debug_name (self));
3559             }
3560         }
3561       else
3562         {
3563           ClutterColor col = { 0, };
3564
3565           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3566
3567           /* Actor will then paint silhouette of itself in supplied
3568            * color.  See clutter_stage_get_actor_at_pos() for where
3569            * picking is enabled.
3570            */
3571           g_signal_emit (self, actor_signals[PICK], 0, &col);
3572         }
3573     }
3574   else
3575     {
3576       ClutterEffect *old_current_effect;
3577       ClutterEffectPaintFlags run_flags = 0;
3578
3579       /* Cache the current effect so that we can put it back before
3580          returning */
3581       old_current_effect = priv->current_effect;
3582
3583       priv->current_effect = priv->next_effect_to_paint->data;
3584       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3585
3586       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3587         {
3588           if (priv->is_dirty)
3589             {
3590               /* If there's an effect queued with this redraw then all
3591                  effects up to that one will be considered dirty. It
3592                  is expected the queued effect will paint the cached
3593                  image and not call clutter_actor_continue_paint again
3594                  (although it should work ok if it does) */
3595               if (priv->effect_to_redraw == NULL ||
3596                   priv->current_effect != priv->effect_to_redraw)
3597                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3598             }
3599
3600           _clutter_effect_paint (priv->current_effect, run_flags);
3601         }
3602       else
3603         {
3604           /* We can't determine when an actor has been modified since
3605              its last pick so lets just assume it has always been
3606              modified */
3607           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3608
3609           _clutter_effect_pick (priv->current_effect, run_flags);
3610         }
3611
3612       priv->current_effect = old_current_effect;
3613     }
3614 }
3615
3616 static ClutterActorTraverseVisitFlags
3617 invalidate_queue_redraw_entry (ClutterActor *self,
3618                                int           depth,
3619                                gpointer      user_data)
3620 {
3621   ClutterActorPrivate *priv = self->priv;
3622
3623   if (priv->queue_redraw_entry != NULL)
3624     {
3625       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3626       priv->queue_redraw_entry = NULL;
3627     }
3628
3629   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3630 }
3631
3632 static inline void
3633 remove_child (ClutterActor *self,
3634               ClutterActor *child)
3635 {
3636   ClutterActor *prev_sibling, *next_sibling;
3637
3638   prev_sibling = child->priv->prev_sibling;
3639   next_sibling = child->priv->next_sibling;
3640
3641   if (prev_sibling != NULL)
3642     prev_sibling->priv->next_sibling = next_sibling;
3643
3644   if (next_sibling != NULL)
3645     next_sibling->priv->prev_sibling = prev_sibling;
3646
3647   if (self->priv->first_child == child)
3648     self->priv->first_child = next_sibling;
3649
3650   if (self->priv->last_child == child)
3651     self->priv->last_child = prev_sibling;
3652
3653   child->priv->parent = NULL;
3654   child->priv->prev_sibling = NULL;
3655   child->priv->next_sibling = NULL;
3656 }
3657
3658 typedef enum {
3659   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3660   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3661   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3662   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3663   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3664   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3665
3666   /* default flags for public API */
3667   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3668                                     REMOVE_CHILD_EMIT_PARENT_SET |
3669                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3670                                     REMOVE_CHILD_CHECK_STATE |
3671                                     REMOVE_CHILD_FLUSH_QUEUE |
3672                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3673
3674   /* flags for legacy/deprecated API */
3675   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3676                                     REMOVE_CHILD_FLUSH_QUEUE |
3677                                     REMOVE_CHILD_EMIT_PARENT_SET |
3678                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3679 } ClutterActorRemoveChildFlags;
3680
3681 /*< private >
3682  * clutter_actor_remove_child_internal:
3683  * @self: a #ClutterActor
3684  * @child: the child of @self that has to be removed
3685  * @flags: control the removal operations
3686  *
3687  * Removes @child from the list of children of @self.
3688  */
3689 static void
3690 clutter_actor_remove_child_internal (ClutterActor                 *self,
3691                                      ClutterActor                 *child,
3692                                      ClutterActorRemoveChildFlags  flags)
3693 {
3694   ClutterActor *old_first, *old_last;
3695   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3696   gboolean flush_queue;
3697   gboolean notify_first_last;
3698   gboolean was_mapped;
3699
3700   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3701   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3702   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3703   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3704   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3705   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3706
3707   g_object_freeze_notify (G_OBJECT (self));
3708
3709   if (destroy_meta)
3710     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3711
3712   if (check_state)
3713     {
3714       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3715
3716       /* we need to unrealize *before* we set parent_actor to NULL,
3717        * because in an unrealize method actors are dissociating from the
3718        * stage, which means they need to be able to
3719        * clutter_actor_get_stage().
3720        *
3721        * yhis should unmap and unrealize, unless we're reparenting.
3722        */
3723       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3724     }
3725   else
3726     was_mapped = FALSE;
3727
3728   if (flush_queue)
3729     {
3730       /* We take this opportunity to invalidate any queue redraw entry
3731        * associated with the actor and descendants since we won't be able to
3732        * determine the appropriate stage after this.
3733        *
3734        * we do this after we updated the mapped state because actors might
3735        * end up queueing redraws inside their mapped/unmapped virtual
3736        * functions, and if we invalidate the redraw entry we could end up
3737        * with an inconsistent state and weird memory corruption. see
3738        * bugs:
3739        *
3740        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3741        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3742        */
3743       _clutter_actor_traverse (child,
3744                                0,
3745                                invalidate_queue_redraw_entry,
3746                                NULL,
3747                                NULL);
3748     }
3749
3750   old_first = self->priv->first_child;
3751   old_last = self->priv->last_child;
3752
3753   remove_child (self, child);
3754
3755   self->priv->n_children -= 1;
3756
3757   self->priv->age += 1;
3758
3759   /* clutter_actor_reparent() will emit ::parent-set for us */
3760   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3761     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3762
3763   /* if the child was mapped then we need to relayout ourselves to account
3764    * for the removed child
3765    */
3766   if (was_mapped)
3767     clutter_actor_queue_relayout (self);
3768
3769   /* we need to emit the signal before dropping the reference */
3770   if (emit_actor_removed)
3771     g_signal_emit_by_name (self, "actor-removed", child);
3772
3773   if (notify_first_last)
3774     {
3775       if (old_first != self->priv->first_child)
3776         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3777
3778       if (old_last != self->priv->last_child)
3779         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3780     }
3781
3782   g_object_thaw_notify (G_OBJECT (self));
3783
3784   /* remove the reference we acquired in clutter_actor_add_child() */
3785   g_object_unref (child);
3786 }
3787
3788 static const ClutterTransformInfo default_transform_info = {
3789   0.0, { 0, },          /* rotation-x */
3790   0.0, { 0, },          /* rotation-y */
3791   0.0, { 0, },          /* rotation-z */
3792
3793   1.0, 1.0, { 0, },     /* scale */
3794
3795   { 0, },               /* anchor */
3796
3797   0.0,                  /* depth */
3798 };
3799
3800 /*< private >
3801  * _clutter_actor_get_transform_info_or_defaults:
3802  * @self: a #ClutterActor
3803  *
3804  * Retrieves the ClutterTransformInfo structure associated to an actor.
3805  *
3806  * If the actor does not have a ClutterTransformInfo structure associated
3807  * to it, then the default structure will be returned.
3808  *
3809  * This function should only be used for getters.
3810  *
3811  * Return value: a const pointer to the ClutterTransformInfo structure
3812  */
3813 const ClutterTransformInfo *
3814 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3815 {
3816   ClutterTransformInfo *info;
3817
3818   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3819   if (info != NULL)
3820     return info;
3821
3822   return &default_transform_info;
3823 }
3824
3825 static void
3826 clutter_transform_info_free (gpointer data)
3827 {
3828   if (data != NULL)
3829     g_slice_free (ClutterTransformInfo, data);
3830 }
3831
3832 /*< private >
3833  * _clutter_actor_get_transform_info:
3834  * @self: a #ClutterActor
3835  *
3836  * Retrieves a pointer to the ClutterTransformInfo structure.
3837  *
3838  * If the actor does not have a ClutterTransformInfo associated to it, one
3839  * will be created and initialized to the default values.
3840  *
3841  * This function should be used for setters.
3842  *
3843  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3844  * instead.
3845  *
3846  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3847  *   structure
3848  */
3849 ClutterTransformInfo *
3850 _clutter_actor_get_transform_info (ClutterActor *self)
3851 {
3852   ClutterTransformInfo *info;
3853
3854   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3855   if (info == NULL)
3856     {
3857       info = g_slice_new (ClutterTransformInfo);
3858
3859       *info = default_transform_info;
3860
3861       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3862                                info,
3863                                clutter_transform_info_free);
3864     }
3865
3866   return info;
3867 }
3868
3869 /*< private >
3870  * clutter_actor_set_rotation_angle_internal:
3871  * @self: a #ClutterActor
3872  * @axis: the axis of the angle to change
3873  * @angle: the angle of rotation
3874  *
3875  * Sets the rotation angle on the given axis without affecting the
3876  * rotation center point.
3877  */
3878 static inline void
3879 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3880                                            ClutterRotateAxis  axis,
3881                                            gdouble            angle)
3882 {
3883   GObject *obj = G_OBJECT (self);
3884   ClutterTransformInfo *info;
3885
3886   info = _clutter_actor_get_transform_info (self);
3887
3888   g_object_freeze_notify (obj);
3889
3890   switch (axis)
3891     {
3892     case CLUTTER_X_AXIS:
3893       info->rx_angle = angle;
3894       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3895       break;
3896
3897     case CLUTTER_Y_AXIS:
3898       info->ry_angle = angle;
3899       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3900       break;
3901
3902     case CLUTTER_Z_AXIS:
3903       info->rz_angle = angle;
3904       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3905       break;
3906     }
3907
3908   self->priv->transform_valid = FALSE;
3909
3910   g_object_thaw_notify (obj);
3911
3912   clutter_actor_queue_redraw (self);
3913 }
3914
3915 static inline void
3916 clutter_actor_set_rotation_angle (ClutterActor      *self,
3917                                   ClutterRotateAxis  axis,
3918                                   gdouble            angle)
3919 {
3920   ClutterTransformInfo *info;
3921
3922   info = _clutter_actor_get_transform_info (self);
3923
3924   if (clutter_actor_get_easing_duration (self) != 0)
3925     {
3926       ClutterTransition *transition;
3927       GParamSpec *pspec = NULL;
3928       double *cur_angle_p = NULL;
3929
3930       switch (axis)
3931         {
3932         case CLUTTER_X_AXIS:
3933           cur_angle_p = &info->rx_angle;
3934           pspec = obj_props[PROP_ROTATION_ANGLE_X];
3935           break;
3936
3937         case CLUTTER_Y_AXIS:
3938           cur_angle_p = &info->ry_angle;
3939           pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3940           break;
3941
3942         case CLUTTER_Z_AXIS:
3943           cur_angle_p = &info->rz_angle;
3944           pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3945           break;
3946         }
3947
3948       g_assert (pspec != NULL);
3949       g_assert (cur_angle_p != NULL);
3950
3951       transition = _clutter_actor_get_transition (self, pspec);
3952       if (transition == NULL)
3953         {
3954           transition = _clutter_actor_create_transition (self, pspec,
3955                                                          *cur_angle_p,
3956                                                          angle);
3957           clutter_timeline_start (CLUTTER_TIMELINE (transition));
3958         }
3959       else
3960         _clutter_actor_update_transition (self, pspec, angle);
3961
3962       self->priv->transform_valid = FALSE;
3963       clutter_actor_queue_redraw (self);
3964     }
3965   else
3966     clutter_actor_set_rotation_angle_internal (self, axis, angle);
3967 }
3968
3969 /*< private >
3970  * clutter_actor_set_rotation_center_internal:
3971  * @self: a #ClutterActor
3972  * @axis: the axis of the center to change
3973  * @center: the coordinates of the rotation center
3974  *
3975  * Sets the rotation center on the given axis without affecting the
3976  * rotation angle.
3977  */
3978 static inline void
3979 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3980                                             ClutterRotateAxis    axis,
3981                                             const ClutterVertex *center)
3982 {
3983   GObject *obj = G_OBJECT (self);
3984   ClutterTransformInfo *info;
3985   ClutterVertex v = { 0, 0, 0 };
3986
3987   info = _clutter_actor_get_transform_info (self);
3988
3989   if (center != NULL)
3990     v = *center;
3991
3992   g_object_freeze_notify (obj);
3993
3994   switch (axis)
3995     {
3996     case CLUTTER_X_AXIS:
3997       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3998       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3999       break;
4000
4001     case CLUTTER_Y_AXIS:
4002       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4003       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4004       break;
4005
4006     case CLUTTER_Z_AXIS:
4007       /* if the previously set rotation center was fractional, then
4008        * setting explicit coordinates will have to notify the
4009        * :rotation-center-z-gravity property as well
4010        */
4011       if (info->rz_center.is_fractional)
4012         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4013
4014       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4015       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4016       break;
4017     }
4018
4019   self->priv->transform_valid = FALSE;
4020
4021   g_object_thaw_notify (obj);
4022
4023   clutter_actor_queue_redraw (self);
4024 }
4025
4026 static void
4027 clutter_actor_animate_scale_factor (ClutterActor *self,
4028                                     double        old_factor,
4029                                     double        new_factor,
4030                                     GParamSpec   *pspec)
4031 {
4032   ClutterTransition *transition;
4033
4034   transition = _clutter_actor_get_transition (self, pspec);
4035   if (transition == NULL)
4036     {
4037       transition = _clutter_actor_create_transition (self, pspec,
4038                                                      old_factor,
4039                                                      new_factor);
4040       clutter_timeline_start (CLUTTER_TIMELINE (transition));
4041     }
4042   else
4043     _clutter_actor_update_transition (self, pspec, new_factor);
4044
4045
4046   self->priv->transform_valid = FALSE;
4047   clutter_actor_queue_redraw (self);
4048 }
4049
4050 static void
4051 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4052                                          double factor,
4053                                          GParamSpec *pspec)
4054 {
4055   GObject *obj = G_OBJECT (self);
4056   ClutterTransformInfo *info;
4057
4058   info = _clutter_actor_get_transform_info (self);
4059
4060   if (pspec == obj_props[PROP_SCALE_X])
4061     info->scale_x = factor;
4062   else
4063     info->scale_y = factor;
4064
4065   self->priv->transform_valid = FALSE;
4066   clutter_actor_queue_redraw (self);
4067   g_object_notify_by_pspec (obj, pspec);
4068 }
4069
4070 static inline void
4071 clutter_actor_set_scale_factor (ClutterActor      *self,
4072                                 ClutterRotateAxis  axis,
4073                                 gdouble            factor)
4074 {
4075   GObject *obj = G_OBJECT (self);
4076   ClutterTransformInfo *info;
4077   GParamSpec *pspec;
4078
4079   info = _clutter_actor_get_transform_info (self);
4080
4081   g_object_freeze_notify (obj);
4082
4083   switch (axis)
4084     {
4085     case CLUTTER_X_AXIS:
4086       pspec = obj_props[PROP_SCALE_X];
4087
4088       if (clutter_actor_get_easing_duration (self) != 0)
4089         clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
4090       else
4091         clutter_actor_set_scale_factor_internal (self, factor, pspec);
4092       break;
4093
4094     case CLUTTER_Y_AXIS:
4095       pspec = obj_props[PROP_SCALE_Y];
4096
4097       if (clutter_actor_get_easing_duration (self) != 0)
4098         clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4099       else
4100         clutter_actor_set_scale_factor_internal (self, factor, pspec);
4101       break;
4102
4103     default:
4104       g_assert_not_reached ();
4105     }
4106
4107   g_object_thaw_notify (obj);
4108 }
4109
4110 static inline void
4111 clutter_actor_set_scale_center (ClutterActor      *self,
4112                                 ClutterRotateAxis  axis,
4113                                 gfloat             coord)
4114 {
4115   GObject *obj = G_OBJECT (self);
4116   ClutterTransformInfo *info;
4117   gfloat center_x, center_y;
4118
4119   info = _clutter_actor_get_transform_info (self);
4120
4121   g_object_freeze_notify (obj);
4122
4123   /* get the current scale center coordinates */
4124   clutter_anchor_coord_get_units (self, &info->scale_center,
4125                                   &center_x,
4126                                   &center_y,
4127                                   NULL);
4128
4129   /* we need to notify this too, because setting explicit coordinates will
4130    * change the gravity as a side effect
4131    */
4132   if (info->scale_center.is_fractional)
4133     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4134
4135   switch (axis)
4136     {
4137     case CLUTTER_X_AXIS:
4138       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4139       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4140       break;
4141
4142     case CLUTTER_Y_AXIS:
4143       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4144       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4145       break;
4146
4147     default:
4148       g_assert_not_reached ();
4149     }
4150
4151   self->priv->transform_valid = FALSE;
4152
4153   clutter_actor_queue_redraw (self);
4154
4155   g_object_thaw_notify (obj);
4156 }
4157
4158 static inline void
4159 clutter_actor_set_anchor_coord (ClutterActor      *self,
4160                                 ClutterRotateAxis  axis,
4161                                 gfloat             coord)
4162 {
4163   GObject *obj = G_OBJECT (self);
4164   ClutterTransformInfo *info;
4165   gfloat anchor_x, anchor_y;
4166
4167   info = _clutter_actor_get_transform_info (self);
4168
4169   g_object_freeze_notify (obj);
4170
4171   clutter_anchor_coord_get_units (self, &info->anchor,
4172                                   &anchor_x,
4173                                   &anchor_y,
4174                                   NULL);
4175
4176   if (info->anchor.is_fractional)
4177     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4178
4179   switch (axis)
4180     {
4181     case CLUTTER_X_AXIS:
4182       clutter_anchor_coord_set_units (&info->anchor,
4183                                       coord,
4184                                       anchor_y,
4185                                       0.0);
4186       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4187       break;
4188
4189     case CLUTTER_Y_AXIS:
4190       clutter_anchor_coord_set_units (&info->anchor,
4191                                       anchor_x,
4192                                       coord,
4193                                       0.0);
4194       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4195       break;
4196
4197     default:
4198       g_assert_not_reached ();
4199     }
4200
4201   self->priv->transform_valid = FALSE;
4202
4203   clutter_actor_queue_redraw (self);
4204
4205   g_object_thaw_notify (obj);
4206 }
4207
4208 static void
4209 clutter_actor_set_property (GObject      *object,
4210                             guint         prop_id,
4211                             const GValue *value,
4212                             GParamSpec   *pspec)
4213 {
4214   ClutterActor *actor = CLUTTER_ACTOR (object);
4215   ClutterActorPrivate *priv = actor->priv;
4216
4217   switch (prop_id)
4218     {
4219     case PROP_X:
4220       clutter_actor_set_x (actor, g_value_get_float (value));
4221       break;
4222
4223     case PROP_Y:
4224       clutter_actor_set_y (actor, g_value_get_float (value));
4225       break;
4226
4227     case PROP_WIDTH:
4228       clutter_actor_set_width (actor, g_value_get_float (value));
4229       break;
4230
4231     case PROP_HEIGHT:
4232       clutter_actor_set_height (actor, g_value_get_float (value));
4233       break;
4234
4235     case PROP_FIXED_X:
4236       clutter_actor_set_x (actor, g_value_get_float (value));
4237       break;
4238
4239     case PROP_FIXED_Y:
4240       clutter_actor_set_y (actor, g_value_get_float (value));
4241       break;
4242
4243     case PROP_FIXED_POSITION_SET:
4244       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4245       break;
4246
4247     case PROP_MIN_WIDTH:
4248       clutter_actor_set_min_width (actor, g_value_get_float (value));
4249       break;
4250
4251     case PROP_MIN_HEIGHT:
4252       clutter_actor_set_min_height (actor, g_value_get_float (value));
4253       break;
4254
4255     case PROP_NATURAL_WIDTH:
4256       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4257       break;
4258
4259     case PROP_NATURAL_HEIGHT:
4260       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4261       break;
4262
4263     case PROP_MIN_WIDTH_SET:
4264       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4265       break;
4266
4267     case PROP_MIN_HEIGHT_SET:
4268       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4269       break;
4270
4271     case PROP_NATURAL_WIDTH_SET:
4272       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4273       break;
4274
4275     case PROP_NATURAL_HEIGHT_SET:
4276       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4277       break;
4278
4279     case PROP_REQUEST_MODE:
4280       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4281       break;
4282
4283     case PROP_DEPTH:
4284       clutter_actor_set_depth (actor, g_value_get_float (value));
4285       break;
4286
4287     case PROP_OPACITY:
4288       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4289       break;
4290
4291     case PROP_OFFSCREEN_REDIRECT:
4292       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4293       break;
4294
4295     case PROP_NAME:
4296       clutter_actor_set_name (actor, g_value_get_string (value));
4297       break;
4298
4299     case PROP_VISIBLE:
4300       if (g_value_get_boolean (value) == TRUE)
4301         clutter_actor_show (actor);
4302       else
4303         clutter_actor_hide (actor);
4304       break;
4305
4306     case PROP_SCALE_X:
4307       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4308                                       g_value_get_double (value));
4309       break;
4310
4311     case PROP_SCALE_Y:
4312       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4313                                       g_value_get_double (value));
4314       break;
4315
4316     case PROP_SCALE_CENTER_X:
4317       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4318                                       g_value_get_float (value));
4319       break;
4320
4321     case PROP_SCALE_CENTER_Y:
4322       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4323                                       g_value_get_float (value));
4324       break;
4325
4326     case PROP_SCALE_GRAVITY:
4327       {
4328         const ClutterTransformInfo *info;
4329         ClutterGravity gravity;
4330
4331         info = _clutter_actor_get_transform_info_or_defaults (actor);
4332         gravity = g_value_get_enum (value);
4333
4334         clutter_actor_set_scale_with_gravity (actor,
4335                                               info->scale_x,
4336                                               info->scale_y,
4337                                               gravity);
4338       }
4339       break;
4340
4341     case PROP_CLIP:
4342       {
4343         const ClutterGeometry *geom = g_value_get_boxed (value);
4344
4345         clutter_actor_set_clip (actor,
4346                                 geom->x, geom->y,
4347                                 geom->width, geom->height);
4348       }
4349       break;
4350
4351     case PROP_CLIP_TO_ALLOCATION:
4352       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4353       break;
4354
4355     case PROP_REACTIVE:
4356       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4357       break;
4358
4359     case PROP_ROTATION_ANGLE_X:
4360       clutter_actor_set_rotation_angle (actor,
4361                                         CLUTTER_X_AXIS,
4362                                         g_value_get_double (value));
4363       break;
4364
4365     case PROP_ROTATION_ANGLE_Y:
4366       clutter_actor_set_rotation_angle (actor,
4367                                         CLUTTER_Y_AXIS,
4368                                         g_value_get_double (value));
4369       break;
4370
4371     case PROP_ROTATION_ANGLE_Z:
4372       clutter_actor_set_rotation_angle (actor,
4373                                         CLUTTER_Z_AXIS,
4374                                         g_value_get_double (value));
4375       break;
4376
4377     case PROP_ROTATION_CENTER_X:
4378       clutter_actor_set_rotation_center_internal (actor,
4379                                                   CLUTTER_X_AXIS,
4380                                                   g_value_get_boxed (value));
4381       break;
4382
4383     case PROP_ROTATION_CENTER_Y:
4384       clutter_actor_set_rotation_center_internal (actor,
4385                                                   CLUTTER_Y_AXIS,
4386                                                   g_value_get_boxed (value));
4387       break;
4388
4389     case PROP_ROTATION_CENTER_Z:
4390       clutter_actor_set_rotation_center_internal (actor,
4391                                                   CLUTTER_Z_AXIS,
4392                                                   g_value_get_boxed (value));
4393       break;
4394
4395     case PROP_ROTATION_CENTER_Z_GRAVITY:
4396       {
4397         const ClutterTransformInfo *info;
4398
4399         info = _clutter_actor_get_transform_info_or_defaults (actor);
4400         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4401                                                    g_value_get_enum (value));
4402       }
4403       break;
4404
4405     case PROP_ANCHOR_X:
4406       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4407                                       g_value_get_float (value));
4408       break;
4409
4410     case PROP_ANCHOR_Y:
4411       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4412                                       g_value_get_float (value));
4413       break;
4414
4415     case PROP_ANCHOR_GRAVITY:
4416       clutter_actor_set_anchor_point_from_gravity (actor,
4417                                                    g_value_get_enum (value));
4418       break;
4419
4420     case PROP_SHOW_ON_SET_PARENT:
4421       priv->show_on_set_parent = g_value_get_boolean (value);
4422       break;
4423
4424     case PROP_TEXT_DIRECTION:
4425       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4426       break;
4427
4428     case PROP_ACTIONS:
4429       clutter_actor_add_action (actor, g_value_get_object (value));
4430       break;
4431
4432     case PROP_CONSTRAINTS:
4433       clutter_actor_add_constraint (actor, g_value_get_object (value));
4434       break;
4435
4436     case PROP_EFFECT:
4437       clutter_actor_add_effect (actor, g_value_get_object (value));
4438       break;
4439
4440     case PROP_LAYOUT_MANAGER:
4441       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4442       break;
4443
4444     case PROP_X_ALIGN:
4445       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4446       break;
4447
4448     case PROP_Y_ALIGN:
4449       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4450       break;
4451
4452     case PROP_MARGIN_TOP:
4453       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4454       break;
4455
4456     case PROP_MARGIN_BOTTOM:
4457       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4458       break;
4459
4460     case PROP_MARGIN_LEFT:
4461       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4462       break;
4463
4464     case PROP_MARGIN_RIGHT:
4465       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4466       break;
4467
4468     case PROP_BACKGROUND_COLOR:
4469       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4470       break;
4471
4472     case PROP_CONTENT:
4473       clutter_actor_set_content (actor, g_value_get_object (value));
4474       break;
4475
4476     case PROP_CONTENT_GRAVITY:
4477       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4478       break;
4479
4480     case PROP_MINIFICATION_FILTER:
4481       clutter_actor_set_content_scaling_filters (actor,
4482                                                  g_value_get_enum (value),
4483                                                  actor->priv->mag_filter);
4484       break;
4485
4486     case PROP_MAGNIFICATION_FILTER:
4487       clutter_actor_set_content_scaling_filters (actor,
4488                                                  actor->priv->min_filter,
4489                                                  g_value_get_enum (value));
4490       break;
4491
4492     default:
4493       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4494       break;
4495     }
4496 }
4497
4498 static void
4499 clutter_actor_get_property (GObject    *object,
4500                             guint       prop_id,
4501                             GValue     *value,
4502                             GParamSpec *pspec)
4503 {
4504   ClutterActor *actor = CLUTTER_ACTOR (object);
4505   ClutterActorPrivate *priv = actor->priv;
4506
4507   switch (prop_id)
4508     {
4509     case PROP_X:
4510       g_value_set_float (value, clutter_actor_get_x (actor));
4511       break;
4512
4513     case PROP_Y:
4514       g_value_set_float (value, clutter_actor_get_y (actor));
4515       break;
4516
4517     case PROP_WIDTH:
4518       g_value_set_float (value, clutter_actor_get_width (actor));
4519       break;
4520
4521     case PROP_HEIGHT:
4522       g_value_set_float (value, clutter_actor_get_height (actor));
4523       break;
4524
4525     case PROP_FIXED_X:
4526       {
4527         const ClutterLayoutInfo *info;
4528
4529         info = _clutter_actor_get_layout_info_or_defaults (actor);
4530         g_value_set_float (value, info->fixed_x);
4531       }
4532       break;
4533
4534     case PROP_FIXED_Y:
4535       {
4536         const ClutterLayoutInfo *info;
4537
4538         info = _clutter_actor_get_layout_info_or_defaults (actor);
4539         g_value_set_float (value, info->fixed_y);
4540       }
4541       break;
4542
4543     case PROP_FIXED_POSITION_SET:
4544       g_value_set_boolean (value, priv->position_set);
4545       break;
4546
4547     case PROP_MIN_WIDTH:
4548       {
4549         const ClutterLayoutInfo *info;
4550
4551         info = _clutter_actor_get_layout_info_or_defaults (actor);
4552         g_value_set_float (value, info->min_width);
4553       }
4554       break;
4555
4556     case PROP_MIN_HEIGHT:
4557       {
4558         const ClutterLayoutInfo *info;
4559
4560         info = _clutter_actor_get_layout_info_or_defaults (actor);
4561         g_value_set_float (value, info->min_height);
4562       }
4563       break;
4564
4565     case PROP_NATURAL_WIDTH:
4566       {
4567         const ClutterLayoutInfo *info;
4568
4569         info = _clutter_actor_get_layout_info_or_defaults (actor);
4570         g_value_set_float (value, info->natural_width);
4571       }
4572       break;
4573
4574     case PROP_NATURAL_HEIGHT:
4575       {
4576         const ClutterLayoutInfo *info;
4577
4578         info = _clutter_actor_get_layout_info_or_defaults (actor);
4579         g_value_set_float (value, info->natural_height);
4580       }
4581       break;
4582
4583     case PROP_MIN_WIDTH_SET:
4584       g_value_set_boolean (value, priv->min_width_set);
4585       break;
4586
4587     case PROP_MIN_HEIGHT_SET:
4588       g_value_set_boolean (value, priv->min_height_set);
4589       break;
4590
4591     case PROP_NATURAL_WIDTH_SET:
4592       g_value_set_boolean (value, priv->natural_width_set);
4593       break;
4594
4595     case PROP_NATURAL_HEIGHT_SET:
4596       g_value_set_boolean (value, priv->natural_height_set);
4597       break;
4598
4599     case PROP_REQUEST_MODE:
4600       g_value_set_enum (value, priv->request_mode);
4601       break;
4602
4603     case PROP_ALLOCATION:
4604       g_value_set_boxed (value, &priv->allocation);
4605       break;
4606
4607     case PROP_DEPTH:
4608       g_value_set_float (value, clutter_actor_get_depth (actor));
4609       break;
4610
4611     case PROP_OPACITY:
4612       g_value_set_uint (value, priv->opacity);
4613       break;
4614
4615     case PROP_OFFSCREEN_REDIRECT:
4616       g_value_set_enum (value, priv->offscreen_redirect);
4617       break;
4618
4619     case PROP_NAME:
4620       g_value_set_string (value, priv->name);
4621       break;
4622
4623     case PROP_VISIBLE:
4624       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4625       break;
4626
4627     case PROP_MAPPED:
4628       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4629       break;
4630
4631     case PROP_REALIZED:
4632       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4633       break;
4634
4635     case PROP_HAS_CLIP:
4636       g_value_set_boolean (value, priv->has_clip);
4637       break;
4638
4639     case PROP_CLIP:
4640       {
4641         ClutterGeometry clip;
4642
4643         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4644         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4645         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4646         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4647
4648         g_value_set_boxed (value, &clip);
4649       }
4650       break;
4651
4652     case PROP_CLIP_TO_ALLOCATION:
4653       g_value_set_boolean (value, priv->clip_to_allocation);
4654       break;
4655
4656     case PROP_SCALE_X:
4657       {
4658         const ClutterTransformInfo *info;
4659
4660         info = _clutter_actor_get_transform_info_or_defaults (actor);
4661         g_value_set_double (value, info->scale_x);
4662       }
4663       break;
4664
4665     case PROP_SCALE_Y:
4666       {
4667         const ClutterTransformInfo *info;
4668
4669         info = _clutter_actor_get_transform_info_or_defaults (actor);
4670         g_value_set_double (value, info->scale_y);
4671       }
4672       break;
4673
4674     case PROP_SCALE_CENTER_X:
4675       {
4676         gfloat center;
4677
4678         clutter_actor_get_scale_center (actor, &center, NULL);
4679
4680         g_value_set_float (value, center);
4681       }
4682       break;
4683
4684     case PROP_SCALE_CENTER_Y:
4685       {
4686         gfloat center;
4687
4688         clutter_actor_get_scale_center (actor, NULL, &center);
4689
4690         g_value_set_float (value, center);
4691       }
4692       break;
4693
4694     case PROP_SCALE_GRAVITY:
4695       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4696       break;
4697
4698     case PROP_REACTIVE:
4699       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4700       break;
4701
4702     case PROP_ROTATION_ANGLE_X:
4703       {
4704         const ClutterTransformInfo *info;
4705
4706         info = _clutter_actor_get_transform_info_or_defaults (actor);
4707         g_value_set_double (value, info->rx_angle);
4708       }
4709       break;
4710
4711     case PROP_ROTATION_ANGLE_Y:
4712       {
4713         const ClutterTransformInfo *info;
4714
4715         info = _clutter_actor_get_transform_info_or_defaults (actor);
4716         g_value_set_double (value, info->ry_angle);
4717       }
4718       break;
4719
4720     case PROP_ROTATION_ANGLE_Z:
4721       {
4722         const ClutterTransformInfo *info;
4723
4724         info = _clutter_actor_get_transform_info_or_defaults (actor);
4725         g_value_set_double (value, info->rz_angle);
4726       }
4727       break;
4728
4729     case PROP_ROTATION_CENTER_X:
4730       {
4731         ClutterVertex center;
4732
4733         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4734                                     &center.x,
4735                                     &center.y,
4736                                     &center.z);
4737
4738         g_value_set_boxed (value, &center);
4739       }
4740       break;
4741
4742     case PROP_ROTATION_CENTER_Y:
4743       {
4744         ClutterVertex center;
4745
4746         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4747                                     &center.x,
4748                                     &center.y,
4749                                     &center.z);
4750
4751         g_value_set_boxed (value, &center);
4752       }
4753       break;
4754
4755     case PROP_ROTATION_CENTER_Z:
4756       {
4757         ClutterVertex center;
4758
4759         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4760                                     &center.x,
4761                                     &center.y,
4762                                     &center.z);
4763
4764         g_value_set_boxed (value, &center);
4765       }
4766       break;
4767
4768     case PROP_ROTATION_CENTER_Z_GRAVITY:
4769       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4770       break;
4771
4772     case PROP_ANCHOR_X:
4773       {
4774         const ClutterTransformInfo *info;
4775         gfloat anchor_x;
4776
4777         info = _clutter_actor_get_transform_info_or_defaults (actor);
4778         clutter_anchor_coord_get_units (actor, &info->anchor,
4779                                         &anchor_x,
4780                                         NULL,
4781                                         NULL);
4782         g_value_set_float (value, anchor_x);
4783       }
4784       break;
4785
4786     case PROP_ANCHOR_Y:
4787       {
4788         const ClutterTransformInfo *info;
4789         gfloat anchor_y;
4790
4791         info = _clutter_actor_get_transform_info_or_defaults (actor);
4792         clutter_anchor_coord_get_units (actor, &info->anchor,
4793                                         NULL,
4794                                         &anchor_y,
4795                                         NULL);
4796         g_value_set_float (value, anchor_y);
4797       }
4798       break;
4799
4800     case PROP_ANCHOR_GRAVITY:
4801       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4802       break;
4803
4804     case PROP_SHOW_ON_SET_PARENT:
4805       g_value_set_boolean (value, priv->show_on_set_parent);
4806       break;
4807
4808     case PROP_TEXT_DIRECTION:
4809       g_value_set_enum (value, priv->text_direction);
4810       break;
4811
4812     case PROP_HAS_POINTER:
4813       g_value_set_boolean (value, priv->has_pointer);
4814       break;
4815
4816     case PROP_LAYOUT_MANAGER:
4817       g_value_set_object (value, priv->layout_manager);
4818       break;
4819
4820     case PROP_X_ALIGN:
4821       {
4822         const ClutterLayoutInfo *info;
4823
4824         info = _clutter_actor_get_layout_info_or_defaults (actor);
4825         g_value_set_enum (value, info->x_align);
4826       }
4827       break;
4828
4829     case PROP_Y_ALIGN:
4830       {
4831         const ClutterLayoutInfo *info;
4832
4833         info = _clutter_actor_get_layout_info_or_defaults (actor);
4834         g_value_set_enum (value, info->y_align);
4835       }
4836       break;
4837
4838     case PROP_MARGIN_TOP:
4839       {
4840         const ClutterLayoutInfo *info;
4841
4842         info = _clutter_actor_get_layout_info_or_defaults (actor);
4843         g_value_set_float (value, info->margin.top);
4844       }
4845       break;
4846
4847     case PROP_MARGIN_BOTTOM:
4848       {
4849         const ClutterLayoutInfo *info;
4850
4851         info = _clutter_actor_get_layout_info_or_defaults (actor);
4852         g_value_set_float (value, info->margin.bottom);
4853       }
4854       break;
4855
4856     case PROP_MARGIN_LEFT:
4857       {
4858         const ClutterLayoutInfo *info;
4859
4860         info = _clutter_actor_get_layout_info_or_defaults (actor);
4861         g_value_set_float (value, info->margin.left);
4862       }
4863       break;
4864
4865     case PROP_MARGIN_RIGHT:
4866       {
4867         const ClutterLayoutInfo *info;
4868
4869         info = _clutter_actor_get_layout_info_or_defaults (actor);
4870         g_value_set_float (value, info->margin.right);
4871       }
4872       break;
4873
4874     case PROP_BACKGROUND_COLOR_SET:
4875       g_value_set_boolean (value, priv->bg_color_set);
4876       break;
4877
4878     case PROP_BACKGROUND_COLOR:
4879       g_value_set_boxed (value, &priv->bg_color);
4880       break;
4881
4882     case PROP_FIRST_CHILD:
4883       g_value_set_object (value, priv->first_child);
4884       break;
4885
4886     case PROP_LAST_CHILD:
4887       g_value_set_object (value, priv->last_child);
4888       break;
4889
4890     case PROP_CONTENT:
4891       g_value_set_object (value, priv->content);
4892       break;
4893
4894     case PROP_CONTENT_GRAVITY:
4895       g_value_set_enum (value, priv->content_gravity);
4896       break;
4897
4898     case PROP_CONTENT_BOX:
4899       {
4900         ClutterActorBox box = { 0, };
4901
4902         clutter_actor_get_content_box (actor, &box);
4903         g_value_set_boxed (value, &box);
4904       }
4905       break;
4906
4907     case PROP_MINIFICATION_FILTER:
4908       g_value_set_enum (value, priv->min_filter);
4909       break;
4910
4911     case PROP_MAGNIFICATION_FILTER:
4912       g_value_set_enum (value, priv->mag_filter);
4913       break;
4914
4915     default:
4916       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4917       break;
4918     }
4919 }
4920
4921 static void
4922 clutter_actor_dispose (GObject *object)
4923 {
4924   ClutterActor *self = CLUTTER_ACTOR (object);
4925   ClutterActorPrivate *priv = self->priv;
4926
4927   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4928                 priv->id,
4929                 g_type_name (G_OBJECT_TYPE (self)),
4930                 object->ref_count);
4931
4932   g_signal_emit (self, actor_signals[DESTROY], 0);
4933
4934   /* avoid recursing when called from clutter_actor_destroy() */
4935   if (priv->parent != NULL)
4936     {
4937       ClutterActor *parent = priv->parent;
4938
4939       /* go through the Container implementation unless this
4940        * is an internal child and has been marked as such.
4941        *
4942        * removing the actor from its parent will reset the
4943        * realized and mapped states.
4944        */
4945       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4946         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4947       else
4948         clutter_actor_remove_child_internal (parent, self,
4949                                              REMOVE_CHILD_LEGACY_FLAGS);
4950     }
4951
4952   /* parent must be gone at this point */
4953   g_assert (priv->parent == NULL);
4954
4955   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4956     {
4957       /* can't be mapped or realized with no parent */
4958       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4959       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4960     }
4961
4962   g_clear_object (&priv->pango_context);
4963   g_clear_object (&priv->actions);
4964   g_clear_object (&priv->constraints);
4965   g_clear_object (&priv->effects);
4966   g_clear_object (&priv->flatten_effect);
4967
4968   if (priv->layout_manager != NULL)
4969     {
4970       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4971       g_clear_object (&priv->layout_manager);
4972     }
4973
4974   if (priv->content != NULL)
4975     {
4976       _clutter_content_detached (priv->content, self);
4977       g_clear_object (&priv->content);
4978     }
4979
4980   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4981 }
4982
4983 static void
4984 clutter_actor_finalize (GObject *object)
4985 {
4986   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4987
4988   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4989                 priv->name != NULL ? priv->name : "<none>",
4990                 priv->id,
4991                 g_type_name (G_OBJECT_TYPE (object)));
4992
4993   _clutter_context_release_id (priv->id);
4994
4995   g_free (priv->name);
4996
4997   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4998 }
4999
5000
5001 /**
5002  * clutter_actor_get_accessible:
5003  * @self: a #ClutterActor
5004  *
5005  * Returns the accessible object that describes the actor to an
5006  * assistive technology.
5007  *
5008  * If no class-specific #AtkObject implementation is available for the
5009  * actor instance in question, it will inherit an #AtkObject
5010  * implementation from the first ancestor class for which such an
5011  * implementation is defined.
5012  *
5013  * The documentation of the <ulink
5014  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5015  * library contains more information about accessible objects and
5016  * their uses.
5017  *
5018  * Returns: (transfer none): the #AtkObject associated with @actor
5019  */
5020 AtkObject *
5021 clutter_actor_get_accessible (ClutterActor *self)
5022 {
5023   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5024
5025   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5026 }
5027
5028 static AtkObject *
5029 clutter_actor_real_get_accessible (ClutterActor *actor)
5030 {
5031   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5032 }
5033
5034 static AtkObject *
5035 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5036 {
5037   AtkObject *accessible;
5038
5039   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5040   if (accessible != NULL)
5041     g_object_ref (accessible);
5042
5043   return accessible;
5044 }
5045
5046 static void
5047 atk_implementor_iface_init (AtkImplementorIface *iface)
5048 {
5049   iface->ref_accessible = _clutter_actor_ref_accessible;
5050 }
5051
5052 static gboolean
5053 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5054                                            ClutterPaintVolume *volume)
5055 {
5056   ClutterActorPrivate *priv = self->priv;
5057   gboolean res = FALSE;
5058
5059   /* we start from the allocation */
5060   clutter_paint_volume_set_width (volume,
5061                                   priv->allocation.x2 - priv->allocation.x1);
5062   clutter_paint_volume_set_height (volume,
5063                                    priv->allocation.y2 - priv->allocation.y1);
5064
5065   /* if the actor has a clip set then we have a pretty definite
5066    * size for the paint volume: the actor cannot possibly paint
5067    * outside the clip region.
5068    */
5069   if (priv->clip_to_allocation)
5070     {
5071       /* the allocation has already been set, so we just flip the
5072        * return value
5073        */
5074       res = TRUE;
5075     }
5076   else
5077     {
5078       ClutterActor *child;
5079
5080       if (priv->has_clip &&
5081           priv->clip.width >= 0 &&
5082           priv->clip.height >= 0)
5083         {
5084           ClutterVertex origin;
5085
5086           origin.x = priv->clip.x;
5087           origin.y = priv->clip.y;
5088           origin.z = 0;
5089
5090           clutter_paint_volume_set_origin (volume, &origin);
5091           clutter_paint_volume_set_width (volume, priv->clip.width);
5092           clutter_paint_volume_set_height (volume, priv->clip.height);
5093
5094           res = TRUE;
5095         }
5096
5097       /* if we don't have children we just bail out here... */
5098       if (priv->n_children == 0)
5099         return res;
5100
5101       /* ...but if we have children then we ask for their paint volume in
5102        * our coordinates. if any of our children replies that it doesn't
5103        * have a paint volume, we bail out
5104        */
5105       for (child = priv->first_child;
5106            child != NULL;
5107            child = child->priv->next_sibling)
5108         {
5109           const ClutterPaintVolume *child_volume;
5110
5111           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5112           if (child_volume == NULL)
5113             {
5114               res = FALSE;
5115               break;
5116             }
5117
5118           clutter_paint_volume_union (volume, child_volume);
5119           res = TRUE;
5120         }
5121     }
5122
5123   return res;
5124
5125 }
5126
5127 static gboolean
5128 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5129                                      ClutterPaintVolume *volume)
5130 {
5131   ClutterActorClass *klass;
5132   gboolean res;
5133
5134   klass = CLUTTER_ACTOR_GET_CLASS (self);
5135
5136   /* XXX - this thoroughly sucks, but we don't want to penalize users
5137    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5138    * redraw. This should go away in 2.0.
5139    */
5140   if (klass->paint == clutter_actor_real_paint &&
5141       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5142     {
5143       res = TRUE;
5144     }
5145   else
5146     {
5147       /* this is the default return value: we cannot know if a class
5148        * is going to paint outside its allocation, so we take the
5149        * conservative approach.
5150        */
5151       res = FALSE;
5152     }
5153
5154   if (clutter_actor_update_default_paint_volume (self, volume))
5155     return res;
5156
5157   return FALSE;
5158 }
5159
5160 /**
5161  * clutter_actor_get_default_paint_volume:
5162  * @self: a #ClutterActor
5163  *
5164  * Retrieves the default paint volume for @self.
5165  *
5166  * This function provides the same #ClutterPaintVolume that would be
5167  * computed by the default implementation inside #ClutterActor of the
5168  * #ClutterActorClass.get_paint_volume() virtual function.
5169  *
5170  * This function should only be used by #ClutterActor subclasses that
5171  * cannot chain up to the parent implementation when computing their
5172  * paint volume.
5173  *
5174  * Return value: (transfer none): a pointer to the default
5175  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5176  *   the actor could not compute a valid paint volume. The returned value
5177  *   is not guaranteed to be stable across multiple frames, so if you
5178  *   want to retain it, you will need to copy it using
5179  *   clutter_paint_volume_copy().
5180  *
5181  * Since: 1.10
5182  */
5183 const ClutterPaintVolume *
5184 clutter_actor_get_default_paint_volume (ClutterActor *self)
5185 {
5186   ClutterPaintVolume volume;
5187   ClutterPaintVolume *res;
5188
5189   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5190
5191   res = NULL;
5192   _clutter_paint_volume_init_static (&volume, self);
5193   if (clutter_actor_update_default_paint_volume (self, &volume))
5194     {
5195       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5196
5197       if (stage != NULL)
5198         {
5199           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5200           _clutter_paint_volume_copy_static (&volume, res);
5201         }
5202     }
5203
5204   clutter_paint_volume_free (&volume);
5205
5206   return res;
5207 }
5208
5209 static gboolean
5210 clutter_actor_real_has_overlaps (ClutterActor *self)
5211 {
5212   /* By default we'll assume that all actors need an offscreen redirect to get
5213    * the correct opacity. Actors such as ClutterTexture that would never need
5214    * an offscreen redirect can override this to return FALSE. */
5215   return TRUE;
5216 }
5217
5218 static void
5219 clutter_actor_real_destroy (ClutterActor *actor)
5220 {
5221   ClutterActorIter iter;
5222
5223   clutter_actor_iter_init (&iter, actor);
5224   while (clutter_actor_iter_next (&iter, NULL))
5225     clutter_actor_iter_destroy (&iter);
5226 }
5227
5228 static GObject *
5229 clutter_actor_constructor (GType gtype,
5230                            guint n_props,
5231                            GObjectConstructParam *props)
5232 {
5233   GObjectClass *gobject_class;
5234   ClutterActor *self;
5235   GObject *retval;
5236
5237   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5238   retval = gobject_class->constructor (gtype, n_props, props);
5239   self = CLUTTER_ACTOR (retval);
5240
5241   if (self->priv->layout_manager == NULL)
5242     {
5243       ClutterLayoutManager *default_layout;
5244
5245       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5246
5247       default_layout = clutter_fixed_layout_new ();
5248       clutter_actor_set_layout_manager (self, default_layout);
5249     }
5250
5251   return retval;
5252 }
5253
5254 static void
5255 clutter_actor_class_init (ClutterActorClass *klass)
5256 {
5257   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5258
5259   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5260   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5261   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5262   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5263
5264   object_class->constructor = clutter_actor_constructor;
5265   object_class->set_property = clutter_actor_set_property;
5266   object_class->get_property = clutter_actor_get_property;
5267   object_class->dispose = clutter_actor_dispose;
5268   object_class->finalize = clutter_actor_finalize;
5269
5270   klass->show = clutter_actor_real_show;
5271   klass->show_all = clutter_actor_show;
5272   klass->hide = clutter_actor_real_hide;
5273   klass->hide_all = clutter_actor_hide;
5274   klass->map = clutter_actor_real_map;
5275   klass->unmap = clutter_actor_real_unmap;
5276   klass->unrealize = clutter_actor_real_unrealize;
5277   klass->pick = clutter_actor_real_pick;
5278   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5279   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5280   klass->allocate = clutter_actor_real_allocate;
5281   klass->queue_redraw = clutter_actor_real_queue_redraw;
5282   klass->queue_relayout = clutter_actor_real_queue_relayout;
5283   klass->apply_transform = clutter_actor_real_apply_transform;
5284   klass->get_accessible = clutter_actor_real_get_accessible;
5285   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5286   klass->has_overlaps = clutter_actor_real_has_overlaps;
5287   klass->paint = clutter_actor_real_paint;
5288   klass->destroy = clutter_actor_real_destroy;
5289
5290   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5291
5292   /**
5293    * ClutterActor:x:
5294    *
5295    * X coordinate of the actor in pixels. If written, forces a fixed
5296    * position for the actor. If read, returns the fixed position if any,
5297    * otherwise the allocation if available, otherwise 0.
5298    *
5299    * The #ClutterActor:x property is animatable.
5300    */
5301   obj_props[PROP_X] =
5302     g_param_spec_float ("x",
5303                         P_("X coordinate"),
5304                         P_("X coordinate of the actor"),
5305                         -G_MAXFLOAT, G_MAXFLOAT,
5306                         0.0,
5307                         G_PARAM_READWRITE |
5308                         G_PARAM_STATIC_STRINGS |
5309                         CLUTTER_PARAM_ANIMATABLE);
5310
5311   /**
5312    * ClutterActor:y:
5313    *
5314    * Y coordinate of the actor in pixels. If written, forces a fixed
5315    * position for the actor.  If read, returns the fixed position if
5316    * any, otherwise the allocation if available, otherwise 0.
5317    *
5318    * The #ClutterActor:y property is animatable.
5319    */
5320   obj_props[PROP_Y] =
5321     g_param_spec_float ("y",
5322                         P_("Y coordinate"),
5323                         P_("Y coordinate of the actor"),
5324                         -G_MAXFLOAT, G_MAXFLOAT,
5325                         0.0,
5326                         G_PARAM_READWRITE |
5327                         G_PARAM_STATIC_STRINGS |
5328                         CLUTTER_PARAM_ANIMATABLE);
5329
5330   /**
5331    * ClutterActor:width:
5332    *
5333    * Width of the actor (in pixels). If written, forces the minimum and
5334    * natural size request of the actor to the given width. If read, returns
5335    * the allocated width if available, otherwise the width request.
5336    *
5337    * The #ClutterActor:width property is animatable.
5338    */
5339   obj_props[PROP_WIDTH] =
5340     g_param_spec_float ("width",
5341                         P_("Width"),
5342                         P_("Width of the actor"),
5343                         0.0, G_MAXFLOAT,
5344                         0.0,
5345                         G_PARAM_READWRITE |
5346                         G_PARAM_STATIC_STRINGS |
5347                         CLUTTER_PARAM_ANIMATABLE);
5348
5349   /**
5350    * ClutterActor:height:
5351    *
5352    * Height of the actor (in pixels).  If written, forces the minimum and
5353    * natural size request of the actor to the given height. If read, returns
5354    * the allocated height if available, otherwise the height request.
5355    *
5356    * The #ClutterActor:height property is animatable.
5357    */
5358   obj_props[PROP_HEIGHT] =
5359     g_param_spec_float ("height",
5360                         P_("Height"),
5361                         P_("Height of the actor"),
5362                         0.0, G_MAXFLOAT,
5363                         0.0,
5364                         G_PARAM_READWRITE |
5365                         G_PARAM_STATIC_STRINGS |
5366                         CLUTTER_PARAM_ANIMATABLE);
5367
5368   /**
5369    * ClutterActor:fixed-x:
5370    *
5371    * The fixed X position of the actor in pixels.
5372    *
5373    * Writing this property sets #ClutterActor:fixed-position-set
5374    * property as well, as a side effect
5375    *
5376    * Since: 0.8
5377    */
5378   obj_props[PROP_FIXED_X] =
5379     g_param_spec_float ("fixed-x",
5380                         P_("Fixed X"),
5381                         P_("Forced X position of the actor"),
5382                         -G_MAXFLOAT, G_MAXFLOAT,
5383                         0.0,
5384                         CLUTTER_PARAM_READWRITE);
5385
5386   /**
5387    * ClutterActor:fixed-y:
5388    *
5389    * The fixed Y position of the actor in pixels.
5390    *
5391    * Writing this property sets the #ClutterActor:fixed-position-set
5392    * property as well, as a side effect
5393    *
5394    * Since: 0.8
5395    */
5396   obj_props[PROP_FIXED_Y] =
5397     g_param_spec_float ("fixed-y",
5398                         P_("Fixed Y"),
5399                         P_("Forced Y position of the actor"),
5400                         -G_MAXFLOAT, G_MAXFLOAT,
5401                         0,
5402                         CLUTTER_PARAM_READWRITE);
5403
5404   /**
5405    * ClutterActor:fixed-position-set:
5406    *
5407    * This flag controls whether the #ClutterActor:fixed-x and
5408    * #ClutterActor:fixed-y properties are used
5409    *
5410    * Since: 0.8
5411    */
5412   obj_props[PROP_FIXED_POSITION_SET] =
5413     g_param_spec_boolean ("fixed-position-set",
5414                           P_("Fixed position set"),
5415                           P_("Whether to use fixed positioning for the actor"),
5416                           FALSE,
5417                           CLUTTER_PARAM_READWRITE);
5418
5419   /**
5420    * ClutterActor:min-width:
5421    *
5422    * A forced minimum width request for the actor, in pixels
5423    *
5424    * Writing this property sets the #ClutterActor:min-width-set property
5425    * as well, as a side effect.
5426    *
5427    *This property overrides the usual width request of the actor.
5428    *
5429    * Since: 0.8
5430    */
5431   obj_props[PROP_MIN_WIDTH] =
5432     g_param_spec_float ("min-width",
5433                         P_("Min Width"),
5434                         P_("Forced minimum width request for the actor"),
5435                         0.0, G_MAXFLOAT,
5436                         0.0,
5437                         CLUTTER_PARAM_READWRITE);
5438
5439   /**
5440    * ClutterActor:min-height:
5441    *
5442    * A forced minimum height request for the actor, in pixels
5443    *
5444    * Writing this property sets the #ClutterActor:min-height-set property
5445    * as well, as a side effect. This property overrides the usual height
5446    * request of the actor.
5447    *
5448    * Since: 0.8
5449    */
5450   obj_props[PROP_MIN_HEIGHT] =
5451     g_param_spec_float ("min-height",
5452                         P_("Min Height"),
5453                         P_("Forced minimum height request for the actor"),
5454                         0.0, G_MAXFLOAT,
5455                         0.0,
5456                         CLUTTER_PARAM_READWRITE);
5457
5458   /**
5459    * ClutterActor:natural-width:
5460    *
5461    * A forced natural width request for the actor, in pixels
5462    *
5463    * Writing this property sets the #ClutterActor:natural-width-set
5464    * property as well, as a side effect. This property overrides the
5465    * usual width request of the actor
5466    *
5467    * Since: 0.8
5468    */
5469   obj_props[PROP_NATURAL_WIDTH] =
5470     g_param_spec_float ("natural-width",
5471                         P_("Natural Width"),
5472                         P_("Forced natural width request for the actor"),
5473                         0.0, G_MAXFLOAT,
5474                         0.0,
5475                         CLUTTER_PARAM_READWRITE);
5476
5477   /**
5478    * ClutterActor:natural-height:
5479    *
5480    * A forced natural height request for the actor, in pixels
5481    *
5482    * Writing this property sets the #ClutterActor:natural-height-set
5483    * property as well, as a side effect. This property overrides the
5484    * usual height request of the actor
5485    *
5486    * Since: 0.8
5487    */
5488   obj_props[PROP_NATURAL_HEIGHT] =
5489     g_param_spec_float ("natural-height",
5490                         P_("Natural Height"),
5491                         P_("Forced natural height request for the actor"),
5492                         0.0, G_MAXFLOAT,
5493                         0.0,
5494                         CLUTTER_PARAM_READWRITE);
5495
5496   /**
5497    * ClutterActor:min-width-set:
5498    *
5499    * This flag controls whether the #ClutterActor:min-width property
5500    * is used
5501    *
5502    * Since: 0.8
5503    */
5504   obj_props[PROP_MIN_WIDTH_SET] =
5505     g_param_spec_boolean ("min-width-set",
5506                           P_("Minimum width set"),
5507                           P_("Whether to use the min-width property"),
5508                           FALSE,
5509                           CLUTTER_PARAM_READWRITE);
5510
5511   /**
5512    * ClutterActor:min-height-set:
5513    *
5514    * This flag controls whether the #ClutterActor:min-height property
5515    * is used
5516    *
5517    * Since: 0.8
5518    */
5519   obj_props[PROP_MIN_HEIGHT_SET] =
5520     g_param_spec_boolean ("min-height-set",
5521                           P_("Minimum height set"),
5522                           P_("Whether to use the min-height property"),
5523                           FALSE,
5524                           CLUTTER_PARAM_READWRITE);
5525
5526   /**
5527    * ClutterActor:natural-width-set:
5528    *
5529    * This flag controls whether the #ClutterActor:natural-width property
5530    * is used
5531    *
5532    * Since: 0.8
5533    */
5534   obj_props[PROP_NATURAL_WIDTH_SET] =
5535     g_param_spec_boolean ("natural-width-set",
5536                           P_("Natural width set"),
5537                           P_("Whether to use the natural-width property"),
5538                           FALSE,
5539                           CLUTTER_PARAM_READWRITE);
5540
5541   /**
5542    * ClutterActor:natural-height-set:
5543    *
5544    * This flag controls whether the #ClutterActor:natural-height property
5545    * is used
5546    *
5547    * Since: 0.8
5548    */
5549   obj_props[PROP_NATURAL_HEIGHT_SET] =
5550     g_param_spec_boolean ("natural-height-set",
5551                           P_("Natural height set"),
5552                           P_("Whether to use the natural-height property"),
5553                           FALSE,
5554                           CLUTTER_PARAM_READWRITE);
5555
5556   /**
5557    * ClutterActor:allocation:
5558    *
5559    * The allocation for the actor, in pixels
5560    *
5561    * This is property is read-only, but you might monitor it to know when an
5562    * actor moves or resizes
5563    *
5564    * Since: 0.8
5565    */
5566   obj_props[PROP_ALLOCATION] =
5567     g_param_spec_boxed ("allocation",
5568                         P_("Allocation"),
5569                         P_("The actor's allocation"),
5570                         CLUTTER_TYPE_ACTOR_BOX,
5571                         CLUTTER_PARAM_READABLE);
5572
5573   /**
5574    * ClutterActor:request-mode:
5575    *
5576    * Request mode for the #ClutterActor. The request mode determines the
5577    * type of geometry management used by the actor, either height for width
5578    * (the default) or width for height.
5579    *
5580    * For actors implementing height for width, the parent container should get
5581    * the preferred width first, and then the preferred height for that width.
5582    *
5583    * For actors implementing width for height, the parent container should get
5584    * the preferred height first, and then the preferred width for that height.
5585    *
5586    * For instance:
5587    *
5588    * |[
5589    *   ClutterRequestMode mode;
5590    *   gfloat natural_width, min_width;
5591    *   gfloat natural_height, min_height;
5592    *
5593    *   mode = clutter_actor_get_request_mode (child);
5594    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5595    *     {
5596    *       clutter_actor_get_preferred_width (child, -1,
5597    *                                          &amp;min_width,
5598    *                                          &amp;natural_width);
5599    *       clutter_actor_get_preferred_height (child, natural_width,
5600    *                                           &amp;min_height,
5601    *                                           &amp;natural_height);
5602    *     }
5603    *   else
5604    *     {
5605    *       clutter_actor_get_preferred_height (child, -1,
5606    *                                           &amp;min_height,
5607    *                                           &amp;natural_height);
5608    *       clutter_actor_get_preferred_width (child, natural_height,
5609    *                                          &amp;min_width,
5610    *                                          &amp;natural_width);
5611    *     }
5612    * ]|
5613    *
5614    * will retrieve the minimum and natural width and height depending on the
5615    * preferred request mode of the #ClutterActor "child".
5616    *
5617    * The clutter_actor_get_preferred_size() function will implement this
5618    * check for you.
5619    *
5620    * Since: 0.8
5621    */
5622   obj_props[PROP_REQUEST_MODE] =
5623     g_param_spec_enum ("request-mode",
5624                        P_("Request Mode"),
5625                        P_("The actor's request mode"),
5626                        CLUTTER_TYPE_REQUEST_MODE,
5627                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5628                        CLUTTER_PARAM_READWRITE);
5629
5630   /**
5631    * ClutterActor:depth:
5632    *
5633    * The position of the actor on the Z axis.
5634    *
5635    * The #ClutterActor:depth property is relative to the parent's
5636    * modelview matrix.
5637    *
5638    * The #ClutterActor:depth property is animatable.
5639    *
5640    * Since: 0.6
5641    */
5642   obj_props[PROP_DEPTH] =
5643     g_param_spec_float ("depth",
5644                         P_("Depth"),
5645                         P_("Position on the Z axis"),
5646                         -G_MAXFLOAT, G_MAXFLOAT,
5647                         0.0,
5648                         G_PARAM_READWRITE |
5649                         G_PARAM_STATIC_STRINGS |
5650                         CLUTTER_PARAM_ANIMATABLE);
5651
5652   /**
5653    * ClutterActor:opacity:
5654    *
5655    * Opacity of an actor, between 0 (fully transparent) and
5656    * 255 (fully opaque)
5657    *
5658    * The #ClutterActor:opacity property is animatable.
5659    */
5660   obj_props[PROP_OPACITY] =
5661     g_param_spec_uint ("opacity",
5662                        P_("Opacity"),
5663                        P_("Opacity of an actor"),
5664                        0, 255,
5665                        255,
5666                        G_PARAM_READWRITE |
5667                        G_PARAM_STATIC_STRINGS |
5668                        CLUTTER_PARAM_ANIMATABLE);
5669
5670   /**
5671    * ClutterActor:offscreen-redirect:
5672    *
5673    * Determines the conditions in which the actor will be redirected
5674    * to an offscreen framebuffer while being painted. For example this
5675    * can be used to cache an actor in a framebuffer or for improved
5676    * handling of transparent actors. See
5677    * clutter_actor_set_offscreen_redirect() for details.
5678    *
5679    * Since: 1.8
5680    */
5681   obj_props[PROP_OFFSCREEN_REDIRECT] =
5682     g_param_spec_flags ("offscreen-redirect",
5683                         P_("Offscreen redirect"),
5684                         P_("Flags controlling when to flatten the actor into a single image"),
5685                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5686                         0,
5687                         CLUTTER_PARAM_READWRITE);
5688
5689   /**
5690    * ClutterActor:visible:
5691    *
5692    * Whether the actor is set to be visible or not
5693    *
5694    * See also #ClutterActor:mapped
5695    */
5696   obj_props[PROP_VISIBLE] =
5697     g_param_spec_boolean ("visible",
5698                           P_("Visible"),
5699                           P_("Whether the actor is visible or not"),
5700                           FALSE,
5701                           CLUTTER_PARAM_READWRITE);
5702
5703   /**
5704    * ClutterActor:mapped:
5705    *
5706    * Whether the actor is mapped (will be painted when the stage
5707    * to which it belongs is mapped)
5708    *
5709    * Since: 1.0
5710    */
5711   obj_props[PROP_MAPPED] =
5712     g_param_spec_boolean ("mapped",
5713                           P_("Mapped"),
5714                           P_("Whether the actor will be painted"),
5715                           FALSE,
5716                           CLUTTER_PARAM_READABLE);
5717
5718   /**
5719    * ClutterActor:realized:
5720    *
5721    * Whether the actor has been realized
5722    *
5723    * Since: 1.0
5724    */
5725   obj_props[PROP_REALIZED] =
5726     g_param_spec_boolean ("realized",
5727                           P_("Realized"),
5728                           P_("Whether the actor has been realized"),
5729                           FALSE,
5730                           CLUTTER_PARAM_READABLE);
5731
5732   /**
5733    * ClutterActor:reactive:
5734    *
5735    * Whether the actor is reactive to events or not
5736    *
5737    * Only reactive actors will emit event-related signals
5738    *
5739    * Since: 0.6
5740    */
5741   obj_props[PROP_REACTIVE] =
5742     g_param_spec_boolean ("reactive",
5743                           P_("Reactive"),
5744                           P_("Whether the actor is reactive to events"),
5745                           FALSE,
5746                           CLUTTER_PARAM_READWRITE);
5747
5748   /**
5749    * ClutterActor:has-clip:
5750    *
5751    * Whether the actor has the #ClutterActor:clip property set or not
5752    */
5753   obj_props[PROP_HAS_CLIP] =
5754     g_param_spec_boolean ("has-clip",
5755                           P_("Has Clip"),
5756                           P_("Whether the actor has a clip set"),
5757                           FALSE,
5758                           CLUTTER_PARAM_READABLE);
5759
5760   /**
5761    * ClutterActor:clip:
5762    *
5763    * The clip region for the actor, in actor-relative coordinates
5764    *
5765    * Every part of the actor outside the clip region will not be
5766    * painted
5767    */
5768   obj_props[PROP_CLIP] =
5769     g_param_spec_boxed ("clip",
5770                         P_("Clip"),
5771                         P_("The clip region for the actor"),
5772                         CLUTTER_TYPE_GEOMETRY,
5773                         CLUTTER_PARAM_READWRITE);
5774
5775   /**
5776    * ClutterActor:name:
5777    *
5778    * The name of the actor
5779    *
5780    * Since: 0.2
5781    */
5782   obj_props[PROP_NAME] =
5783     g_param_spec_string ("name",
5784                          P_("Name"),
5785                          P_("Name of the actor"),
5786                          NULL,
5787                          CLUTTER_PARAM_READWRITE);
5788
5789   /**
5790    * ClutterActor:scale-x:
5791    *
5792    * The horizontal scale of the actor.
5793    *
5794    * The #ClutterActor:scale-x property is animatable.
5795    *
5796    * Since: 0.6
5797    */
5798   obj_props[PROP_SCALE_X] =
5799     g_param_spec_double ("scale-x",
5800                          P_("Scale X"),
5801                          P_("Scale factor on the X axis"),
5802                          0.0, G_MAXDOUBLE,
5803                          1.0,
5804                          G_PARAM_READWRITE |
5805                          G_PARAM_STATIC_STRINGS |
5806                          CLUTTER_PARAM_ANIMATABLE);
5807
5808   /**
5809    * ClutterActor:scale-y:
5810    *
5811    * The vertical scale of the actor.
5812    *
5813    * The #ClutterActor:scale-y property is animatable.
5814    *
5815    * Since: 0.6
5816    */
5817   obj_props[PROP_SCALE_Y] =
5818     g_param_spec_double ("scale-y",
5819                          P_("Scale Y"),
5820                          P_("Scale factor on the Y axis"),
5821                          0.0, G_MAXDOUBLE,
5822                          1.0,
5823                          G_PARAM_READWRITE |
5824                          G_PARAM_STATIC_STRINGS |
5825                          CLUTTER_PARAM_ANIMATABLE);
5826
5827   /**
5828    * ClutterActor:scale-center-x:
5829    *
5830    * The horizontal center point for scaling
5831    *
5832    * Since: 1.0
5833    */
5834   obj_props[PROP_SCALE_CENTER_X] =
5835     g_param_spec_float ("scale-center-x",
5836                         P_("Scale Center X"),
5837                         P_("Horizontal scale center"),
5838                         -G_MAXFLOAT, G_MAXFLOAT,
5839                         0.0,
5840                         CLUTTER_PARAM_READWRITE);
5841
5842   /**
5843    * ClutterActor:scale-center-y:
5844    *
5845    * The vertical center point for scaling
5846    *
5847    * Since: 1.0
5848    */
5849   obj_props[PROP_SCALE_CENTER_Y] =
5850     g_param_spec_float ("scale-center-y",
5851                         P_("Scale Center Y"),
5852                         P_("Vertical scale center"),
5853                         -G_MAXFLOAT, G_MAXFLOAT,
5854                         0.0,
5855                         CLUTTER_PARAM_READWRITE);
5856
5857   /**
5858    * ClutterActor:scale-gravity:
5859    *
5860    * The center point for scaling expressed as a #ClutterGravity
5861    *
5862    * Since: 1.0
5863    */
5864   obj_props[PROP_SCALE_GRAVITY] =
5865     g_param_spec_enum ("scale-gravity",
5866                        P_("Scale Gravity"),
5867                        P_("The center of scaling"),
5868                        CLUTTER_TYPE_GRAVITY,
5869                        CLUTTER_GRAVITY_NONE,
5870                        CLUTTER_PARAM_READWRITE);
5871
5872   /**
5873    * ClutterActor:rotation-angle-x:
5874    *
5875    * The rotation angle on the X axis.
5876    *
5877    * The #ClutterActor:rotation-angle-x property is animatable.
5878    *
5879    * Since: 0.6
5880    */
5881   obj_props[PROP_ROTATION_ANGLE_X] =
5882     g_param_spec_double ("rotation-angle-x",
5883                          P_("Rotation Angle X"),
5884                          P_("The rotation angle on the X axis"),
5885                          -G_MAXDOUBLE, G_MAXDOUBLE,
5886                          0.0,
5887                          G_PARAM_READWRITE |
5888                          G_PARAM_STATIC_STRINGS |
5889                          CLUTTER_PARAM_ANIMATABLE);
5890
5891   /**
5892    * ClutterActor:rotation-angle-y:
5893    *
5894    * The rotation angle on the Y axis
5895    *
5896    * The #ClutterActor:rotation-angle-y property is animatable.
5897    *
5898    * Since: 0.6
5899    */
5900   obj_props[PROP_ROTATION_ANGLE_Y] =
5901     g_param_spec_double ("rotation-angle-y",
5902                          P_("Rotation Angle Y"),
5903                          P_("The rotation angle on the Y axis"),
5904                          -G_MAXDOUBLE, G_MAXDOUBLE,
5905                          0.0,
5906                          G_PARAM_READWRITE |
5907                          G_PARAM_STATIC_STRINGS |
5908                          CLUTTER_PARAM_ANIMATABLE);
5909
5910   /**
5911    * ClutterActor:rotation-angle-z:
5912    *
5913    * The rotation angle on the Z axis
5914    *
5915    * The #ClutterActor:rotation-angle-z property is animatable.
5916    *
5917    * Since: 0.6
5918    */
5919   obj_props[PROP_ROTATION_ANGLE_Z] =
5920     g_param_spec_double ("rotation-angle-z",
5921                          P_("Rotation Angle Z"),
5922                          P_("The rotation angle on the Z axis"),
5923                          -G_MAXDOUBLE, G_MAXDOUBLE,
5924                          0.0,
5925                          G_PARAM_READWRITE |
5926                          G_PARAM_STATIC_STRINGS |
5927                          CLUTTER_PARAM_ANIMATABLE);
5928
5929   /**
5930    * ClutterActor:rotation-center-x:
5931    *
5932    * The rotation center on the X axis.
5933    *
5934    * Since: 0.6
5935    */
5936   obj_props[PROP_ROTATION_CENTER_X] =
5937     g_param_spec_boxed ("rotation-center-x",
5938                         P_("Rotation Center X"),
5939                         P_("The rotation center on the X axis"),
5940                         CLUTTER_TYPE_VERTEX,
5941                         CLUTTER_PARAM_READWRITE);
5942
5943   /**
5944    * ClutterActor:rotation-center-y:
5945    *
5946    * The rotation center on the Y axis.
5947    *
5948    * Since: 0.6
5949    */
5950   obj_props[PROP_ROTATION_CENTER_Y] =
5951     g_param_spec_boxed ("rotation-center-y",
5952                         P_("Rotation Center Y"),
5953                         P_("The rotation center on the Y axis"),
5954                         CLUTTER_TYPE_VERTEX,
5955                         CLUTTER_PARAM_READWRITE);
5956
5957   /**
5958    * ClutterActor:rotation-center-z:
5959    *
5960    * The rotation center on the Z axis.
5961    *
5962    * Since: 0.6
5963    */
5964   obj_props[PROP_ROTATION_CENTER_Z] =
5965     g_param_spec_boxed ("rotation-center-z",
5966                         P_("Rotation Center Z"),
5967                         P_("The rotation center on the Z axis"),
5968                         CLUTTER_TYPE_VERTEX,
5969                         CLUTTER_PARAM_READWRITE);
5970
5971   /**
5972    * ClutterActor:rotation-center-z-gravity:
5973    *
5974    * The rotation center on the Z axis expressed as a #ClutterGravity.
5975    *
5976    * Since: 1.0
5977    */
5978   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5979     g_param_spec_enum ("rotation-center-z-gravity",
5980                        P_("Rotation Center Z Gravity"),
5981                        P_("Center point for rotation around the Z axis"),
5982                        CLUTTER_TYPE_GRAVITY,
5983                        CLUTTER_GRAVITY_NONE,
5984                        CLUTTER_PARAM_READWRITE);
5985
5986   /**
5987    * ClutterActor:anchor-x:
5988    *
5989    * The X coordinate of an actor's anchor point, relative to
5990    * the actor coordinate space, in pixels
5991    *
5992    * Since: 0.8
5993    */
5994   obj_props[PROP_ANCHOR_X] =
5995     g_param_spec_float ("anchor-x",
5996                         P_("Anchor X"),
5997                         P_("X coordinate of the anchor point"),
5998                         -G_MAXFLOAT, G_MAXFLOAT,
5999                         0,
6000                         CLUTTER_PARAM_READWRITE);
6001
6002   /**
6003    * ClutterActor:anchor-y:
6004    *
6005    * The Y coordinate of an actor's anchor point, relative to
6006    * the actor coordinate space, in pixels
6007    *
6008    * Since: 0.8
6009    */
6010   obj_props[PROP_ANCHOR_Y] =
6011     g_param_spec_float ("anchor-y",
6012                         P_("Anchor Y"),
6013                         P_("Y coordinate of the anchor point"),
6014                         -G_MAXFLOAT, G_MAXFLOAT,
6015                         0,
6016                         CLUTTER_PARAM_READWRITE);
6017
6018   /**
6019    * ClutterActor:anchor-gravity:
6020    *
6021    * The anchor point expressed as a #ClutterGravity
6022    *
6023    * Since: 1.0
6024    */
6025   obj_props[PROP_ANCHOR_GRAVITY] =
6026     g_param_spec_enum ("anchor-gravity",
6027                        P_("Anchor Gravity"),
6028                        P_("The anchor point as a ClutterGravity"),
6029                        CLUTTER_TYPE_GRAVITY,
6030                        CLUTTER_GRAVITY_NONE,
6031                        CLUTTER_PARAM_READWRITE);
6032
6033   /**
6034    * ClutterActor:show-on-set-parent:
6035    *
6036    * If %TRUE, the actor is automatically shown when parented.
6037    *
6038    * Calling clutter_actor_hide() on an actor which has not been
6039    * parented will set this property to %FALSE as a side effect.
6040    *
6041    * Since: 0.8
6042    */
6043   obj_props[PROP_SHOW_ON_SET_PARENT] =
6044     g_param_spec_boolean ("show-on-set-parent",
6045                           P_("Show on set parent"),
6046                           P_("Whether the actor is shown when parented"),
6047                           TRUE,
6048                           CLUTTER_PARAM_READWRITE);
6049
6050   /**
6051    * ClutterActor:clip-to-allocation:
6052    *
6053    * Whether the clip region should track the allocated area
6054    * of the actor.
6055    *
6056    * This property is ignored if a clip area has been explicitly
6057    * set using clutter_actor_set_clip().
6058    *
6059    * Since: 1.0
6060    */
6061   obj_props[PROP_CLIP_TO_ALLOCATION] =
6062     g_param_spec_boolean ("clip-to-allocation",
6063                           P_("Clip to Allocation"),
6064                           P_("Sets the clip region to track the actor's allocation"),
6065                           FALSE,
6066                           CLUTTER_PARAM_READWRITE);
6067
6068   /**
6069    * ClutterActor:text-direction:
6070    *
6071    * The direction of the text inside a #ClutterActor.
6072    *
6073    * Since: 1.0
6074    */
6075   obj_props[PROP_TEXT_DIRECTION] =
6076     g_param_spec_enum ("text-direction",
6077                        P_("Text Direction"),
6078                        P_("Direction of the text"),
6079                        CLUTTER_TYPE_TEXT_DIRECTION,
6080                        CLUTTER_TEXT_DIRECTION_LTR,
6081                        CLUTTER_PARAM_READWRITE);
6082
6083   /**
6084    * ClutterActor:has-pointer:
6085    *
6086    * Whether the actor contains the pointer of a #ClutterInputDevice
6087    * or not.
6088    *
6089    * Since: 1.2
6090    */
6091   obj_props[PROP_HAS_POINTER] =
6092     g_param_spec_boolean ("has-pointer",
6093                           P_("Has Pointer"),
6094                           P_("Whether the actor contains the pointer of an input device"),
6095                           FALSE,
6096                           CLUTTER_PARAM_READABLE);
6097
6098   /**
6099    * ClutterActor:actions:
6100    *
6101    * Adds a #ClutterAction to the actor
6102    *
6103    * Since: 1.4
6104    */
6105   obj_props[PROP_ACTIONS] =
6106     g_param_spec_object ("actions",
6107                          P_("Actions"),
6108                          P_("Adds an action to the actor"),
6109                          CLUTTER_TYPE_ACTION,
6110                          CLUTTER_PARAM_WRITABLE);
6111
6112   /**
6113    * ClutterActor:constraints:
6114    *
6115    * Adds a #ClutterConstraint to the actor
6116    *
6117    * Since: 1.4
6118    */
6119   obj_props[PROP_CONSTRAINTS] =
6120     g_param_spec_object ("constraints",
6121                          P_("Constraints"),
6122                          P_("Adds a constraint to the actor"),
6123                          CLUTTER_TYPE_CONSTRAINT,
6124                          CLUTTER_PARAM_WRITABLE);
6125
6126   /**
6127    * ClutterActor:effect:
6128    *
6129    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6130    *
6131    * Since: 1.4
6132    */
6133   obj_props[PROP_EFFECT] =
6134     g_param_spec_object ("effect",
6135                          P_("Effect"),
6136                          P_("Add an effect to be applied on the actor"),
6137                          CLUTTER_TYPE_EFFECT,
6138                          CLUTTER_PARAM_WRITABLE);
6139
6140   /**
6141    * ClutterActor:layout-manager:
6142    *
6143    * A delegate object for controlling the layout of the children of
6144    * an actor.
6145    *
6146    * Since: 1.10
6147    */
6148   obj_props[PROP_LAYOUT_MANAGER] =
6149     g_param_spec_object ("layout-manager",
6150                          P_("Layout Manager"),
6151                          P_("The object controlling the layout of an actor's children"),
6152                          CLUTTER_TYPE_LAYOUT_MANAGER,
6153                          CLUTTER_PARAM_READWRITE);
6154
6155
6156   /**
6157    * ClutterActor:x-align:
6158    *
6159    * The alignment of an actor on the X axis, if the actor has been given
6160    * extra space for its allocation.
6161    *
6162    * Since: 1.10
6163    */
6164   obj_props[PROP_X_ALIGN] =
6165     g_param_spec_enum ("x-align",
6166                        P_("X Alignment"),
6167                        P_("The alignment of the actor on the X axis within its allocation"),
6168                        CLUTTER_TYPE_ACTOR_ALIGN,
6169                        CLUTTER_ACTOR_ALIGN_FILL,
6170                        CLUTTER_PARAM_READWRITE);
6171
6172   /**
6173    * ClutterActor:y-align:
6174    *
6175    * The alignment of an actor on the Y axis, if the actor has been given
6176    * extra space for its allocation.
6177    *
6178    * Since: 1.10
6179    */
6180   obj_props[PROP_Y_ALIGN] =
6181     g_param_spec_enum ("y-align",
6182                        P_("Y Alignment"),
6183                        P_("The alignment of the actor on the Y axis within its allocation"),
6184                        CLUTTER_TYPE_ACTOR_ALIGN,
6185                        CLUTTER_ACTOR_ALIGN_FILL,
6186                        CLUTTER_PARAM_READWRITE);
6187
6188   /**
6189    * ClutterActor:margin-top:
6190    *
6191    * The margin (in pixels) from the top of the actor.
6192    *
6193    * This property adds a margin to the actor's preferred size; the margin
6194    * will be automatically taken into account when allocating the actor.
6195    *
6196    * Since: 1.10
6197    */
6198   obj_props[PROP_MARGIN_TOP] =
6199     g_param_spec_float ("margin-top",
6200                         P_("Margin Top"),
6201                         P_("Extra space at the top"),
6202                         0.0, G_MAXFLOAT,
6203                         0.0,
6204                         CLUTTER_PARAM_READWRITE);
6205
6206   /**
6207    * ClutterActor:margin-bottom:
6208    *
6209    * The margin (in pixels) from the bottom of the actor.
6210    *
6211    * This property adds a margin to the actor's preferred size; the margin
6212    * will be automatically taken into account when allocating the actor.
6213    *
6214    * Since: 1.10
6215    */
6216   obj_props[PROP_MARGIN_BOTTOM] =
6217     g_param_spec_float ("margin-bottom",
6218                         P_("Margin Bottom"),
6219                         P_("Extra space at the bottom"),
6220                         0.0, G_MAXFLOAT,
6221                         0.0,
6222                         CLUTTER_PARAM_READWRITE);
6223
6224   /**
6225    * ClutterActor:margin-left:
6226    *
6227    * The margin (in pixels) from the left of the actor.
6228    *
6229    * This property adds a margin to the actor's preferred size; the margin
6230    * will be automatically taken into account when allocating the actor.
6231    *
6232    * Since: 1.10
6233    */
6234   obj_props[PROP_MARGIN_LEFT] =
6235     g_param_spec_float ("margin-left",
6236                         P_("Margin Left"),
6237                         P_("Extra space at the left"),
6238                         0.0, G_MAXFLOAT,
6239                         0.0,
6240                         CLUTTER_PARAM_READWRITE);
6241
6242   /**
6243    * ClutterActor:margin-right:
6244    *
6245    * The margin (in pixels) from the right of the actor.
6246    *
6247    * This property adds a margin to the actor's preferred size; the margin
6248    * will be automatically taken into account when allocating the actor.
6249    *
6250    * Since: 1.10
6251    */
6252   obj_props[PROP_MARGIN_RIGHT] =
6253     g_param_spec_float ("margin-right",
6254                         P_("Margin Right"),
6255                         P_("Extra space at the right"),
6256                         0.0, G_MAXFLOAT,
6257                         0.0,
6258                         CLUTTER_PARAM_READWRITE);
6259
6260   /**
6261    * ClutterActor:background-color-set:
6262    *
6263    * Whether the #ClutterActor:background-color property has been set.
6264    *
6265    * Since: 1.10
6266    */
6267   obj_props[PROP_BACKGROUND_COLOR_SET] =
6268     g_param_spec_boolean ("background-color-set",
6269                           P_("Background Color Set"),
6270                           P_("Whether the background color is set"),
6271                           FALSE,
6272                           CLUTTER_PARAM_READABLE);
6273
6274   /**
6275    * ClutterActor:background-color:
6276    *
6277    * Paints a solid fill of the actor's allocation using the specified
6278    * color.
6279    *
6280    * The #ClutterActor:background-color property is animatable.
6281    *
6282    * Since: 1.10
6283    */
6284   obj_props[PROP_BACKGROUND_COLOR] =
6285     clutter_param_spec_color ("background-color",
6286                               P_("Background color"),
6287                               P_("The actor's background color"),
6288                               CLUTTER_COLOR_Transparent,
6289                               G_PARAM_READWRITE |
6290                               G_PARAM_STATIC_STRINGS |
6291                               CLUTTER_PARAM_ANIMATABLE);
6292
6293   /**
6294    * ClutterActor:first-child:
6295    *
6296    * The actor's first child.
6297    *
6298    * Since: 1.10
6299    */
6300   obj_props[PROP_FIRST_CHILD] =
6301     g_param_spec_object ("first-child",
6302                          P_("First Child"),
6303                          P_("The actor's first child"),
6304                          CLUTTER_TYPE_ACTOR,
6305                          CLUTTER_PARAM_READABLE);
6306
6307   /**
6308    * ClutterActor:last-child:
6309    *
6310    * The actor's last child.
6311    *
6312    * Since: 1.10
6313    */
6314   obj_props[PROP_LAST_CHILD] =
6315     g_param_spec_object ("last-child",
6316                          P_("Last Child"),
6317                          P_("The actor's last child"),
6318                          CLUTTER_TYPE_ACTOR,
6319                          CLUTTER_PARAM_READABLE);
6320
6321   /**
6322    * ClutterActor:content:
6323    *
6324    * The #ClutterContent implementation that controls the content
6325    * of the actor.
6326    *
6327    * Since: 1.10
6328    */
6329   obj_props[PROP_CONTENT] =
6330     g_param_spec_object ("content",
6331                          P_("Content"),
6332                          P_("Delegate object for painting the actor's content"),
6333                          CLUTTER_TYPE_CONTENT,
6334                          CLUTTER_PARAM_READWRITE);
6335
6336   /**
6337    * ClutterActor:content-gravity:
6338    *
6339    * The alignment that should be honoured by the #ClutterContent
6340    * set with the #ClutterActor:content property.
6341    *
6342    * Changing the value of this property will change the bounding box of
6343    * the content; you can use the #ClutterActor:content-box property to
6344    * get the position and size of the content within the actor's
6345    * allocation.
6346    *
6347    * This property is meaningful only for #ClutterContent implementations
6348    * that have a preferred size, and if the preferred size is smaller than
6349    * the actor's allocation.
6350    *
6351    * Since: 1.10
6352    */
6353   obj_props[PROP_CONTENT_GRAVITY] =
6354     g_param_spec_enum ("content-gravity",
6355                        P_("Content Gravity"),
6356                        P_("Alignment of the actor's content"),
6357                        CLUTTER_TYPE_CONTENT_GRAVITY,
6358                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6359                        CLUTTER_PARAM_READWRITE);
6360
6361   /**
6362    * ClutterActor:content-box:
6363    *
6364    * The bounding box for the #ClutterContent used by the actor.
6365    *
6366    * The value of this property is controlled by the #ClutterActor:allocation
6367    * and #ClutterActor:content-gravity properties of #ClutterActor.
6368    *
6369    * The bounding box for the content is guaranteed to never exceed the
6370    * allocation's of the actor.
6371    *
6372    * Since: 1.10
6373    */
6374   obj_props[PROP_CONTENT_BOX] =
6375     g_param_spec_boxed ("content-box",
6376                         P_("Content Box"),
6377                         P_("The bounding box of the actor's content"),
6378                         CLUTTER_TYPE_ACTOR_BOX,
6379                         CLUTTER_PARAM_READABLE);
6380
6381   obj_props[PROP_MINIFICATION_FILTER] =
6382     g_param_spec_enum ("minification-filter",
6383                        P_("Minification Filter"),
6384                        P_("The filter used when reducing the size of the content"),
6385                        CLUTTER_TYPE_SCALING_FILTER,
6386                        CLUTTER_SCALING_FILTER_LINEAR,
6387                        CLUTTER_PARAM_READWRITE);
6388
6389   obj_props[PROP_MAGNIFICATION_FILTER] =
6390     g_param_spec_enum ("magnification-filter",
6391                        P_("Magnification Filter"),
6392                        P_("The filter used when increasing the size of the content"),
6393                        CLUTTER_TYPE_SCALING_FILTER,
6394                        CLUTTER_SCALING_FILTER_LINEAR,
6395                        CLUTTER_PARAM_READWRITE);
6396
6397   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6398
6399   /**
6400    * ClutterActor::destroy:
6401    * @actor: the #ClutterActor which emitted the signal
6402    *
6403    * The ::destroy signal notifies that all references held on the
6404    * actor which emitted it should be released.
6405    *
6406    * The ::destroy signal should be used by all holders of a reference
6407    * on @actor.
6408    *
6409    * This signal might result in the finalization of the #ClutterActor
6410    * if all references are released.
6411    *
6412    * Composite actors and actors implementing the #ClutterContainer
6413    * interface should override the default implementation of the
6414    * class handler of this signal and call clutter_actor_destroy() on
6415    * their children. When overriding the default class handler, it is
6416    * required to chain up to the parent's implementation.
6417    *
6418    * Since: 0.2
6419    */
6420   actor_signals[DESTROY] =
6421     g_signal_new (I_("destroy"),
6422                   G_TYPE_FROM_CLASS (object_class),
6423                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6424                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6425                   NULL, NULL,
6426                   _clutter_marshal_VOID__VOID,
6427                   G_TYPE_NONE, 0);
6428   /**
6429    * ClutterActor::show:
6430    * @actor: the object which received the signal
6431    *
6432    * The ::show signal is emitted when an actor is visible and
6433    * rendered on the stage.
6434    *
6435    * Since: 0.2
6436    */
6437   actor_signals[SHOW] =
6438     g_signal_new (I_("show"),
6439                   G_TYPE_FROM_CLASS (object_class),
6440                   G_SIGNAL_RUN_FIRST,
6441                   G_STRUCT_OFFSET (ClutterActorClass, show),
6442                   NULL, NULL,
6443                   _clutter_marshal_VOID__VOID,
6444                   G_TYPE_NONE, 0);
6445   /**
6446    * ClutterActor::hide:
6447    * @actor: the object which received the signal
6448    *
6449    * The ::hide signal is emitted when an actor is no longer rendered
6450    * on the stage.
6451    *
6452    * Since: 0.2
6453    */
6454   actor_signals[HIDE] =
6455     g_signal_new (I_("hide"),
6456                   G_TYPE_FROM_CLASS (object_class),
6457                   G_SIGNAL_RUN_FIRST,
6458                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6459                   NULL, NULL,
6460                   _clutter_marshal_VOID__VOID,
6461                   G_TYPE_NONE, 0);
6462   /**
6463    * ClutterActor::parent-set:
6464    * @actor: the object which received the signal
6465    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6466    *
6467    * This signal is emitted when the parent of the actor changes.
6468    *
6469    * Since: 0.2
6470    */
6471   actor_signals[PARENT_SET] =
6472     g_signal_new (I_("parent-set"),
6473                   G_TYPE_FROM_CLASS (object_class),
6474                   G_SIGNAL_RUN_LAST,
6475                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6476                   NULL, NULL,
6477                   _clutter_marshal_VOID__OBJECT,
6478                   G_TYPE_NONE, 1,
6479                   CLUTTER_TYPE_ACTOR);
6480
6481   /**
6482    * ClutterActor::queue-redraw:
6483    * @actor: the actor we're bubbling the redraw request through
6484    * @origin: the actor which initiated the redraw request
6485    *
6486    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6487    * is called on @origin.
6488    *
6489    * The default implementation for #ClutterActor chains up to the
6490    * parent actor and queues a redraw on the parent, thus "bubbling"
6491    * the redraw queue up through the actor graph. The default
6492    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6493    * in a main loop idle handler.
6494    *
6495    * Note that the @origin actor may be the stage, or a container; it
6496    * does not have to be a leaf node in the actor graph.
6497    *
6498    * Toolkits embedding a #ClutterStage which require a redraw and
6499    * relayout cycle can stop the emission of this signal using the
6500    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6501    * themselves, like:
6502    *
6503    * |[
6504    *   static void
6505    *   on_redraw_complete (gpointer data)
6506    *   {
6507    *     ClutterStage *stage = data;
6508    *
6509    *     /&ast; execute the Clutter drawing pipeline &ast;/
6510    *     clutter_stage_ensure_redraw (stage);
6511    *   }
6512    *
6513    *   static void
6514    *   on_stage_queue_redraw (ClutterStage *stage)
6515    *   {
6516    *     /&ast; this prevents the default handler to run &ast;/
6517    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6518    *
6519    *     /&ast; queue a redraw with the host toolkit and call
6520    *      &ast; a function when the redraw has been completed
6521    *      &ast;/
6522    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6523    *   }
6524    * ]|
6525    *
6526    * <note><para>This signal is emitted before the Clutter paint
6527    * pipeline is executed. If you want to know when the pipeline has
6528    * been completed you should connect to the ::paint signal on the
6529    * Stage with g_signal_connect_after().</para></note>
6530    *
6531    * Since: 1.0
6532    */
6533   actor_signals[QUEUE_REDRAW] =
6534     g_signal_new (I_("queue-redraw"),
6535                   G_TYPE_FROM_CLASS (object_class),
6536                   G_SIGNAL_RUN_LAST |
6537                   G_SIGNAL_NO_HOOKS,
6538                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6539                   NULL, NULL,
6540                   _clutter_marshal_VOID__OBJECT,
6541                   G_TYPE_NONE, 1,
6542                   CLUTTER_TYPE_ACTOR);
6543
6544   /**
6545    * ClutterActor::queue-relayout
6546    * @actor: the actor being queued for relayout
6547    *
6548    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6549    * is called on an actor.
6550    *
6551    * The default implementation for #ClutterActor chains up to the
6552    * parent actor and queues a relayout on the parent, thus "bubbling"
6553    * the relayout queue up through the actor graph.
6554    *
6555    * The main purpose of this signal is to allow relayout to be propagated
6556    * properly in the procense of #ClutterClone actors. Applications will
6557    * not normally need to connect to this signal.
6558    *
6559    * Since: 1.2
6560    */
6561   actor_signals[QUEUE_RELAYOUT] =
6562     g_signal_new (I_("queue-relayout"),
6563                   G_TYPE_FROM_CLASS (object_class),
6564                   G_SIGNAL_RUN_LAST |
6565                   G_SIGNAL_NO_HOOKS,
6566                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6567                   NULL, NULL,
6568                   _clutter_marshal_VOID__VOID,
6569                   G_TYPE_NONE, 0);
6570
6571   /**
6572    * ClutterActor::event:
6573    * @actor: the actor which received the event
6574    * @event: a #ClutterEvent
6575    *
6576    * The ::event signal is emitted each time an event is received
6577    * by the @actor. This signal will be emitted on every actor,
6578    * following the hierarchy chain, until it reaches the top-level
6579    * container (the #ClutterStage).
6580    *
6581    * Return value: %TRUE if the event has been handled by the actor,
6582    *   or %FALSE to continue the emission.
6583    *
6584    * Since: 0.6
6585    */
6586   actor_signals[EVENT] =
6587     g_signal_new (I_("event"),
6588                   G_TYPE_FROM_CLASS (object_class),
6589                   G_SIGNAL_RUN_LAST,
6590                   G_STRUCT_OFFSET (ClutterActorClass, event),
6591                   _clutter_boolean_handled_accumulator, NULL,
6592                   _clutter_marshal_BOOLEAN__BOXED,
6593                   G_TYPE_BOOLEAN, 1,
6594                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6595   /**
6596    * ClutterActor::button-press-event:
6597    * @actor: the actor which received the event
6598    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6599    *
6600    * The ::button-press-event signal is emitted each time a mouse button
6601    * is pressed on @actor.
6602    *
6603    * Return value: %TRUE if the event has been handled by the actor,
6604    *   or %FALSE to continue the emission.
6605    *
6606    * Since: 0.6
6607    */
6608   actor_signals[BUTTON_PRESS_EVENT] =
6609     g_signal_new (I_("button-press-event"),
6610                   G_TYPE_FROM_CLASS (object_class),
6611                   G_SIGNAL_RUN_LAST,
6612                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6613                   _clutter_boolean_handled_accumulator, NULL,
6614                   _clutter_marshal_BOOLEAN__BOXED,
6615                   G_TYPE_BOOLEAN, 1,
6616                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6617   /**
6618    * ClutterActor::button-release-event:
6619    * @actor: the actor which received the event
6620    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6621    *
6622    * The ::button-release-event signal is emitted each time a mouse button
6623    * is released on @actor.
6624    *
6625    * Return value: %TRUE if the event has been handled by the actor,
6626    *   or %FALSE to continue the emission.
6627    *
6628    * Since: 0.6
6629    */
6630   actor_signals[BUTTON_RELEASE_EVENT] =
6631     g_signal_new (I_("button-release-event"),
6632                   G_TYPE_FROM_CLASS (object_class),
6633                   G_SIGNAL_RUN_LAST,
6634                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6635                   _clutter_boolean_handled_accumulator, NULL,
6636                   _clutter_marshal_BOOLEAN__BOXED,
6637                   G_TYPE_BOOLEAN, 1,
6638                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6639   /**
6640    * ClutterActor::scroll-event:
6641    * @actor: the actor which received the event
6642    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6643    *
6644    * The ::scroll-event signal is emitted each time the mouse is
6645    * scrolled on @actor
6646    *
6647    * Return value: %TRUE if the event has been handled by the actor,
6648    *   or %FALSE to continue the emission.
6649    *
6650    * Since: 0.6
6651    */
6652   actor_signals[SCROLL_EVENT] =
6653     g_signal_new (I_("scroll-event"),
6654                   G_TYPE_FROM_CLASS (object_class),
6655                   G_SIGNAL_RUN_LAST,
6656                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6657                   _clutter_boolean_handled_accumulator, NULL,
6658                   _clutter_marshal_BOOLEAN__BOXED,
6659                   G_TYPE_BOOLEAN, 1,
6660                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6661   /**
6662    * ClutterActor::key-press-event:
6663    * @actor: the actor which received the event
6664    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6665    *
6666    * The ::key-press-event signal is emitted each time a keyboard button
6667    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6668    *
6669    * Return value: %TRUE if the event has been handled by the actor,
6670    *   or %FALSE to continue the emission.
6671    *
6672    * Since: 0.6
6673    */
6674   actor_signals[KEY_PRESS_EVENT] =
6675     g_signal_new (I_("key-press-event"),
6676                   G_TYPE_FROM_CLASS (object_class),
6677                   G_SIGNAL_RUN_LAST,
6678                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6679                   _clutter_boolean_handled_accumulator, NULL,
6680                   _clutter_marshal_BOOLEAN__BOXED,
6681                   G_TYPE_BOOLEAN, 1,
6682                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6683   /**
6684    * ClutterActor::key-release-event:
6685    * @actor: the actor which received the event
6686    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6687    *
6688    * The ::key-release-event signal is emitted each time a keyboard button
6689    * is released while @actor has key focus (see
6690    * clutter_stage_set_key_focus()).
6691    *
6692    * Return value: %TRUE if the event has been handled by the actor,
6693    *   or %FALSE to continue the emission.
6694    *
6695    * Since: 0.6
6696    */
6697   actor_signals[KEY_RELEASE_EVENT] =
6698     g_signal_new (I_("key-release-event"),
6699                   G_TYPE_FROM_CLASS (object_class),
6700                   G_SIGNAL_RUN_LAST,
6701                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6702                   _clutter_boolean_handled_accumulator, NULL,
6703                   _clutter_marshal_BOOLEAN__BOXED,
6704                   G_TYPE_BOOLEAN, 1,
6705                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6706   /**
6707    * ClutterActor::motion-event:
6708    * @actor: the actor which received the event
6709    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6710    *
6711    * The ::motion-event signal is emitted each time the mouse pointer is
6712    * moved over @actor.
6713    *
6714    * Return value: %TRUE if the event has been handled by the actor,
6715    *   or %FALSE to continue the emission.
6716    *
6717    * Since: 0.6
6718    */
6719   actor_signals[MOTION_EVENT] =
6720     g_signal_new (I_("motion-event"),
6721                   G_TYPE_FROM_CLASS (object_class),
6722                   G_SIGNAL_RUN_LAST,
6723                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6724                   _clutter_boolean_handled_accumulator, NULL,
6725                   _clutter_marshal_BOOLEAN__BOXED,
6726                   G_TYPE_BOOLEAN, 1,
6727                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6728
6729   /**
6730    * ClutterActor::key-focus-in:
6731    * @actor: the actor which now has key focus
6732    *
6733    * The ::key-focus-in signal is emitted when @actor receives key focus.
6734    *
6735    * Since: 0.6
6736    */
6737   actor_signals[KEY_FOCUS_IN] =
6738     g_signal_new (I_("key-focus-in"),
6739                   G_TYPE_FROM_CLASS (object_class),
6740                   G_SIGNAL_RUN_LAST,
6741                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6742                   NULL, NULL,
6743                   _clutter_marshal_VOID__VOID,
6744                   G_TYPE_NONE, 0);
6745
6746   /**
6747    * ClutterActor::key-focus-out:
6748    * @actor: the actor which now has key focus
6749    *
6750    * The ::key-focus-out signal is emitted when @actor loses key focus.
6751    *
6752    * Since: 0.6
6753    */
6754   actor_signals[KEY_FOCUS_OUT] =
6755     g_signal_new (I_("key-focus-out"),
6756                   G_TYPE_FROM_CLASS (object_class),
6757                   G_SIGNAL_RUN_LAST,
6758                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6759                   NULL, NULL,
6760                   _clutter_marshal_VOID__VOID,
6761                   G_TYPE_NONE, 0);
6762
6763   /**
6764    * ClutterActor::enter-event:
6765    * @actor: the actor which the pointer has entered.
6766    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6767    *
6768    * The ::enter-event signal is emitted when the pointer enters the @actor
6769    *
6770    * Return value: %TRUE if the event has been handled by the actor,
6771    *   or %FALSE to continue the emission.
6772    *
6773    * Since: 0.6
6774    */
6775   actor_signals[ENTER_EVENT] =
6776     g_signal_new (I_("enter-event"),
6777                   G_TYPE_FROM_CLASS (object_class),
6778                   G_SIGNAL_RUN_LAST,
6779                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6780                   _clutter_boolean_handled_accumulator, NULL,
6781                   _clutter_marshal_BOOLEAN__BOXED,
6782                   G_TYPE_BOOLEAN, 1,
6783                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6784
6785   /**
6786    * ClutterActor::leave-event:
6787    * @actor: the actor which the pointer has left
6788    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6789    *
6790    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6791    *
6792    * Return value: %TRUE if the event has been handled by the actor,
6793    *   or %FALSE to continue the emission.
6794    *
6795    * Since: 0.6
6796    */
6797   actor_signals[LEAVE_EVENT] =
6798     g_signal_new (I_("leave-event"),
6799                   G_TYPE_FROM_CLASS (object_class),
6800                   G_SIGNAL_RUN_LAST,
6801                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6802                   _clutter_boolean_handled_accumulator, NULL,
6803                   _clutter_marshal_BOOLEAN__BOXED,
6804                   G_TYPE_BOOLEAN, 1,
6805                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6806
6807   /**
6808    * ClutterActor::captured-event:
6809    * @actor: the actor which received the signal
6810    * @event: a #ClutterEvent
6811    *
6812    * The ::captured-event signal is emitted when an event is captured
6813    * by Clutter. This signal will be emitted starting from the top-level
6814    * container (the #ClutterStage) to the actor which received the event
6815    * going down the hierarchy. This signal can be used to intercept every
6816    * event before the specialized events (like
6817    * ClutterActor::button-press-event or ::key-released-event) are
6818    * emitted.
6819    *
6820    * Return value: %TRUE if the event has been handled by the actor,
6821    *   or %FALSE to continue the emission.
6822    *
6823    * Since: 0.6
6824    */
6825   actor_signals[CAPTURED_EVENT] =
6826     g_signal_new (I_("captured-event"),
6827                   G_TYPE_FROM_CLASS (object_class),
6828                   G_SIGNAL_RUN_LAST,
6829                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6830                   _clutter_boolean_handled_accumulator, NULL,
6831                   _clutter_marshal_BOOLEAN__BOXED,
6832                   G_TYPE_BOOLEAN, 1,
6833                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6834
6835   /**
6836    * ClutterActor::paint:
6837    * @actor: the #ClutterActor that received the signal
6838    *
6839    * The ::paint signal is emitted each time an actor is being painted.
6840    *
6841    * Subclasses of #ClutterActor should override the class signal handler
6842    * and paint themselves in that function.
6843    *
6844    * It is possible to connect a handler to the ::paint signal in order
6845    * to set up some custom aspect of a paint.
6846    *
6847    * Since: 0.8
6848    */
6849   actor_signals[PAINT] =
6850     g_signal_new (I_("paint"),
6851                   G_TYPE_FROM_CLASS (object_class),
6852                   G_SIGNAL_RUN_LAST |
6853                   G_SIGNAL_NO_HOOKS,
6854                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6855                   NULL, NULL,
6856                   _clutter_marshal_VOID__VOID,
6857                   G_TYPE_NONE, 0);
6858   /**
6859    * ClutterActor::realize:
6860    * @actor: the #ClutterActor that received the signal
6861    *
6862    * The ::realize signal is emitted each time an actor is being
6863    * realized.
6864    *
6865    * Since: 0.8
6866    */
6867   actor_signals[REALIZE] =
6868     g_signal_new (I_("realize"),
6869                   G_TYPE_FROM_CLASS (object_class),
6870                   G_SIGNAL_RUN_LAST,
6871                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6872                   NULL, NULL,
6873                   _clutter_marshal_VOID__VOID,
6874                   G_TYPE_NONE, 0);
6875   /**
6876    * ClutterActor::unrealize:
6877    * @actor: the #ClutterActor that received the signal
6878    *
6879    * The ::unrealize signal is emitted each time an actor is being
6880    * unrealized.
6881    *
6882    * Since: 0.8
6883    */
6884   actor_signals[UNREALIZE] =
6885     g_signal_new (I_("unrealize"),
6886                   G_TYPE_FROM_CLASS (object_class),
6887                   G_SIGNAL_RUN_LAST,
6888                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6889                   NULL, NULL,
6890                   _clutter_marshal_VOID__VOID,
6891                   G_TYPE_NONE, 0);
6892
6893   /**
6894    * ClutterActor::pick:
6895    * @actor: the #ClutterActor that received the signal
6896    * @color: the #ClutterColor to be used when picking
6897    *
6898    * The ::pick signal is emitted each time an actor is being painted
6899    * in "pick mode". The pick mode is used to identify the actor during
6900    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6901    * The actor should paint its shape using the passed @pick_color.
6902    *
6903    * Subclasses of #ClutterActor should override the class signal handler
6904    * and paint themselves in that function.
6905    *
6906    * It is possible to connect a handler to the ::pick signal in order
6907    * to set up some custom aspect of a paint in pick mode.
6908    *
6909    * Since: 1.0
6910    */
6911   actor_signals[PICK] =
6912     g_signal_new (I_("pick"),
6913                   G_TYPE_FROM_CLASS (object_class),
6914                   G_SIGNAL_RUN_LAST,
6915                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6916                   NULL, NULL,
6917                   _clutter_marshal_VOID__BOXED,
6918                   G_TYPE_NONE, 1,
6919                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6920
6921   /**
6922    * ClutterActor::allocation-changed:
6923    * @actor: the #ClutterActor that emitted the signal
6924    * @box: a #ClutterActorBox with the new allocation
6925    * @flags: #ClutterAllocationFlags for the allocation
6926    *
6927    * The ::allocation-changed signal is emitted when the
6928    * #ClutterActor:allocation property changes. Usually, application
6929    * code should just use the notifications for the :allocation property
6930    * but if you want to track the allocation flags as well, for instance
6931    * to know whether the absolute origin of @actor changed, then you might
6932    * want use this signal instead.
6933    *
6934    * Since: 1.0
6935    */
6936   actor_signals[ALLOCATION_CHANGED] =
6937     g_signal_new (I_("allocation-changed"),
6938                   G_TYPE_FROM_CLASS (object_class),
6939                   G_SIGNAL_RUN_LAST,
6940                   0,
6941                   NULL, NULL,
6942                   _clutter_marshal_VOID__BOXED_FLAGS,
6943                   G_TYPE_NONE, 2,
6944                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6945                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6946 }
6947
6948 static void
6949 clutter_actor_init (ClutterActor *self)
6950 {
6951   ClutterActorPrivate *priv;
6952
6953   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6954
6955   priv->id = _clutter_context_acquire_id (self);
6956   priv->pick_id = -1;
6957
6958   priv->opacity = 0xff;
6959   priv->show_on_set_parent = TRUE;
6960
6961   priv->needs_width_request = TRUE;
6962   priv->needs_height_request = TRUE;
6963   priv->needs_allocation = TRUE;
6964
6965   priv->cached_width_age = 1;
6966   priv->cached_height_age = 1;
6967
6968   priv->opacity_override = -1;
6969   priv->enable_model_view_transform = TRUE;
6970
6971   /* Initialize an empty paint volume to start with */
6972   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6973   priv->last_paint_volume_valid = TRUE;
6974
6975   priv->transform_valid = FALSE;
6976
6977   /* the default is to stretch the content, to match the
6978    * current behaviour of basically all actors. also, it's
6979    * the easiest thing to compute.
6980    */
6981   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
6982   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
6983   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
6984 }
6985
6986 /**
6987  * clutter_actor_new:
6988  *
6989  * Creates a new #ClutterActor.
6990  *
6991  * A newly created actor has a floating reference, which will be sunk
6992  * when it is added to another actor.
6993  *
6994  * Return value: (transfer full): the newly created #ClutterActor
6995  *
6996  * Since: 1.10
6997  */
6998 ClutterActor *
6999 clutter_actor_new (void)
7000 {
7001   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7002 }
7003
7004 /**
7005  * clutter_actor_destroy:
7006  * @self: a #ClutterActor
7007  *
7008  * Destroys an actor.  When an actor is destroyed, it will break any
7009  * references it holds to other objects.  If the actor is inside a
7010  * container, the actor will be removed.
7011  *
7012  * When you destroy a container, its children will be destroyed as well.
7013  *
7014  * Note: you cannot destroy the #ClutterStage returned by
7015  * clutter_stage_get_default().
7016  */
7017 void
7018 clutter_actor_destroy (ClutterActor *self)
7019 {
7020   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7021
7022   g_object_ref (self);
7023
7024   /* avoid recursion while destroying */
7025   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7026     {
7027       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7028
7029       g_object_run_dispose (G_OBJECT (self));
7030
7031       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7032     }
7033
7034   g_object_unref (self);
7035 }
7036
7037 void
7038 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7039                                     ClutterPaintVolume *clip)
7040 {
7041   ClutterActorPrivate *priv = self->priv;
7042   ClutterPaintVolume *pv;
7043   gboolean clipped;
7044
7045   /* Remove queue entry early in the process, otherwise a new
7046      queue_redraw() during signal handling could put back this
7047      object in the stage redraw list (but the entry is freed as
7048      soon as we return from this function, causing a segfault
7049      later)
7050   */
7051   priv->queue_redraw_entry = NULL;
7052
7053   /* If we've been explicitly passed a clip volume then there's
7054    * nothing more to calculate, but otherwise the only thing we know
7055    * is that the change is constrained to the given actor.
7056    *
7057    * The idea is that if we know the paint volume for where the actor
7058    * was last drawn (in eye coordinates) and we also have the paint
7059    * volume for where it will be drawn next (in actor coordinates)
7060    * then if we queue a redraw for both these volumes that will cover
7061    * everything that needs to be redrawn to clear the old view and
7062    * show the latest view of the actor.
7063    *
7064    * Don't clip this redraw if we don't know what position we had for
7065    * the previous redraw since we don't know where to set the clip so
7066    * it will clear the actor as it is currently.
7067    */
7068   if (clip)
7069     {
7070       _clutter_actor_set_queue_redraw_clip (self, clip);
7071       clipped = TRUE;
7072     }
7073   else if (G_LIKELY (priv->last_paint_volume_valid))
7074     {
7075       pv = _clutter_actor_get_paint_volume_mutable (self);
7076       if (pv)
7077         {
7078           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7079
7080           /* make sure we redraw the actors old position... */
7081           _clutter_actor_set_queue_redraw_clip (stage,
7082                                                 &priv->last_paint_volume);
7083           _clutter_actor_signal_queue_redraw (stage, stage);
7084           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7085
7086           /* XXX: Ideally the redraw signal would take a clip volume
7087            * argument, but that would be an ABI break. Until we can
7088            * break the ABI we pass the argument out-of-band
7089            */
7090
7091           /* setup the clip for the actors new position... */
7092           _clutter_actor_set_queue_redraw_clip (self, pv);
7093           clipped = TRUE;
7094         }
7095       else
7096         clipped = FALSE;
7097     }
7098   else
7099     clipped = FALSE;
7100
7101   _clutter_actor_signal_queue_redraw (self, self);
7102
7103   /* Just in case anyone is manually firing redraw signals without
7104    * using the public queue_redraw() API we are careful to ensure that
7105    * our out-of-band clip member is cleared before returning...
7106    *
7107    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7108    */
7109   if (G_LIKELY (clipped))
7110     _clutter_actor_set_queue_redraw_clip (self, NULL);
7111 }
7112
7113 static void
7114 _clutter_actor_get_allocation_clip (ClutterActor *self,
7115                                     ClutterActorBox *clip)
7116 {
7117   ClutterActorBox allocation;
7118
7119   /* XXX: we don't care if we get an out of date allocation here
7120    * because clutter_actor_queue_redraw_with_clip knows to ignore
7121    * the clip if the actor's allocation is invalid.
7122    *
7123    * This is noted because clutter_actor_get_allocation_box does some
7124    * unnecessary work to support buggy code with a comment suggesting
7125    * that it could be changed later which would be good for this use
7126    * case!
7127    */
7128   clutter_actor_get_allocation_box (self, &allocation);
7129
7130   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7131    * actor's own coordinate space but the allocation is in parent
7132    * coordinates */
7133   clip->x1 = 0;
7134   clip->y1 = 0;
7135   clip->x2 = allocation.x2 - allocation.x1;
7136   clip->y2 = allocation.y2 - allocation.y1;
7137 }
7138
7139 void
7140 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7141                                   ClutterRedrawFlags  flags,
7142                                   ClutterPaintVolume *volume,
7143                                   ClutterEffect      *effect)
7144 {
7145   ClutterActorPrivate *priv = self->priv;
7146   ClutterPaintVolume allocation_pv;
7147   ClutterPaintVolume *pv;
7148   gboolean should_free_pv;
7149   ClutterActor *stage;
7150
7151   /* Here's an outline of the actor queue redraw mechanism:
7152    *
7153    * The process starts in one of the following two functions which
7154    * are wrappers for this function:
7155    * clutter_actor_queue_redraw
7156    * _clutter_actor_queue_redraw_with_clip
7157    *
7158    * additionally, an effect can queue a redraw by wrapping this
7159    * function in clutter_effect_queue_rerun
7160    *
7161    * This functions queues an entry in a list associated with the
7162    * stage which is a list of actors that queued a redraw while
7163    * updating the timelines, performing layouting and processing other
7164    * mainloop sources before the next paint starts.
7165    *
7166    * We aim to minimize the processing done at this point because
7167    * there is a good chance other events will happen while updating
7168    * the scenegraph that would invalidate any expensive work we might
7169    * otherwise try to do here. For example we don't try and resolve
7170    * the screen space bounding box of an actor at this stage so as to
7171    * minimize how much of the screen redraw because it's possible
7172    * something else will happen which will force a full redraw anyway.
7173    *
7174    * When all updates are complete and we come to paint the stage then
7175    * we iterate this list and actually emit the "queue-redraw" signals
7176    * for each of the listed actors which will bubble up to the stage
7177    * for each actor and at that point we will transform the actors
7178    * paint volume into screen coordinates to determine the clip region
7179    * for what needs to be redrawn in the next paint.
7180    *
7181    * Besides minimizing redundant work another reason for this
7182    * deferred design is that it's more likely we will be able to
7183    * determine the paint volume of an actor once we've finished
7184    * updating the scenegraph because its allocation should be up to
7185    * date. NB: If we can't determine an actors paint volume then we
7186    * can't automatically queue a clipped redraw which can make a big
7187    * difference to performance.
7188    *
7189    * So the control flow goes like this:
7190    * One of clutter_actor_queue_redraw,
7191    *        _clutter_actor_queue_redraw_with_clip
7192    *     or clutter_effect_queue_rerun
7193    *
7194    * then control moves to:
7195    *   _clutter_stage_queue_actor_redraw
7196    *
7197    * later during _clutter_stage_do_update, once relayouting is done
7198    * and the scenegraph has been updated we will call:
7199    * _clutter_stage_finish_queue_redraws
7200    *
7201    * _clutter_stage_finish_queue_redraws will call
7202    * _clutter_actor_finish_queue_redraw for each listed actor.
7203    * Note: actors *are* allowed to queue further redraws during this
7204    * process (considering clone actors or texture_new_from_actor which
7205    * respond to their source queueing a redraw by queuing a redraw
7206    * themselves). We repeat the process until the list is empty.
7207    *
7208    * This will result in the "queue-redraw" signal being fired for
7209    * each actor which will pass control to the default signal handler:
7210    * clutter_actor_real_queue_redraw
7211    *
7212    * This will bubble up to the stages handler:
7213    * clutter_stage_real_queue_redraw
7214    *
7215    * clutter_stage_real_queue_redraw will transform the actors paint
7216    * volume into screen space and add it as a clip region for the next
7217    * paint.
7218    */
7219
7220   /* ignore queueing a redraw for actors being destroyed */
7221   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7222     return;
7223
7224   stage = _clutter_actor_get_stage_internal (self);
7225
7226   /* Ignore queueing a redraw for actors not descended from a stage */
7227   if (stage == NULL)
7228     return;
7229
7230   /* ignore queueing a redraw on stages that are being destroyed */
7231   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7232     return;
7233
7234   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7235     {
7236       ClutterActorBox allocation_clip;
7237       ClutterVertex origin;
7238
7239       /* If the actor doesn't have a valid allocation then we will
7240        * queue a full stage redraw. */
7241       if (priv->needs_allocation)
7242         {
7243           /* NB: NULL denotes an undefined clip which will result in a
7244            * full redraw... */
7245           _clutter_actor_set_queue_redraw_clip (self, NULL);
7246           _clutter_actor_signal_queue_redraw (self, self);
7247           return;
7248         }
7249
7250       _clutter_paint_volume_init_static (&allocation_pv, self);
7251       pv = &allocation_pv;
7252
7253       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7254
7255       origin.x = allocation_clip.x1;
7256       origin.y = allocation_clip.y1;
7257       origin.z = 0;
7258       clutter_paint_volume_set_origin (pv, &origin);
7259       clutter_paint_volume_set_width (pv,
7260                                       allocation_clip.x2 - allocation_clip.x1);
7261       clutter_paint_volume_set_height (pv,
7262                                        allocation_clip.y2 -
7263                                        allocation_clip.y1);
7264       should_free_pv = TRUE;
7265     }
7266   else
7267     {
7268       pv = volume;
7269       should_free_pv = FALSE;
7270     }
7271
7272   self->priv->queue_redraw_entry =
7273     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7274                                        priv->queue_redraw_entry,
7275                                        self,
7276                                        pv);
7277
7278   if (should_free_pv)
7279     clutter_paint_volume_free (pv);
7280
7281   /* If this is the first redraw queued then we can directly use the
7282      effect parameter */
7283   if (!priv->is_dirty)
7284     priv->effect_to_redraw = effect;
7285   /* Otherwise we need to merge it with the existing effect parameter */
7286   else if (effect != NULL)
7287     {
7288       /* If there's already an effect then we need to use whichever is
7289          later in the chain of actors. Otherwise a full redraw has
7290          already been queued on the actor so we need to ignore the
7291          effect parameter */
7292       if (priv->effect_to_redraw != NULL)
7293         {
7294           if (priv->effects == NULL)
7295             g_warning ("Redraw queued with an effect that is "
7296                        "not applied to the actor");
7297           else
7298             {
7299               const GList *l;
7300
7301               for (l = _clutter_meta_group_peek_metas (priv->effects);
7302                    l != NULL;
7303                    l = l->next)
7304                 {
7305                   if (l->data == priv->effect_to_redraw ||
7306                       l->data == effect)
7307                     priv->effect_to_redraw = l->data;
7308                 }
7309             }
7310         }
7311     }
7312   else
7313     {
7314       /* If no effect is specified then we need to redraw the whole
7315          actor */
7316       priv->effect_to_redraw = NULL;
7317     }
7318
7319   priv->is_dirty = TRUE;
7320 }
7321
7322 /**
7323  * clutter_actor_queue_redraw:
7324  * @self: A #ClutterActor
7325  *
7326  * Queues up a redraw of an actor and any children. The redraw occurs
7327  * once the main loop becomes idle (after the current batch of events
7328  * has been processed, roughly).
7329  *
7330  * Applications rarely need to call this, as redraws are handled
7331  * automatically by modification functions.
7332  *
7333  * This function will not do anything if @self is not visible, or
7334  * if the actor is inside an invisible part of the scenegraph.
7335  *
7336  * Also be aware that painting is a NOP for actors with an opacity of
7337  * 0
7338  *
7339  * When you are implementing a custom actor you must queue a redraw
7340  * whenever some private state changes that will affect painting or
7341  * picking of your actor.
7342  */
7343 void
7344 clutter_actor_queue_redraw (ClutterActor *self)
7345 {
7346   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7347
7348   _clutter_actor_queue_redraw_full (self,
7349                                     0, /* flags */
7350                                     NULL, /* clip volume */
7351                                     NULL /* effect */);
7352 }
7353
7354 /*< private >
7355  * _clutter_actor_queue_redraw_with_clip:
7356  * @self: A #ClutterActor
7357  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7358  *   this queue redraw.
7359  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7360  *   redrawn or %NULL if you are just using a @flag to state your
7361  *   desired clipping.
7362  *
7363  * Queues up a clipped redraw of an actor and any children. The redraw
7364  * occurs once the main loop becomes idle (after the current batch of
7365  * events has been processed, roughly).
7366  *
7367  * If no flags are given the clip volume is defined by @volume
7368  * specified in actor coordinates and tells Clutter that only content
7369  * within this volume has been changed so Clutter can optionally
7370  * optimize the redraw.
7371  *
7372  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7373  * should be %NULL and this tells Clutter to use the actor's current
7374  * allocation as a clip box. This flag can only be used for 2D actors,
7375  * because any actor with depth may be projected outside its
7376  * allocation.
7377  *
7378  * Applications rarely need to call this, as redraws are handled
7379  * automatically by modification functions.
7380  *
7381  * This function will not do anything if @self is not visible, or if
7382  * the actor is inside an invisible part of the scenegraph.
7383  *
7384  * Also be aware that painting is a NOP for actors with an opacity of
7385  * 0
7386  *
7387  * When you are implementing a custom actor you must queue a redraw
7388  * whenever some private state changes that will affect painting or
7389  * picking of your actor.
7390  */
7391 void
7392 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7393                                        ClutterRedrawFlags  flags,
7394                                        ClutterPaintVolume *volume)
7395 {
7396   _clutter_actor_queue_redraw_full (self,
7397                                     flags, /* flags */
7398                                     volume, /* clip volume */
7399                                     NULL /* effect */);
7400 }
7401
7402 static void
7403 _clutter_actor_queue_only_relayout (ClutterActor *self)
7404 {
7405   ClutterActorPrivate *priv = self->priv;
7406
7407   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7408     return;
7409
7410   if (priv->needs_width_request &&
7411       priv->needs_height_request &&
7412       priv->needs_allocation)
7413     return; /* save some cpu cycles */
7414
7415 #if CLUTTER_ENABLE_DEBUG
7416   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7417     {
7418       g_warning ("The actor '%s' is currently inside an allocation "
7419                  "cycle; calling clutter_actor_queue_relayout() is "
7420                  "not recommended",
7421                  _clutter_actor_get_debug_name (self));
7422     }
7423 #endif /* CLUTTER_ENABLE_DEBUG */
7424
7425   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7426 }
7427
7428 /**
7429  * clutter_actor_queue_redraw_with_clip:
7430  * @self: a #ClutterActor
7431  * @clip: (allow-none): a rectangular clip region, or %NULL
7432  *
7433  * Queues a redraw on @self limited to a specific, actor-relative
7434  * rectangular area.
7435  *
7436  * If @clip is %NULL this function is equivalent to
7437  * clutter_actor_queue_redraw().
7438  *
7439  * Since: 1.10
7440  */
7441 void
7442 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7443                                       const cairo_rectangle_int_t *clip)
7444 {
7445   ClutterPaintVolume volume;
7446   ClutterVertex origin;
7447
7448   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7449
7450   if (clip == NULL)
7451     {
7452       clutter_actor_queue_redraw (self);
7453       return;
7454     }
7455
7456   _clutter_paint_volume_init_static (&volume, self);
7457
7458   origin.x = clip->x;
7459   origin.y = clip->y;
7460   origin.z = 0.0f;
7461
7462   clutter_paint_volume_set_origin (&volume, &origin);
7463   clutter_paint_volume_set_width (&volume, clip->width);
7464   clutter_paint_volume_set_height (&volume, clip->height);
7465
7466   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7467
7468   clutter_paint_volume_free (&volume);
7469 }
7470
7471 /**
7472  * clutter_actor_queue_relayout:
7473  * @self: A #ClutterActor
7474  *
7475  * Indicates that the actor's size request or other layout-affecting
7476  * properties may have changed. This function is used inside #ClutterActor
7477  * subclass implementations, not by applications directly.
7478  *
7479  * Queueing a new layout automatically queues a redraw as well.
7480  *
7481  * Since: 0.8
7482  */
7483 void
7484 clutter_actor_queue_relayout (ClutterActor *self)
7485 {
7486   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7487
7488   _clutter_actor_queue_only_relayout (self);
7489   clutter_actor_queue_redraw (self);
7490 }
7491
7492 /**
7493  * clutter_actor_get_preferred_size:
7494  * @self: a #ClutterActor
7495  * @min_width_p: (out) (allow-none): return location for the minimum
7496  *   width, or %NULL
7497  * @min_height_p: (out) (allow-none): return location for the minimum
7498  *   height, or %NULL
7499  * @natural_width_p: (out) (allow-none): return location for the natural
7500  *   width, or %NULL
7501  * @natural_height_p: (out) (allow-none): return location for the natural
7502  *   height, or %NULL
7503  *
7504  * Computes the preferred minimum and natural size of an actor, taking into
7505  * account the actor's geometry management (either height-for-width
7506  * or width-for-height).
7507  *
7508  * The width and height used to compute the preferred height and preferred
7509  * width are the actor's natural ones.
7510  *
7511  * If you need to control the height for the preferred width, or the width for
7512  * the preferred height, you should use clutter_actor_get_preferred_width()
7513  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7514  * geometry management using the #ClutterActor:request-mode property.
7515  *
7516  * Since: 0.8
7517  */
7518 void
7519 clutter_actor_get_preferred_size (ClutterActor *self,
7520                                   gfloat       *min_width_p,
7521                                   gfloat       *min_height_p,
7522                                   gfloat       *natural_width_p,
7523                                   gfloat       *natural_height_p)
7524 {
7525   ClutterActorPrivate *priv;
7526   gfloat min_width, min_height;
7527   gfloat natural_width, natural_height;
7528
7529   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7530
7531   priv = self->priv;
7532
7533   min_width = min_height = 0;
7534   natural_width = natural_height = 0;
7535
7536   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7537     {
7538       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7539       clutter_actor_get_preferred_width (self, -1,
7540                                          &min_width,
7541                                          &natural_width);
7542       clutter_actor_get_preferred_height (self, natural_width,
7543                                           &min_height,
7544                                           &natural_height);
7545     }
7546   else
7547     {
7548       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7549       clutter_actor_get_preferred_height (self, -1,
7550                                           &min_height,
7551                                           &natural_height);
7552       clutter_actor_get_preferred_width (self, natural_height,
7553                                          &min_width,
7554                                          &natural_width);
7555     }
7556
7557   if (min_width_p)
7558     *min_width_p = min_width;
7559
7560   if (min_height_p)
7561     *min_height_p = min_height;
7562
7563   if (natural_width_p)
7564     *natural_width_p = natural_width;
7565
7566   if (natural_height_p)
7567     *natural_height_p = natural_height;
7568 }
7569
7570 /*< private >
7571  * effective_align:
7572  * @align: a #ClutterActorAlign
7573  * @direction: a #ClutterTextDirection
7574  *
7575  * Retrieves the correct alignment depending on the text direction
7576  *
7577  * Return value: the effective alignment
7578  */
7579 static ClutterActorAlign
7580 effective_align (ClutterActorAlign    align,
7581                  ClutterTextDirection direction)
7582 {
7583   ClutterActorAlign res;
7584
7585   switch (align)
7586     {
7587     case CLUTTER_ACTOR_ALIGN_START:
7588       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7589           ? CLUTTER_ACTOR_ALIGN_END
7590           : CLUTTER_ACTOR_ALIGN_START;
7591       break;
7592
7593     case CLUTTER_ACTOR_ALIGN_END:
7594       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7595           ? CLUTTER_ACTOR_ALIGN_START
7596           : CLUTTER_ACTOR_ALIGN_END;
7597       break;
7598
7599     default:
7600       res = align;
7601       break;
7602     }
7603
7604   return res;
7605 }
7606
7607 static inline void
7608 adjust_for_margin (float  margin_start,
7609                    float  margin_end,
7610                    float *minimum_size,
7611                    float *natural_size,
7612                    float *allocated_start,
7613                    float *allocated_end)
7614 {
7615   *minimum_size -= (margin_start + margin_end);
7616   *natural_size -= (margin_start + margin_end);
7617   *allocated_start += margin_start;
7618   *allocated_end -= margin_end;
7619 }
7620
7621 static inline void
7622 adjust_for_alignment (ClutterActorAlign  alignment,
7623                       float              natural_size,
7624                       float             *allocated_start,
7625                       float             *allocated_end)
7626 {
7627   float allocated_size = *allocated_end - *allocated_start;
7628
7629   switch (alignment)
7630     {
7631     case CLUTTER_ACTOR_ALIGN_FILL:
7632       /* do nothing */
7633       break;
7634
7635     case CLUTTER_ACTOR_ALIGN_START:
7636       /* keep start */
7637       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7638       break;
7639
7640     case CLUTTER_ACTOR_ALIGN_END:
7641       if (allocated_size > natural_size)
7642         {
7643           *allocated_start += (allocated_size - natural_size);
7644           *allocated_end = *allocated_start + natural_size;
7645         }
7646       break;
7647
7648     case CLUTTER_ACTOR_ALIGN_CENTER:
7649       if (allocated_size > natural_size)
7650         {
7651           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7652           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7653         }
7654       break;
7655     }
7656 }
7657
7658 /*< private >
7659  * clutter_actor_adjust_width:
7660  * @self: a #ClutterActor
7661  * @minimum_width: (inout): the actor's preferred minimum width, which
7662  *   will be adjusted depending on the margin
7663  * @natural_width: (inout): the actor's preferred natural width, which
7664  *   will be adjusted depending on the margin
7665  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7666  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7667  *
7668  * Adjusts the preferred and allocated position and size of an actor,
7669  * depending on the margin and alignment properties.
7670  */
7671 static void
7672 clutter_actor_adjust_width (ClutterActor *self,
7673                             gfloat       *minimum_width,
7674                             gfloat       *natural_width,
7675                             gfloat       *adjusted_x1,
7676                             gfloat       *adjusted_x2)
7677 {
7678   ClutterTextDirection text_dir;
7679   const ClutterLayoutInfo *info;
7680
7681   info = _clutter_actor_get_layout_info_or_defaults (self);
7682   text_dir = clutter_actor_get_text_direction (self);
7683
7684   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7685
7686   /* this will tweak natural_width to remove the margin, so that
7687    * adjust_for_alignment() will use the correct size
7688    */
7689   adjust_for_margin (info->margin.left, info->margin.right,
7690                      minimum_width, natural_width,
7691                      adjusted_x1, adjusted_x2);
7692
7693   adjust_for_alignment (effective_align (info->x_align, text_dir),
7694                         *natural_width,
7695                         adjusted_x1, adjusted_x2);
7696 }
7697
7698 /*< private >
7699  * clutter_actor_adjust_height:
7700  * @self: a #ClutterActor
7701  * @minimum_height: (inout): the actor's preferred minimum height, which
7702  *   will be adjusted depending on the margin
7703  * @natural_height: (inout): the actor's preferred natural height, which
7704  *   will be adjusted depending on the margin
7705  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7706  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7707  *
7708  * Adjusts the preferred and allocated position and size of an actor,
7709  * depending on the margin and alignment properties.
7710  */
7711 static void
7712 clutter_actor_adjust_height (ClutterActor *self,
7713                              gfloat       *minimum_height,
7714                              gfloat       *natural_height,
7715                              gfloat       *adjusted_y1,
7716                              gfloat       *adjusted_y2)
7717 {
7718   const ClutterLayoutInfo *info;
7719
7720   info = _clutter_actor_get_layout_info_or_defaults (self);
7721
7722   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7723
7724   /* this will tweak natural_height to remove the margin, so that
7725    * adjust_for_alignment() will use the correct size
7726    */
7727   adjust_for_margin (info->margin.top, info->margin.bottom,
7728                      minimum_height, natural_height,
7729                      adjusted_y1,
7730                      adjusted_y2);
7731
7732   /* we don't use effective_align() here, because text direction
7733    * only affects the horizontal axis
7734    */
7735   adjust_for_alignment (info->y_align,
7736                         *natural_height,
7737                         adjusted_y1,
7738                         adjusted_y2);
7739
7740 }
7741
7742 /* looks for a cached size request for this for_size. If not
7743  * found, returns the oldest entry so it can be overwritten */
7744 static gboolean
7745 _clutter_actor_get_cached_size_request (gfloat         for_size,
7746                                         SizeRequest   *cached_size_requests,
7747                                         SizeRequest  **result)
7748 {
7749   guint i;
7750
7751   *result = &cached_size_requests[0];
7752
7753   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7754     {
7755       SizeRequest *sr;
7756
7757       sr = &cached_size_requests[i];
7758
7759       if (sr->age > 0 &&
7760           sr->for_size == for_size)
7761         {
7762           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7763           *result = sr;
7764           return TRUE;
7765         }
7766       else if (sr->age < (*result)->age)
7767         {
7768           *result = sr;
7769         }
7770     }
7771
7772   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7773
7774   return FALSE;
7775 }
7776
7777 /**
7778  * clutter_actor_get_preferred_width:
7779  * @self: A #ClutterActor
7780  * @for_height: available height when computing the preferred width,
7781  *   or a negative value to indicate that no height is defined
7782  * @min_width_p: (out) (allow-none): return location for minimum width,
7783  *   or %NULL
7784  * @natural_width_p: (out) (allow-none): return location for the natural
7785  *   width, or %NULL
7786  *
7787  * Computes the requested minimum and natural widths for an actor,
7788  * optionally depending on the specified height, or if they are
7789  * already computed, returns the cached values.
7790  *
7791  * An actor may not get its request - depending on the layout
7792  * manager that's in effect.
7793  *
7794  * A request should not incorporate the actor's scale or anchor point;
7795  * those transformations do not affect layout, only rendering.
7796  *
7797  * Since: 0.8
7798  */
7799 void
7800 clutter_actor_get_preferred_width (ClutterActor *self,
7801                                    gfloat        for_height,
7802                                    gfloat       *min_width_p,
7803                                    gfloat       *natural_width_p)
7804 {
7805   float request_min_width, request_natural_width;
7806   SizeRequest *cached_size_request;
7807   const ClutterLayoutInfo *info;
7808   ClutterActorPrivate *priv;
7809   gboolean found_in_cache;
7810
7811   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7812
7813   priv = self->priv;
7814
7815   info = _clutter_actor_get_layout_info_or_defaults (self);
7816
7817   /* we shortcircuit the case of a fixed size set using set_width() */
7818   if (priv->min_width_set && priv->natural_width_set)
7819     {
7820       if (min_width_p != NULL)
7821         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7822
7823       if (natural_width_p != NULL)
7824         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7825
7826       return;
7827     }
7828
7829   /* the remaining cases are:
7830    *
7831    *   - either min_width or natural_width have been set
7832    *   - neither min_width or natural_width have been set
7833    *
7834    * in both cases, we go through the cache (and through the actor in case
7835    * of cache misses) and determine the authoritative value depending on
7836    * the *_set flags.
7837    */
7838
7839   if (!priv->needs_width_request)
7840     {
7841       found_in_cache =
7842         _clutter_actor_get_cached_size_request (for_height,
7843                                                 priv->width_requests,
7844                                                 &cached_size_request);
7845     }
7846   else
7847     {
7848       /* if the actor needs a width request we use the first slot */
7849       found_in_cache = FALSE;
7850       cached_size_request = &priv->width_requests[0];
7851     }
7852
7853   if (!found_in_cache)
7854     {
7855       gfloat minimum_width, natural_width;
7856       ClutterActorClass *klass;
7857
7858       minimum_width = natural_width = 0;
7859
7860       /* adjust for the margin */
7861       if (for_height >= 0)
7862         {
7863           for_height -= (info->margin.top + info->margin.bottom);
7864           if (for_height < 0)
7865             for_height = 0;
7866         }
7867
7868       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7869
7870       klass = CLUTTER_ACTOR_GET_CLASS (self);
7871       klass->get_preferred_width (self, for_height,
7872                                   &minimum_width,
7873                                   &natural_width);
7874
7875       /* adjust for the margin */
7876       minimum_width += (info->margin.left + info->margin.right);
7877       natural_width += (info->margin.left + info->margin.right);
7878
7879       /* Due to accumulated float errors, it's better not to warn
7880        * on this, but just fix it.
7881        */
7882       if (natural_width < minimum_width)
7883         natural_width = minimum_width;
7884
7885       cached_size_request->min_size = minimum_width;
7886       cached_size_request->natural_size = natural_width;
7887       cached_size_request->for_size = for_height;
7888       cached_size_request->age = priv->cached_width_age;
7889
7890       priv->cached_width_age += 1;
7891       priv->needs_width_request = FALSE;
7892     }
7893
7894   if (!priv->min_width_set)
7895     request_min_width = cached_size_request->min_size;
7896   else
7897     request_min_width = info->min_width;
7898
7899   if (!priv->natural_width_set)
7900     request_natural_width = cached_size_request->natural_size;
7901   else
7902     request_natural_width = info->natural_width;
7903
7904   if (min_width_p)
7905     *min_width_p = request_min_width;
7906
7907   if (natural_width_p)
7908     *natural_width_p = request_natural_width;
7909 }
7910
7911 /**
7912  * clutter_actor_get_preferred_height:
7913  * @self: A #ClutterActor
7914  * @for_width: available width to assume in computing desired height,
7915  *   or a negative value to indicate that no width is defined
7916  * @min_height_p: (out) (allow-none): return location for minimum height,
7917  *   or %NULL
7918  * @natural_height_p: (out) (allow-none): return location for natural
7919  *   height, or %NULL
7920  *
7921  * Computes the requested minimum and natural heights for an actor,
7922  * or if they are already computed, returns the cached values.
7923  *
7924  * An actor may not get its request - depending on the layout
7925  * manager that's in effect.
7926  *
7927  * A request should not incorporate the actor's scale or anchor point;
7928  * those transformations do not affect layout, only rendering.
7929  *
7930  * Since: 0.8
7931  */
7932 void
7933 clutter_actor_get_preferred_height (ClutterActor *self,
7934                                     gfloat        for_width,
7935                                     gfloat       *min_height_p,
7936                                     gfloat       *natural_height_p)
7937 {
7938   float request_min_height, request_natural_height;
7939   SizeRequest *cached_size_request;
7940   const ClutterLayoutInfo *info;
7941   ClutterActorPrivate *priv;
7942   gboolean found_in_cache;
7943
7944   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7945
7946   priv = self->priv;
7947
7948   info = _clutter_actor_get_layout_info_or_defaults (self);
7949
7950   /* we shortcircuit the case of a fixed size set using set_height() */
7951   if (priv->min_height_set && priv->natural_height_set)
7952     {
7953       if (min_height_p != NULL)
7954         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7955
7956       if (natural_height_p != NULL)
7957         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7958
7959       return;
7960     }
7961
7962   /* the remaining cases are:
7963    *
7964    *   - either min_height or natural_height have been set
7965    *   - neither min_height or natural_height have been set
7966    *
7967    * in both cases, we go through the cache (and through the actor in case
7968    * of cache misses) and determine the authoritative value depending on
7969    * the *_set flags.
7970    */
7971
7972   if (!priv->needs_height_request)
7973     {
7974       found_in_cache =
7975         _clutter_actor_get_cached_size_request (for_width,
7976                                                 priv->height_requests,
7977                                                 &cached_size_request);
7978     }
7979   else
7980     {
7981       found_in_cache = FALSE;
7982       cached_size_request = &priv->height_requests[0];
7983     }
7984
7985   if (!found_in_cache)
7986     {
7987       gfloat minimum_height, natural_height;
7988       ClutterActorClass *klass;
7989
7990       minimum_height = natural_height = 0;
7991
7992       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7993
7994       /* adjust for margin */
7995       if (for_width >= 0)
7996         {
7997           for_width -= (info->margin.left + info->margin.right);
7998           if (for_width < 0)
7999             for_width = 0;
8000         }
8001
8002       klass = CLUTTER_ACTOR_GET_CLASS (self);
8003       klass->get_preferred_height (self, for_width,
8004                                    &minimum_height,
8005                                    &natural_height);
8006
8007       /* adjust for margin */
8008       minimum_height += (info->margin.top + info->margin.bottom);
8009       natural_height += (info->margin.top + info->margin.bottom);
8010
8011       /* Due to accumulated float errors, it's better not to warn
8012        * on this, but just fix it.
8013        */
8014       if (natural_height < minimum_height)
8015         natural_height = minimum_height;
8016
8017       cached_size_request->min_size = minimum_height;
8018       cached_size_request->natural_size = natural_height;
8019       cached_size_request->for_size = for_width;
8020       cached_size_request->age = priv->cached_height_age;
8021
8022       priv->cached_height_age += 1;
8023       priv->needs_height_request = FALSE;
8024     }
8025
8026   if (!priv->min_height_set)
8027     request_min_height = cached_size_request->min_size;
8028   else
8029     request_min_height = info->min_height;
8030
8031   if (!priv->natural_height_set)
8032     request_natural_height = cached_size_request->natural_size;
8033   else
8034     request_natural_height = info->natural_height;
8035
8036   if (min_height_p)
8037     *min_height_p = request_min_height;
8038
8039   if (natural_height_p)
8040     *natural_height_p = request_natural_height;
8041 }
8042
8043 /**
8044  * clutter_actor_get_allocation_box:
8045  * @self: A #ClutterActor
8046  * @box: (out): the function fills this in with the actor's allocation
8047  *
8048  * Gets the layout box an actor has been assigned. The allocation can
8049  * only be assumed valid inside a paint() method; anywhere else, it
8050  * may be out-of-date.
8051  *
8052  * An allocation does not incorporate the actor's scale or anchor point;
8053  * those transformations do not affect layout, only rendering.
8054  *
8055  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8056  * of functions inside the implementation of the get_preferred_width()
8057  * or get_preferred_height() virtual functions.</note>
8058  *
8059  * Since: 0.8
8060  */
8061 void
8062 clutter_actor_get_allocation_box (ClutterActor    *self,
8063                                   ClutterActorBox *box)
8064 {
8065   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8066
8067   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8068    * which limits calling get_allocation to inside paint() basically; or
8069    * we can 2) force a layout, which could be expensive if someone calls
8070    * get_allocation somewhere silly; or we can 3) just return the latest
8071    * value, allowing it to be out-of-date, and assume people know what
8072    * they are doing.
8073    *
8074    * The least-surprises approach that keeps existing code working is
8075    * likely to be 2). People can end up doing some inefficient things,
8076    * though, and in general code that requires 2) is probably broken.
8077    */
8078
8079   /* this implements 2) */
8080   if (G_UNLIKELY (self->priv->needs_allocation))
8081     {
8082       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8083
8084       /* do not queue a relayout on an unparented actor */
8085       if (stage)
8086         _clutter_stage_maybe_relayout (stage);
8087     }
8088
8089   /* commenting out the code above and just keeping this assigment
8090    * implements 3)
8091    */
8092   *box = self->priv->allocation;
8093 }
8094
8095 /**
8096  * clutter_actor_get_allocation_geometry:
8097  * @self: A #ClutterActor
8098  * @geom: (out): allocation geometry in pixels
8099  *
8100  * Gets the layout box an actor has been assigned.  The allocation can
8101  * only be assumed valid inside a paint() method; anywhere else, it
8102  * may be out-of-date.
8103  *
8104  * An allocation does not incorporate the actor's scale or anchor point;
8105  * those transformations do not affect layout, only rendering.
8106  *
8107  * The returned rectangle is in pixels.
8108  *
8109  * Since: 0.8
8110  */
8111 void
8112 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8113                                        ClutterGeometry *geom)
8114 {
8115   ClutterActorBox box;
8116
8117   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8118   g_return_if_fail (geom != NULL);
8119
8120   clutter_actor_get_allocation_box (self, &box);
8121
8122   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8123   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8124   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8125   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8126 }
8127
8128 static void
8129 clutter_actor_update_constraints (ClutterActor    *self,
8130                                   ClutterActorBox *allocation)
8131 {
8132   ClutterActorPrivate *priv = self->priv;
8133   const GList *constraints, *l;
8134
8135   if (priv->constraints == NULL)
8136     return;
8137
8138   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8139   for (l = constraints; l != NULL; l = l->next)
8140     {
8141       ClutterConstraint *constraint = l->data;
8142       ClutterActorMeta *meta = l->data;
8143
8144       if (clutter_actor_meta_get_enabled (meta))
8145         {
8146           _clutter_constraint_update_allocation (constraint,
8147                                                  self,
8148                                                  allocation);
8149         }
8150     }
8151 }
8152
8153 /*< private >
8154  * clutter_actor_adjust_allocation:
8155  * @self: a #ClutterActor
8156  * @allocation: (inout): the allocation to adjust
8157  *
8158  * Adjusts the passed allocation box taking into account the actor's
8159  * layout information, like alignment, expansion, and margin.
8160  */
8161 static void
8162 clutter_actor_adjust_allocation (ClutterActor    *self,
8163                                  ClutterActorBox *allocation)
8164 {
8165   ClutterActorBox adj_allocation;
8166   float alloc_width, alloc_height;
8167   float min_width, min_height;
8168   float nat_width, nat_height;
8169   ClutterRequestMode req_mode;
8170
8171   adj_allocation = *allocation;
8172
8173   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8174
8175   /* we want to hit the cache, so we use the public API */
8176   req_mode = clutter_actor_get_request_mode (self);
8177
8178   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8179     {
8180       clutter_actor_get_preferred_width (self, -1,
8181                                          &min_width,
8182                                          &nat_width);
8183       clutter_actor_get_preferred_height (self, alloc_width,
8184                                           &min_height,
8185                                           &nat_height);
8186     }
8187   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8188     {
8189       clutter_actor_get_preferred_height (self, -1,
8190                                           &min_height,
8191                                           &nat_height);
8192       clutter_actor_get_preferred_height (self, alloc_height,
8193                                           &min_width,
8194                                           &nat_width);
8195     }
8196
8197 #ifdef CLUTTER_ENABLE_DEBUG
8198   /* warn about underallocations */
8199   if (_clutter_diagnostic_enabled () &&
8200       (floorf (min_width - alloc_width) > 0 ||
8201        floorf (min_height - alloc_height) > 0))
8202     {
8203       ClutterActor *parent = clutter_actor_get_parent (self);
8204
8205       /* the only actors that are allowed to be underallocated are the Stage,
8206        * as it doesn't have an implicit size, and Actors that specifically
8207        * told us that they want to opt-out from layout control mechanisms
8208        * through the NO_LAYOUT escape hatch.
8209        */
8210       if (parent != NULL &&
8211           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8212         {
8213           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8214                      "of %.2f x %.2f from its parent actor '%s', but its "
8215                      "requested minimum size is of %.2f x %.2f",
8216                      _clutter_actor_get_debug_name (self),
8217                      alloc_width, alloc_height,
8218                      _clutter_actor_get_debug_name (parent),
8219                      min_width, min_height);
8220         }
8221     }
8222 #endif
8223
8224   clutter_actor_adjust_width (self,
8225                               &min_width,
8226                               &nat_width,
8227                               &adj_allocation.x1,
8228                               &adj_allocation.x2);
8229
8230   clutter_actor_adjust_height (self,
8231                                &min_height,
8232                                &nat_height,
8233                                &adj_allocation.y1,
8234                                &adj_allocation.y2);
8235
8236   /* we maintain the invariant that an allocation cannot be adjusted
8237    * to be outside the parent-given box
8238    */
8239   if (adj_allocation.x1 < allocation->x1 ||
8240       adj_allocation.y1 < allocation->y1 ||
8241       adj_allocation.x2 > allocation->x2 ||
8242       adj_allocation.y2 > allocation->y2)
8243     {
8244       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8245                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8246                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8247                  _clutter_actor_get_debug_name (self),
8248                  adj_allocation.x1, adj_allocation.y1,
8249                  adj_allocation.x2 - adj_allocation.x1,
8250                  adj_allocation.y2 - adj_allocation.y1,
8251                  allocation->x1, allocation->y1,
8252                  allocation->x2 - allocation->x1,
8253                  allocation->y2 - allocation->y1);
8254       return;
8255     }
8256
8257   *allocation = adj_allocation;
8258 }
8259
8260 /**
8261  * clutter_actor_allocate:
8262  * @self: A #ClutterActor
8263  * @box: new allocation of the actor, in parent-relative coordinates
8264  * @flags: flags that control the allocation
8265  *
8266  * Called by the parent of an actor to assign the actor its size.
8267  * Should never be called by applications (except when implementing
8268  * a container or layout manager).
8269  *
8270  * Actors can know from their allocation box whether they have moved
8271  * with respect to their parent actor. The @flags parameter describes
8272  * additional information about the allocation, for instance whether
8273  * the parent has moved with respect to the stage, for example because
8274  * a grandparent's origin has moved.
8275  *
8276  * Since: 0.8
8277  */
8278 void
8279 clutter_actor_allocate (ClutterActor           *self,
8280                         const ClutterActorBox  *box,
8281                         ClutterAllocationFlags  flags)
8282 {
8283   ClutterActorPrivate *priv;
8284   ClutterActorClass *klass;
8285   ClutterActorBox old_allocation, real_allocation;
8286   gboolean origin_changed, child_moved, size_changed;
8287   gboolean stage_allocation_changed;
8288
8289   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8290   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8291     {
8292       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8293                  "which isn't a descendent of the stage!\n",
8294                  self, _clutter_actor_get_debug_name (self));
8295       return;
8296     }
8297
8298   priv = self->priv;
8299
8300   old_allocation = priv->allocation;
8301   real_allocation = *box;
8302
8303   /* constraints are allowed to modify the allocation only here; we do
8304    * this prior to all the other checks so that we can bail out if the
8305    * allocation did not change
8306    */
8307   clutter_actor_update_constraints (self, &real_allocation);
8308
8309   /* adjust the allocation depending on the align/margin properties */
8310   clutter_actor_adjust_allocation (self, &real_allocation);
8311
8312   if (real_allocation.x2 < real_allocation.x1 ||
8313       real_allocation.y2 < real_allocation.y1)
8314     {
8315       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8316                  _clutter_actor_get_debug_name (self),
8317                  real_allocation.x2 - real_allocation.x1,
8318                  real_allocation.y2 - real_allocation.y1);
8319     }
8320
8321   /* we allow 0-sized actors, but not negative-sized ones */
8322   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8323   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8324
8325   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8326
8327   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8328                  real_allocation.y1 != old_allocation.y1);
8329
8330   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8331                   real_allocation.y2 != old_allocation.y2);
8332
8333   if (origin_changed || child_moved || size_changed)
8334     stage_allocation_changed = TRUE;
8335   else
8336     stage_allocation_changed = FALSE;
8337
8338   /* If we get an allocation "out of the blue"
8339    * (we did not queue relayout), then we want to
8340    * ignore it. But if we have needs_allocation set,
8341    * we want to guarantee that allocate() virtual
8342    * method is always called, i.e. that queue_relayout()
8343    * always results in an allocate() invocation on
8344    * an actor.
8345    *
8346    * The optimization here is to avoid re-allocating
8347    * actors that did not queue relayout and were
8348    * not moved.
8349    */
8350   if (!priv->needs_allocation && !stage_allocation_changed)
8351     {
8352       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8353       return;
8354     }
8355
8356   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8357    * clutter_actor_allocate(), it indicates whether the parent has its
8358    * absolute origin moved; when passed in to ClutterActor::allocate()
8359    * virtual method though, it indicates whether the child has its
8360    * absolute origin moved.  So we set it when child_moved is TRUE
8361    */
8362   if (child_moved)
8363     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8364
8365   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8366
8367   klass = CLUTTER_ACTOR_GET_CLASS (self);
8368   klass->allocate (self, &real_allocation, flags);
8369
8370   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8371
8372   if (stage_allocation_changed)
8373     clutter_actor_queue_redraw (self);
8374 }
8375
8376 /**
8377  * clutter_actor_set_allocation:
8378  * @self: a #ClutterActor
8379  * @box: a #ClutterActorBox
8380  * @flags: allocation flags
8381  *
8382  * Stores the allocation of @self as defined by @box.
8383  *
8384  * This function can only be called from within the implementation of
8385  * the #ClutterActorClass.allocate() virtual function.
8386  *
8387  * The allocation should have been adjusted to take into account constraints,
8388  * alignment, and margin properties. If you are implementing a #ClutterActor
8389  * subclass that provides its own layout management policy for its children
8390  * instead of using a #ClutterLayoutManager delegate, you should not call
8391  * this function on the children of @self; instead, you should call
8392  * clutter_actor_allocate(), which will adjust the allocation box for
8393  * you.
8394  *
8395  * This function should only be used by subclasses of #ClutterActor
8396  * that wish to store their allocation but cannot chain up to the
8397  * parent's implementation; the default implementation of the
8398  * #ClutterActorClass.allocate() virtual function will call this
8399  * function.
8400  *
8401  * It is important to note that, while chaining up was the recommended
8402  * behaviour for #ClutterActor subclasses prior to the introduction of
8403  * this function, it is recommended to call clutter_actor_set_allocation()
8404  * instead.
8405  *
8406  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8407  * to handle the allocation of its children, this function will call
8408  * the clutter_layout_manager_allocate() function only if the
8409  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8410  * expected that the subclass will call clutter_layout_manager_allocate()
8411  * by itself. For instance, the following code:
8412  *
8413  * |[
8414  * static void
8415  * my_actor_allocate (ClutterActor *actor,
8416  *                    const ClutterActorBox *allocation,
8417  *                    ClutterAllocationFlags flags)
8418  * {
8419  *   ClutterActorBox new_alloc;
8420  *   ClutterAllocationFlags new_flags;
8421  *
8422  *   adjust_allocation (allocation, &amp;new_alloc);
8423  *
8424  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8425  *
8426  *   /&ast; this will use the layout manager set on the actor &ast;/
8427  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8428  * }
8429  * ]|
8430  *
8431  * is equivalent to this:
8432  *
8433  * |[
8434  * static void
8435  * my_actor_allocate (ClutterActor *actor,
8436  *                    const ClutterActorBox *allocation,
8437  *                    ClutterAllocationFlags flags)
8438  * {
8439  *   ClutterLayoutManager *layout;
8440  *   ClutterActorBox new_alloc;
8441  *
8442  *   adjust_allocation (allocation, &amp;new_alloc);
8443  *
8444  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8445  *
8446  *   layout = clutter_actor_get_layout_manager (actor);
8447  *   clutter_layout_manager_allocate (layout,
8448  *                                    CLUTTER_CONTAINER (actor),
8449  *                                    &amp;new_alloc,
8450  *                                    flags);
8451  * }
8452  * ]|
8453  *
8454  * Since: 1.10
8455  */
8456 void
8457 clutter_actor_set_allocation (ClutterActor           *self,
8458                               const ClutterActorBox  *box,
8459                               ClutterAllocationFlags  flags)
8460 {
8461   ClutterActorPrivate *priv;
8462   gboolean changed;
8463
8464   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8465   g_return_if_fail (box != NULL);
8466
8467   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8468     {
8469       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8470                   "can only be called from within the implementation of "
8471                   "the ClutterActor::allocate() virtual function.");
8472       return;
8473     }
8474
8475   priv = self->priv;
8476
8477   g_object_freeze_notify (G_OBJECT (self));
8478
8479   changed = clutter_actor_set_allocation_internal (self, box, flags);
8480
8481   /* we allocate our children before we notify changes in our geometry,
8482    * so that people connecting to properties will be able to get valid
8483    * data out of the sub-tree of the scene graph that has this actor at
8484    * the root.
8485    */
8486   clutter_actor_maybe_layout_children (self, box, flags);
8487
8488   if (changed)
8489     {
8490       ClutterActorBox signal_box = priv->allocation;
8491       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8492
8493       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8494                      &signal_box,
8495                      signal_flags);
8496     }
8497
8498   g_object_thaw_notify (G_OBJECT (self));
8499 }
8500
8501 /**
8502  * clutter_actor_set_geometry:
8503  * @self: A #ClutterActor
8504  * @geometry: A #ClutterGeometry
8505  *
8506  * Sets the actor's fixed position and forces its minimum and natural
8507  * size, in pixels. This means the untransformed actor will have the
8508  * given geometry. This is the same as calling clutter_actor_set_position()
8509  * and clutter_actor_set_size().
8510  *
8511  * Deprecated: 1.10: Use clutter_actor_set_position() and
8512  *   clutter_actor_set_size() instead.
8513  */
8514 void
8515 clutter_actor_set_geometry (ClutterActor          *self,
8516                             const ClutterGeometry *geometry)
8517 {
8518   g_object_freeze_notify (G_OBJECT (self));
8519
8520   clutter_actor_set_position (self, geometry->x, geometry->y);
8521   clutter_actor_set_size (self, geometry->width, geometry->height);
8522
8523   g_object_thaw_notify (G_OBJECT (self));
8524 }
8525
8526 /**
8527  * clutter_actor_get_geometry:
8528  * @self: A #ClutterActor
8529  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8530  *
8531  * Gets the size and position of an actor relative to its parent
8532  * actor. This is the same as calling clutter_actor_get_position() and
8533  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8534  * requested size and position if the actor's allocation is invalid.
8535  *
8536  * Deprecated: 1.10: Use clutter_actor_get_position() and
8537  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8538  *   instead.
8539  */
8540 void
8541 clutter_actor_get_geometry (ClutterActor    *self,
8542                             ClutterGeometry *geometry)
8543 {
8544   gfloat x, y, width, height;
8545
8546   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8547   g_return_if_fail (geometry != NULL);
8548
8549   clutter_actor_get_position (self, &x, &y);
8550   clutter_actor_get_size (self, &width, &height);
8551
8552   geometry->x = (int) x;
8553   geometry->y = (int) y;
8554   geometry->width = (int) width;
8555   geometry->height = (int) height;
8556 }
8557
8558 /**
8559  * clutter_actor_set_position:
8560  * @self: A #ClutterActor
8561  * @x: New left position of actor in pixels.
8562  * @y: New top position of actor in pixels.
8563  *
8564  * Sets the actor's fixed position in pixels relative to any parent
8565  * actor.
8566  *
8567  * If a layout manager is in use, this position will override the
8568  * layout manager and force a fixed position.
8569  */
8570 void
8571 clutter_actor_set_position (ClutterActor *self,
8572                             gfloat        x,
8573                             gfloat        y)
8574 {
8575   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8576
8577   g_object_freeze_notify (G_OBJECT (self));
8578
8579   clutter_actor_set_x (self, x);
8580   clutter_actor_set_y (self, y);
8581
8582   g_object_thaw_notify (G_OBJECT (self));
8583 }
8584
8585 /**
8586  * clutter_actor_get_fixed_position_set:
8587  * @self: A #ClutterActor
8588  *
8589  * Checks whether an actor has a fixed position set (and will thus be
8590  * unaffected by any layout manager).
8591  *
8592  * Return value: %TRUE if the fixed position is set on the actor
8593  *
8594  * Since: 0.8
8595  */
8596 gboolean
8597 clutter_actor_get_fixed_position_set (ClutterActor *self)
8598 {
8599   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8600
8601   return self->priv->position_set;
8602 }
8603
8604 /**
8605  * clutter_actor_set_fixed_position_set:
8606  * @self: A #ClutterActor
8607  * @is_set: whether to use fixed position
8608  *
8609  * Sets whether an actor has a fixed position set (and will thus be
8610  * unaffected by any layout manager).
8611  *
8612  * Since: 0.8
8613  */
8614 void
8615 clutter_actor_set_fixed_position_set (ClutterActor *self,
8616                                       gboolean      is_set)
8617 {
8618   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8619
8620   if (self->priv->position_set == (is_set != FALSE))
8621     return;
8622
8623   self->priv->position_set = is_set != FALSE;
8624   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8625
8626   clutter_actor_queue_relayout (self);
8627 }
8628
8629 /**
8630  * clutter_actor_move_by:
8631  * @self: A #ClutterActor
8632  * @dx: Distance to move Actor on X axis.
8633  * @dy: Distance to move Actor on Y axis.
8634  *
8635  * Moves an actor by the specified distance relative to its current
8636  * position in pixels.
8637  *
8638  * This function modifies the fixed position of an actor and thus removes
8639  * it from any layout management. Another way to move an actor is with an
8640  * anchor point, see clutter_actor_set_anchor_point().
8641  *
8642  * Since: 0.2
8643  */
8644 void
8645 clutter_actor_move_by (ClutterActor *self,
8646                        gfloat        dx,
8647                        gfloat        dy)
8648 {
8649   const ClutterLayoutInfo *info;
8650   gfloat x, y;
8651
8652   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8653
8654   info = _clutter_actor_get_layout_info_or_defaults (self);
8655   x = info->fixed_x;
8656   y = info->fixed_y;
8657
8658   clutter_actor_set_position (self, x + dx, y + dy);
8659 }
8660
8661 static void
8662 clutter_actor_set_min_width (ClutterActor *self,
8663                              gfloat        min_width)
8664 {
8665   ClutterActorPrivate *priv = self->priv;
8666   ClutterActorBox old = { 0, };
8667   ClutterLayoutInfo *info;
8668
8669   /* if we are setting the size on a top-level actor and the
8670    * backend only supports static top-levels (e.g. framebuffers)
8671    * then we ignore the passed value and we override it with
8672    * the stage implementation's preferred size.
8673    */
8674   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8675       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8676     return;
8677
8678   info = _clutter_actor_get_layout_info (self);
8679
8680   if (priv->min_width_set && min_width == info->min_width)
8681     return;
8682
8683   g_object_freeze_notify (G_OBJECT (self));
8684
8685   clutter_actor_store_old_geometry (self, &old);
8686
8687   info->min_width = min_width;
8688   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8689   clutter_actor_set_min_width_set (self, TRUE);
8690
8691   clutter_actor_notify_if_geometry_changed (self, &old);
8692
8693   g_object_thaw_notify (G_OBJECT (self));
8694
8695   clutter_actor_queue_relayout (self);
8696 }
8697
8698 static void
8699 clutter_actor_set_min_height (ClutterActor *self,
8700                               gfloat        min_height)
8701
8702 {
8703   ClutterActorPrivate *priv = self->priv;
8704   ClutterActorBox old = { 0, };
8705   ClutterLayoutInfo *info;
8706
8707   /* if we are setting the size on a top-level actor and the
8708    * backend only supports static top-levels (e.g. framebuffers)
8709    * then we ignore the passed value and we override it with
8710    * the stage implementation's preferred size.
8711    */
8712   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8713       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8714     return;
8715
8716   info = _clutter_actor_get_layout_info (self);
8717
8718   if (priv->min_height_set && min_height == info->min_height)
8719     return;
8720
8721   g_object_freeze_notify (G_OBJECT (self));
8722
8723   clutter_actor_store_old_geometry (self, &old);
8724
8725   info->min_height = min_height;
8726   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8727   clutter_actor_set_min_height_set (self, TRUE);
8728
8729   clutter_actor_notify_if_geometry_changed (self, &old);
8730
8731   g_object_thaw_notify (G_OBJECT (self));
8732
8733   clutter_actor_queue_relayout (self);
8734 }
8735
8736 static void
8737 clutter_actor_set_natural_width (ClutterActor *self,
8738                                  gfloat        natural_width)
8739 {
8740   ClutterActorPrivate *priv = self->priv;
8741   ClutterActorBox old = { 0, };
8742   ClutterLayoutInfo *info;
8743
8744   /* if we are setting the size on a top-level actor and the
8745    * backend only supports static top-levels (e.g. framebuffers)
8746    * then we ignore the passed value and we override it with
8747    * the stage implementation's preferred size.
8748    */
8749   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8750       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8751     return;
8752
8753   info = _clutter_actor_get_layout_info (self);
8754
8755   if (priv->natural_width_set && natural_width == info->natural_width)
8756     return;
8757
8758   g_object_freeze_notify (G_OBJECT (self));
8759
8760   clutter_actor_store_old_geometry (self, &old);
8761
8762   info->natural_width = natural_width;
8763   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8764   clutter_actor_set_natural_width_set (self, TRUE);
8765
8766   clutter_actor_notify_if_geometry_changed (self, &old);
8767
8768   g_object_thaw_notify (G_OBJECT (self));
8769
8770   clutter_actor_queue_relayout (self);
8771 }
8772
8773 static void
8774 clutter_actor_set_natural_height (ClutterActor *self,
8775                                   gfloat        natural_height)
8776 {
8777   ClutterActorPrivate *priv = self->priv;
8778   ClutterActorBox old = { 0, };
8779   ClutterLayoutInfo *info;
8780
8781   /* if we are setting the size on a top-level actor and the
8782    * backend only supports static top-levels (e.g. framebuffers)
8783    * then we ignore the passed value and we override it with
8784    * the stage implementation's preferred size.
8785    */
8786   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8787       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8788     return;
8789
8790   info = _clutter_actor_get_layout_info (self);
8791
8792   if (priv->natural_height_set && natural_height == info->natural_height)
8793     return;
8794
8795   g_object_freeze_notify (G_OBJECT (self));
8796
8797   clutter_actor_store_old_geometry (self, &old);
8798
8799   info->natural_height = natural_height;
8800   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8801   clutter_actor_set_natural_height_set (self, TRUE);
8802
8803   clutter_actor_notify_if_geometry_changed (self, &old);
8804
8805   g_object_thaw_notify (G_OBJECT (self));
8806
8807   clutter_actor_queue_relayout (self);
8808 }
8809
8810 static void
8811 clutter_actor_set_min_width_set (ClutterActor *self,
8812                                  gboolean      use_min_width)
8813 {
8814   ClutterActorPrivate *priv = self->priv;
8815   ClutterActorBox old = { 0, };
8816
8817   if (priv->min_width_set == (use_min_width != FALSE))
8818     return;
8819
8820   clutter_actor_store_old_geometry (self, &old);
8821
8822   priv->min_width_set = use_min_width != FALSE;
8823   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8824
8825   clutter_actor_notify_if_geometry_changed (self, &old);
8826
8827   clutter_actor_queue_relayout (self);
8828 }
8829
8830 static void
8831 clutter_actor_set_min_height_set (ClutterActor *self,
8832                                   gboolean      use_min_height)
8833 {
8834   ClutterActorPrivate *priv = self->priv;
8835   ClutterActorBox old = { 0, };
8836
8837   if (priv->min_height_set == (use_min_height != FALSE))
8838     return;
8839
8840   clutter_actor_store_old_geometry (self, &old);
8841
8842   priv->min_height_set = use_min_height != FALSE;
8843   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8844
8845   clutter_actor_notify_if_geometry_changed (self, &old);
8846
8847   clutter_actor_queue_relayout (self);
8848 }
8849
8850 static void
8851 clutter_actor_set_natural_width_set (ClutterActor *self,
8852                                      gboolean      use_natural_width)
8853 {
8854   ClutterActorPrivate *priv = self->priv;
8855   ClutterActorBox old = { 0, };
8856
8857   if (priv->natural_width_set == (use_natural_width != FALSE))
8858     return;
8859
8860   clutter_actor_store_old_geometry (self, &old);
8861
8862   priv->natural_width_set = use_natural_width != FALSE;
8863   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8864
8865   clutter_actor_notify_if_geometry_changed (self, &old);
8866
8867   clutter_actor_queue_relayout (self);
8868 }
8869
8870 static void
8871 clutter_actor_set_natural_height_set (ClutterActor *self,
8872                                       gboolean      use_natural_height)
8873 {
8874   ClutterActorPrivate *priv = self->priv;
8875   ClutterActorBox old = { 0, };
8876
8877   if (priv->natural_height_set == (use_natural_height != FALSE))
8878     return;
8879
8880   clutter_actor_store_old_geometry (self, &old);
8881
8882   priv->natural_height_set = use_natural_height != FALSE;
8883   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8884
8885   clutter_actor_notify_if_geometry_changed (self, &old);
8886
8887   clutter_actor_queue_relayout (self);
8888 }
8889
8890 /**
8891  * clutter_actor_set_request_mode:
8892  * @self: a #ClutterActor
8893  * @mode: the request mode
8894  *
8895  * Sets the geometry request mode of @self.
8896  *
8897  * The @mode determines the order for invoking
8898  * clutter_actor_get_preferred_width() and
8899  * clutter_actor_get_preferred_height()
8900  *
8901  * Since: 1.2
8902  */
8903 void
8904 clutter_actor_set_request_mode (ClutterActor       *self,
8905                                 ClutterRequestMode  mode)
8906 {
8907   ClutterActorPrivate *priv;
8908
8909   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8910
8911   priv = self->priv;
8912
8913   if (priv->request_mode == mode)
8914     return;
8915
8916   priv->request_mode = mode;
8917
8918   priv->needs_width_request = TRUE;
8919   priv->needs_height_request = TRUE;
8920
8921   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8922
8923   clutter_actor_queue_relayout (self);
8924 }
8925
8926 /**
8927  * clutter_actor_get_request_mode:
8928  * @self: a #ClutterActor
8929  *
8930  * Retrieves the geometry request mode of @self
8931  *
8932  * Return value: the request mode for the actor
8933  *
8934  * Since: 1.2
8935  */
8936 ClutterRequestMode
8937 clutter_actor_get_request_mode (ClutterActor *self)
8938 {
8939   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8940                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8941
8942   return self->priv->request_mode;
8943 }
8944
8945 /* variant of set_width() without checks and without notification
8946  * freeze+thaw, for internal usage only
8947  */
8948 static inline void
8949 clutter_actor_set_width_internal (ClutterActor *self,
8950                                   gfloat        width)
8951 {
8952   if (width >= 0)
8953     {
8954       /* the Stage will use the :min-width to control the minimum
8955        * width to be resized to, so we should not be setting it
8956        * along with the :natural-width
8957        */
8958       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8959         clutter_actor_set_min_width (self, width);
8960
8961       clutter_actor_set_natural_width (self, width);
8962     }
8963   else
8964     {
8965       /* we only unset the :natural-width for the Stage */
8966       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8967         clutter_actor_set_min_width_set (self, FALSE);
8968
8969       clutter_actor_set_natural_width_set (self, FALSE);
8970     }
8971 }
8972
8973 /* variant of set_height() without checks and without notification
8974  * freeze+thaw, for internal usage only
8975  */
8976 static inline void
8977 clutter_actor_set_height_internal (ClutterActor *self,
8978                                    gfloat        height)
8979 {
8980   if (height >= 0)
8981     {
8982       /* see the comment above in set_width_internal() */
8983       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8984         clutter_actor_set_min_height (self, height);
8985
8986       clutter_actor_set_natural_height (self, height);
8987     }
8988   else
8989     {
8990       /* see the comment above in set_width_internal() */
8991       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8992         clutter_actor_set_min_height_set (self, FALSE);
8993
8994       clutter_actor_set_natural_height_set (self, FALSE);
8995     }
8996 }
8997
8998 /**
8999  * clutter_actor_set_size:
9000  * @self: A #ClutterActor
9001  * @width: New width of actor in pixels, or -1
9002  * @height: New height of actor in pixels, or -1
9003  *
9004  * Sets the actor's size request in pixels. This overrides any
9005  * "normal" size request the actor would have. For example
9006  * a text actor might normally request the size of the text;
9007  * this function would force a specific size instead.
9008  *
9009  * If @width and/or @height are -1 the actor will use its
9010  * "normal" size request instead of overriding it, i.e.
9011  * you can "unset" the size with -1.
9012  *
9013  * This function sets or unsets both the minimum and natural size.
9014  */
9015 void
9016 clutter_actor_set_size (ClutterActor *self,
9017                         gfloat        width,
9018                         gfloat        height)
9019 {
9020   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9021
9022   g_object_freeze_notify (G_OBJECT (self));
9023
9024   clutter_actor_set_width (self, width);
9025   clutter_actor_set_height (self, height);
9026
9027   g_object_thaw_notify (G_OBJECT (self));
9028 }
9029
9030 /**
9031  * clutter_actor_get_size:
9032  * @self: A #ClutterActor
9033  * @width: (out) (allow-none): return location for the width, or %NULL.
9034  * @height: (out) (allow-none): return location for the height, or %NULL.
9035  *
9036  * This function tries to "do what you mean" and return
9037  * the size an actor will have. If the actor has a valid
9038  * allocation, the allocation will be returned; otherwise,
9039  * the actors natural size request will be returned.
9040  *
9041  * If you care whether you get the request vs. the allocation, you
9042  * should probably call a different function like
9043  * clutter_actor_get_allocation_box() or
9044  * clutter_actor_get_preferred_width().
9045  *
9046  * Since: 0.2
9047  */
9048 void
9049 clutter_actor_get_size (ClutterActor *self,
9050                         gfloat       *width,
9051                         gfloat       *height)
9052 {
9053   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9054
9055   if (width)
9056     *width = clutter_actor_get_width (self);
9057
9058   if (height)
9059     *height = clutter_actor_get_height (self);
9060 }
9061
9062 /**
9063  * clutter_actor_get_position:
9064  * @self: a #ClutterActor
9065  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9066  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9067  *
9068  * This function tries to "do what you mean" and tell you where the
9069  * actor is, prior to any transformations. Retrieves the fixed
9070  * position of an actor in pixels, if one has been set; otherwise, if
9071  * the allocation is valid, returns the actor's allocated position;
9072  * otherwise, returns 0,0.
9073  *
9074  * The returned position is in pixels.
9075  *
9076  * Since: 0.6
9077  */
9078 void
9079 clutter_actor_get_position (ClutterActor *self,
9080                             gfloat       *x,
9081                             gfloat       *y)
9082 {
9083   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9084
9085   if (x)
9086     *x = clutter_actor_get_x (self);
9087
9088   if (y)
9089     *y = clutter_actor_get_y (self);
9090 }
9091
9092 /**
9093  * clutter_actor_get_transformed_position:
9094  * @self: A #ClutterActor
9095  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9096  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9097  *
9098  * Gets the absolute position of an actor, in pixels relative to the stage.
9099  *
9100  * Since: 0.8
9101  */
9102 void
9103 clutter_actor_get_transformed_position (ClutterActor *self,
9104                                         gfloat       *x,
9105                                         gfloat       *y)
9106 {
9107   ClutterVertex v1;
9108   ClutterVertex v2;
9109
9110   v1.x = v1.y = v1.z = 0;
9111   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9112
9113   if (x)
9114     *x = v2.x;
9115
9116   if (y)
9117     *y = v2.y;
9118 }
9119
9120 /**
9121  * clutter_actor_get_transformed_size:
9122  * @self: A #ClutterActor
9123  * @width: (out) (allow-none): return location for the width, or %NULL
9124  * @height: (out) (allow-none): return location for the height, or %NULL
9125  *
9126  * Gets the absolute size of an actor in pixels, taking into account the
9127  * scaling factors.
9128  *
9129  * If the actor has a valid allocation, the allocated size will be used.
9130  * If the actor has not a valid allocation then the preferred size will
9131  * be transformed and returned.
9132  *
9133  * If you want the transformed allocation, see
9134  * clutter_actor_get_abs_allocation_vertices() instead.
9135  *
9136  * <note>When the actor (or one of its ancestors) is rotated around the
9137  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9138  * as a generic quadrangle; in that case this function returns the size
9139  * of the smallest rectangle that encapsulates the entire quad. Please
9140  * note that in this case no assumptions can be made about the relative
9141  * position of this envelope to the absolute position of the actor, as
9142  * returned by clutter_actor_get_transformed_position(); if you need this
9143  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9144  * to get the coords of the actual quadrangle.</note>
9145  *
9146  * Since: 0.8
9147  */
9148 void
9149 clutter_actor_get_transformed_size (ClutterActor *self,
9150                                     gfloat       *width,
9151                                     gfloat       *height)
9152 {
9153   ClutterActorPrivate *priv;
9154   ClutterVertex v[4];
9155   gfloat x_min, x_max, y_min, y_max;
9156   gint i;
9157
9158   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9159
9160   priv = self->priv;
9161
9162   /* if the actor hasn't been allocated yet, get the preferred
9163    * size and transform that
9164    */
9165   if (priv->needs_allocation)
9166     {
9167       gfloat natural_width, natural_height;
9168       ClutterActorBox box;
9169
9170       /* Make a fake allocation to transform.
9171        *
9172        * NB: _clutter_actor_transform_and_project_box expects a box in
9173        * the actor's coordinate space... */
9174
9175       box.x1 = 0;
9176       box.y1 = 0;
9177
9178       natural_width = natural_height = 0;
9179       clutter_actor_get_preferred_size (self, NULL, NULL,
9180                                         &natural_width,
9181                                         &natural_height);
9182
9183       box.x2 = natural_width;
9184       box.y2 = natural_height;
9185
9186       _clutter_actor_transform_and_project_box (self, &box, v);
9187     }
9188   else
9189     clutter_actor_get_abs_allocation_vertices (self, v);
9190
9191   x_min = x_max = v[0].x;
9192   y_min = y_max = v[0].y;
9193
9194   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9195     {
9196       if (v[i].x < x_min)
9197         x_min = v[i].x;
9198
9199       if (v[i].x > x_max)
9200         x_max = v[i].x;
9201
9202       if (v[i].y < y_min)
9203         y_min = v[i].y;
9204
9205       if (v[i].y > y_max)
9206         y_max = v[i].y;
9207     }
9208
9209   if (width)
9210     *width  = x_max - x_min;
9211
9212   if (height)
9213     *height = y_max - y_min;
9214 }
9215
9216 /**
9217  * clutter_actor_get_width:
9218  * @self: A #ClutterActor
9219  *
9220  * Retrieves the width of a #ClutterActor.
9221  *
9222  * If the actor has a valid allocation, this function will return the
9223  * width of the allocated area given to the actor.
9224  *
9225  * If the actor does not have a valid allocation, this function will
9226  * return the actor's natural width, that is the preferred width of
9227  * the actor.
9228  *
9229  * If you care whether you get the preferred width or the width that
9230  * has been assigned to the actor, you should probably call a different
9231  * function like clutter_actor_get_allocation_box() to retrieve the
9232  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9233  * preferred width.
9234  *
9235  * If an actor has a fixed width, for instance a width that has been
9236  * assigned using clutter_actor_set_width(), the width returned will
9237  * be the same value.
9238  *
9239  * Return value: the width of the actor, in pixels
9240  */
9241 gfloat
9242 clutter_actor_get_width (ClutterActor *self)
9243 {
9244   ClutterActorPrivate *priv;
9245
9246   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9247
9248   priv = self->priv;
9249
9250   if (priv->needs_allocation)
9251     {
9252       gfloat natural_width = 0;
9253
9254       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9255         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9256       else
9257         {
9258           gfloat natural_height = 0;
9259
9260           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9261           clutter_actor_get_preferred_width (self, natural_height,
9262                                              NULL,
9263                                              &natural_width);
9264         }
9265
9266       return natural_width;
9267     }
9268   else
9269     return priv->allocation.x2 - priv->allocation.x1;
9270 }
9271
9272 /**
9273  * clutter_actor_get_height:
9274  * @self: A #ClutterActor
9275  *
9276  * Retrieves the height of a #ClutterActor.
9277  *
9278  * If the actor has a valid allocation, this function will return the
9279  * height of the allocated area given to the actor.
9280  *
9281  * If the actor does not have a valid allocation, this function will
9282  * return the actor's natural height, that is the preferred height of
9283  * the actor.
9284  *
9285  * If you care whether you get the preferred height or the height that
9286  * has been assigned to the actor, you should probably call a different
9287  * function like clutter_actor_get_allocation_box() to retrieve the
9288  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9289  * preferred height.
9290  *
9291  * If an actor has a fixed height, for instance a height that has been
9292  * assigned using clutter_actor_set_height(), the height returned will
9293  * be the same value.
9294  *
9295  * Return value: the height of the actor, in pixels
9296  */
9297 gfloat
9298 clutter_actor_get_height (ClutterActor *self)
9299 {
9300   ClutterActorPrivate *priv;
9301
9302   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9303
9304   priv = self->priv;
9305
9306   if (priv->needs_allocation)
9307     {
9308       gfloat natural_height = 0;
9309
9310       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9311         {
9312           gfloat natural_width = 0;
9313
9314           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9315           clutter_actor_get_preferred_height (self, natural_width,
9316                                               NULL, &natural_height);
9317         }
9318       else
9319         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9320
9321       return natural_height;
9322     }
9323   else
9324     return priv->allocation.y2 - priv->allocation.y1;
9325 }
9326
9327 /**
9328  * clutter_actor_set_width:
9329  * @self: A #ClutterActor
9330  * @width: Requested new width for the actor, in pixels, or -1
9331  *
9332  * Forces a width on an actor, causing the actor's preferred width
9333  * and height (if any) to be ignored.
9334  *
9335  * If @width is -1 the actor will use its preferred width request
9336  * instead of overriding it, i.e. you can "unset" the width with -1.
9337  *
9338  * This function sets both the minimum and natural size of the actor.
9339  *
9340  * since: 0.2
9341  */
9342 void
9343 clutter_actor_set_width (ClutterActor *self,
9344                          gfloat        width)
9345 {
9346   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9347
9348   if (clutter_actor_get_easing_duration (self) != 0)
9349     {
9350       ClutterTransition *transition;
9351
9352       transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9353       if (transition == NULL)
9354         {
9355           float old_width = clutter_actor_get_width (self);
9356
9357           transition = _clutter_actor_create_transition (self,
9358                                                          obj_props[PROP_WIDTH],
9359                                                          old_width,
9360                                                          width);
9361           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9362         }
9363       else
9364         _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9365
9366       clutter_actor_queue_relayout (self);
9367     }
9368   else
9369     {
9370       g_object_freeze_notify (G_OBJECT (self));
9371
9372       clutter_actor_set_width_internal (self, width);
9373
9374       g_object_thaw_notify (G_OBJECT (self));
9375     }
9376 }
9377
9378 /**
9379  * clutter_actor_set_height:
9380  * @self: A #ClutterActor
9381  * @height: Requested new height for the actor, in pixels, or -1
9382  *
9383  * Forces a height on an actor, causing the actor's preferred width
9384  * and height (if any) to be ignored.
9385  *
9386  * If @height is -1 the actor will use its preferred height instead of
9387  * overriding it, i.e. you can "unset" the height with -1.
9388  *
9389  * This function sets both the minimum and natural size of the actor.
9390  *
9391  * since: 0.2
9392  */
9393 void
9394 clutter_actor_set_height (ClutterActor *self,
9395                           gfloat        height)
9396 {
9397   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9398
9399   if (clutter_actor_get_easing_duration (self) != 0)
9400     {
9401       ClutterTransition *transition;
9402
9403       transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9404       if (transition ==  NULL)
9405         {
9406           float old_height = clutter_actor_get_height (self);
9407
9408           transition = _clutter_actor_create_transition (self,
9409                                                          obj_props[PROP_HEIGHT],
9410                                                          old_height,
9411                                                          height);
9412           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9413         }
9414       else
9415         _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9416
9417       clutter_actor_queue_relayout (self);
9418     }
9419   else
9420     {
9421       g_object_freeze_notify (G_OBJECT (self));
9422
9423       clutter_actor_set_height_internal (self, height);
9424
9425       g_object_thaw_notify (G_OBJECT (self));
9426     }
9427 }
9428
9429 static inline void
9430 clutter_actor_set_x_internal (ClutterActor *self,
9431                               float         x)
9432 {
9433   ClutterActorPrivate *priv = self->priv;
9434   ClutterLayoutInfo *linfo;
9435   ClutterActorBox old = { 0, };
9436
9437   linfo = _clutter_actor_get_layout_info (self);
9438
9439   if (priv->position_set && linfo->fixed_x == x)
9440     return;
9441
9442   clutter_actor_store_old_geometry (self, &old);
9443
9444   linfo->fixed_x = x;
9445   clutter_actor_set_fixed_position_set (self, TRUE);
9446
9447   clutter_actor_notify_if_geometry_changed (self, &old);
9448
9449   clutter_actor_queue_relayout (self);
9450 }
9451
9452 static inline void
9453 clutter_actor_set_y_internal (ClutterActor *self,
9454                               float         y)
9455 {
9456   ClutterActorPrivate *priv = self->priv;
9457   ClutterLayoutInfo *linfo;
9458   ClutterActorBox old = { 0, };
9459
9460   linfo = _clutter_actor_get_layout_info (self);
9461
9462   if (priv->position_set && linfo->fixed_y == y)
9463     return;
9464
9465   clutter_actor_store_old_geometry (self, &old);
9466
9467   linfo->fixed_y = y;
9468   clutter_actor_set_fixed_position_set (self, TRUE);
9469
9470   clutter_actor_notify_if_geometry_changed (self, &old);
9471 }
9472
9473 /**
9474  * clutter_actor_set_x:
9475  * @self: a #ClutterActor
9476  * @x: the actor's position on the X axis
9477  *
9478  * Sets the actor's X coordinate, relative to its parent, in pixels.
9479  *
9480  * Overrides any layout manager and forces a fixed position for
9481  * the actor.
9482  *
9483  * The #ClutterActor:x property is animatable.
9484  *
9485  * Since: 0.6
9486  */
9487 void
9488 clutter_actor_set_x (ClutterActor *self,
9489                      gfloat        x)
9490 {
9491   const ClutterLayoutInfo *linfo;
9492
9493   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9494
9495   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9496
9497   if (clutter_actor_get_easing_duration (self) != 0)
9498     {
9499       ClutterTransition *transition;
9500
9501       transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9502       if (transition == NULL)
9503         {
9504           transition = _clutter_actor_create_transition (self,
9505                                                          obj_props[PROP_X],
9506                                                          linfo->fixed_x,
9507                                                          x);
9508
9509           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9510         }
9511       else
9512         _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9513
9514       clutter_actor_queue_relayout (self);
9515     }
9516   else
9517     clutter_actor_set_x_internal (self, x);
9518 }
9519
9520 /**
9521  * clutter_actor_set_y:
9522  * @self: a #ClutterActor
9523  * @y: the actor's position on the Y axis
9524  *
9525  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9526  *
9527  * Overrides any layout manager and forces a fixed position for
9528  * the actor.
9529  *
9530  * The #ClutterActor:y property is animatable.
9531  *
9532  * Since: 0.6
9533  */
9534 void
9535 clutter_actor_set_y (ClutterActor *self,
9536                      gfloat        y)
9537 {
9538   const ClutterLayoutInfo *linfo;
9539
9540   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9541
9542   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9543
9544   if (clutter_actor_get_easing_duration (self) != 0)
9545     {
9546       ClutterTransition *transition;
9547
9548       transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9549       if (transition == NULL)
9550         {
9551           transition = _clutter_actor_create_transition (self,
9552                                                          obj_props[PROP_Y],
9553                                                          linfo->fixed_y,
9554                                                          y);
9555
9556           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9557         }
9558       else
9559         _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9560
9561       clutter_actor_queue_relayout (self);
9562     }
9563   else
9564     clutter_actor_set_y_internal (self, y);
9565
9566   clutter_actor_queue_relayout (self);
9567 }
9568
9569 /**
9570  * clutter_actor_get_x:
9571  * @self: A #ClutterActor
9572  *
9573  * Retrieves the X coordinate of a #ClutterActor.
9574  *
9575  * This function tries to "do what you mean", by returning the
9576  * correct value depending on the actor's state.
9577  *
9578  * If the actor has a valid allocation, this function will return
9579  * the X coordinate of the origin of the allocation box.
9580  *
9581  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9582  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9583  * function will return that coordinate.
9584  *
9585  * If both the allocation and a fixed position are missing, this function
9586  * will return 0.
9587  *
9588  * Return value: the X coordinate, in pixels, ignoring any
9589  *   transformation (i.e. scaling, rotation)
9590  */
9591 gfloat
9592 clutter_actor_get_x (ClutterActor *self)
9593 {
9594   ClutterActorPrivate *priv;
9595
9596   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9597
9598   priv = self->priv;
9599
9600   if (priv->needs_allocation)
9601     {
9602       if (priv->position_set)
9603         {
9604           const ClutterLayoutInfo *info;
9605
9606           info = _clutter_actor_get_layout_info_or_defaults (self);
9607
9608           return info->fixed_x;
9609         }
9610       else
9611         return 0;
9612     }
9613   else
9614     return priv->allocation.x1;
9615 }
9616
9617 /**
9618  * clutter_actor_get_y:
9619  * @self: A #ClutterActor
9620  *
9621  * Retrieves the Y coordinate of a #ClutterActor.
9622  *
9623  * This function tries to "do what you mean", by returning the
9624  * correct value depending on the actor's state.
9625  *
9626  * If the actor has a valid allocation, this function will return
9627  * the Y coordinate of the origin of the allocation box.
9628  *
9629  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9630  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9631  * function will return that coordinate.
9632  *
9633  * If both the allocation and a fixed position are missing, this function
9634  * will return 0.
9635  *
9636  * Return value: the Y coordinate, in pixels, ignoring any
9637  *   transformation (i.e. scaling, rotation)
9638  */
9639 gfloat
9640 clutter_actor_get_y (ClutterActor *self)
9641 {
9642   ClutterActorPrivate *priv;
9643
9644   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9645
9646   priv = self->priv;
9647
9648   if (priv->needs_allocation)
9649     {
9650       if (priv->position_set)
9651         {
9652           const ClutterLayoutInfo *info;
9653
9654           info = _clutter_actor_get_layout_info_or_defaults (self);
9655
9656           return info->fixed_y;
9657         }
9658       else
9659         return 0;
9660     }
9661   else
9662     return priv->allocation.y1;
9663 }
9664
9665 /**
9666  * clutter_actor_set_scale:
9667  * @self: A #ClutterActor
9668  * @scale_x: double factor to scale actor by horizontally.
9669  * @scale_y: double factor to scale actor by vertically.
9670  *
9671  * Scales an actor with the given factors. The scaling is relative to
9672  * the scale center and the anchor point. The scale center is
9673  * unchanged by this function and defaults to 0,0.
9674  *
9675  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9676  * animatable.
9677  *
9678  * Since: 0.2
9679  */
9680 void
9681 clutter_actor_set_scale (ClutterActor *self,
9682                          gdouble       scale_x,
9683                          gdouble       scale_y)
9684 {
9685   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9686
9687   g_object_freeze_notify (G_OBJECT (self));
9688
9689   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9690   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9691
9692   g_object_thaw_notify (G_OBJECT (self));
9693 }
9694
9695 /**
9696  * clutter_actor_set_scale_full:
9697  * @self: A #ClutterActor
9698  * @scale_x: double factor to scale actor by horizontally.
9699  * @scale_y: double factor to scale actor by vertically.
9700  * @center_x: X coordinate of the center of the scale.
9701  * @center_y: Y coordinate of the center of the scale
9702  *
9703  * Scales an actor with the given factors around the given center
9704  * point. The center point is specified in pixels relative to the
9705  * anchor point (usually the top left corner of the actor).
9706  *
9707  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9708  * are animatable.
9709  *
9710  * Since: 1.0
9711  */
9712 void
9713 clutter_actor_set_scale_full (ClutterActor *self,
9714                               gdouble       scale_x,
9715                               gdouble       scale_y,
9716                               gfloat        center_x,
9717                               gfloat        center_y)
9718 {
9719   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9720
9721   g_object_freeze_notify (G_OBJECT (self));
9722
9723   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9724   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9725   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9726   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9727
9728   g_object_thaw_notify (G_OBJECT (self));
9729 }
9730
9731 /**
9732  * clutter_actor_set_scale_with_gravity:
9733  * @self: A #ClutterActor
9734  * @scale_x: double factor to scale actor by horizontally.
9735  * @scale_y: double factor to scale actor by vertically.
9736  * @gravity: the location of the scale center expressed as a compass
9737  * direction.
9738  *
9739  * Scales an actor with the given factors around the given
9740  * center point. The center point is specified as one of the compass
9741  * directions in #ClutterGravity. For example, setting it to north
9742  * will cause the top of the actor to remain unchanged and the rest of
9743  * the actor to expand left, right and downwards.
9744  *
9745  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9746  * animatable.
9747  *
9748  * Since: 1.0
9749  */
9750 void
9751 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9752                                       gdouble         scale_x,
9753                                       gdouble         scale_y,
9754                                       ClutterGravity  gravity)
9755 {
9756   ClutterTransformInfo *info;
9757   GObject *obj;
9758
9759   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9760
9761   obj = G_OBJECT (self);
9762
9763   g_object_freeze_notify (obj);
9764
9765   info = _clutter_actor_get_transform_info (self);
9766   info->scale_x = scale_x;
9767   info->scale_y = scale_y;
9768
9769   if (gravity == CLUTTER_GRAVITY_NONE)
9770     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9771   else
9772     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9773
9774   self->priv->transform_valid = FALSE;
9775
9776   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9777   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9778   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9779   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9780   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9781
9782   clutter_actor_queue_redraw (self);
9783
9784   g_object_thaw_notify (obj);
9785 }
9786
9787 /**
9788  * clutter_actor_get_scale:
9789  * @self: A #ClutterActor
9790  * @scale_x: (out) (allow-none): Location to store horizonal
9791  *   scale factor, or %NULL.
9792  * @scale_y: (out) (allow-none): Location to store vertical
9793  *   scale factor, or %NULL.
9794  *
9795  * Retrieves an actors scale factors.
9796  *
9797  * Since: 0.2
9798  */
9799 void
9800 clutter_actor_get_scale (ClutterActor *self,
9801                          gdouble      *scale_x,
9802                          gdouble      *scale_y)
9803 {
9804   const ClutterTransformInfo *info;
9805
9806   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9807
9808   info = _clutter_actor_get_transform_info_or_defaults (self);
9809
9810   if (scale_x)
9811     *scale_x = info->scale_x;
9812
9813   if (scale_y)
9814     *scale_y = info->scale_y;
9815 }
9816
9817 /**
9818  * clutter_actor_get_scale_center:
9819  * @self: A #ClutterActor
9820  * @center_x: (out) (allow-none): Location to store the X position
9821  *   of the scale center, or %NULL.
9822  * @center_y: (out) (allow-none): Location to store the Y position
9823  *   of the scale center, or %NULL.
9824  *
9825  * Retrieves the scale center coordinate in pixels relative to the top
9826  * left corner of the actor. If the scale center was specified using a
9827  * #ClutterGravity this will calculate the pixel offset using the
9828  * current size of the actor.
9829  *
9830  * Since: 1.0
9831  */
9832 void
9833 clutter_actor_get_scale_center (ClutterActor *self,
9834                                 gfloat       *center_x,
9835                                 gfloat       *center_y)
9836 {
9837   const ClutterTransformInfo *info;
9838
9839   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9840
9841   info = _clutter_actor_get_transform_info_or_defaults (self);
9842
9843   clutter_anchor_coord_get_units (self, &info->scale_center,
9844                                   center_x,
9845                                   center_y,
9846                                   NULL);
9847 }
9848
9849 /**
9850  * clutter_actor_get_scale_gravity:
9851  * @self: A #ClutterActor
9852  *
9853  * Retrieves the scale center as a compass direction. If the scale
9854  * center was specified in pixels or units this will return
9855  * %CLUTTER_GRAVITY_NONE.
9856  *
9857  * Return value: the scale gravity
9858  *
9859  * Since: 1.0
9860  */
9861 ClutterGravity
9862 clutter_actor_get_scale_gravity (ClutterActor *self)
9863 {
9864   const ClutterTransformInfo *info;
9865
9866   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9867
9868   info = _clutter_actor_get_transform_info_or_defaults (self);
9869
9870   return clutter_anchor_coord_get_gravity (&info->scale_center);
9871 }
9872
9873 static inline void
9874 clutter_actor_set_opacity_internal (ClutterActor *self,
9875                                     guint8        opacity)
9876 {
9877   ClutterActorPrivate *priv = self->priv;
9878
9879   if (priv->opacity != opacity)
9880     {
9881       priv->opacity = opacity;
9882
9883       /* Queue a redraw from the flatten effect so that it can use
9884          its cached image if available instead of having to redraw the
9885          actual actor. If it doesn't end up using the FBO then the
9886          effect is still able to continue the paint anyway. If there
9887          is no flatten effect yet then this is equivalent to queueing
9888          a full redraw */
9889       _clutter_actor_queue_redraw_full (self,
9890                                         0, /* flags */
9891                                         NULL, /* clip */
9892                                         priv->flatten_effect);
9893
9894       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9895     }
9896 }
9897
9898 /**
9899  * clutter_actor_set_opacity:
9900  * @self: A #ClutterActor
9901  * @opacity: New opacity value for the actor.
9902  *
9903  * Sets the actor's opacity, with zero being completely transparent and
9904  * 255 (0xff) being fully opaque.
9905  *
9906  * The #ClutterActor:opacity property is animatable.
9907  */
9908 void
9909 clutter_actor_set_opacity (ClutterActor *self,
9910                            guint8        opacity)
9911 {
9912   ClutterActorPrivate *priv;
9913
9914   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9915
9916   priv = self->priv;
9917
9918   if (clutter_actor_get_easing_duration (self) != 0)
9919     {
9920       ClutterTransition *transition;
9921
9922       transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9923       if (transition == NULL)
9924         {
9925           transition = _clutter_actor_create_transition (self,
9926                                                          obj_props[PROP_OPACITY],
9927                                                          priv->opacity,
9928                                                          opacity);
9929           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9930         }
9931       else
9932         _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9933
9934       clutter_actor_queue_redraw (self);
9935     }
9936   else
9937     clutter_actor_set_opacity_internal (self, opacity);
9938 }
9939
9940 /*
9941  * clutter_actor_get_paint_opacity_internal:
9942  * @self: a #ClutterActor
9943  *
9944  * Retrieves the absolute opacity of the actor, as it appears on the stage
9945  *
9946  * This function does not do type checks
9947  *
9948  * Return value: the absolute opacity of the actor
9949  */
9950 static guint8
9951 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9952 {
9953   ClutterActorPrivate *priv = self->priv;
9954   ClutterActor *parent;
9955
9956   /* override the top-level opacity to always be 255; even in
9957    * case of ClutterStage:use-alpha being TRUE we want the rest
9958    * of the scene to be painted
9959    */
9960   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9961     return 255;
9962
9963   if (priv->opacity_override >= 0)
9964     return priv->opacity_override;
9965
9966   parent = priv->parent;
9967
9968   /* Factor in the actual actors opacity with parents */
9969   if (parent != NULL)
9970     {
9971       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9972
9973       if (opacity != 0xff)
9974         return (opacity * priv->opacity) / 0xff;
9975     }
9976
9977   return priv->opacity;
9978
9979 }
9980
9981 /**
9982  * clutter_actor_get_paint_opacity:
9983  * @self: A #ClutterActor
9984  *
9985  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9986  *
9987  * This function traverses the hierarchy chain and composites the opacity of
9988  * the actor with that of its parents.
9989  *
9990  * This function is intended for subclasses to use in the paint virtual
9991  * function, to paint themselves with the correct opacity.
9992  *
9993  * Return value: The actor opacity value.
9994  *
9995  * Since: 0.8
9996  */
9997 guint8
9998 clutter_actor_get_paint_opacity (ClutterActor *self)
9999 {
10000   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10001
10002   return clutter_actor_get_paint_opacity_internal (self);
10003 }
10004
10005 /**
10006  * clutter_actor_get_opacity:
10007  * @self: a #ClutterActor
10008  *
10009  * Retrieves the opacity value of an actor, as set by
10010  * clutter_actor_set_opacity().
10011  *
10012  * For retrieving the absolute opacity of the actor inside a paint
10013  * virtual function, see clutter_actor_get_paint_opacity().
10014  *
10015  * Return value: the opacity of the actor
10016  */
10017 guint8
10018 clutter_actor_get_opacity (ClutterActor *self)
10019 {
10020   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10021
10022   return self->priv->opacity;
10023 }
10024
10025 /**
10026  * clutter_actor_set_offscreen_redirect:
10027  * @self: A #ClutterActor
10028  * @redirect: New offscreen redirect flags for the actor.
10029  *
10030  * Defines the circumstances where the actor should be redirected into
10031  * an offscreen image. The offscreen image is used to flatten the
10032  * actor into a single image while painting for two main reasons.
10033  * Firstly, when the actor is painted a second time without any of its
10034  * contents changing it can simply repaint the cached image without
10035  * descending further down the actor hierarchy. Secondly, it will make
10036  * the opacity look correct even if there are overlapping primitives
10037  * in the actor.
10038  *
10039  * Caching the actor could in some cases be a performance win and in
10040  * some cases be a performance lose so it is important to determine
10041  * which value is right for an actor before modifying this value. For
10042  * example, there is never any reason to flatten an actor that is just
10043  * a single texture (such as a #ClutterTexture) because it is
10044  * effectively already cached in an image so the offscreen would be
10045  * redundant. Also if the actor contains primitives that are far apart
10046  * with a large transparent area in the middle (such as a large
10047  * CluterGroup with a small actor in the top left and a small actor in
10048  * the bottom right) then the cached image will contain the entire
10049  * image of the large area and the paint will waste time blending all
10050  * of the transparent pixels in the middle.
10051  *
10052  * The default method of implementing opacity on a container simply
10053  * forwards on the opacity to all of the children. If the children are
10054  * overlapping then it will appear as if they are two separate glassy
10055  * objects and there will be a break in the color where they
10056  * overlap. By redirecting to an offscreen buffer it will be as if the
10057  * two opaque objects are combined into one and then made transparent
10058  * which is usually what is expected.
10059  *
10060  * The image below demonstrates the difference between redirecting and
10061  * not. The image shows two Clutter groups, each containing a red and
10062  * a green rectangle which overlap. The opacity on the group is set to
10063  * 128 (which is 50%). When the offscreen redirect is not used, the
10064  * red rectangle can be seen through the blue rectangle as if the two
10065  * rectangles were separately transparent. When the redirect is used
10066  * the group as a whole is transparent instead so the red rectangle is
10067  * not visible where they overlap.
10068  *
10069  * <figure id="offscreen-redirect">
10070  *   <title>Sample of using an offscreen redirect for transparency</title>
10071  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10072  * </figure>
10073  *
10074  * The default value for this property is 0, so we effectively will
10075  * never redirect an actor offscreen by default. This means that there
10076  * are times that transparent actors may look glassy as described
10077  * above. The reason this is the default is because there is a
10078  * performance trade off between quality and performance here. In many
10079  * cases the default form of glassy opacity looks good enough, but if
10080  * it's not you will need to set the
10081  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10082  * redirection for opacity.
10083  *
10084  * Custom actors that don't contain any overlapping primitives are
10085  * recommended to override the has_overlaps() virtual to return %FALSE
10086  * for maximum efficiency.
10087  *
10088  * Since: 1.8
10089  */
10090 void
10091 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10092                                       ClutterOffscreenRedirect redirect)
10093 {
10094   ClutterActorPrivate *priv;
10095
10096   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10097
10098   priv = self->priv;
10099
10100   if (priv->offscreen_redirect != redirect)
10101     {
10102       priv->offscreen_redirect = redirect;
10103
10104       /* Queue a redraw from the effect so that it can use its cached
10105          image if available instead of having to redraw the actual
10106          actor. If it doesn't end up using the FBO then the effect is
10107          still able to continue the paint anyway. If there is no
10108          effect then this is equivalent to queuing a full redraw */
10109       _clutter_actor_queue_redraw_full (self,
10110                                         0, /* flags */
10111                                         NULL, /* clip */
10112                                         priv->flatten_effect);
10113
10114       g_object_notify_by_pspec (G_OBJECT (self),
10115                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10116     }
10117 }
10118
10119 /**
10120  * clutter_actor_get_offscreen_redirect:
10121  * @self: a #ClutterActor
10122  *
10123  * Retrieves whether to redirect the actor to an offscreen buffer, as
10124  * set by clutter_actor_set_offscreen_redirect().
10125  *
10126  * Return value: the value of the offscreen-redirect property of the actor
10127  *
10128  * Since: 1.8
10129  */
10130 ClutterOffscreenRedirect
10131 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10132 {
10133   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10134
10135   return self->priv->offscreen_redirect;
10136 }
10137
10138 /**
10139  * clutter_actor_set_name:
10140  * @self: A #ClutterActor
10141  * @name: Textual tag to apply to actor
10142  *
10143  * Sets the given name to @self. The name can be used to identify
10144  * a #ClutterActor.
10145  */
10146 void
10147 clutter_actor_set_name (ClutterActor *self,
10148                         const gchar  *name)
10149 {
10150   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10151
10152   g_free (self->priv->name);
10153   self->priv->name = g_strdup (name);
10154
10155   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10156 }
10157
10158 /**
10159  * clutter_actor_get_name:
10160  * @self: A #ClutterActor
10161  *
10162  * Retrieves the name of @self.
10163  *
10164  * Return value: the name of the actor, or %NULL. The returned string is
10165  *   owned by the actor and should not be modified or freed.
10166  */
10167 const gchar *
10168 clutter_actor_get_name (ClutterActor *self)
10169 {
10170   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10171
10172   return self->priv->name;
10173 }
10174
10175 /**
10176  * clutter_actor_get_gid:
10177  * @self: A #ClutterActor
10178  *
10179  * Retrieves the unique id for @self.
10180  *
10181  * Return value: Globally unique value for this object instance.
10182  *
10183  * Since: 0.6
10184  *
10185  * Deprecated: 1.8: The id is not used any longer.
10186  */
10187 guint32
10188 clutter_actor_get_gid (ClutterActor *self)
10189 {
10190   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10191
10192   return self->priv->id;
10193 }
10194
10195 static inline void
10196 clutter_actor_set_depth_internal (ClutterActor *self,
10197                                   float         depth)
10198 {
10199   ClutterTransformInfo *info;
10200
10201   info = _clutter_actor_get_transform_info (self);
10202
10203   if (info->depth != depth)
10204     {
10205       /* Sets Z value - XXX 2.0: should we invert? */
10206       info->depth = depth;
10207
10208       self->priv->transform_valid = FALSE;
10209
10210       /* FIXME - remove this crap; sadly, there are still containers
10211        * in Clutter that depend on this utter brain damage
10212        */
10213       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10214
10215       clutter_actor_queue_redraw (self);
10216
10217       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10218     }
10219 }
10220
10221 /**
10222  * clutter_actor_set_depth:
10223  * @self: a #ClutterActor
10224  * @depth: Z co-ord
10225  *
10226  * Sets the Z coordinate of @self to @depth.
10227  *
10228  * The unit used by @depth is dependant on the perspective setup. See
10229  * also clutter_stage_set_perspective().
10230  */
10231 void
10232 clutter_actor_set_depth (ClutterActor *self,
10233                          gfloat        depth)
10234 {
10235   const ClutterTransformInfo *tinfo;
10236
10237   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10238
10239   tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10240
10241   if (clutter_actor_get_easing_duration (self) != 0)
10242     {
10243       ClutterTransition *transition;
10244
10245       transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10246       if (transition == NULL)
10247         {
10248           transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10249                                                          tinfo->depth,
10250                                                          depth);
10251           clutter_timeline_start (CLUTTER_TIMELINE (transition));
10252         }
10253       else
10254         _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10255
10256       clutter_actor_queue_redraw (self);
10257     }
10258   else
10259     clutter_actor_set_depth_internal (self, depth);
10260 }
10261
10262 /**
10263  * clutter_actor_get_depth:
10264  * @self: a #ClutterActor
10265  *
10266  * Retrieves the depth of @self.
10267  *
10268  * Return value: the depth of the actor
10269  */
10270 gfloat
10271 clutter_actor_get_depth (ClutterActor *self)
10272 {
10273   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10274
10275   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10276 }
10277
10278 /**
10279  * clutter_actor_set_rotation:
10280  * @self: a #ClutterActor
10281  * @axis: the axis of rotation
10282  * @angle: the angle of rotation
10283  * @x: X coordinate of the rotation center
10284  * @y: Y coordinate of the rotation center
10285  * @z: Z coordinate of the rotation center
10286  *
10287  * Sets the rotation angle of @self around the given axis.
10288  *
10289  * The rotation center coordinates used depend on the value of @axis:
10290  * <itemizedlist>
10291  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10292  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10293  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10294  * </itemizedlist>
10295  *
10296  * The rotation coordinates are relative to the anchor point of the
10297  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10298  * point is set, the upper left corner is assumed as the origin.
10299  *
10300  * Since: 0.8
10301  */
10302 void
10303 clutter_actor_set_rotation (ClutterActor      *self,
10304                             ClutterRotateAxis  axis,
10305                             gdouble            angle,
10306                             gfloat             x,
10307                             gfloat             y,
10308                             gfloat             z)
10309 {
10310   ClutterVertex v;
10311
10312   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10313
10314   v.x = x;
10315   v.y = y;
10316   v.z = z;
10317
10318   g_object_freeze_notify (G_OBJECT (self));
10319
10320   clutter_actor_set_rotation_angle (self, axis, angle);
10321   clutter_actor_set_rotation_center_internal (self, axis, &v);
10322
10323   g_object_thaw_notify (G_OBJECT (self));
10324 }
10325
10326 /**
10327  * clutter_actor_set_z_rotation_from_gravity:
10328  * @self: a #ClutterActor
10329  * @angle: the angle of rotation
10330  * @gravity: the center point of the rotation
10331  *
10332  * Sets the rotation angle of @self around the Z axis using the center
10333  * point specified as a compass point. For example to rotate such that
10334  * the center of the actor remains static you can use
10335  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10336  * will move accordingly.
10337  *
10338  * Since: 1.0
10339  */
10340 void
10341 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10342                                            gdouble         angle,
10343                                            ClutterGravity  gravity)
10344 {
10345   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10346
10347   if (gravity == CLUTTER_GRAVITY_NONE)
10348     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10349   else
10350     {
10351       GObject *obj = G_OBJECT (self);
10352       ClutterTransformInfo *info;
10353
10354       info = _clutter_actor_get_transform_info (self);
10355
10356       g_object_freeze_notify (obj);
10357
10358       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10359
10360       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10361       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10362       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10363
10364       g_object_thaw_notify (obj);
10365     }
10366 }
10367
10368 /**
10369  * clutter_actor_get_rotation:
10370  * @self: a #ClutterActor
10371  * @axis: the axis of rotation
10372  * @x: (out): return value for the X coordinate of the center of rotation
10373  * @y: (out): return value for the Y coordinate of the center of rotation
10374  * @z: (out): return value for the Z coordinate of the center of rotation
10375  *
10376  * Retrieves the angle and center of rotation on the given axis,
10377  * set using clutter_actor_set_rotation().
10378  *
10379  * Return value: the angle of rotation
10380  *
10381  * Since: 0.8
10382  */
10383 gdouble
10384 clutter_actor_get_rotation (ClutterActor      *self,
10385                             ClutterRotateAxis  axis,
10386                             gfloat            *x,
10387                             gfloat            *y,
10388                             gfloat            *z)
10389 {
10390   const ClutterTransformInfo *info;
10391   const AnchorCoord *anchor_coord;
10392   gdouble retval = 0;
10393
10394   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10395
10396   info = _clutter_actor_get_transform_info_or_defaults (self);
10397
10398   switch (axis)
10399     {
10400     case CLUTTER_X_AXIS:
10401       anchor_coord = &info->rx_center;
10402       retval = info->rx_angle;
10403       break;
10404
10405     case CLUTTER_Y_AXIS:
10406       anchor_coord = &info->ry_center;
10407       retval = info->ry_angle;
10408       break;
10409
10410     case CLUTTER_Z_AXIS:
10411       anchor_coord = &info->rz_center;
10412       retval = info->rz_angle;
10413       break;
10414
10415     default:
10416       anchor_coord = NULL;
10417       retval = 0.0;
10418       break;
10419     }
10420
10421   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10422
10423   return retval;
10424 }
10425
10426 /**
10427  * clutter_actor_get_z_rotation_gravity:
10428  * @self: A #ClutterActor
10429  *
10430  * Retrieves the center for the rotation around the Z axis as a
10431  * compass direction. If the center was specified in pixels or units
10432  * this will return %CLUTTER_GRAVITY_NONE.
10433  *
10434  * Return value: the Z rotation center
10435  *
10436  * Since: 1.0
10437  */
10438 ClutterGravity
10439 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10440 {
10441   const ClutterTransformInfo *info;
10442
10443   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10444
10445   info = _clutter_actor_get_transform_info_or_defaults (self);
10446
10447   return clutter_anchor_coord_get_gravity (&info->rz_center);
10448 }
10449
10450 /**
10451  * clutter_actor_set_clip:
10452  * @self: A #ClutterActor
10453  * @xoff: X offset of the clip rectangle
10454  * @yoff: Y offset of the clip rectangle
10455  * @width: Width of the clip rectangle
10456  * @height: Height of the clip rectangle
10457  *
10458  * Sets clip area for @self. The clip area is always computed from the
10459  * upper left corner of the actor, even if the anchor point is set
10460  * otherwise.
10461  *
10462  * Since: 0.6
10463  */
10464 void
10465 clutter_actor_set_clip (ClutterActor *self,
10466                         gfloat        xoff,
10467                         gfloat        yoff,
10468                         gfloat        width,
10469                         gfloat        height)
10470 {
10471   ClutterActorPrivate *priv;
10472
10473   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10474
10475   priv = self->priv;
10476
10477   if (priv->has_clip &&
10478       priv->clip.x == xoff &&
10479       priv->clip.y == yoff &&
10480       priv->clip.width == width &&
10481       priv->clip.height == height)
10482     return;
10483
10484   priv->clip.x = xoff;
10485   priv->clip.y = yoff;
10486   priv->clip.width = width;
10487   priv->clip.height = height;
10488
10489   priv->has_clip = TRUE;
10490
10491   clutter_actor_queue_redraw (self);
10492
10493   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10494   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10495 }
10496
10497 /**
10498  * clutter_actor_remove_clip:
10499  * @self: A #ClutterActor
10500  *
10501  * Removes clip area from @self.
10502  */
10503 void
10504 clutter_actor_remove_clip (ClutterActor *self)
10505 {
10506   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10507
10508   if (!self->priv->has_clip)
10509     return;
10510
10511   self->priv->has_clip = FALSE;
10512
10513   clutter_actor_queue_redraw (self);
10514
10515   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10516 }
10517
10518 /**
10519  * clutter_actor_has_clip:
10520  * @self: a #ClutterActor
10521  *
10522  * Determines whether the actor has a clip area set or not.
10523  *
10524  * Return value: %TRUE if the actor has a clip area set.
10525  *
10526  * Since: 0.1.1
10527  */
10528 gboolean
10529 clutter_actor_has_clip (ClutterActor *self)
10530 {
10531   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10532
10533   return self->priv->has_clip;
10534 }
10535
10536 /**
10537  * clutter_actor_get_clip:
10538  * @self: a #ClutterActor
10539  * @xoff: (out) (allow-none): return location for the X offset of
10540  *   the clip rectangle, or %NULL
10541  * @yoff: (out) (allow-none): return location for the Y offset of
10542  *   the clip rectangle, or %NULL
10543  * @width: (out) (allow-none): return location for the width of
10544  *   the clip rectangle, or %NULL
10545  * @height: (out) (allow-none): return location for the height of
10546  *   the clip rectangle, or %NULL
10547  *
10548  * Gets the clip area for @self, if any is set
10549  *
10550  * Since: 0.6
10551  */
10552 void
10553 clutter_actor_get_clip (ClutterActor *self,
10554                         gfloat       *xoff,
10555                         gfloat       *yoff,
10556                         gfloat       *width,
10557                         gfloat       *height)
10558 {
10559   ClutterActorPrivate *priv;
10560
10561   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10562
10563   priv = self->priv;
10564
10565   if (!priv->has_clip)
10566     return;
10567
10568   if (xoff != NULL)
10569     *xoff = priv->clip.x;
10570
10571   if (yoff != NULL)
10572     *yoff = priv->clip.y;
10573
10574   if (width != NULL)
10575     *width = priv->clip.width;
10576
10577   if (height != NULL)
10578     *height = priv->clip.height;
10579 }
10580
10581 /**
10582  * clutter_actor_get_children:
10583  * @self: a #ClutterActor
10584  *
10585  * Retrieves the list of children of @self.
10586  *
10587  * Return value: (transfer container) (element-type ClutterActor): A newly
10588  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10589  *   done.
10590  *
10591  * Since: 1.10
10592  */
10593 GList *
10594 clutter_actor_get_children (ClutterActor *self)
10595 {
10596   ClutterActor *iter;
10597   GList *res;
10598
10599   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10600
10601   /* we walk the list backward so that we can use prepend(),
10602    * which is O(1)
10603    */
10604   for (iter = self->priv->last_child, res = NULL;
10605        iter != NULL;
10606        iter = iter->priv->prev_sibling)
10607     {
10608       res = g_list_prepend (res, iter);
10609     }
10610
10611   return res;
10612 }
10613
10614 /*< private >
10615  * insert_child_at_depth:
10616  * @self: a #ClutterActor
10617  * @child: a #ClutterActor
10618  *
10619  * Inserts @child inside the list of children held by @self, using
10620  * the depth as the insertion criteria.
10621  *
10622  * This sadly makes the insertion not O(1), but we can keep the
10623  * list sorted so that the painters algorithm we use for painting
10624  * the children will work correctly.
10625  */
10626 static void
10627 insert_child_at_depth (ClutterActor *self,
10628                        ClutterActor *child,
10629                        gpointer      dummy G_GNUC_UNUSED)
10630 {
10631   ClutterActor *iter;
10632   float child_depth;
10633
10634   child->priv->parent = self;
10635
10636   child_depth =
10637     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10638
10639   /* special-case the first child */
10640   if (self->priv->n_children == 0)
10641     {
10642       self->priv->first_child = child;
10643       self->priv->last_child = child;
10644
10645       child->priv->next_sibling = NULL;
10646       child->priv->prev_sibling = NULL;
10647
10648       return;
10649     }
10650
10651   /* Find the right place to insert the child so that it will still be
10652      sorted and the child will be after all of the actors at the same
10653      dept */
10654   for (iter = self->priv->first_child;
10655        iter != NULL;
10656        iter = iter->priv->next_sibling)
10657     {
10658       float iter_depth;
10659
10660       iter_depth =
10661         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10662
10663       if (iter_depth > child_depth)
10664         break;
10665     }
10666
10667   if (iter != NULL)
10668     {
10669       ClutterActor *tmp = iter->priv->prev_sibling;
10670
10671       if (tmp != NULL)
10672         tmp->priv->next_sibling = child;
10673
10674       /* Insert the node before the found one */
10675       child->priv->prev_sibling = iter->priv->prev_sibling;
10676       child->priv->next_sibling = iter;
10677       iter->priv->prev_sibling = child;
10678     }
10679   else
10680     {
10681       ClutterActor *tmp = self->priv->last_child;
10682
10683       if (tmp != NULL)
10684         tmp->priv->next_sibling = child;
10685
10686       /* insert the node at the end of the list */
10687       child->priv->prev_sibling = self->priv->last_child;
10688       child->priv->next_sibling = NULL;
10689     }
10690
10691   if (child->priv->prev_sibling == NULL)
10692     self->priv->first_child = child;
10693
10694   if (child->priv->next_sibling == NULL)
10695     self->priv->last_child = child;
10696 }
10697
10698 static void
10699 insert_child_at_index (ClutterActor *self,
10700                        ClutterActor *child,
10701                        gpointer      data_)
10702 {
10703   gint index_ = GPOINTER_TO_INT (data_);
10704
10705   child->priv->parent = self;
10706
10707   if (index_ == 0)
10708     {
10709       ClutterActor *tmp = self->priv->first_child;
10710
10711       if (tmp != NULL)
10712         tmp->priv->prev_sibling = child;
10713
10714       child->priv->prev_sibling = NULL;
10715       child->priv->next_sibling = tmp;
10716     }
10717   else if (index_ < 0 || index_ >= self->priv->n_children)
10718     {
10719       ClutterActor *tmp = self->priv->last_child;
10720
10721       if (tmp != NULL)
10722         tmp->priv->next_sibling = child;
10723
10724       child->priv->prev_sibling = tmp;
10725       child->priv->next_sibling = NULL;
10726     }
10727   else
10728     {
10729       ClutterActor *iter;
10730       int i;
10731
10732       for (iter = self->priv->first_child, i = 0;
10733            iter != NULL;
10734            iter = iter->priv->next_sibling, i += 1)
10735         {
10736           if (index_ == i)
10737             {
10738               ClutterActor *tmp = iter->priv->prev_sibling;
10739
10740               child->priv->prev_sibling = tmp;
10741               child->priv->next_sibling = iter;
10742
10743               iter->priv->prev_sibling = child;
10744
10745               if (tmp != NULL)
10746                 tmp->priv->next_sibling = child;
10747
10748               break;
10749             }
10750         }
10751     }
10752
10753   if (child->priv->prev_sibling == NULL)
10754     self->priv->first_child = child;
10755
10756   if (child->priv->next_sibling == NULL)
10757     self->priv->last_child = child;
10758 }
10759
10760 static void
10761 insert_child_above (ClutterActor *self,
10762                     ClutterActor *child,
10763                     gpointer      data)
10764 {
10765   ClutterActor *sibling = data;
10766
10767   child->priv->parent = self;
10768
10769   if (sibling == NULL)
10770     sibling = self->priv->last_child;
10771
10772   child->priv->prev_sibling = sibling;
10773
10774   if (sibling != NULL)
10775     {
10776       ClutterActor *tmp = sibling->priv->next_sibling;
10777
10778       child->priv->next_sibling = tmp;
10779
10780       if (tmp != NULL)
10781         tmp->priv->prev_sibling = child;
10782
10783       sibling->priv->next_sibling = child;
10784     }
10785   else
10786     child->priv->next_sibling = NULL;
10787
10788   if (child->priv->prev_sibling == NULL)
10789     self->priv->first_child = child;
10790
10791   if (child->priv->next_sibling == NULL)
10792     self->priv->last_child = child;
10793 }
10794
10795 static void
10796 insert_child_below (ClutterActor *self,
10797                     ClutterActor *child,
10798                     gpointer      data)
10799 {
10800   ClutterActor *sibling = data;
10801
10802   child->priv->parent = self;
10803
10804   if (sibling == NULL)
10805     sibling = self->priv->first_child;
10806
10807   child->priv->next_sibling = sibling;
10808
10809   if (sibling != NULL)
10810     {
10811       ClutterActor *tmp = sibling->priv->prev_sibling;
10812
10813       child->priv->prev_sibling = tmp;
10814
10815       if (tmp != NULL)
10816         tmp->priv->next_sibling = child;
10817
10818       sibling->priv->prev_sibling = child;
10819     }
10820   else
10821     child->priv->prev_sibling = NULL;
10822
10823   if (child->priv->prev_sibling == NULL)
10824     self->priv->first_child = child;
10825
10826   if (child->priv->next_sibling == NULL)
10827     self->priv->last_child = child;
10828 }
10829
10830 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10831                                            ClutterActor *child,
10832                                            gpointer      data);
10833
10834 typedef enum {
10835   ADD_CHILD_CREATE_META       = 1 << 0,
10836   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10837   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10838   ADD_CHILD_CHECK_STATE       = 1 << 3,
10839   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10840
10841   /* default flags for public API */
10842   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10843                                ADD_CHILD_EMIT_PARENT_SET |
10844                                ADD_CHILD_EMIT_ACTOR_ADDED |
10845                                ADD_CHILD_CHECK_STATE |
10846                                ADD_CHILD_NOTIFY_FIRST_LAST,
10847
10848   /* flags for legacy/deprecated API */
10849   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10850                                ADD_CHILD_CHECK_STATE |
10851                                ADD_CHILD_NOTIFY_FIRST_LAST
10852 } ClutterActorAddChildFlags;
10853
10854 /*< private >
10855  * clutter_actor_add_child_internal:
10856  * @self: a #ClutterActor
10857  * @child: a #ClutterActor
10858  * @flags: control flags for actions
10859  * @add_func: delegate function
10860  * @data: (closure): data to pass to @add_func
10861  *
10862  * Adds @child to the list of children of @self.
10863  *
10864  * The actual insertion inside the list is delegated to @add_func: this
10865  * function will just set up the state, perform basic checks, and emit
10866  * signals.
10867  *
10868  * The @flags argument is used to perform additional operations.
10869  */
10870 static inline void
10871 clutter_actor_add_child_internal (ClutterActor              *self,
10872                                   ClutterActor              *child,
10873                                   ClutterActorAddChildFlags  flags,
10874                                   ClutterActorAddChildFunc   add_func,
10875                                   gpointer                   data)
10876 {
10877   ClutterTextDirection text_dir;
10878   gboolean create_meta;
10879   gboolean emit_parent_set, emit_actor_added;
10880   gboolean check_state;
10881   gboolean notify_first_last;
10882   ClutterActor *old_first_child, *old_last_child;
10883
10884   if (child->priv->parent != NULL)
10885     {
10886       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10887                  "use clutter_actor_remove_child() first.",
10888                  _clutter_actor_get_debug_name (child),
10889                  _clutter_actor_get_debug_name (child->priv->parent));
10890       return;
10891     }
10892
10893   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10894     {
10895       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10896                  "a child of another actor.",
10897                  _clutter_actor_get_debug_name (child));
10898       return;
10899     }
10900
10901 #if 0
10902   /* XXX - this check disallows calling methods that change the stacking
10903    * order within the destruction sequence, by triggering a critical
10904    * warning first, and leaving the actor in an undefined state, which
10905    * then ends up being caught by an assertion.
10906    *
10907    * the reproducible sequence is:
10908    *
10909    *   - actor gets destroyed;
10910    *   - another actor, linked to the first, will try to change the
10911    *     stacking order of the first actor;
10912    *   - changing the stacking order is a composite operation composed
10913    *     by the following steps:
10914    *     1. ref() the child;
10915    *     2. remove_child_internal(), which removes the reference;
10916    *     3. add_child_internal(), which adds a reference;
10917    *   - the state of the actor is not changed between (2) and (3), as
10918    *     it could be an expensive recomputation;
10919    *   - if (3) bails out, then the actor is in an undefined state, but
10920    *     still alive;
10921    *   - the destruction sequence terminates, but the actor is unparented
10922    *     while its state indicates being parented instead.
10923    *   - assertion failure.
10924    *
10925    * the obvious fix would be to decompose each set_child_*_sibling()
10926    * method into proper remove_child()/add_child(), with state validation;
10927    * this may cause excessive work, though, and trigger a cascade of other
10928    * bugs in code that assumes that a change in the stacking order is an
10929    * atomic operation.
10930    *
10931    * another potential fix is to just remove this check here, and let
10932    * code doing stacking order changes inside the destruction sequence
10933    * of an actor continue doing the work.
10934    *
10935    * the third fix is to silently bail out early from every
10936    * set_child_*_sibling() and set_child_at_index() method, and avoid
10937    * doing work.
10938    *
10939    * I have a preference for the second solution, since it involves the
10940    * least amount of work, and the least amount of code duplication.
10941    *
10942    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10943    */
10944   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10945     {
10946       g_warning ("The actor '%s' is currently being destroyed, and "
10947                  "cannot be added as a child of another actor.",
10948                  _clutter_actor_get_debug_name (child));
10949       return;
10950     }
10951 #endif
10952
10953   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10954   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10955   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10956   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10957   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10958
10959   old_first_child = self->priv->first_child;
10960   old_last_child = self->priv->last_child;
10961
10962   g_object_freeze_notify (G_OBJECT (self));
10963
10964   if (create_meta)
10965     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10966
10967   g_object_ref_sink (child);
10968   child->priv->parent = NULL;
10969   child->priv->next_sibling = NULL;
10970   child->priv->prev_sibling = NULL;
10971
10972   /* delegate the actual insertion */
10973   add_func (self, child, data);
10974
10975   g_assert (child->priv->parent == self);
10976
10977   self->priv->n_children += 1;
10978
10979   self->priv->age += 1;
10980
10981   /* if push_internal() has been called then we automatically set
10982    * the flag on the actor
10983    */
10984   if (self->priv->internal_child)
10985     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10986
10987   /* clutter_actor_reparent() will emit ::parent-set for us */
10988   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10989     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10990
10991   if (check_state)
10992     {
10993       /* If parent is mapped or realized, we need to also be mapped or
10994        * realized once we're inside the parent.
10995        */
10996       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10997
10998       /* propagate the parent's text direction to the child */
10999       text_dir = clutter_actor_get_text_direction (self);
11000       clutter_actor_set_text_direction (child, text_dir);
11001     }
11002
11003   if (child->priv->show_on_set_parent)
11004     clutter_actor_show (child);
11005
11006   if (CLUTTER_ACTOR_IS_MAPPED (child))
11007     clutter_actor_queue_redraw (child);
11008
11009   /* maintain the invariant that if an actor needs layout,
11010    * its parents do as well
11011    */
11012   if (child->priv->needs_width_request ||
11013       child->priv->needs_height_request ||
11014       child->priv->needs_allocation)
11015     {
11016       /* we work around the short-circuiting we do
11017        * in clutter_actor_queue_relayout() since we
11018        * want to force a relayout
11019        */
11020       child->priv->needs_width_request = TRUE;
11021       child->priv->needs_height_request = TRUE;
11022       child->priv->needs_allocation = TRUE;
11023
11024       clutter_actor_queue_relayout (child->priv->parent);
11025     }
11026
11027   if (emit_actor_added)
11028     g_signal_emit_by_name (self, "actor-added", child);
11029
11030   if (notify_first_last)
11031     {
11032       if (old_first_child != self->priv->first_child)
11033         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11034
11035       if (old_last_child != self->priv->last_child)
11036         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11037     }
11038
11039   g_object_thaw_notify (G_OBJECT (self));
11040 }
11041
11042 /**
11043  * clutter_actor_add_child:
11044  * @self: a #ClutterActor
11045  * @child: a #ClutterActor
11046  *
11047  * Adds @child to the children of @self.
11048  *
11049  * This function will acquire a reference on @child that will only
11050  * be released when calling clutter_actor_remove_child().
11051  *
11052  * This function will take into consideration the #ClutterActor:depth
11053  * of @child, and will keep the list of children sorted.
11054  *
11055  * This function will emit the #ClutterContainer::actor-added signal
11056  * on @self.
11057  *
11058  * Since: 1.10
11059  */
11060 void
11061 clutter_actor_add_child (ClutterActor *self,
11062                          ClutterActor *child)
11063 {
11064   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11065   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11066   g_return_if_fail (self != child);
11067   g_return_if_fail (child->priv->parent == NULL);
11068
11069   clutter_actor_add_child_internal (self, child,
11070                                     ADD_CHILD_DEFAULT_FLAGS,
11071                                     insert_child_at_depth,
11072                                     NULL);
11073 }
11074
11075 /**
11076  * clutter_actor_insert_child_at_index:
11077  * @self: a #ClutterActor
11078  * @child: a #ClutterActor
11079  * @index_: the index
11080  *
11081  * Inserts @child into the list of children of @self, using the
11082  * given @index_. If @index_ is greater than the number of children
11083  * in @self, or is less than 0, then the new child is added at the end.
11084  *
11085  * This function will acquire a reference on @child that will only
11086  * be released when calling clutter_actor_remove_child().
11087  *
11088  * This function will not take into consideration the #ClutterActor:depth
11089  * of @child.
11090  *
11091  * This function will emit the #ClutterContainer::actor-added signal
11092  * on @self.
11093  *
11094  * Since: 1.10
11095  */
11096 void
11097 clutter_actor_insert_child_at_index (ClutterActor *self,
11098                                      ClutterActor *child,
11099                                      gint          index_)
11100 {
11101   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11102   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11103   g_return_if_fail (self != child);
11104   g_return_if_fail (child->priv->parent == NULL);
11105
11106   clutter_actor_add_child_internal (self, child,
11107                                     ADD_CHILD_DEFAULT_FLAGS,
11108                                     insert_child_at_index,
11109                                     GINT_TO_POINTER (index_));
11110 }
11111
11112 /**
11113  * clutter_actor_insert_child_above:
11114  * @self: a #ClutterActor
11115  * @child: a #ClutterActor
11116  * @sibling: (allow-none): a child of @self, or %NULL
11117  *
11118  * Inserts @child into the list of children of @self, above another
11119  * child of @self or, if @sibling is %NULL, above all the children
11120  * of @self.
11121  *
11122  * This function will acquire a reference on @child that will only
11123  * be released when calling clutter_actor_remove_child().
11124  *
11125  * This function will not take into consideration the #ClutterActor:depth
11126  * of @child.
11127  *
11128  * This function will emit the #ClutterContainer::actor-added signal
11129  * on @self.
11130  *
11131  * Since: 1.10
11132  */
11133 void
11134 clutter_actor_insert_child_above (ClutterActor *self,
11135                                   ClutterActor *child,
11136                                   ClutterActor *sibling)
11137 {
11138   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11139   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11140   g_return_if_fail (self != child);
11141   g_return_if_fail (child != sibling);
11142   g_return_if_fail (child->priv->parent == NULL);
11143   g_return_if_fail (sibling == NULL ||
11144                     (CLUTTER_IS_ACTOR (sibling) &&
11145                      sibling->priv->parent == self));
11146
11147   clutter_actor_add_child_internal (self, child,
11148                                     ADD_CHILD_DEFAULT_FLAGS,
11149                                     insert_child_above,
11150                                     sibling);
11151 }
11152
11153 /**
11154  * clutter_actor_insert_child_below:
11155  * @self: a #ClutterActor
11156  * @child: a #ClutterActor
11157  * @sibling: (allow-none): a child of @self, or %NULL
11158  *
11159  * Inserts @child into the list of children of @self, below another
11160  * child of @self or, if @sibling is %NULL, below all the children
11161  * of @self.
11162  *
11163  * This function will acquire a reference on @child that will only
11164  * be released when calling clutter_actor_remove_child().
11165  *
11166  * This function will not take into consideration the #ClutterActor:depth
11167  * of @child.
11168  *
11169  * This function will emit the #ClutterContainer::actor-added signal
11170  * on @self.
11171  *
11172  * Since: 1.10
11173  */
11174 void
11175 clutter_actor_insert_child_below (ClutterActor *self,
11176                                   ClutterActor *child,
11177                                   ClutterActor *sibling)
11178 {
11179   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11180   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11181   g_return_if_fail (self != child);
11182   g_return_if_fail (child != sibling);
11183   g_return_if_fail (child->priv->parent == NULL);
11184   g_return_if_fail (sibling == NULL ||
11185                     (CLUTTER_IS_ACTOR (sibling) &&
11186                      sibling->priv->parent == self));
11187
11188   clutter_actor_add_child_internal (self, child,
11189                                     ADD_CHILD_DEFAULT_FLAGS,
11190                                     insert_child_below,
11191                                     sibling);
11192 }
11193
11194 /**
11195  * clutter_actor_set_parent:
11196  * @self: A #ClutterActor
11197  * @parent: A new #ClutterActor parent
11198  *
11199  * Sets the parent of @self to @parent.
11200  *
11201  * This function will result in @parent acquiring a reference on @self,
11202  * eventually by sinking its floating reference first. The reference
11203  * will be released by clutter_actor_unparent().
11204  *
11205  * This function should only be called by legacy #ClutterActor<!-- -->s
11206  * implementing the #ClutterContainer interface.
11207  *
11208  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11209  */
11210 void
11211 clutter_actor_set_parent (ClutterActor *self,
11212                           ClutterActor *parent)
11213 {
11214   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11215   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11216   g_return_if_fail (self != parent);
11217   g_return_if_fail (self->priv->parent == NULL);
11218
11219   /* as this function will be called inside ClutterContainer::add
11220    * implementations or when building up a composite actor, we have
11221    * to preserve the old behaviour, and not create child meta or
11222    * emit the ::actor-added signal, to avoid recursion or double
11223    * emissions
11224    */
11225   clutter_actor_add_child_internal (parent, self,
11226                                     ADD_CHILD_LEGACY_FLAGS,
11227                                     insert_child_at_depth,
11228                                     NULL);
11229 }
11230
11231 /**
11232  * clutter_actor_get_parent:
11233  * @self: A #ClutterActor
11234  *
11235  * Retrieves the parent of @self.
11236  *
11237  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11238  *  if no parent is set
11239  */
11240 ClutterActor *
11241 clutter_actor_get_parent (ClutterActor *self)
11242 {
11243   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11244
11245   return self->priv->parent;
11246 }
11247
11248 /**
11249  * clutter_actor_get_paint_visibility:
11250  * @self: A #ClutterActor
11251  *
11252  * Retrieves the 'paint' visibility of an actor recursively checking for non
11253  * visible parents.
11254  *
11255  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11256  *
11257  * Return Value: %TRUE if the actor is visibile and will be painted.
11258  *
11259  * Since: 0.8.4
11260  */
11261 gboolean
11262 clutter_actor_get_paint_visibility (ClutterActor *actor)
11263 {
11264   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11265
11266   return CLUTTER_ACTOR_IS_MAPPED (actor);
11267 }
11268
11269 /**
11270  * clutter_actor_remove_child:
11271  * @self: a #ClutterActor
11272  * @child: a #ClutterActor
11273  *
11274  * Removes @child from the children of @self.
11275  *
11276  * This function will release the reference added by
11277  * clutter_actor_add_child(), so if you want to keep using @child
11278  * you will have to acquire a referenced on it before calling this
11279  * function.
11280  *
11281  * This function will emit the #ClutterContainer::actor-removed
11282  * signal on @self.
11283  *
11284  * Since: 1.10
11285  */
11286 void
11287 clutter_actor_remove_child (ClutterActor *self,
11288                             ClutterActor *child)
11289 {
11290   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11291   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11292   g_return_if_fail (self != child);
11293   g_return_if_fail (child->priv->parent != NULL);
11294   g_return_if_fail (child->priv->parent == self);
11295
11296   clutter_actor_remove_child_internal (self, child,
11297                                        REMOVE_CHILD_DEFAULT_FLAGS);
11298 }
11299
11300 /**
11301  * clutter_actor_remove_all_children:
11302  * @self: a #ClutterActor
11303  *
11304  * Removes all children of @self.
11305  *
11306  * This function releases the reference added by inserting a child actor
11307  * in the list of children of @self.
11308  *
11309  * If the reference count of a child drops to zero, the child will be
11310  * destroyed. If you want to ensure the destruction of all the children
11311  * of @self, use clutter_actor_destroy_all_children().
11312  *
11313  * Since: 1.10
11314  */
11315 void
11316 clutter_actor_remove_all_children (ClutterActor *self)
11317 {
11318   ClutterActorIter iter;
11319
11320   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11321
11322   if (self->priv->n_children == 0)
11323     return;
11324
11325   g_object_freeze_notify (G_OBJECT (self));
11326
11327   clutter_actor_iter_init (&iter, self);
11328   while (clutter_actor_iter_next (&iter, NULL))
11329     clutter_actor_iter_remove (&iter);
11330
11331   g_object_thaw_notify (G_OBJECT (self));
11332
11333   /* sanity check */
11334   g_assert (self->priv->first_child == NULL);
11335   g_assert (self->priv->last_child == NULL);
11336   g_assert (self->priv->n_children == 0);
11337 }
11338
11339 /**
11340  * clutter_actor_destroy_all_children:
11341  * @self: a #ClutterActor
11342  *
11343  * Destroys all children of @self.
11344  *
11345  * This function releases the reference added by inserting a child
11346  * actor in the list of children of @self, and ensures that the
11347  * #ClutterActor::destroy signal is emitted on each child of the
11348  * actor.
11349  *
11350  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11351  * when its reference count drops to 0; the default handler of the
11352  * #ClutterActor::destroy signal will destroy all the children of an
11353  * actor. This function ensures that all children are destroyed, instead
11354  * of just removed from @self, unlike clutter_actor_remove_all_children()
11355  * which will merely release the reference and remove each child.
11356  *
11357  * Unless you acquired an additional reference on each child of @self
11358  * prior to calling clutter_actor_remove_all_children() and want to reuse
11359  * the actors, you should use clutter_actor_destroy_all_children() in
11360  * order to make sure that children are destroyed and signal handlers
11361  * are disconnected even in cases where circular references prevent this
11362  * from automatically happening through reference counting alone.
11363  *
11364  * Since: 1.10
11365  */
11366 void
11367 clutter_actor_destroy_all_children (ClutterActor *self)
11368 {
11369   ClutterActorIter iter;
11370
11371   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11372
11373   if (self->priv->n_children == 0)
11374     return;
11375
11376   g_object_freeze_notify (G_OBJECT (self));
11377
11378   clutter_actor_iter_init (&iter, self);
11379   while (clutter_actor_iter_next (&iter, NULL))
11380     clutter_actor_iter_destroy (&iter);
11381
11382   g_object_thaw_notify (G_OBJECT (self));
11383
11384   /* sanity check */
11385   g_assert (self->priv->first_child == NULL);
11386   g_assert (self->priv->last_child == NULL);
11387   g_assert (self->priv->n_children == 0);
11388 }
11389
11390 typedef struct _InsertBetweenData {
11391   ClutterActor *prev_sibling;
11392   ClutterActor *next_sibling;
11393 } InsertBetweenData;
11394
11395 static void
11396 insert_child_between (ClutterActor *self,
11397                       ClutterActor *child,
11398                       gpointer      data_)
11399 {
11400   InsertBetweenData *data = data_;
11401   ClutterActor *prev_sibling = data->prev_sibling;
11402   ClutterActor *next_sibling = data->next_sibling;
11403
11404   child->priv->parent = self;
11405   child->priv->prev_sibling = prev_sibling;
11406   child->priv->next_sibling = next_sibling;
11407
11408   if (prev_sibling != NULL)
11409     prev_sibling->priv->next_sibling = child;
11410
11411   if (next_sibling != NULL)
11412     next_sibling->priv->prev_sibling = child;
11413
11414   if (child->priv->prev_sibling == NULL)
11415     self->priv->first_child = child;
11416
11417   if (child->priv->next_sibling == NULL)
11418     self->priv->last_child = child;
11419 }
11420
11421 /**
11422  * clutter_actor_replace_child:
11423  * @self: a #ClutterActor
11424  * @old_child: the child of @self to replace
11425  * @new_child: the #ClutterActor to replace @old_child
11426  *
11427  * Replaces @old_child with @new_child in the list of children of @self.
11428  *
11429  * Since: 1.10
11430  */
11431 void
11432 clutter_actor_replace_child (ClutterActor *self,
11433                              ClutterActor *old_child,
11434                              ClutterActor *new_child)
11435 {
11436   ClutterActor *prev_sibling, *next_sibling;
11437   InsertBetweenData clos;
11438
11439   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11440   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11441   g_return_if_fail (old_child->priv->parent == self);
11442   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11443   g_return_if_fail (old_child != new_child);
11444   g_return_if_fail (new_child != self);
11445   g_return_if_fail (new_child->priv->parent == NULL);
11446
11447   prev_sibling = old_child->priv->prev_sibling;
11448   next_sibling = old_child->priv->next_sibling;
11449   clutter_actor_remove_child_internal (self, old_child,
11450                                        REMOVE_CHILD_DEFAULT_FLAGS);
11451
11452   clos.prev_sibling = prev_sibling;
11453   clos.next_sibling = next_sibling;
11454   clutter_actor_add_child_internal (self, new_child,
11455                                     ADD_CHILD_DEFAULT_FLAGS,
11456                                     insert_child_between,
11457                                     &clos);
11458 }
11459
11460 /**
11461  * clutter_actor_unparent:
11462  * @self: a #ClutterActor
11463  *
11464  * Removes the parent of @self.
11465  *
11466  * This will cause the parent of @self to release the reference
11467  * acquired when calling clutter_actor_set_parent(), so if you
11468  * want to keep @self you will have to acquire a reference of
11469  * your own, through g_object_ref().
11470  *
11471  * This function should only be called by legacy #ClutterActor<!-- -->s
11472  * implementing the #ClutterContainer interface.
11473  *
11474  * Since: 0.1.1
11475  *
11476  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11477  */
11478 void
11479 clutter_actor_unparent (ClutterActor *self)
11480 {
11481   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11482
11483   if (self->priv->parent == NULL)
11484     return;
11485
11486   clutter_actor_remove_child_internal (self->priv->parent, self,
11487                                        REMOVE_CHILD_LEGACY_FLAGS);
11488 }
11489
11490 /**
11491  * clutter_actor_reparent:
11492  * @self: a #ClutterActor
11493  * @new_parent: the new #ClutterActor parent
11494  *
11495  * Resets the parent actor of @self.
11496  *
11497  * This function is logically equivalent to calling clutter_actor_unparent()
11498  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11499  * ensures the child is not finalized when unparented, and emits the
11500  * #ClutterActor::parent-set signal only once.
11501  *
11502  * In reality, calling this function is less useful than it sounds, as some
11503  * application code may rely on changes in the intermediate state between
11504  * removal and addition of the actor from its old parent to the @new_parent.
11505  * Thus, it is strongly encouraged to avoid using this function in application
11506  * code.
11507  *
11508  * Since: 0.2
11509  *
11510  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11511  *   clutter_actor_add_child() instead; remember to take a reference on
11512  *   the actor being removed before calling clutter_actor_remove_child()
11513  *   to avoid the reference count dropping to zero and the actor being
11514  *   destroyed.
11515  */
11516 void
11517 clutter_actor_reparent (ClutterActor *self,
11518                         ClutterActor *new_parent)
11519 {
11520   ClutterActorPrivate *priv;
11521
11522   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11523   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11524   g_return_if_fail (self != new_parent);
11525
11526   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11527     {
11528       g_warning ("Cannot set a parent on a toplevel actor");
11529       return;
11530     }
11531
11532   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11533     {
11534       g_warning ("Cannot set a parent currently being destroyed");
11535       return;
11536     }
11537
11538   priv = self->priv;
11539
11540   if (priv->parent != new_parent)
11541     {
11542       ClutterActor *old_parent;
11543
11544       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11545
11546       old_parent = priv->parent;
11547
11548       g_object_ref (self);
11549
11550       if (old_parent != NULL)
11551         {
11552          /* go through the Container implementation if this is a regular
11553           * child and not an internal one
11554           */
11555          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11556            {
11557              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11558
11559              /* this will have to call unparent() */
11560              clutter_container_remove_actor (parent, self);
11561            }
11562          else
11563            clutter_actor_remove_child_internal (old_parent, self,
11564                                                 REMOVE_CHILD_LEGACY_FLAGS);
11565         }
11566
11567       /* Note, will call set_parent() */
11568       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11569         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11570       else
11571         clutter_actor_add_child_internal (new_parent, self,
11572                                           ADD_CHILD_LEGACY_FLAGS,
11573                                           insert_child_at_depth,
11574                                           NULL);
11575
11576       /* we emit the ::parent-set signal once */
11577       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11578
11579       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11580
11581       /* the IN_REPARENT flag suspends state updates */
11582       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11583
11584       g_object_unref (self);
11585    }
11586 }
11587
11588 /**
11589  * clutter_actor_contains:
11590  * @self: A #ClutterActor
11591  * @descendant: A #ClutterActor, possibly contained in @self
11592  *
11593  * Determines if @descendant is contained inside @self (either as an
11594  * immediate child, or as a deeper descendant). If @self and
11595  * @descendant point to the same actor then it will also return %TRUE.
11596  *
11597  * Return value: whether @descendent is contained within @self
11598  *
11599  * Since: 1.4
11600  */
11601 gboolean
11602 clutter_actor_contains (ClutterActor *self,
11603                         ClutterActor *descendant)
11604 {
11605   ClutterActor *actor;
11606
11607   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11608   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11609
11610   for (actor = descendant; actor; actor = actor->priv->parent)
11611     if (actor == self)
11612       return TRUE;
11613
11614   return FALSE;
11615 }
11616
11617 /**
11618  * clutter_actor_set_child_above_sibling:
11619  * @self: a #ClutterActor
11620  * @child: a #ClutterActor child of @self
11621  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11622  *
11623  * Sets @child to be above @sibling in the list of children of @self.
11624  *
11625  * If @sibling is %NULL, @child will be the new last child of @self.
11626  *
11627  * This function is logically equivalent to removing @child and using
11628  * clutter_actor_insert_child_above(), but it will not emit signals
11629  * or change state on @child.
11630  *
11631  * Since: 1.10
11632  */
11633 void
11634 clutter_actor_set_child_above_sibling (ClutterActor *self,
11635                                        ClutterActor *child,
11636                                        ClutterActor *sibling)
11637 {
11638   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11639   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11640   g_return_if_fail (child->priv->parent == self);
11641   g_return_if_fail (child != sibling);
11642   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11643
11644   if (sibling != NULL)
11645     g_return_if_fail (sibling->priv->parent == self);
11646
11647   /* we don't want to change the state of child, or emit signals, or
11648    * regenerate ChildMeta instances here, but we still want to follow
11649    * the correct sequence of steps encoded in remove_child() and
11650    * add_child(), so that correctness is ensured, and we only go
11651    * through one known code path.
11652    */
11653   g_object_ref (child);
11654   clutter_actor_remove_child_internal (self, child, 0);
11655   clutter_actor_add_child_internal (self, child,
11656                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11657                                     insert_child_above,
11658                                     sibling);
11659
11660   clutter_actor_queue_relayout (self);
11661 }
11662
11663 /**
11664  * clutter_actor_set_child_below_sibling:
11665  * @self: a #ClutterActor
11666  * @child: a #ClutterActor child of @self
11667  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11668  *
11669  * Sets @child to be below @sibling in the list of children of @self.
11670  *
11671  * If @sibling is %NULL, @child will be the new first child of @self.
11672  *
11673  * This function is logically equivalent to removing @self and using
11674  * clutter_actor_insert_child_below(), but it will not emit signals
11675  * or change state on @child.
11676  *
11677  * Since: 1.10
11678  */
11679 void
11680 clutter_actor_set_child_below_sibling (ClutterActor *self,
11681                                        ClutterActor *child,
11682                                        ClutterActor *sibling)
11683 {
11684   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11685   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11686   g_return_if_fail (child->priv->parent == self);
11687   g_return_if_fail (child != sibling);
11688   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11689
11690   if (sibling != NULL)
11691     g_return_if_fail (sibling->priv->parent == self);
11692
11693   /* see the comment in set_child_above_sibling() */
11694   g_object_ref (child);
11695   clutter_actor_remove_child_internal (self, child, 0);
11696   clutter_actor_add_child_internal (self, child,
11697                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11698                                     insert_child_below,
11699                                     sibling);
11700
11701   clutter_actor_queue_relayout (self);
11702 }
11703
11704 /**
11705  * clutter_actor_set_child_at_index:
11706  * @self: a #ClutterActor
11707  * @child: a #ClutterActor child of @self
11708  * @index_: the new index for @child
11709  *
11710  * Changes the index of @child in the list of children of @self.
11711  *
11712  * This function is logically equivalent to removing @child and
11713  * calling clutter_actor_insert_child_at_index(), but it will not
11714  * emit signals or change state on @child.
11715  *
11716  * Since: 1.10
11717  */
11718 void
11719 clutter_actor_set_child_at_index (ClutterActor *self,
11720                                   ClutterActor *child,
11721                                   gint          index_)
11722 {
11723   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11724   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11725   g_return_if_fail (child->priv->parent == self);
11726   g_return_if_fail (index_ <= self->priv->n_children);
11727
11728   g_object_ref (child);
11729   clutter_actor_remove_child_internal (self, child, 0);
11730   clutter_actor_add_child_internal (self, child,
11731                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11732                                     insert_child_at_index,
11733                                     GINT_TO_POINTER (index_));
11734
11735   clutter_actor_queue_relayout (self);
11736 }
11737
11738 /**
11739  * clutter_actor_raise:
11740  * @self: A #ClutterActor
11741  * @below: (allow-none): A #ClutterActor to raise above.
11742  *
11743  * Puts @self above @below.
11744  *
11745  * Both actors must have the same parent, and the parent must implement
11746  * the #ClutterContainer interface
11747  *
11748  * This function calls clutter_container_raise_child() internally.
11749  *
11750  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11751  */
11752 void
11753 clutter_actor_raise (ClutterActor *self,
11754                      ClutterActor *below)
11755 {
11756   ClutterActor *parent;
11757
11758   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11759
11760   parent = clutter_actor_get_parent (self);
11761   if (parent == NULL)
11762     {
11763       g_warning ("%s: Actor '%s' is not inside a container",
11764                  G_STRFUNC,
11765                  _clutter_actor_get_debug_name (self));
11766       return;
11767     }
11768
11769   if (below != NULL)
11770     {
11771       if (parent != clutter_actor_get_parent (below))
11772         {
11773           g_warning ("%s Actor '%s' is not in the same container as "
11774                      "actor '%s'",
11775                      G_STRFUNC,
11776                      _clutter_actor_get_debug_name (self),
11777                      _clutter_actor_get_debug_name (below));
11778           return;
11779         }
11780     }
11781
11782   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11783 }
11784
11785 /**
11786  * clutter_actor_lower:
11787  * @self: A #ClutterActor
11788  * @above: (allow-none): A #ClutterActor to lower below
11789  *
11790  * Puts @self below @above.
11791  *
11792  * Both actors must have the same parent, and the parent must implement
11793  * the #ClutterContainer interface.
11794  *
11795  * This function calls clutter_container_lower_child() internally.
11796  *
11797  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11798  */
11799 void
11800 clutter_actor_lower (ClutterActor *self,
11801                      ClutterActor *above)
11802 {
11803   ClutterActor *parent;
11804
11805   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11806
11807   parent = clutter_actor_get_parent (self);
11808   if (parent == NULL)
11809     {
11810       g_warning ("%s: Actor of type %s is not inside a container",
11811                  G_STRFUNC,
11812                  _clutter_actor_get_debug_name (self));
11813       return;
11814     }
11815
11816   if (above)
11817     {
11818       if (parent != clutter_actor_get_parent (above))
11819         {
11820           g_warning ("%s: Actor '%s' is not in the same container as "
11821                      "actor '%s'",
11822                      G_STRFUNC,
11823                      _clutter_actor_get_debug_name (self),
11824                      _clutter_actor_get_debug_name (above));
11825           return;
11826         }
11827     }
11828
11829   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11830 }
11831
11832 /**
11833  * clutter_actor_raise_top:
11834  * @self: A #ClutterActor
11835  *
11836  * Raises @self to the top.
11837  *
11838  * This function calls clutter_actor_raise() internally.
11839  *
11840  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11841  *   a %NULL sibling, instead.
11842  */
11843 void
11844 clutter_actor_raise_top (ClutterActor *self)
11845 {
11846   clutter_actor_raise (self, NULL);
11847 }
11848
11849 /**
11850  * clutter_actor_lower_bottom:
11851  * @self: A #ClutterActor
11852  *
11853  * Lowers @self to the bottom.
11854  *
11855  * This function calls clutter_actor_lower() internally.
11856  *
11857  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11858  *   a %NULL sibling, instead.
11859  */
11860 void
11861 clutter_actor_lower_bottom (ClutterActor *self)
11862 {
11863   clutter_actor_lower (self, NULL);
11864 }
11865
11866 /*
11867  * Event handling
11868  */
11869
11870 /**
11871  * clutter_actor_event:
11872  * @actor: a #ClutterActor
11873  * @event: a #ClutterEvent
11874  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11875  *
11876  * This function is used to emit an event on the main stage.
11877  * You should rarely need to use this function, except for
11878  * synthetising events.
11879  *
11880  * Return value: the return value from the signal emission: %TRUE
11881  *   if the actor handled the event, or %FALSE if the event was
11882  *   not handled
11883  *
11884  * Since: 0.6
11885  */
11886 gboolean
11887 clutter_actor_event (ClutterActor *actor,
11888                      ClutterEvent *event,
11889                      gboolean      capture)
11890 {
11891   gboolean retval = FALSE;
11892   gint signal_num = -1;
11893
11894   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11895   g_return_val_if_fail (event != NULL, FALSE);
11896
11897   g_object_ref (actor);
11898
11899   if (capture)
11900     {
11901       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11902                      event,
11903                      &retval);
11904       goto out;
11905     }
11906
11907   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11908
11909   if (!retval)
11910     {
11911       switch (event->type)
11912         {
11913         case CLUTTER_NOTHING:
11914           break;
11915         case CLUTTER_BUTTON_PRESS:
11916           signal_num = BUTTON_PRESS_EVENT;
11917           break;
11918         case CLUTTER_BUTTON_RELEASE:
11919           signal_num = BUTTON_RELEASE_EVENT;
11920           break;
11921         case CLUTTER_SCROLL:
11922           signal_num = SCROLL_EVENT;
11923           break;
11924         case CLUTTER_KEY_PRESS:
11925           signal_num = KEY_PRESS_EVENT;
11926           break;
11927         case CLUTTER_KEY_RELEASE:
11928           signal_num = KEY_RELEASE_EVENT;
11929           break;
11930         case CLUTTER_MOTION:
11931           signal_num = MOTION_EVENT;
11932           break;
11933         case CLUTTER_ENTER:
11934           signal_num = ENTER_EVENT;
11935           break;
11936         case CLUTTER_LEAVE:
11937           signal_num = LEAVE_EVENT;
11938           break;
11939         case CLUTTER_DELETE:
11940         case CLUTTER_DESTROY_NOTIFY:
11941         case CLUTTER_CLIENT_MESSAGE:
11942         default:
11943           signal_num = -1;
11944           break;
11945         }
11946
11947       if (signal_num != -1)
11948         g_signal_emit (actor, actor_signals[signal_num], 0,
11949                        event, &retval);
11950     }
11951
11952 out:
11953   g_object_unref (actor);
11954
11955   return retval;
11956 }
11957
11958 /**
11959  * clutter_actor_set_reactive:
11960  * @actor: a #ClutterActor
11961  * @reactive: whether the actor should be reactive to events
11962  *
11963  * Sets @actor as reactive. Reactive actors will receive events.
11964  *
11965  * Since: 0.6
11966  */
11967 void
11968 clutter_actor_set_reactive (ClutterActor *actor,
11969                             gboolean      reactive)
11970 {
11971   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11972
11973   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11974     return;
11975
11976   if (reactive)
11977     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11978   else
11979     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11980
11981   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11982 }
11983
11984 /**
11985  * clutter_actor_get_reactive:
11986  * @actor: a #ClutterActor
11987  *
11988  * Checks whether @actor is marked as reactive.
11989  *
11990  * Return value: %TRUE if the actor is reactive
11991  *
11992  * Since: 0.6
11993  */
11994 gboolean
11995 clutter_actor_get_reactive (ClutterActor *actor)
11996 {
11997   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11998
11999   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12000 }
12001
12002 /**
12003  * clutter_actor_get_anchor_point:
12004  * @self: a #ClutterActor
12005  * @anchor_x: (out): return location for the X coordinate of the anchor point
12006  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12007  *
12008  * Gets the current anchor point of the @actor in pixels.
12009  *
12010  * Since: 0.6
12011  */
12012 void
12013 clutter_actor_get_anchor_point (ClutterActor *self,
12014                                 gfloat       *anchor_x,
12015                                 gfloat       *anchor_y)
12016 {
12017   const ClutterTransformInfo *info;
12018
12019   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12020
12021   info = _clutter_actor_get_transform_info_or_defaults (self);
12022   clutter_anchor_coord_get_units (self, &info->anchor,
12023                                   anchor_x,
12024                                   anchor_y,
12025                                   NULL);
12026 }
12027
12028 /**
12029  * clutter_actor_set_anchor_point:
12030  * @self: a #ClutterActor
12031  * @anchor_x: X coordinate of the anchor point
12032  * @anchor_y: Y coordinate of the anchor point
12033  *
12034  * Sets an anchor point for @self. The anchor point is a point in the
12035  * coordinate space of an actor to which the actor position within its
12036  * parent is relative; the default is (0, 0), i.e. the top-left corner
12037  * of the actor.
12038  *
12039  * Since: 0.6
12040  */
12041 void
12042 clutter_actor_set_anchor_point (ClutterActor *self,
12043                                 gfloat        anchor_x,
12044                                 gfloat        anchor_y)
12045 {
12046   ClutterTransformInfo *info;
12047   ClutterActorPrivate *priv;
12048   gboolean changed = FALSE;
12049   gfloat old_anchor_x, old_anchor_y;
12050   GObject *obj;
12051
12052   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12053
12054   obj = G_OBJECT (self);
12055   priv = self->priv;
12056   info = _clutter_actor_get_transform_info (self);
12057
12058   g_object_freeze_notify (obj);
12059
12060   clutter_anchor_coord_get_units (self, &info->anchor,
12061                                   &old_anchor_x,
12062                                   &old_anchor_y,
12063                                   NULL);
12064
12065   if (info->anchor.is_fractional)
12066     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12067
12068   if (old_anchor_x != anchor_x)
12069     {
12070       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12071       changed = TRUE;
12072     }
12073
12074   if (old_anchor_y != anchor_y)
12075     {
12076       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12077       changed = TRUE;
12078     }
12079
12080   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12081
12082   if (changed)
12083     {
12084       priv->transform_valid = FALSE;
12085       clutter_actor_queue_redraw (self);
12086     }
12087
12088   g_object_thaw_notify (obj);
12089 }
12090
12091 /**
12092  * clutter_actor_get_anchor_point_gravity:
12093  * @self: a #ClutterActor
12094  *
12095  * Retrieves the anchor position expressed as a #ClutterGravity. If
12096  * the anchor point was specified using pixels or units this will
12097  * return %CLUTTER_GRAVITY_NONE.
12098  *
12099  * Return value: the #ClutterGravity used by the anchor point
12100  *
12101  * Since: 1.0
12102  */
12103 ClutterGravity
12104 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12105 {
12106   const ClutterTransformInfo *info;
12107
12108   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12109
12110   info = _clutter_actor_get_transform_info_or_defaults (self);
12111
12112   return clutter_anchor_coord_get_gravity (&info->anchor);
12113 }
12114
12115 /**
12116  * clutter_actor_move_anchor_point:
12117  * @self: a #ClutterActor
12118  * @anchor_x: X coordinate of the anchor point
12119  * @anchor_y: Y coordinate of the anchor point
12120  *
12121  * Sets an anchor point for the actor, and adjusts the actor postion so that
12122  * the relative position of the actor toward its parent remains the same.
12123  *
12124  * Since: 0.6
12125  */
12126 void
12127 clutter_actor_move_anchor_point (ClutterActor *self,
12128                                  gfloat        anchor_x,
12129                                  gfloat        anchor_y)
12130 {
12131   gfloat old_anchor_x, old_anchor_y;
12132   const ClutterTransformInfo *info;
12133
12134   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12135
12136   info = _clutter_actor_get_transform_info (self);
12137   clutter_anchor_coord_get_units (self, &info->anchor,
12138                                   &old_anchor_x,
12139                                   &old_anchor_y,
12140                                   NULL);
12141
12142   g_object_freeze_notify (G_OBJECT (self));
12143
12144   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12145
12146   if (self->priv->position_set)
12147     clutter_actor_move_by (self,
12148                            anchor_x - old_anchor_x,
12149                            anchor_y - old_anchor_y);
12150
12151   g_object_thaw_notify (G_OBJECT (self));
12152 }
12153
12154 /**
12155  * clutter_actor_move_anchor_point_from_gravity:
12156  * @self: a #ClutterActor
12157  * @gravity: #ClutterGravity.
12158  *
12159  * Sets an anchor point on the actor based on the given gravity, adjusting the
12160  * actor postion so that its relative position within its parent remains
12161  * unchanged.
12162  *
12163  * Since version 1.0 the anchor point will be stored as a gravity so
12164  * that if the actor changes size then the anchor point will move. For
12165  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12166  * and later double the size of the actor, the anchor point will move
12167  * to the bottom right.
12168  *
12169  * Since: 0.6
12170  */
12171 void
12172 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12173                                               ClutterGravity  gravity)
12174 {
12175   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12176   const ClutterTransformInfo *info;
12177   ClutterActorPrivate *priv;
12178
12179   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12180
12181   priv = self->priv;
12182   info = _clutter_actor_get_transform_info (self);
12183
12184   g_object_freeze_notify (G_OBJECT (self));
12185
12186   clutter_anchor_coord_get_units (self, &info->anchor,
12187                                   &old_anchor_x,
12188                                   &old_anchor_y,
12189                                   NULL);
12190   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12191   clutter_anchor_coord_get_units (self, &info->anchor,
12192                                   &new_anchor_x,
12193                                   &new_anchor_y,
12194                                   NULL);
12195
12196   if (priv->position_set)
12197     clutter_actor_move_by (self,
12198                            new_anchor_x - old_anchor_x,
12199                            new_anchor_y - old_anchor_y);
12200
12201   g_object_thaw_notify (G_OBJECT (self));
12202 }
12203
12204 /**
12205  * clutter_actor_set_anchor_point_from_gravity:
12206  * @self: a #ClutterActor
12207  * @gravity: #ClutterGravity.
12208  *
12209  * Sets an anchor point on the actor, based on the given gravity (this is a
12210  * convenience function wrapping clutter_actor_set_anchor_point()).
12211  *
12212  * Since version 1.0 the anchor point will be stored as a gravity so
12213  * that if the actor changes size then the anchor point will move. For
12214  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12215  * and later double the size of the actor, the anchor point will move
12216  * to the bottom right.
12217  *
12218  * Since: 0.6
12219  */
12220 void
12221 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12222                                              ClutterGravity  gravity)
12223 {
12224   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12225
12226   if (gravity == CLUTTER_GRAVITY_NONE)
12227     clutter_actor_set_anchor_point (self, 0, 0);
12228   else
12229     {
12230       GObject *obj = G_OBJECT (self);
12231       ClutterTransformInfo *info;
12232
12233       g_object_freeze_notify (obj);
12234
12235       info = _clutter_actor_get_transform_info (self);
12236       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12237
12238       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12239       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12240       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12241
12242       self->priv->transform_valid = FALSE;
12243
12244       clutter_actor_queue_redraw (self);
12245
12246       g_object_thaw_notify (obj);
12247     }
12248 }
12249
12250 static void
12251 clutter_container_iface_init (ClutterContainerIface *iface)
12252 {
12253   /* we don't override anything, as ClutterContainer already has a default
12254    * implementation that we can use, and which calls into our own API.
12255    */
12256 }
12257
12258 typedef enum
12259 {
12260   PARSE_X,
12261   PARSE_Y,
12262   PARSE_WIDTH,
12263   PARSE_HEIGHT,
12264   PARSE_ANCHOR_X,
12265   PARSE_ANCHOR_Y
12266 } ParseDimension;
12267
12268 static gfloat
12269 parse_units (ClutterActor   *self,
12270              ParseDimension  dimension,
12271              JsonNode       *node)
12272 {
12273   GValue value = { 0, };
12274   gfloat retval = 0;
12275
12276   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12277     return 0;
12278
12279   json_node_get_value (node, &value);
12280
12281   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12282     {
12283       retval = (gfloat) g_value_get_int64 (&value);
12284     }
12285   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12286     {
12287       retval = g_value_get_double (&value);
12288     }
12289   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12290     {
12291       ClutterUnits units;
12292       gboolean res;
12293
12294       res = clutter_units_from_string (&units, g_value_get_string (&value));
12295       if (res)
12296         retval = clutter_units_to_pixels (&units);
12297       else
12298         {
12299           g_warning ("Invalid value '%s': integers, strings or floating point "
12300                      "values can be used for the x, y, width and height "
12301                      "properties. Valid modifiers for strings are 'px', 'mm', "
12302                      "'pt' and 'em'.",
12303                      g_value_get_string (&value));
12304           retval = 0;
12305         }
12306     }
12307   else
12308     {
12309       g_warning ("Invalid value of type '%s': integers, strings of floating "
12310                  "point values can be used for the x, y, width, height "
12311                  "anchor-x and anchor-y properties.",
12312                  g_type_name (G_VALUE_TYPE (&value)));
12313     }
12314
12315   g_value_unset (&value);
12316
12317   return retval;
12318 }
12319
12320 typedef struct {
12321   ClutterRotateAxis axis;
12322
12323   gdouble angle;
12324
12325   gfloat center_x;
12326   gfloat center_y;
12327   gfloat center_z;
12328 } RotationInfo;
12329
12330 static inline gboolean
12331 parse_rotation_array (ClutterActor *actor,
12332                       JsonArray    *array,
12333                       RotationInfo *info)
12334 {
12335   JsonNode *element;
12336
12337   if (json_array_get_length (array) != 2)
12338     return FALSE;
12339
12340   /* angle */
12341   element = json_array_get_element (array, 0);
12342   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12343     info->angle = json_node_get_double (element);
12344   else
12345     return FALSE;
12346
12347   /* center */
12348   element = json_array_get_element (array, 1);
12349   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12350     {
12351       JsonArray *center = json_node_get_array (element);
12352
12353       if (json_array_get_length (center) != 2)
12354         return FALSE;
12355
12356       switch (info->axis)
12357         {
12358         case CLUTTER_X_AXIS:
12359           info->center_y = parse_units (actor, PARSE_Y,
12360                                         json_array_get_element (center, 0));
12361           info->center_z = parse_units (actor, PARSE_Y,
12362                                         json_array_get_element (center, 1));
12363           return TRUE;
12364
12365         case CLUTTER_Y_AXIS:
12366           info->center_x = parse_units (actor, PARSE_X,
12367                                         json_array_get_element (center, 0));
12368           info->center_z = parse_units (actor, PARSE_X,
12369                                         json_array_get_element (center, 1));
12370           return TRUE;
12371
12372         case CLUTTER_Z_AXIS:
12373           info->center_x = parse_units (actor, PARSE_X,
12374                                         json_array_get_element (center, 0));
12375           info->center_y = parse_units (actor, PARSE_Y,
12376                                         json_array_get_element (center, 1));
12377           return TRUE;
12378         }
12379     }
12380
12381   return FALSE;
12382 }
12383
12384 static gboolean
12385 parse_rotation (ClutterActor *actor,
12386                 JsonNode     *node,
12387                 RotationInfo *info)
12388 {
12389   JsonArray *array;
12390   guint len, i;
12391   gboolean retval = FALSE;
12392
12393   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12394     {
12395       g_warning ("Invalid node of type '%s' found, expecting an array",
12396                  json_node_type_name (node));
12397       return FALSE;
12398     }
12399
12400   array = json_node_get_array (node);
12401   len = json_array_get_length (array);
12402
12403   for (i = 0; i < len; i++)
12404     {
12405       JsonNode *element = json_array_get_element (array, i);
12406       JsonObject *object;
12407       JsonNode *member;
12408
12409       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12410         {
12411           g_warning ("Invalid node of type '%s' found, expecting an object",
12412                      json_node_type_name (element));
12413           return FALSE;
12414         }
12415
12416       object = json_node_get_object (element);
12417
12418       if (json_object_has_member (object, "x-axis"))
12419         {
12420           member = json_object_get_member (object, "x-axis");
12421
12422           info->axis = CLUTTER_X_AXIS;
12423
12424           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12425             {
12426               info->angle = json_node_get_double (member);
12427               retval = TRUE;
12428             }
12429           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12430             retval = parse_rotation_array (actor,
12431                                            json_node_get_array (member),
12432                                            info);
12433           else
12434             retval = FALSE;
12435         }
12436       else if (json_object_has_member (object, "y-axis"))
12437         {
12438           member = json_object_get_member (object, "y-axis");
12439
12440           info->axis = CLUTTER_Y_AXIS;
12441
12442           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12443             {
12444               info->angle = json_node_get_double (member);
12445               retval = TRUE;
12446             }
12447           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12448             retval = parse_rotation_array (actor,
12449                                            json_node_get_array (member),
12450                                            info);
12451           else
12452             retval = FALSE;
12453         }
12454       else if (json_object_has_member (object, "z-axis"))
12455         {
12456           member = json_object_get_member (object, "z-axis");
12457
12458           info->axis = CLUTTER_Z_AXIS;
12459
12460           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12461             {
12462               info->angle = json_node_get_double (member);
12463               retval = TRUE;
12464             }
12465           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12466             retval = parse_rotation_array (actor,
12467                                            json_node_get_array (member),
12468                                            info);
12469           else
12470             retval = FALSE;
12471         }
12472     }
12473
12474   return retval;
12475 }
12476
12477 static GSList *
12478 parse_actor_metas (ClutterScript *script,
12479                    ClutterActor  *actor,
12480                    JsonNode      *node)
12481 {
12482   GList *elements, *l;
12483   GSList *retval = NULL;
12484
12485   if (!JSON_NODE_HOLDS_ARRAY (node))
12486     return NULL;
12487
12488   elements = json_array_get_elements (json_node_get_array (node));
12489
12490   for (l = elements; l != NULL; l = l->next)
12491     {
12492       JsonNode *element = l->data;
12493       const gchar *id_ = _clutter_script_get_id_from_node (element);
12494       GObject *meta;
12495
12496       if (id_ == NULL || *id_ == '\0')
12497         continue;
12498
12499       meta = clutter_script_get_object (script, id_);
12500       if (meta == NULL)
12501         continue;
12502
12503       retval = g_slist_prepend (retval, meta);
12504     }
12505
12506   g_list_free (elements);
12507
12508   return g_slist_reverse (retval);
12509 }
12510
12511 static GSList *
12512 parse_behaviours (ClutterScript *script,
12513                   ClutterActor  *actor,
12514                   JsonNode      *node)
12515 {
12516   GList *elements, *l;
12517   GSList *retval = NULL;
12518
12519   if (!JSON_NODE_HOLDS_ARRAY (node))
12520     return NULL;
12521
12522   elements = json_array_get_elements (json_node_get_array (node));
12523
12524   for (l = elements; l != NULL; l = l->next)
12525     {
12526       JsonNode *element = l->data;
12527       const gchar *id_ = _clutter_script_get_id_from_node (element);
12528       GObject *behaviour;
12529
12530       if (id_ == NULL || *id_ == '\0')
12531         continue;
12532
12533       behaviour = clutter_script_get_object (script, id_);
12534       if (behaviour == NULL)
12535         continue;
12536
12537       retval = g_slist_prepend (retval, behaviour);
12538     }
12539
12540   g_list_free (elements);
12541
12542   return g_slist_reverse (retval);
12543 }
12544
12545 static gboolean
12546 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12547                                  ClutterScript     *script,
12548                                  GValue            *value,
12549                                  const gchar       *name,
12550                                  JsonNode          *node)
12551 {
12552   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12553   gboolean retval = FALSE;
12554
12555   if ((name[0] == 'x' && name[1] == '\0') ||
12556       (name[0] == 'y' && name[1] == '\0') ||
12557       (strcmp (name, "width") == 0) ||
12558       (strcmp (name, "height") == 0) ||
12559       (strcmp (name, "anchor_x") == 0) ||
12560       (strcmp (name, "anchor_y") == 0))
12561     {
12562       ParseDimension dimension;
12563       gfloat units;
12564
12565       if (name[0] == 'x')
12566         dimension = PARSE_X;
12567       else if (name[0] == 'y')
12568         dimension = PARSE_Y;
12569       else if (name[0] == 'w')
12570         dimension = PARSE_WIDTH;
12571       else if (name[0] == 'h')
12572         dimension = PARSE_HEIGHT;
12573       else if (name[0] == 'a' && name[7] == 'x')
12574         dimension = PARSE_ANCHOR_X;
12575       else if (name[0] == 'a' && name[7] == 'y')
12576         dimension = PARSE_ANCHOR_Y;
12577       else
12578         return FALSE;
12579
12580       units = parse_units (actor, dimension, node);
12581
12582       /* convert back to pixels: all properties are pixel-based */
12583       g_value_init (value, G_TYPE_FLOAT);
12584       g_value_set_float (value, units);
12585
12586       retval = TRUE;
12587     }
12588   else if (strcmp (name, "rotation") == 0)
12589     {
12590       RotationInfo *info;
12591
12592       info = g_slice_new0 (RotationInfo);
12593       retval = parse_rotation (actor, node, info);
12594
12595       if (retval)
12596         {
12597           g_value_init (value, G_TYPE_POINTER);
12598           g_value_set_pointer (value, info);
12599         }
12600       else
12601         g_slice_free (RotationInfo, info);
12602     }
12603   else if (strcmp (name, "behaviours") == 0)
12604     {
12605       GSList *l;
12606
12607 #ifdef CLUTTER_ENABLE_DEBUG
12608       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12609         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12610                                      "and it should not be used in newly "
12611                                      "written ClutterScript definitions.");
12612 #endif
12613
12614       l = parse_behaviours (script, actor, node);
12615
12616       g_value_init (value, G_TYPE_POINTER);
12617       g_value_set_pointer (value, l);
12618
12619       retval = TRUE;
12620     }
12621   else if (strcmp (name, "actions") == 0 ||
12622            strcmp (name, "constraints") == 0 ||
12623            strcmp (name, "effects") == 0)
12624     {
12625       GSList *l;
12626
12627       l = parse_actor_metas (script, actor, node);
12628
12629       g_value_init (value, G_TYPE_POINTER);
12630       g_value_set_pointer (value, l);
12631
12632       retval = TRUE;
12633     }
12634
12635   return retval;
12636 }
12637
12638 static void
12639 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12640                                    ClutterScript     *script,
12641                                    const gchar       *name,
12642                                    const GValue      *value)
12643 {
12644   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12645
12646 #ifdef CLUTTER_ENABLE_DEBUG
12647   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12648     {
12649       gchar *tmp = g_strdup_value_contents (value);
12650
12651       CLUTTER_NOTE (SCRIPT,
12652                     "in ClutterActor::set_custom_property('%s') = %s",
12653                     name,
12654                     tmp);
12655
12656       g_free (tmp);
12657     }
12658 #endif /* CLUTTER_ENABLE_DEBUG */
12659
12660   if (strcmp (name, "rotation") == 0)
12661     {
12662       RotationInfo *info;
12663
12664       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12665         return;
12666
12667       info = g_value_get_pointer (value);
12668
12669       clutter_actor_set_rotation (actor,
12670                                   info->axis, info->angle,
12671                                   info->center_x,
12672                                   info->center_y,
12673                                   info->center_z);
12674
12675       g_slice_free (RotationInfo, info);
12676
12677       return;
12678     }
12679
12680   if (strcmp (name, "behaviours") == 0)
12681     {
12682       GSList *behaviours, *l;
12683
12684       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12685         return;
12686
12687       behaviours = g_value_get_pointer (value);
12688       for (l = behaviours; l != NULL; l = l->next)
12689         {
12690           ClutterBehaviour *behaviour = l->data;
12691
12692           clutter_behaviour_apply (behaviour, actor);
12693         }
12694
12695       g_slist_free (behaviours);
12696
12697       return;
12698     }
12699
12700   if (strcmp (name, "actions") == 0 ||
12701       strcmp (name, "constraints") == 0 ||
12702       strcmp (name, "effects") == 0)
12703     {
12704       GSList *metas, *l;
12705
12706       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12707         return;
12708
12709       metas = g_value_get_pointer (value);
12710       for (l = metas; l != NULL; l = l->next)
12711         {
12712           if (name[0] == 'a')
12713             clutter_actor_add_action (actor, l->data);
12714
12715           if (name[0] == 'c')
12716             clutter_actor_add_constraint (actor, l->data);
12717
12718           if (name[0] == 'e')
12719             clutter_actor_add_effect (actor, l->data);
12720         }
12721
12722       g_slist_free (metas);
12723
12724       return;
12725     }
12726
12727   g_object_set_property (G_OBJECT (scriptable), name, value);
12728 }
12729
12730 static void
12731 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12732 {
12733   iface->parse_custom_node = clutter_actor_parse_custom_node;
12734   iface->set_custom_property = clutter_actor_set_custom_property;
12735 }
12736
12737 static ClutterActorMeta *
12738 get_meta_from_animation_property (ClutterActor  *actor,
12739                                   const gchar   *name,
12740                                   gchar        **name_p)
12741 {
12742   ClutterActorPrivate *priv = actor->priv;
12743   ClutterActorMeta *meta = NULL;
12744   gchar **tokens;
12745
12746   /* if this is not a special property, fall through */
12747   if (name[0] != '@')
12748     return NULL;
12749
12750   /* detect the properties named using the following spec:
12751    *
12752    *   @<section>.<meta-name>.<property-name>
12753    *
12754    * where <section> can be one of the following:
12755    *
12756    *   - actions
12757    *   - constraints
12758    *   - effects
12759    *
12760    * and <meta-name> is the name set on a specific ActorMeta
12761    */
12762
12763   tokens = g_strsplit (name + 1, ".", -1);
12764   if (tokens == NULL || g_strv_length (tokens) != 3)
12765     {
12766       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12767                     name + 1);
12768       g_strfreev (tokens);
12769       return NULL;
12770     }
12771
12772   if (strcmp (tokens[0], "actions") == 0)
12773     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12774
12775   if (strcmp (tokens[0], "constraints") == 0)
12776     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12777
12778   if (strcmp (tokens[0], "effects") == 0)
12779     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12780
12781   if (name_p != NULL)
12782     *name_p = g_strdup (tokens[2]);
12783
12784   CLUTTER_NOTE (ANIMATION,
12785                 "Looking for property '%s' of object '%s' in section '%s'",
12786                 tokens[2],
12787                 tokens[1],
12788                 tokens[0]);
12789
12790   g_strfreev (tokens);
12791
12792   return meta;
12793 }
12794
12795 static GParamSpec *
12796 clutter_actor_find_property (ClutterAnimatable *animatable,
12797                              const gchar       *property_name)
12798 {
12799   ClutterActorMeta *meta = NULL;
12800   GObjectClass *klass = NULL;
12801   GParamSpec *pspec = NULL;
12802   gchar *p_name = NULL;
12803
12804   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12805                                            property_name,
12806                                            &p_name);
12807
12808   if (meta != NULL)
12809     {
12810       klass = G_OBJECT_GET_CLASS (meta);
12811
12812       pspec = g_object_class_find_property (klass, p_name);
12813     }
12814   else
12815     {
12816       klass = G_OBJECT_GET_CLASS (animatable);
12817
12818       pspec = g_object_class_find_property (klass, property_name);
12819     }
12820
12821   g_free (p_name);
12822
12823   return pspec;
12824 }
12825
12826 static void
12827 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12828                                  const gchar       *property_name,
12829                                  GValue            *initial)
12830 {
12831   ClutterActorMeta *meta = NULL;
12832   gchar *p_name = NULL;
12833
12834   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12835                                            property_name,
12836                                            &p_name);
12837
12838   if (meta != NULL)
12839     g_object_get_property (G_OBJECT (meta), p_name, initial);
12840   else
12841     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12842
12843   g_free (p_name);
12844 }
12845
12846 /*
12847  * clutter_actor_set_animatable_property:
12848  * @actor: a #ClutterActor
12849  * @prop_id: the paramspec id
12850  * @value: the value to set
12851  * @pspec: the paramspec
12852  *
12853  * Sets values of animatable properties.
12854  *
12855  * This is a variant of clutter_actor_set_property() that gets called
12856  * by the #ClutterAnimatable implementation of #ClutterActor for the
12857  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12858  * #GParamSpec.
12859  *
12860  * Unlike the implementation of #GObjectClass.set_property(), this
12861  * function will not update the interval if a transition involving an
12862  * animatable property is in progress - this avoids cycles with the
12863  * transition API calling the public API.
12864  */
12865 static void
12866 clutter_actor_set_animatable_property (ClutterActor *actor,
12867                                        guint         prop_id,
12868                                        const GValue *value,
12869                                        GParamSpec   *pspec)
12870 {
12871   switch (prop_id)
12872     {
12873     case PROP_X:
12874       clutter_actor_set_x_internal (actor, g_value_get_float (value));
12875       break;
12876
12877     case PROP_Y:
12878       clutter_actor_set_y_internal (actor, g_value_get_float (value));
12879       break;
12880
12881     case PROP_WIDTH:
12882       clutter_actor_set_width_internal (actor, g_value_get_float (value));
12883       break;
12884
12885     case PROP_HEIGHT:
12886       clutter_actor_set_height_internal (actor, g_value_get_float (value));
12887       break;
12888
12889     case PROP_DEPTH:
12890       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12891       break;
12892
12893     case PROP_OPACITY:
12894       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12895       break;
12896
12897     case PROP_BACKGROUND_COLOR:
12898       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12899       break;
12900
12901     case PROP_SCALE_X:
12902       clutter_actor_set_scale_factor_internal (actor,
12903                                                g_value_get_double (value),
12904                                                pspec);
12905       break;
12906
12907     case PROP_SCALE_Y:
12908       clutter_actor_set_scale_factor_internal (actor,
12909                                                g_value_get_double (value),
12910                                                pspec);
12911       break;
12912
12913     case PROP_ROTATION_ANGLE_X:
12914       clutter_actor_set_rotation_angle_internal (actor,
12915                                                  CLUTTER_X_AXIS,
12916                                                  g_value_get_double (value));
12917       break;
12918
12919     case PROP_ROTATION_ANGLE_Y:
12920       clutter_actor_set_rotation_angle_internal (actor,
12921                                                  CLUTTER_Y_AXIS,
12922                                                  g_value_get_double (value));
12923       break;
12924
12925     case PROP_ROTATION_ANGLE_Z:
12926       clutter_actor_set_rotation_angle_internal (actor,
12927                                                  CLUTTER_Z_AXIS,
12928                                                  g_value_get_double (value));
12929       break;
12930
12931     default:
12932       g_object_set_property (G_OBJECT (actor), pspec->name, value);
12933       break;
12934     }
12935 }
12936
12937 static void
12938 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12939                                const gchar       *property_name,
12940                                const GValue      *final)
12941 {
12942   ClutterActor *actor = CLUTTER_ACTOR (animatable);
12943   ClutterActorMeta *meta = NULL;
12944   gchar *p_name = NULL;
12945
12946   meta = get_meta_from_animation_property (actor,
12947                                            property_name,
12948                                            &p_name);
12949   if (meta != NULL)
12950     g_object_set_property (G_OBJECT (meta), p_name, final);
12951   else
12952     {
12953       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12954       GParamSpec *pspec;
12955
12956       pspec = g_object_class_find_property (obj_class, property_name);
12957
12958       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12959         {
12960           /* XXX - I'm going to the special hell for this */
12961           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12962         }
12963       else
12964         g_object_set_property (G_OBJECT (animatable), property_name, final);
12965     }
12966
12967   g_free (p_name);
12968 }
12969
12970 static void
12971 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12972 {
12973   iface->find_property = clutter_actor_find_property;
12974   iface->get_initial_state = clutter_actor_get_initial_state;
12975   iface->set_final_state = clutter_actor_set_final_state;
12976 }
12977
12978 /**
12979  * clutter_actor_transform_stage_point:
12980  * @self: A #ClutterActor
12981  * @x: (in): x screen coordinate of the point to unproject
12982  * @y: (in): y screen coordinate of the point to unproject
12983  * @x_out: (out): return location for the unprojected x coordinance
12984  * @y_out: (out): return location for the unprojected y coordinance
12985  *
12986  * This function translates screen coordinates (@x, @y) to
12987  * coordinates relative to the actor. For example, it can be used to translate
12988  * screen events from global screen coordinates into actor-local coordinates.
12989  *
12990  * The conversion can fail, notably if the transform stack results in the
12991  * actor being projected on the screen as a mere line.
12992  *
12993  * The conversion should not be expected to be pixel-perfect due to the
12994  * nature of the operation. In general the error grows when the skewing
12995  * of the actor rectangle on screen increases.
12996  *
12997  * <note><para>This function can be computationally intensive.</para></note>
12998  *
12999  * <note><para>This function only works when the allocation is up-to-date,
13000  * i.e. inside of paint().</para></note>
13001  *
13002  * Return value: %TRUE if conversion was successful.
13003  *
13004  * Since: 0.6
13005  */
13006 gboolean
13007 clutter_actor_transform_stage_point (ClutterActor *self,
13008                                      gfloat        x,
13009                                      gfloat        y,
13010                                      gfloat       *x_out,
13011                                      gfloat       *y_out)
13012 {
13013   ClutterVertex v[4];
13014   float ST[3][3];
13015   float RQ[3][3];
13016   int du, dv, xi, yi;
13017   float px, py;
13018   float xf, yf, wf, det;
13019   ClutterActorPrivate *priv;
13020
13021   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13022
13023   priv = self->priv;
13024
13025   /* This implementation is based on the quad -> quad projection algorithm
13026    * described by Paul Heckbert in:
13027    *
13028    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13029    *
13030    * and the sample implementation at:
13031    *
13032    *   http://www.cs.cmu.edu/~ph/src/texfund/
13033    *
13034    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13035    * quad to rectangle only, which significantly simplifies things; the
13036    * function calls have been unrolled, and most of the math is done in fixed
13037    * point.
13038    */
13039
13040   clutter_actor_get_abs_allocation_vertices (self, v);
13041
13042   /* Keeping these as ints simplifies the multiplication (no significant
13043    * loss of precision here).
13044    */
13045   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13046   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13047
13048   if (!du || !dv)
13049     return FALSE;
13050
13051 #define UX2FP(x)        (x)
13052 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13053
13054   /* First, find mapping from unit uv square to xy quadrilateral; this
13055    * equivalent to the pmap_square_quad() functions in the sample
13056    * implementation, which we can simplify, since our target is always
13057    * a rectangle.
13058    */
13059   px = v[0].x - v[1].x + v[3].x - v[2].x;
13060   py = v[0].y - v[1].y + v[3].y - v[2].y;
13061
13062   if (!px && !py)
13063     {
13064       /* affine transform */
13065       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13066       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13067       RQ[2][0] = UX2FP (v[0].x);
13068       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13069       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13070       RQ[2][1] = UX2FP (v[0].y);
13071       RQ[0][2] = 0;
13072       RQ[1][2] = 0;
13073       RQ[2][2] = 1.0;
13074     }
13075   else
13076     {
13077       /* projective transform */
13078       double dx1, dx2, dy1, dy2, del;
13079
13080       dx1 = UX2FP (v[1].x - v[3].x);
13081       dx2 = UX2FP (v[2].x - v[3].x);
13082       dy1 = UX2FP (v[1].y - v[3].y);
13083       dy2 = UX2FP (v[2].y - v[3].y);
13084
13085       del = DET2FP (dx1, dx2, dy1, dy2);
13086       if (!del)
13087         return FALSE;
13088
13089       /*
13090        * The division here needs to be done in floating point for
13091        * precisions reasons.
13092        */
13093       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13094       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13095       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13096       RQ[2][2] = 1.0;
13097       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13098       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13099       RQ[2][0] = UX2FP (v[0].x);
13100       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13101       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13102       RQ[2][1] = UX2FP (v[0].y);
13103     }
13104
13105   /*
13106    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13107    * square. Since our rectangle is based at 0,0 we only need to scale.
13108    */
13109   RQ[0][0] /= du;
13110   RQ[1][0] /= dv;
13111   RQ[0][1] /= du;
13112   RQ[1][1] /= dv;
13113   RQ[0][2] /= du;
13114   RQ[1][2] /= dv;
13115
13116   /*
13117    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13118    * inverse of that.
13119    */
13120   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13121   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13122   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13123   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13124   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13125   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13126   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13127   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13128   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13129
13130   /*
13131    * Check the resulting matrix is OK.
13132    */
13133   det = (RQ[0][0] * ST[0][0])
13134       + (RQ[0][1] * ST[0][1])
13135       + (RQ[0][2] * ST[0][2]);
13136   if (!det)
13137     return FALSE;
13138
13139   /*
13140    * Now transform our point with the ST matrix; the notional w
13141    * coordinate is 1, hence the last part is simply added.
13142    */
13143   xi = (int) x;
13144   yi = (int) y;
13145
13146   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13147   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13148   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13149
13150   if (x_out)
13151     *x_out = xf / wf;
13152
13153   if (y_out)
13154     *y_out = yf / wf;
13155
13156 #undef UX2FP
13157 #undef DET2FP
13158
13159   return TRUE;
13160 }
13161
13162 /*
13163  * ClutterGeometry
13164  */
13165
13166 static ClutterGeometry*
13167 clutter_geometry_copy (const ClutterGeometry *geometry)
13168 {
13169   return g_slice_dup (ClutterGeometry, geometry);
13170 }
13171
13172 static void
13173 clutter_geometry_free (ClutterGeometry *geometry)
13174 {
13175   if (G_LIKELY (geometry != NULL))
13176     g_slice_free (ClutterGeometry, geometry);
13177 }
13178
13179 /**
13180  * clutter_geometry_union:
13181  * @geometry_a: a #ClutterGeometry
13182  * @geometry_b: another #ClutterGeometry
13183  * @result: (out): location to store the result
13184  *
13185  * Find the union of two rectangles represented as #ClutterGeometry.
13186  *
13187  * Since: 1.4
13188  */
13189 void
13190 clutter_geometry_union (const ClutterGeometry *geometry_a,
13191                         const ClutterGeometry *geometry_b,
13192                         ClutterGeometry       *result)
13193 {
13194   /* We don't try to handle rectangles that can't be represented
13195    * as a signed integer box */
13196   gint x_1 = MIN (geometry_a->x, geometry_b->x);
13197   gint y_1 = MIN (geometry_a->y, geometry_b->y);
13198   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13199                   geometry_b->x + (gint)geometry_b->width);
13200   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13201                   geometry_b->y + (gint)geometry_b->height);
13202   result->x = x_1;
13203   result->y = y_1;
13204   result->width = x_2 - x_1;
13205   result->height = y_2 - y_1;
13206 }
13207
13208 /**
13209  * clutter_geometry_intersects:
13210  * @geometry0: The first geometry to test
13211  * @geometry1: The second geometry to test
13212  *
13213  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13214  * they do else %FALSE.
13215  *
13216  * Return value: %TRUE of @geometry0 and geometry1 intersect else
13217  * %FALSE.
13218  *
13219  * Since: 1.4
13220  */
13221 gboolean
13222 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13223                              const ClutterGeometry *geometry1)
13224 {
13225   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13226       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13227       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13228       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13229     return FALSE;
13230   else
13231     return TRUE;
13232 }
13233
13234 static gboolean
13235 clutter_geometry_progress (const GValue *a,
13236                            const GValue *b,
13237                            gdouble       progress,
13238                            GValue       *retval)
13239 {
13240   const ClutterGeometry *a_geom = g_value_get_boxed (a);
13241   const ClutterGeometry *b_geom = g_value_get_boxed (b);
13242   ClutterGeometry res = { 0, };
13243   gint a_width = a_geom->width;
13244   gint b_width = b_geom->width;
13245   gint a_height = a_geom->height;
13246   gint b_height = b_geom->height;
13247
13248   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13249   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13250
13251   res.width = a_width + (b_width - a_width) * progress;
13252   res.height = a_height + (b_height - a_height) * progress;
13253
13254   g_value_set_boxed (retval, &res);
13255
13256   return TRUE;
13257 }
13258
13259 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13260                                clutter_geometry_copy,
13261                                clutter_geometry_free,
13262                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13263
13264 /*
13265  * ClutterVertices
13266  */
13267
13268 /**
13269  * clutter_vertex_new:
13270  * @x: X coordinate
13271  * @y: Y coordinate
13272  * @z: Z coordinate
13273  *
13274  * Creates a new #ClutterVertex for the point in 3D space
13275  * identified by the 3 coordinates @x, @y, @z
13276  *
13277  * Return value: the newly allocate #ClutterVertex. Use
13278  *   clutter_vertex_free() to free the resources
13279  *
13280  * Since: 1.0
13281  */
13282 ClutterVertex *
13283 clutter_vertex_new (gfloat x,
13284                     gfloat y,
13285                     gfloat z)
13286 {
13287   ClutterVertex *vertex;
13288
13289   vertex = g_slice_new (ClutterVertex);
13290   vertex->x = x;
13291   vertex->y = y;
13292   vertex->z = z;
13293
13294   return vertex;
13295 }
13296
13297 /**
13298  * clutter_vertex_copy:
13299  * @vertex: a #ClutterVertex
13300  *
13301  * Copies @vertex
13302  *
13303  * Return value: a newly allocated copy of #ClutterVertex. Use
13304  *   clutter_vertex_free() to free the allocated resources
13305  *
13306  * Since: 1.0
13307  */
13308 ClutterVertex *
13309 clutter_vertex_copy (const ClutterVertex *vertex)
13310 {
13311   if (G_LIKELY (vertex != NULL))
13312     return g_slice_dup (ClutterVertex, vertex);
13313
13314   return NULL;
13315 }
13316
13317 /**
13318  * clutter_vertex_free:
13319  * @vertex: a #ClutterVertex
13320  *
13321  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13322  *
13323  * Since: 1.0
13324  */
13325 void
13326 clutter_vertex_free (ClutterVertex *vertex)
13327 {
13328   if (G_UNLIKELY (vertex != NULL))
13329     g_slice_free (ClutterVertex, vertex);
13330 }
13331
13332 /**
13333  * clutter_vertex_equal:
13334  * @vertex_a: a #ClutterVertex
13335  * @vertex_b: a #ClutterVertex
13336  *
13337  * Compares @vertex_a and @vertex_b for equality
13338  *
13339  * Return value: %TRUE if the passed #ClutterVertex are equal
13340  *
13341  * Since: 1.0
13342  */
13343 gboolean
13344 clutter_vertex_equal (const ClutterVertex *vertex_a,
13345                       const ClutterVertex *vertex_b)
13346 {
13347   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13348
13349   if (vertex_a == vertex_b)
13350     return TRUE;
13351
13352   return vertex_a->x == vertex_b->x &&
13353          vertex_a->y == vertex_b->y &&
13354          vertex_a->z == vertex_b->z;
13355 }
13356
13357 static gboolean
13358 clutter_vertex_progress (const GValue *a,
13359                          const GValue *b,
13360                          gdouble       progress,
13361                          GValue       *retval)
13362 {
13363   const ClutterVertex *av = g_value_get_boxed (a);
13364   const ClutterVertex *bv = g_value_get_boxed (b);
13365   ClutterVertex res = { 0, };
13366
13367   res.x = av->x + (bv->x - av->x) * progress;
13368   res.y = av->y + (bv->y - av->y) * progress;
13369   res.z = av->z + (bv->z - av->z) * progress;
13370
13371   g_value_set_boxed (retval, &res);
13372
13373   return TRUE;
13374 }
13375
13376 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13377                                clutter_vertex_copy,
13378                                clutter_vertex_free,
13379                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13380
13381 /**
13382  * clutter_actor_is_rotated:
13383  * @self: a #ClutterActor
13384  *
13385  * Checks whether any rotation is applied to the actor.
13386  *
13387  * Return value: %TRUE if the actor is rotated.
13388  *
13389  * Since: 0.6
13390  */
13391 gboolean
13392 clutter_actor_is_rotated (ClutterActor *self)
13393 {
13394   const ClutterTransformInfo *info;
13395
13396   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13397
13398   info = _clutter_actor_get_transform_info_or_defaults (self);
13399
13400   if (info->rx_angle || info->ry_angle || info->rz_angle)
13401     return TRUE;
13402
13403   return FALSE;
13404 }
13405
13406 /**
13407  * clutter_actor_is_scaled:
13408  * @self: a #ClutterActor
13409  *
13410  * Checks whether the actor is scaled in either dimension.
13411  *
13412  * Return value: %TRUE if the actor is scaled.
13413  *
13414  * Since: 0.6
13415  */
13416 gboolean
13417 clutter_actor_is_scaled (ClutterActor *self)
13418 {
13419   const ClutterTransformInfo *info;
13420
13421   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13422
13423   info = _clutter_actor_get_transform_info_or_defaults (self);
13424
13425   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13426     return TRUE;
13427
13428   return FALSE;
13429 }
13430
13431 ClutterActor *
13432 _clutter_actor_get_stage_internal (ClutterActor *actor)
13433 {
13434   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13435     actor = actor->priv->parent;
13436
13437   return actor;
13438 }
13439
13440 /**
13441  * clutter_actor_get_stage:
13442  * @actor: a #ClutterActor
13443  *
13444  * Retrieves the #ClutterStage where @actor is contained.
13445  *
13446  * Return value: (transfer none) (type Clutter.Stage): the stage
13447  *   containing the actor, or %NULL
13448  *
13449  * Since: 0.8
13450  */
13451 ClutterActor *
13452 clutter_actor_get_stage (ClutterActor *actor)
13453 {
13454   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13455
13456   return _clutter_actor_get_stage_internal (actor);
13457 }
13458
13459 /**
13460  * clutter_actor_allocate_available_size:
13461  * @self: a #ClutterActor
13462  * @x: the actor's X coordinate
13463  * @y: the actor's Y coordinate
13464  * @available_width: the maximum available width, or -1 to use the
13465  *   actor's natural width
13466  * @available_height: the maximum available height, or -1 to use the
13467  *   actor's natural height
13468  * @flags: flags controlling the allocation
13469  *
13470  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13471  * preferred size, but limiting it to the maximum available width
13472  * and height provided.
13473  *
13474  * This function will do the right thing when dealing with the
13475  * actor's request mode.
13476  *
13477  * The implementation of this function is equivalent to:
13478  *
13479  * |[
13480  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13481  *     {
13482  *       clutter_actor_get_preferred_width (self, available_height,
13483  *                                          &amp;min_width,
13484  *                                          &amp;natural_width);
13485  *       width = CLAMP (natural_width, min_width, available_width);
13486  *
13487  *       clutter_actor_get_preferred_height (self, width,
13488  *                                           &amp;min_height,
13489  *                                           &amp;natural_height);
13490  *       height = CLAMP (natural_height, min_height, available_height);
13491  *     }
13492  *   else
13493  *     {
13494  *       clutter_actor_get_preferred_height (self, available_width,
13495  *                                           &amp;min_height,
13496  *                                           &amp;natural_height);
13497  *       height = CLAMP (natural_height, min_height, available_height);
13498  *
13499  *       clutter_actor_get_preferred_width (self, height,
13500  *                                          &amp;min_width,
13501  *                                          &amp;natural_width);
13502  *       width = CLAMP (natural_width, min_width, available_width);
13503  *     }
13504  *
13505  *   box.x1 = x; box.y1 = y;
13506  *   box.x2 = box.x1 + available_width;
13507  *   box.y2 = box.y1 + available_height;
13508  *   clutter_actor_allocate (self, &amp;box, flags);
13509  * ]|
13510  *
13511  * This function can be used by fluid layout managers to allocate
13512  * an actor's preferred size without making it bigger than the area
13513  * available for the container.
13514  *
13515  * Since: 1.0
13516  */
13517 void
13518 clutter_actor_allocate_available_size (ClutterActor           *self,
13519                                        gfloat                  x,
13520                                        gfloat                  y,
13521                                        gfloat                  available_width,
13522                                        gfloat                  available_height,
13523                                        ClutterAllocationFlags  flags)
13524 {
13525   ClutterActorPrivate *priv;
13526   gfloat width, height;
13527   gfloat min_width, min_height;
13528   gfloat natural_width, natural_height;
13529   ClutterActorBox box;
13530
13531   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13532
13533   priv = self->priv;
13534
13535   width = height = 0.0;
13536
13537   switch (priv->request_mode)
13538     {
13539     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13540       clutter_actor_get_preferred_width (self, available_height,
13541                                          &min_width,
13542                                          &natural_width);
13543       width  = CLAMP (natural_width, min_width, available_width);
13544
13545       clutter_actor_get_preferred_height (self, width,
13546                                           &min_height,
13547                                           &natural_height);
13548       height = CLAMP (natural_height, min_height, available_height);
13549       break;
13550
13551     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13552       clutter_actor_get_preferred_height (self, available_width,
13553                                           &min_height,
13554                                           &natural_height);
13555       height = CLAMP (natural_height, min_height, available_height);
13556
13557       clutter_actor_get_preferred_width (self, height,
13558                                          &min_width,
13559                                          &natural_width);
13560       width  = CLAMP (natural_width, min_width, available_width);
13561       break;
13562     }
13563
13564
13565   box.x1 = x;
13566   box.y1 = y;
13567   box.x2 = box.x1 + width;
13568   box.y2 = box.y1 + height;
13569   clutter_actor_allocate (self, &box, flags);
13570 }
13571
13572 /**
13573  * clutter_actor_allocate_preferred_size:
13574  * @self: a #ClutterActor
13575  * @flags: flags controlling the allocation
13576  *
13577  * Allocates the natural size of @self.
13578  *
13579  * This function is a utility call for #ClutterActor implementations
13580  * that allocates the actor's preferred natural size. It can be used
13581  * by fixed layout managers (like #ClutterGroup or so called
13582  * 'composite actors') inside the ClutterActor::allocate
13583  * implementation to give each child exactly how much space it
13584  * requires.
13585  *
13586  * This function is not meant to be used by applications. It is also
13587  * not meant to be used outside the implementation of the
13588  * ClutterActor::allocate virtual function.
13589  *
13590  * Since: 0.8
13591  */
13592 void
13593 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13594                                        ClutterAllocationFlags  flags)
13595 {
13596   gfloat actor_x, actor_y;
13597   gfloat natural_width, natural_height;
13598   ClutterActorBox actor_box;
13599
13600   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13601
13602   actor_x = clutter_actor_get_x (self);
13603   actor_y = clutter_actor_get_y (self);
13604
13605   clutter_actor_get_preferred_size (self,
13606                                     NULL, NULL,
13607                                     &natural_width,
13608                                     &natural_height);
13609
13610   actor_box.x1 = actor_x;
13611   actor_box.y1 = actor_y;
13612   actor_box.x2 = actor_box.x1 + natural_width;
13613   actor_box.y2 = actor_box.y1 + natural_height;
13614
13615   clutter_actor_allocate (self, &actor_box, flags);
13616 }
13617
13618 /**
13619  * clutter_actor_allocate_align_fill:
13620  * @self: a #ClutterActor
13621  * @box: a #ClutterActorBox, containing the available width and height
13622  * @x_align: the horizontal alignment, between 0 and 1
13623  * @y_align: the vertical alignment, between 0 and 1
13624  * @x_fill: whether the actor should fill horizontally
13625  * @y_fill: whether the actor should fill vertically
13626  * @flags: allocation flags to be passed to clutter_actor_allocate()
13627  *
13628  * Allocates @self by taking into consideration the available allocation
13629  * area; an alignment factor on either axis; and whether the actor should
13630  * fill the allocation on either axis.
13631  *
13632  * The @box should contain the available allocation width and height;
13633  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13634  * allocation will be offset by their value.
13635  *
13636  * This function takes into consideration the geometry request specified by
13637  * the #ClutterActor:request-mode property, and the text direction.
13638  *
13639  * This function is useful for fluid layout managers, like #ClutterBinLayout
13640  * or #ClutterTableLayout
13641  *
13642  * Since: 1.4
13643  */
13644 void
13645 clutter_actor_allocate_align_fill (ClutterActor           *self,
13646                                    const ClutterActorBox  *box,
13647                                    gdouble                 x_align,
13648                                    gdouble                 y_align,
13649                                    gboolean                x_fill,
13650                                    gboolean                y_fill,
13651                                    ClutterAllocationFlags  flags)
13652 {
13653   ClutterActorPrivate *priv;
13654   ClutterActorBox allocation = { 0, };
13655   gfloat x_offset, y_offset;
13656   gfloat available_width, available_height;
13657   gfloat child_width, child_height;
13658
13659   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13660   g_return_if_fail (box != NULL);
13661   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13662   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13663
13664   priv = self->priv;
13665
13666   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13667   clutter_actor_box_get_size (box, &available_width, &available_height);
13668
13669   if (available_width < 0)
13670     available_width = 0;
13671
13672   if (available_height < 0)
13673     available_height = 0;
13674
13675   if (x_fill)
13676     {
13677       allocation.x1 = x_offset;
13678       allocation.x2 = allocation.x1 + available_width;
13679     }
13680
13681   if (y_fill)
13682     {
13683       allocation.y1 = y_offset;
13684       allocation.y2 = allocation.y1 + available_height;
13685     }
13686
13687   /* if we are filling horizontally and vertically then we're done */
13688   if (x_fill && y_fill)
13689     goto out;
13690
13691   child_width = child_height = 0.0f;
13692
13693   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13694     {
13695       gfloat min_width, natural_width;
13696       gfloat min_height, natural_height;
13697
13698       clutter_actor_get_preferred_width (self, available_height,
13699                                          &min_width,
13700                                          &natural_width);
13701
13702       child_width = CLAMP (natural_width, min_width, available_width);
13703
13704       if (!y_fill)
13705         {
13706           clutter_actor_get_preferred_height (self, child_width,
13707                                               &min_height,
13708                                               &natural_height);
13709
13710           child_height = CLAMP (natural_height, min_height, available_height);
13711         }
13712     }
13713   else
13714     {
13715       gfloat min_width, natural_width;
13716       gfloat min_height, natural_height;
13717
13718       clutter_actor_get_preferred_height (self, available_width,
13719                                           &min_height,
13720                                           &natural_height);
13721
13722       child_height = CLAMP (natural_height, min_height, available_height);
13723
13724       if (!x_fill)
13725         {
13726           clutter_actor_get_preferred_width (self, child_height,
13727                                              &min_width,
13728                                              &natural_width);
13729
13730           child_width = CLAMP (natural_width, min_width, available_width);
13731         }
13732     }
13733
13734   /* invert the horizontal alignment for RTL languages */
13735   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13736     x_align = 1.0 - x_align;
13737
13738   if (!x_fill)
13739     {
13740       allocation.x1 = x_offset
13741                     + ((available_width - child_width) * x_align);
13742       allocation.x2 = allocation.x1 + child_width;
13743     }
13744
13745   if (!y_fill)
13746     {
13747       allocation.y1 = y_offset
13748                     + ((available_height - child_height) * y_align);
13749       allocation.y2 = allocation.y1 + child_height;
13750     }
13751
13752 out:
13753   clutter_actor_box_clamp_to_pixel (&allocation);
13754   clutter_actor_allocate (self, &allocation, flags);
13755 }
13756
13757 /**
13758  * clutter_actor_grab_key_focus:
13759  * @self: a #ClutterActor
13760  *
13761  * Sets the key focus of the #ClutterStage including @self
13762  * to this #ClutterActor.
13763  *
13764  * Since: 1.0
13765  */
13766 void
13767 clutter_actor_grab_key_focus (ClutterActor *self)
13768 {
13769   ClutterActor *stage;
13770
13771   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13772
13773   stage = _clutter_actor_get_stage_internal (self);
13774   if (stage != NULL)
13775     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13776 }
13777
13778 /**
13779  * clutter_actor_get_pango_context:
13780  * @self: a #ClutterActor
13781  *
13782  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13783  * is already configured using the appropriate font map, resolution
13784  * and font options.
13785  *
13786  * Unlike clutter_actor_create_pango_context(), this context is owend
13787  * by the #ClutterActor and it will be updated each time the options
13788  * stored by the #ClutterBackend change.
13789  *
13790  * You can use the returned #PangoContext to create a #PangoLayout
13791  * and render text using cogl_pango_render_layout() to reuse the
13792  * glyphs cache also used by Clutter.
13793  *
13794  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13795  *   The returned #PangoContext is owned by the actor and should not be
13796  *   unreferenced by the application code
13797  *
13798  * Since: 1.0
13799  */
13800 PangoContext *
13801 clutter_actor_get_pango_context (ClutterActor *self)
13802 {
13803   ClutterActorPrivate *priv;
13804
13805   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13806
13807   priv = self->priv;
13808
13809   if (priv->pango_context != NULL)
13810     return priv->pango_context;
13811
13812   priv->pango_context = _clutter_context_get_pango_context ();
13813   g_object_ref (priv->pango_context);
13814
13815   return priv->pango_context;
13816 }
13817
13818 /**
13819  * clutter_actor_create_pango_context:
13820  * @self: a #ClutterActor
13821  *
13822  * Creates a #PangoContext for the given actor. The #PangoContext
13823  * is already configured using the appropriate font map, resolution
13824  * and font options.
13825  *
13826  * See also clutter_actor_get_pango_context().
13827  *
13828  * Return value: (transfer full): the newly created #PangoContext.
13829  *   Use g_object_unref() on the returned value to deallocate its
13830  *   resources
13831  *
13832  * Since: 1.0
13833  */
13834 PangoContext *
13835 clutter_actor_create_pango_context (ClutterActor *self)
13836 {
13837   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13838
13839   return _clutter_context_create_pango_context ();
13840 }
13841
13842 /**
13843  * clutter_actor_create_pango_layout:
13844  * @self: a #ClutterActor
13845  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13846  *
13847  * Creates a new #PangoLayout from the same #PangoContext used
13848  * by the #ClutterActor. The #PangoLayout is already configured
13849  * with the font map, resolution and font options, and the
13850  * given @text.
13851  *
13852  * If you want to keep around a #PangoLayout created by this
13853  * function you will have to connect to the #ClutterBackend::font-changed
13854  * and #ClutterBackend::resolution-changed signals, and call
13855  * pango_layout_context_changed() in response to them.
13856  *
13857  * Return value: (transfer full): the newly created #PangoLayout.
13858  *   Use g_object_unref() when done
13859  *
13860  * Since: 1.0
13861  */
13862 PangoLayout *
13863 clutter_actor_create_pango_layout (ClutterActor *self,
13864                                    const gchar  *text)
13865 {
13866   PangoContext *context;
13867   PangoLayout *layout;
13868
13869   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13870
13871   context = clutter_actor_get_pango_context (self);
13872   layout = pango_layout_new (context);
13873
13874   if (text)
13875     pango_layout_set_text (layout, text, -1);
13876
13877   return layout;
13878 }
13879
13880 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13881  * ClutterOffscreenEffect.
13882  */
13883 void
13884 _clutter_actor_set_opacity_override (ClutterActor *self,
13885                                      gint          opacity)
13886 {
13887   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13888
13889   self->priv->opacity_override = opacity;
13890 }
13891
13892 gint
13893 _clutter_actor_get_opacity_override (ClutterActor *self)
13894 {
13895   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13896
13897   return self->priv->opacity_override;
13898 }
13899
13900 /* Allows you to disable applying the actors model view transform during
13901  * a paint. Used by ClutterClone. */
13902 void
13903 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13904                                                 gboolean      enable)
13905 {
13906   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13907
13908   self->priv->enable_model_view_transform = enable;
13909 }
13910
13911 void
13912 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13913                                           gboolean      enable)
13914 {
13915   ClutterActorPrivate *priv;
13916
13917   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13918
13919   priv = self->priv;
13920
13921   priv->enable_paint_unmapped = enable;
13922
13923   if (priv->enable_paint_unmapped)
13924     {
13925       /* Make sure that the parents of the widget are realized first;
13926        * otherwise checks in clutter_actor_update_map_state() will
13927        * fail.
13928        */
13929       clutter_actor_realize (self);
13930
13931       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13932     }
13933   else
13934     {
13935       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13936     }
13937 }
13938
13939 static void
13940 clutter_anchor_coord_get_units (ClutterActor      *self,
13941                                 const AnchorCoord *coord,
13942                                 gfloat            *x,
13943                                 gfloat            *y,
13944                                 gfloat            *z)
13945 {
13946   if (coord->is_fractional)
13947     {
13948       gfloat actor_width, actor_height;
13949
13950       clutter_actor_get_size (self, &actor_width, &actor_height);
13951
13952       if (x)
13953         *x = actor_width * coord->v.fraction.x;
13954
13955       if (y)
13956         *y = actor_height * coord->v.fraction.y;
13957
13958       if (z)
13959         *z = 0;
13960     }
13961   else
13962     {
13963       if (x)
13964         *x = coord->v.units.x;
13965
13966       if (y)
13967         *y = coord->v.units.y;
13968
13969       if (z)
13970         *z = coord->v.units.z;
13971     }
13972 }
13973
13974 static void
13975 clutter_anchor_coord_set_units (AnchorCoord *coord,
13976                                 gfloat       x,
13977                                 gfloat       y,
13978                                 gfloat       z)
13979 {
13980   coord->is_fractional = FALSE;
13981   coord->v.units.x = x;
13982   coord->v.units.y = y;
13983   coord->v.units.z = z;
13984 }
13985
13986 static ClutterGravity
13987 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13988 {
13989   if (coord->is_fractional)
13990     {
13991       if (coord->v.fraction.x == 0.0)
13992         {
13993           if (coord->v.fraction.y == 0.0)
13994             return CLUTTER_GRAVITY_NORTH_WEST;
13995           else if (coord->v.fraction.y == 0.5)
13996             return CLUTTER_GRAVITY_WEST;
13997           else if (coord->v.fraction.y == 1.0)
13998             return CLUTTER_GRAVITY_SOUTH_WEST;
13999           else
14000             return CLUTTER_GRAVITY_NONE;
14001         }
14002       else if (coord->v.fraction.x == 0.5)
14003         {
14004           if (coord->v.fraction.y == 0.0)
14005             return CLUTTER_GRAVITY_NORTH;
14006           else if (coord->v.fraction.y == 0.5)
14007             return CLUTTER_GRAVITY_CENTER;
14008           else if (coord->v.fraction.y == 1.0)
14009             return CLUTTER_GRAVITY_SOUTH;
14010           else
14011             return CLUTTER_GRAVITY_NONE;
14012         }
14013       else if (coord->v.fraction.x == 1.0)
14014         {
14015           if (coord->v.fraction.y == 0.0)
14016             return CLUTTER_GRAVITY_NORTH_EAST;
14017           else if (coord->v.fraction.y == 0.5)
14018             return CLUTTER_GRAVITY_EAST;
14019           else if (coord->v.fraction.y == 1.0)
14020             return CLUTTER_GRAVITY_SOUTH_EAST;
14021           else
14022             return CLUTTER_GRAVITY_NONE;
14023         }
14024       else
14025         return CLUTTER_GRAVITY_NONE;
14026     }
14027   else
14028     return CLUTTER_GRAVITY_NONE;
14029 }
14030
14031 static void
14032 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14033                                   ClutterGravity  gravity)
14034 {
14035   switch (gravity)
14036     {
14037     case CLUTTER_GRAVITY_NORTH:
14038       coord->v.fraction.x = 0.5;
14039       coord->v.fraction.y = 0.0;
14040       break;
14041
14042     case CLUTTER_GRAVITY_NORTH_EAST:
14043       coord->v.fraction.x = 1.0;
14044       coord->v.fraction.y = 0.0;
14045       break;
14046
14047     case CLUTTER_GRAVITY_EAST:
14048       coord->v.fraction.x = 1.0;
14049       coord->v.fraction.y = 0.5;
14050       break;
14051
14052     case CLUTTER_GRAVITY_SOUTH_EAST:
14053       coord->v.fraction.x = 1.0;
14054       coord->v.fraction.y = 1.0;
14055       break;
14056
14057     case CLUTTER_GRAVITY_SOUTH:
14058       coord->v.fraction.x = 0.5;
14059       coord->v.fraction.y = 1.0;
14060       break;
14061
14062     case CLUTTER_GRAVITY_SOUTH_WEST:
14063       coord->v.fraction.x = 0.0;
14064       coord->v.fraction.y = 1.0;
14065       break;
14066
14067     case CLUTTER_GRAVITY_WEST:
14068       coord->v.fraction.x = 0.0;
14069       coord->v.fraction.y = 0.5;
14070       break;
14071
14072     case CLUTTER_GRAVITY_NORTH_WEST:
14073       coord->v.fraction.x = 0.0;
14074       coord->v.fraction.y = 0.0;
14075       break;
14076
14077     case CLUTTER_GRAVITY_CENTER:
14078       coord->v.fraction.x = 0.5;
14079       coord->v.fraction.y = 0.5;
14080       break;
14081
14082     default:
14083       coord->v.fraction.x = 0.0;
14084       coord->v.fraction.y = 0.0;
14085       break;
14086     }
14087
14088   coord->is_fractional = TRUE;
14089 }
14090
14091 static gboolean
14092 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14093 {
14094   if (coord->is_fractional)
14095     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14096   else
14097     return (coord->v.units.x == 0.0
14098             && coord->v.units.y == 0.0
14099             && coord->v.units.z == 0.0);
14100 }
14101
14102 /**
14103  * clutter_actor_get_flags:
14104  * @self: a #ClutterActor
14105  *
14106  * Retrieves the flags set on @self
14107  *
14108  * Return value: a bitwise or of #ClutterActorFlags or 0
14109  *
14110  * Since: 1.0
14111  */
14112 ClutterActorFlags
14113 clutter_actor_get_flags (ClutterActor *self)
14114 {
14115   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14116
14117   return self->flags;
14118 }
14119
14120 /**
14121  * clutter_actor_set_flags:
14122  * @self: a #ClutterActor
14123  * @flags: the flags to set
14124  *
14125  * Sets @flags on @self
14126  *
14127  * This function will emit notifications for the changed properties
14128  *
14129  * Since: 1.0
14130  */
14131 void
14132 clutter_actor_set_flags (ClutterActor      *self,
14133                          ClutterActorFlags  flags)
14134 {
14135   ClutterActorFlags old_flags;
14136   GObject *obj;
14137   gboolean was_reactive_set, reactive_set;
14138   gboolean was_realized_set, realized_set;
14139   gboolean was_mapped_set, mapped_set;
14140   gboolean was_visible_set, visible_set;
14141
14142   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14143
14144   if (self->flags == flags)
14145     return;
14146
14147   obj = G_OBJECT (self);
14148   g_object_ref (obj);
14149   g_object_freeze_notify (obj);
14150
14151   old_flags = self->flags;
14152
14153   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14154   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14155   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14156   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14157
14158   self->flags |= flags;
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   g_object_unref (obj);
14179 }
14180
14181 /**
14182  * clutter_actor_unset_flags:
14183  * @self: a #ClutterActor
14184  * @flags: the flags to unset
14185  *
14186  * Unsets @flags on @self
14187  *
14188  * This function will emit notifications for the changed properties
14189  *
14190  * Since: 1.0
14191  */
14192 void
14193 clutter_actor_unset_flags (ClutterActor      *self,
14194                            ClutterActorFlags  flags)
14195 {
14196   ClutterActorFlags old_flags;
14197   GObject *obj;
14198   gboolean was_reactive_set, reactive_set;
14199   gboolean was_realized_set, realized_set;
14200   gboolean was_mapped_set, mapped_set;
14201   gboolean was_visible_set, visible_set;
14202
14203   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14204
14205   obj = G_OBJECT (self);
14206   g_object_freeze_notify (obj);
14207
14208   old_flags = self->flags;
14209
14210   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14211   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14212   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14213   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14214
14215   self->flags &= ~flags;
14216
14217   if (self->flags == old_flags)
14218     return;
14219
14220   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14221   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14222   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14223   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14224
14225   if (reactive_set != was_reactive_set)
14226     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14227
14228   if (realized_set != was_realized_set)
14229     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14230
14231   if (mapped_set != was_mapped_set)
14232     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14233
14234   if (visible_set != was_visible_set)
14235     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14236
14237   g_object_thaw_notify (obj);
14238 }
14239
14240 /**
14241  * clutter_actor_get_transformation_matrix:
14242  * @self: a #ClutterActor
14243  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14244  *
14245  * Retrieves the transformations applied to @self relative to its
14246  * parent.
14247  *
14248  * Since: 1.0
14249  */
14250 void
14251 clutter_actor_get_transformation_matrix (ClutterActor *self,
14252                                          CoglMatrix   *matrix)
14253 {
14254   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14255
14256   cogl_matrix_init_identity (matrix);
14257
14258   _clutter_actor_apply_modelview_transform (self, matrix);
14259 }
14260
14261 void
14262 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14263                                    gboolean      is_in_clone_paint)
14264 {
14265   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14266   self->priv->in_clone_paint = is_in_clone_paint;
14267 }
14268
14269 /**
14270  * clutter_actor_is_in_clone_paint:
14271  * @self: a #ClutterActor
14272  *
14273  * Checks whether @self is being currently painted by a #ClutterClone
14274  *
14275  * This function is useful only inside the ::paint virtual function
14276  * implementations or within handlers for the #ClutterActor::paint
14277  * signal
14278  *
14279  * This function should not be used by applications
14280  *
14281  * Return value: %TRUE if the #ClutterActor is currently being painted
14282  *   by a #ClutterClone, and %FALSE otherwise
14283  *
14284  * Since: 1.0
14285  */
14286 gboolean
14287 clutter_actor_is_in_clone_paint (ClutterActor *self)
14288 {
14289   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14290
14291   return self->priv->in_clone_paint;
14292 }
14293
14294 static gboolean
14295 set_direction_recursive (ClutterActor *actor,
14296                          gpointer      user_data)
14297 {
14298   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14299
14300   clutter_actor_set_text_direction (actor, text_dir);
14301
14302   return TRUE;
14303 }
14304
14305 /**
14306  * clutter_actor_set_text_direction:
14307  * @self: a #ClutterActor
14308  * @text_dir: the text direction for @self
14309  *
14310  * Sets the #ClutterTextDirection for an actor
14311  *
14312  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14313  *
14314  * If @self implements #ClutterContainer then this function will recurse
14315  * inside all the children of @self (including the internal ones).
14316  *
14317  * Composite actors not implementing #ClutterContainer, or actors requiring
14318  * special handling when the text direction changes, should connect to
14319  * the #GObject::notify signal for the #ClutterActor:text-direction property
14320  *
14321  * Since: 1.2
14322  */
14323 void
14324 clutter_actor_set_text_direction (ClutterActor         *self,
14325                                   ClutterTextDirection  text_dir)
14326 {
14327   ClutterActorPrivate *priv;
14328
14329   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14330   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14331
14332   priv = self->priv;
14333
14334   if (priv->text_direction != text_dir)
14335     {
14336       priv->text_direction = text_dir;
14337
14338       /* we need to emit the notify::text-direction first, so that
14339        * the sub-classes can catch that and do specific handling of
14340        * the text direction; see clutter_text_direction_changed_cb()
14341        * inside clutter-text.c
14342        */
14343       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14344
14345       _clutter_actor_foreach_child (self, set_direction_recursive,
14346                                     GINT_TO_POINTER (text_dir));
14347
14348       clutter_actor_queue_relayout (self);
14349     }
14350 }
14351
14352 void
14353 _clutter_actor_set_has_pointer (ClutterActor *self,
14354                                 gboolean      has_pointer)
14355 {
14356   ClutterActorPrivate *priv = self->priv;
14357
14358   if (priv->has_pointer != has_pointer)
14359     {
14360       priv->has_pointer = has_pointer;
14361
14362       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14363     }
14364 }
14365
14366 /**
14367  * clutter_actor_get_text_direction:
14368  * @self: a #ClutterActor
14369  *
14370  * Retrieves the value set using clutter_actor_set_text_direction()
14371  *
14372  * If no text direction has been previously set, the default text
14373  * direction, as returned by clutter_get_default_text_direction(), will
14374  * be returned instead
14375  *
14376  * Return value: the #ClutterTextDirection for the actor
14377  *
14378  * Since: 1.2
14379  */
14380 ClutterTextDirection
14381 clutter_actor_get_text_direction (ClutterActor *self)
14382 {
14383   ClutterActorPrivate *priv;
14384
14385   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14386                         CLUTTER_TEXT_DIRECTION_LTR);
14387
14388   priv = self->priv;
14389
14390   /* if no direction has been set yet use the default */
14391   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14392     priv->text_direction = clutter_get_default_text_direction ();
14393
14394   return priv->text_direction;
14395 }
14396
14397 /**
14398  * clutter_actor_push_internal:
14399  * @self: a #ClutterActor
14400  *
14401  * Should be used by actors implementing the #ClutterContainer and with
14402  * internal children added through clutter_actor_set_parent(), for instance:
14403  *
14404  * |[
14405  *   static void
14406  *   my_actor_init (MyActor *self)
14407  *   {
14408  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14409  *
14410  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14411  *
14412  *     /&ast; calling clutter_actor_set_parent() now will result in
14413  *      &ast; the internal flag being set on a child of MyActor
14414  *      &ast;/
14415  *
14416  *     /&ast; internal child - a background texture &ast;/
14417  *     self->priv->background_tex = clutter_texture_new ();
14418  *     clutter_actor_set_parent (self->priv->background_tex,
14419  *                               CLUTTER_ACTOR (self));
14420  *
14421  *     /&ast; internal child - a label &ast;/
14422  *     self->priv->label = clutter_text_new ();
14423  *     clutter_actor_set_parent (self->priv->label,
14424  *                               CLUTTER_ACTOR (self));
14425  *
14426  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14427  *
14428  *     /&ast; calling clutter_actor_set_parent() now will not result in
14429  *      &ast; the internal flag being set on a child of MyActor
14430  *      &ast;/
14431  *   }
14432  * ]|
14433  *
14434  * This function will be used by Clutter to toggle an "internal child"
14435  * flag whenever clutter_actor_set_parent() is called; internal children
14436  * are handled differently by Clutter, specifically when destroying their
14437  * parent.
14438  *
14439  * Call clutter_actor_pop_internal() when you finished adding internal
14440  * children.
14441  *
14442  * Nested calls to clutter_actor_push_internal() are allowed, but each
14443  * one must by followed by a clutter_actor_pop_internal() call.
14444  *
14445  * Since: 1.2
14446  *
14447  * Deprecated: 1.10: All children of an actor are accessible through
14448  *   the #ClutterActor API, and #ClutterActor implements the
14449  *   #ClutterContainer interface, so this function is only useful
14450  *   for legacy containers overriding the default implementation.
14451  */
14452 void
14453 clutter_actor_push_internal (ClutterActor *self)
14454 {
14455   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14456
14457   self->priv->internal_child += 1;
14458 }
14459
14460 /**
14461  * clutter_actor_pop_internal:
14462  * @self: a #ClutterActor
14463  *
14464  * Disables the effects of clutter_actor_push_internal().
14465  *
14466  * Since: 1.2
14467  *
14468  * Deprecated: 1.10: All children of an actor are accessible through
14469  *   the #ClutterActor API. This function is only useful for legacy
14470  *   containers overriding the default implementation of the
14471  *   #ClutterContainer interface.
14472  */
14473 void
14474 clutter_actor_pop_internal (ClutterActor *self)
14475 {
14476   ClutterActorPrivate *priv;
14477
14478   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14479
14480   priv = self->priv;
14481
14482   if (priv->internal_child == 0)
14483     {
14484       g_warning ("Mismatched %s: you need to call "
14485                  "clutter_actor_push_composite() at least once before "
14486                  "calling this function", G_STRFUNC);
14487       return;
14488     }
14489
14490   priv->internal_child -= 1;
14491 }
14492
14493 /**
14494  * clutter_actor_has_pointer:
14495  * @self: a #ClutterActor
14496  *
14497  * Checks whether an actor contains the pointer of a
14498  * #ClutterInputDevice
14499  *
14500  * Return value: %TRUE if the actor contains the pointer, and
14501  *   %FALSE otherwise
14502  *
14503  * Since: 1.2
14504  */
14505 gboolean
14506 clutter_actor_has_pointer (ClutterActor *self)
14507 {
14508   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14509
14510   return self->priv->has_pointer;
14511 }
14512
14513 /* XXX: This is a workaround for not being able to break the ABI of
14514  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14515  * clutter_actor_queue_clipped_redraw() for details.
14516  */
14517 ClutterPaintVolume *
14518 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14519 {
14520   return g_object_get_data (G_OBJECT (self),
14521                             "-clutter-actor-queue-redraw-clip");
14522 }
14523
14524 void
14525 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14526                                       ClutterPaintVolume *clip)
14527 {
14528   g_object_set_data (G_OBJECT (self),
14529                      "-clutter-actor-queue-redraw-clip",
14530                      clip);
14531 }
14532
14533 /**
14534  * clutter_actor_has_allocation:
14535  * @self: a #ClutterActor
14536  *
14537  * Checks if the actor has an up-to-date allocation assigned to
14538  * it. This means that the actor should have an allocation: it's
14539  * visible and has a parent. It also means that there is no
14540  * outstanding relayout request in progress for the actor or its
14541  * children (There might be other outstanding layout requests in
14542  * progress that will cause the actor to get a new allocation
14543  * when the stage is laid out, however).
14544  *
14545  * If this function returns %FALSE, then the actor will normally
14546  * be allocated before it is next drawn on the screen.
14547  *
14548  * Return value: %TRUE if the actor has an up-to-date allocation
14549  *
14550  * Since: 1.4
14551  */
14552 gboolean
14553 clutter_actor_has_allocation (ClutterActor *self)
14554 {
14555   ClutterActorPrivate *priv;
14556
14557   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14558
14559   priv = self->priv;
14560
14561   return priv->parent != NULL &&
14562          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14563          !priv->needs_allocation;
14564 }
14565
14566 /**
14567  * clutter_actor_add_action:
14568  * @self: a #ClutterActor
14569  * @action: a #ClutterAction
14570  *
14571  * Adds @action to the list of actions applied to @self
14572  *
14573  * A #ClutterAction can only belong to one actor at a time
14574  *
14575  * The #ClutterActor will hold a reference on @action until either
14576  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14577  * is called
14578  *
14579  * Since: 1.4
14580  */
14581 void
14582 clutter_actor_add_action (ClutterActor  *self,
14583                           ClutterAction *action)
14584 {
14585   ClutterActorPrivate *priv;
14586
14587   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14588   g_return_if_fail (CLUTTER_IS_ACTION (action));
14589
14590   priv = self->priv;
14591
14592   if (priv->actions == NULL)
14593     {
14594       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14595       priv->actions->actor = self;
14596     }
14597
14598   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14599
14600   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14601 }
14602
14603 /**
14604  * clutter_actor_add_action_with_name:
14605  * @self: a #ClutterActor
14606  * @name: the name to set on the action
14607  * @action: a #ClutterAction
14608  *
14609  * A convenience function for setting the name of a #ClutterAction
14610  * while adding it to the list of actions applied to @self
14611  *
14612  * This function is the logical equivalent of:
14613  *
14614  * |[
14615  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14616  *   clutter_actor_add_action (self, action);
14617  * ]|
14618  *
14619  * Since: 1.4
14620  */
14621 void
14622 clutter_actor_add_action_with_name (ClutterActor  *self,
14623                                     const gchar   *name,
14624                                     ClutterAction *action)
14625 {
14626   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14627   g_return_if_fail (name != NULL);
14628   g_return_if_fail (CLUTTER_IS_ACTION (action));
14629
14630   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14631   clutter_actor_add_action (self, action);
14632 }
14633
14634 /**
14635  * clutter_actor_remove_action:
14636  * @self: a #ClutterActor
14637  * @action: a #ClutterAction
14638  *
14639  * Removes @action from the list of actions applied to @self
14640  *
14641  * The reference held by @self on the #ClutterAction will be released
14642  *
14643  * Since: 1.4
14644  */
14645 void
14646 clutter_actor_remove_action (ClutterActor  *self,
14647                              ClutterAction *action)
14648 {
14649   ClutterActorPrivate *priv;
14650
14651   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14652   g_return_if_fail (CLUTTER_IS_ACTION (action));
14653
14654   priv = self->priv;
14655
14656   if (priv->actions == NULL)
14657     return;
14658
14659   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14660
14661   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14662 }
14663
14664 /**
14665  * clutter_actor_remove_action_by_name:
14666  * @self: a #ClutterActor
14667  * @name: the name of the action to remove
14668  *
14669  * Removes the #ClutterAction with the given name from the list
14670  * of actions applied to @self
14671  *
14672  * Since: 1.4
14673  */
14674 void
14675 clutter_actor_remove_action_by_name (ClutterActor *self,
14676                                      const gchar  *name)
14677 {
14678   ClutterActorPrivate *priv;
14679   ClutterActorMeta *meta;
14680
14681   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14682   g_return_if_fail (name != NULL);
14683
14684   priv = self->priv;
14685
14686   if (priv->actions == NULL)
14687     return;
14688
14689   meta = _clutter_meta_group_get_meta (priv->actions, name);
14690   if (meta == NULL)
14691     return;
14692
14693   _clutter_meta_group_remove_meta (priv->actions, meta);
14694
14695   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14696 }
14697
14698 /**
14699  * clutter_actor_get_actions:
14700  * @self: a #ClutterActor
14701  *
14702  * Retrieves the list of actions applied to @self
14703  *
14704  * Return value: (transfer container) (element-type Clutter.Action): a copy
14705  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14706  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14707  *   allocated by the returned #GList
14708  *
14709  * Since: 1.4
14710  */
14711 GList *
14712 clutter_actor_get_actions (ClutterActor *self)
14713 {
14714   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14715
14716   if (self->priv->actions == NULL)
14717     return NULL;
14718
14719   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14720 }
14721
14722 /**
14723  * clutter_actor_get_action:
14724  * @self: a #ClutterActor
14725  * @name: the name of the action to retrieve
14726  *
14727  * Retrieves the #ClutterAction with the given name in the list
14728  * of actions applied to @self
14729  *
14730  * Return value: (transfer none): a #ClutterAction for the given
14731  *   name, or %NULL. The returned #ClutterAction is owned by the
14732  *   actor and it should not be unreferenced directly
14733  *
14734  * Since: 1.4
14735  */
14736 ClutterAction *
14737 clutter_actor_get_action (ClutterActor *self,
14738                           const gchar  *name)
14739 {
14740   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14741   g_return_val_if_fail (name != NULL, NULL);
14742
14743   if (self->priv->actions == NULL)
14744     return NULL;
14745
14746   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14747 }
14748
14749 /**
14750  * clutter_actor_clear_actions:
14751  * @self: a #ClutterActor
14752  *
14753  * Clears the list of actions applied to @self
14754  *
14755  * Since: 1.4
14756  */
14757 void
14758 clutter_actor_clear_actions (ClutterActor *self)
14759 {
14760   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14761
14762   if (self->priv->actions == NULL)
14763     return;
14764
14765   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14766 }
14767
14768 /**
14769  * clutter_actor_add_constraint:
14770  * @self: a #ClutterActor
14771  * @constraint: a #ClutterConstraint
14772  *
14773  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14774  * to @self
14775  *
14776  * The #ClutterActor will hold a reference on the @constraint until
14777  * either clutter_actor_remove_constraint() or
14778  * clutter_actor_clear_constraints() is called.
14779  *
14780  * Since: 1.4
14781  */
14782 void
14783 clutter_actor_add_constraint (ClutterActor      *self,
14784                               ClutterConstraint *constraint)
14785 {
14786   ClutterActorPrivate *priv;
14787
14788   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14789   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14790
14791   priv = self->priv;
14792
14793   if (priv->constraints == NULL)
14794     {
14795       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14796       priv->constraints->actor = self;
14797     }
14798
14799   _clutter_meta_group_add_meta (priv->constraints,
14800                                 CLUTTER_ACTOR_META (constraint));
14801   clutter_actor_queue_relayout (self);
14802
14803   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14804 }
14805
14806 /**
14807  * clutter_actor_add_constraint_with_name:
14808  * @self: a #ClutterActor
14809  * @name: the name to set on the constraint
14810  * @constraint: a #ClutterConstraint
14811  *
14812  * A convenience function for setting the name of a #ClutterConstraint
14813  * while adding it to the list of constraints applied to @self
14814  *
14815  * This function is the logical equivalent of:
14816  *
14817  * |[
14818  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14819  *   clutter_actor_add_constraint (self, constraint);
14820  * ]|
14821  *
14822  * Since: 1.4
14823  */
14824 void
14825 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14826                                         const gchar       *name,
14827                                         ClutterConstraint *constraint)
14828 {
14829   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14830   g_return_if_fail (name != NULL);
14831   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14832
14833   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14834   clutter_actor_add_constraint (self, constraint);
14835 }
14836
14837 /**
14838  * clutter_actor_remove_constraint:
14839  * @self: a #ClutterActor
14840  * @constraint: a #ClutterConstraint
14841  *
14842  * Removes @constraint from the list of constraints applied to @self
14843  *
14844  * The reference held by @self on the #ClutterConstraint will be released
14845  *
14846  * Since: 1.4
14847  */
14848 void
14849 clutter_actor_remove_constraint (ClutterActor      *self,
14850                                  ClutterConstraint *constraint)
14851 {
14852   ClutterActorPrivate *priv;
14853
14854   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14855   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14856
14857   priv = self->priv;
14858
14859   if (priv->constraints == NULL)
14860     return;
14861
14862   _clutter_meta_group_remove_meta (priv->constraints,
14863                                    CLUTTER_ACTOR_META (constraint));
14864   clutter_actor_queue_relayout (self);
14865
14866   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14867 }
14868
14869 /**
14870  * clutter_actor_remove_constraint_by_name:
14871  * @self: a #ClutterActor
14872  * @name: the name of the constraint to remove
14873  *
14874  * Removes the #ClutterConstraint with the given name from the list
14875  * of constraints applied to @self
14876  *
14877  * Since: 1.4
14878  */
14879 void
14880 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14881                                          const gchar  *name)
14882 {
14883   ClutterActorPrivate *priv;
14884   ClutterActorMeta *meta;
14885
14886   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14887   g_return_if_fail (name != NULL);
14888
14889   priv = self->priv;
14890
14891   if (priv->constraints == NULL)
14892     return;
14893
14894   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14895   if (meta == NULL)
14896     return;
14897
14898   _clutter_meta_group_remove_meta (priv->constraints, meta);
14899   clutter_actor_queue_relayout (self);
14900 }
14901
14902 /**
14903  * clutter_actor_get_constraints:
14904  * @self: a #ClutterActor
14905  *
14906  * Retrieves the list of constraints applied to @self
14907  *
14908  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14909  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14910  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14911  *   allocated by the returned #GList
14912  *
14913  * Since: 1.4
14914  */
14915 GList *
14916 clutter_actor_get_constraints (ClutterActor *self)
14917 {
14918   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14919
14920   if (self->priv->constraints == NULL)
14921     return NULL;
14922
14923   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14924 }
14925
14926 /**
14927  * clutter_actor_get_constraint:
14928  * @self: a #ClutterActor
14929  * @name: the name of the constraint to retrieve
14930  *
14931  * Retrieves the #ClutterConstraint with the given name in the list
14932  * of constraints applied to @self
14933  *
14934  * Return value: (transfer none): a #ClutterConstraint for the given
14935  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14936  *   actor and it should not be unreferenced directly
14937  *
14938  * Since: 1.4
14939  */
14940 ClutterConstraint *
14941 clutter_actor_get_constraint (ClutterActor *self,
14942                               const gchar  *name)
14943 {
14944   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14945   g_return_val_if_fail (name != NULL, NULL);
14946
14947   if (self->priv->constraints == NULL)
14948     return NULL;
14949
14950   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14951 }
14952
14953 /**
14954  * clutter_actor_clear_constraints:
14955  * @self: a #ClutterActor
14956  *
14957  * Clears the list of constraints applied to @self
14958  *
14959  * Since: 1.4
14960  */
14961 void
14962 clutter_actor_clear_constraints (ClutterActor *self)
14963 {
14964   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14965
14966   if (self->priv->constraints == NULL)
14967     return;
14968
14969   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14970
14971   clutter_actor_queue_relayout (self);
14972 }
14973
14974 /**
14975  * clutter_actor_set_clip_to_allocation:
14976  * @self: a #ClutterActor
14977  * @clip_set: %TRUE to apply a clip tracking the allocation
14978  *
14979  * Sets whether @self should be clipped to the same size as its
14980  * allocation
14981  *
14982  * Since: 1.4
14983  */
14984 void
14985 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14986                                       gboolean      clip_set)
14987 {
14988   ClutterActorPrivate *priv;
14989
14990   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14991
14992   clip_set = !!clip_set;
14993
14994   priv = self->priv;
14995
14996   if (priv->clip_to_allocation != clip_set)
14997     {
14998       priv->clip_to_allocation = clip_set;
14999
15000       clutter_actor_queue_redraw (self);
15001
15002       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15003     }
15004 }
15005
15006 /**
15007  * clutter_actor_get_clip_to_allocation:
15008  * @self: a #ClutterActor
15009  *
15010  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15011  *
15012  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15013  *
15014  * Since: 1.4
15015  */
15016 gboolean
15017 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15018 {
15019   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15020
15021   return self->priv->clip_to_allocation;
15022 }
15023
15024 /**
15025  * clutter_actor_add_effect:
15026  * @self: a #ClutterActor
15027  * @effect: a #ClutterEffect
15028  *
15029  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15030  *
15031  * The #ClutterActor will hold a reference on the @effect until either
15032  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15033  * called.
15034  *
15035  * Since: 1.4
15036  */
15037 void
15038 clutter_actor_add_effect (ClutterActor  *self,
15039                           ClutterEffect *effect)
15040 {
15041   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15042   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15043
15044   _clutter_actor_add_effect_internal (self, effect);
15045
15046   clutter_actor_queue_redraw (self);
15047
15048   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15049 }
15050
15051 /**
15052  * clutter_actor_add_effect_with_name:
15053  * @self: a #ClutterActor
15054  * @name: the name to set on the effect
15055  * @effect: a #ClutterEffect
15056  *
15057  * A convenience function for setting the name of a #ClutterEffect
15058  * while adding it to the list of effectss applied to @self
15059  *
15060  * This function is the logical equivalent of:
15061  *
15062  * |[
15063  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15064  *   clutter_actor_add_effect (self, effect);
15065  * ]|
15066  *
15067  * Since: 1.4
15068  */
15069 void
15070 clutter_actor_add_effect_with_name (ClutterActor  *self,
15071                                     const gchar   *name,
15072                                     ClutterEffect *effect)
15073 {
15074   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15075   g_return_if_fail (name != NULL);
15076   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15077
15078   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15079   clutter_actor_add_effect (self, effect);
15080 }
15081
15082 /**
15083  * clutter_actor_remove_effect:
15084  * @self: a #ClutterActor
15085  * @effect: a #ClutterEffect
15086  *
15087  * Removes @effect from the list of effects applied to @self
15088  *
15089  * The reference held by @self on the #ClutterEffect will be released
15090  *
15091  * Since: 1.4
15092  */
15093 void
15094 clutter_actor_remove_effect (ClutterActor  *self,
15095                              ClutterEffect *effect)
15096 {
15097   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15098   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15099
15100   _clutter_actor_remove_effect_internal (self, effect);
15101
15102   clutter_actor_queue_redraw (self);
15103
15104   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15105 }
15106
15107 /**
15108  * clutter_actor_remove_effect_by_name:
15109  * @self: a #ClutterActor
15110  * @name: the name of the effect to remove
15111  *
15112  * Removes the #ClutterEffect with the given name from the list
15113  * of effects applied to @self
15114  *
15115  * Since: 1.4
15116  */
15117 void
15118 clutter_actor_remove_effect_by_name (ClutterActor *self,
15119                                      const gchar  *name)
15120 {
15121   ClutterActorPrivate *priv;
15122   ClutterActorMeta *meta;
15123
15124   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15125   g_return_if_fail (name != NULL);
15126
15127   priv = self->priv;
15128
15129   if (priv->effects == NULL)
15130     return;
15131
15132   meta = _clutter_meta_group_get_meta (priv->effects, name);
15133   if (meta == NULL)
15134     return;
15135
15136   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15137 }
15138
15139 /**
15140  * clutter_actor_get_effects:
15141  * @self: a #ClutterActor
15142  *
15143  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15144  *
15145  * Return value: (transfer container) (element-type Clutter.Effect): a list
15146  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15147  *   list are owned by Clutter and they should not be freed. You should
15148  *   free the returned list using g_list_free() when done
15149  *
15150  * Since: 1.4
15151  */
15152 GList *
15153 clutter_actor_get_effects (ClutterActor *self)
15154 {
15155   ClutterActorPrivate *priv;
15156
15157   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15158
15159   priv = self->priv;
15160
15161   if (priv->effects == NULL)
15162     return NULL;
15163
15164   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15165 }
15166
15167 /**
15168  * clutter_actor_get_effect:
15169  * @self: a #ClutterActor
15170  * @name: the name of the effect to retrieve
15171  *
15172  * Retrieves the #ClutterEffect with the given name in the list
15173  * of effects applied to @self
15174  *
15175  * Return value: (transfer none): a #ClutterEffect for the given
15176  *   name, or %NULL. The returned #ClutterEffect is owned by the
15177  *   actor and it should not be unreferenced directly
15178  *
15179  * Since: 1.4
15180  */
15181 ClutterEffect *
15182 clutter_actor_get_effect (ClutterActor *self,
15183                           const gchar  *name)
15184 {
15185   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15186   g_return_val_if_fail (name != NULL, NULL);
15187
15188   if (self->priv->effects == NULL)
15189     return NULL;
15190
15191   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15192 }
15193
15194 /**
15195  * clutter_actor_clear_effects:
15196  * @self: a #ClutterActor
15197  *
15198  * Clears the list of effects applied to @self
15199  *
15200  * Since: 1.4
15201  */
15202 void
15203 clutter_actor_clear_effects (ClutterActor *self)
15204 {
15205   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15206
15207   if (self->priv->effects == NULL)
15208     return;
15209
15210   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15211
15212   clutter_actor_queue_redraw (self);
15213 }
15214
15215 /**
15216  * clutter_actor_has_key_focus:
15217  * @self: a #ClutterActor
15218  *
15219  * Checks whether @self is the #ClutterActor that has key focus
15220  *
15221  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15222  *
15223  * Since: 1.4
15224  */
15225 gboolean
15226 clutter_actor_has_key_focus (ClutterActor *self)
15227 {
15228   ClutterActor *stage;
15229
15230   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15231
15232   stage = _clutter_actor_get_stage_internal (self);
15233   if (stage == NULL)
15234     return FALSE;
15235
15236   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15237 }
15238
15239 static gboolean
15240 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15241                                       ClutterPaintVolume *pv)
15242 {
15243   ClutterActorPrivate *priv = self->priv;
15244
15245   /* Actors are only expected to report a valid paint volume
15246    * while they have a valid allocation. */
15247   if (G_UNLIKELY (priv->needs_allocation))
15248     {
15249       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15250                     "Actor needs allocation",
15251                     _clutter_actor_get_debug_name (self));
15252       return FALSE;
15253     }
15254
15255   /* Check if there are any handlers connected to the paint
15256    * signal. If there are then all bets are off for what the paint
15257    * volume for this actor might possibly be!
15258    *
15259    * XXX: It's expected that this is going to end up being quite a
15260    * costly check to have to do here, but we haven't come up with
15261    * another solution that can reliably catch paint signal handlers at
15262    * the right time to either avoid artefacts due to invalid stage
15263    * clipping or due to incorrect culling.
15264    *
15265    * Previously we checked in clutter_actor_paint(), but at that time
15266    * we may already be using a stage clip that could be derived from
15267    * an invalid paint-volume. We used to try and handle that by
15268    * queuing a follow up, unclipped, redraw but still the previous
15269    * checking wasn't enough to catch invalid volumes involved in
15270    * culling (considering that containers may derive their volume from
15271    * children that haven't yet been painted)
15272    *
15273    * Longer term, improved solutions could be:
15274    * - Disallow painting in the paint signal, only allow using it
15275    *   for tracking when paints happen. We can add another API that
15276    *   allows monkey patching the paint of arbitrary actors but in a
15277    *   more controlled way and that also supports modifying the
15278    *   paint-volume.
15279    * - If we could be notified somehow when signal handlers are
15280    *   connected we wouldn't have to poll for handlers like this.
15281    */
15282   if (g_signal_has_handler_pending (self,
15283                                     actor_signals[PAINT],
15284                                     0,
15285                                     TRUE))
15286     {
15287       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15288                     "Actor has \"paint\" signal handlers",
15289                     _clutter_actor_get_debug_name (self));
15290       return FALSE;
15291     }
15292
15293   _clutter_paint_volume_init_static (pv, self);
15294
15295   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15296     {
15297       clutter_paint_volume_free (pv);
15298       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15299                     "Actor failed to report a volume",
15300                     _clutter_actor_get_debug_name (self));
15301       return FALSE;
15302     }
15303
15304   /* since effects can modify the paint volume, we allow them to actually
15305    * do this by making get_paint_volume() "context sensitive"
15306    */
15307   if (priv->effects != NULL)
15308     {
15309       if (priv->current_effect != NULL)
15310         {
15311           const GList *effects, *l;
15312
15313           /* if we are being called from within the paint sequence of
15314            * an actor, get the paint volume up to the current effect
15315            */
15316           effects = _clutter_meta_group_peek_metas (priv->effects);
15317           for (l = effects;
15318                l != NULL || (l != NULL && l->data != priv->current_effect);
15319                l = l->next)
15320             {
15321               if (!_clutter_effect_get_paint_volume (l->data, pv))
15322                 {
15323                   clutter_paint_volume_free (pv);
15324                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15325                                 "Effect (%s) failed to report a volume",
15326                                 _clutter_actor_get_debug_name (self),
15327                                 _clutter_actor_meta_get_debug_name (l->data));
15328                   return FALSE;
15329                 }
15330             }
15331         }
15332       else
15333         {
15334           const GList *effects, *l;
15335
15336           /* otherwise, get the cumulative volume */
15337           effects = _clutter_meta_group_peek_metas (priv->effects);
15338           for (l = effects; l != NULL; l = l->next)
15339             if (!_clutter_effect_get_paint_volume (l->data, pv))
15340               {
15341                 clutter_paint_volume_free (pv);
15342                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15343                               "Effect (%s) failed to report a volume",
15344                               _clutter_actor_get_debug_name (self),
15345                               _clutter_actor_meta_get_debug_name (l->data));
15346                 return FALSE;
15347               }
15348         }
15349     }
15350
15351   return TRUE;
15352 }
15353
15354 /* The public clutter_actor_get_paint_volume API returns a const
15355  * pointer since we return a pointer directly to the cached
15356  * PaintVolume associated with the actor and don't want the user to
15357  * inadvertently modify it, but for internal uses we sometimes need
15358  * access to the same PaintVolume but need to apply some book-keeping
15359  * modifications to it so we don't want a const pointer.
15360  */
15361 static ClutterPaintVolume *
15362 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15363 {
15364   ClutterActorPrivate *priv;
15365
15366   priv = self->priv;
15367
15368   if (priv->paint_volume_valid)
15369     clutter_paint_volume_free (&priv->paint_volume);
15370
15371   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15372     {
15373       priv->paint_volume_valid = TRUE;
15374       return &priv->paint_volume;
15375     }
15376   else
15377     {
15378       priv->paint_volume_valid = FALSE;
15379       return NULL;
15380     }
15381 }
15382
15383 /**
15384  * clutter_actor_get_paint_volume:
15385  * @self: a #ClutterActor
15386  *
15387  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15388  * when a paint volume can't be determined.
15389  *
15390  * The paint volume is defined as the 3D space occupied by an actor
15391  * when being painted.
15392  *
15393  * This function will call the <function>get_paint_volume()</function>
15394  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15395  * should not usually care about overriding the default implementation,
15396  * unless they are, for instance: painting outside their allocation, or
15397  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15398  * 3D depth).
15399  *
15400  * <note>2D actors overriding <function>get_paint_volume()</function>
15401  * ensure their volume has a depth of 0. (This will be true so long as
15402  * you don't call clutter_paint_volume_set_depth().)</note>
15403  *
15404  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15405  *   or %NULL if no volume could be determined. The returned pointer
15406  *   is not guaranteed to be valid across multiple frames; if you want
15407  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15408  *
15409  * Since: 1.6
15410  */
15411 const ClutterPaintVolume *
15412 clutter_actor_get_paint_volume (ClutterActor *self)
15413 {
15414   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15415
15416   return _clutter_actor_get_paint_volume_mutable (self);
15417 }
15418
15419 /**
15420  * clutter_actor_get_transformed_paint_volume:
15421  * @self: a #ClutterActor
15422  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15423  *    (or %NULL for the stage)
15424  *
15425  * Retrieves the 3D paint volume of an actor like
15426  * clutter_actor_get_paint_volume() does (Please refer to the
15427  * documentation of clutter_actor_get_paint_volume() for more
15428  * details.) and it additionally transforms the paint volume into the
15429  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15430  * is passed for @relative_to_ancestor)
15431  *
15432  * This can be used by containers that base their paint volume on
15433  * the volume of their children. Such containers can query the
15434  * transformed paint volume of all of its children and union them
15435  * together using clutter_paint_volume_union().
15436  *
15437  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15438  *   or %NULL if no volume could be determined. The returned pointer is
15439  *   not guaranteed to be valid across multiple frames; if you wish to
15440  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15441  *
15442  * Since: 1.6
15443  */
15444 const ClutterPaintVolume *
15445 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15446                                             ClutterActor *relative_to_ancestor)
15447 {
15448   const ClutterPaintVolume *volume;
15449   ClutterActor *stage;
15450   ClutterPaintVolume *transformed_volume;
15451
15452   stage = _clutter_actor_get_stage_internal (self);
15453   if (G_UNLIKELY (stage == NULL))
15454     return NULL;
15455
15456   if (relative_to_ancestor == NULL)
15457     relative_to_ancestor = stage;
15458
15459   volume = clutter_actor_get_paint_volume (self);
15460   if (volume == NULL)
15461     return NULL;
15462
15463   transformed_volume =
15464     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15465
15466   _clutter_paint_volume_copy_static (volume, transformed_volume);
15467
15468   _clutter_paint_volume_transform_relative (transformed_volume,
15469                                             relative_to_ancestor);
15470
15471   return transformed_volume;
15472 }
15473
15474 /**
15475  * clutter_actor_get_paint_box:
15476  * @self: a #ClutterActor
15477  * @box: (out): return location for a #ClutterActorBox
15478  *
15479  * Retrieves the paint volume of the passed #ClutterActor, and
15480  * transforms it into a 2D bounding box in stage coordinates.
15481  *
15482  * This function is useful to determine the on screen area occupied by
15483  * the actor. The box is only an approximation and may often be
15484  * considerably larger due to the optimizations used to calculate the
15485  * box. The box is never smaller though, so it can reliably be used
15486  * for culling.
15487  *
15488  * There are times when a 2D paint box can't be determined, e.g.
15489  * because the actor isn't yet parented under a stage or because
15490  * the actor is unable to determine a paint volume.
15491  *
15492  * Return value: %TRUE if a 2D paint box could be determined, else
15493  * %FALSE.
15494  *
15495  * Since: 1.6
15496  */
15497 gboolean
15498 clutter_actor_get_paint_box (ClutterActor    *self,
15499                              ClutterActorBox *box)
15500 {
15501   ClutterActor *stage;
15502   ClutterPaintVolume *pv;
15503
15504   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15505   g_return_val_if_fail (box != NULL, FALSE);
15506
15507   stage = _clutter_actor_get_stage_internal (self);
15508   if (G_UNLIKELY (!stage))
15509     return FALSE;
15510
15511   pv = _clutter_actor_get_paint_volume_mutable (self);
15512   if (G_UNLIKELY (!pv))
15513     return FALSE;
15514
15515   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15516
15517   return TRUE;
15518 }
15519
15520 /**
15521  * clutter_actor_has_overlaps:
15522  * @self: A #ClutterActor
15523  *
15524  * Asks the actor's implementation whether it may contain overlapping
15525  * primitives.
15526  *
15527  * For example; Clutter may use this to determine whether the painting
15528  * should be redirected to an offscreen buffer to correctly implement
15529  * the opacity property.
15530  *
15531  * Custom actors can override the default response by implementing the
15532  * #ClutterActor <function>has_overlaps</function> virtual function. See
15533  * clutter_actor_set_offscreen_redirect() for more information.
15534  *
15535  * Return value: %TRUE if the actor may have overlapping primitives, and
15536  *   %FALSE otherwise
15537  *
15538  * Since: 1.8
15539  */
15540 gboolean
15541 clutter_actor_has_overlaps (ClutterActor *self)
15542 {
15543   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15544
15545   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15546 }
15547
15548 /**
15549  * clutter_actor_has_effects:
15550  * @self: A #ClutterActor
15551  *
15552  * Returns whether the actor has any effects applied.
15553  *
15554  * Return value: %TRUE if the actor has any effects,
15555  *   %FALSE otherwise
15556  *
15557  * Since: 1.10
15558  */
15559 gboolean
15560 clutter_actor_has_effects (ClutterActor *self)
15561 {
15562   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15563
15564   if (self->priv->effects == NULL)
15565     return FALSE;
15566
15567   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15568 }
15569
15570 /**
15571  * clutter_actor_has_constraints:
15572  * @self: A #ClutterActor
15573  *
15574  * Returns whether the actor has any constraints applied.
15575  *
15576  * Return value: %TRUE if the actor has any constraints,
15577  *   %FALSE otherwise
15578  *
15579  * Since: 1.10
15580  */
15581 gboolean
15582 clutter_actor_has_constraints (ClutterActor *self)
15583 {
15584   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15585
15586   return self->priv->constraints != NULL;
15587 }
15588
15589 /**
15590  * clutter_actor_has_actions:
15591  * @self: A #ClutterActor
15592  *
15593  * Returns whether the actor has any actions applied.
15594  *
15595  * Return value: %TRUE if the actor has any actions,
15596  *   %FALSE otherwise
15597  *
15598  * Since: 1.10
15599  */
15600 gboolean
15601 clutter_actor_has_actions (ClutterActor *self)
15602 {
15603   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15604
15605   return self->priv->actions != NULL;
15606 }
15607
15608 /**
15609  * clutter_actor_get_n_children:
15610  * @self: a #ClutterActor
15611  *
15612  * Retrieves the number of children of @self.
15613  *
15614  * Return value: the number of children of an actor
15615  *
15616  * Since: 1.10
15617  */
15618 gint
15619 clutter_actor_get_n_children (ClutterActor *self)
15620 {
15621   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15622
15623   return self->priv->n_children;
15624 }
15625
15626 /**
15627  * clutter_actor_get_child_at_index:
15628  * @self: a #ClutterActor
15629  * @index_: the position in the list of children
15630  *
15631  * Retrieves the actor at the given @index_ inside the list of
15632  * children of @self.
15633  *
15634  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15635  *
15636  * Since: 1.10
15637  */
15638 ClutterActor *
15639 clutter_actor_get_child_at_index (ClutterActor *self,
15640                                   gint          index_)
15641 {
15642   ClutterActor *iter;
15643   int i;
15644
15645   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15646   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15647
15648   for (iter = self->priv->first_child, i = 0;
15649        iter != NULL && i < index_;
15650        iter = iter->priv->next_sibling, i += 1)
15651     ;
15652
15653   return iter;
15654 }
15655
15656 /*< private >
15657  * _clutter_actor_foreach_child:
15658  * @actor: The actor whos children you want to iterate
15659  * @callback: The function to call for each child
15660  * @user_data: Private data to pass to @callback
15661  *
15662  * Calls a given @callback once for each child of the specified @actor and
15663  * passing the @user_data pointer each time.
15664  *
15665  * Return value: returns %TRUE if all children were iterated, else
15666  *    %FALSE if a callback broke out of iteration early.
15667  */
15668 gboolean
15669 _clutter_actor_foreach_child (ClutterActor           *self,
15670                               ClutterForeachCallback  callback,
15671                               gpointer                user_data)
15672 {
15673   ClutterActorPrivate *priv = self->priv;
15674   ClutterActor *iter;
15675   gboolean cont;
15676
15677   for (cont = TRUE, iter = priv->first_child;
15678        cont && iter != NULL;
15679        iter = iter->priv->next_sibling)
15680     {
15681       cont = callback (iter, user_data);
15682     }
15683
15684   return cont;
15685 }
15686
15687 #if 0
15688 /* For debugging purposes this gives us a simple way to print out
15689  * the scenegraph e.g in gdb using:
15690  * [|
15691  *   _clutter_actor_traverse (stage,
15692  *                            0,
15693  *                            clutter_debug_print_actor_cb,
15694  *                            NULL,
15695  *                            NULL);
15696  * |]
15697  */
15698 static ClutterActorTraverseVisitFlags
15699 clutter_debug_print_actor_cb (ClutterActor *actor,
15700                               int depth,
15701                               void *user_data)
15702 {
15703   g_print ("%*s%s:%p\n",
15704            depth * 2, "",
15705            _clutter_actor_get_debug_name (actor),
15706            actor);
15707
15708   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15709 }
15710 #endif
15711
15712 static void
15713 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15714                                  ClutterTraverseCallback callback,
15715                                  gpointer                user_data)
15716 {
15717   GQueue *queue = g_queue_new ();
15718   ClutterActor dummy;
15719   int current_depth = 0;
15720
15721   g_queue_push_tail (queue, actor);
15722   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15723
15724   while ((actor = g_queue_pop_head (queue)))
15725     {
15726       ClutterActorTraverseVisitFlags flags;
15727
15728       if (actor == &dummy)
15729         {
15730           current_depth++;
15731           g_queue_push_tail (queue, &dummy);
15732           continue;
15733         }
15734
15735       flags = callback (actor, current_depth, user_data);
15736       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15737         break;
15738       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15739         {
15740           ClutterActor *iter;
15741
15742           for (iter = actor->priv->first_child;
15743                iter != NULL;
15744                iter = iter->priv->next_sibling)
15745             {
15746               g_queue_push_tail (queue, iter);
15747             }
15748         }
15749     }
15750
15751   g_queue_free (queue);
15752 }
15753
15754 static ClutterActorTraverseVisitFlags
15755 _clutter_actor_traverse_depth (ClutterActor           *actor,
15756                                ClutterTraverseCallback before_children_callback,
15757                                ClutterTraverseCallback after_children_callback,
15758                                int                     current_depth,
15759                                gpointer                user_data)
15760 {
15761   ClutterActorTraverseVisitFlags flags;
15762
15763   flags = before_children_callback (actor, current_depth, user_data);
15764   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15765     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15766
15767   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15768     {
15769       ClutterActor *iter;
15770
15771       for (iter = actor->priv->first_child;
15772            iter != NULL;
15773            iter = iter->priv->next_sibling)
15774         {
15775           flags = _clutter_actor_traverse_depth (iter,
15776                                                  before_children_callback,
15777                                                  after_children_callback,
15778                                                  current_depth + 1,
15779                                                  user_data);
15780
15781           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15782             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15783         }
15784     }
15785
15786   if (after_children_callback)
15787     return after_children_callback (actor, current_depth, user_data);
15788   else
15789     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15790 }
15791
15792 /* _clutter_actor_traverse:
15793  * @actor: The actor to start traversing the graph from
15794  * @flags: These flags may affect how the traversal is done
15795  * @before_children_callback: A function to call before visiting the
15796  *   children of the current actor.
15797  * @after_children_callback: A function to call after visiting the
15798  *   children of the current actor. (Ignored if
15799  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15800  * @user_data: The private data to pass to the callbacks
15801  *
15802  * Traverses the scenegraph starting at the specified @actor and
15803  * descending through all its children and its children's children.
15804  * For each actor traversed @before_children_callback and
15805  * @after_children_callback are called with the specified
15806  * @user_data, before and after visiting that actor's children.
15807  *
15808  * The callbacks can return flags that affect the ongoing traversal
15809  * such as by skipping over an actors children or bailing out of
15810  * any further traversing.
15811  */
15812 void
15813 _clutter_actor_traverse (ClutterActor              *actor,
15814                          ClutterActorTraverseFlags  flags,
15815                          ClutterTraverseCallback    before_children_callback,
15816                          ClutterTraverseCallback    after_children_callback,
15817                          gpointer                   user_data)
15818 {
15819   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15820     _clutter_actor_traverse_breadth (actor,
15821                                      before_children_callback,
15822                                      user_data);
15823   else /* DEPTH_FIRST */
15824     _clutter_actor_traverse_depth (actor,
15825                                    before_children_callback,
15826                                    after_children_callback,
15827                                    0, /* start depth */
15828                                    user_data);
15829 }
15830
15831 static void
15832 on_layout_manager_changed (ClutterLayoutManager *manager,
15833                            ClutterActor         *self)
15834 {
15835   clutter_actor_queue_relayout (self);
15836 }
15837
15838 /**
15839  * clutter_actor_set_layout_manager:
15840  * @self: a #ClutterActor
15841  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15842  *
15843  * Sets the #ClutterLayoutManager delegate object that will be used to
15844  * lay out the children of @self.
15845  *
15846  * The #ClutterActor will take a reference on the passed @manager which
15847  * will be released either when the layout manager is removed, or when
15848  * the actor is destroyed.
15849  *
15850  * Since: 1.10
15851  */
15852 void
15853 clutter_actor_set_layout_manager (ClutterActor         *self,
15854                                   ClutterLayoutManager *manager)
15855 {
15856   ClutterActorPrivate *priv;
15857
15858   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15859   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15860
15861   priv = self->priv;
15862
15863   if (priv->layout_manager != NULL)
15864     {
15865       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15866                                             G_CALLBACK (on_layout_manager_changed),
15867                                             self);
15868       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15869       g_object_unref (priv->layout_manager);
15870     }
15871
15872   priv->layout_manager = manager;
15873
15874   if (priv->layout_manager != NULL)
15875     {
15876       g_object_ref_sink (priv->layout_manager);
15877       clutter_layout_manager_set_container (priv->layout_manager,
15878                                             CLUTTER_CONTAINER (self));
15879       g_signal_connect (priv->layout_manager, "layout-changed",
15880                         G_CALLBACK (on_layout_manager_changed),
15881                         self);
15882     }
15883
15884   clutter_actor_queue_relayout (self);
15885
15886   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15887 }
15888
15889 /**
15890  * clutter_actor_get_layout_manager:
15891  * @self: a #ClutterActor
15892  *
15893  * Retrieves the #ClutterLayoutManager used by @self.
15894  *
15895  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15896  *   or %NULL
15897  *
15898  * Since: 1.10
15899  */
15900 ClutterLayoutManager *
15901 clutter_actor_get_layout_manager (ClutterActor *self)
15902 {
15903   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15904
15905   return self->priv->layout_manager;
15906 }
15907
15908 static const ClutterLayoutInfo default_layout_info = {
15909   0.f,                          /* fixed-x */
15910   0.f,                          /* fixed-y */
15911   { 0, 0, 0, 0 },               /* margin */
15912   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15913   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15914   0.f, 0.f,                     /* min_width, natural_width */
15915   0.f, 0.f,                     /* natual_width, natural_height */
15916 };
15917
15918 static void
15919 layout_info_free (gpointer data)
15920 {
15921   if (G_LIKELY (data != NULL))
15922     g_slice_free (ClutterLayoutInfo, data);
15923 }
15924
15925 /*< private >
15926  * _clutter_actor_get_layout_info:
15927  * @self: a #ClutterActor
15928  *
15929  * Retrieves a pointer to the ClutterLayoutInfo structure.
15930  *
15931  * If the actor does not have a ClutterLayoutInfo associated to it, one
15932  * will be created and initialized to the default values.
15933  *
15934  * This function should be used for setters.
15935  *
15936  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15937  * instead.
15938  *
15939  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15940  */
15941 ClutterLayoutInfo *
15942 _clutter_actor_get_layout_info (ClutterActor *self)
15943 {
15944   ClutterLayoutInfo *retval;
15945
15946   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15947   if (retval == NULL)
15948     {
15949       retval = g_slice_new (ClutterLayoutInfo);
15950
15951       *retval = default_layout_info;
15952
15953       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15954                                retval,
15955                                layout_info_free);
15956     }
15957
15958   return retval;
15959 }
15960
15961 /*< private >
15962  * _clutter_actor_get_layout_info_or_defaults:
15963  * @self: a #ClutterActor
15964  *
15965  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15966  *
15967  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15968  * then the default structure will be returned.
15969  *
15970  * This function should only be used for getters.
15971  *
15972  * Return value: a const pointer to the ClutterLayoutInfo structure
15973  */
15974 const ClutterLayoutInfo *
15975 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15976 {
15977   const ClutterLayoutInfo *info;
15978
15979   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15980   if (info == NULL)
15981     return &default_layout_info;
15982
15983   return info;
15984 }
15985
15986 /**
15987  * clutter_actor_set_x_align:
15988  * @self: a #ClutterActor
15989  * @x_align: the horizontal alignment policy
15990  *
15991  * Sets the horizontal alignment policy of a #ClutterActor, in case the
15992  * actor received extra horizontal space.
15993  *
15994  * See also the #ClutterActor:x-align property.
15995  *
15996  * Since: 1.10
15997  */
15998 void
15999 clutter_actor_set_x_align (ClutterActor      *self,
16000                            ClutterActorAlign  x_align)
16001 {
16002   ClutterLayoutInfo *info;
16003
16004   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16005
16006   info = _clutter_actor_get_layout_info (self);
16007
16008   if (info->x_align != x_align)
16009     {
16010       info->x_align = x_align;
16011
16012       clutter_actor_queue_relayout (self);
16013
16014       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16015     }
16016 }
16017
16018 /**
16019  * clutter_actor_get_x_align:
16020  * @self: a #ClutterActor
16021  *
16022  * Retrieves the horizontal alignment policy set using
16023  * clutter_actor_set_x_align().
16024  *
16025  * Return value: the horizontal alignment policy.
16026  *
16027  * Since: 1.10
16028  */
16029 ClutterActorAlign
16030 clutter_actor_get_x_align (ClutterActor *self)
16031 {
16032   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16033
16034   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16035 }
16036
16037 /**
16038  * clutter_actor_set_y_align:
16039  * @self: a #ClutterActor
16040  * @y_align: the vertical alignment policy
16041  *
16042  * Sets the vertical alignment policy of a #ClutterActor, in case the
16043  * actor received extra vertical space.
16044  *
16045  * See also the #ClutterActor:y-align property.
16046  *
16047  * Since: 1.10
16048  */
16049 void
16050 clutter_actor_set_y_align (ClutterActor      *self,
16051                            ClutterActorAlign  y_align)
16052 {
16053   ClutterLayoutInfo *info;
16054
16055   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16056
16057   info = _clutter_actor_get_layout_info (self);
16058
16059   if (info->y_align != y_align)
16060     {
16061       info->y_align = y_align;
16062
16063       clutter_actor_queue_relayout (self);
16064
16065       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16066     }
16067 }
16068
16069 /**
16070  * clutter_actor_get_y_align:
16071  * @self: a #ClutterActor
16072  *
16073  * Retrieves the vertical alignment policy set using
16074  * clutter_actor_set_y_align().
16075  *
16076  * Return value: the vertical alignment policy.
16077  *
16078  * Since: 1.10
16079  */
16080 ClutterActorAlign
16081 clutter_actor_get_y_align (ClutterActor *self)
16082 {
16083   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16084
16085   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16086 }
16087
16088
16089 /**
16090  * clutter_margin_new:
16091  *
16092  * Creates a new #ClutterMargin.
16093  *
16094  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16095  *   clutter_margin_free() to free the resources associated with it when
16096  *   done.
16097  *
16098  * Since: 1.10
16099  */
16100 ClutterMargin *
16101 clutter_margin_new (void)
16102 {
16103   return g_slice_new0 (ClutterMargin);
16104 }
16105
16106 /**
16107  * clutter_margin_copy:
16108  * @margin_: a #ClutterMargin
16109  *
16110  * Creates a new #ClutterMargin and copies the contents of @margin_ into
16111  * the newly created structure.
16112  *
16113  * Return value: (transfer full): a copy of the #ClutterMargin.
16114  *
16115  * Since: 1.10
16116  */
16117 ClutterMargin *
16118 clutter_margin_copy (const ClutterMargin *margin_)
16119 {
16120   if (G_LIKELY (margin_ != NULL))
16121     return g_slice_dup (ClutterMargin, margin_);
16122
16123   return NULL;
16124 }
16125
16126 /**
16127  * clutter_margin_free:
16128  * @margin_: a #ClutterMargin
16129  *
16130  * Frees the resources allocated by clutter_margin_new() and
16131  * clutter_margin_copy().
16132  *
16133  * Since: 1.10
16134  */
16135 void
16136 clutter_margin_free (ClutterMargin *margin_)
16137 {
16138   if (G_LIKELY (margin_ != NULL))
16139     g_slice_free (ClutterMargin, margin_);
16140 }
16141
16142 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16143                      clutter_margin_copy,
16144                      clutter_margin_free)
16145
16146 /**
16147  * clutter_actor_set_margin:
16148  * @self: a #ClutterActor
16149  * @margin: a #ClutterMargin
16150  *
16151  * Sets all the components of the margin of a #ClutterActor.
16152  *
16153  * Since: 1.10
16154  */
16155 void
16156 clutter_actor_set_margin (ClutterActor        *self,
16157                           const ClutterMargin *margin)
16158 {
16159   ClutterLayoutInfo *info;
16160   gboolean changed;
16161   GObject *obj;
16162
16163   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16164   g_return_if_fail (margin != NULL);
16165
16166   obj = G_OBJECT (self);
16167   changed = FALSE;
16168
16169   g_object_freeze_notify (obj);
16170
16171   info = _clutter_actor_get_layout_info (self);
16172
16173   if (info->margin.top != margin->top)
16174     {
16175       info->margin.top = margin->top;
16176       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16177       changed = TRUE;
16178     }
16179
16180   if (info->margin.right != margin->right)
16181     {
16182       info->margin.right = margin->right;
16183       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16184       changed = TRUE;
16185     }
16186
16187   if (info->margin.bottom != margin->bottom)
16188     {
16189       info->margin.bottom = margin->bottom;
16190       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16191       changed = TRUE;
16192     }
16193
16194   if (info->margin.left != margin->left)
16195     {
16196       info->margin.left = margin->left;
16197       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16198       changed = TRUE;
16199     }
16200
16201   if (changed)
16202     clutter_actor_queue_relayout (self);
16203
16204   g_object_thaw_notify (obj);
16205 }
16206
16207 /**
16208  * clutter_actor_get_margin:
16209  * @self: a #ClutterActor
16210  * @margin: (out caller-allocates): return location for a #ClutterMargin
16211  *
16212  * Retrieves all the components of the margin of a #ClutterActor.
16213  *
16214  * Since: 1.10
16215  */
16216 void
16217 clutter_actor_get_margin (ClutterActor  *self,
16218                           ClutterMargin *margin)
16219 {
16220   const ClutterLayoutInfo *info;
16221
16222   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16223   g_return_if_fail (margin != NULL);
16224
16225   info = _clutter_actor_get_layout_info_or_defaults (self);
16226
16227   *margin = info->margin;
16228 }
16229
16230 /**
16231  * clutter_actor_set_margin_top:
16232  * @self: a #ClutterActor
16233  * @margin: the top margin
16234  *
16235  * Sets the margin from the top of a #ClutterActor.
16236  *
16237  * Since: 1.10
16238  */
16239 void
16240 clutter_actor_set_margin_top (ClutterActor *self,
16241                               gfloat        margin)
16242 {
16243   ClutterLayoutInfo *info;
16244
16245   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16246   g_return_if_fail (margin >= 0.f);
16247
16248   info = _clutter_actor_get_layout_info (self);
16249
16250   if (info->margin.top == margin)
16251     return;
16252
16253   info->margin.top = margin;
16254
16255   clutter_actor_queue_relayout (self);
16256
16257   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16258 }
16259
16260 /**
16261  * clutter_actor_get_margin_top:
16262  * @self: a #ClutterActor
16263  *
16264  * Retrieves the top margin of a #ClutterActor.
16265  *
16266  * Return value: the top margin
16267  *
16268  * Since: 1.10
16269  */
16270 gfloat
16271 clutter_actor_get_margin_top (ClutterActor *self)
16272 {
16273   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16274
16275   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16276 }
16277
16278 /**
16279  * clutter_actor_set_margin_bottom:
16280  * @self: a #ClutterActor
16281  * @margin: the bottom margin
16282  *
16283  * Sets the margin from the bottom of a #ClutterActor.
16284  *
16285  * Since: 1.10
16286  */
16287 void
16288 clutter_actor_set_margin_bottom (ClutterActor *self,
16289                                  gfloat        margin)
16290 {
16291   ClutterLayoutInfo *info;
16292
16293   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16294   g_return_if_fail (margin >= 0.f);
16295
16296   info = _clutter_actor_get_layout_info (self);
16297
16298   if (info->margin.bottom == margin)
16299     return;
16300
16301   info->margin.bottom = margin;
16302
16303   clutter_actor_queue_relayout (self);
16304
16305   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16306 }
16307
16308 /**
16309  * clutter_actor_get_margin_bottom:
16310  * @self: a #ClutterActor
16311  *
16312  * Retrieves the bottom margin of a #ClutterActor.
16313  *
16314  * Return value: the bottom margin
16315  *
16316  * Since: 1.10
16317  */
16318 gfloat
16319 clutter_actor_get_margin_bottom (ClutterActor *self)
16320 {
16321   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16322
16323   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16324 }
16325
16326 /**
16327  * clutter_actor_set_margin_left:
16328  * @self: a #ClutterActor
16329  * @margin: the left margin
16330  *
16331  * Sets the margin from the left of a #ClutterActor.
16332  *
16333  * Since: 1.10
16334  */
16335 void
16336 clutter_actor_set_margin_left (ClutterActor *self,
16337                                gfloat        margin)
16338 {
16339   ClutterLayoutInfo *info;
16340
16341   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16342   g_return_if_fail (margin >= 0.f);
16343
16344   info = _clutter_actor_get_layout_info (self);
16345
16346   if (info->margin.left == margin)
16347     return;
16348
16349   info->margin.left = margin;
16350
16351   clutter_actor_queue_relayout (self);
16352
16353   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16354 }
16355
16356 /**
16357  * clutter_actor_get_margin_left:
16358  * @self: a #ClutterActor
16359  *
16360  * Retrieves the left margin of a #ClutterActor.
16361  *
16362  * Return value: the left margin
16363  *
16364  * Since: 1.10
16365  */
16366 gfloat
16367 clutter_actor_get_margin_left (ClutterActor *self)
16368 {
16369   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16370
16371   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16372 }
16373
16374 /**
16375  * clutter_actor_set_margin_right:
16376  * @self: a #ClutterActor
16377  * @margin: the right margin
16378  *
16379  * Sets the margin from the right of a #ClutterActor.
16380  *
16381  * Since: 1.10
16382  */
16383 void
16384 clutter_actor_set_margin_right (ClutterActor *self,
16385                                 gfloat        margin)
16386 {
16387   ClutterLayoutInfo *info;
16388
16389   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16390   g_return_if_fail (margin >= 0.f);
16391
16392   info = _clutter_actor_get_layout_info (self);
16393
16394   if (info->margin.right == margin)
16395     return;
16396
16397   info->margin.right = margin;
16398
16399   clutter_actor_queue_relayout (self);
16400
16401   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16402 }
16403
16404 /**
16405  * clutter_actor_get_margin_right:
16406  * @self: a #ClutterActor
16407  *
16408  * Retrieves the right margin of a #ClutterActor.
16409  *
16410  * Return value: the right margin
16411  *
16412  * Since: 1.10
16413  */
16414 gfloat
16415 clutter_actor_get_margin_right (ClutterActor *self)
16416 {
16417   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16418
16419   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16420 }
16421
16422 static inline void
16423 clutter_actor_set_background_color_internal (ClutterActor *self,
16424                                              const ClutterColor *color)
16425 {
16426   ClutterActorPrivate *priv = self->priv;
16427   GObject *obj;
16428
16429   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16430     return;
16431
16432   obj = G_OBJECT (self);
16433
16434   priv->bg_color = *color;
16435   priv->bg_color_set = TRUE;
16436
16437   clutter_actor_queue_redraw (self);
16438
16439   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16440   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16441 }
16442
16443 /**
16444  * clutter_actor_set_background_color:
16445  * @self: a #ClutterActor
16446  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16447  *  set color
16448  *
16449  * Sets the background color of a #ClutterActor.
16450  *
16451  * The background color will be used to cover the whole allocation of the
16452  * actor. The default background color of an actor is transparent.
16453  *
16454  * To check whether an actor has a background color, you can use the
16455  * #ClutterActor:background-color-set actor property.
16456  *
16457  * The #ClutterActor:background-color property is animatable.
16458  *
16459  * Since: 1.10
16460  */
16461 void
16462 clutter_actor_set_background_color (ClutterActor       *self,
16463                                     const ClutterColor *color)
16464 {
16465   ClutterActorPrivate *priv;
16466   GObject *obj;
16467   GParamSpec *bg_color_pspec;
16468
16469   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16470
16471   obj = G_OBJECT (self);
16472
16473   priv = self->priv;
16474
16475   if (color == NULL)
16476     {
16477       priv->bg_color_set = FALSE;
16478       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16479       clutter_actor_queue_redraw (self);
16480       return;
16481     }
16482
16483   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16484   if (clutter_actor_get_easing_duration (self) != 0)
16485     {
16486       ClutterTransition *transition;
16487
16488       transition = _clutter_actor_get_transition (self, bg_color_pspec);
16489       if (transition == NULL)
16490         {
16491           transition = _clutter_actor_create_transition (self, bg_color_pspec,
16492                                                          &priv->bg_color,
16493                                                          color);
16494           clutter_timeline_start (CLUTTER_TIMELINE (transition));
16495         }
16496       else
16497         _clutter_actor_update_transition (self, bg_color_pspec, color);
16498
16499       clutter_actor_queue_redraw (self);
16500     }
16501   else
16502     clutter_actor_set_background_color_internal (self, color);
16503 }
16504
16505 /**
16506  * clutter_actor_get_background_color:
16507  * @self: a #ClutterActor
16508  * @color: (out caller-allocates): return location for a #ClutterColor
16509  *
16510  * Retrieves the color set using clutter_actor_set_background_color().
16511  *
16512  * Since: 1.10
16513  */
16514 void
16515 clutter_actor_get_background_color (ClutterActor *self,
16516                                     ClutterColor *color)
16517 {
16518   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16519   g_return_if_fail (color != NULL);
16520
16521   *color = self->priv->bg_color;
16522 }
16523
16524 /**
16525  * clutter_actor_get_previous_sibling:
16526  * @self: a #ClutterActor
16527  *
16528  * Retrieves the sibling of @self that comes before it in the list
16529  * of children of @self's parent.
16530  *
16531  * The returned pointer is only valid until the scene graph changes; it
16532  * is not safe to modify the list of children of @self while iterating
16533  * it.
16534  *
16535  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16536  *
16537  * Since: 1.10
16538  */
16539 ClutterActor *
16540 clutter_actor_get_previous_sibling (ClutterActor *self)
16541 {
16542   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16543
16544   return self->priv->prev_sibling;
16545 }
16546
16547 /**
16548  * clutter_actor_get_next_sibling:
16549  * @self: a #ClutterActor
16550  *
16551  * Retrieves the sibling of @self that comes after it in the list
16552  * of children of @self's parent.
16553  *
16554  * The returned pointer is only valid until the scene graph changes; it
16555  * is not safe to modify the list of children of @self while iterating
16556  * it.
16557  *
16558  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16559  *
16560  * Since: 1.10
16561  */
16562 ClutterActor *
16563 clutter_actor_get_next_sibling (ClutterActor *self)
16564 {
16565   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16566
16567   return self->priv->next_sibling;
16568 }
16569
16570 /**
16571  * clutter_actor_get_first_child:
16572  * @self: a #ClutterActor
16573  *
16574  * Retrieves the first child of @self.
16575  *
16576  * The returned pointer is only valid until the scene graph changes; it
16577  * is not safe to modify the list of children of @self while iterating
16578  * it.
16579  *
16580  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16581  *
16582  * Since: 1.10
16583  */
16584 ClutterActor *
16585 clutter_actor_get_first_child (ClutterActor *self)
16586 {
16587   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16588
16589   return self->priv->first_child;
16590 }
16591
16592 /**
16593  * clutter_actor_get_last_child:
16594  * @self: a #ClutterActor
16595  *
16596  * Retrieves the last child of @self.
16597  *
16598  * The returned pointer is only valid until the scene graph changes; it
16599  * is not safe to modify the list of children of @self while iterating
16600  * it.
16601  *
16602  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16603  *
16604  * Since: 1.10
16605  */
16606 ClutterActor *
16607 clutter_actor_get_last_child (ClutterActor *self)
16608 {
16609   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16610
16611   return self->priv->last_child;
16612 }
16613
16614 /* easy way to have properly named fields instead of the dummy ones
16615  * we use in the public structure
16616  */
16617 typedef struct _RealActorIter
16618 {
16619   ClutterActor *root;           /* dummy1 */
16620   ClutterActor *current;        /* dummy2 */
16621   gpointer padding_1;           /* dummy3 */
16622   gint age;                     /* dummy4 */
16623   gpointer padding_2;           /* dummy5 */
16624 } RealActorIter;
16625
16626 /**
16627  * clutter_actor_iter_init:
16628  * @iter: a #ClutterActorIter
16629  * @root: a #ClutterActor
16630  *
16631  * Initializes a #ClutterActorIter, which can then be used to iterate
16632  * efficiently over a section of the scene graph, and associates it
16633  * with @root.
16634  *
16635  * Modifying the scene graph section that contains @root will invalidate
16636  * the iterator.
16637  *
16638  * |[
16639  *   ClutterActorIter iter;
16640  *   ClutterActor *child;
16641  *
16642  *   clutter_actor_iter_init (&iter, container);
16643  *   while (clutter_actor_iter_next (&iter, &child))
16644  *     {
16645  *       /&ast; do something with child &ast;/
16646  *     }
16647  * ]|
16648  *
16649  * Since: 1.10
16650  */
16651 void
16652 clutter_actor_iter_init (ClutterActorIter *iter,
16653                          ClutterActor     *root)
16654 {
16655   RealActorIter *ri = (RealActorIter *) iter;
16656
16657   g_return_if_fail (iter != NULL);
16658   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16659
16660   ri->root = root;
16661   ri->current = NULL;
16662   ri->age = root->priv->age;
16663 }
16664
16665 /**
16666  * clutter_actor_iter_next:
16667  * @iter: a #ClutterActorIter
16668  * @child: (out): return location for a #ClutterActor
16669  *
16670  * Advances the @iter and retrieves the next child of the root #ClutterActor
16671  * that was used to initialize the #ClutterActorIterator.
16672  *
16673  * If the iterator can advance, this function returns %TRUE and sets the
16674  * @child argument.
16675  *
16676  * If the iterator cannot advance, this function returns %FALSE, and
16677  * the contents of @child are undefined.
16678  *
16679  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16680  *
16681  * Since: 1.10
16682  */
16683 gboolean
16684 clutter_actor_iter_next (ClutterActorIter  *iter,
16685                          ClutterActor     **child)
16686 {
16687   RealActorIter *ri = (RealActorIter *) iter;
16688
16689   g_return_val_if_fail (iter != NULL, FALSE);
16690   g_return_val_if_fail (ri->root != NULL, FALSE);
16691 #ifndef G_DISABLE_ASSERT
16692   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16693 #endif
16694
16695   if (ri->current == NULL)
16696     ri->current = ri->root->priv->first_child;
16697   else
16698     ri->current = ri->current->priv->next_sibling;
16699
16700   if (child != NULL)
16701     *child = ri->current;
16702
16703   return ri->current != NULL;
16704 }
16705
16706 /**
16707  * clutter_actor_iter_prev:
16708  * @iter: a #ClutterActorIter
16709  * @child: (out): return location for a #ClutterActor
16710  *
16711  * Advances the @iter and retrieves the previous child of the root
16712  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16713  *
16714  * If the iterator can advance, this function returns %TRUE and sets the
16715  * @child argument.
16716  *
16717  * If the iterator cannot advance, this function returns %FALSE, and
16718  * the contents of @child are undefined.
16719  *
16720  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16721  *
16722  * Since: 1.10
16723  */
16724 gboolean
16725 clutter_actor_iter_prev (ClutterActorIter  *iter,
16726                          ClutterActor     **child)
16727 {
16728   RealActorIter *ri = (RealActorIter *) iter;
16729
16730   g_return_val_if_fail (iter != NULL, FALSE);
16731   g_return_val_if_fail (ri->root != NULL, FALSE);
16732 #ifndef G_DISABLE_ASSERT
16733   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16734 #endif
16735
16736   if (ri->current == NULL)
16737     ri->current = ri->root->priv->last_child;
16738   else
16739     ri->current = ri->current->priv->prev_sibling;
16740
16741   if (child != NULL)
16742     *child = ri->current;
16743
16744   return ri->current != NULL;
16745 }
16746
16747 /**
16748  * clutter_actor_iter_remove:
16749  * @iter: a #ClutterActorIter
16750  *
16751  * Safely removes the #ClutterActor currently pointer to by the iterator
16752  * from its parent.
16753  *
16754  * This function can only be called after clutter_actor_iter_next() or
16755  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16756  * than once for the same actor.
16757  *
16758  * This function will call clutter_actor_remove_child() internally.
16759  *
16760  * Since: 1.10
16761  */
16762 void
16763 clutter_actor_iter_remove (ClutterActorIter *iter)
16764 {
16765   RealActorIter *ri = (RealActorIter *) iter;
16766   ClutterActor *cur;
16767
16768   g_return_if_fail (iter != NULL);
16769   g_return_if_fail (ri->root != NULL);
16770 #ifndef G_DISABLE_ASSERT
16771   g_return_if_fail (ri->age == ri->root->priv->age);
16772 #endif
16773   g_return_if_fail (ri->current != NULL);
16774
16775   cur = ri->current;
16776
16777   if (cur != NULL)
16778     {
16779       ri->current = cur->priv->prev_sibling;
16780
16781       clutter_actor_remove_child_internal (ri->root, cur,
16782                                            REMOVE_CHILD_DEFAULT_FLAGS);
16783
16784       ri->age += 1;
16785     }
16786 }
16787
16788 /**
16789  * clutter_actor_iter_destroy:
16790  * @iter: a #ClutterActorIter
16791  *
16792  * Safely destroys the #ClutterActor currently pointer to by the iterator
16793  * from its parent.
16794  *
16795  * This function can only be called after clutter_actor_iter_next() or
16796  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16797  * than once for the same actor.
16798  *
16799  * This function will call clutter_actor_destroy() internally.
16800  *
16801  * Since: 1.10
16802  */
16803 void
16804 clutter_actor_iter_destroy (ClutterActorIter *iter)
16805 {
16806   RealActorIter *ri = (RealActorIter *) iter;
16807   ClutterActor *cur;
16808
16809   g_return_if_fail (iter != NULL);
16810   g_return_if_fail (ri->root != NULL);
16811 #ifndef G_DISABLE_ASSERT
16812   g_return_if_fail (ri->age == ri->root->priv->age);
16813 #endif
16814   g_return_if_fail (ri->current != NULL);
16815
16816   cur = ri->current;
16817
16818   if (cur != NULL)
16819     {
16820       ri->current = cur->priv->prev_sibling;
16821
16822       clutter_actor_destroy (cur);
16823
16824       ri->age += 1;
16825     }
16826 }
16827
16828 static const ClutterAnimationInfo default_animation_info = {
16829   NULL,         /* transitions */
16830   NULL,         /* states */
16831   NULL,         /* cur_state */
16832 };
16833
16834 static void
16835 clutter_animation_info_free (gpointer data)
16836 {
16837   if (data != NULL)
16838     {
16839       ClutterAnimationInfo *info = data;
16840
16841       if (info->transitions != NULL)
16842         g_hash_table_unref (info->transitions);
16843
16844       if (info->states != NULL)
16845         g_array_unref (info->states);
16846
16847       g_slice_free (ClutterAnimationInfo, info);
16848     }
16849 }
16850
16851 const ClutterAnimationInfo *
16852 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16853 {
16854   const ClutterAnimationInfo *res;
16855   GObject *obj = G_OBJECT (self);
16856
16857   res = g_object_get_qdata (obj, quark_actor_animation_info);
16858   if (res != NULL)
16859     return res;
16860
16861   return &default_animation_info;
16862 }
16863
16864 ClutterAnimationInfo *
16865 _clutter_actor_get_animation_info (ClutterActor *self)
16866 {
16867   GObject *obj = G_OBJECT (self);
16868   ClutterAnimationInfo *res;
16869
16870   res = g_object_get_qdata (obj, quark_actor_animation_info);
16871   if (res == NULL)
16872     {
16873       res = g_slice_new (ClutterAnimationInfo);
16874
16875       *res = default_animation_info;
16876
16877       g_object_set_qdata_full (obj, quark_actor_animation_info,
16878                                res,
16879                                clutter_animation_info_free);
16880     }
16881
16882   return res;
16883 }
16884
16885 ClutterTransition *
16886 _clutter_actor_get_transition (ClutterActor *actor,
16887                                GParamSpec   *pspec)
16888 {
16889   const ClutterAnimationInfo *info;
16890
16891   info = _clutter_actor_get_animation_info_or_defaults (actor);
16892
16893   if (info->transitions == NULL)
16894     return NULL;
16895
16896   return g_hash_table_lookup (info->transitions, pspec->name);
16897 }
16898
16899 typedef struct _TransitionClosure
16900 {
16901   ClutterActor *actor;
16902   ClutterTransition *transition;
16903   gchar *name;
16904   gulong completed_id;
16905 } TransitionClosure;
16906
16907 static void
16908 transition_closure_free (gpointer data)
16909 {
16910   if (G_LIKELY (data != NULL))
16911     {
16912       TransitionClosure *clos = data;
16913
16914       g_signal_handler_disconnect (clos->transition, clos->completed_id);
16915       g_free (clos->name);
16916
16917       g_slice_free (TransitionClosure, clos);
16918     }
16919 }
16920
16921 static void
16922 on_transition_completed (ClutterTransition *transition,
16923                          TransitionClosure *clos)
16924 {
16925   ClutterAnimationInfo *info;
16926
16927   info = _clutter_actor_get_animation_info (clos->actor);
16928
16929   /* this will take care of cleaning clos for us */
16930   g_hash_table_remove (info->transitions, clos->name);
16931 }
16932
16933 void
16934 _clutter_actor_update_transition (ClutterActor *actor,
16935                                   GParamSpec   *pspec,
16936                                   ...)
16937 {
16938   TransitionClosure *clos;
16939   ClutterInterval *interval;
16940   const ClutterAnimationInfo *info;
16941   va_list var_args;
16942   GType ptype;
16943   GValue initial = G_VALUE_INIT;
16944   GValue final = G_VALUE_INIT;
16945   char *error = NULL;
16946
16947   info = _clutter_actor_get_animation_info_or_defaults (actor);
16948
16949   if (info->transitions == NULL)
16950     return;
16951
16952   clos = g_hash_table_lookup (info->transitions, pspec->name);
16953   if (clos == NULL)
16954     return;
16955
16956   va_start (var_args, pspec);
16957
16958   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16959
16960   g_value_init (&initial, ptype);
16961   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
16962                                         pspec->name,
16963                                         &initial);
16964
16965   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
16966   if (error != NULL)
16967     {
16968       g_critical ("%s: %s", G_STRLOC, error);
16969       g_free (error);
16970       goto out;
16971     }
16972
16973   interval = clutter_transition_get_interval (clos->transition);
16974   clutter_interval_set_initial_value (interval, &initial);
16975   clutter_interval_set_final_value (interval, &final);
16976
16977   clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
16978
16979 out:
16980   g_value_unset (&initial);
16981   g_value_unset (&final);
16982
16983   va_end (var_args);
16984 }
16985
16986 /*< private >*
16987  * _clutter_actor_create_transition:
16988  * @actor: a #ClutterActor
16989  * @pspec: the property used for the transition
16990  * @...: initial and final state
16991  *
16992  * Creates a #ClutterTransition for the property represented by @pspec.
16993  *
16994  * Return value: a #ClutterTransition
16995  */
16996 ClutterTransition *
16997 _clutter_actor_create_transition (ClutterActor *actor,
16998                                   GParamSpec   *pspec,
16999                                   ...)
17000 {
17001   ClutterAnimationInfo *info;
17002   ClutterTransition *res = NULL;
17003   gboolean call_restore = FALSE;
17004   TransitionClosure *clos;
17005   va_list var_args;
17006
17007   info = _clutter_actor_get_animation_info (actor);
17008
17009   if (info->states == NULL)
17010     {
17011       clutter_actor_save_easing_state (actor);
17012       call_restore = TRUE;
17013     }
17014
17015   if (info->transitions == NULL)
17016     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17017                                                NULL,
17018                                                transition_closure_free);
17019
17020   va_start (var_args, pspec);
17021
17022   clos = g_hash_table_lookup (info->transitions, pspec->name);
17023   if (clos == NULL)
17024     {
17025       ClutterInterval *interval;
17026       GValue initial = G_VALUE_INIT;
17027       GValue final = G_VALUE_INIT;
17028       GType ptype;
17029       char *error;
17030
17031       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17032
17033       G_VALUE_COLLECT_INIT (&initial, ptype,
17034                             var_args, 0,
17035                             &error);
17036       if (error != NULL)
17037         {
17038           g_critical ("%s: %s", G_STRLOC, error);
17039           g_free (error);
17040           goto out;
17041         }
17042
17043       G_VALUE_COLLECT_INIT (&final, ptype,
17044                             var_args, 0,
17045                             &error);
17046
17047       if (error != NULL)
17048         {
17049           g_critical ("%s: %s", G_STRLOC, error);
17050           g_value_unset (&initial);
17051           g_free (error);
17052           goto out;
17053         }
17054
17055       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17056
17057       g_value_unset (&initial);
17058       g_value_unset (&final);
17059
17060       res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
17061                                              pspec->name);
17062
17063       clutter_transition_set_interval (res, interval);
17064       clutter_transition_set_remove_on_complete (res, TRUE);
17065
17066       clutter_actor_add_transition (actor, pspec->name, res);
17067     }
17068   else
17069     res = clos->transition;
17070
17071 out:
17072   if (call_restore)
17073     clutter_actor_restore_easing_state (actor);
17074
17075   va_end (var_args);
17076
17077   return res;
17078 }
17079
17080 /**
17081  * clutter_actor_add_transition:
17082  * @self: a #ClutterActor
17083  * @name: the name of the transition to add
17084  * @transition: the #ClutterTransition to add
17085  *
17086  * Adds a @transition to the #ClutterActor's list of animations.
17087  *
17088  * The @name string is a per-actor unique identifier of the @transition: only
17089  * one #ClutterTransition can be associated to the specified @name.
17090  *
17091  * The @transition will be given the easing duration, mode, and delay
17092  * associated to the actor's current easing state; it is possible to modify
17093  * these values after calling clutter_actor_add_transition().
17094  *
17095  * This function is usually called implicitly when modifying an animatable
17096  * property.
17097  *
17098  * Since: 1.10
17099  */
17100 void
17101 clutter_actor_add_transition (ClutterActor      *self,
17102                               const char        *name,
17103                               ClutterTransition *transition)
17104 {
17105   ClutterTimeline *timeline;
17106   TransitionClosure *clos;
17107   ClutterAnimationInfo *info;
17108
17109   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17110   g_return_if_fail (name != NULL);
17111   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17112
17113   info = _clutter_actor_get_animation_info (self);
17114
17115   if (info->cur_state == NULL)
17116     {
17117       g_warning ("No easing state is defined for the actor '%s'; you "
17118                  "must call clutter_actor_save_easing_state() before "
17119                  "calling clutter_actor_add_transition().",
17120                  _clutter_actor_get_debug_name (self));
17121       return;
17122     }
17123
17124   if (info->transitions == NULL)
17125     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17126                                                NULL,
17127                                                transition_closure_free);
17128
17129   if (g_hash_table_lookup (info->transitions, name) != NULL)
17130     {
17131       g_warning ("A transition with name '%s' already exists for "
17132                  "the actor '%s'",
17133                  name,
17134                  _clutter_actor_get_debug_name (self));
17135       return;
17136     }
17137
17138   timeline = CLUTTER_TIMELINE (transition);
17139
17140   clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17141   clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17142   clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17143
17144   clos = g_slice_new (TransitionClosure);
17145   clos->actor = self;
17146   clos->transition = transition;
17147   clos->name = g_strdup (name);
17148   clos->completed_id = g_signal_connect (timeline, "completed",
17149                                          G_CALLBACK (on_transition_completed),
17150                                          clos);
17151
17152   g_hash_table_insert (info->transitions, clos->name, clos);
17153 }
17154
17155 /**
17156  * clutter_actor_remove_transition:
17157  * @self: a #ClutterActor
17158  * @name: the name of the transition to remove
17159  *
17160  * Removes the transition stored inside a #ClutterActor using @name
17161  * identifier.
17162  *
17163  * Since: 1.10
17164  */
17165 void
17166 clutter_actor_remove_transition (ClutterActor *self,
17167                                  const char   *name)
17168 {
17169   const ClutterAnimationInfo *info;
17170
17171   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17172   g_return_if_fail (name != NULL);
17173
17174   info = _clutter_actor_get_animation_info_or_defaults (self);
17175
17176   if (info->transitions == NULL)
17177     return;
17178
17179   g_hash_table_remove (info->transitions, name);
17180 }
17181
17182 /**
17183  * clutter_actor_remove_all_transitions:
17184  * @self: a #ClutterActor
17185  *
17186  * Removes all transitions associated to @self.
17187  *
17188  * Since: 1.10
17189  */
17190 void
17191 clutter_actor_remove_all_transitions (ClutterActor *self)
17192 {
17193   const ClutterAnimationInfo *info;
17194
17195   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17196
17197   info = _clutter_actor_get_animation_info_or_defaults (self);
17198   if (info->transitions == NULL)
17199     return;
17200
17201   g_hash_table_remove_all (info->transitions);
17202 }
17203
17204 /**
17205  * clutter_actor_set_easing_duration:
17206  * @self: a #ClutterActor
17207  * @msecs: the duration of the easing, or %NULL
17208  *
17209  * Sets the duration of the tweening for animatable properties
17210  * of @self for the current easing state.
17211  *
17212  * Calling this function will implicitly call
17213  * clutter_actor_save_easing_state() if no previous call to
17214  * that function was made.
17215  *
17216  * Since: 1.10
17217  */
17218 void
17219 clutter_actor_set_easing_duration (ClutterActor *self,
17220                                    guint         msecs)
17221 {
17222   ClutterAnimationInfo *info;
17223
17224   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17225
17226   info = _clutter_actor_get_animation_info (self);
17227
17228   if (info->states == NULL)
17229     clutter_actor_save_easing_state (self);
17230
17231   if (info->cur_state->easing_duration != msecs)
17232     info->cur_state->easing_duration = msecs;
17233 }
17234
17235 /**
17236  * clutter_actor_get_easing_duration:
17237  * @self: a #ClutterActor
17238  *
17239  * Retrieves the duration of the tweening for animatable
17240  * properties of @self for the current easing state.
17241  *
17242  * Return value: the duration of the tweening, in milliseconds
17243  *
17244  * Since: 1.10
17245  */
17246 guint
17247 clutter_actor_get_easing_duration (ClutterActor *self)
17248 {
17249   const ClutterAnimationInfo *info;
17250
17251   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17252
17253   info = _clutter_actor_get_animation_info_or_defaults (self);
17254
17255   if (info->cur_state != NULL)
17256     return info->cur_state->easing_duration;
17257
17258   return 0;
17259 }
17260
17261 /**
17262  * clutter_actor_set_easing_mode:
17263  * @self: a #ClutterActor
17264  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17265  *
17266  * Sets the easing mode for the tweening of animatable properties
17267  * of @self.
17268  *
17269  * Calling this function will implicitly call
17270  * clutter_actor_save_easing_state() if no previous calls to
17271  * that function were made.
17272  *
17273  * Since: 1.10
17274  */
17275 void
17276 clutter_actor_set_easing_mode (ClutterActor         *self,
17277                                ClutterAnimationMode  mode)
17278 {
17279   ClutterAnimationInfo *info;
17280
17281   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17282   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17283   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17284
17285   info = _clutter_actor_get_animation_info (self);
17286
17287   if (info->states == NULL)
17288     clutter_actor_save_easing_state (self);
17289
17290   if (info->cur_state->easing_mode != mode)
17291     info->cur_state->easing_mode = mode;
17292 }
17293
17294 /**
17295  * clutter_actor_get_easing_mode:
17296  * @self: a #ClutterActor
17297  *
17298  * Retrieves the easing mode for the tweening of animatable properties
17299  * of @self for the current easing state.
17300  *
17301  * Return value: an easing mode
17302  *
17303  * Since: 1.10
17304  */
17305 ClutterAnimationMode
17306 clutter_actor_get_easing_mode (ClutterActor *self)
17307 {
17308   const ClutterAnimationInfo *info;
17309
17310   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17311
17312   info = _clutter_actor_get_animation_info_or_defaults (self);
17313
17314   if (info->cur_state != NULL)
17315     return info->cur_state->easing_mode;
17316
17317   return CLUTTER_EASE_OUT_CUBIC;
17318 }
17319
17320 /**
17321  * clutter_actor_set_easing_delay:
17322  * @self: a #ClutterActor
17323  * @msecs: the delay before the start of the tweening, in milliseconds
17324  *
17325  * Sets the delay that should be applied before tweening animatable
17326  * properties.
17327  *
17328  * Calling this function will implicitly call
17329  * clutter_actor_save_easing_state() if no previous calls to
17330  * that function were made.
17331  *
17332  * Since: 1.10
17333  */
17334 void
17335 clutter_actor_set_easing_delay (ClutterActor *self,
17336                                 guint         msecs)
17337 {
17338   ClutterAnimationInfo *info;
17339
17340   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17341
17342   info = _clutter_actor_get_animation_info (self);
17343
17344   if (info->states == NULL)
17345     clutter_actor_save_easing_state (self);
17346
17347   if (info->cur_state->easing_delay != msecs)
17348     info->cur_state->easing_delay = msecs;
17349 }
17350
17351 /**
17352  * clutter_actor_get_easing_delay:
17353  * @self: a #ClutterActor
17354  *
17355  * Retrieves the delay that should be applied when tweening animatable
17356  * properties.
17357  *
17358  * Return value: a delay, in milliseconds
17359  *
17360  * Since: 1.10
17361  */
17362 guint
17363 clutter_actor_get_easing_delay (ClutterActor *self)
17364 {
17365   const ClutterAnimationInfo *info;
17366
17367   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17368
17369   info = _clutter_actor_get_animation_info_or_defaults (self);
17370
17371   if (info->cur_state != NULL)
17372     return info->cur_state->easing_delay;
17373
17374   return 0;
17375 }
17376
17377 /**
17378  * clutter_actor_get_transition:
17379  * @self: a #ClutterActor
17380  * @name: the name of the transition
17381  *
17382  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17383  * transition @name.
17384  *
17385  * Transitions created for animatable properties use the name of the
17386  * property itself, for instance the code below:
17387  *
17388  * |[
17389  *   clutter_actor_set_easing_duration (actor, 1000);
17390  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17391  *
17392  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17393  *   g_signal_connect (transition, "completed",
17394  *                     G_CALLBACK (on_transition_complete),
17395  *                     actor);
17396  * ]|
17397  *
17398  * will call the <function>on_transition_complete</function> callback when
17399  * the transition is complete.
17400  *
17401  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17402  *   was found to match the passed name; the returned instance is owned
17403  *   by Clutter and it should not be freed
17404  *
17405  * Since: 1.10
17406  */
17407 ClutterTransition *
17408 clutter_actor_get_transition (ClutterActor *self,
17409                               const char   *name)
17410 {
17411   TransitionClosure *clos;
17412   const ClutterAnimationInfo *info;
17413
17414   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17415   g_return_val_if_fail (name != NULL, NULL);
17416
17417   info = _clutter_actor_get_animation_info_or_defaults (self);
17418
17419   if (info->transitions == NULL)
17420     return NULL;
17421
17422   clos = g_hash_table_lookup (info->transitions, name);
17423   if (clos == NULL)
17424     return NULL;
17425
17426   return clos->transition;
17427 }
17428
17429 /**
17430  * clutter_actor_save_easing_state:
17431  * @self: a #ClutterActor
17432  *
17433  * Saves the current easing state for animatable properties, and creates
17434  * a new state with the default values for easing mode and duration.
17435  *
17436  * Since: 1.10
17437  */
17438 void
17439 clutter_actor_save_easing_state (ClutterActor *self)
17440 {
17441   ClutterAnimationInfo *info;
17442   AState new_state;
17443
17444   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17445
17446   info = _clutter_actor_get_animation_info (self);
17447
17448   if (info->states == NULL)
17449     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17450
17451   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17452   new_state.easing_duration = 250;
17453   new_state.easing_delay = 0;
17454
17455   g_array_append_val (info->states, new_state);
17456
17457   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17458 }
17459
17460 /**
17461  * clutter_actor_restore_easing_state:
17462  * @self: a #ClutterActor
17463  *
17464  * Restores the easing state as it was prior to a call to
17465  * clutter_actor_save_easing_state().
17466  *
17467  * Since: 1.10
17468  */
17469 void
17470 clutter_actor_restore_easing_state (ClutterActor *self)
17471 {
17472   ClutterAnimationInfo *info;
17473
17474   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17475
17476   info = _clutter_actor_get_animation_info (self);
17477
17478   if (info->states == NULL)
17479     {
17480       g_critical ("The function clutter_actor_restore_easing_state() has "
17481                   "called without a previous call to "
17482                   "clutter_actor_save_easing_state().");
17483       return;
17484     }
17485
17486   g_array_remove_index (info->states, info->states->len - 1);
17487   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17488 }
17489
17490 /**
17491  * clutter_actor_set_content:
17492  * @self: a #ClutterActor
17493  * @content: (allow-none): a #ClutterContent, or %NULL
17494  *
17495  * Sets the contents of a #ClutterActor.
17496  *
17497  * Since: 1.10
17498  */
17499 void
17500 clutter_actor_set_content (ClutterActor   *self,
17501                            ClutterContent *content)
17502 {
17503   ClutterActorPrivate *priv;
17504
17505   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17506   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17507
17508   priv = self->priv;
17509
17510   if (priv->content != NULL)
17511     {
17512       _clutter_content_detached (priv->content, self);
17513       g_object_unref (priv->content);
17514     }
17515
17516   priv->content = content;
17517
17518   if (priv->content != NULL)
17519     {
17520       g_object_ref (priv->content);
17521       _clutter_content_attached (priv->content, self);
17522     }
17523
17524   /* given that the content is always painted within the allocation,
17525    * we only need to queue a redraw here
17526    */
17527   clutter_actor_queue_redraw (self);
17528
17529   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17530
17531   /* if the content gravity is not resize-fill, and the new content has a
17532    * different preferred size than the previous one, then the content box
17533    * may have been changed. since we compute that lazily, we just notify
17534    * here, and let whomever watches :content-box do whatever they need to
17535    * do.
17536    */
17537   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17538     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17539 }
17540
17541 /**
17542  * clutter_actor_get_content:
17543  * @self: a #ClutterActor
17544  *
17545  * Retrieves the contents of @self.
17546  *
17547  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17548  *   or %NULL if none was set
17549  *
17550  * Since: 1.10
17551  */
17552 ClutterContent *
17553 clutter_actor_get_content (ClutterActor *self)
17554 {
17555   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17556
17557   return self->priv->content;
17558 }
17559
17560 /**
17561  * clutter_actor_set_content_gravity:
17562  * @self: a #ClutterActor
17563  * @gravity: the #ClutterContentGravity
17564  *
17565  * Sets the gravity of the #ClutterContent used by @self.
17566  *
17567  * See the description of the #ClutterActor:content-gravity property for
17568  * more information.
17569  *
17570  * Since: 1.10
17571  */
17572 void
17573 clutter_actor_set_content_gravity (ClutterActor *self,
17574                                    ClutterContentGravity  gravity)
17575 {
17576   ClutterActorPrivate *priv;
17577
17578   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17579
17580   priv = self->priv;
17581
17582   if (priv->content_gravity == gravity)
17583     return;
17584
17585   priv->content_gravity = gravity;
17586
17587   clutter_actor_queue_redraw (self);
17588
17589   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17590   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17591 }
17592
17593 /**
17594  * clutter_actor_get_content_gravity:
17595  * @self: a #ClutterActor
17596  *
17597  * Retrieves the content gravity as set using
17598  * clutter_actor_get_content_gravity().
17599  *
17600  * Return value: the content gravity
17601  *
17602  * Since: 1.10
17603  */
17604 ClutterContentGravity
17605 clutter_actor_get_content_gravity (ClutterActor *self)
17606 {
17607   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17608                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17609
17610   return self->priv->content_gravity;
17611 }
17612
17613 /**
17614  * clutter_actor_get_content_box:
17615  * @self: a #ClutterActor
17616  * @box: (out caller-allocates): the return location for the bounding
17617  *   box for the #ClutterContent
17618  *
17619  * Retrieves the bounding box for the #ClutterContent of @self.
17620  *
17621  * The bounding box is relative to the actor's allocation.
17622  *
17623  * If no #ClutterContent is set for @self, or if @self has not been
17624  * allocated yet, then the result is undefined.
17625  *
17626  * The content box is guaranteed to be, at most, as big as the allocation
17627  * of the #ClutterActor.
17628  *
17629  * If the #ClutterContent used by the actor has a preferred size, then
17630  * it is possible to modify the content box by using the
17631  * #ClutterActor:content-gravity property.
17632  *
17633  * Since: 1.10
17634  */
17635 void
17636 clutter_actor_get_content_box (ClutterActor    *self,
17637                                ClutterActorBox *box)
17638 {
17639   ClutterActorPrivate *priv;
17640   gfloat content_w, content_h;
17641   gfloat alloc_w, alloc_h;
17642
17643   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17644   g_return_if_fail (box != NULL);
17645
17646   priv = self->priv;
17647
17648   if (!clutter_actor_has_allocation (self))
17649     return;
17650
17651   box->x1 = 0.f;
17652   box->y1 = 0.f;
17653   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17654   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17655
17656   if (priv->content == NULL)
17657     return;
17658
17659   /* no need to do any more work */
17660   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17661     return;
17662
17663   /* if the content does not have a preferred size then there is
17664    * no point in computing the content box
17665    */
17666   if (!clutter_content_get_preferred_size (priv->content,
17667                                            &content_w,
17668                                            &content_h))
17669     return;
17670
17671   alloc_w = box->x2;
17672   alloc_h = box->y2;
17673
17674   switch (priv->content_gravity)
17675     {
17676     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17677       box->x2 = box->x1 + MIN (content_w, alloc_w);
17678       box->y2 = box->y1 + MIN (content_h, alloc_h);
17679       break;
17680
17681     case CLUTTER_CONTENT_GRAVITY_TOP:
17682       if (alloc_w > content_w)
17683         {
17684           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17685           box->x2 = box->x1 + content_w;
17686         }
17687       box->y2 = box->y1 + MIN (content_h, alloc_h);
17688       break;
17689
17690     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17691       if (alloc_w > content_w)
17692         {
17693           box->x1 += (alloc_w - content_w);
17694           box->x2 = box->x1 + content_w;
17695         }
17696       box->y2 = box->y1 + MIN (content_h, alloc_h);
17697       break;
17698
17699     case CLUTTER_CONTENT_GRAVITY_LEFT:
17700       box->x2 = box->x1 + MIN (content_w, alloc_w);
17701       if (alloc_h > content_h)
17702         {
17703           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17704           box->y2 = box->y1 + content_h;
17705         }
17706       break;
17707
17708     case CLUTTER_CONTENT_GRAVITY_CENTER:
17709       if (alloc_w > content_w)
17710         {
17711           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17712           box->x2 = box->x1 + content_w;
17713         }
17714       if (alloc_h > content_h)
17715         {
17716           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17717           box->y2 = box->y1 + content_h;
17718         }
17719       break;
17720
17721     case CLUTTER_CONTENT_GRAVITY_RIGHT:
17722       if (alloc_w > content_w)
17723         {
17724           box->x1 += (alloc_w - content_w);
17725           box->x2 = box->x1 + content_w;
17726         }
17727       if (alloc_h > content_h)
17728         {
17729           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17730           box->y2 = box->y1 + content_h;
17731         }
17732       break;
17733
17734     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17735       box->x2 = box->x1 + MIN (content_w, alloc_w);
17736       if (alloc_h > content_h)
17737         {
17738           box->y1 += (alloc_h - content_h);
17739           box->y2 = box->y1 + content_h;
17740         }
17741       break;
17742
17743     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17744       if (alloc_w > content_w)
17745         {
17746           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17747           box->x2 = box->x1 + content_w;
17748         }
17749       if (alloc_h > content_h)
17750         {
17751           box->y1 += (alloc_h - content_h);
17752           box->y2 = box->y1 + content_h;
17753         }
17754       break;
17755
17756     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17757       if (alloc_w > content_w)
17758         {
17759           box->x1 += (alloc_w - content_w);
17760           box->x2 = box->x1 + content_w;
17761         }
17762       if (alloc_h > content_h)
17763         {
17764           box->y1 += (alloc_h - content_h);
17765           box->y2 = box->y1 + content_h;
17766         }
17767       break;
17768
17769     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17770       g_assert_not_reached ();
17771       break;
17772
17773     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17774       {
17775         double r_c = content_w / content_h;
17776         double r_a = alloc_w / alloc_h;
17777
17778         if (r_c >= 1.0)
17779           {
17780             if (r_a >= 1.0)
17781               {
17782                 box->x1 = 0.f;
17783                 box->x2 = alloc_w;
17784
17785                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17786                 box->y2 = box->y1 + (alloc_w * r_c);
17787               }
17788             else
17789               {
17790                 box->y1 = 0.f;
17791                 box->y2 = alloc_h;
17792
17793                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17794                 box->x2 = box->x1 + (alloc_h * r_c);
17795               }
17796           }
17797         else
17798           {
17799             if (r_a >= 1.0)
17800               {
17801                 box->y1 = 0.f;
17802                 box->y2 = alloc_h;
17803
17804                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17805                 box->x2 = box->x1 + (alloc_h * r_c);
17806               }
17807             else
17808               {
17809                 box->x1 = 0.f;
17810                 box->x2 = alloc_w;
17811
17812                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17813                 box->y2 = box->y1 + (alloc_w * r_c);
17814               }
17815           }
17816       }
17817       break;
17818     }
17819 }
17820
17821 /**
17822  * clutter_actor_set_content_scaling_filters:
17823  * @self: a #ClutterActor
17824  * @min_filter: the minification filter for the content
17825  * @mag_filter: the magnification filter for the content
17826  *
17827  * Sets the minification and magnification filter to be applied when
17828  * scaling the #ClutterActor:content of a #ClutterActor.
17829  *
17830  * The #ClutterActor:minification-filter will be used when reducing
17831  * the size of the content; the #ClutterActor:magnification-filter
17832  * will be used when increasing the size of the content.
17833  *
17834  * Since: 1.10
17835  */
17836 void
17837 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
17838                                            ClutterScalingFilter  min_filter,
17839                                            ClutterScalingFilter  mag_filter)
17840 {
17841   ClutterActorPrivate *priv;
17842   gboolean changed;
17843   GObject *obj;
17844
17845   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17846
17847   priv = self->priv;
17848   obj = G_OBJECT (self);
17849
17850   g_object_freeze_notify (obj);
17851
17852   changed = FALSE;
17853
17854   if (priv->min_filter != min_filter)
17855     {
17856       priv->min_filter = min_filter;
17857       changed = TRUE;
17858
17859       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
17860     }
17861
17862   if (priv->mag_filter != mag_filter)
17863     {
17864       priv->mag_filter = mag_filter;
17865       changed = TRUE;
17866
17867       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
17868     }
17869
17870   if (changed)
17871     clutter_actor_queue_redraw (self);
17872
17873   g_object_thaw_notify (obj);
17874 }
17875
17876 /**
17877  * clutter_actor_get_content_scaling_filters:
17878  * @self: a #ClutterActor
17879  * @min_filter: (out) (allow-none): return location for the minification
17880  *   filter, or %NULL
17881  * @mag_filter: (out) (allow-none): return location for the magnification
17882  *   filter, or %NULL
17883  *
17884  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
17885  *
17886  * Since: 1.10
17887  */
17888 void
17889 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
17890                                            ClutterScalingFilter *min_filter,
17891                                            ClutterScalingFilter *mag_filter)
17892 {
17893   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17894
17895   if (min_filter != NULL)
17896     *min_filter = self->priv->min_filter;
17897
17898   if (mag_filter != NULL)
17899     *mag_filter = self->priv->mag_filter;
17900 }