actor: Add paint_node virtual function
[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-events">
119  *   <title>Handling events on an actor</title>
120  *   <para>A #ClutterActor can receive and handle input device events, for
121  *   instance pointer events and key events, as long as its
122  *   #ClutterActor:reactive property is set to %TRUE.</para>
123  *   <para>Once an actor has been determined to be the source of an event,
124  *   Clutter will traverse the scene graph from the top-level actor towards the
125  *   event source, emitting the #ClutterActor::captured-event signal on each
126  *   ancestor until it reaches the source; this phase is also called
127  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
128  *   stopped, the graph is walked backwards, from the source actor to the
129  *   top-level, and the #ClutterActor::event signal, along with other event
130  *   signals if needed, is emitted; this phase is also called <emphasis>the
131  *   bubble phase</emphasis>. At any point of the signal emission, signal
132  *   handlers can stop the propagation through the scene graph by returning
133  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
134  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
135  * </refsect2>
136  *
137  * <refsect2 id="ClutterActor-subclassing">
138  *   <title>Implementing an actor</title>
139  *   <para>Careful consideration should be given when deciding to implement
140  *   a #ClutterActor sub-class. It is generally recommended to implement a
141  *   sub-class of #ClutterActor only for actors that should be used as leaf
142  *   nodes of a scene graph.</para>
143  *   <para>If your actor should be painted in a custom way, you should
144  *   override the #ClutterActor::paint signal class handler. You can either
145  *   opt to chain up to the parent class implementation or decide to fully
146  *   override the default paint implementation; Clutter will set up the
147  *   transformations and clip regions prior to emitting the #ClutterActor::paint
148  *   signal.</para>
149  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
150  *   #ClutterActorClass.get_preferred_height() virtual functions it is
151  *   possible to change or provide the preferred size of an actor; similarly,
152  *   by overriding the #ClutterActorClass.allocate() virtual function it is
153  *   possible to control the layout of the children of an actor. Make sure to
154  *   always chain up to the parent implementation of the
155  *   #ClutterActorClass.allocate() virtual function.</para>
156  *   <para>In general, it is strongly encouraged to use delegation and
157  *   composition instead of direct subclassing.</para>
158  * </refsect2>
159  *
160  * <refsect2 id="ClutterActor-script">
161  *   <title>ClutterActor custom properties for #ClutterScript</title>
162  *   <para>#ClutterActor defines a custom "rotation" property which
163  *   allows a short-hand description of the rotations to be applied
164  *   to an actor.</para>
165  *   <para>The syntax of the "rotation" property is the following:</para>
166  *   <informalexample>
167  *     <programlisting>
168  * "rotation" : [
169  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
170  * ]
171  *     </programlisting>
172  *   </informalexample>
173  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
174  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
175  *   floating point value representing the rotation angle on the given axis,
176  *   in degrees.</para>
177  *   <para>The <emphasis>center</emphasis> array is optional, and if present
178  *   it must contain the center of rotation as described by two coordinates:
179  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
180  *   "z-axis".</para>
181  *   <para>#ClutterActor will also parse every positional and dimensional
182  *   property defined as a string through clutter_units_from_string(); you
183  *   should read the documentation for the #ClutterUnits parser format for
184  *   the valid units and syntax.</para>
185  * </refsect2>
186  *
187  * <refsect2 id="ClutterActor-animating">
188  *   <title>Custom animatable properties</title>
189  *   <para>#ClutterActor allows accessing properties of #ClutterAction
190  *   and #ClutterConstraint instances associated to an actor instance
191  *   for animation purposes.</para>
192  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
193  *   property it is necessary to set the #ClutterActorMeta:name property on the
194  *   given action or constraint.</para>
195  *   <para>The property can be accessed using the following syntax:</para>
196  *   <informalexample>
197  *     <programlisting>
198  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
199  *     </programlisting>
200  *   </informalexample>
201  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
202  *   <para>The <emphasis>section</emphasis> fragment can be one between
203  *   "actions", "constraints" and "effects".</para>
204  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
205  *   action or constraint, as specified by the #ClutterActorMeta:name
206  *   property.</para>
207  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
208  *   action or constraint property to be animated.</para>
209  *   <para>The example below animates a #ClutterBindConstraint applied to an
210  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
211  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
212  *   its initial state is fully transparent and overlapping the actor to
213  *   which is bound to. </para>
214  *   <informalexample><programlisting>
215  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
216  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
217  * clutter_actor_add_constraint (rect, constraint);
218  *
219  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
220  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
221  * clutter_actor_add_constraint (rect, constraint);
222  *
223  * clutter_actor_set_reactive (rect, TRUE);
224  * clutter_actor_set_opacity (rect, 0);
225  *
226  * g_signal_connect (rect, "button-press-event",
227  *                   G_CALLBACK (on_button_press),
228  *                   NULL);
229  *   </programlisting></informalexample>
230  *   <para>On button press, the rectangle "slides" from behind the actor to
231  *   which is bound to, using the #ClutterBindConstraint:offset property and
232  *   the #ClutterActor:opacity property.</para>
233  *   <informalexample><programlisting>
234  * float new_offset = clutter_actor_get_width (origin) + h_padding;
235  *
236  * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
237  *                        "opacity", 255,
238  *                        "@constraints.bind-x.offset", new_offset,
239  *                        NULL);
240  *   </programlisting></informalexample>
241  * </refsect2>
242  *
243  * <refsect2 id="ClutterActor-animatable-properties">
244  *   <title>Animatable properties</title>
245  *   <para>Certain properties on #ClutterActor are marked as "animatable";
246  *   these properties will be automatically tweened between the current
247  *   value and the new value when one is set.</para>
248  *   <para>For backward compatibility, animatable properties will only be
249  *   tweened if the easing duration is greater than 0, or if a new easing
250  *   state is set, for instance the following example:</para>
251  *   <informalexample><programlisting>
252  * clutter_actor_save_easing_state (actor);
253  * clutter_actor_set_position (actor, 200, 200);
254  * clutter_actor_restore_easing_state (actor);
255  *   </programlisting></informalexample>
256  *   <para>will tween the actor to the (200, 200) coordinates using the default
257  *   easing mode and duration of a new easing state. The example above is
258  *   equivalent to the following code:</para>
259  *   <informalexample><programlisting>
260  * clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC);
261  * clutter_actor_set_easing_duration (actor, 250);
262  * clutter_actor_set_position (actor, 200, 200);
263  * clutter_actor_restore_easing_state (actor);
264  *   </programlisting></informalexample>
265  *   <para>It is possible to nest easing states to tween animatable
266  *   properties using different modes and durations, for instance:</para>
267  *   <informalexample><programlisting>
268  * clutter_actor_save_easing_state (actor); /&ast; outer state &ast;/
269  *
270  * /&ast; set the duration of the animation to 2 seconds and change position &ast;/
271  * clutter_actor_set_easing_duration (actor, 2000);
272  * clutter_actor_set_position (actor, 0, 0);
273  *
274  * clutter_actor_save_easing_state (actor); /&ast; inner state &ast;/
275  *
276  * /&ast; set the duration of the animation to 5 seconds and change depth and opacity &ast;/
277  * clutter_actor_set_easing_duration (actor, 5000);
278  * clutter_actor_set_depth (actor, 200);
279  * clutter_actor_set_opacity (actor, 0);
280  *
281  * clutter_actor_restore_easing_state (actor);
282  *
283  * clutter_actor_restore_easing_state (actor);
284  *   </programlisting></informalexample>
285  * </refsect2>
286  */
287
288 /**
289  * CLUTTER_ACTOR_IS_MAPPED:
290  * @a: a #ClutterActor
291  *
292  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
293  *
294  * The mapped state is set when the actor is visible and all its parents up
295  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
296  *
297  * This check can be used to see if an actor is going to be painted, as only
298  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
299  *
300  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
301  * not be checked directly; instead, the recommended usage is to connect a
302  * handler on the #GObject::notify signal for the #ClutterActor:mapped
303  * property of #ClutterActor, and check the presence of
304  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
305  *
306  * It is also important to note that Clutter may delay the changes of
307  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
308  * limitations, or during the reparenting of an actor, to optimize
309  * unnecessary (and potentially expensive) state changes.
310  *
311  * Since: 0.2
312  */
313
314 /**
315  * CLUTTER_ACTOR_IS_REALIZED:
316  * @a: a #ClutterActor
317  *
318  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
319  *
320  * The realized state has an actor-dependant interpretation. If an
321  * actor wants to delay allocating resources until it is attached to a
322  * stage, it may use the realize state to do so. However it is
323  * perfectly acceptable for an actor to allocate Cogl resources before
324  * being realized because there is only one drawing context used by Clutter
325  * so any resources will work on any stage.  If an actor is mapped it
326  * must also be realized, but an actor can be realized and unmapped
327  * (this is so hiding an actor temporarily doesn't do an expensive
328  * unrealize/realize).
329  *
330  * To be realized an actor must be inside a stage, and all its parents
331  * must be realized.
332  *
333  * Since: 0.2
334  */
335
336 /**
337  * CLUTTER_ACTOR_IS_VISIBLE:
338  * @a: a #ClutterActor
339  *
340  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
341  * Equivalent to the ClutterActor::visible object property.
342  *
343  * Note that an actor is only painted onscreen if it's mapped, which
344  * means it's visible, and all its parents are visible, and one of the
345  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
346  *
347  * Since: 0.2
348  */
349
350 /**
351  * CLUTTER_ACTOR_IS_REACTIVE:
352  * @a: a #ClutterActor
353  *
354  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
355  *
356  * Only reactive actors will receive event-related signals.
357  *
358  * Since: 0.6
359  */
360
361 #ifdef HAVE_CONFIG_H
362 #include "config.h"
363 #endif
364
365 #include <math.h>
366
367 #include <gobject/gvaluecollector.h>
368
369 #include <cogl/cogl.h>
370
371 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
372 #define CLUTTER_ENABLE_EXPERIMENTAL_API
373
374 #include "clutter-actor-private.h"
375
376 #include "clutter-action.h"
377 #include "clutter-actor-meta-private.h"
378 #include "clutter-animatable.h"
379 #include "clutter-color-static.h"
380 #include "clutter-color.h"
381 #include "clutter-constraint.h"
382 #include "clutter-container.h"
383 #include "clutter-debug.h"
384 #include "clutter-effect-private.h"
385 #include "clutter-enum-types.h"
386 #include "clutter-fixed-layout.h"
387 #include "clutter-flatten-effect.h"
388 #include "clutter-interval.h"
389 #include "clutter-main.h"
390 #include "clutter-marshal.h"
391 #include "clutter-paint-nodes.h"
392 #include "clutter-paint-node-private.h"
393 #include "clutter-paint-volume-private.h"
394 #include "clutter-private.h"
395 #include "clutter-profile.h"
396 #include "clutter-property-transition.h"
397 #include "clutter-scriptable.h"
398 #include "clutter-script-private.h"
399 #include "clutter-stage-private.h"
400 #include "clutter-timeline.h"
401 #include "clutter-transition.h"
402 #include "clutter-units.h"
403
404 #include "deprecated/clutter-actor.h"
405 #include "deprecated/clutter-behaviour.h"
406 #include "deprecated/clutter-container.h"
407
408 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
409 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
410
411 /* Internal enum used to control mapped state update.  This is a hint
412  * which indicates when to do something other than just enforce
413  * invariants.
414  */
415 typedef enum {
416   MAP_STATE_CHECK,           /* just enforce invariants. */
417   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
418                               * used when about to unparent.
419                               */
420   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
421                               * used to set mapped on toplevels.
422                               */
423   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
424                               * used just before unmapping parent.
425                               */
426 } MapStateChange;
427
428 /* 3 entries should be a good compromise, few layout managers
429  * will ask for 3 different preferred size in each allocation cycle */
430 #define N_CACHED_SIZE_REQUESTS 3
431
432 struct _ClutterActorPrivate
433 {
434   /* request mode */
435   ClutterRequestMode request_mode;
436
437   /* our cached size requests for different width / height */
438   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
439   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
440
441   /* An age of 0 means the entry is not set */
442   guint cached_height_age;
443   guint cached_width_age;
444
445   /* the bounding box of the actor, relative to the parent's
446    * allocation
447    */
448   ClutterActorBox allocation;
449   ClutterAllocationFlags allocation_flags;
450
451   /* clip, in actor coordinates */
452   cairo_rectangle_t clip;
453
454   /* the cached transformation matrix; see apply_transform() */
455   CoglMatrix transform;
456
457   guint8 opacity;
458   gint opacity_override;
459
460   ClutterOffscreenRedirect offscreen_redirect;
461
462   /* This is an internal effect used to implement the
463      offscreen-redirect property */
464   ClutterEffect *flatten_effect;
465
466   /* scene graph */
467   ClutterActor *parent;
468   ClutterActor *prev_sibling;
469   ClutterActor *next_sibling;
470   ClutterActor *first_child;
471   ClutterActor *last_child;
472
473   gint n_children;
474
475   /* tracks whenever the children of an actor are changed; the
476    * age is incremented by 1 whenever an actor is added or
477    * removed. the age is not incremented when the first or the
478    * last child pointers are changed, or when grandchildren of
479    * an actor are changed.
480    */
481   gint age;
482
483   gchar *name; /* a non-unique name, used for debugging */
484   guint32 id; /* unique id, used for backward compatibility */
485
486   gint32 pick_id; /* per-stage unique id, used for picking */
487
488   /* a back-pointer to the Pango context that we can use
489    * to create pre-configured PangoLayout
490    */
491   PangoContext *pango_context;
492
493   /* the text direction configured for this child - either by
494    * application code, or by the actor's parent
495    */
496   ClutterTextDirection text_direction;
497
498   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
499   gint internal_child;
500
501   /* meta classes */
502   ClutterMetaGroup *actions;
503   ClutterMetaGroup *constraints;
504   ClutterMetaGroup *effects;
505
506   /* delegate object used to allocate the children of this actor */
507   ClutterLayoutManager *layout_manager;
508
509   /* used when painting, to update the paint volume */
510   ClutterEffect *current_effect;
511
512   /* This is used to store an effect which needs to be redrawn. A
513      redraw can be queued to start from a particular effect. This is
514      used by parametrised effects that can cache an image of the
515      actor. If a parameter of the effect changes then it only needs to
516      redraw the cached image, not the actual actor. The pointer is
517      only valid if is_dirty == TRUE. If the pointer is NULL then the
518      whole actor is dirty. */
519   ClutterEffect *effect_to_redraw;
520
521   /* This is used when painting effects to implement the
522      clutter_actor_continue_paint() function. It points to the node in
523      the list of effects that is next in the chain */
524   const GList *next_effect_to_paint;
525
526   ClutterPaintVolume paint_volume;
527
528   /* NB: This volume isn't relative to this actor, it is in eye
529    * coordinates so that it can remain valid after the actor changes.
530    */
531   ClutterPaintVolume last_paint_volume;
532
533   ClutterStageQueueRedrawEntry *queue_redraw_entry;
534
535   ClutterColor bg_color;
536
537   /* bitfields */
538
539   /* fixed position and sizes */
540   guint position_set                : 1;
541   guint min_width_set               : 1;
542   guint min_height_set              : 1;
543   guint natural_width_set           : 1;
544   guint natural_height_set          : 1;
545   /* cached request is invalid (implies allocation is too) */
546   guint needs_width_request         : 1;
547   /* cached request is invalid (implies allocation is too) */
548   guint needs_height_request        : 1;
549   /* cached allocation is invalid (request has changed, probably) */
550   guint needs_allocation            : 1;
551   guint show_on_set_parent          : 1;
552   guint has_clip                    : 1;
553   guint clip_to_allocation          : 1;
554   guint enable_model_view_transform : 1;
555   guint enable_paint_unmapped       : 1;
556   guint has_pointer                 : 1;
557   guint propagated_one_redraw       : 1;
558   guint paint_volume_valid          : 1;
559   guint last_paint_volume_valid     : 1;
560   guint in_clone_paint              : 1;
561   guint transform_valid             : 1;
562   /* This is TRUE if anything has queued a redraw since we were last
563      painted. In this case effect_to_redraw will point to an effect
564      the redraw was queued from or it will be NULL if the redraw was
565      queued without an effect. */
566   guint is_dirty                    : 1;
567   guint bg_color_set                : 1;
568 };
569
570 enum
571 {
572   PROP_0,
573
574   PROP_NAME,
575
576   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
577    * when set they force a size request, when gotten they
578    * get the allocation if the allocation is valid, and the
579    * request otherwise
580    */
581   PROP_X,
582   PROP_Y,
583   PROP_WIDTH,
584   PROP_HEIGHT,
585
586   /* Then the rest of these size-related properties are the "actual"
587    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
588    */
589   PROP_FIXED_X,
590   PROP_FIXED_Y,
591
592   PROP_FIXED_POSITION_SET,
593
594   PROP_MIN_WIDTH,
595   PROP_MIN_WIDTH_SET,
596
597   PROP_MIN_HEIGHT,
598   PROP_MIN_HEIGHT_SET,
599
600   PROP_NATURAL_WIDTH,
601   PROP_NATURAL_WIDTH_SET,
602
603   PROP_NATURAL_HEIGHT,
604   PROP_NATURAL_HEIGHT_SET,
605
606   PROP_REQUEST_MODE,
607
608   /* Allocation properties are read-only */
609   PROP_ALLOCATION,
610
611   PROP_DEPTH,
612
613   PROP_CLIP,
614   PROP_HAS_CLIP,
615   PROP_CLIP_TO_ALLOCATION,
616
617   PROP_OPACITY,
618
619   PROP_OFFSCREEN_REDIRECT,
620
621   PROP_VISIBLE,
622   PROP_MAPPED,
623   PROP_REALIZED,
624   PROP_REACTIVE,
625
626   PROP_SCALE_X,
627   PROP_SCALE_Y,
628   PROP_SCALE_CENTER_X,
629   PROP_SCALE_CENTER_Y,
630   PROP_SCALE_GRAVITY,
631
632   PROP_ROTATION_ANGLE_X,
633   PROP_ROTATION_ANGLE_Y,
634   PROP_ROTATION_ANGLE_Z,
635   PROP_ROTATION_CENTER_X,
636   PROP_ROTATION_CENTER_Y,
637   PROP_ROTATION_CENTER_Z,
638   /* This property only makes sense for the z rotation because the
639      others would depend on the actor having a size along the
640      z-axis */
641   PROP_ROTATION_CENTER_Z_GRAVITY,
642
643   PROP_ANCHOR_X,
644   PROP_ANCHOR_Y,
645   PROP_ANCHOR_GRAVITY,
646
647   PROP_SHOW_ON_SET_PARENT,
648
649   PROP_TEXT_DIRECTION,
650   PROP_HAS_POINTER,
651
652   PROP_ACTIONS,
653   PROP_CONSTRAINTS,
654   PROP_EFFECT,
655
656   PROP_LAYOUT_MANAGER,
657
658   PROP_X_ALIGN,
659   PROP_Y_ALIGN,
660   PROP_MARGIN_TOP,
661   PROP_MARGIN_BOTTOM,
662   PROP_MARGIN_LEFT,
663   PROP_MARGIN_RIGHT,
664
665   PROP_BACKGROUND_COLOR,
666   PROP_BACKGROUND_COLOR_SET,
667
668   PROP_FIRST_CHILD,
669   PROP_LAST_CHILD,
670
671   PROP_LAST
672 };
673
674 static GParamSpec *obj_props[PROP_LAST];
675
676 enum
677 {
678   SHOW,
679   HIDE,
680   DESTROY,
681   PARENT_SET,
682   KEY_FOCUS_IN,
683   KEY_FOCUS_OUT,
684   PAINT,
685   PICK,
686   REALIZE,
687   UNREALIZE,
688   QUEUE_REDRAW,
689   QUEUE_RELAYOUT,
690   EVENT,
691   CAPTURED_EVENT,
692   BUTTON_PRESS_EVENT,
693   BUTTON_RELEASE_EVENT,
694   SCROLL_EVENT,
695   KEY_PRESS_EVENT,
696   KEY_RELEASE_EVENT,
697   MOTION_EVENT,
698   ENTER_EVENT,
699   LEAVE_EVENT,
700   ALLOCATION_CHANGED,
701
702   LAST_SIGNAL
703 };
704
705 static guint actor_signals[LAST_SIGNAL] = { 0, };
706
707 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
708 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
709 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
710 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
711
712 /* These setters are all static for now, maybe they should be in the
713  * public API, but they are perhaps obscure enough to leave only as
714  * properties
715  */
716 static void clutter_actor_set_min_width          (ClutterActor *self,
717                                                   gfloat        min_width);
718 static void clutter_actor_set_min_height         (ClutterActor *self,
719                                                   gfloat        min_height);
720 static void clutter_actor_set_natural_width      (ClutterActor *self,
721                                                   gfloat        natural_width);
722 static void clutter_actor_set_natural_height     (ClutterActor *self,
723                                                   gfloat        natural_height);
724 static void clutter_actor_set_min_width_set      (ClutterActor *self,
725                                                   gboolean      use_min_width);
726 static void clutter_actor_set_min_height_set     (ClutterActor *self,
727                                                   gboolean      use_min_height);
728 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
729                                                   gboolean  use_natural_width);
730 static void clutter_actor_set_natural_height_set (ClutterActor *self,
731                                                   gboolean  use_natural_height);
732 static void clutter_actor_update_map_state       (ClutterActor  *self,
733                                                   MapStateChange change);
734 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
735
736 /* Helper routines for managing anchor coords */
737 static void clutter_anchor_coord_get_units (ClutterActor      *self,
738                                             const AnchorCoord *coord,
739                                             gfloat            *x,
740                                             gfloat            *y,
741                                             gfloat            *z);
742 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
743                                             gfloat             x,
744                                             gfloat             y,
745                                             gfloat             z);
746
747 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
748 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
749                                                         ClutterGravity     gravity);
750
751 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
752
753 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
754
755 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
756                                                                ClutterActor *ancestor,
757                                                                CoglMatrix *matrix);
758
759 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
760
761 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
762
763 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
764                                                                 const ClutterColor *color);
765
766 static void on_layout_manager_changed (ClutterLayoutManager *manager,
767                                        ClutterActor         *self);
768
769 /* Helper macro which translates by the anchor coord, applies the
770    given transformation and then translates back */
771 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
772   gfloat _tx, _ty, _tz;                                                \
773   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
774   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
775   { _transform; }                                                      \
776   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
777
778 static GQuark quark_shader_data = 0;
779 static GQuark quark_actor_layout_info = 0;
780 static GQuark quark_actor_transform_info = 0;
781 static GQuark quark_actor_animation_info = 0;
782
783 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
784                          clutter_actor,
785                          G_TYPE_INITIALLY_UNOWNED,
786                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
787                                                 clutter_container_iface_init)
788                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
789                                                 clutter_scriptable_iface_init)
790                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
791                                                 clutter_animatable_iface_init)
792                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
793                                                 atk_implementor_iface_init));
794
795 /*< private >
796  * clutter_actor_get_debug_name:
797  * @actor: a #ClutterActor
798  *
799  * Retrieves a printable name of @actor for debugging messages
800  *
801  * Return value: a string with a printable name
802  */
803 const gchar *
804 _clutter_actor_get_debug_name (ClutterActor *actor)
805 {
806   return actor->priv->name != NULL ? actor->priv->name
807                                    : G_OBJECT_TYPE_NAME (actor);
808 }
809
810 #ifdef CLUTTER_ENABLE_DEBUG
811 /* XXX - this is for debugging only, remove once working (or leave
812  * in only in some debug mode). Should leave it for a little while
813  * until we're confident in the new map/realize/visible handling.
814  */
815 static inline void
816 clutter_actor_verify_map_state (ClutterActor *self)
817 {
818   ClutterActorPrivate *priv = self->priv;
819
820   if (CLUTTER_ACTOR_IS_REALIZED (self))
821     {
822       /* all bets are off during reparent when we're potentially realized,
823        * but should not be according to invariants
824        */
825       if (!CLUTTER_ACTOR_IN_REPARENT (self))
826         {
827           if (priv->parent == NULL)
828             {
829               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
830                 {
831                 }
832               else
833                 g_warning ("Realized non-toplevel actor '%s' should "
834                            "have a parent",
835                            _clutter_actor_get_debug_name (self));
836             }
837           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
838             {
839               g_warning ("Realized actor %s has an unrealized parent %s",
840                          _clutter_actor_get_debug_name (self),
841                          _clutter_actor_get_debug_name (priv->parent));
842             }
843         }
844     }
845
846   if (CLUTTER_ACTOR_IS_MAPPED (self))
847     {
848       if (!CLUTTER_ACTOR_IS_REALIZED (self))
849         g_warning ("Actor '%s' is mapped but not realized",
850                    _clutter_actor_get_debug_name (self));
851
852       /* remaining bets are off during reparent when we're potentially
853        * mapped, but should not be according to invariants
854        */
855       if (!CLUTTER_ACTOR_IN_REPARENT (self))
856         {
857           if (priv->parent == NULL)
858             {
859               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
860                 {
861                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
862                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
863                     {
864                       g_warning ("Toplevel actor '%s' is mapped "
865                                  "but not visible",
866                                  _clutter_actor_get_debug_name (self));
867                     }
868                 }
869               else
870                 {
871                   g_warning ("Mapped actor '%s' should have a parent",
872                              _clutter_actor_get_debug_name (self));
873                 }
874             }
875           else
876             {
877               ClutterActor *iter = self;
878
879               /* check for the enable_paint_unmapped flag on the actor
880                * and parents; if the flag is enabled at any point of this
881                * branch of the scene graph then all the later checks
882                * become pointless
883                */
884               while (iter != NULL)
885                 {
886                   if (iter->priv->enable_paint_unmapped)
887                     return;
888
889                   iter = iter->priv->parent;
890                 }
891
892               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
893                 {
894                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
895                              "is not visible",
896                              _clutter_actor_get_debug_name (self),
897                              _clutter_actor_get_debug_name (priv->parent));
898                 }
899
900               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
901                 {
902                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
903                              "is not realized",
904                              _clutter_actor_get_debug_name (self),
905                              _clutter_actor_get_debug_name (priv->parent));
906                 }
907
908               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
909                 {
910                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
911                     g_warning ("Actor '%s' is mapped but its non-toplevel "
912                                "parent '%s' is not mapped",
913                                _clutter_actor_get_debug_name (self),
914                                _clutter_actor_get_debug_name (priv->parent));
915                 }
916             }
917         }
918     }
919 }
920
921 #endif /* CLUTTER_ENABLE_DEBUG */
922
923 static void
924 clutter_actor_set_mapped (ClutterActor *self,
925                           gboolean      mapped)
926 {
927   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
928     return;
929
930   if (mapped)
931     {
932       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
933       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
934     }
935   else
936     {
937       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
938       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
939     }
940 }
941
942 /* this function updates the mapped and realized states according to
943  * invariants, in the appropriate order.
944  */
945 static void
946 clutter_actor_update_map_state (ClutterActor  *self,
947                                 MapStateChange change)
948 {
949   gboolean was_mapped;
950
951   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
952
953   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
954     {
955       /* the mapped flag on top-level actors must be set by the
956        * per-backend implementation because it might be asynchronous.
957        *
958        * That is, the MAPPED flag on toplevels currently tracks the X
959        * server mapped-ness of the window, while the expected behavior
960        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
961        * This creates some weird complexity by breaking the invariant
962        * that if we're visible and all ancestors shown then we are
963        * also mapped - instead, we are mapped if all ancestors
964        * _possibly excepting_ the stage are mapped. The stage
965        * will map/unmap for example when it is minimized or
966        * moved to another workspace.
967        *
968        * So, the only invariant on the stage is that if visible it
969        * should be realized, and that it has to be visible to be
970        * mapped.
971        */
972       if (CLUTTER_ACTOR_IS_VISIBLE (self))
973         clutter_actor_realize (self);
974
975       switch (change)
976         {
977         case MAP_STATE_CHECK:
978           break;
979
980         case MAP_STATE_MAKE_MAPPED:
981           g_assert (!was_mapped);
982           clutter_actor_set_mapped (self, TRUE);
983           break;
984
985         case MAP_STATE_MAKE_UNMAPPED:
986           g_assert (was_mapped);
987           clutter_actor_set_mapped (self, FALSE);
988           break;
989
990         case MAP_STATE_MAKE_UNREALIZED:
991           /* we only use MAKE_UNREALIZED in unparent,
992            * and unparenting a stage isn't possible.
993            * If someone wants to just unrealize a stage
994            * then clutter_actor_unrealize() doesn't
995            * go through this codepath.
996            */
997           g_warning ("Trying to force unrealize stage is not allowed");
998           break;
999         }
1000
1001       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1002           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1003           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1004         {
1005           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1006                      "it is somehow still mapped",
1007                      _clutter_actor_get_debug_name (self));
1008         }
1009     }
1010   else
1011     {
1012       ClutterActorPrivate *priv = self->priv;
1013       ClutterActor *parent = priv->parent;
1014       gboolean should_be_mapped;
1015       gboolean may_be_realized;
1016       gboolean must_be_realized;
1017
1018       should_be_mapped = FALSE;
1019       may_be_realized = TRUE;
1020       must_be_realized = FALSE;
1021
1022       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1023         {
1024           may_be_realized = FALSE;
1025         }
1026       else
1027         {
1028           /* Maintain invariant that if parent is mapped, and we are
1029            * visible, then we are mapped ...  unless parent is a
1030            * stage, in which case we map regardless of parent's map
1031            * state but do require stage to be visible and realized.
1032            *
1033            * If parent is realized, that does not force us to be
1034            * realized; but if parent is unrealized, that does force
1035            * us to be unrealized.
1036            *
1037            * The reason we don't force children to realize with
1038            * parents is _clutter_actor_rerealize(); if we require that
1039            * a realized parent means children are realized, then to
1040            * unrealize an actor we would have to unrealize its
1041            * parents, which would end up meaning unrealizing and
1042            * hiding the entire stage. So we allow unrealizing a
1043            * child (as long as that child is not mapped) while that
1044            * child still has a realized parent.
1045            *
1046            * Also, if we unrealize from leaf nodes to root, and
1047            * realize from root to leaf, the invariants are never
1048            * violated if we allow children to be unrealized
1049            * while parents are realized.
1050            *
1051            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1052            * to force us to unmap, even though parent is still
1053            * mapped. This is because we're unmapping from leaf nodes
1054            * up to root nodes.
1055            */
1056           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1057               change != MAP_STATE_MAKE_UNMAPPED)
1058             {
1059               gboolean parent_is_visible_realized_toplevel;
1060
1061               parent_is_visible_realized_toplevel =
1062                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1063                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1064                  CLUTTER_ACTOR_IS_REALIZED (parent));
1065
1066               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1067                   parent_is_visible_realized_toplevel)
1068                 {
1069                   must_be_realized = TRUE;
1070                   should_be_mapped = TRUE;
1071                 }
1072             }
1073
1074           /* if the actor has been set to be painted even if unmapped
1075            * then we should map it and check for realization as well;
1076            * this is an override for the branch of the scene graph
1077            * which begins with this node
1078            */
1079           if (priv->enable_paint_unmapped)
1080             {
1081               if (priv->parent == NULL)
1082                 g_warning ("Attempting to map an unparented actor '%s'",
1083                            _clutter_actor_get_debug_name (self));
1084
1085               should_be_mapped = TRUE;
1086               must_be_realized = TRUE;
1087             }
1088
1089           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1090             may_be_realized = FALSE;
1091         }
1092
1093       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1094         {
1095           if (parent == NULL)
1096             g_warning ("Attempting to map a child that does not "
1097                        "meet the necessary invariants: the actor '%s' "
1098                        "has no parent",
1099                        _clutter_actor_get_debug_name (self));
1100           else
1101             g_warning ("Attempting to map a child that does not "
1102                        "meet the necessary invariants: the actor '%s' "
1103                        "is parented to an unmapped actor '%s'",
1104                        _clutter_actor_get_debug_name (self),
1105                        _clutter_actor_get_debug_name (priv->parent));
1106         }
1107
1108       /* If in reparent, we temporarily suspend unmap and unrealize.
1109        *
1110        * We want to go in the order "realize, map" and "unmap, unrealize"
1111        */
1112
1113       /* Unmap */
1114       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1115         clutter_actor_set_mapped (self, FALSE);
1116
1117       /* Realize */
1118       if (must_be_realized)
1119         clutter_actor_realize (self);
1120
1121       /* if we must be realized then we may be, presumably */
1122       g_assert (!(must_be_realized && !may_be_realized));
1123
1124       /* Unrealize */
1125       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1126         clutter_actor_unrealize_not_hiding (self);
1127
1128       /* Map */
1129       if (should_be_mapped)
1130         {
1131           if (!must_be_realized)
1132             g_warning ("Somehow we think actor '%s' should be mapped but "
1133                        "not realized, which isn't allowed",
1134                        _clutter_actor_get_debug_name (self));
1135
1136           /* realization is allowed to fail (though I don't know what
1137            * an app is supposed to do about that - shouldn't it just
1138            * be a g_error? anyway, we have to avoid mapping if this
1139            * happens)
1140            */
1141           if (CLUTTER_ACTOR_IS_REALIZED (self))
1142             clutter_actor_set_mapped (self, TRUE);
1143         }
1144     }
1145
1146 #ifdef CLUTTER_ENABLE_DEBUG
1147   /* check all invariants were kept */
1148   clutter_actor_verify_map_state (self);
1149 #endif
1150 }
1151
1152 static void
1153 clutter_actor_real_map (ClutterActor *self)
1154 {
1155   ClutterActorPrivate *priv = self->priv;
1156   ClutterActor *stage, *iter;
1157
1158   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1159
1160   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1161                 _clutter_actor_get_debug_name (self));
1162
1163   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1164
1165   stage = _clutter_actor_get_stage_internal (self);
1166   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1167
1168   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1169                 priv->pick_id,
1170                 _clutter_actor_get_debug_name (self));
1171
1172   /* notify on parent mapped before potentially mapping
1173    * children, so apps see a top-down notification.
1174    */
1175   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1176
1177   for (iter = self->priv->first_child;
1178        iter != NULL;
1179        iter = iter->priv->next_sibling)
1180     {
1181       clutter_actor_map (iter);
1182     }
1183 }
1184
1185 /**
1186  * clutter_actor_map:
1187  * @self: A #ClutterActor
1188  *
1189  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1190  * and realizes its children if they are visible. Does nothing if the
1191  * actor is not visible.
1192  *
1193  * Calling this function is strongly disencouraged: the default
1194  * implementation of #ClutterActorClass.map() will map all the children
1195  * of an actor when mapping its parent.
1196  *
1197  * When overriding map, it is mandatory to chain up to the parent
1198  * implementation.
1199  *
1200  * Since: 1.0
1201  */
1202 void
1203 clutter_actor_map (ClutterActor *self)
1204 {
1205   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1206
1207   if (CLUTTER_ACTOR_IS_MAPPED (self))
1208     return;
1209
1210   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1211     return;
1212
1213   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1214 }
1215
1216 static void
1217 clutter_actor_real_unmap (ClutterActor *self)
1218 {
1219   ClutterActorPrivate *priv = self->priv;
1220   ClutterActor *iter;
1221
1222   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1223
1224   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1225                 _clutter_actor_get_debug_name (self));
1226
1227   for (iter = self->priv->first_child;
1228        iter != NULL;
1229        iter = iter->priv->next_sibling)
1230     {
1231       clutter_actor_unmap (iter);
1232     }
1233
1234   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1235
1236   /* clear the contents of the last paint volume, so that hiding + moving +
1237    * showing will not result in the wrong area being repainted
1238    */
1239   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1240   priv->last_paint_volume_valid = TRUE;
1241
1242   /* notify on parent mapped after potentially unmapping
1243    * children, so apps see a bottom-up notification.
1244    */
1245   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1246
1247   /* relinquish keyboard focus if we were unmapped while owning it */
1248   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1249     {
1250       ClutterStage *stage;
1251
1252       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1253
1254       if (stage != NULL)
1255         _clutter_stage_release_pick_id (stage, priv->pick_id);
1256
1257       priv->pick_id = -1;
1258
1259       if (stage != NULL &&
1260           clutter_stage_get_key_focus (stage) == self)
1261         {
1262           clutter_stage_set_key_focus (stage, NULL);
1263         }
1264     }
1265 }
1266
1267 /**
1268  * clutter_actor_unmap:
1269  * @self: A #ClutterActor
1270  *
1271  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1272  * unmaps its children if they were mapped.
1273  *
1274  * Calling this function is not encouraged: the default #ClutterActor
1275  * implementation of #ClutterActorClass.unmap() will also unmap any
1276  * eventual children by default when their parent is unmapped.
1277  *
1278  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1279  * chain up to the parent implementation.
1280  *
1281  * <note>It is important to note that the implementation of the
1282  * #ClutterActorClass.unmap() virtual function may be called after
1283  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1284  * implementation, but it is guaranteed to be called before the
1285  * #GObjectClass.finalize() implementation.</note>
1286  *
1287  * Since: 1.0
1288  */
1289 void
1290 clutter_actor_unmap (ClutterActor *self)
1291 {
1292   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1293
1294   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1295     return;
1296
1297   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1298 }
1299
1300 static void
1301 clutter_actor_real_show (ClutterActor *self)
1302 {
1303   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1304     {
1305       ClutterActorPrivate *priv = self->priv;
1306
1307       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1308
1309       /* we notify on the "visible" flag in the clutter_actor_show()
1310        * wrapper so the entire show signal emission completes first
1311        * (?)
1312        */
1313       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1314
1315       /* we queue a relayout unless the actor is inside a
1316        * container that explicitly told us not to
1317        */
1318       if (priv->parent != NULL &&
1319           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1320         {
1321           /* While an actor is hidden the parent may not have
1322            * allocated/requested so we need to start from scratch
1323            * and avoid the short-circuiting in
1324            * clutter_actor_queue_relayout().
1325            */
1326           priv->needs_width_request  = FALSE;
1327           priv->needs_height_request = FALSE;
1328           priv->needs_allocation     = FALSE;
1329           clutter_actor_queue_relayout (self);
1330         }
1331     }
1332 }
1333
1334 static inline void
1335 set_show_on_set_parent (ClutterActor *self,
1336                         gboolean      set_show)
1337 {
1338   ClutterActorPrivate *priv = self->priv;
1339
1340   set_show = !!set_show;
1341
1342   if (priv->show_on_set_parent == set_show)
1343     return;
1344
1345   if (priv->parent == NULL)
1346     {
1347       priv->show_on_set_parent = set_show;
1348       g_object_notify_by_pspec (G_OBJECT (self),
1349                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1350     }
1351 }
1352
1353 /**
1354  * clutter_actor_show:
1355  * @self: A #ClutterActor
1356  *
1357  * Flags an actor to be displayed. An actor that isn't shown will not
1358  * be rendered on the stage.
1359  *
1360  * Actors are visible by default.
1361  *
1362  * If this function is called on an actor without a parent, the
1363  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1364  * effect.
1365  */
1366 void
1367 clutter_actor_show (ClutterActor *self)
1368 {
1369   ClutterActorPrivate *priv;
1370
1371   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1372
1373   /* simple optimization */
1374   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1375     {
1376       /* we still need to set the :show-on-set-parent property, in
1377        * case show() is called on an unparented actor
1378        */
1379       set_show_on_set_parent (self, TRUE);
1380       return;
1381     }
1382
1383 #ifdef CLUTTER_ENABLE_DEBUG
1384   clutter_actor_verify_map_state (self);
1385 #endif
1386
1387   priv = self->priv;
1388
1389   g_object_freeze_notify (G_OBJECT (self));
1390
1391   set_show_on_set_parent (self, TRUE);
1392
1393   g_signal_emit (self, actor_signals[SHOW], 0);
1394   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1395
1396   if (priv->parent != NULL)
1397     clutter_actor_queue_redraw (priv->parent);
1398
1399   g_object_thaw_notify (G_OBJECT (self));
1400 }
1401
1402 /**
1403  * clutter_actor_show_all:
1404  * @self: a #ClutterActor
1405  *
1406  * Calls clutter_actor_show() on all children of an actor (if any).
1407  *
1408  * Since: 0.2
1409  *
1410  * Deprecated: 1.10: Actors are visible by default
1411  */
1412 void
1413 clutter_actor_show_all (ClutterActor *self)
1414 {
1415   ClutterActorClass *klass;
1416
1417   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1418
1419   klass = CLUTTER_ACTOR_GET_CLASS (self);
1420   if (klass->show_all)
1421     klass->show_all (self);
1422 }
1423
1424 static void
1425 clutter_actor_real_hide (ClutterActor *self)
1426 {
1427   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1428     {
1429       ClutterActorPrivate *priv = self->priv;
1430
1431       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1432
1433       /* we notify on the "visible" flag in the clutter_actor_hide()
1434        * wrapper so the entire hide signal emission completes first
1435        * (?)
1436        */
1437       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1438
1439       /* we queue a relayout unless the actor is inside a
1440        * container that explicitly told us not to
1441        */
1442       if (priv->parent != NULL &&
1443           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1444         clutter_actor_queue_relayout (priv->parent);
1445     }
1446 }
1447
1448 /**
1449  * clutter_actor_hide:
1450  * @self: A #ClutterActor
1451  *
1452  * Flags an actor to be hidden. A hidden actor will not be
1453  * rendered on the stage.
1454  *
1455  * Actors are visible by default.
1456  *
1457  * If this function is called on an actor without a parent, the
1458  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1459  * as a side-effect.
1460  */
1461 void
1462 clutter_actor_hide (ClutterActor *self)
1463 {
1464   ClutterActorPrivate *priv;
1465
1466   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1467
1468   /* simple optimization */
1469   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1470     {
1471       /* we still need to set the :show-on-set-parent property, in
1472        * case hide() is called on an unparented actor
1473        */
1474       set_show_on_set_parent (self, FALSE);
1475       return;
1476     }
1477
1478 #ifdef CLUTTER_ENABLE_DEBUG
1479   clutter_actor_verify_map_state (self);
1480 #endif
1481
1482   priv = self->priv;
1483
1484   g_object_freeze_notify (G_OBJECT (self));
1485
1486   set_show_on_set_parent (self, FALSE);
1487
1488   g_signal_emit (self, actor_signals[HIDE], 0);
1489   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1490
1491   if (priv->parent != NULL)
1492     clutter_actor_queue_redraw (priv->parent);
1493
1494   g_object_thaw_notify (G_OBJECT (self));
1495 }
1496
1497 /**
1498  * clutter_actor_hide_all:
1499  * @self: a #ClutterActor
1500  *
1501  * Calls clutter_actor_hide() on all child actors (if any).
1502  *
1503  * Since: 0.2
1504  *
1505  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1506  *   prevent its children from being painted as well.
1507  */
1508 void
1509 clutter_actor_hide_all (ClutterActor *self)
1510 {
1511   ClutterActorClass *klass;
1512
1513   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1514
1515   klass = CLUTTER_ACTOR_GET_CLASS (self);
1516   if (klass->hide_all)
1517     klass->hide_all (self);
1518 }
1519
1520 /**
1521  * clutter_actor_realize:
1522  * @self: A #ClutterActor
1523  *
1524  * Realization informs the actor that it is attached to a stage. It
1525  * can use this to allocate resources if it wanted to delay allocation
1526  * until it would be rendered. However it is perfectly acceptable for
1527  * an actor to create resources before being realized because Clutter
1528  * only ever has a single rendering context so that actor is free to
1529  * be moved from one stage to another.
1530  *
1531  * This function does nothing if the actor is already realized.
1532  *
1533  * Because a realized actor must have realized parent actors, calling
1534  * clutter_actor_realize() will also realize all parents of the actor.
1535  *
1536  * This function does not realize child actors, except in the special
1537  * case that realizing the stage, when the stage is visible, will
1538  * suddenly map (and thus realize) the children of the stage.
1539  **/
1540 void
1541 clutter_actor_realize (ClutterActor *self)
1542 {
1543   ClutterActorPrivate *priv;
1544
1545   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1546
1547   priv = self->priv;
1548
1549 #ifdef CLUTTER_ENABLE_DEBUG
1550   clutter_actor_verify_map_state (self);
1551 #endif
1552
1553   if (CLUTTER_ACTOR_IS_REALIZED (self))
1554     return;
1555
1556   /* To be realized, our parent actors must be realized first.
1557    * This will only succeed if we're inside a toplevel.
1558    */
1559   if (priv->parent != NULL)
1560     clutter_actor_realize (priv->parent);
1561
1562   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1563     {
1564       /* toplevels can be realized at any time */
1565     }
1566   else
1567     {
1568       /* "Fail" the realization if parent is missing or unrealized;
1569        * this should really be a g_warning() not some kind of runtime
1570        * failure; how can an app possibly recover? Instead it's a bug
1571        * in the app and the app should get an explanatory warning so
1572        * someone can fix it. But for now it's too hard to fix this
1573        * because e.g. ClutterTexture needs reworking.
1574        */
1575       if (priv->parent == NULL ||
1576           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1577         return;
1578     }
1579
1580   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1581
1582   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1583   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1584
1585   g_signal_emit (self, actor_signals[REALIZE], 0);
1586
1587   /* Stage actor is allowed to unset the realized flag again in its
1588    * default signal handler, though that is a pathological situation.
1589    */
1590
1591   /* If realization "failed" we'll have to update child state. */
1592   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1593 }
1594
1595 static void
1596 clutter_actor_real_unrealize (ClutterActor *self)
1597 {
1598   /* we must be unmapped (implying our children are also unmapped) */
1599   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1600 }
1601
1602 /**
1603  * clutter_actor_unrealize:
1604  * @self: A #ClutterActor
1605  *
1606  * Unrealization informs the actor that it may be being destroyed or
1607  * moved to another stage. The actor may want to destroy any
1608  * underlying graphics resources at this point. However it is
1609  * perfectly acceptable for it to retain the resources until the actor
1610  * is destroyed because Clutter only ever uses a single rendering
1611  * context and all of the graphics resources are valid on any stage.
1612  *
1613  * Because mapped actors must be realized, actors may not be
1614  * unrealized if they are mapped. This function hides the actor to be
1615  * sure it isn't mapped, an application-visible side effect that you
1616  * may not be expecting.
1617  *
1618  * This function should not be called by application code.
1619  */
1620 void
1621 clutter_actor_unrealize (ClutterActor *self)
1622 {
1623   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1624   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1625
1626 /* This function should not really be in the public API, because
1627  * there isn't a good reason to call it. ClutterActor will already
1628  * unrealize things for you when it's important to do so.
1629  *
1630  * If you were using clutter_actor_unrealize() in a dispose
1631  * implementation, then don't, just chain up to ClutterActor's
1632  * dispose.
1633  *
1634  * If you were using clutter_actor_unrealize() to implement
1635  * unrealizing children of your container, then don't, ClutterActor
1636  * will already take care of that.
1637  *
1638  * If you were using clutter_actor_unrealize() to re-realize to
1639  * create your resources in a different way, then use
1640  * _clutter_actor_rerealize() (inside Clutter) or just call your
1641  * code that recreates your resources directly (outside Clutter).
1642  */
1643
1644 #ifdef CLUTTER_ENABLE_DEBUG
1645   clutter_actor_verify_map_state (self);
1646 #endif
1647
1648   clutter_actor_hide (self);
1649
1650   clutter_actor_unrealize_not_hiding (self);
1651 }
1652
1653 static ClutterActorTraverseVisitFlags
1654 unrealize_actor_before_children_cb (ClutterActor *self,
1655                                     int depth,
1656                                     void *user_data)
1657 {
1658   /* If an actor is already unrealized we know its children have also
1659    * already been unrealized... */
1660   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1661     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1662
1663   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1664
1665   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1666 }
1667
1668 static ClutterActorTraverseVisitFlags
1669 unrealize_actor_after_children_cb (ClutterActor *self,
1670                                    int depth,
1671                                    void *user_data)
1672 {
1673   /* We want to unset the realized flag only _after_
1674    * child actors are unrealized, to maintain invariants.
1675    */
1676   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1677   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1678   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1679 }
1680
1681 /*
1682  * clutter_actor_unrealize_not_hiding:
1683  * @self: A #ClutterActor
1684  *
1685  * Unrealization informs the actor that it may be being destroyed or
1686  * moved to another stage. The actor may want to destroy any
1687  * underlying graphics resources at this point. However it is
1688  * perfectly acceptable for it to retain the resources until the actor
1689  * is destroyed because Clutter only ever uses a single rendering
1690  * context and all of the graphics resources are valid on any stage.
1691  *
1692  * Because mapped actors must be realized, actors may not be
1693  * unrealized if they are mapped. You must hide the actor or one of
1694  * its parents before attempting to unrealize.
1695  *
1696  * This function is separate from clutter_actor_unrealize() because it
1697  * does not automatically hide the actor.
1698  * Actors need not be hidden to be unrealized, they just need to
1699  * be unmapped. In fact we don't want to mess up the application's
1700  * setting of the "visible" flag, so hiding is very undesirable.
1701  *
1702  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1703  * backward compatibility.
1704  */
1705 static void
1706 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1707 {
1708   _clutter_actor_traverse (self,
1709                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1710                            unrealize_actor_before_children_cb,
1711                            unrealize_actor_after_children_cb,
1712                            NULL);
1713 }
1714
1715 /*
1716  * _clutter_actor_rerealize:
1717  * @self: A #ClutterActor
1718  * @callback: Function to call while unrealized
1719  * @data: data for callback
1720  *
1721  * If an actor is already unrealized, this just calls the callback.
1722  *
1723  * If it is realized, it unrealizes temporarily, calls the callback,
1724  * and then re-realizes the actor.
1725  *
1726  * As a side effect, leaves all children of the actor unrealized if
1727  * the actor was realized but not showing.  This is because when we
1728  * unrealize the actor temporarily we must unrealize its children
1729  * (e.g. children of a stage can't be realized if stage window is
1730  * gone). And we aren't clever enough to save the realization state of
1731  * all children. In most cases this should not matter, because
1732  * the children will automatically realize when they next become mapped.
1733  */
1734 void
1735 _clutter_actor_rerealize (ClutterActor    *self,
1736                           ClutterCallback  callback,
1737                           void            *data)
1738 {
1739   gboolean was_mapped;
1740   gboolean was_showing;
1741   gboolean was_realized;
1742
1743   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1744
1745 #ifdef CLUTTER_ENABLE_DEBUG
1746   clutter_actor_verify_map_state (self);
1747 #endif
1748
1749   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1750   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1751   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1752
1753   /* Must be unmapped to unrealize. Note we only have to hide this
1754    * actor if it was mapped (if all parents were showing).  If actor
1755    * is merely visible (but not mapped), then that's fine, we can
1756    * leave it visible.
1757    */
1758   if (was_mapped)
1759     clutter_actor_hide (self);
1760
1761   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1762
1763   /* unrealize self and all children */
1764   clutter_actor_unrealize_not_hiding (self);
1765
1766   if (callback != NULL)
1767     {
1768       (* callback) (self, data);
1769     }
1770
1771   if (was_showing)
1772     clutter_actor_show (self); /* will realize only if mapping implies it */
1773   else if (was_realized)
1774     clutter_actor_realize (self); /* realize self and all parents */
1775 }
1776
1777 static void
1778 clutter_actor_real_pick (ClutterActor       *self,
1779                          const ClutterColor *color)
1780 {
1781   /* the default implementation is just to paint a rectangle
1782    * with the same size of the actor using the passed color
1783    */
1784   if (clutter_actor_should_pick_paint (self))
1785     {
1786       ClutterActorBox box = { 0, };
1787       float width, height;
1788
1789       clutter_actor_get_allocation_box (self, &box);
1790
1791       width = box.x2 - box.x1;
1792       height = box.y2 - box.y1;
1793
1794       cogl_set_source_color4ub (color->red,
1795                                 color->green,
1796                                 color->blue,
1797                                 color->alpha);
1798
1799       cogl_rectangle (0, 0, width, height);
1800     }
1801
1802   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1803    * with existing container classes that override the pick() virtual
1804    * and chain up to the default implementation - otherwise we'll end up
1805    * painting our children twice.
1806    *
1807    * this has to go away for 2.0; hopefully along the pick() itself.
1808    */
1809   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1810     {
1811       ClutterActor *iter;
1812
1813       for (iter = self->priv->first_child;
1814            iter != NULL;
1815            iter = iter->priv->next_sibling)
1816         clutter_actor_paint (iter);
1817     }
1818 }
1819
1820 /**
1821  * clutter_actor_should_pick_paint:
1822  * @self: A #ClutterActor
1823  *
1824  * Should be called inside the implementation of the
1825  * #ClutterActor::pick virtual function in order to check whether
1826  * the actor should paint itself in pick mode or not.
1827  *
1828  * This function should never be called directly by applications.
1829  *
1830  * Return value: %TRUE if the actor should paint its silhouette,
1831  *   %FALSE otherwise
1832  */
1833 gboolean
1834 clutter_actor_should_pick_paint (ClutterActor *self)
1835 {
1836   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1837
1838   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1839       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1840        CLUTTER_ACTOR_IS_REACTIVE (self)))
1841     return TRUE;
1842
1843   return FALSE;
1844 }
1845
1846 static void
1847 clutter_actor_real_get_preferred_width (ClutterActor *self,
1848                                         gfloat        for_height,
1849                                         gfloat       *min_width_p,
1850                                         gfloat       *natural_width_p)
1851 {
1852   ClutterActorPrivate *priv = self->priv;
1853
1854   if (priv->n_children != 0 &&
1855       priv->layout_manager != NULL)
1856     {
1857       ClutterContainer *container = CLUTTER_CONTAINER (self);
1858
1859       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1860                     "for the preferred width",
1861                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1862                     priv->layout_manager);
1863
1864       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1865                                                   container,
1866                                                   for_height,
1867                                                   min_width_p,
1868                                                   natural_width_p);
1869
1870       return;
1871     }
1872
1873   /* Default implementation is always 0x0, usually an actor
1874    * using this default is relying on someone to set the
1875    * request manually
1876    */
1877   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1878
1879   if (min_width_p)
1880     *min_width_p = 0;
1881
1882   if (natural_width_p)
1883     *natural_width_p = 0;
1884 }
1885
1886 static void
1887 clutter_actor_real_get_preferred_height (ClutterActor *self,
1888                                          gfloat        for_width,
1889                                          gfloat       *min_height_p,
1890                                          gfloat       *natural_height_p)
1891 {
1892   ClutterActorPrivate *priv = self->priv;
1893
1894   if (priv->n_children != 0 &&
1895       priv->layout_manager != NULL)
1896     {
1897       ClutterContainer *container = CLUTTER_CONTAINER (self);
1898
1899       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1900                     "for the preferred height",
1901                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1902                     priv->layout_manager);
1903
1904       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1905                                                    container,
1906                                                    for_width,
1907                                                    min_height_p,
1908                                                    natural_height_p);
1909
1910       return;
1911     }
1912   /* Default implementation is always 0x0, usually an actor
1913    * using this default is relying on someone to set the
1914    * request manually
1915    */
1916   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1917
1918   if (min_height_p)
1919     *min_height_p = 0;
1920
1921   if (natural_height_p)
1922     *natural_height_p = 0;
1923 }
1924
1925 static void
1926 clutter_actor_store_old_geometry (ClutterActor    *self,
1927                                   ClutterActorBox *box)
1928 {
1929   *box = self->priv->allocation;
1930 }
1931
1932 static inline void
1933 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
1934                                           const ClutterActorBox *old)
1935 {
1936   ClutterActorPrivate *priv = self->priv;
1937   GObject *obj = G_OBJECT (self);
1938
1939   g_object_freeze_notify (obj);
1940
1941   /* to avoid excessive requisition or allocation cycles we
1942    * use the cached values.
1943    *
1944    * - if we don't have an allocation we assume that we need
1945    *   to notify anyway
1946    * - if we don't have a width or a height request we notify
1947    *   width and height
1948    * - if we have a valid allocation then we check the old
1949    *   bounding box with the current allocation and we notify
1950    *   the changes
1951    */
1952   if (priv->needs_allocation)
1953     {
1954       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1955       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1956       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1957       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1958     }
1959   else if (priv->needs_width_request || priv->needs_height_request)
1960     {
1961       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1962       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1963     }
1964   else
1965     {
1966       gfloat xu, yu;
1967       gfloat widthu, heightu;
1968
1969       xu = priv->allocation.x1;
1970       yu = priv->allocation.y1;
1971       widthu = priv->allocation.x2 - priv->allocation.x1;
1972       heightu = priv->allocation.y2 - priv->allocation.y1;
1973
1974       if (xu != old->x1)
1975         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1976
1977       if (yu != old->y1)
1978         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1979
1980       if (widthu != (old->x2 - old->x1))
1981         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1982
1983       if (heightu != (old->y2 - old->y1))
1984         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1985     }
1986
1987   g_object_thaw_notify (obj);
1988 }
1989
1990 /*< private >
1991  * clutter_actor_set_allocation_internal:
1992  * @self: a #ClutterActor
1993  * @box: a #ClutterActorBox
1994  * @flags: allocation flags
1995  *
1996  * Stores the allocation of @self.
1997  *
1998  * This function only performs basic storage and property notification.
1999  *
2000  * This function should be called by clutter_actor_set_allocation()
2001  * and by the default implementation of #ClutterActorClass.allocate().
2002  *
2003  * Return value: %TRUE if the allocation of the #ClutterActor has been
2004  *   changed, and %FALSE otherwise
2005  */
2006 static inline gboolean
2007 clutter_actor_set_allocation_internal (ClutterActor           *self,
2008                                        const ClutterActorBox  *box,
2009                                        ClutterAllocationFlags  flags)
2010 {
2011   ClutterActorPrivate *priv = self->priv;
2012   GObject *obj;
2013   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2014   gboolean flags_changed;
2015   gboolean retval;
2016   ClutterActorBox old_alloc = { 0, };
2017
2018   obj = G_OBJECT (self);
2019
2020   g_object_freeze_notify (obj);
2021
2022   clutter_actor_store_old_geometry (self, &old_alloc);
2023
2024   x1_changed = priv->allocation.x1 != box->x1;
2025   y1_changed = priv->allocation.y1 != box->y1;
2026   x2_changed = priv->allocation.x2 != box->x2;
2027   y2_changed = priv->allocation.y2 != box->y2;
2028
2029   flags_changed = priv->allocation_flags != flags;
2030
2031   priv->allocation = *box;
2032   priv->allocation_flags = flags;
2033
2034   /* allocation is authoritative */
2035   priv->needs_width_request = FALSE;
2036   priv->needs_height_request = FALSE;
2037   priv->needs_allocation = FALSE;
2038
2039   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
2040     {
2041       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2042                     _clutter_actor_get_debug_name (self));
2043
2044       priv->transform_valid = FALSE;
2045
2046       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2047
2048       retval = TRUE;
2049     }
2050   else
2051     retval = FALSE;
2052
2053   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2054
2055   g_object_thaw_notify (obj);
2056
2057   return retval;
2058 }
2059
2060 static void clutter_actor_real_allocate (ClutterActor           *self,
2061                                          const ClutterActorBox  *box,
2062                                          ClutterAllocationFlags  flags);
2063
2064 static inline void
2065 clutter_actor_maybe_layout_children (ClutterActor           *self,
2066                                      const ClutterActorBox  *allocation,
2067                                      ClutterAllocationFlags  flags)
2068 {
2069   ClutterActorPrivate *priv = self->priv;
2070
2071   /* this is going to be a bit hard to follow, so let's put an explanation
2072    * here.
2073    *
2074    * we want ClutterActor to have a default layout manager if the actor was
2075    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2076    *
2077    * we also want any subclass of ClutterActor that does not override the
2078    * ::allocate() virtual function to delegate to a layout manager.
2079    *
2080    * finally, we want to allow people subclassing ClutterActor and overriding
2081    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2082    *
2083    * on the other hand, we want existing actor subclasses overriding the
2084    * ::allocate() virtual function and chaining up to the parent's
2085    * implementation to continue working without allocating their children
2086    * twice, or without entering an allocation loop.
2087    *
2088    * for the first two points, we check if the class of the actor is
2089    * overridding the ::allocate() virtual function; if it isn't, then we
2090    * follow through with checking whether we have children and a layout
2091    * manager, and eventually calling clutter_layout_manager_allocate().
2092    *
2093    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2094    * allocation flags that we got passed, and if it is present, we continue
2095    * with the check above.
2096    *
2097    * if neither of these two checks yields a positive result, we just
2098    * assume that the ::allocate() virtual function that resulted in this
2099    * function being called will also allocate the children of the actor.
2100    */
2101
2102   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2103     goto check_layout;
2104
2105   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2106     goto check_layout;
2107
2108   return;
2109
2110 check_layout:
2111   if (priv->n_children != 0 &&
2112       priv->layout_manager != NULL)
2113     {
2114       ClutterContainer *container = CLUTTER_CONTAINER (self);
2115       ClutterAllocationFlags children_flags;
2116       ClutterActorBox children_box;
2117
2118       /* normalize the box passed to the layout manager */
2119       children_box.x1 = children_box.y1 = 0.f;
2120       children_box.x2 = (allocation->x2 - allocation->x1);
2121       children_box.y2 = (allocation->y2 - allocation->y1);
2122
2123       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2124        * the actor's children, since it refers only to the current
2125        * actor's allocation.
2126        */
2127       children_flags = flags;
2128       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2129
2130       CLUTTER_NOTE (LAYOUT,
2131                     "Allocating %d children of %s "
2132                     "at { %.2f, %.2f - %.2f x %.2f } "
2133                     "using %s",
2134                     priv->n_children,
2135                     _clutter_actor_get_debug_name (self),
2136                     allocation->x1,
2137                     allocation->y1,
2138                     (allocation->x2 - allocation->x1),
2139                     (allocation->y2 - allocation->y1),
2140                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2141
2142       clutter_layout_manager_allocate (priv->layout_manager,
2143                                        container,
2144                                        &children_box,
2145                                        children_flags);
2146     }
2147 }
2148
2149 static void
2150 clutter_actor_real_allocate (ClutterActor           *self,
2151                              const ClutterActorBox  *box,
2152                              ClutterAllocationFlags  flags)
2153 {
2154   ClutterActorPrivate *priv = self->priv;
2155   gboolean changed;
2156
2157   g_object_freeze_notify (G_OBJECT (self));
2158
2159   changed = clutter_actor_set_allocation_internal (self, box, flags);
2160
2161   /* we allocate our children before we notify changes in our geometry,
2162    * so that people connecting to properties will be able to get valid
2163    * data out of the sub-tree of the scene graph that has this actor at
2164    * the root.
2165    */
2166   clutter_actor_maybe_layout_children (self, box, flags);
2167
2168   if (changed)
2169     {
2170       ClutterActorBox signal_box = priv->allocation;
2171       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2172
2173       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2174                      &signal_box,
2175                      signal_flags);
2176     }
2177
2178   g_object_thaw_notify (G_OBJECT (self));
2179 }
2180
2181 static void
2182 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2183                                     ClutterActor *origin)
2184 {
2185   /* no point in queuing a redraw on a destroyed actor */
2186   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2187     return;
2188
2189   /* NB: We can't bail out early here if the actor is hidden in case
2190    * the actor bas been cloned. In this case the clone will need to
2191    * receive the signal so it can queue its own redraw.
2192    */
2193
2194   /* calls klass->queue_redraw in default handler */
2195   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2196 }
2197
2198 static void
2199 clutter_actor_real_queue_redraw (ClutterActor *self,
2200                                  ClutterActor *origin)
2201 {
2202   ClutterActor *parent;
2203
2204   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2205                 _clutter_actor_get_debug_name (self),
2206                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2207                                : "same actor");
2208
2209   /* no point in queuing a redraw on a destroyed actor */
2210   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2211     return;
2212
2213   /* If the queue redraw is coming from a child then the actor has
2214      become dirty and any queued effect is no longer valid */
2215   if (self != origin)
2216     {
2217       self->priv->is_dirty = TRUE;
2218       self->priv->effect_to_redraw = NULL;
2219     }
2220
2221   /* If the actor isn't visible, we still had to emit the signal
2222    * to allow for a ClutterClone, but the appearance of the parent
2223    * won't change so we don't have to propagate up the hierarchy.
2224    */
2225   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2226     return;
2227
2228   /* Although we could determine here that a full stage redraw
2229    * has already been queued and immediately bail out, we actually
2230    * guarantee that we will propagate a queue-redraw signal to our
2231    * parent at least once so that it's possible to implement a
2232    * container that tracks which of its children have queued a
2233    * redraw.
2234    */
2235   if (self->priv->propagated_one_redraw)
2236     {
2237       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2238       if (stage != NULL &&
2239           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2240         return;
2241     }
2242
2243   self->priv->propagated_one_redraw = TRUE;
2244
2245   /* notify parents, if they are all visible eventually we'll
2246    * queue redraw on the stage, which queues the redraw idle.
2247    */
2248   parent = clutter_actor_get_parent (self);
2249   if (parent != NULL)
2250     {
2251       /* this will go up recursively */
2252       _clutter_actor_signal_queue_redraw (parent, origin);
2253     }
2254 }
2255
2256 static void
2257 clutter_actor_real_queue_relayout (ClutterActor *self)
2258 {
2259   ClutterActorPrivate *priv = self->priv;
2260
2261   /* no point in queueing a redraw on a destroyed actor */
2262   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2263     return;
2264
2265   priv->needs_width_request  = TRUE;
2266   priv->needs_height_request = TRUE;
2267   priv->needs_allocation     = TRUE;
2268
2269   /* reset the cached size requests */
2270   memset (priv->width_requests, 0,
2271           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2272   memset (priv->height_requests, 0,
2273           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2274
2275   /* We need to go all the way up the hierarchy */
2276   if (priv->parent != NULL)
2277     _clutter_actor_queue_only_relayout (priv->parent);
2278 }
2279
2280 /**
2281  * clutter_actor_apply_relative_transform_to_point:
2282  * @self: A #ClutterActor
2283  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2284  *   default #ClutterStage
2285  * @point: A point as #ClutterVertex
2286  * @vertex: (out caller-allocates): The translated #ClutterVertex
2287  *
2288  * Transforms @point in coordinates relative to the actor into
2289  * ancestor-relative coordinates using the relevant transform
2290  * stack (i.e. scale, rotation, etc).
2291  *
2292  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2293  * this case, the coordinates returned will be the coordinates on
2294  * the stage before the projection is applied. This is different from
2295  * the behaviour of clutter_actor_apply_transform_to_point().
2296  *
2297  * Since: 0.6
2298  */
2299 void
2300 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2301                                                  ClutterActor        *ancestor,
2302                                                  const ClutterVertex *point,
2303                                                  ClutterVertex       *vertex)
2304 {
2305   gfloat w;
2306   CoglMatrix matrix;
2307
2308   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2309   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2310   g_return_if_fail (point != NULL);
2311   g_return_if_fail (vertex != NULL);
2312
2313   *vertex = *point;
2314   w = 1.0;
2315
2316   if (ancestor == NULL)
2317     ancestor = _clutter_actor_get_stage_internal (self);
2318
2319   if (ancestor == NULL)
2320     {
2321       *vertex = *point;
2322       return;
2323     }
2324
2325   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2326   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2327 }
2328
2329 static gboolean
2330 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2331                                          const ClutterVertex *vertices_in,
2332                                          ClutterVertex *vertices_out,
2333                                          int n_vertices)
2334 {
2335   ClutterActor *stage;
2336   CoglMatrix modelview;
2337   CoglMatrix projection;
2338   float viewport[4];
2339
2340   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2341
2342   stage = _clutter_actor_get_stage_internal (self);
2343
2344   /* We really can't do anything meaningful in this case so don't try
2345    * to do any transform */
2346   if (stage == NULL)
2347     return FALSE;
2348
2349   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2350    * that gets us to stage coordinates, we want to go all the way to eye
2351    * coordinates */
2352   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2353
2354   /* Fetch the projection and viewport */
2355   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2356   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2357                                &viewport[0],
2358                                &viewport[1],
2359                                &viewport[2],
2360                                &viewport[3]);
2361
2362   _clutter_util_fully_transform_vertices (&modelview,
2363                                           &projection,
2364                                           viewport,
2365                                           vertices_in,
2366                                           vertices_out,
2367                                           n_vertices);
2368
2369   return TRUE;
2370 }
2371
2372 /**
2373  * clutter_actor_apply_transform_to_point:
2374  * @self: A #ClutterActor
2375  * @point: A point as #ClutterVertex
2376  * @vertex: (out caller-allocates): The translated #ClutterVertex
2377  *
2378  * Transforms @point in coordinates relative to the actor
2379  * into screen-relative coordinates with the current actor
2380  * transformation (i.e. scale, rotation, etc)
2381  *
2382  * Since: 0.4
2383  **/
2384 void
2385 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2386                                         const ClutterVertex *point,
2387                                         ClutterVertex       *vertex)
2388 {
2389   g_return_if_fail (point != NULL);
2390   g_return_if_fail (vertex != NULL);
2391   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2392 }
2393
2394 /*
2395  * _clutter_actor_get_relative_transformation_matrix:
2396  * @self: The actor whose coordinate space you want to transform from.
2397  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2398  *            or %NULL if you want to transform all the way to eye coordinates.
2399  * @matrix: A #CoglMatrix to store the transformation
2400  *
2401  * This gets a transformation @matrix that will transform coordinates from the
2402  * coordinate space of @self into the coordinate space of @ancestor.
2403  *
2404  * For example if you need a matrix that can transform the local actor
2405  * coordinates of @self into stage coordinates you would pass the actor's stage
2406  * pointer as the @ancestor.
2407  *
2408  * If you pass %NULL then the transformation will take you all the way through
2409  * to eye coordinates. This can be useful if you want to extract the entire
2410  * modelview transform that Clutter applies before applying the projection
2411  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2412  * using cogl_set_modelview_matrix() for example then you would want a matrix
2413  * that transforms into eye coordinates.
2414  *
2415  * <note><para>This function explicitly initializes the given @matrix. If you just
2416  * want clutter to multiply a relative transformation with an existing matrix
2417  * you can use clutter_actor_apply_relative_transformation_matrix()
2418  * instead.</para></note>
2419  *
2420  */
2421 /* XXX: We should consider caching the stage relative modelview along with
2422  * the actor itself */
2423 static void
2424 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2425                                                    ClutterActor *ancestor,
2426                                                    CoglMatrix *matrix)
2427 {
2428   cogl_matrix_init_identity (matrix);
2429
2430   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2431 }
2432
2433 /* Project the given @box into stage window coordinates, writing the
2434  * transformed vertices to @verts[]. */
2435 static gboolean
2436 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2437                                           const ClutterActorBox *box,
2438                                           ClutterVertex          verts[])
2439 {
2440   ClutterVertex box_vertices[4];
2441
2442   box_vertices[0].x = box->x1;
2443   box_vertices[0].y = box->y1;
2444   box_vertices[0].z = 0;
2445   box_vertices[1].x = box->x2;
2446   box_vertices[1].y = box->y1;
2447   box_vertices[1].z = 0;
2448   box_vertices[2].x = box->x1;
2449   box_vertices[2].y = box->y2;
2450   box_vertices[2].z = 0;
2451   box_vertices[3].x = box->x2;
2452   box_vertices[3].y = box->y2;
2453   box_vertices[3].z = 0;
2454
2455   return
2456     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2457 }
2458
2459 /**
2460  * clutter_actor_get_allocation_vertices:
2461  * @self: A #ClutterActor
2462  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2463  *   against, or %NULL to use the #ClutterStage
2464  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2465  *   location for an array of 4 #ClutterVertex in which to store the result
2466  *
2467  * Calculates the transformed coordinates of the four corners of the
2468  * actor in the plane of @ancestor. The returned vertices relate to
2469  * the #ClutterActorBox coordinates as follows:
2470  * <itemizedlist>
2471  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2472  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2473  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2474  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2475  * </itemizedlist>
2476  *
2477  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2478  * this case, the coordinates returned will be the coordinates on
2479  * the stage before the projection is applied. This is different from
2480  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2481  *
2482  * Since: 0.6
2483  */
2484 void
2485 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2486                                        ClutterActor  *ancestor,
2487                                        ClutterVertex  verts[])
2488 {
2489   ClutterActorPrivate *priv;
2490   ClutterActorBox box;
2491   ClutterVertex vertices[4];
2492   CoglMatrix modelview;
2493
2494   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2495   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2496
2497   if (ancestor == NULL)
2498     ancestor = _clutter_actor_get_stage_internal (self);
2499
2500   /* Fallback to a NOP transform if the actor isn't parented under a
2501    * stage. */
2502   if (ancestor == NULL)
2503     ancestor = self;
2504
2505   priv = self->priv;
2506
2507   /* if the actor needs to be allocated we force a relayout, so that
2508    * we will have valid values to use in the transformations */
2509   if (priv->needs_allocation)
2510     {
2511       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2512       if (stage)
2513         _clutter_stage_maybe_relayout (stage);
2514       else
2515         {
2516           box.x1 = box.y1 = 0;
2517           /* The result isn't really meaningful in this case but at
2518            * least try to do something *vaguely* reasonable... */
2519           clutter_actor_get_size (self, &box.x2, &box.y2);
2520         }
2521     }
2522
2523   clutter_actor_get_allocation_box (self, &box);
2524
2525   vertices[0].x = box.x1;
2526   vertices[0].y = box.y1;
2527   vertices[0].z = 0;
2528   vertices[1].x = box.x2;
2529   vertices[1].y = box.y1;
2530   vertices[1].z = 0;
2531   vertices[2].x = box.x1;
2532   vertices[2].y = box.y2;
2533   vertices[2].z = 0;
2534   vertices[3].x = box.x2;
2535   vertices[3].y = box.y2;
2536   vertices[3].z = 0;
2537
2538   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2539                                                      &modelview);
2540
2541   cogl_matrix_transform_points (&modelview,
2542                                 3,
2543                                 sizeof (ClutterVertex),
2544                                 vertices,
2545                                 sizeof (ClutterVertex),
2546                                 vertices,
2547                                 4);
2548 }
2549
2550 /**
2551  * clutter_actor_get_abs_allocation_vertices:
2552  * @self: A #ClutterActor
2553  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2554  *   of 4 #ClutterVertex where to store the result.
2555  *
2556  * Calculates the transformed screen coordinates of the four corners of
2557  * the actor; the returned vertices relate to the #ClutterActorBox
2558  * coordinates  as follows:
2559  * <itemizedlist>
2560  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2561  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2562  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2563  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2564  * </itemizedlist>
2565  *
2566  * Since: 0.4
2567  */
2568 void
2569 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2570                                            ClutterVertex  verts[])
2571 {
2572   ClutterActorPrivate *priv;
2573   ClutterActorBox actor_space_allocation;
2574
2575   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2576
2577   priv = self->priv;
2578
2579   /* if the actor needs to be allocated we force a relayout, so that
2580    * the actor allocation box will be valid for
2581    * _clutter_actor_transform_and_project_box()
2582    */
2583   if (priv->needs_allocation)
2584     {
2585       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2586       /* There's nothing meaningful we can do now */
2587       if (!stage)
2588         return;
2589
2590       _clutter_stage_maybe_relayout (stage);
2591     }
2592
2593   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2594    * own coordinate space... */
2595   actor_space_allocation.x1 = 0;
2596   actor_space_allocation.y1 = 0;
2597   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2598   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2599   _clutter_actor_transform_and_project_box (self,
2600                                             &actor_space_allocation,
2601                                             verts);
2602 }
2603
2604 static void
2605 clutter_actor_real_apply_transform (ClutterActor *self,
2606                                     CoglMatrix   *matrix)
2607 {
2608   ClutterActorPrivate *priv = self->priv;
2609
2610   if (!priv->transform_valid)
2611     {
2612       CoglMatrix *transform = &priv->transform;
2613       const ClutterTransformInfo *info;
2614
2615       info = _clutter_actor_get_transform_info_or_defaults (self);
2616
2617       cogl_matrix_init_identity (transform);
2618
2619       cogl_matrix_translate (transform,
2620                              priv->allocation.x1,
2621                              priv->allocation.y1,
2622                              0.0);
2623
2624       if (info->depth)
2625         cogl_matrix_translate (transform, 0, 0, info->depth);
2626
2627       /*
2628        * because the rotation involves translations, we must scale
2629        * before applying the rotations (if we apply the scale after
2630        * the rotations, the translations included in the rotation are
2631        * not scaled and so the entire object will move on the screen
2632        * as a result of rotating it).
2633        */
2634       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2635         {
2636           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2637                                         &info->scale_center,
2638                                         cogl_matrix_scale (transform,
2639                                                            info->scale_x,
2640                                                            info->scale_y,
2641                                                            1.0));
2642         }
2643
2644       if (info->rz_angle)
2645         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2646                                       &info->rz_center,
2647                                       cogl_matrix_rotate (transform,
2648                                                           info->rz_angle,
2649                                                           0, 0, 1.0));
2650
2651       if (info->ry_angle)
2652         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2653                                       &info->ry_center,
2654                                       cogl_matrix_rotate (transform,
2655                                                           info->ry_angle,
2656                                                           0, 1.0, 0));
2657
2658       if (info->rx_angle)
2659         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2660                                       &info->rx_center,
2661                                       cogl_matrix_rotate (transform,
2662                                                           info->rx_angle,
2663                                                           1.0, 0, 0));
2664
2665       if (!clutter_anchor_coord_is_zero (&info->anchor))
2666         {
2667           gfloat x, y, z;
2668
2669           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2670           cogl_matrix_translate (transform, -x, -y, -z);
2671         }
2672
2673       priv->transform_valid = TRUE;
2674     }
2675
2676   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2677 }
2678
2679 /* Applies the transforms associated with this actor to the given
2680  * matrix. */
2681 void
2682 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2683                                           CoglMatrix *matrix)
2684 {
2685   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2686 }
2687
2688 /*
2689  * clutter_actor_apply_relative_transformation_matrix:
2690  * @self: The actor whose coordinate space you want to transform from.
2691  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2692  *            or %NULL if you want to transform all the way to eye coordinates.
2693  * @matrix: A #CoglMatrix to apply the transformation too.
2694  *
2695  * This multiplies a transform with @matrix that will transform coordinates
2696  * from the coordinate space of @self into the coordinate space of @ancestor.
2697  *
2698  * For example if you need a matrix that can transform the local actor
2699  * coordinates of @self into stage coordinates you would pass the actor's stage
2700  * pointer as the @ancestor.
2701  *
2702  * If you pass %NULL then the transformation will take you all the way through
2703  * to eye coordinates. This can be useful if you want to extract the entire
2704  * modelview transform that Clutter applies before applying the projection
2705  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2706  * using cogl_set_modelview_matrix() for example then you would want a matrix
2707  * that transforms into eye coordinates.
2708  *
2709  * <note>This function doesn't initialize the given @matrix, it simply
2710  * multiplies the requested transformation matrix with the existing contents of
2711  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2712  * before calling this function, or you can use
2713  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2714  */
2715 void
2716 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2717                                                      ClutterActor *ancestor,
2718                                                      CoglMatrix *matrix)
2719 {
2720   ClutterActor *parent;
2721
2722   /* Note we terminate before ever calling stage->apply_transform()
2723    * since that would conceptually be relative to the underlying
2724    * window OpenGL coordinates so we'd need a special @ancestor
2725    * value to represent the fake parent of the stage. */
2726   if (self == ancestor)
2727     return;
2728
2729   parent = clutter_actor_get_parent (self);
2730
2731   if (parent != NULL)
2732     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2733                                                          matrix);
2734
2735   _clutter_actor_apply_modelview_transform (self, matrix);
2736 }
2737
2738 static void
2739 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2740                                        ClutterPaintVolume *pv,
2741                                        const char *label,
2742                                        const CoglColor *color)
2743 {
2744   static CoglPipeline *outline = NULL;
2745   CoglPrimitive *prim;
2746   ClutterVertex line_ends[12 * 2];
2747   int n_vertices;
2748   CoglContext *ctx =
2749     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2750   /* XXX: at some point we'll query this from the stage but we can't
2751    * do that until the osx backend uses Cogl natively. */
2752   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2753
2754   if (outline == NULL)
2755     outline = cogl_pipeline_new (ctx);
2756
2757   _clutter_paint_volume_complete (pv);
2758
2759   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2760
2761   /* Front face */
2762   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2763   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2764   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2765   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2766
2767   if (!pv->is_2d)
2768     {
2769       /* Back face */
2770       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2771       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2772       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2773       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2774
2775       /* Lines connecting front face to back face */
2776       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2777       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2778       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2779       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2780     }
2781
2782   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2783                                 n_vertices,
2784                                 (CoglVertexP3 *)line_ends);
2785
2786   cogl_pipeline_set_color (outline, color);
2787   cogl_framebuffer_draw_primitive (fb, outline, prim);
2788   cogl_object_unref (prim);
2789
2790   if (label)
2791     {
2792       PangoLayout *layout;
2793       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2794       pango_layout_set_text (layout, label, -1);
2795       cogl_pango_render_layout (layout,
2796                                 pv->vertices[0].x,
2797                                 pv->vertices[0].y,
2798                                 color,
2799                                 0);
2800       g_object_unref (layout);
2801     }
2802 }
2803
2804 static void
2805 _clutter_actor_draw_paint_volume (ClutterActor *self)
2806 {
2807   ClutterPaintVolume *pv;
2808   CoglColor color;
2809
2810   pv = _clutter_actor_get_paint_volume_mutable (self);
2811   if (!pv)
2812     {
2813       gfloat width, height;
2814       ClutterPaintVolume fake_pv;
2815
2816       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2817       _clutter_paint_volume_init_static (&fake_pv, stage);
2818
2819       clutter_actor_get_size (self, &width, &height);
2820       clutter_paint_volume_set_width (&fake_pv, width);
2821       clutter_paint_volume_set_height (&fake_pv, height);
2822
2823       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2824       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2825                                              _clutter_actor_get_debug_name (self),
2826                                              &color);
2827
2828       clutter_paint_volume_free (&fake_pv);
2829     }
2830   else
2831     {
2832       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2833       _clutter_actor_draw_paint_volume_full (self, pv,
2834                                              _clutter_actor_get_debug_name (self),
2835                                              &color);
2836     }
2837 }
2838
2839 static void
2840 _clutter_actor_paint_cull_result (ClutterActor *self,
2841                                   gboolean success,
2842                                   ClutterCullResult result)
2843 {
2844   ClutterPaintVolume *pv;
2845   CoglColor color;
2846
2847   if (success)
2848     {
2849       if (result == CLUTTER_CULL_RESULT_IN)
2850         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2851       else if (result == CLUTTER_CULL_RESULT_OUT)
2852         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2853       else
2854         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2855     }
2856   else
2857     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2858
2859   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2860     _clutter_actor_draw_paint_volume_full (self, pv,
2861                                            _clutter_actor_get_debug_name (self),
2862                                            &color);
2863   else
2864     {
2865       PangoLayout *layout;
2866       char *label =
2867         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2868       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2869       cogl_set_source_color (&color);
2870
2871       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2872       pango_layout_set_text (layout, label, -1);
2873       cogl_pango_render_layout (layout,
2874                                 0,
2875                                 0,
2876                                 &color,
2877                                 0);
2878       g_free (label);
2879       g_object_unref (layout);
2880     }
2881 }
2882
2883 static int clone_paint_level = 0;
2884
2885 void
2886 _clutter_actor_push_clone_paint (void)
2887 {
2888   clone_paint_level++;
2889 }
2890
2891 void
2892 _clutter_actor_pop_clone_paint (void)
2893 {
2894   clone_paint_level--;
2895 }
2896
2897 static gboolean
2898 in_clone_paint (void)
2899 {
2900   return clone_paint_level > 0;
2901 }
2902
2903 /* Returns TRUE if the actor can be ignored */
2904 /* FIXME: we should return a ClutterCullResult, and
2905  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2906  * means there's no point in trying to cull descendants of the current
2907  * node. */
2908 static gboolean
2909 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2910 {
2911   ClutterActorPrivate *priv = self->priv;
2912   ClutterActor *stage;
2913   const ClutterPlane *stage_clip;
2914
2915   if (!priv->last_paint_volume_valid)
2916     {
2917       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2918                     "->last_paint_volume_valid == FALSE",
2919                     _clutter_actor_get_debug_name (self));
2920       return FALSE;
2921     }
2922
2923   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2924     return FALSE;
2925
2926   stage = _clutter_actor_get_stage_internal (self);
2927   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2928   if (G_UNLIKELY (!stage_clip))
2929     {
2930       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2931                     "No stage clip set",
2932                     _clutter_actor_get_debug_name (self));
2933       return FALSE;
2934     }
2935
2936   if (cogl_get_draw_framebuffer () !=
2937       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2938     {
2939       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2940                     "Current framebuffer doesn't correspond to stage",
2941                     _clutter_actor_get_debug_name (self));
2942       return FALSE;
2943     }
2944
2945   *result_out =
2946     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2947   return TRUE;
2948 }
2949
2950 static void
2951 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2952 {
2953   ClutterActorPrivate *priv = self->priv;
2954   const ClutterPaintVolume *pv;
2955
2956   if (priv->last_paint_volume_valid)
2957     {
2958       clutter_paint_volume_free (&priv->last_paint_volume);
2959       priv->last_paint_volume_valid = FALSE;
2960     }
2961
2962   pv = clutter_actor_get_paint_volume (self);
2963   if (!pv)
2964     {
2965       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2966                     "Actor failed to report a paint volume",
2967                     _clutter_actor_get_debug_name (self));
2968       return;
2969     }
2970
2971   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2972
2973   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2974                                             NULL); /* eye coordinates */
2975
2976   priv->last_paint_volume_valid = TRUE;
2977 }
2978
2979 static inline gboolean
2980 actor_has_shader_data (ClutterActor *self)
2981 {
2982   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
2983 }
2984
2985 guint32
2986 _clutter_actor_get_pick_id (ClutterActor *self)
2987 {
2988   if (self->priv->pick_id < 0)
2989     return 0;
2990
2991   return self->priv->pick_id;
2992 }
2993
2994 /* This is the same as clutter_actor_add_effect except that it doesn't
2995    queue a redraw and it doesn't notify on the effect property */
2996 static void
2997 _clutter_actor_add_effect_internal (ClutterActor  *self,
2998                                     ClutterEffect *effect)
2999 {
3000   ClutterActorPrivate *priv = self->priv;
3001
3002   if (priv->effects == NULL)
3003     {
3004       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3005       priv->effects->actor = self;
3006     }
3007
3008   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3009 }
3010
3011 /* This is the same as clutter_actor_remove_effect except that it doesn't
3012    queue a redraw and it doesn't notify on the effect property */
3013 static void
3014 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3015                                        ClutterEffect *effect)
3016 {
3017   ClutterActorPrivate *priv = self->priv;
3018
3019   if (priv->effects == NULL)
3020     return;
3021
3022   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3023 }
3024
3025 static gboolean
3026 needs_flatten_effect (ClutterActor *self)
3027 {
3028   ClutterActorPrivate *priv = self->priv;
3029
3030   if (G_UNLIKELY (clutter_paint_debug_flags &
3031                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3032     return FALSE;
3033
3034   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3035     return TRUE;
3036   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3037     {
3038       if (clutter_actor_get_paint_opacity (self) < 255 &&
3039           clutter_actor_has_overlaps (self))
3040         return TRUE;
3041     }
3042
3043   return FALSE;
3044 }
3045
3046 static void
3047 add_or_remove_flatten_effect (ClutterActor *self)
3048 {
3049   ClutterActorPrivate *priv = self->priv;
3050
3051   /* Add or remove the flatten effect depending on the
3052      offscreen-redirect property. */
3053   if (needs_flatten_effect (self))
3054     {
3055       if (priv->flatten_effect == NULL)
3056         {
3057           ClutterActorMeta *actor_meta;
3058           gint priority;
3059
3060           priv->flatten_effect = _clutter_flatten_effect_new ();
3061           /* Keep a reference to the effect so that we can queue
3062              redraws from it */
3063           g_object_ref_sink (priv->flatten_effect);
3064
3065           /* Set the priority of the effect to high so that it will
3066              always be applied to the actor first. It uses an internal
3067              priority so that it won't be visible to applications */
3068           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3069           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3070           _clutter_actor_meta_set_priority (actor_meta, priority);
3071
3072           /* This will add the effect without queueing a redraw */
3073           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3074         }
3075     }
3076   else
3077     {
3078       if (priv->flatten_effect != NULL)
3079         {
3080           /* Destroy the effect so that it will lose its fbo cache of
3081              the actor */
3082           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3083           g_object_unref (priv->flatten_effect);
3084           priv->flatten_effect = NULL;
3085         }
3086     }
3087 }
3088
3089 static void
3090 clutter_actor_paint_node (ClutterActor     *actor,
3091                           ClutterPaintNode *root)
3092 {
3093   ClutterActorPrivate *priv = actor->priv;
3094
3095   if (priv->bg_color_set)
3096     {
3097       ClutterPaintNode *node;
3098       ClutterColor bg_color;
3099
3100       bg_color = priv->bg_color;
3101       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3102                      * priv->bg_color.alpha
3103                      / 255;
3104
3105       node = clutter_color_node_new (&bg_color);
3106       clutter_paint_node_set_name (node, "backgroundColor");
3107       clutter_paint_node_add_rectangle (node, &priv->allocation);
3108       clutter_paint_node_add_child (root, node);
3109       clutter_paint_node_unref (node);
3110     }
3111
3112   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3113     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3114
3115   if (clutter_paint_node_get_n_children (root) == 0)
3116     return;
3117
3118   _clutter_paint_node_paint (root);
3119 }
3120
3121 static void
3122 clutter_actor_real_paint (ClutterActor *actor)
3123 {
3124   ClutterActorPrivate *priv = actor->priv;
3125   ClutterActor *iter;
3126
3127   for (iter = priv->first_child;
3128        iter != NULL;
3129        iter = iter->priv->next_sibling)
3130     {
3131       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3132                     _clutter_actor_get_debug_name (iter),
3133                     _clutter_actor_get_debug_name (actor),
3134                     iter->priv->allocation.x1,
3135                     iter->priv->allocation.y1,
3136                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3137                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3138
3139       clutter_actor_paint (iter);
3140     }
3141 }
3142
3143 /**
3144  * clutter_actor_paint:
3145  * @self: A #ClutterActor
3146  *
3147  * Renders the actor to display.
3148  *
3149  * This function should not be called directly by applications.
3150  * Call clutter_actor_queue_redraw() to queue paints, instead.
3151  *
3152  * This function is context-aware, and will either cause a
3153  * regular paint or a pick paint.
3154  *
3155  * This function will emit the #ClutterActor::paint signal or
3156  * the #ClutterActor::pick signal, depending on the context.
3157  *
3158  * This function does not paint the actor if the actor is set to 0,
3159  * unless it is performing a pick paint.
3160  */
3161 void
3162 clutter_actor_paint (ClutterActor *self)
3163 {
3164   ClutterActorPrivate *priv;
3165   ClutterPickMode pick_mode;
3166   gboolean clip_set = FALSE;
3167   gboolean shader_applied = FALSE;
3168
3169   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3170                           "Actor real-paint counter",
3171                           "Increments each time any actor is painted",
3172                           0 /* no application private data */);
3173   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3174                           "Actor pick-paint counter",
3175                           "Increments each time any actor is painted "
3176                           "for picking",
3177                           0 /* no application private data */);
3178
3179   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3180
3181   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3182     return;
3183
3184   priv = self->priv;
3185
3186   pick_mode = _clutter_context_get_pick_mode ();
3187
3188   if (pick_mode == CLUTTER_PICK_NONE)
3189     priv->propagated_one_redraw = FALSE;
3190
3191   /* It's an important optimization that we consider painting of
3192    * actors with 0 opacity to be a NOP... */
3193   if (pick_mode == CLUTTER_PICK_NONE &&
3194       /* ignore top-levels, since they might be transparent */
3195       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3196       /* Use the override opacity if its been set */
3197       ((priv->opacity_override >= 0) ?
3198        priv->opacity_override : priv->opacity) == 0)
3199     return;
3200
3201   /* if we aren't paintable (not in a toplevel with all
3202    * parents paintable) then do nothing.
3203    */
3204   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3205     return;
3206
3207   /* mark that we are in the paint process */
3208   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3209
3210   cogl_push_matrix();
3211
3212   if (priv->enable_model_view_transform)
3213     {
3214       CoglMatrix matrix;
3215
3216       /* XXX: It could be better to cache the modelview with the actor
3217        * instead of progressively building up the transformations on
3218        * the matrix stack every time we paint. */
3219       cogl_get_modelview_matrix (&matrix);
3220       _clutter_actor_apply_modelview_transform (self, &matrix);
3221
3222 #ifdef CLUTTER_ENABLE_DEBUG
3223       /* Catch when out-of-band transforms have been made by actors not as part
3224        * of an apply_transform vfunc... */
3225       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3226         {
3227           CoglMatrix expected_matrix;
3228
3229           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3230                                                              &expected_matrix);
3231
3232           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3233             {
3234               GString *buf = g_string_sized_new (1024);
3235               ClutterActor *parent;
3236
3237               parent = self;
3238               while (parent != NULL)
3239                 {
3240                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3241
3242                   if (parent->priv->parent != NULL)
3243                     g_string_append (buf, "->");
3244
3245                   parent = parent->priv->parent;
3246                 }
3247
3248               g_warning ("Unexpected transform found when painting actor "
3249                          "\"%s\". This will be caused by one of the actor's "
3250                          "ancestors (%s) using the Cogl API directly to transform "
3251                          "children instead of using ::apply_transform().",
3252                          _clutter_actor_get_debug_name (self),
3253                          buf->str);
3254
3255               g_string_free (buf, TRUE);
3256             }
3257         }
3258 #endif /* CLUTTER_ENABLE_DEBUG */
3259
3260       cogl_set_modelview_matrix (&matrix);
3261     }
3262
3263   if (priv->has_clip)
3264     {
3265       cogl_clip_push_rectangle (priv->clip.x,
3266                                 priv->clip.y,
3267                                 priv->clip.x + priv->clip.width,
3268                                 priv->clip.y + priv->clip.height);
3269       clip_set = TRUE;
3270     }
3271   else if (priv->clip_to_allocation)
3272     {
3273       gfloat width, height;
3274
3275       width  = priv->allocation.x2 - priv->allocation.x1;
3276       height = priv->allocation.y2 - priv->allocation.y1;
3277
3278       cogl_clip_push_rectangle (0, 0, width, height);
3279       clip_set = TRUE;
3280     }
3281
3282   if (pick_mode == CLUTTER_PICK_NONE)
3283     {
3284       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3285
3286       /* We check whether we need to add the flatten effect before
3287          each paint so that we can avoid having a mechanism for
3288          applications to notify when the value of the
3289          has_overlaps virtual changes. */
3290       add_or_remove_flatten_effect (self);
3291     }
3292   else
3293     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3294
3295   /* We save the current paint volume so that the next time the
3296    * actor queues a redraw we can constrain the redraw to just
3297    * cover the union of the new bounding box and the old.
3298    *
3299    * We also fetch the current paint volume to perform culling so
3300    * we can avoid painting actors outside the current clip region.
3301    *
3302    * If we are painting inside a clone, we should neither update
3303    * the paint volume or use it to cull painting, since the paint
3304    * box represents the location of the source actor on the
3305    * screen.
3306    *
3307    * XXX: We are starting to do a lot of vertex transforms on
3308    * the CPU in a typical paint, so at some point we should
3309    * audit these and consider caching some things.
3310    *
3311    * NB: We don't perform culling while picking at this point because
3312    * clutter-stage.c doesn't setup the clipping planes appropriately.
3313    *
3314    * NB: We don't want to update the last-paint-volume during picking
3315    * because the last-paint-volume is used to determine the old screen
3316    * space location of an actor that has moved so we can know the
3317    * minimal region to redraw to clear an old view of the actor. If we
3318    * update this during picking then by the time we come around to
3319    * paint then the last-paint-volume would likely represent the new
3320    * actor position not the old.
3321    */
3322   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3323     {
3324       gboolean success;
3325       /* annoyingly gcc warns if uninitialized even though
3326        * the initialization is redundant :-( */
3327       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3328
3329       if (G_LIKELY ((clutter_paint_debug_flags &
3330                      (CLUTTER_DEBUG_DISABLE_CULLING |
3331                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3332                     (CLUTTER_DEBUG_DISABLE_CULLING |
3333                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3334         _clutter_actor_update_last_paint_volume (self);
3335
3336       success = cull_actor (self, &result);
3337
3338       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3339         _clutter_actor_paint_cull_result (self, success, result);
3340       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3341         goto done;
3342     }
3343
3344   if (priv->effects == NULL)
3345     {
3346       if (pick_mode == CLUTTER_PICK_NONE &&
3347           actor_has_shader_data (self))
3348         {
3349           _clutter_actor_shader_pre_paint (self, FALSE);
3350           shader_applied = TRUE;
3351         }
3352
3353       priv->next_effect_to_paint = NULL;
3354     }
3355   else
3356     priv->next_effect_to_paint =
3357       _clutter_meta_group_peek_metas (priv->effects);
3358
3359   clutter_actor_continue_paint (self);
3360
3361   if (shader_applied)
3362     _clutter_actor_shader_post_paint (self);
3363
3364   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3365                   pick_mode == CLUTTER_PICK_NONE))
3366     _clutter_actor_draw_paint_volume (self);
3367
3368 done:
3369   /* If we make it here then the actor has run through a complete
3370      paint run including all the effects so it's no longer dirty */
3371   if (pick_mode == CLUTTER_PICK_NONE)
3372     priv->is_dirty = FALSE;
3373
3374   if (clip_set)
3375     cogl_clip_pop();
3376
3377   cogl_pop_matrix();
3378
3379   /* paint sequence complete */
3380   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3381 }
3382
3383 /**
3384  * clutter_actor_continue_paint:
3385  * @self: A #ClutterActor
3386  *
3387  * Run the next stage of the paint sequence. This function should only
3388  * be called within the implementation of the ‘run’ virtual of a
3389  * #ClutterEffect. It will cause the run method of the next effect to
3390  * be applied, or it will paint the actual actor if the current effect
3391  * is the last effect in the chain.
3392  *
3393  * Since: 1.8
3394  */
3395 void
3396 clutter_actor_continue_paint (ClutterActor *self)
3397 {
3398   ClutterActorPrivate *priv;
3399
3400   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3401   /* This should only be called from with in the ‘run’ implementation
3402      of a ClutterEffect */
3403   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3404
3405   priv = self->priv;
3406
3407   /* Skip any effects that are disabled */
3408   while (priv->next_effect_to_paint &&
3409          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3410     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3411
3412   /* If this has come from the last effect then we'll just paint the
3413      actual actor */
3414   if (priv->next_effect_to_paint == NULL)
3415     {
3416       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3417         {
3418           ClutterPaintNode *dummy;
3419
3420           /* XXX - this will go away in 2.0, when we can get rid of this
3421            * stuff and switch to a pure retained render tree of PaintNodes
3422            * for the entire frame, starting from the Stage.
3423            */
3424           dummy = _clutter_dummy_node_new ();
3425           clutter_paint_node_set_name (dummy, "Root");
3426           clutter_actor_paint_node (self, dummy);
3427
3428           if (clutter_paint_node_get_n_children (dummy) != 0)
3429             {
3430 #ifdef CLUTTER_ENABLE_DEBUG
3431               if (CLUTTER_HAS_DEBUG (PAINT))
3432                 {
3433                   /* dump the tree only if we have one */
3434                   _clutter_paint_node_dump_tree (dummy);
3435                 }
3436 #endif /* CLUTTER_ENABLE_DEBUG */
3437
3438               _clutter_paint_node_paint (dummy);
3439             }
3440
3441           clutter_paint_node_unref (dummy);
3442
3443           g_signal_emit (self, actor_signals[PAINT], 0);
3444         }
3445       else
3446         {
3447           ClutterColor col = { 0, };
3448
3449           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3450
3451           /* Actor will then paint silhouette of itself in supplied
3452            * color.  See clutter_stage_get_actor_at_pos() for where
3453            * picking is enabled.
3454            */
3455           g_signal_emit (self, actor_signals[PICK], 0, &col);
3456         }
3457     }
3458   else
3459     {
3460       ClutterEffect *old_current_effect;
3461       ClutterEffectPaintFlags run_flags = 0;
3462
3463       /* Cache the current effect so that we can put it back before
3464          returning */
3465       old_current_effect = priv->current_effect;
3466
3467       priv->current_effect = priv->next_effect_to_paint->data;
3468       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3469
3470       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3471         {
3472           if (priv->is_dirty)
3473             {
3474               /* If there's an effect queued with this redraw then all
3475                  effects up to that one will be considered dirty. It
3476                  is expected the queued effect will paint the cached
3477                  image and not call clutter_actor_continue_paint again
3478                  (although it should work ok if it does) */
3479               if (priv->effect_to_redraw == NULL ||
3480                   priv->current_effect != priv->effect_to_redraw)
3481                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3482             }
3483
3484           _clutter_effect_paint (priv->current_effect, run_flags);
3485         }
3486       else
3487         {
3488           /* We can't determine when an actor has been modified since
3489              its last pick so lets just assume it has always been
3490              modified */
3491           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3492
3493           _clutter_effect_pick (priv->current_effect, run_flags);
3494         }
3495
3496       priv->current_effect = old_current_effect;
3497     }
3498 }
3499
3500 static ClutterActorTraverseVisitFlags
3501 invalidate_queue_redraw_entry (ClutterActor *self,
3502                                int           depth,
3503                                gpointer      user_data)
3504 {
3505   ClutterActorPrivate *priv = self->priv;
3506
3507   if (priv->queue_redraw_entry != NULL)
3508     {
3509       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3510       priv->queue_redraw_entry = NULL;
3511     }
3512
3513   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3514 }
3515
3516 static inline void
3517 remove_child (ClutterActor *self,
3518               ClutterActor *child)
3519 {
3520   ClutterActor *prev_sibling, *next_sibling;
3521
3522   prev_sibling = child->priv->prev_sibling;
3523   next_sibling = child->priv->next_sibling;
3524
3525   if (prev_sibling != NULL)
3526     prev_sibling->priv->next_sibling = next_sibling;
3527
3528   if (next_sibling != NULL)
3529     next_sibling->priv->prev_sibling = prev_sibling;
3530
3531   if (self->priv->first_child == child)
3532     self->priv->first_child = next_sibling;
3533
3534   if (self->priv->last_child == child)
3535     self->priv->last_child = prev_sibling;
3536
3537   child->priv->parent = NULL;
3538   child->priv->prev_sibling = NULL;
3539   child->priv->next_sibling = NULL;
3540 }
3541
3542 typedef enum {
3543   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3544   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3545   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3546   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3547   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3548   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3549
3550   /* default flags for public API */
3551   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3552                                     REMOVE_CHILD_EMIT_PARENT_SET |
3553                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3554                                     REMOVE_CHILD_CHECK_STATE |
3555                                     REMOVE_CHILD_FLUSH_QUEUE |
3556                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3557
3558   /* flags for legacy/deprecated API */
3559   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3560                                     REMOVE_CHILD_FLUSH_QUEUE |
3561                                     REMOVE_CHILD_EMIT_PARENT_SET |
3562                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3563 } ClutterActorRemoveChildFlags;
3564
3565 /*< private >
3566  * clutter_actor_remove_child_internal:
3567  * @self: a #ClutterActor
3568  * @child: the child of @self that has to be removed
3569  * @flags: control the removal operations
3570  *
3571  * Removes @child from the list of children of @self.
3572  */
3573 static void
3574 clutter_actor_remove_child_internal (ClutterActor                 *self,
3575                                      ClutterActor                 *child,
3576                                      ClutterActorRemoveChildFlags  flags)
3577 {
3578   ClutterActor *old_first, *old_last;
3579   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3580   gboolean flush_queue;
3581   gboolean notify_first_last;
3582   gboolean was_mapped;
3583
3584   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3585   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3586   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3587   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3588   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3589   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3590
3591   g_object_freeze_notify (G_OBJECT (self));
3592
3593   if (destroy_meta)
3594     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3595
3596   if (check_state)
3597     {
3598       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3599
3600       /* we need to unrealize *before* we set parent_actor to NULL,
3601        * because in an unrealize method actors are dissociating from the
3602        * stage, which means they need to be able to
3603        * clutter_actor_get_stage().
3604        *
3605        * yhis should unmap and unrealize, unless we're reparenting.
3606        */
3607       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3608     }
3609   else
3610     was_mapped = FALSE;
3611
3612   if (flush_queue)
3613     {
3614       /* We take this opportunity to invalidate any queue redraw entry
3615        * associated with the actor and descendants since we won't be able to
3616        * determine the appropriate stage after this.
3617        *
3618        * we do this after we updated the mapped state because actors might
3619        * end up queueing redraws inside their mapped/unmapped virtual
3620        * functions, and if we invalidate the redraw entry we could end up
3621        * with an inconsistent state and weird memory corruption. see
3622        * bugs:
3623        *
3624        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3625        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3626        */
3627       _clutter_actor_traverse (child,
3628                                0,
3629                                invalidate_queue_redraw_entry,
3630                                NULL,
3631                                NULL);
3632     }
3633
3634   old_first = self->priv->first_child;
3635   old_last = self->priv->last_child;
3636
3637   remove_child (self, child);
3638
3639   self->priv->n_children -= 1;
3640
3641   self->priv->age += 1;
3642
3643   /* clutter_actor_reparent() will emit ::parent-set for us */
3644   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3645     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3646
3647   /* if the child was mapped then we need to relayout ourselves to account
3648    * for the removed child
3649    */
3650   if (was_mapped)
3651     clutter_actor_queue_relayout (self);
3652
3653   /* we need to emit the signal before dropping the reference */
3654   if (emit_actor_removed)
3655     g_signal_emit_by_name (self, "actor-removed", child);
3656
3657   if (notify_first_last)
3658     {
3659       if (old_first != self->priv->first_child)
3660         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3661
3662       if (old_last != self->priv->last_child)
3663         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3664     }
3665
3666   g_object_thaw_notify (G_OBJECT (self));
3667
3668   /* remove the reference we acquired in clutter_actor_add_child() */
3669   g_object_unref (child);
3670 }
3671
3672 static const ClutterTransformInfo default_transform_info = {
3673   0.0, { 0, },          /* rotation-x */
3674   0.0, { 0, },          /* rotation-y */
3675   0.0, { 0, },          /* rotation-z */
3676
3677   1.0, 1.0, { 0, },     /* scale */
3678
3679   { 0, },               /* anchor */
3680
3681   0.0,                  /* depth */
3682 };
3683
3684 /*< private >
3685  * _clutter_actor_get_transform_info_or_defaults:
3686  * @self: a #ClutterActor
3687  *
3688  * Retrieves the ClutterTransformInfo structure associated to an actor.
3689  *
3690  * If the actor does not have a ClutterTransformInfo structure associated
3691  * to it, then the default structure will be returned.
3692  *
3693  * This function should only be used for getters.
3694  *
3695  * Return value: a const pointer to the ClutterTransformInfo structure
3696  */
3697 const ClutterTransformInfo *
3698 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3699 {
3700   ClutterTransformInfo *info;
3701
3702   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3703   if (info != NULL)
3704     return info;
3705
3706   return &default_transform_info;
3707 }
3708
3709 static void
3710 clutter_transform_info_free (gpointer data)
3711 {
3712   if (data != NULL)
3713     g_slice_free (ClutterTransformInfo, data);
3714 }
3715
3716 /*< private >
3717  * _clutter_actor_get_transform_info:
3718  * @self: a #ClutterActor
3719  *
3720  * Retrieves a pointer to the ClutterTransformInfo structure.
3721  *
3722  * If the actor does not have a ClutterTransformInfo associated to it, one
3723  * will be created and initialized to the default values.
3724  *
3725  * This function should be used for setters.
3726  *
3727  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3728  * instead.
3729  *
3730  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3731  *   structure
3732  */
3733 ClutterTransformInfo *
3734 _clutter_actor_get_transform_info (ClutterActor *self)
3735 {
3736   ClutterTransformInfo *info;
3737
3738   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3739   if (info == NULL)
3740     {
3741       info = g_slice_new (ClutterTransformInfo);
3742
3743       *info = default_transform_info;
3744
3745       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3746                                info,
3747                                clutter_transform_info_free);
3748     }
3749
3750   return info;
3751 }
3752
3753 /*< private >
3754  * clutter_actor_set_rotation_angle_internal:
3755  * @self: a #ClutterActor
3756  * @axis: the axis of the angle to change
3757  * @angle: the angle of rotation
3758  *
3759  * Sets the rotation angle on the given axis without affecting the
3760  * rotation center point.
3761  */
3762 static inline void
3763 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3764                                            ClutterRotateAxis  axis,
3765                                            gdouble            angle)
3766 {
3767   GObject *obj = G_OBJECT (self);
3768   ClutterTransformInfo *info;
3769
3770   info = _clutter_actor_get_transform_info (self);
3771
3772   g_object_freeze_notify (obj);
3773
3774   switch (axis)
3775     {
3776     case CLUTTER_X_AXIS:
3777       info->rx_angle = angle;
3778       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3779       break;
3780
3781     case CLUTTER_Y_AXIS:
3782       info->ry_angle = angle;
3783       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3784       break;
3785
3786     case CLUTTER_Z_AXIS:
3787       info->rz_angle = angle;
3788       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3789       break;
3790     }
3791
3792   self->priv->transform_valid = FALSE;
3793
3794   g_object_thaw_notify (obj);
3795
3796   clutter_actor_queue_redraw (self);
3797 }
3798
3799 static inline void
3800 clutter_actor_set_rotation_angle (ClutterActor      *self,
3801                                   ClutterRotateAxis  axis,
3802                                   gdouble            angle)
3803 {
3804   ClutterTransformInfo *info;
3805
3806   info = _clutter_actor_get_transform_info (self);
3807
3808   if (clutter_actor_get_easing_duration (self) != 0)
3809     {
3810       ClutterTransition *transition;
3811       GParamSpec *pspec = NULL;
3812       double *cur_angle_p = NULL;
3813
3814       switch (axis)
3815         {
3816         case CLUTTER_X_AXIS:
3817           cur_angle_p = &info->rx_angle;
3818           pspec = obj_props[PROP_ROTATION_ANGLE_X];
3819           break;
3820
3821         case CLUTTER_Y_AXIS:
3822           cur_angle_p = &info->ry_angle;
3823           pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3824           break;
3825
3826         case CLUTTER_Z_AXIS:
3827           cur_angle_p = &info->rz_angle;
3828           pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3829           break;
3830         }
3831
3832       g_assert (pspec != NULL);
3833       g_assert (cur_angle_p != NULL);
3834
3835       transition = _clutter_actor_get_transition (self, pspec);
3836       if (transition == NULL)
3837         {
3838           transition = _clutter_actor_create_transition (self, pspec,
3839                                                          *cur_angle_p,
3840                                                          angle);
3841           clutter_timeline_start (CLUTTER_TIMELINE (transition));
3842         }
3843       else
3844         _clutter_actor_update_transition (self, pspec, angle);
3845
3846       self->priv->transform_valid = FALSE;
3847       clutter_actor_queue_redraw (self);
3848     }
3849   else
3850     clutter_actor_set_rotation_angle_internal (self, axis, angle);
3851 }
3852
3853 /*< private >
3854  * clutter_actor_set_rotation_center_internal:
3855  * @self: a #ClutterActor
3856  * @axis: the axis of the center to change
3857  * @center: the coordinates of the rotation center
3858  *
3859  * Sets the rotation center on the given axis without affecting the
3860  * rotation angle.
3861  */
3862 static inline void
3863 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3864                                             ClutterRotateAxis    axis,
3865                                             const ClutterVertex *center)
3866 {
3867   GObject *obj = G_OBJECT (self);
3868   ClutterTransformInfo *info;
3869   ClutterVertex v = { 0, 0, 0 };
3870
3871   info = _clutter_actor_get_transform_info (self);
3872
3873   if (center != NULL)
3874     v = *center;
3875
3876   g_object_freeze_notify (obj);
3877
3878   switch (axis)
3879     {
3880     case CLUTTER_X_AXIS:
3881       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3882       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3883       break;
3884
3885     case CLUTTER_Y_AXIS:
3886       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3887       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3888       break;
3889
3890     case CLUTTER_Z_AXIS:
3891       /* if the previously set rotation center was fractional, then
3892        * setting explicit coordinates will have to notify the
3893        * :rotation-center-z-gravity property as well
3894        */
3895       if (info->rz_center.is_fractional)
3896         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3897
3898       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3899       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3900       break;
3901     }
3902
3903   self->priv->transform_valid = FALSE;
3904
3905   g_object_thaw_notify (obj);
3906
3907   clutter_actor_queue_redraw (self);
3908 }
3909
3910 static void
3911 clutter_actor_animate_scale_factor (ClutterActor *self,
3912                                     double        old_factor,
3913                                     double        new_factor,
3914                                     GParamSpec   *pspec)
3915 {
3916   ClutterTransition *transition;
3917
3918   transition = _clutter_actor_get_transition (self, pspec);
3919   if (transition == NULL)
3920     {
3921       transition = _clutter_actor_create_transition (self, pspec,
3922                                                      old_factor,
3923                                                      new_factor);
3924       clutter_timeline_start (CLUTTER_TIMELINE (transition));
3925     }
3926   else
3927     _clutter_actor_update_transition (self, pspec, new_factor);
3928
3929
3930   self->priv->transform_valid = FALSE;
3931   clutter_actor_queue_redraw (self);
3932 }
3933
3934 static void
3935 clutter_actor_set_scale_factor_internal (ClutterActor *self,
3936                                          double factor,
3937                                          GParamSpec *pspec)
3938 {
3939   GObject *obj = G_OBJECT (self);
3940   ClutterTransformInfo *info;
3941
3942   info = _clutter_actor_get_transform_info (self);
3943
3944   if (pspec == obj_props[PROP_SCALE_X])
3945     info->scale_x = factor;
3946   else
3947     info->scale_y = factor;
3948
3949   self->priv->transform_valid = FALSE;
3950   clutter_actor_queue_redraw (self);
3951   g_object_notify_by_pspec (obj, pspec);
3952 }
3953
3954 static inline void
3955 clutter_actor_set_scale_factor (ClutterActor      *self,
3956                                 ClutterRotateAxis  axis,
3957                                 gdouble            factor)
3958 {
3959   GObject *obj = G_OBJECT (self);
3960   ClutterTransformInfo *info;
3961   GParamSpec *pspec;
3962
3963   info = _clutter_actor_get_transform_info (self);
3964
3965   g_object_freeze_notify (obj);
3966
3967   switch (axis)
3968     {
3969     case CLUTTER_X_AXIS:
3970       pspec = obj_props[PROP_SCALE_X];
3971
3972       if (clutter_actor_get_easing_duration (self) != 0)
3973         clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
3974       else
3975         clutter_actor_set_scale_factor_internal (self, factor, pspec);
3976       break;
3977
3978     case CLUTTER_Y_AXIS:
3979       pspec = obj_props[PROP_SCALE_Y];
3980
3981       if (clutter_actor_get_easing_duration (self) != 0)
3982         clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
3983       else
3984         clutter_actor_set_scale_factor_internal (self, factor, pspec);
3985       break;
3986
3987     default:
3988       g_assert_not_reached ();
3989     }
3990
3991   g_object_thaw_notify (obj);
3992 }
3993
3994 static inline void
3995 clutter_actor_set_scale_center (ClutterActor      *self,
3996                                 ClutterRotateAxis  axis,
3997                                 gfloat             coord)
3998 {
3999   GObject *obj = G_OBJECT (self);
4000   ClutterTransformInfo *info;
4001   gfloat center_x, center_y;
4002
4003   info = _clutter_actor_get_transform_info (self);
4004
4005   g_object_freeze_notify (obj);
4006
4007   /* get the current scale center coordinates */
4008   clutter_anchor_coord_get_units (self, &info->scale_center,
4009                                   &center_x,
4010                                   &center_y,
4011                                   NULL);
4012
4013   /* we need to notify this too, because setting explicit coordinates will
4014    * change the gravity as a side effect
4015    */
4016   if (info->scale_center.is_fractional)
4017     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4018
4019   switch (axis)
4020     {
4021     case CLUTTER_X_AXIS:
4022       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4023       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4024       break;
4025
4026     case CLUTTER_Y_AXIS:
4027       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4028       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4029       break;
4030
4031     default:
4032       g_assert_not_reached ();
4033     }
4034
4035   self->priv->transform_valid = FALSE;
4036
4037   clutter_actor_queue_redraw (self);
4038
4039   g_object_thaw_notify (obj);
4040 }
4041
4042 static inline void
4043 clutter_actor_set_anchor_coord (ClutterActor      *self,
4044                                 ClutterRotateAxis  axis,
4045                                 gfloat             coord)
4046 {
4047   GObject *obj = G_OBJECT (self);
4048   ClutterTransformInfo *info;
4049   gfloat anchor_x, anchor_y;
4050
4051   info = _clutter_actor_get_transform_info (self);
4052
4053   g_object_freeze_notify (obj);
4054
4055   clutter_anchor_coord_get_units (self, &info->anchor,
4056                                   &anchor_x,
4057                                   &anchor_y,
4058                                   NULL);
4059
4060   if (info->anchor.is_fractional)
4061     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4062
4063   switch (axis)
4064     {
4065     case CLUTTER_X_AXIS:
4066       clutter_anchor_coord_set_units (&info->anchor,
4067                                       coord,
4068                                       anchor_y,
4069                                       0.0);
4070       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4071       break;
4072
4073     case CLUTTER_Y_AXIS:
4074       clutter_anchor_coord_set_units (&info->anchor,
4075                                       anchor_x,
4076                                       coord,
4077                                       0.0);
4078       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4079       break;
4080
4081     default:
4082       g_assert_not_reached ();
4083     }
4084
4085   self->priv->transform_valid = FALSE;
4086
4087   clutter_actor_queue_redraw (self);
4088
4089   g_object_thaw_notify (obj);
4090 }
4091
4092 static void
4093 clutter_actor_set_property (GObject      *object,
4094                             guint         prop_id,
4095                             const GValue *value,
4096                             GParamSpec   *pspec)
4097 {
4098   ClutterActor *actor = CLUTTER_ACTOR (object);
4099   ClutterActorPrivate *priv = actor->priv;
4100
4101   switch (prop_id)
4102     {
4103     case PROP_X:
4104       clutter_actor_set_x (actor, g_value_get_float (value));
4105       break;
4106
4107     case PROP_Y:
4108       clutter_actor_set_y (actor, g_value_get_float (value));
4109       break;
4110
4111     case PROP_WIDTH:
4112       clutter_actor_set_width (actor, g_value_get_float (value));
4113       break;
4114
4115     case PROP_HEIGHT:
4116       clutter_actor_set_height (actor, g_value_get_float (value));
4117       break;
4118
4119     case PROP_FIXED_X:
4120       clutter_actor_set_x (actor, g_value_get_float (value));
4121       break;
4122
4123     case PROP_FIXED_Y:
4124       clutter_actor_set_y (actor, g_value_get_float (value));
4125       break;
4126
4127     case PROP_FIXED_POSITION_SET:
4128       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4129       break;
4130
4131     case PROP_MIN_WIDTH:
4132       clutter_actor_set_min_width (actor, g_value_get_float (value));
4133       break;
4134
4135     case PROP_MIN_HEIGHT:
4136       clutter_actor_set_min_height (actor, g_value_get_float (value));
4137       break;
4138
4139     case PROP_NATURAL_WIDTH:
4140       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4141       break;
4142
4143     case PROP_NATURAL_HEIGHT:
4144       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4145       break;
4146
4147     case PROP_MIN_WIDTH_SET:
4148       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4149       break;
4150
4151     case PROP_MIN_HEIGHT_SET:
4152       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4153       break;
4154
4155     case PROP_NATURAL_WIDTH_SET:
4156       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4157       break;
4158
4159     case PROP_NATURAL_HEIGHT_SET:
4160       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4161       break;
4162
4163     case PROP_REQUEST_MODE:
4164       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4165       break;
4166
4167     case PROP_DEPTH:
4168       clutter_actor_set_depth (actor, g_value_get_float (value));
4169       break;
4170
4171     case PROP_OPACITY:
4172       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4173       break;
4174
4175     case PROP_OFFSCREEN_REDIRECT:
4176       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4177       break;
4178
4179     case PROP_NAME:
4180       clutter_actor_set_name (actor, g_value_get_string (value));
4181       break;
4182
4183     case PROP_VISIBLE:
4184       if (g_value_get_boolean (value) == TRUE)
4185         clutter_actor_show (actor);
4186       else
4187         clutter_actor_hide (actor);
4188       break;
4189
4190     case PROP_SCALE_X:
4191       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4192                                       g_value_get_double (value));
4193       break;
4194
4195     case PROP_SCALE_Y:
4196       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4197                                       g_value_get_double (value));
4198       break;
4199
4200     case PROP_SCALE_CENTER_X:
4201       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4202                                       g_value_get_float (value));
4203       break;
4204
4205     case PROP_SCALE_CENTER_Y:
4206       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4207                                       g_value_get_float (value));
4208       break;
4209
4210     case PROP_SCALE_GRAVITY:
4211       {
4212         const ClutterTransformInfo *info;
4213         ClutterGravity gravity;
4214
4215         info = _clutter_actor_get_transform_info_or_defaults (actor);
4216         gravity = g_value_get_enum (value);
4217
4218         clutter_actor_set_scale_with_gravity (actor,
4219                                               info->scale_x,
4220                                               info->scale_y,
4221                                               gravity);
4222       }
4223       break;
4224
4225     case PROP_CLIP:
4226       {
4227         const ClutterGeometry *geom = g_value_get_boxed (value);
4228
4229         clutter_actor_set_clip (actor,
4230                                 geom->x, geom->y,
4231                                 geom->width, geom->height);
4232       }
4233       break;
4234
4235     case PROP_CLIP_TO_ALLOCATION:
4236       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4237       break;
4238
4239     case PROP_REACTIVE:
4240       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4241       break;
4242
4243     case PROP_ROTATION_ANGLE_X:
4244       clutter_actor_set_rotation_angle (actor,
4245                                         CLUTTER_X_AXIS,
4246                                         g_value_get_double (value));
4247       break;
4248
4249     case PROP_ROTATION_ANGLE_Y:
4250       clutter_actor_set_rotation_angle (actor,
4251                                         CLUTTER_Y_AXIS,
4252                                         g_value_get_double (value));
4253       break;
4254
4255     case PROP_ROTATION_ANGLE_Z:
4256       clutter_actor_set_rotation_angle (actor,
4257                                         CLUTTER_Z_AXIS,
4258                                         g_value_get_double (value));
4259       break;
4260
4261     case PROP_ROTATION_CENTER_X:
4262       clutter_actor_set_rotation_center_internal (actor,
4263                                                   CLUTTER_X_AXIS,
4264                                                   g_value_get_boxed (value));
4265       break;
4266
4267     case PROP_ROTATION_CENTER_Y:
4268       clutter_actor_set_rotation_center_internal (actor,
4269                                                   CLUTTER_Y_AXIS,
4270                                                   g_value_get_boxed (value));
4271       break;
4272
4273     case PROP_ROTATION_CENTER_Z:
4274       clutter_actor_set_rotation_center_internal (actor,
4275                                                   CLUTTER_Z_AXIS,
4276                                                   g_value_get_boxed (value));
4277       break;
4278
4279     case PROP_ROTATION_CENTER_Z_GRAVITY:
4280       {
4281         const ClutterTransformInfo *info;
4282
4283         info = _clutter_actor_get_transform_info_or_defaults (actor);
4284         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4285                                                    g_value_get_enum (value));
4286       }
4287       break;
4288
4289     case PROP_ANCHOR_X:
4290       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4291                                       g_value_get_float (value));
4292       break;
4293
4294     case PROP_ANCHOR_Y:
4295       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4296                                       g_value_get_float (value));
4297       break;
4298
4299     case PROP_ANCHOR_GRAVITY:
4300       clutter_actor_set_anchor_point_from_gravity (actor,
4301                                                    g_value_get_enum (value));
4302       break;
4303
4304     case PROP_SHOW_ON_SET_PARENT:
4305       priv->show_on_set_parent = g_value_get_boolean (value);
4306       break;
4307
4308     case PROP_TEXT_DIRECTION:
4309       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4310       break;
4311
4312     case PROP_ACTIONS:
4313       clutter_actor_add_action (actor, g_value_get_object (value));
4314       break;
4315
4316     case PROP_CONSTRAINTS:
4317       clutter_actor_add_constraint (actor, g_value_get_object (value));
4318       break;
4319
4320     case PROP_EFFECT:
4321       clutter_actor_add_effect (actor, g_value_get_object (value));
4322       break;
4323
4324     case PROP_LAYOUT_MANAGER:
4325       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4326       break;
4327
4328     case PROP_X_ALIGN:
4329       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4330       break;
4331
4332     case PROP_Y_ALIGN:
4333       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4334       break;
4335
4336     case PROP_MARGIN_TOP:
4337       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4338       break;
4339
4340     case PROP_MARGIN_BOTTOM:
4341       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4342       break;
4343
4344     case PROP_MARGIN_LEFT:
4345       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4346       break;
4347
4348     case PROP_MARGIN_RIGHT:
4349       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4350       break;
4351
4352     case PROP_BACKGROUND_COLOR:
4353       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4354       break;
4355
4356     default:
4357       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4358       break;
4359     }
4360 }
4361
4362 static void
4363 clutter_actor_get_property (GObject    *object,
4364                             guint       prop_id,
4365                             GValue     *value,
4366                             GParamSpec *pspec)
4367 {
4368   ClutterActor *actor = CLUTTER_ACTOR (object);
4369   ClutterActorPrivate *priv = actor->priv;
4370
4371   switch (prop_id)
4372     {
4373     case PROP_X:
4374       g_value_set_float (value, clutter_actor_get_x (actor));
4375       break;
4376
4377     case PROP_Y:
4378       g_value_set_float (value, clutter_actor_get_y (actor));
4379       break;
4380
4381     case PROP_WIDTH:
4382       g_value_set_float (value, clutter_actor_get_width (actor));
4383       break;
4384
4385     case PROP_HEIGHT:
4386       g_value_set_float (value, clutter_actor_get_height (actor));
4387       break;
4388
4389     case PROP_FIXED_X:
4390       {
4391         const ClutterLayoutInfo *info;
4392
4393         info = _clutter_actor_get_layout_info_or_defaults (actor);
4394         g_value_set_float (value, info->fixed_x);
4395       }
4396       break;
4397
4398     case PROP_FIXED_Y:
4399       {
4400         const ClutterLayoutInfo *info;
4401
4402         info = _clutter_actor_get_layout_info_or_defaults (actor);
4403         g_value_set_float (value, info->fixed_y);
4404       }
4405       break;
4406
4407     case PROP_FIXED_POSITION_SET:
4408       g_value_set_boolean (value, priv->position_set);
4409       break;
4410
4411     case PROP_MIN_WIDTH:
4412       {
4413         const ClutterLayoutInfo *info;
4414
4415         info = _clutter_actor_get_layout_info_or_defaults (actor);
4416         g_value_set_float (value, info->min_width);
4417       }
4418       break;
4419
4420     case PROP_MIN_HEIGHT:
4421       {
4422         const ClutterLayoutInfo *info;
4423
4424         info = _clutter_actor_get_layout_info_or_defaults (actor);
4425         g_value_set_float (value, info->min_height);
4426       }
4427       break;
4428
4429     case PROP_NATURAL_WIDTH:
4430       {
4431         const ClutterLayoutInfo *info;
4432
4433         info = _clutter_actor_get_layout_info_or_defaults (actor);
4434         g_value_set_float (value, info->natural_width);
4435       }
4436       break;
4437
4438     case PROP_NATURAL_HEIGHT:
4439       {
4440         const ClutterLayoutInfo *info;
4441
4442         info = _clutter_actor_get_layout_info_or_defaults (actor);
4443         g_value_set_float (value, info->natural_height);
4444       }
4445       break;
4446
4447     case PROP_MIN_WIDTH_SET:
4448       g_value_set_boolean (value, priv->min_width_set);
4449       break;
4450
4451     case PROP_MIN_HEIGHT_SET:
4452       g_value_set_boolean (value, priv->min_height_set);
4453       break;
4454
4455     case PROP_NATURAL_WIDTH_SET:
4456       g_value_set_boolean (value, priv->natural_width_set);
4457       break;
4458
4459     case PROP_NATURAL_HEIGHT_SET:
4460       g_value_set_boolean (value, priv->natural_height_set);
4461       break;
4462
4463     case PROP_REQUEST_MODE:
4464       g_value_set_enum (value, priv->request_mode);
4465       break;
4466
4467     case PROP_ALLOCATION:
4468       g_value_set_boxed (value, &priv->allocation);
4469       break;
4470
4471     case PROP_DEPTH:
4472       g_value_set_float (value, clutter_actor_get_depth (actor));
4473       break;
4474
4475     case PROP_OPACITY:
4476       g_value_set_uint (value, priv->opacity);
4477       break;
4478
4479     case PROP_OFFSCREEN_REDIRECT:
4480       g_value_set_enum (value, priv->offscreen_redirect);
4481       break;
4482
4483     case PROP_NAME:
4484       g_value_set_string (value, priv->name);
4485       break;
4486
4487     case PROP_VISIBLE:
4488       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4489       break;
4490
4491     case PROP_MAPPED:
4492       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4493       break;
4494
4495     case PROP_REALIZED:
4496       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4497       break;
4498
4499     case PROP_HAS_CLIP:
4500       g_value_set_boolean (value, priv->has_clip);
4501       break;
4502
4503     case PROP_CLIP:
4504       {
4505         ClutterGeometry clip;
4506
4507         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4508         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4509         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4510         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4511
4512         g_value_set_boxed (value, &clip);
4513       }
4514       break;
4515
4516     case PROP_CLIP_TO_ALLOCATION:
4517       g_value_set_boolean (value, priv->clip_to_allocation);
4518       break;
4519
4520     case PROP_SCALE_X:
4521       {
4522         const ClutterTransformInfo *info;
4523
4524         info = _clutter_actor_get_transform_info_or_defaults (actor);
4525         g_value_set_double (value, info->scale_x);
4526       }
4527       break;
4528
4529     case PROP_SCALE_Y:
4530       {
4531         const ClutterTransformInfo *info;
4532
4533         info = _clutter_actor_get_transform_info_or_defaults (actor);
4534         g_value_set_double (value, info->scale_y);
4535       }
4536       break;
4537
4538     case PROP_SCALE_CENTER_X:
4539       {
4540         gfloat center;
4541
4542         clutter_actor_get_scale_center (actor, &center, NULL);
4543
4544         g_value_set_float (value, center);
4545       }
4546       break;
4547
4548     case PROP_SCALE_CENTER_Y:
4549       {
4550         gfloat center;
4551
4552         clutter_actor_get_scale_center (actor, NULL, &center);
4553
4554         g_value_set_float (value, center);
4555       }
4556       break;
4557
4558     case PROP_SCALE_GRAVITY:
4559       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4560       break;
4561
4562     case PROP_REACTIVE:
4563       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4564       break;
4565
4566     case PROP_ROTATION_ANGLE_X:
4567       {
4568         const ClutterTransformInfo *info;
4569
4570         info = _clutter_actor_get_transform_info_or_defaults (actor);
4571         g_value_set_double (value, info->rx_angle);
4572       }
4573       break;
4574
4575     case PROP_ROTATION_ANGLE_Y:
4576       {
4577         const ClutterTransformInfo *info;
4578
4579         info = _clutter_actor_get_transform_info_or_defaults (actor);
4580         g_value_set_double (value, info->ry_angle);
4581       }
4582       break;
4583
4584     case PROP_ROTATION_ANGLE_Z:
4585       {
4586         const ClutterTransformInfo *info;
4587
4588         info = _clutter_actor_get_transform_info_or_defaults (actor);
4589         g_value_set_double (value, info->rz_angle);
4590       }
4591       break;
4592
4593     case PROP_ROTATION_CENTER_X:
4594       {
4595         ClutterVertex center;
4596
4597         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4598                                     &center.x,
4599                                     &center.y,
4600                                     &center.z);
4601
4602         g_value_set_boxed (value, &center);
4603       }
4604       break;
4605
4606     case PROP_ROTATION_CENTER_Y:
4607       {
4608         ClutterVertex center;
4609
4610         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4611                                     &center.x,
4612                                     &center.y,
4613                                     &center.z);
4614
4615         g_value_set_boxed (value, &center);
4616       }
4617       break;
4618
4619     case PROP_ROTATION_CENTER_Z:
4620       {
4621         ClutterVertex center;
4622
4623         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4624                                     &center.x,
4625                                     &center.y,
4626                                     &center.z);
4627
4628         g_value_set_boxed (value, &center);
4629       }
4630       break;
4631
4632     case PROP_ROTATION_CENTER_Z_GRAVITY:
4633       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4634       break;
4635
4636     case PROP_ANCHOR_X:
4637       {
4638         const ClutterTransformInfo *info;
4639         gfloat anchor_x;
4640
4641         info = _clutter_actor_get_transform_info_or_defaults (actor);
4642         clutter_anchor_coord_get_units (actor, &info->anchor,
4643                                         &anchor_x,
4644                                         NULL,
4645                                         NULL);
4646         g_value_set_float (value, anchor_x);
4647       }
4648       break;
4649
4650     case PROP_ANCHOR_Y:
4651       {
4652         const ClutterTransformInfo *info;
4653         gfloat anchor_y;
4654
4655         info = _clutter_actor_get_transform_info_or_defaults (actor);
4656         clutter_anchor_coord_get_units (actor, &info->anchor,
4657                                         NULL,
4658                                         &anchor_y,
4659                                         NULL);
4660         g_value_set_float (value, anchor_y);
4661       }
4662       break;
4663
4664     case PROP_ANCHOR_GRAVITY:
4665       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4666       break;
4667
4668     case PROP_SHOW_ON_SET_PARENT:
4669       g_value_set_boolean (value, priv->show_on_set_parent);
4670       break;
4671
4672     case PROP_TEXT_DIRECTION:
4673       g_value_set_enum (value, priv->text_direction);
4674       break;
4675
4676     case PROP_HAS_POINTER:
4677       g_value_set_boolean (value, priv->has_pointer);
4678       break;
4679
4680     case PROP_LAYOUT_MANAGER:
4681       g_value_set_object (value, priv->layout_manager);
4682       break;
4683
4684     case PROP_X_ALIGN:
4685       {
4686         const ClutterLayoutInfo *info;
4687
4688         info = _clutter_actor_get_layout_info_or_defaults (actor);
4689         g_value_set_enum (value, info->x_align);
4690       }
4691       break;
4692
4693     case PROP_Y_ALIGN:
4694       {
4695         const ClutterLayoutInfo *info;
4696
4697         info = _clutter_actor_get_layout_info_or_defaults (actor);
4698         g_value_set_enum (value, info->y_align);
4699       }
4700       break;
4701
4702     case PROP_MARGIN_TOP:
4703       {
4704         const ClutterLayoutInfo *info;
4705
4706         info = _clutter_actor_get_layout_info_or_defaults (actor);
4707         g_value_set_float (value, info->margin.top);
4708       }
4709       break;
4710
4711     case PROP_MARGIN_BOTTOM:
4712       {
4713         const ClutterLayoutInfo *info;
4714
4715         info = _clutter_actor_get_layout_info_or_defaults (actor);
4716         g_value_set_float (value, info->margin.bottom);
4717       }
4718       break;
4719
4720     case PROP_MARGIN_LEFT:
4721       {
4722         const ClutterLayoutInfo *info;
4723
4724         info = _clutter_actor_get_layout_info_or_defaults (actor);
4725         g_value_set_float (value, info->margin.left);
4726       }
4727       break;
4728
4729     case PROP_MARGIN_RIGHT:
4730       {
4731         const ClutterLayoutInfo *info;
4732
4733         info = _clutter_actor_get_layout_info_or_defaults (actor);
4734         g_value_set_float (value, info->margin.right);
4735       }
4736       break;
4737
4738     case PROP_BACKGROUND_COLOR_SET:
4739       g_value_set_boolean (value, priv->bg_color_set);
4740       break;
4741
4742     case PROP_BACKGROUND_COLOR:
4743       g_value_set_boxed (value, &priv->bg_color);
4744       break;
4745
4746     case PROP_FIRST_CHILD:
4747       g_value_set_object (value, priv->first_child);
4748       break;
4749
4750     case PROP_LAST_CHILD:
4751       g_value_set_object (value, priv->last_child);
4752       break;
4753
4754     default:
4755       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4756       break;
4757     }
4758 }
4759
4760 static void
4761 clutter_actor_dispose (GObject *object)
4762 {
4763   ClutterActor *self = CLUTTER_ACTOR (object);
4764   ClutterActorPrivate *priv = self->priv;
4765
4766   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4767                 priv->id,
4768                 g_type_name (G_OBJECT_TYPE (self)),
4769                 object->ref_count);
4770
4771   g_signal_emit (self, actor_signals[DESTROY], 0);
4772
4773   /* avoid recursing when called from clutter_actor_destroy() */
4774   if (priv->parent != NULL)
4775     {
4776       ClutterActor *parent = priv->parent;
4777
4778       /* go through the Container implementation unless this
4779        * is an internal child and has been marked as such.
4780        *
4781        * removing the actor from its parent will reset the
4782        * realized and mapped states.
4783        */
4784       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4785         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4786       else
4787         clutter_actor_remove_child_internal (parent, self,
4788                                              REMOVE_CHILD_LEGACY_FLAGS);
4789     }
4790
4791   /* parent must be gone at this point */
4792   g_assert (priv->parent == NULL);
4793
4794   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4795     {
4796       /* can't be mapped or realized with no parent */
4797       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4798       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4799     }
4800
4801   g_clear_object (&priv->pango_context);
4802   g_clear_object (&priv->actions);
4803   g_clear_object (&priv->constraints);
4804   g_clear_object (&priv->effects);
4805   g_clear_object (&priv->flatten_effect);
4806
4807   if (priv->layout_manager != NULL)
4808     {
4809       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4810       g_object_unref (priv->layout_manager);
4811       priv->layout_manager = NULL;
4812     }
4813
4814   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4815 }
4816
4817 static void
4818 clutter_actor_finalize (GObject *object)
4819 {
4820   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4821
4822   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4823                 priv->name != NULL ? priv->name : "<none>",
4824                 priv->id,
4825                 g_type_name (G_OBJECT_TYPE (object)));
4826
4827   _clutter_context_release_id (priv->id);
4828
4829   g_free (priv->name);
4830
4831   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4832 }
4833
4834
4835 /**
4836  * clutter_actor_get_accessible:
4837  * @self: a #ClutterActor
4838  *
4839  * Returns the accessible object that describes the actor to an
4840  * assistive technology.
4841  *
4842  * If no class-specific #AtkObject implementation is available for the
4843  * actor instance in question, it will inherit an #AtkObject
4844  * implementation from the first ancestor class for which such an
4845  * implementation is defined.
4846  *
4847  * The documentation of the <ulink
4848  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4849  * library contains more information about accessible objects and
4850  * their uses.
4851  *
4852  * Returns: (transfer none): the #AtkObject associated with @actor
4853  */
4854 AtkObject *
4855 clutter_actor_get_accessible (ClutterActor *self)
4856 {
4857   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4858
4859   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4860 }
4861
4862 static AtkObject *
4863 clutter_actor_real_get_accessible (ClutterActor *actor)
4864 {
4865   return atk_gobject_accessible_for_object (G_OBJECT (actor));
4866 }
4867
4868 static AtkObject *
4869 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4870 {
4871   AtkObject *accessible;
4872
4873   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4874   if (accessible != NULL)
4875     g_object_ref (accessible);
4876
4877   return accessible;
4878 }
4879
4880 static void
4881 atk_implementor_iface_init (AtkImplementorIface *iface)
4882 {
4883   iface->ref_accessible = _clutter_actor_ref_accessible;
4884 }
4885
4886 static gboolean
4887 clutter_actor_update_default_paint_volume (ClutterActor       *self,
4888                                            ClutterPaintVolume *volume)
4889 {
4890   ClutterActorPrivate *priv = self->priv;
4891   gboolean res = FALSE;
4892
4893   /* we start from the allocation */
4894   clutter_paint_volume_set_width (volume,
4895                                   priv->allocation.x2 - priv->allocation.x1);
4896   clutter_paint_volume_set_height (volume,
4897                                    priv->allocation.y2 - priv->allocation.y1);
4898
4899   /* if the actor has a clip set then we have a pretty definite
4900    * size for the paint volume: the actor cannot possibly paint
4901    * outside the clip region.
4902    */
4903   if (priv->clip_to_allocation)
4904     {
4905       /* the allocation has already been set, so we just flip the
4906        * return value
4907        */
4908       res = TRUE;
4909     }
4910   else
4911     {
4912       ClutterActor *child;
4913
4914       if (priv->has_clip &&
4915           priv->clip.width >= 0 &&
4916           priv->clip.height >= 0)
4917         {
4918           ClutterVertex origin;
4919
4920           origin.x = priv->clip.x;
4921           origin.y = priv->clip.y;
4922           origin.z = 0;
4923
4924           clutter_paint_volume_set_origin (volume, &origin);
4925           clutter_paint_volume_set_width (volume, priv->clip.width);
4926           clutter_paint_volume_set_height (volume, priv->clip.height);
4927
4928           res = TRUE;
4929         }
4930
4931       /* if we don't have children we just bail out here... */
4932       if (priv->n_children == 0)
4933         return res;
4934
4935       /* ...but if we have children then we ask for their paint volume in
4936        * our coordinates. if any of our children replies that it doesn't
4937        * have a paint volume, we bail out
4938        */
4939       for (child = priv->first_child;
4940            child != NULL;
4941            child = child->priv->next_sibling)
4942         {
4943           const ClutterPaintVolume *child_volume;
4944
4945           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4946           if (child_volume == NULL)
4947             {
4948               res = FALSE;
4949               break;
4950             }
4951
4952           clutter_paint_volume_union (volume, child_volume);
4953           res = TRUE;
4954         }
4955     }
4956
4957   return res;
4958
4959 }
4960
4961 static gboolean
4962 clutter_actor_real_get_paint_volume (ClutterActor       *self,
4963                                      ClutterPaintVolume *volume)
4964 {
4965   ClutterActorClass *klass;
4966   gboolean res;
4967
4968   klass = CLUTTER_ACTOR_GET_CLASS (self);
4969
4970   /* XXX - this thoroughly sucks, but we don't want to penalize users
4971    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
4972    * redraw. This should go away in 2.0.
4973    */
4974   if (klass->paint == clutter_actor_real_paint &&
4975       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
4976     {
4977       res = TRUE;
4978     }
4979   else
4980     {
4981       /* this is the default return value: we cannot know if a class
4982        * is going to paint outside its allocation, so we take the
4983        * conservative approach.
4984        */
4985       res = FALSE;
4986     }
4987
4988   if (clutter_actor_update_default_paint_volume (self, volume))
4989     return res;
4990
4991   return FALSE;
4992 }
4993
4994 /**
4995  * clutter_actor_get_default_paint_volume:
4996  * @self: a #ClutterActor
4997  *
4998  * Retrieves the default paint volume for @self.
4999  *
5000  * This function provides the same #ClutterPaintVolume that would be
5001  * computed by the default implementation inside #ClutterActor of the
5002  * #ClutterActorClass.get_paint_volume() virtual function.
5003  *
5004  * This function should only be used by #ClutterActor subclasses that
5005  * cannot chain up to the parent implementation when computing their
5006  * paint volume.
5007  *
5008  * Return value: (transfer none): a pointer to the default
5009  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5010  *   the actor could not compute a valid paint volume. The returned value
5011  *   is not guaranteed to be stable across multiple frames, so if you
5012  *   want to retain it, you will need to copy it using
5013  *   clutter_paint_volume_copy().
5014  *
5015  * Since: 1.10
5016  */
5017 const ClutterPaintVolume *
5018 clutter_actor_get_default_paint_volume (ClutterActor *self)
5019 {
5020   ClutterPaintVolume volume;
5021   ClutterPaintVolume *res;
5022
5023   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5024
5025   res = NULL;
5026   _clutter_paint_volume_init_static (&volume, self);
5027   if (clutter_actor_update_default_paint_volume (self, &volume))
5028     {
5029       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5030
5031       if (stage != NULL)
5032         {
5033           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5034           _clutter_paint_volume_copy_static (&volume, res);
5035         }
5036     }
5037
5038   clutter_paint_volume_free (&volume);
5039
5040   return res;
5041 }
5042
5043 static gboolean
5044 clutter_actor_real_has_overlaps (ClutterActor *self)
5045 {
5046   /* By default we'll assume that all actors need an offscreen redirect to get
5047    * the correct opacity. Actors such as ClutterTexture that would never need
5048    * an offscreen redirect can override this to return FALSE. */
5049   return TRUE;
5050 }
5051
5052 static void
5053 clutter_actor_real_destroy (ClutterActor *actor)
5054 {
5055   ClutterActorIter iter;
5056
5057   clutter_actor_iter_init (&iter, actor);
5058   while (clutter_actor_iter_next (&iter, NULL))
5059     clutter_actor_iter_destroy (&iter);
5060 }
5061
5062 static GObject *
5063 clutter_actor_constructor (GType gtype,
5064                            guint n_props,
5065                            GObjectConstructParam *props)
5066 {
5067   GObjectClass *gobject_class;
5068   ClutterActor *self;
5069   GObject *retval;
5070
5071   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5072   retval = gobject_class->constructor (gtype, n_props, props);
5073   self = CLUTTER_ACTOR (retval);
5074
5075   if (self->priv->layout_manager == NULL)
5076     {
5077       ClutterLayoutManager *default_layout;
5078
5079       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5080
5081       default_layout = clutter_fixed_layout_new ();
5082       clutter_actor_set_layout_manager (self, default_layout);
5083     }
5084
5085   return retval;
5086 }
5087
5088 static void
5089 clutter_actor_class_init (ClutterActorClass *klass)
5090 {
5091   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5092
5093   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5094   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5095   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5096   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5097
5098   object_class->constructor = clutter_actor_constructor;
5099   object_class->set_property = clutter_actor_set_property;
5100   object_class->get_property = clutter_actor_get_property;
5101   object_class->dispose = clutter_actor_dispose;
5102   object_class->finalize = clutter_actor_finalize;
5103
5104   klass->show = clutter_actor_real_show;
5105   klass->show_all = clutter_actor_show;
5106   klass->hide = clutter_actor_real_hide;
5107   klass->hide_all = clutter_actor_hide;
5108   klass->map = clutter_actor_real_map;
5109   klass->unmap = clutter_actor_real_unmap;
5110   klass->unrealize = clutter_actor_real_unrealize;
5111   klass->pick = clutter_actor_real_pick;
5112   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5113   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5114   klass->allocate = clutter_actor_real_allocate;
5115   klass->queue_redraw = clutter_actor_real_queue_redraw;
5116   klass->queue_relayout = clutter_actor_real_queue_relayout;
5117   klass->apply_transform = clutter_actor_real_apply_transform;
5118   klass->get_accessible = clutter_actor_real_get_accessible;
5119   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5120   klass->has_overlaps = clutter_actor_real_has_overlaps;
5121   klass->paint = clutter_actor_real_paint;
5122   klass->destroy = clutter_actor_real_destroy;
5123
5124   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5125
5126   /**
5127    * ClutterActor:x:
5128    *
5129    * X coordinate of the actor in pixels. If written, forces a fixed
5130    * position for the actor. If read, returns the fixed position if any,
5131    * otherwise the allocation if available, otherwise 0.
5132    *
5133    * The #ClutterActor:x property is animatable.
5134    */
5135   obj_props[PROP_X] =
5136     g_param_spec_float ("x",
5137                         P_("X coordinate"),
5138                         P_("X coordinate of the actor"),
5139                         -G_MAXFLOAT, G_MAXFLOAT,
5140                         0.0,
5141                         G_PARAM_READWRITE |
5142                         G_PARAM_STATIC_STRINGS |
5143                         CLUTTER_PARAM_ANIMATABLE);
5144
5145   /**
5146    * ClutterActor:y:
5147    *
5148    * Y coordinate of the actor in pixels. If written, forces a fixed
5149    * position for the actor.  If read, returns the fixed position if
5150    * any, otherwise the allocation if available, otherwise 0.
5151    *
5152    * The #ClutterActor:y property is animatable.
5153    */
5154   obj_props[PROP_Y] =
5155     g_param_spec_float ("y",
5156                         P_("Y coordinate"),
5157                         P_("Y coordinate of the actor"),
5158                         -G_MAXFLOAT, G_MAXFLOAT,
5159                         0.0,
5160                         G_PARAM_READWRITE |
5161                         G_PARAM_STATIC_STRINGS |
5162                         CLUTTER_PARAM_ANIMATABLE);
5163
5164   /**
5165    * ClutterActor:width:
5166    *
5167    * Width of the actor (in pixels). If written, forces the minimum and
5168    * natural size request of the actor to the given width. If read, returns
5169    * the allocated width if available, otherwise the width request.
5170    *
5171    * The #ClutterActor:width property is animatable.
5172    */
5173   obj_props[PROP_WIDTH] =
5174     g_param_spec_float ("width",
5175                         P_("Width"),
5176                         P_("Width of the actor"),
5177                         0.0, G_MAXFLOAT,
5178                         0.0,
5179                         G_PARAM_READWRITE |
5180                         G_PARAM_STATIC_STRINGS |
5181                         CLUTTER_PARAM_ANIMATABLE);
5182
5183   /**
5184    * ClutterActor:height:
5185    *
5186    * Height of the actor (in pixels).  If written, forces the minimum and
5187    * natural size request of the actor to the given height. If read, returns
5188    * the allocated height if available, otherwise the height request.
5189    *
5190    * The #ClutterActor:height property is animatable.
5191    */
5192   obj_props[PROP_HEIGHT] =
5193     g_param_spec_float ("height",
5194                         P_("Height"),
5195                         P_("Height of the actor"),
5196                         0.0, G_MAXFLOAT,
5197                         0.0,
5198                         G_PARAM_READWRITE |
5199                         G_PARAM_STATIC_STRINGS |
5200                         CLUTTER_PARAM_ANIMATABLE);
5201
5202   /**
5203    * ClutterActor:fixed-x:
5204    *
5205    * The fixed X position of the actor in pixels.
5206    *
5207    * Writing this property sets #ClutterActor:fixed-position-set
5208    * property as well, as a side effect
5209    *
5210    * Since: 0.8
5211    */
5212   obj_props[PROP_FIXED_X] =
5213     g_param_spec_float ("fixed-x",
5214                         P_("Fixed X"),
5215                         P_("Forced X position of the actor"),
5216                         -G_MAXFLOAT, G_MAXFLOAT,
5217                         0.0,
5218                         CLUTTER_PARAM_READWRITE);
5219
5220   /**
5221    * ClutterActor:fixed-y:
5222    *
5223    * The fixed Y position of the actor in pixels.
5224    *
5225    * Writing this property sets the #ClutterActor:fixed-position-set
5226    * property as well, as a side effect
5227    *
5228    * Since: 0.8
5229    */
5230   obj_props[PROP_FIXED_Y] =
5231     g_param_spec_float ("fixed-y",
5232                         P_("Fixed Y"),
5233                         P_("Forced Y position of the actor"),
5234                         -G_MAXFLOAT, G_MAXFLOAT,
5235                         0,
5236                         CLUTTER_PARAM_READWRITE);
5237
5238   /**
5239    * ClutterActor:fixed-position-set:
5240    *
5241    * This flag controls whether the #ClutterActor:fixed-x and
5242    * #ClutterActor:fixed-y properties are used
5243    *
5244    * Since: 0.8
5245    */
5246   obj_props[PROP_FIXED_POSITION_SET] =
5247     g_param_spec_boolean ("fixed-position-set",
5248                           P_("Fixed position set"),
5249                           P_("Whether to use fixed positioning for the actor"),
5250                           FALSE,
5251                           CLUTTER_PARAM_READWRITE);
5252
5253   /**
5254    * ClutterActor:min-width:
5255    *
5256    * A forced minimum width request for the actor, in pixels
5257    *
5258    * Writing this property sets the #ClutterActor:min-width-set property
5259    * as well, as a side effect.
5260    *
5261    *This property overrides the usual width request of the actor.
5262    *
5263    * Since: 0.8
5264    */
5265   obj_props[PROP_MIN_WIDTH] =
5266     g_param_spec_float ("min-width",
5267                         P_("Min Width"),
5268                         P_("Forced minimum width request for the actor"),
5269                         0.0, G_MAXFLOAT,
5270                         0.0,
5271                         CLUTTER_PARAM_READWRITE);
5272
5273   /**
5274    * ClutterActor:min-height:
5275    *
5276    * A forced minimum height request for the actor, in pixels
5277    *
5278    * Writing this property sets the #ClutterActor:min-height-set property
5279    * as well, as a side effect. This property overrides the usual height
5280    * request of the actor.
5281    *
5282    * Since: 0.8
5283    */
5284   obj_props[PROP_MIN_HEIGHT] =
5285     g_param_spec_float ("min-height",
5286                         P_("Min Height"),
5287                         P_("Forced minimum height request for the actor"),
5288                         0.0, G_MAXFLOAT,
5289                         0.0,
5290                         CLUTTER_PARAM_READWRITE);
5291
5292   /**
5293    * ClutterActor:natural-width:
5294    *
5295    * A forced natural width request for the actor, in pixels
5296    *
5297    * Writing this property sets the #ClutterActor:natural-width-set
5298    * property as well, as a side effect. This property overrides the
5299    * usual width request of the actor
5300    *
5301    * Since: 0.8
5302    */
5303   obj_props[PROP_NATURAL_WIDTH] =
5304     g_param_spec_float ("natural-width",
5305                         P_("Natural Width"),
5306                         P_("Forced natural width request for the actor"),
5307                         0.0, G_MAXFLOAT,
5308                         0.0,
5309                         CLUTTER_PARAM_READWRITE);
5310
5311   /**
5312    * ClutterActor:natural-height:
5313    *
5314    * A forced natural height request for the actor, in pixels
5315    *
5316    * Writing this property sets the #ClutterActor:natural-height-set
5317    * property as well, as a side effect. This property overrides the
5318    * usual height request of the actor
5319    *
5320    * Since: 0.8
5321    */
5322   obj_props[PROP_NATURAL_HEIGHT] =
5323     g_param_spec_float ("natural-height",
5324                         P_("Natural Height"),
5325                         P_("Forced natural height request for the actor"),
5326                         0.0, G_MAXFLOAT,
5327                         0.0,
5328                         CLUTTER_PARAM_READWRITE);
5329
5330   /**
5331    * ClutterActor:min-width-set:
5332    *
5333    * This flag controls whether the #ClutterActor:min-width property
5334    * is used
5335    *
5336    * Since: 0.8
5337    */
5338   obj_props[PROP_MIN_WIDTH_SET] =
5339     g_param_spec_boolean ("min-width-set",
5340                           P_("Minimum width set"),
5341                           P_("Whether to use the min-width property"),
5342                           FALSE,
5343                           CLUTTER_PARAM_READWRITE);
5344
5345   /**
5346    * ClutterActor:min-height-set:
5347    *
5348    * This flag controls whether the #ClutterActor:min-height property
5349    * is used
5350    *
5351    * Since: 0.8
5352    */
5353   obj_props[PROP_MIN_HEIGHT_SET] =
5354     g_param_spec_boolean ("min-height-set",
5355                           P_("Minimum height set"),
5356                           P_("Whether to use the min-height property"),
5357                           FALSE,
5358                           CLUTTER_PARAM_READWRITE);
5359
5360   /**
5361    * ClutterActor:natural-width-set:
5362    *
5363    * This flag controls whether the #ClutterActor:natural-width property
5364    * is used
5365    *
5366    * Since: 0.8
5367    */
5368   obj_props[PROP_NATURAL_WIDTH_SET] =
5369     g_param_spec_boolean ("natural-width-set",
5370                           P_("Natural width set"),
5371                           P_("Whether to use the natural-width property"),
5372                           FALSE,
5373                           CLUTTER_PARAM_READWRITE);
5374
5375   /**
5376    * ClutterActor:natural-height-set:
5377    *
5378    * This flag controls whether the #ClutterActor:natural-height property
5379    * is used
5380    *
5381    * Since: 0.8
5382    */
5383   obj_props[PROP_NATURAL_HEIGHT_SET] =
5384     g_param_spec_boolean ("natural-height-set",
5385                           P_("Natural height set"),
5386                           P_("Whether to use the natural-height property"),
5387                           FALSE,
5388                           CLUTTER_PARAM_READWRITE);
5389
5390   /**
5391    * ClutterActor:allocation:
5392    *
5393    * The allocation for the actor, in pixels
5394    *
5395    * This is property is read-only, but you might monitor it to know when an
5396    * actor moves or resizes
5397    *
5398    * Since: 0.8
5399    */
5400   obj_props[PROP_ALLOCATION] =
5401     g_param_spec_boxed ("allocation",
5402                         P_("Allocation"),
5403                         P_("The actor's allocation"),
5404                         CLUTTER_TYPE_ACTOR_BOX,
5405                         CLUTTER_PARAM_READABLE);
5406
5407   /**
5408    * ClutterActor:request-mode:
5409    *
5410    * Request mode for the #ClutterActor. The request mode determines the
5411    * type of geometry management used by the actor, either height for width
5412    * (the default) or width for height.
5413    *
5414    * For actors implementing height for width, the parent container should get
5415    * the preferred width first, and then the preferred height for that width.
5416    *
5417    * For actors implementing width for height, the parent container should get
5418    * the preferred height first, and then the preferred width for that height.
5419    *
5420    * For instance:
5421    *
5422    * |[
5423    *   ClutterRequestMode mode;
5424    *   gfloat natural_width, min_width;
5425    *   gfloat natural_height, min_height;
5426    *
5427    *   mode = clutter_actor_get_request_mode (child);
5428    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5429    *     {
5430    *       clutter_actor_get_preferred_width (child, -1,
5431    *                                          &amp;min_width,
5432    *                                          &amp;natural_width);
5433    *       clutter_actor_get_preferred_height (child, natural_width,
5434    *                                           &amp;min_height,
5435    *                                           &amp;natural_height);
5436    *     }
5437    *   else
5438    *     {
5439    *       clutter_actor_get_preferred_height (child, -1,
5440    *                                           &amp;min_height,
5441    *                                           &amp;natural_height);
5442    *       clutter_actor_get_preferred_width (child, natural_height,
5443    *                                          &amp;min_width,
5444    *                                          &amp;natural_width);
5445    *     }
5446    * ]|
5447    *
5448    * will retrieve the minimum and natural width and height depending on the
5449    * preferred request mode of the #ClutterActor "child".
5450    *
5451    * The clutter_actor_get_preferred_size() function will implement this
5452    * check for you.
5453    *
5454    * Since: 0.8
5455    */
5456   obj_props[PROP_REQUEST_MODE] =
5457     g_param_spec_enum ("request-mode",
5458                        P_("Request Mode"),
5459                        P_("The actor's request mode"),
5460                        CLUTTER_TYPE_REQUEST_MODE,
5461                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5462                        CLUTTER_PARAM_READWRITE);
5463
5464   /**
5465    * ClutterActor:depth:
5466    *
5467    * The position of the actor on the Z axis.
5468    *
5469    * The #ClutterActor:depth property is relative to the parent's
5470    * modelview matrix.
5471    *
5472    * The #ClutterActor:depth property is animatable.
5473    *
5474    * Since: 0.6
5475    */
5476   obj_props[PROP_DEPTH] =
5477     g_param_spec_float ("depth",
5478                         P_("Depth"),
5479                         P_("Position on the Z axis"),
5480                         -G_MAXFLOAT, G_MAXFLOAT,
5481                         0.0,
5482                         G_PARAM_READWRITE |
5483                         G_PARAM_STATIC_STRINGS |
5484                         CLUTTER_PARAM_ANIMATABLE);
5485
5486   /**
5487    * ClutterActor:opacity:
5488    *
5489    * Opacity of an actor, between 0 (fully transparent) and
5490    * 255 (fully opaque)
5491    *
5492    * The #ClutterActor:opacity property is animatable.
5493    */
5494   obj_props[PROP_OPACITY] =
5495     g_param_spec_uint ("opacity",
5496                        P_("Opacity"),
5497                        P_("Opacity of an actor"),
5498                        0, 255,
5499                        255,
5500                        G_PARAM_READWRITE |
5501                        G_PARAM_STATIC_STRINGS |
5502                        CLUTTER_PARAM_ANIMATABLE);
5503
5504   /**
5505    * ClutterActor:offscreen-redirect:
5506    *
5507    * Determines the conditions in which the actor will be redirected
5508    * to an offscreen framebuffer while being painted. For example this
5509    * can be used to cache an actor in a framebuffer or for improved
5510    * handling of transparent actors. See
5511    * clutter_actor_set_offscreen_redirect() for details.
5512    *
5513    * Since: 1.8
5514    */
5515   obj_props[PROP_OFFSCREEN_REDIRECT] =
5516     g_param_spec_flags ("offscreen-redirect",
5517                         P_("Offscreen redirect"),
5518                         P_("Flags controlling when to flatten the actor into a single image"),
5519                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5520                         0,
5521                         CLUTTER_PARAM_READWRITE);
5522
5523   /**
5524    * ClutterActor:visible:
5525    *
5526    * Whether the actor is set to be visible or not
5527    *
5528    * See also #ClutterActor:mapped
5529    */
5530   obj_props[PROP_VISIBLE] =
5531     g_param_spec_boolean ("visible",
5532                           P_("Visible"),
5533                           P_("Whether the actor is visible or not"),
5534                           FALSE,
5535                           CLUTTER_PARAM_READWRITE);
5536
5537   /**
5538    * ClutterActor:mapped:
5539    *
5540    * Whether the actor is mapped (will be painted when the stage
5541    * to which it belongs is mapped)
5542    *
5543    * Since: 1.0
5544    */
5545   obj_props[PROP_MAPPED] =
5546     g_param_spec_boolean ("mapped",
5547                           P_("Mapped"),
5548                           P_("Whether the actor will be painted"),
5549                           FALSE,
5550                           CLUTTER_PARAM_READABLE);
5551
5552   /**
5553    * ClutterActor:realized:
5554    *
5555    * Whether the actor has been realized
5556    *
5557    * Since: 1.0
5558    */
5559   obj_props[PROP_REALIZED] =
5560     g_param_spec_boolean ("realized",
5561                           P_("Realized"),
5562                           P_("Whether the actor has been realized"),
5563                           FALSE,
5564                           CLUTTER_PARAM_READABLE);
5565
5566   /**
5567    * ClutterActor:reactive:
5568    *
5569    * Whether the actor is reactive to events or not
5570    *
5571    * Only reactive actors will emit event-related signals
5572    *
5573    * Since: 0.6
5574    */
5575   obj_props[PROP_REACTIVE] =
5576     g_param_spec_boolean ("reactive",
5577                           P_("Reactive"),
5578                           P_("Whether the actor is reactive to events"),
5579                           FALSE,
5580                           CLUTTER_PARAM_READWRITE);
5581
5582   /**
5583    * ClutterActor:has-clip:
5584    *
5585    * Whether the actor has the #ClutterActor:clip property set or not
5586    */
5587   obj_props[PROP_HAS_CLIP] =
5588     g_param_spec_boolean ("has-clip",
5589                           P_("Has Clip"),
5590                           P_("Whether the actor has a clip set"),
5591                           FALSE,
5592                           CLUTTER_PARAM_READABLE);
5593
5594   /**
5595    * ClutterActor:clip:
5596    *
5597    * The clip region for the actor, in actor-relative coordinates
5598    *
5599    * Every part of the actor outside the clip region will not be
5600    * painted
5601    */
5602   obj_props[PROP_CLIP] =
5603     g_param_spec_boxed ("clip",
5604                         P_("Clip"),
5605                         P_("The clip region for the actor"),
5606                         CLUTTER_TYPE_GEOMETRY,
5607                         CLUTTER_PARAM_READWRITE);
5608
5609   /**
5610    * ClutterActor:name:
5611    *
5612    * The name of the actor
5613    *
5614    * Since: 0.2
5615    */
5616   obj_props[PROP_NAME] =
5617     g_param_spec_string ("name",
5618                          P_("Name"),
5619                          P_("Name of the actor"),
5620                          NULL,
5621                          CLUTTER_PARAM_READWRITE);
5622
5623   /**
5624    * ClutterActor:scale-x:
5625    *
5626    * The horizontal scale of the actor.
5627    *
5628    * The #ClutterActor:scale-x property is animatable.
5629    *
5630    * Since: 0.6
5631    */
5632   obj_props[PROP_SCALE_X] =
5633     g_param_spec_double ("scale-x",
5634                          P_("Scale X"),
5635                          P_("Scale factor on the X axis"),
5636                          0.0, G_MAXDOUBLE,
5637                          1.0,
5638                          G_PARAM_READWRITE |
5639                          G_PARAM_STATIC_STRINGS |
5640                          CLUTTER_PARAM_ANIMATABLE);
5641
5642   /**
5643    * ClutterActor:scale-y:
5644    *
5645    * The vertical scale of the actor.
5646    *
5647    * The #ClutterActor:scale-y property is animatable.
5648    *
5649    * Since: 0.6
5650    */
5651   obj_props[PROP_SCALE_Y] =
5652     g_param_spec_double ("scale-y",
5653                          P_("Scale Y"),
5654                          P_("Scale factor on the Y axis"),
5655                          0.0, G_MAXDOUBLE,
5656                          1.0,
5657                          G_PARAM_READWRITE |
5658                          G_PARAM_STATIC_STRINGS |
5659                          CLUTTER_PARAM_ANIMATABLE);
5660
5661   /**
5662    * ClutterActor:scale-center-x:
5663    *
5664    * The horizontal center point for scaling
5665    *
5666    * Since: 1.0
5667    */
5668   obj_props[PROP_SCALE_CENTER_X] =
5669     g_param_spec_float ("scale-center-x",
5670                         P_("Scale Center X"),
5671                         P_("Horizontal scale center"),
5672                         -G_MAXFLOAT, G_MAXFLOAT,
5673                         0.0,
5674                         CLUTTER_PARAM_READWRITE);
5675
5676   /**
5677    * ClutterActor:scale-center-y:
5678    *
5679    * The vertical center point for scaling
5680    *
5681    * Since: 1.0
5682    */
5683   obj_props[PROP_SCALE_CENTER_Y] =
5684     g_param_spec_float ("scale-center-y",
5685                         P_("Scale Center Y"),
5686                         P_("Vertical scale center"),
5687                         -G_MAXFLOAT, G_MAXFLOAT,
5688                         0.0,
5689                         CLUTTER_PARAM_READWRITE);
5690
5691   /**
5692    * ClutterActor:scale-gravity:
5693    *
5694    * The center point for scaling expressed as a #ClutterGravity
5695    *
5696    * Since: 1.0
5697    */
5698   obj_props[PROP_SCALE_GRAVITY] =
5699     g_param_spec_enum ("scale-gravity",
5700                        P_("Scale Gravity"),
5701                        P_("The center of scaling"),
5702                        CLUTTER_TYPE_GRAVITY,
5703                        CLUTTER_GRAVITY_NONE,
5704                        CLUTTER_PARAM_READWRITE);
5705
5706   /**
5707    * ClutterActor:rotation-angle-x:
5708    *
5709    * The rotation angle on the X axis.
5710    *
5711    * The #ClutterActor:rotation-angle-x property is animatable.
5712    *
5713    * Since: 0.6
5714    */
5715   obj_props[PROP_ROTATION_ANGLE_X] =
5716     g_param_spec_double ("rotation-angle-x",
5717                          P_("Rotation Angle X"),
5718                          P_("The rotation angle on the X axis"),
5719                          -G_MAXDOUBLE, G_MAXDOUBLE,
5720                          0.0,
5721                          G_PARAM_READWRITE |
5722                          G_PARAM_STATIC_STRINGS |
5723                          CLUTTER_PARAM_ANIMATABLE);
5724
5725   /**
5726    * ClutterActor:rotation-angle-y:
5727    *
5728    * The rotation angle on the Y axis
5729    *
5730    * The #ClutterActor:rotation-angle-y property is animatable.
5731    *
5732    * Since: 0.6
5733    */
5734   obj_props[PROP_ROTATION_ANGLE_Y] =
5735     g_param_spec_double ("rotation-angle-y",
5736                          P_("Rotation Angle Y"),
5737                          P_("The rotation angle on the Y axis"),
5738                          -G_MAXDOUBLE, G_MAXDOUBLE,
5739                          0.0,
5740                          G_PARAM_READWRITE |
5741                          G_PARAM_STATIC_STRINGS |
5742                          CLUTTER_PARAM_ANIMATABLE);
5743
5744   /**
5745    * ClutterActor:rotation-angle-z:
5746    *
5747    * The rotation angle on the Z axis
5748    *
5749    * The #ClutterActor:rotation-angle-z property is animatable.
5750    *
5751    * Since: 0.6
5752    */
5753   obj_props[PROP_ROTATION_ANGLE_Z] =
5754     g_param_spec_double ("rotation-angle-z",
5755                          P_("Rotation Angle Z"),
5756                          P_("The rotation angle on the Z axis"),
5757                          -G_MAXDOUBLE, G_MAXDOUBLE,
5758                          0.0,
5759                          G_PARAM_READWRITE |
5760                          G_PARAM_STATIC_STRINGS |
5761                          CLUTTER_PARAM_ANIMATABLE);
5762
5763   /**
5764    * ClutterActor:rotation-center-x:
5765    *
5766    * The rotation center on the X axis.
5767    *
5768    * Since: 0.6
5769    */
5770   obj_props[PROP_ROTATION_CENTER_X] =
5771     g_param_spec_boxed ("rotation-center-x",
5772                         P_("Rotation Center X"),
5773                         P_("The rotation center on the X axis"),
5774                         CLUTTER_TYPE_VERTEX,
5775                         CLUTTER_PARAM_READWRITE);
5776
5777   /**
5778    * ClutterActor:rotation-center-y:
5779    *
5780    * The rotation center on the Y axis.
5781    *
5782    * Since: 0.6
5783    */
5784   obj_props[PROP_ROTATION_CENTER_Y] =
5785     g_param_spec_boxed ("rotation-center-y",
5786                         P_("Rotation Center Y"),
5787                         P_("The rotation center on the Y axis"),
5788                         CLUTTER_TYPE_VERTEX,
5789                         CLUTTER_PARAM_READWRITE);
5790
5791   /**
5792    * ClutterActor:rotation-center-z:
5793    *
5794    * The rotation center on the Z axis.
5795    *
5796    * Since: 0.6
5797    */
5798   obj_props[PROP_ROTATION_CENTER_Z] =
5799     g_param_spec_boxed ("rotation-center-z",
5800                         P_("Rotation Center Z"),
5801                         P_("The rotation center on the Z axis"),
5802                         CLUTTER_TYPE_VERTEX,
5803                         CLUTTER_PARAM_READWRITE);
5804
5805   /**
5806    * ClutterActor:rotation-center-z-gravity:
5807    *
5808    * The rotation center on the Z axis expressed as a #ClutterGravity.
5809    *
5810    * Since: 1.0
5811    */
5812   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5813     g_param_spec_enum ("rotation-center-z-gravity",
5814                        P_("Rotation Center Z Gravity"),
5815                        P_("Center point for rotation around the Z axis"),
5816                        CLUTTER_TYPE_GRAVITY,
5817                        CLUTTER_GRAVITY_NONE,
5818                        CLUTTER_PARAM_READWRITE);
5819
5820   /**
5821    * ClutterActor:anchor-x:
5822    *
5823    * The X coordinate of an actor's anchor point, relative to
5824    * the actor coordinate space, in pixels
5825    *
5826    * Since: 0.8
5827    */
5828   obj_props[PROP_ANCHOR_X] =
5829     g_param_spec_float ("anchor-x",
5830                         P_("Anchor X"),
5831                         P_("X coordinate of the anchor point"),
5832                         -G_MAXFLOAT, G_MAXFLOAT,
5833                         0,
5834                         CLUTTER_PARAM_READWRITE);
5835
5836   /**
5837    * ClutterActor:anchor-y:
5838    *
5839    * The Y coordinate of an actor's anchor point, relative to
5840    * the actor coordinate space, in pixels
5841    *
5842    * Since: 0.8
5843    */
5844   obj_props[PROP_ANCHOR_Y] =
5845     g_param_spec_float ("anchor-y",
5846                         P_("Anchor Y"),
5847                         P_("Y coordinate of the anchor point"),
5848                         -G_MAXFLOAT, G_MAXFLOAT,
5849                         0,
5850                         CLUTTER_PARAM_READWRITE);
5851
5852   /**
5853    * ClutterActor:anchor-gravity:
5854    *
5855    * The anchor point expressed as a #ClutterGravity
5856    *
5857    * Since: 1.0
5858    */
5859   obj_props[PROP_ANCHOR_GRAVITY] =
5860     g_param_spec_enum ("anchor-gravity",
5861                        P_("Anchor Gravity"),
5862                        P_("The anchor point as a ClutterGravity"),
5863                        CLUTTER_TYPE_GRAVITY,
5864                        CLUTTER_GRAVITY_NONE,
5865                        CLUTTER_PARAM_READWRITE);
5866
5867   /**
5868    * ClutterActor:show-on-set-parent:
5869    *
5870    * If %TRUE, the actor is automatically shown when parented.
5871    *
5872    * Calling clutter_actor_hide() on an actor which has not been
5873    * parented will set this property to %FALSE as a side effect.
5874    *
5875    * Since: 0.8
5876    */
5877   obj_props[PROP_SHOW_ON_SET_PARENT] =
5878     g_param_spec_boolean ("show-on-set-parent",
5879                           P_("Show on set parent"),
5880                           P_("Whether the actor is shown when parented"),
5881                           TRUE,
5882                           CLUTTER_PARAM_READWRITE);
5883
5884   /**
5885    * ClutterActor:clip-to-allocation:
5886    *
5887    * Whether the clip region should track the allocated area
5888    * of the actor.
5889    *
5890    * This property is ignored if a clip area has been explicitly
5891    * set using clutter_actor_set_clip().
5892    *
5893    * Since: 1.0
5894    */
5895   obj_props[PROP_CLIP_TO_ALLOCATION] =
5896     g_param_spec_boolean ("clip-to-allocation",
5897                           P_("Clip to Allocation"),
5898                           P_("Sets the clip region to track the actor's allocation"),
5899                           FALSE,
5900                           CLUTTER_PARAM_READWRITE);
5901
5902   /**
5903    * ClutterActor:text-direction:
5904    *
5905    * The direction of the text inside a #ClutterActor.
5906    *
5907    * Since: 1.0
5908    */
5909   obj_props[PROP_TEXT_DIRECTION] =
5910     g_param_spec_enum ("text-direction",
5911                        P_("Text Direction"),
5912                        P_("Direction of the text"),
5913                        CLUTTER_TYPE_TEXT_DIRECTION,
5914                        CLUTTER_TEXT_DIRECTION_LTR,
5915                        CLUTTER_PARAM_READWRITE);
5916
5917   /**
5918    * ClutterActor:has-pointer:
5919    *
5920    * Whether the actor contains the pointer of a #ClutterInputDevice
5921    * or not.
5922    *
5923    * Since: 1.2
5924    */
5925   obj_props[PROP_HAS_POINTER] =
5926     g_param_spec_boolean ("has-pointer",
5927                           P_("Has Pointer"),
5928                           P_("Whether the actor contains the pointer of an input device"),
5929                           FALSE,
5930                           CLUTTER_PARAM_READABLE);
5931
5932   /**
5933    * ClutterActor:actions:
5934    *
5935    * Adds a #ClutterAction to the actor
5936    *
5937    * Since: 1.4
5938    */
5939   obj_props[PROP_ACTIONS] =
5940     g_param_spec_object ("actions",
5941                          P_("Actions"),
5942                          P_("Adds an action to the actor"),
5943                          CLUTTER_TYPE_ACTION,
5944                          CLUTTER_PARAM_WRITABLE);
5945
5946   /**
5947    * ClutterActor:constraints:
5948    *
5949    * Adds a #ClutterConstraint to the actor
5950    *
5951    * Since: 1.4
5952    */
5953   obj_props[PROP_CONSTRAINTS] =
5954     g_param_spec_object ("constraints",
5955                          P_("Constraints"),
5956                          P_("Adds a constraint to the actor"),
5957                          CLUTTER_TYPE_CONSTRAINT,
5958                          CLUTTER_PARAM_WRITABLE);
5959
5960   /**
5961    * ClutterActor:effect:
5962    *
5963    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
5964    *
5965    * Since: 1.4
5966    */
5967   obj_props[PROP_EFFECT] =
5968     g_param_spec_object ("effect",
5969                          P_("Effect"),
5970                          P_("Add an effect to be applied on the actor"),
5971                          CLUTTER_TYPE_EFFECT,
5972                          CLUTTER_PARAM_WRITABLE);
5973
5974   /**
5975    * ClutterActor:layout-manager:
5976    *
5977    * A delegate object for controlling the layout of the children of
5978    * an actor.
5979    *
5980    * Since: 1.10
5981    */
5982   obj_props[PROP_LAYOUT_MANAGER] =
5983     g_param_spec_object ("layout-manager",
5984                          P_("Layout Manager"),
5985                          P_("The object controlling the layout of an actor's children"),
5986                          CLUTTER_TYPE_LAYOUT_MANAGER,
5987                          CLUTTER_PARAM_READWRITE);
5988
5989
5990   /**
5991    * ClutterActor:x-align:
5992    *
5993    * The alignment of an actor on the X axis, if the actor has been given
5994    * extra space for its allocation.
5995    *
5996    * Since: 1.10
5997    */
5998   obj_props[PROP_X_ALIGN] =
5999     g_param_spec_enum ("x-align",
6000                        P_("X Alignment"),
6001                        P_("The alignment of the actor on the X axis within its allocation"),
6002                        CLUTTER_TYPE_ACTOR_ALIGN,
6003                        CLUTTER_ACTOR_ALIGN_FILL,
6004                        CLUTTER_PARAM_READWRITE);
6005
6006   /**
6007    * ClutterActor:y-align:
6008    *
6009    * The alignment of an actor on the Y axis, if the actor has been given
6010    * extra space for its allocation.
6011    *
6012    * Since: 1.10
6013    */
6014   obj_props[PROP_Y_ALIGN] =
6015     g_param_spec_enum ("y-align",
6016                        P_("Y Alignment"),
6017                        P_("The alignment of the actor on the Y axis within its allocation"),
6018                        CLUTTER_TYPE_ACTOR_ALIGN,
6019                        CLUTTER_ACTOR_ALIGN_FILL,
6020                        CLUTTER_PARAM_READWRITE);
6021
6022   /**
6023    * ClutterActor:margin-top:
6024    *
6025    * The margin (in pixels) from the top of the actor.
6026    *
6027    * This property adds a margin to the actor's preferred size; the margin
6028    * will be automatically taken into account when allocating the actor.
6029    *
6030    * Since: 1.10
6031    */
6032   obj_props[PROP_MARGIN_TOP] =
6033     g_param_spec_float ("margin-top",
6034                         P_("Margin Top"),
6035                         P_("Extra space at the top"),
6036                         0.0, G_MAXFLOAT,
6037                         0.0,
6038                         CLUTTER_PARAM_READWRITE);
6039
6040   /**
6041    * ClutterActor:margin-bottom:
6042    *
6043    * The margin (in pixels) from the bottom of the actor.
6044    *
6045    * This property adds a margin to the actor's preferred size; the margin
6046    * will be automatically taken into account when allocating the actor.
6047    *
6048    * Since: 1.10
6049    */
6050   obj_props[PROP_MARGIN_BOTTOM] =
6051     g_param_spec_float ("margin-bottom",
6052                         P_("Margin Bottom"),
6053                         P_("Extra space at the bottom"),
6054                         0.0, G_MAXFLOAT,
6055                         0.0,
6056                         CLUTTER_PARAM_READWRITE);
6057
6058   /**
6059    * ClutterActor:margin-left:
6060    *
6061    * The margin (in pixels) from the left of the actor.
6062    *
6063    * This property adds a margin to the actor's preferred size; the margin
6064    * will be automatically taken into account when allocating the actor.
6065    *
6066    * Since: 1.10
6067    */
6068   obj_props[PROP_MARGIN_LEFT] =
6069     g_param_spec_float ("margin-left",
6070                         P_("Margin Left"),
6071                         P_("Extra space at the left"),
6072                         0.0, G_MAXFLOAT,
6073                         0.0,
6074                         CLUTTER_PARAM_READWRITE);
6075
6076   /**
6077    * ClutterActor:margin-right:
6078    *
6079    * The margin (in pixels) from the right of the actor.
6080    *
6081    * This property adds a margin to the actor's preferred size; the margin
6082    * will be automatically taken into account when allocating the actor.
6083    *
6084    * Since: 1.10
6085    */
6086   obj_props[PROP_MARGIN_RIGHT] =
6087     g_param_spec_float ("margin-right",
6088                         P_("Margin Right"),
6089                         P_("Extra space at the right"),
6090                         0.0, G_MAXFLOAT,
6091                         0.0,
6092                         CLUTTER_PARAM_READWRITE);
6093
6094   /**
6095    * ClutterActor:background-color-set:
6096    *
6097    * Whether the #ClutterActor:background-color property has been set.
6098    *
6099    * Since: 1.10
6100    */
6101   obj_props[PROP_BACKGROUND_COLOR_SET] =
6102     g_param_spec_boolean ("background-color-set",
6103                           P_("Background Color Set"),
6104                           P_("Whether the background color is set"),
6105                           FALSE,
6106                           CLUTTER_PARAM_READABLE);
6107
6108   /**
6109    * ClutterActor:background-color:
6110    *
6111    * Paints a solid fill of the actor's allocation using the specified
6112    * color.
6113    *
6114    * The #ClutterActor:background-color property is animatable.
6115    *
6116    * Since: 1.10
6117    */
6118   obj_props[PROP_BACKGROUND_COLOR] =
6119     clutter_param_spec_color ("background-color",
6120                               P_("Background color"),
6121                               P_("The actor's background color"),
6122                               CLUTTER_COLOR_Transparent,
6123                               G_PARAM_READWRITE |
6124                               G_PARAM_STATIC_STRINGS |
6125                               CLUTTER_PARAM_ANIMATABLE);
6126
6127   /**
6128    * ClutterActor:first-child:
6129    *
6130    * The actor's first child.
6131    *
6132    * Since: 1.10
6133    */
6134   obj_props[PROP_FIRST_CHILD] =
6135     g_param_spec_object ("first-child",
6136                          P_("First Child"),
6137                          P_("The actor's first child"),
6138                          CLUTTER_TYPE_ACTOR,
6139                          CLUTTER_PARAM_READABLE);
6140
6141   /**
6142    * ClutterActor:last-child:
6143    *
6144    * The actor's last child.
6145    *
6146    * Since: 1.10
6147    */
6148   obj_props[PROP_LAST_CHILD] =
6149     g_param_spec_object ("last-child",
6150                          P_("Last Child"),
6151                          P_("The actor's last child"),
6152                          CLUTTER_TYPE_ACTOR,
6153                          CLUTTER_PARAM_READABLE);
6154
6155   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6156
6157   /**
6158    * ClutterActor::destroy:
6159    * @actor: the #ClutterActor which emitted the signal
6160    *
6161    * The ::destroy signal notifies that all references held on the
6162    * actor which emitted it should be released.
6163    *
6164    * The ::destroy signal should be used by all holders of a reference
6165    * on @actor.
6166    *
6167    * This signal might result in the finalization of the #ClutterActor
6168    * if all references are released.
6169    *
6170    * Composite actors and actors implementing the #ClutterContainer
6171    * interface should override the default implementation of the
6172    * class handler of this signal and call clutter_actor_destroy() on
6173    * their children. When overriding the default class handler, it is
6174    * required to chain up to the parent's implementation.
6175    *
6176    * Since: 0.2
6177    */
6178   actor_signals[DESTROY] =
6179     g_signal_new (I_("destroy"),
6180                   G_TYPE_FROM_CLASS (object_class),
6181                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6182                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6183                   NULL, NULL,
6184                   _clutter_marshal_VOID__VOID,
6185                   G_TYPE_NONE, 0);
6186   /**
6187    * ClutterActor::show:
6188    * @actor: the object which received the signal
6189    *
6190    * The ::show signal is emitted when an actor is visible and
6191    * rendered on the stage.
6192    *
6193    * Since: 0.2
6194    */
6195   actor_signals[SHOW] =
6196     g_signal_new (I_("show"),
6197                   G_TYPE_FROM_CLASS (object_class),
6198                   G_SIGNAL_RUN_FIRST,
6199                   G_STRUCT_OFFSET (ClutterActorClass, show),
6200                   NULL, NULL,
6201                   _clutter_marshal_VOID__VOID,
6202                   G_TYPE_NONE, 0);
6203   /**
6204    * ClutterActor::hide:
6205    * @actor: the object which received the signal
6206    *
6207    * The ::hide signal is emitted when an actor is no longer rendered
6208    * on the stage.
6209    *
6210    * Since: 0.2
6211    */
6212   actor_signals[HIDE] =
6213     g_signal_new (I_("hide"),
6214                   G_TYPE_FROM_CLASS (object_class),
6215                   G_SIGNAL_RUN_FIRST,
6216                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6217                   NULL, NULL,
6218                   _clutter_marshal_VOID__VOID,
6219                   G_TYPE_NONE, 0);
6220   /**
6221    * ClutterActor::parent-set:
6222    * @actor: the object which received the signal
6223    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6224    *
6225    * This signal is emitted when the parent of the actor changes.
6226    *
6227    * Since: 0.2
6228    */
6229   actor_signals[PARENT_SET] =
6230     g_signal_new (I_("parent-set"),
6231                   G_TYPE_FROM_CLASS (object_class),
6232                   G_SIGNAL_RUN_LAST,
6233                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6234                   NULL, NULL,
6235                   _clutter_marshal_VOID__OBJECT,
6236                   G_TYPE_NONE, 1,
6237                   CLUTTER_TYPE_ACTOR);
6238
6239   /**
6240    * ClutterActor::queue-redraw:
6241    * @actor: the actor we're bubbling the redraw request through
6242    * @origin: the actor which initiated the redraw request
6243    *
6244    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6245    * is called on @origin.
6246    *
6247    * The default implementation for #ClutterActor chains up to the
6248    * parent actor and queues a redraw on the parent, thus "bubbling"
6249    * the redraw queue up through the actor graph. The default
6250    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6251    * in a main loop idle handler.
6252    *
6253    * Note that the @origin actor may be the stage, or a container; it
6254    * does not have to be a leaf node in the actor graph.
6255    *
6256    * Toolkits embedding a #ClutterStage which require a redraw and
6257    * relayout cycle can stop the emission of this signal using the
6258    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6259    * themselves, like:
6260    *
6261    * |[
6262    *   static void
6263    *   on_redraw_complete (gpointer data)
6264    *   {
6265    *     ClutterStage *stage = data;
6266    *
6267    *     /&ast; execute the Clutter drawing pipeline &ast;/
6268    *     clutter_stage_ensure_redraw (stage);
6269    *   }
6270    *
6271    *   static void
6272    *   on_stage_queue_redraw (ClutterStage *stage)
6273    *   {
6274    *     /&ast; this prevents the default handler to run &ast;/
6275    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6276    *
6277    *     /&ast; queue a redraw with the host toolkit and call
6278    *      &ast; a function when the redraw has been completed
6279    *      &ast;/
6280    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6281    *   }
6282    * ]|
6283    *
6284    * <note><para>This signal is emitted before the Clutter paint
6285    * pipeline is executed. If you want to know when the pipeline has
6286    * been completed you should connect to the ::paint signal on the
6287    * Stage with g_signal_connect_after().</para></note>
6288    *
6289    * Since: 1.0
6290    */
6291   actor_signals[QUEUE_REDRAW] =
6292     g_signal_new (I_("queue-redraw"),
6293                   G_TYPE_FROM_CLASS (object_class),
6294                   G_SIGNAL_RUN_LAST |
6295                   G_SIGNAL_NO_HOOKS,
6296                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6297                   NULL, NULL,
6298                   _clutter_marshal_VOID__OBJECT,
6299                   G_TYPE_NONE, 1,
6300                   CLUTTER_TYPE_ACTOR);
6301
6302   /**
6303    * ClutterActor::queue-relayout
6304    * @actor: the actor being queued for relayout
6305    *
6306    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6307    * is called on an actor.
6308    *
6309    * The default implementation for #ClutterActor chains up to the
6310    * parent actor and queues a relayout on the parent, thus "bubbling"
6311    * the relayout queue up through the actor graph.
6312    *
6313    * The main purpose of this signal is to allow relayout to be propagated
6314    * properly in the procense of #ClutterClone actors. Applications will
6315    * not normally need to connect to this signal.
6316    *
6317    * Since: 1.2
6318    */
6319   actor_signals[QUEUE_RELAYOUT] =
6320     g_signal_new (I_("queue-relayout"),
6321                   G_TYPE_FROM_CLASS (object_class),
6322                   G_SIGNAL_RUN_LAST |
6323                   G_SIGNAL_NO_HOOKS,
6324                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6325                   NULL, NULL,
6326                   _clutter_marshal_VOID__VOID,
6327                   G_TYPE_NONE, 0);
6328
6329   /**
6330    * ClutterActor::event:
6331    * @actor: the actor which received the event
6332    * @event: a #ClutterEvent
6333    *
6334    * The ::event signal is emitted each time an event is received
6335    * by the @actor. This signal will be emitted on every actor,
6336    * following the hierarchy chain, until it reaches the top-level
6337    * container (the #ClutterStage).
6338    *
6339    * Return value: %TRUE if the event has been handled by the actor,
6340    *   or %FALSE to continue the emission.
6341    *
6342    * Since: 0.6
6343    */
6344   actor_signals[EVENT] =
6345     g_signal_new (I_("event"),
6346                   G_TYPE_FROM_CLASS (object_class),
6347                   G_SIGNAL_RUN_LAST,
6348                   G_STRUCT_OFFSET (ClutterActorClass, event),
6349                   _clutter_boolean_handled_accumulator, NULL,
6350                   _clutter_marshal_BOOLEAN__BOXED,
6351                   G_TYPE_BOOLEAN, 1,
6352                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6353   /**
6354    * ClutterActor::button-press-event:
6355    * @actor: the actor which received the event
6356    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6357    *
6358    * The ::button-press-event signal is emitted each time a mouse button
6359    * is pressed on @actor.
6360    *
6361    * Return value: %TRUE if the event has been handled by the actor,
6362    *   or %FALSE to continue the emission.
6363    *
6364    * Since: 0.6
6365    */
6366   actor_signals[BUTTON_PRESS_EVENT] =
6367     g_signal_new (I_("button-press-event"),
6368                   G_TYPE_FROM_CLASS (object_class),
6369                   G_SIGNAL_RUN_LAST,
6370                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6371                   _clutter_boolean_handled_accumulator, NULL,
6372                   _clutter_marshal_BOOLEAN__BOXED,
6373                   G_TYPE_BOOLEAN, 1,
6374                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6375   /**
6376    * ClutterActor::button-release-event:
6377    * @actor: the actor which received the event
6378    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6379    *
6380    * The ::button-release-event signal is emitted each time a mouse button
6381    * is released on @actor.
6382    *
6383    * Return value: %TRUE if the event has been handled by the actor,
6384    *   or %FALSE to continue the emission.
6385    *
6386    * Since: 0.6
6387    */
6388   actor_signals[BUTTON_RELEASE_EVENT] =
6389     g_signal_new (I_("button-release-event"),
6390                   G_TYPE_FROM_CLASS (object_class),
6391                   G_SIGNAL_RUN_LAST,
6392                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6393                   _clutter_boolean_handled_accumulator, NULL,
6394                   _clutter_marshal_BOOLEAN__BOXED,
6395                   G_TYPE_BOOLEAN, 1,
6396                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6397   /**
6398    * ClutterActor::scroll-event:
6399    * @actor: the actor which received the event
6400    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6401    *
6402    * The ::scroll-event signal is emitted each time the mouse is
6403    * scrolled on @actor
6404    *
6405    * Return value: %TRUE if the event has been handled by the actor,
6406    *   or %FALSE to continue the emission.
6407    *
6408    * Since: 0.6
6409    */
6410   actor_signals[SCROLL_EVENT] =
6411     g_signal_new (I_("scroll-event"),
6412                   G_TYPE_FROM_CLASS (object_class),
6413                   G_SIGNAL_RUN_LAST,
6414                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6415                   _clutter_boolean_handled_accumulator, NULL,
6416                   _clutter_marshal_BOOLEAN__BOXED,
6417                   G_TYPE_BOOLEAN, 1,
6418                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6419   /**
6420    * ClutterActor::key-press-event:
6421    * @actor: the actor which received the event
6422    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6423    *
6424    * The ::key-press-event signal is emitted each time a keyboard button
6425    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6426    *
6427    * Return value: %TRUE if the event has been handled by the actor,
6428    *   or %FALSE to continue the emission.
6429    *
6430    * Since: 0.6
6431    */
6432   actor_signals[KEY_PRESS_EVENT] =
6433     g_signal_new (I_("key-press-event"),
6434                   G_TYPE_FROM_CLASS (object_class),
6435                   G_SIGNAL_RUN_LAST,
6436                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6437                   _clutter_boolean_handled_accumulator, NULL,
6438                   _clutter_marshal_BOOLEAN__BOXED,
6439                   G_TYPE_BOOLEAN, 1,
6440                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6441   /**
6442    * ClutterActor::key-release-event:
6443    * @actor: the actor which received the event
6444    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6445    *
6446    * The ::key-release-event signal is emitted each time a keyboard button
6447    * is released while @actor has key focus (see
6448    * clutter_stage_set_key_focus()).
6449    *
6450    * Return value: %TRUE if the event has been handled by the actor,
6451    *   or %FALSE to continue the emission.
6452    *
6453    * Since: 0.6
6454    */
6455   actor_signals[KEY_RELEASE_EVENT] =
6456     g_signal_new (I_("key-release-event"),
6457                   G_TYPE_FROM_CLASS (object_class),
6458                   G_SIGNAL_RUN_LAST,
6459                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6460                   _clutter_boolean_handled_accumulator, NULL,
6461                   _clutter_marshal_BOOLEAN__BOXED,
6462                   G_TYPE_BOOLEAN, 1,
6463                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6464   /**
6465    * ClutterActor::motion-event:
6466    * @actor: the actor which received the event
6467    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6468    *
6469    * The ::motion-event signal is emitted each time the mouse pointer is
6470    * moved over @actor.
6471    *
6472    * Return value: %TRUE if the event has been handled by the actor,
6473    *   or %FALSE to continue the emission.
6474    *
6475    * Since: 0.6
6476    */
6477   actor_signals[MOTION_EVENT] =
6478     g_signal_new (I_("motion-event"),
6479                   G_TYPE_FROM_CLASS (object_class),
6480                   G_SIGNAL_RUN_LAST,
6481                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6482                   _clutter_boolean_handled_accumulator, NULL,
6483                   _clutter_marshal_BOOLEAN__BOXED,
6484                   G_TYPE_BOOLEAN, 1,
6485                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6486
6487   /**
6488    * ClutterActor::key-focus-in:
6489    * @actor: the actor which now has key focus
6490    *
6491    * The ::key-focus-in signal is emitted when @actor receives key focus.
6492    *
6493    * Since: 0.6
6494    */
6495   actor_signals[KEY_FOCUS_IN] =
6496     g_signal_new (I_("key-focus-in"),
6497                   G_TYPE_FROM_CLASS (object_class),
6498                   G_SIGNAL_RUN_LAST,
6499                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6500                   NULL, NULL,
6501                   _clutter_marshal_VOID__VOID,
6502                   G_TYPE_NONE, 0);
6503
6504   /**
6505    * ClutterActor::key-focus-out:
6506    * @actor: the actor which now has key focus
6507    *
6508    * The ::key-focus-out signal is emitted when @actor loses key focus.
6509    *
6510    * Since: 0.6
6511    */
6512   actor_signals[KEY_FOCUS_OUT] =
6513     g_signal_new (I_("key-focus-out"),
6514                   G_TYPE_FROM_CLASS (object_class),
6515                   G_SIGNAL_RUN_LAST,
6516                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6517                   NULL, NULL,
6518                   _clutter_marshal_VOID__VOID,
6519                   G_TYPE_NONE, 0);
6520
6521   /**
6522    * ClutterActor::enter-event:
6523    * @actor: the actor which the pointer has entered.
6524    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6525    *
6526    * The ::enter-event signal is emitted when the pointer enters the @actor
6527    *
6528    * Return value: %TRUE if the event has been handled by the actor,
6529    *   or %FALSE to continue the emission.
6530    *
6531    * Since: 0.6
6532    */
6533   actor_signals[ENTER_EVENT] =
6534     g_signal_new (I_("enter-event"),
6535                   G_TYPE_FROM_CLASS (object_class),
6536                   G_SIGNAL_RUN_LAST,
6537                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6538                   _clutter_boolean_handled_accumulator, NULL,
6539                   _clutter_marshal_BOOLEAN__BOXED,
6540                   G_TYPE_BOOLEAN, 1,
6541                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6542
6543   /**
6544    * ClutterActor::leave-event:
6545    * @actor: the actor which the pointer has left
6546    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6547    *
6548    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6549    *
6550    * Return value: %TRUE if the event has been handled by the actor,
6551    *   or %FALSE to continue the emission.
6552    *
6553    * Since: 0.6
6554    */
6555   actor_signals[LEAVE_EVENT] =
6556     g_signal_new (I_("leave-event"),
6557                   G_TYPE_FROM_CLASS (object_class),
6558                   G_SIGNAL_RUN_LAST,
6559                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6560                   _clutter_boolean_handled_accumulator, NULL,
6561                   _clutter_marshal_BOOLEAN__BOXED,
6562                   G_TYPE_BOOLEAN, 1,
6563                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6564
6565   /**
6566    * ClutterActor::captured-event:
6567    * @actor: the actor which received the signal
6568    * @event: a #ClutterEvent
6569    *
6570    * The ::captured-event signal is emitted when an event is captured
6571    * by Clutter. This signal will be emitted starting from the top-level
6572    * container (the #ClutterStage) to the actor which received the event
6573    * going down the hierarchy. This signal can be used to intercept every
6574    * event before the specialized events (like
6575    * ClutterActor::button-press-event or ::key-released-event) are
6576    * emitted.
6577    *
6578    * Return value: %TRUE if the event has been handled by the actor,
6579    *   or %FALSE to continue the emission.
6580    *
6581    * Since: 0.6
6582    */
6583   actor_signals[CAPTURED_EVENT] =
6584     g_signal_new (I_("captured-event"),
6585                   G_TYPE_FROM_CLASS (object_class),
6586                   G_SIGNAL_RUN_LAST,
6587                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6588                   _clutter_boolean_handled_accumulator, NULL,
6589                   _clutter_marshal_BOOLEAN__BOXED,
6590                   G_TYPE_BOOLEAN, 1,
6591                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6592
6593   /**
6594    * ClutterActor::paint:
6595    * @actor: the #ClutterActor that received the signal
6596    *
6597    * The ::paint signal is emitted each time an actor is being painted.
6598    *
6599    * Subclasses of #ClutterActor should override the class signal handler
6600    * and paint themselves in that function.
6601    *
6602    * It is possible to connect a handler to the ::paint signal in order
6603    * to set up some custom aspect of a paint.
6604    *
6605    * Since: 0.8
6606    */
6607   actor_signals[PAINT] =
6608     g_signal_new (I_("paint"),
6609                   G_TYPE_FROM_CLASS (object_class),
6610                   G_SIGNAL_RUN_LAST |
6611                   G_SIGNAL_NO_HOOKS,
6612                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6613                   NULL, NULL,
6614                   _clutter_marshal_VOID__VOID,
6615                   G_TYPE_NONE, 0);
6616   /**
6617    * ClutterActor::realize:
6618    * @actor: the #ClutterActor that received the signal
6619    *
6620    * The ::realize signal is emitted each time an actor is being
6621    * realized.
6622    *
6623    * Since: 0.8
6624    */
6625   actor_signals[REALIZE] =
6626     g_signal_new (I_("realize"),
6627                   G_TYPE_FROM_CLASS (object_class),
6628                   G_SIGNAL_RUN_LAST,
6629                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6630                   NULL, NULL,
6631                   _clutter_marshal_VOID__VOID,
6632                   G_TYPE_NONE, 0);
6633   /**
6634    * ClutterActor::unrealize:
6635    * @actor: the #ClutterActor that received the signal
6636    *
6637    * The ::unrealize signal is emitted each time an actor is being
6638    * unrealized.
6639    *
6640    * Since: 0.8
6641    */
6642   actor_signals[UNREALIZE] =
6643     g_signal_new (I_("unrealize"),
6644                   G_TYPE_FROM_CLASS (object_class),
6645                   G_SIGNAL_RUN_LAST,
6646                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6647                   NULL, NULL,
6648                   _clutter_marshal_VOID__VOID,
6649                   G_TYPE_NONE, 0);
6650
6651   /**
6652    * ClutterActor::pick:
6653    * @actor: the #ClutterActor that received the signal
6654    * @color: the #ClutterColor to be used when picking
6655    *
6656    * The ::pick signal is emitted each time an actor is being painted
6657    * in "pick mode". The pick mode is used to identify the actor during
6658    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6659    * The actor should paint its shape using the passed @pick_color.
6660    *
6661    * Subclasses of #ClutterActor should override the class signal handler
6662    * and paint themselves in that function.
6663    *
6664    * It is possible to connect a handler to the ::pick signal in order
6665    * to set up some custom aspect of a paint in pick mode.
6666    *
6667    * Since: 1.0
6668    */
6669   actor_signals[PICK] =
6670     g_signal_new (I_("pick"),
6671                   G_TYPE_FROM_CLASS (object_class),
6672                   G_SIGNAL_RUN_LAST,
6673                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6674                   NULL, NULL,
6675                   _clutter_marshal_VOID__BOXED,
6676                   G_TYPE_NONE, 1,
6677                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6678
6679   /**
6680    * ClutterActor::allocation-changed:
6681    * @actor: the #ClutterActor that emitted the signal
6682    * @box: a #ClutterActorBox with the new allocation
6683    * @flags: #ClutterAllocationFlags for the allocation
6684    *
6685    * The ::allocation-changed signal is emitted when the
6686    * #ClutterActor:allocation property changes. Usually, application
6687    * code should just use the notifications for the :allocation property
6688    * but if you want to track the allocation flags as well, for instance
6689    * to know whether the absolute origin of @actor changed, then you might
6690    * want use this signal instead.
6691    *
6692    * Since: 1.0
6693    */
6694   actor_signals[ALLOCATION_CHANGED] =
6695     g_signal_new (I_("allocation-changed"),
6696                   G_TYPE_FROM_CLASS (object_class),
6697                   G_SIGNAL_RUN_LAST,
6698                   0,
6699                   NULL, NULL,
6700                   _clutter_marshal_VOID__BOXED_FLAGS,
6701                   G_TYPE_NONE, 2,
6702                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6703                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6704 }
6705
6706 static void
6707 clutter_actor_init (ClutterActor *self)
6708 {
6709   ClutterActorPrivate *priv;
6710
6711   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6712
6713   priv->id = _clutter_context_acquire_id (self);
6714   priv->pick_id = -1;
6715
6716   priv->opacity = 0xff;
6717   priv->show_on_set_parent = TRUE;
6718
6719   priv->needs_width_request = TRUE;
6720   priv->needs_height_request = TRUE;
6721   priv->needs_allocation = TRUE;
6722
6723   priv->cached_width_age = 1;
6724   priv->cached_height_age = 1;
6725
6726   priv->opacity_override = -1;
6727   priv->enable_model_view_transform = TRUE;
6728
6729   /* Initialize an empty paint volume to start with */
6730   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6731   priv->last_paint_volume_valid = TRUE;
6732
6733   priv->transform_valid = FALSE;
6734 }
6735
6736 /**
6737  * clutter_actor_new:
6738  *
6739  * Creates a new #ClutterActor.
6740  *
6741  * A newly created actor has a floating reference, which will be sunk
6742  * when it is added to another actor.
6743  *
6744  * Return value: (transfer full): the newly created #ClutterActor
6745  *
6746  * Since: 1.10
6747  */
6748 ClutterActor *
6749 clutter_actor_new (void)
6750 {
6751   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6752 }
6753
6754 /**
6755  * clutter_actor_destroy:
6756  * @self: a #ClutterActor
6757  *
6758  * Destroys an actor.  When an actor is destroyed, it will break any
6759  * references it holds to other objects.  If the actor is inside a
6760  * container, the actor will be removed.
6761  *
6762  * When you destroy a container, its children will be destroyed as well.
6763  *
6764  * Note: you cannot destroy the #ClutterStage returned by
6765  * clutter_stage_get_default().
6766  */
6767 void
6768 clutter_actor_destroy (ClutterActor *self)
6769 {
6770   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6771
6772   g_object_ref (self);
6773
6774   /* avoid recursion while destroying */
6775   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6776     {
6777       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6778
6779       g_object_run_dispose (G_OBJECT (self));
6780
6781       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6782     }
6783
6784   g_object_unref (self);
6785 }
6786
6787 void
6788 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6789                                     ClutterPaintVolume *clip)
6790 {
6791   ClutterActorPrivate *priv = self->priv;
6792   ClutterPaintVolume *pv;
6793   gboolean clipped;
6794
6795   /* Remove queue entry early in the process, otherwise a new
6796      queue_redraw() during signal handling could put back this
6797      object in the stage redraw list (but the entry is freed as
6798      soon as we return from this function, causing a segfault
6799      later)
6800   */
6801   priv->queue_redraw_entry = NULL;
6802
6803   /* If we've been explicitly passed a clip volume then there's
6804    * nothing more to calculate, but otherwise the only thing we know
6805    * is that the change is constrained to the given actor.
6806    *
6807    * The idea is that if we know the paint volume for where the actor
6808    * was last drawn (in eye coordinates) and we also have the paint
6809    * volume for where it will be drawn next (in actor coordinates)
6810    * then if we queue a redraw for both these volumes that will cover
6811    * everything that needs to be redrawn to clear the old view and
6812    * show the latest view of the actor.
6813    *
6814    * Don't clip this redraw if we don't know what position we had for
6815    * the previous redraw since we don't know where to set the clip so
6816    * it will clear the actor as it is currently.
6817    */
6818   if (clip)
6819     {
6820       _clutter_actor_set_queue_redraw_clip (self, clip);
6821       clipped = TRUE;
6822     }
6823   else if (G_LIKELY (priv->last_paint_volume_valid))
6824     {
6825       pv = _clutter_actor_get_paint_volume_mutable (self);
6826       if (pv)
6827         {
6828           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6829
6830           /* make sure we redraw the actors old position... */
6831           _clutter_actor_set_queue_redraw_clip (stage,
6832                                                 &priv->last_paint_volume);
6833           _clutter_actor_signal_queue_redraw (stage, stage);
6834           _clutter_actor_set_queue_redraw_clip (stage, NULL);
6835
6836           /* XXX: Ideally the redraw signal would take a clip volume
6837            * argument, but that would be an ABI break. Until we can
6838            * break the ABI we pass the argument out-of-band
6839            */
6840
6841           /* setup the clip for the actors new position... */
6842           _clutter_actor_set_queue_redraw_clip (self, pv);
6843           clipped = TRUE;
6844         }
6845       else
6846         clipped = FALSE;
6847     }
6848   else
6849     clipped = FALSE;
6850
6851   _clutter_actor_signal_queue_redraw (self, self);
6852
6853   /* Just in case anyone is manually firing redraw signals without
6854    * using the public queue_redraw() API we are careful to ensure that
6855    * our out-of-band clip member is cleared before returning...
6856    *
6857    * Note: A NULL clip denotes a full-stage, un-clipped redraw
6858    */
6859   if (G_LIKELY (clipped))
6860     _clutter_actor_set_queue_redraw_clip (self, NULL);
6861 }
6862
6863 static void
6864 _clutter_actor_get_allocation_clip (ClutterActor *self,
6865                                     ClutterActorBox *clip)
6866 {
6867   ClutterActorBox allocation;
6868
6869   /* XXX: we don't care if we get an out of date allocation here
6870    * because clutter_actor_queue_redraw_with_clip knows to ignore
6871    * the clip if the actor's allocation is invalid.
6872    *
6873    * This is noted because clutter_actor_get_allocation_box does some
6874    * unnecessary work to support buggy code with a comment suggesting
6875    * that it could be changed later which would be good for this use
6876    * case!
6877    */
6878   clutter_actor_get_allocation_box (self, &allocation);
6879
6880   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6881    * actor's own coordinate space but the allocation is in parent
6882    * coordinates */
6883   clip->x1 = 0;
6884   clip->y1 = 0;
6885   clip->x2 = allocation.x2 - allocation.x1;
6886   clip->y2 = allocation.y2 - allocation.y1;
6887 }
6888
6889 void
6890 _clutter_actor_queue_redraw_full (ClutterActor       *self,
6891                                   ClutterRedrawFlags  flags,
6892                                   ClutterPaintVolume *volume,
6893                                   ClutterEffect      *effect)
6894 {
6895   ClutterActorPrivate *priv = self->priv;
6896   ClutterPaintVolume allocation_pv;
6897   ClutterPaintVolume *pv;
6898   gboolean should_free_pv;
6899   ClutterActor *stage;
6900
6901   /* Here's an outline of the actor queue redraw mechanism:
6902    *
6903    * The process starts in one of the following two functions which
6904    * are wrappers for this function:
6905    * clutter_actor_queue_redraw
6906    * _clutter_actor_queue_redraw_with_clip
6907    *
6908    * additionally, an effect can queue a redraw by wrapping this
6909    * function in clutter_effect_queue_rerun
6910    *
6911    * This functions queues an entry in a list associated with the
6912    * stage which is a list of actors that queued a redraw while
6913    * updating the timelines, performing layouting and processing other
6914    * mainloop sources before the next paint starts.
6915    *
6916    * We aim to minimize the processing done at this point because
6917    * there is a good chance other events will happen while updating
6918    * the scenegraph that would invalidate any expensive work we might
6919    * otherwise try to do here. For example we don't try and resolve
6920    * the screen space bounding box of an actor at this stage so as to
6921    * minimize how much of the screen redraw because it's possible
6922    * something else will happen which will force a full redraw anyway.
6923    *
6924    * When all updates are complete and we come to paint the stage then
6925    * we iterate this list and actually emit the "queue-redraw" signals
6926    * for each of the listed actors which will bubble up to the stage
6927    * for each actor and at that point we will transform the actors
6928    * paint volume into screen coordinates to determine the clip region
6929    * for what needs to be redrawn in the next paint.
6930    *
6931    * Besides minimizing redundant work another reason for this
6932    * deferred design is that it's more likely we will be able to
6933    * determine the paint volume of an actor once we've finished
6934    * updating the scenegraph because its allocation should be up to
6935    * date. NB: If we can't determine an actors paint volume then we
6936    * can't automatically queue a clipped redraw which can make a big
6937    * difference to performance.
6938    *
6939    * So the control flow goes like this:
6940    * One of clutter_actor_queue_redraw,
6941    *        _clutter_actor_queue_redraw_with_clip
6942    *     or clutter_effect_queue_rerun
6943    *
6944    * then control moves to:
6945    *   _clutter_stage_queue_actor_redraw
6946    *
6947    * later during _clutter_stage_do_update, once relayouting is done
6948    * and the scenegraph has been updated we will call:
6949    * _clutter_stage_finish_queue_redraws
6950    *
6951    * _clutter_stage_finish_queue_redraws will call
6952    * _clutter_actor_finish_queue_redraw for each listed actor.
6953    * Note: actors *are* allowed to queue further redraws during this
6954    * process (considering clone actors or texture_new_from_actor which
6955    * respond to their source queueing a redraw by queuing a redraw
6956    * themselves). We repeat the process until the list is empty.
6957    *
6958    * This will result in the "queue-redraw" signal being fired for
6959    * each actor which will pass control to the default signal handler:
6960    * clutter_actor_real_queue_redraw
6961    *
6962    * This will bubble up to the stages handler:
6963    * clutter_stage_real_queue_redraw
6964    *
6965    * clutter_stage_real_queue_redraw will transform the actors paint
6966    * volume into screen space and add it as a clip region for the next
6967    * paint.
6968    */
6969
6970   /* ignore queueing a redraw for actors being destroyed */
6971   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6972     return;
6973
6974   stage = _clutter_actor_get_stage_internal (self);
6975
6976   /* Ignore queueing a redraw for actors not descended from a stage */
6977   if (stage == NULL)
6978     return;
6979
6980   /* ignore queueing a redraw on stages that are being destroyed */
6981   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
6982     return;
6983
6984   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
6985     {
6986       ClutterActorBox allocation_clip;
6987       ClutterVertex origin;
6988
6989       /* If the actor doesn't have a valid allocation then we will
6990        * queue a full stage redraw. */
6991       if (priv->needs_allocation)
6992         {
6993           /* NB: NULL denotes an undefined clip which will result in a
6994            * full redraw... */
6995           _clutter_actor_set_queue_redraw_clip (self, NULL);
6996           _clutter_actor_signal_queue_redraw (self, self);
6997           return;
6998         }
6999
7000       _clutter_paint_volume_init_static (&allocation_pv, self);
7001       pv = &allocation_pv;
7002
7003       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7004
7005       origin.x = allocation_clip.x1;
7006       origin.y = allocation_clip.y1;
7007       origin.z = 0;
7008       clutter_paint_volume_set_origin (pv, &origin);
7009       clutter_paint_volume_set_width (pv,
7010                                       allocation_clip.x2 - allocation_clip.x1);
7011       clutter_paint_volume_set_height (pv,
7012                                        allocation_clip.y2 -
7013                                        allocation_clip.y1);
7014       should_free_pv = TRUE;
7015     }
7016   else
7017     {
7018       pv = volume;
7019       should_free_pv = FALSE;
7020     }
7021
7022   self->priv->queue_redraw_entry =
7023     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7024                                        priv->queue_redraw_entry,
7025                                        self,
7026                                        pv);
7027
7028   if (should_free_pv)
7029     clutter_paint_volume_free (pv);
7030
7031   /* If this is the first redraw queued then we can directly use the
7032      effect parameter */
7033   if (!priv->is_dirty)
7034     priv->effect_to_redraw = effect;
7035   /* Otherwise we need to merge it with the existing effect parameter */
7036   else if (effect != NULL)
7037     {
7038       /* If there's already an effect then we need to use whichever is
7039          later in the chain of actors. Otherwise a full redraw has
7040          already been queued on the actor so we need to ignore the
7041          effect parameter */
7042       if (priv->effect_to_redraw != NULL)
7043         {
7044           if (priv->effects == NULL)
7045             g_warning ("Redraw queued with an effect that is "
7046                        "not applied to the actor");
7047           else
7048             {
7049               const GList *l;
7050
7051               for (l = _clutter_meta_group_peek_metas (priv->effects);
7052                    l != NULL;
7053                    l = l->next)
7054                 {
7055                   if (l->data == priv->effect_to_redraw ||
7056                       l->data == effect)
7057                     priv->effect_to_redraw = l->data;
7058                 }
7059             }
7060         }
7061     }
7062   else
7063     {
7064       /* If no effect is specified then we need to redraw the whole
7065          actor */
7066       priv->effect_to_redraw = NULL;
7067     }
7068
7069   priv->is_dirty = TRUE;
7070 }
7071
7072 /**
7073  * clutter_actor_queue_redraw:
7074  * @self: A #ClutterActor
7075  *
7076  * Queues up a redraw of an actor and any children. The redraw occurs
7077  * once the main loop becomes idle (after the current batch of events
7078  * has been processed, roughly).
7079  *
7080  * Applications rarely need to call this, as redraws are handled
7081  * automatically by modification functions.
7082  *
7083  * This function will not do anything if @self is not visible, or
7084  * if the actor is inside an invisible part of the scenegraph.
7085  *
7086  * Also be aware that painting is a NOP for actors with an opacity of
7087  * 0
7088  *
7089  * When you are implementing a custom actor you must queue a redraw
7090  * whenever some private state changes that will affect painting or
7091  * picking of your actor.
7092  */
7093 void
7094 clutter_actor_queue_redraw (ClutterActor *self)
7095 {
7096   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7097
7098   _clutter_actor_queue_redraw_full (self,
7099                                     0, /* flags */
7100                                     NULL, /* clip volume */
7101                                     NULL /* effect */);
7102 }
7103
7104 /*< private >
7105  * _clutter_actor_queue_redraw_with_clip:
7106  * @self: A #ClutterActor
7107  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7108  *   this queue redraw.
7109  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7110  *   redrawn or %NULL if you are just using a @flag to state your
7111  *   desired clipping.
7112  *
7113  * Queues up a clipped redraw of an actor and any children. The redraw
7114  * occurs once the main loop becomes idle (after the current batch of
7115  * events has been processed, roughly).
7116  *
7117  * If no flags are given the clip volume is defined by @volume
7118  * specified in actor coordinates and tells Clutter that only content
7119  * within this volume has been changed so Clutter can optionally
7120  * optimize the redraw.
7121  *
7122  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7123  * should be %NULL and this tells Clutter to use the actor's current
7124  * allocation as a clip box. This flag can only be used for 2D actors,
7125  * because any actor with depth may be projected outside its
7126  * allocation.
7127  *
7128  * Applications rarely need to call this, as redraws are handled
7129  * automatically by modification functions.
7130  *
7131  * This function will not do anything if @self is not visible, or if
7132  * the actor is inside an invisible part of the scenegraph.
7133  *
7134  * Also be aware that painting is a NOP for actors with an opacity of
7135  * 0
7136  *
7137  * When you are implementing a custom actor you must queue a redraw
7138  * whenever some private state changes that will affect painting or
7139  * picking of your actor.
7140  */
7141 void
7142 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7143                                        ClutterRedrawFlags  flags,
7144                                        ClutterPaintVolume *volume)
7145 {
7146   _clutter_actor_queue_redraw_full (self,
7147                                     flags, /* flags */
7148                                     volume, /* clip volume */
7149                                     NULL /* effect */);
7150 }
7151
7152 static void
7153 _clutter_actor_queue_only_relayout (ClutterActor *self)
7154 {
7155   ClutterActorPrivate *priv = self->priv;
7156
7157   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7158     return;
7159
7160   if (priv->needs_width_request &&
7161       priv->needs_height_request &&
7162       priv->needs_allocation)
7163     return; /* save some cpu cycles */
7164
7165 #if CLUTTER_ENABLE_DEBUG
7166   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7167     {
7168       g_warning ("The actor '%s' is currently inside an allocation "
7169                  "cycle; calling clutter_actor_queue_relayout() is "
7170                  "not recommended",
7171                  _clutter_actor_get_debug_name (self));
7172     }
7173 #endif /* CLUTTER_ENABLE_DEBUG */
7174
7175   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7176 }
7177
7178 /**
7179  * clutter_actor_queue_redraw_with_clip:
7180  * @self: a #ClutterActor
7181  * @clip: (allow-none): a rectangular clip region, or %NULL
7182  *
7183  * Queues a redraw on @self limited to a specific, actor-relative
7184  * rectangular area.
7185  *
7186  * If @clip is %NULL this function is equivalent to
7187  * clutter_actor_queue_redraw().
7188  *
7189  * Since: 1.10
7190  */
7191 void
7192 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7193                                       const cairo_rectangle_int_t *clip)
7194 {
7195   ClutterPaintVolume volume;
7196   ClutterVertex origin;
7197
7198   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7199
7200   if (clip == NULL)
7201     {
7202       clutter_actor_queue_redraw (self);
7203       return;
7204     }
7205
7206   _clutter_paint_volume_init_static (&volume, self);
7207
7208   origin.x = clip->x;
7209   origin.y = clip->y;
7210   origin.z = 0.0f;
7211
7212   clutter_paint_volume_set_origin (&volume, &origin);
7213   clutter_paint_volume_set_width (&volume, clip->width);
7214   clutter_paint_volume_set_height (&volume, clip->height);
7215
7216   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7217
7218   clutter_paint_volume_free (&volume);
7219 }
7220
7221 /**
7222  * clutter_actor_queue_relayout:
7223  * @self: A #ClutterActor
7224  *
7225  * Indicates that the actor's size request or other layout-affecting
7226  * properties may have changed. This function is used inside #ClutterActor
7227  * subclass implementations, not by applications directly.
7228  *
7229  * Queueing a new layout automatically queues a redraw as well.
7230  *
7231  * Since: 0.8
7232  */
7233 void
7234 clutter_actor_queue_relayout (ClutterActor *self)
7235 {
7236   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7237
7238   _clutter_actor_queue_only_relayout (self);
7239   clutter_actor_queue_redraw (self);
7240 }
7241
7242 /**
7243  * clutter_actor_get_preferred_size:
7244  * @self: a #ClutterActor
7245  * @min_width_p: (out) (allow-none): return location for the minimum
7246  *   width, or %NULL
7247  * @min_height_p: (out) (allow-none): return location for the minimum
7248  *   height, or %NULL
7249  * @natural_width_p: (out) (allow-none): return location for the natural
7250  *   width, or %NULL
7251  * @natural_height_p: (out) (allow-none): return location for the natural
7252  *   height, or %NULL
7253  *
7254  * Computes the preferred minimum and natural size of an actor, taking into
7255  * account the actor's geometry management (either height-for-width
7256  * or width-for-height).
7257  *
7258  * The width and height used to compute the preferred height and preferred
7259  * width are the actor's natural ones.
7260  *
7261  * If you need to control the height for the preferred width, or the width for
7262  * the preferred height, you should use clutter_actor_get_preferred_width()
7263  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7264  * geometry management using the #ClutterActor:request-mode property.
7265  *
7266  * Since: 0.8
7267  */
7268 void
7269 clutter_actor_get_preferred_size (ClutterActor *self,
7270                                   gfloat       *min_width_p,
7271                                   gfloat       *min_height_p,
7272                                   gfloat       *natural_width_p,
7273                                   gfloat       *natural_height_p)
7274 {
7275   ClutterActorPrivate *priv;
7276   gfloat min_width, min_height;
7277   gfloat natural_width, natural_height;
7278
7279   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7280
7281   priv = self->priv;
7282
7283   min_width = min_height = 0;
7284   natural_width = natural_height = 0;
7285
7286   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7287     {
7288       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7289       clutter_actor_get_preferred_width (self, -1,
7290                                          &min_width,
7291                                          &natural_width);
7292       clutter_actor_get_preferred_height (self, natural_width,
7293                                           &min_height,
7294                                           &natural_height);
7295     }
7296   else
7297     {
7298       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7299       clutter_actor_get_preferred_height (self, -1,
7300                                           &min_height,
7301                                           &natural_height);
7302       clutter_actor_get_preferred_width (self, natural_height,
7303                                          &min_width,
7304                                          &natural_width);
7305     }
7306
7307   if (min_width_p)
7308     *min_width_p = min_width;
7309
7310   if (min_height_p)
7311     *min_height_p = min_height;
7312
7313   if (natural_width_p)
7314     *natural_width_p = natural_width;
7315
7316   if (natural_height_p)
7317     *natural_height_p = natural_height;
7318 }
7319
7320 /*< private >
7321  * effective_align:
7322  * @align: a #ClutterActorAlign
7323  * @direction: a #ClutterTextDirection
7324  *
7325  * Retrieves the correct alignment depending on the text direction
7326  *
7327  * Return value: the effective alignment
7328  */
7329 static ClutterActorAlign
7330 effective_align (ClutterActorAlign    align,
7331                  ClutterTextDirection direction)
7332 {
7333   ClutterActorAlign res;
7334
7335   switch (align)
7336     {
7337     case CLUTTER_ACTOR_ALIGN_START:
7338       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7339           ? CLUTTER_ACTOR_ALIGN_END
7340           : CLUTTER_ACTOR_ALIGN_START;
7341       break;
7342
7343     case CLUTTER_ACTOR_ALIGN_END:
7344       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7345           ? CLUTTER_ACTOR_ALIGN_START
7346           : CLUTTER_ACTOR_ALIGN_END;
7347       break;
7348
7349     default:
7350       res = align;
7351       break;
7352     }
7353
7354   return res;
7355 }
7356
7357 static inline void
7358 adjust_for_margin (float  margin_start,
7359                    float  margin_end,
7360                    float *minimum_size,
7361                    float *natural_size,
7362                    float *allocated_start,
7363                    float *allocated_end)
7364 {
7365   *minimum_size -= (margin_start + margin_end);
7366   *natural_size -= (margin_start + margin_end);
7367   *allocated_start += margin_start;
7368   *allocated_end -= margin_end;
7369 }
7370
7371 static inline void
7372 adjust_for_alignment (ClutterActorAlign  alignment,
7373                       float              natural_size,
7374                       float             *allocated_start,
7375                       float             *allocated_end)
7376 {
7377   float allocated_size = *allocated_end - *allocated_start;
7378
7379   switch (alignment)
7380     {
7381     case CLUTTER_ACTOR_ALIGN_FILL:
7382       /* do nothing */
7383       break;
7384
7385     case CLUTTER_ACTOR_ALIGN_START:
7386       /* keep start */
7387       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7388       break;
7389
7390     case CLUTTER_ACTOR_ALIGN_END:
7391       if (allocated_size > natural_size)
7392         {
7393           *allocated_start += (allocated_size - natural_size);
7394           *allocated_end = *allocated_start + natural_size;
7395         }
7396       break;
7397
7398     case CLUTTER_ACTOR_ALIGN_CENTER:
7399       if (allocated_size > natural_size)
7400         {
7401           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7402           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7403         }
7404       break;
7405     }
7406 }
7407
7408 /*< private >
7409  * clutter_actor_adjust_width:
7410  * @self: a #ClutterActor
7411  * @minimum_width: (inout): the actor's preferred minimum width, which
7412  *   will be adjusted depending on the margin
7413  * @natural_width: (inout): the actor's preferred natural width, which
7414  *   will be adjusted depending on the margin
7415  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7416  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7417  *
7418  * Adjusts the preferred and allocated position and size of an actor,
7419  * depending on the margin and alignment properties.
7420  */
7421 static void
7422 clutter_actor_adjust_width (ClutterActor *self,
7423                             gfloat       *minimum_width,
7424                             gfloat       *natural_width,
7425                             gfloat       *adjusted_x1,
7426                             gfloat       *adjusted_x2)
7427 {
7428   ClutterTextDirection text_dir;
7429   const ClutterLayoutInfo *info;
7430
7431   info = _clutter_actor_get_layout_info_or_defaults (self);
7432   text_dir = clutter_actor_get_text_direction (self);
7433
7434   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7435
7436   /* this will tweak natural_width to remove the margin, so that
7437    * adjust_for_alignment() will use the correct size
7438    */
7439   adjust_for_margin (info->margin.left, info->margin.right,
7440                      minimum_width, natural_width,
7441                      adjusted_x1, adjusted_x2);
7442
7443   adjust_for_alignment (effective_align (info->x_align, text_dir),
7444                         *natural_width,
7445                         adjusted_x1, adjusted_x2);
7446 }
7447
7448 /*< private >
7449  * clutter_actor_adjust_height:
7450  * @self: a #ClutterActor
7451  * @minimum_height: (inout): the actor's preferred minimum height, which
7452  *   will be adjusted depending on the margin
7453  * @natural_height: (inout): the actor's preferred natural height, which
7454  *   will be adjusted depending on the margin
7455  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7456  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7457  *
7458  * Adjusts the preferred and allocated position and size of an actor,
7459  * depending on the margin and alignment properties.
7460  */
7461 static void
7462 clutter_actor_adjust_height (ClutterActor *self,
7463                              gfloat       *minimum_height,
7464                              gfloat       *natural_height,
7465                              gfloat       *adjusted_y1,
7466                              gfloat       *adjusted_y2)
7467 {
7468   const ClutterLayoutInfo *info;
7469
7470   info = _clutter_actor_get_layout_info_or_defaults (self);
7471
7472   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7473
7474   /* this will tweak natural_height to remove the margin, so that
7475    * adjust_for_alignment() will use the correct size
7476    */
7477   adjust_for_margin (info->margin.top, info->margin.bottom,
7478                      minimum_height, natural_height,
7479                      adjusted_y1,
7480                      adjusted_y2);
7481
7482   /* we don't use effective_align() here, because text direction
7483    * only affects the horizontal axis
7484    */
7485   adjust_for_alignment (info->y_align,
7486                         *natural_height,
7487                         adjusted_y1,
7488                         adjusted_y2);
7489
7490 }
7491
7492 /* looks for a cached size request for this for_size. If not
7493  * found, returns the oldest entry so it can be overwritten */
7494 static gboolean
7495 _clutter_actor_get_cached_size_request (gfloat         for_size,
7496                                         SizeRequest   *cached_size_requests,
7497                                         SizeRequest  **result)
7498 {
7499   guint i;
7500
7501   *result = &cached_size_requests[0];
7502
7503   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7504     {
7505       SizeRequest *sr;
7506
7507       sr = &cached_size_requests[i];
7508
7509       if (sr->age > 0 &&
7510           sr->for_size == for_size)
7511         {
7512           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7513           *result = sr;
7514           return TRUE;
7515         }
7516       else if (sr->age < (*result)->age)
7517         {
7518           *result = sr;
7519         }
7520     }
7521
7522   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7523
7524   return FALSE;
7525 }
7526
7527 /**
7528  * clutter_actor_get_preferred_width:
7529  * @self: A #ClutterActor
7530  * @for_height: available height when computing the preferred width,
7531  *   or a negative value to indicate that no height is defined
7532  * @min_width_p: (out) (allow-none): return location for minimum width,
7533  *   or %NULL
7534  * @natural_width_p: (out) (allow-none): return location for the natural
7535  *   width, or %NULL
7536  *
7537  * Computes the requested minimum and natural widths for an actor,
7538  * optionally depending on the specified height, or if they are
7539  * already computed, returns the cached values.
7540  *
7541  * An actor may not get its request - depending on the layout
7542  * manager that's in effect.
7543  *
7544  * A request should not incorporate the actor's scale or anchor point;
7545  * those transformations do not affect layout, only rendering.
7546  *
7547  * Since: 0.8
7548  */
7549 void
7550 clutter_actor_get_preferred_width (ClutterActor *self,
7551                                    gfloat        for_height,
7552                                    gfloat       *min_width_p,
7553                                    gfloat       *natural_width_p)
7554 {
7555   float request_min_width, request_natural_width;
7556   SizeRequest *cached_size_request;
7557   const ClutterLayoutInfo *info;
7558   ClutterActorPrivate *priv;
7559   gboolean found_in_cache;
7560
7561   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7562
7563   priv = self->priv;
7564
7565   info = _clutter_actor_get_layout_info_or_defaults (self);
7566
7567   /* we shortcircuit the case of a fixed size set using set_width() */
7568   if (priv->min_width_set && priv->natural_width_set)
7569     {
7570       if (min_width_p != NULL)
7571         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7572
7573       if (natural_width_p != NULL)
7574         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7575
7576       return;
7577     }
7578
7579   /* the remaining cases are:
7580    *
7581    *   - either min_width or natural_width have been set
7582    *   - neither min_width or natural_width have been set
7583    *
7584    * in both cases, we go through the cache (and through the actor in case
7585    * of cache misses) and determine the authoritative value depending on
7586    * the *_set flags.
7587    */
7588
7589   if (!priv->needs_width_request)
7590     {
7591       found_in_cache =
7592         _clutter_actor_get_cached_size_request (for_height,
7593                                                 priv->width_requests,
7594                                                 &cached_size_request);
7595     }
7596   else
7597     {
7598       /* if the actor needs a width request we use the first slot */
7599       found_in_cache = FALSE;
7600       cached_size_request = &priv->width_requests[0];
7601     }
7602
7603   if (!found_in_cache)
7604     {
7605       gfloat minimum_width, natural_width;
7606       ClutterActorClass *klass;
7607
7608       minimum_width = natural_width = 0;
7609
7610       /* adjust for the margin */
7611       if (for_height >= 0)
7612         {
7613           for_height -= (info->margin.top + info->margin.bottom);
7614           if (for_height < 0)
7615             for_height = 0;
7616         }
7617
7618       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7619
7620       klass = CLUTTER_ACTOR_GET_CLASS (self);
7621       klass->get_preferred_width (self, for_height,
7622                                   &minimum_width,
7623                                   &natural_width);
7624
7625       /* adjust for the margin */
7626       minimum_width += (info->margin.left + info->margin.right);
7627       natural_width += (info->margin.left + info->margin.right);
7628
7629       /* Due to accumulated float errors, it's better not to warn
7630        * on this, but just fix it.
7631        */
7632       if (natural_width < minimum_width)
7633         natural_width = minimum_width;
7634
7635       cached_size_request->min_size = minimum_width;
7636       cached_size_request->natural_size = natural_width;
7637       cached_size_request->for_size = for_height;
7638       cached_size_request->age = priv->cached_width_age;
7639
7640       priv->cached_width_age += 1;
7641       priv->needs_width_request = FALSE;
7642     }
7643
7644   if (!priv->min_width_set)
7645     request_min_width = cached_size_request->min_size;
7646   else
7647     request_min_width = info->min_width;
7648
7649   if (!priv->natural_width_set)
7650     request_natural_width = cached_size_request->natural_size;
7651   else
7652     request_natural_width = info->natural_width;
7653
7654   if (min_width_p)
7655     *min_width_p = request_min_width;
7656
7657   if (natural_width_p)
7658     *natural_width_p = request_natural_width;
7659 }
7660
7661 /**
7662  * clutter_actor_get_preferred_height:
7663  * @self: A #ClutterActor
7664  * @for_width: available width to assume in computing desired height,
7665  *   or a negative value to indicate that no width is defined
7666  * @min_height_p: (out) (allow-none): return location for minimum height,
7667  *   or %NULL
7668  * @natural_height_p: (out) (allow-none): return location for natural
7669  *   height, or %NULL
7670  *
7671  * Computes the requested minimum and natural heights for an actor,
7672  * or if they are already computed, returns the cached values.
7673  *
7674  * An actor may not get its request - depending on the layout
7675  * manager that's in effect.
7676  *
7677  * A request should not incorporate the actor's scale or anchor point;
7678  * those transformations do not affect layout, only rendering.
7679  *
7680  * Since: 0.8
7681  */
7682 void
7683 clutter_actor_get_preferred_height (ClutterActor *self,
7684                                     gfloat        for_width,
7685                                     gfloat       *min_height_p,
7686                                     gfloat       *natural_height_p)
7687 {
7688   float request_min_height, request_natural_height;
7689   SizeRequest *cached_size_request;
7690   const ClutterLayoutInfo *info;
7691   ClutterActorPrivate *priv;
7692   gboolean found_in_cache;
7693
7694   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7695
7696   priv = self->priv;
7697
7698   info = _clutter_actor_get_layout_info_or_defaults (self);
7699
7700   /* we shortcircuit the case of a fixed size set using set_height() */
7701   if (priv->min_height_set && priv->natural_height_set)
7702     {
7703       if (min_height_p != NULL)
7704         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7705
7706       if (natural_height_p != NULL)
7707         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7708
7709       return;
7710     }
7711
7712   /* the remaining cases are:
7713    *
7714    *   - either min_height or natural_height have been set
7715    *   - neither min_height or natural_height have been set
7716    *
7717    * in both cases, we go through the cache (and through the actor in case
7718    * of cache misses) and determine the authoritative value depending on
7719    * the *_set flags.
7720    */
7721
7722   if (!priv->needs_height_request)
7723     {
7724       found_in_cache =
7725         _clutter_actor_get_cached_size_request (for_width,
7726                                                 priv->height_requests,
7727                                                 &cached_size_request);
7728     }
7729   else
7730     {
7731       found_in_cache = FALSE;
7732       cached_size_request = &priv->height_requests[0];
7733     }
7734
7735   if (!found_in_cache)
7736     {
7737       gfloat minimum_height, natural_height;
7738       ClutterActorClass *klass;
7739
7740       minimum_height = natural_height = 0;
7741
7742       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7743
7744       /* adjust for margin */
7745       if (for_width >= 0)
7746         {
7747           for_width -= (info->margin.left + info->margin.right);
7748           if (for_width < 0)
7749             for_width = 0;
7750         }
7751
7752       klass = CLUTTER_ACTOR_GET_CLASS (self);
7753       klass->get_preferred_height (self, for_width,
7754                                    &minimum_height,
7755                                    &natural_height);
7756
7757       /* adjust for margin */
7758       minimum_height += (info->margin.top + info->margin.bottom);
7759       natural_height += (info->margin.top + info->margin.bottom);
7760
7761       /* Due to accumulated float errors, it's better not to warn
7762        * on this, but just fix it.
7763        */
7764       if (natural_height < minimum_height)
7765         natural_height = minimum_height;
7766
7767       cached_size_request->min_size = minimum_height;
7768       cached_size_request->natural_size = natural_height;
7769       cached_size_request->for_size = for_width;
7770       cached_size_request->age = priv->cached_height_age;
7771
7772       priv->cached_height_age += 1;
7773       priv->needs_height_request = FALSE;
7774     }
7775
7776   if (!priv->min_height_set)
7777     request_min_height = cached_size_request->min_size;
7778   else
7779     request_min_height = info->min_height;
7780
7781   if (!priv->natural_height_set)
7782     request_natural_height = cached_size_request->natural_size;
7783   else
7784     request_natural_height = info->natural_height;
7785
7786   if (min_height_p)
7787     *min_height_p = request_min_height;
7788
7789   if (natural_height_p)
7790     *natural_height_p = request_natural_height;
7791 }
7792
7793 /**
7794  * clutter_actor_get_allocation_box:
7795  * @self: A #ClutterActor
7796  * @box: (out): the function fills this in with the actor's allocation
7797  *
7798  * Gets the layout box an actor has been assigned. The allocation can
7799  * only be assumed valid inside a paint() method; anywhere else, it
7800  * may be out-of-date.
7801  *
7802  * An allocation does not incorporate the actor's scale or anchor point;
7803  * those transformations do not affect layout, only rendering.
7804  *
7805  * <note>Do not call any of the clutter_actor_get_allocation_*() family
7806  * of functions inside the implementation of the get_preferred_width()
7807  * or get_preferred_height() virtual functions.</note>
7808  *
7809  * Since: 0.8
7810  */
7811 void
7812 clutter_actor_get_allocation_box (ClutterActor    *self,
7813                                   ClutterActorBox *box)
7814 {
7815   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7816
7817   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7818    * which limits calling get_allocation to inside paint() basically; or
7819    * we can 2) force a layout, which could be expensive if someone calls
7820    * get_allocation somewhere silly; or we can 3) just return the latest
7821    * value, allowing it to be out-of-date, and assume people know what
7822    * they are doing.
7823    *
7824    * The least-surprises approach that keeps existing code working is
7825    * likely to be 2). People can end up doing some inefficient things,
7826    * though, and in general code that requires 2) is probably broken.
7827    */
7828
7829   /* this implements 2) */
7830   if (G_UNLIKELY (self->priv->needs_allocation))
7831     {
7832       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7833
7834       /* do not queue a relayout on an unparented actor */
7835       if (stage)
7836         _clutter_stage_maybe_relayout (stage);
7837     }
7838
7839   /* commenting out the code above and just keeping this assigment
7840    * implements 3)
7841    */
7842   *box = self->priv->allocation;
7843 }
7844
7845 /**
7846  * clutter_actor_get_allocation_geometry:
7847  * @self: A #ClutterActor
7848  * @geom: (out): allocation geometry in pixels
7849  *
7850  * Gets the layout box an actor has been assigned.  The allocation can
7851  * only be assumed valid inside a paint() method; anywhere else, it
7852  * may be out-of-date.
7853  *
7854  * An allocation does not incorporate the actor's scale or anchor point;
7855  * those transformations do not affect layout, only rendering.
7856  *
7857  * The returned rectangle is in pixels.
7858  *
7859  * Since: 0.8
7860  */
7861 void
7862 clutter_actor_get_allocation_geometry (ClutterActor    *self,
7863                                        ClutterGeometry *geom)
7864 {
7865   ClutterActorBox box;
7866
7867   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7868   g_return_if_fail (geom != NULL);
7869
7870   clutter_actor_get_allocation_box (self, &box);
7871
7872   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7873   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7874   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7875   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7876 }
7877
7878 static void
7879 clutter_actor_update_constraints (ClutterActor    *self,
7880                                   ClutterActorBox *allocation)
7881 {
7882   ClutterActorPrivate *priv = self->priv;
7883   const GList *constraints, *l;
7884
7885   if (priv->constraints == NULL)
7886     return;
7887
7888   constraints = _clutter_meta_group_peek_metas (priv->constraints);
7889   for (l = constraints; l != NULL; l = l->next)
7890     {
7891       ClutterConstraint *constraint = l->data;
7892       ClutterActorMeta *meta = l->data;
7893
7894       if (clutter_actor_meta_get_enabled (meta))
7895         {
7896           _clutter_constraint_update_allocation (constraint,
7897                                                  self,
7898                                                  allocation);
7899         }
7900     }
7901 }
7902
7903 /*< private >
7904  * clutter_actor_adjust_allocation:
7905  * @self: a #ClutterActor
7906  * @allocation: (inout): the allocation to adjust
7907  *
7908  * Adjusts the passed allocation box taking into account the actor's
7909  * layout information, like alignment, expansion, and margin.
7910  */
7911 static void
7912 clutter_actor_adjust_allocation (ClutterActor    *self,
7913                                  ClutterActorBox *allocation)
7914 {
7915   ClutterActorBox adj_allocation;
7916   float alloc_width, alloc_height;
7917   float min_width, min_height;
7918   float nat_width, nat_height;
7919   ClutterRequestMode req_mode;
7920
7921   adj_allocation = *allocation;
7922
7923   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
7924
7925   /* we want to hit the cache, so we use the public API */
7926   req_mode = clutter_actor_get_request_mode (self);
7927
7928   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7929     {
7930       clutter_actor_get_preferred_width (self, -1,
7931                                          &min_width,
7932                                          &nat_width);
7933       clutter_actor_get_preferred_height (self, alloc_width,
7934                                           &min_height,
7935                                           &nat_height);
7936     }
7937   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
7938     {
7939       clutter_actor_get_preferred_height (self, -1,
7940                                           &min_height,
7941                                           &nat_height);
7942       clutter_actor_get_preferred_height (self, alloc_height,
7943                                           &min_width,
7944                                           &nat_width);
7945     }
7946
7947 #ifdef CLUTTER_ENABLE_DEBUG
7948   /* warn about underallocations */
7949   if (_clutter_diagnostic_enabled () &&
7950       (floorf (min_width - alloc_width) > 0 ||
7951        floorf (min_height - alloc_height) > 0))
7952     {
7953       ClutterActor *parent = clutter_actor_get_parent (self);
7954
7955       /* the only actors that are allowed to be underallocated are the Stage,
7956        * as it doesn't have an implicit size, and Actors that specifically
7957        * told us that they want to opt-out from layout control mechanisms
7958        * through the NO_LAYOUT escape hatch.
7959        */
7960       if (parent != NULL &&
7961           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
7962         {
7963           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
7964                      "of %.2f x %.2f from its parent actor '%s', but its "
7965                      "requested minimum size is of %.2f x %.2f",
7966                      _clutter_actor_get_debug_name (self),
7967                      alloc_width, alloc_height,
7968                      _clutter_actor_get_debug_name (parent),
7969                      min_width, min_height);
7970         }
7971     }
7972 #endif
7973
7974   clutter_actor_adjust_width (self,
7975                               &min_width,
7976                               &nat_width,
7977                               &adj_allocation.x1,
7978                               &adj_allocation.x2);
7979
7980   clutter_actor_adjust_height (self,
7981                                &min_height,
7982                                &nat_height,
7983                                &adj_allocation.y1,
7984                                &adj_allocation.y2);
7985
7986   /* we maintain the invariant that an allocation cannot be adjusted
7987    * to be outside the parent-given box
7988    */
7989   if (adj_allocation.x1 < allocation->x1 ||
7990       adj_allocation.y1 < allocation->y1 ||
7991       adj_allocation.x2 > allocation->x2 ||
7992       adj_allocation.y2 > allocation->y2)
7993     {
7994       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
7995                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
7996                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
7997                  _clutter_actor_get_debug_name (self),
7998                  adj_allocation.x1, adj_allocation.y1,
7999                  adj_allocation.x2 - adj_allocation.x1,
8000                  adj_allocation.y2 - adj_allocation.y1,
8001                  allocation->x1, allocation->y1,
8002                  allocation->x2 - allocation->x1,
8003                  allocation->y2 - allocation->y1);
8004       return;
8005     }
8006
8007   *allocation = adj_allocation;
8008 }
8009
8010 /**
8011  * clutter_actor_allocate:
8012  * @self: A #ClutterActor
8013  * @box: new allocation of the actor, in parent-relative coordinates
8014  * @flags: flags that control the allocation
8015  *
8016  * Called by the parent of an actor to assign the actor its size.
8017  * Should never be called by applications (except when implementing
8018  * a container or layout manager).
8019  *
8020  * Actors can know from their allocation box whether they have moved
8021  * with respect to their parent actor. The @flags parameter describes
8022  * additional information about the allocation, for instance whether
8023  * the parent has moved with respect to the stage, for example because
8024  * a grandparent's origin has moved.
8025  *
8026  * Since: 0.8
8027  */
8028 void
8029 clutter_actor_allocate (ClutterActor           *self,
8030                         const ClutterActorBox  *box,
8031                         ClutterAllocationFlags  flags)
8032 {
8033   ClutterActorPrivate *priv;
8034   ClutterActorClass *klass;
8035   ClutterActorBox old_allocation, real_allocation;
8036   gboolean origin_changed, child_moved, size_changed;
8037   gboolean stage_allocation_changed;
8038
8039   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8040   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8041     {
8042       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8043                  "which isn't a descendent of the stage!\n",
8044                  self, _clutter_actor_get_debug_name (self));
8045       return;
8046     }
8047
8048   priv = self->priv;
8049
8050   old_allocation = priv->allocation;
8051   real_allocation = *box;
8052
8053   /* constraints are allowed to modify the allocation only here; we do
8054    * this prior to all the other checks so that we can bail out if the
8055    * allocation did not change
8056    */
8057   clutter_actor_update_constraints (self, &real_allocation);
8058
8059   /* adjust the allocation depending on the align/margin properties */
8060   clutter_actor_adjust_allocation (self, &real_allocation);
8061
8062   if (real_allocation.x2 < real_allocation.x1 ||
8063       real_allocation.y2 < real_allocation.y1)
8064     {
8065       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8066                  _clutter_actor_get_debug_name (self),
8067                  real_allocation.x2 - real_allocation.x1,
8068                  real_allocation.y2 - real_allocation.y1);
8069     }
8070
8071   /* we allow 0-sized actors, but not negative-sized ones */
8072   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8073   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8074
8075   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8076
8077   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8078                  real_allocation.y1 != old_allocation.y1);
8079
8080   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8081                   real_allocation.y2 != old_allocation.y2);
8082
8083   if (origin_changed || child_moved || size_changed)
8084     stage_allocation_changed = TRUE;
8085   else
8086     stage_allocation_changed = FALSE;
8087
8088   /* If we get an allocation "out of the blue"
8089    * (we did not queue relayout), then we want to
8090    * ignore it. But if we have needs_allocation set,
8091    * we want to guarantee that allocate() virtual
8092    * method is always called, i.e. that queue_relayout()
8093    * always results in an allocate() invocation on
8094    * an actor.
8095    *
8096    * The optimization here is to avoid re-allocating
8097    * actors that did not queue relayout and were
8098    * not moved.
8099    */
8100   if (!priv->needs_allocation && !stage_allocation_changed)
8101     {
8102       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8103       return;
8104     }
8105
8106   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8107    * clutter_actor_allocate(), it indicates whether the parent has its
8108    * absolute origin moved; when passed in to ClutterActor::allocate()
8109    * virtual method though, it indicates whether the child has its
8110    * absolute origin moved.  So we set it when child_moved is TRUE
8111    */
8112   if (child_moved)
8113     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8114
8115   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8116
8117   klass = CLUTTER_ACTOR_GET_CLASS (self);
8118   klass->allocate (self, &real_allocation, flags);
8119
8120   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8121
8122   if (stage_allocation_changed)
8123     clutter_actor_queue_redraw (self);
8124 }
8125
8126 /**
8127  * clutter_actor_set_allocation:
8128  * @self: a #ClutterActor
8129  * @box: a #ClutterActorBox
8130  * @flags: allocation flags
8131  *
8132  * Stores the allocation of @self as defined by @box.
8133  *
8134  * This function can only be called from within the implementation of
8135  * the #ClutterActorClass.allocate() virtual function.
8136  *
8137  * The allocation should have been adjusted to take into account constraints,
8138  * alignment, and margin properties. If you are implementing a #ClutterActor
8139  * subclass that provides its own layout management policy for its children
8140  * instead of using a #ClutterLayoutManager delegate, you should not call
8141  * this function on the children of @self; instead, you should call
8142  * clutter_actor_allocate(), which will adjust the allocation box for
8143  * you.
8144  *
8145  * This function should only be used by subclasses of #ClutterActor
8146  * that wish to store their allocation but cannot chain up to the
8147  * parent's implementation; the default implementation of the
8148  * #ClutterActorClass.allocate() virtual function will call this
8149  * function.
8150  *
8151  * It is important to note that, while chaining up was the recommended
8152  * behaviour for #ClutterActor subclasses prior to the introduction of
8153  * this function, it is recommended to call clutter_actor_set_allocation()
8154  * instead.
8155  *
8156  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8157  * to handle the allocation of its children, this function will call
8158  * the clutter_layout_manager_allocate() function only if the
8159  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8160  * expected that the subclass will call clutter_layout_manager_allocate()
8161  * by itself. For instance, the following code:
8162  *
8163  * |[
8164  * static void
8165  * my_actor_allocate (ClutterActor *actor,
8166  *                    const ClutterActorBox *allocation,
8167  *                    ClutterAllocationFlags flags)
8168  * {
8169  *   ClutterActorBox new_alloc;
8170  *   ClutterAllocationFlags new_flags;
8171  *
8172  *   adjust_allocation (allocation, &amp;new_alloc);
8173  *
8174  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8175  *
8176  *   /&ast; this will use the layout manager set on the actor &ast;/
8177  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8178  * }
8179  * ]|
8180  *
8181  * is equivalent to this:
8182  *
8183  * |[
8184  * static void
8185  * my_actor_allocate (ClutterActor *actor,
8186  *                    const ClutterActorBox *allocation,
8187  *                    ClutterAllocationFlags flags)
8188  * {
8189  *   ClutterLayoutManager *layout;
8190  *   ClutterActorBox new_alloc;
8191  *
8192  *   adjust_allocation (allocation, &amp;new_alloc);
8193  *
8194  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8195  *
8196  *   layout = clutter_actor_get_layout_manager (actor);
8197  *   clutter_layout_manager_allocate (layout,
8198  *                                    CLUTTER_CONTAINER (actor),
8199  *                                    &amp;new_alloc,
8200  *                                    flags);
8201  * }
8202  * ]|
8203  *
8204  * Since: 1.10
8205  */
8206 void
8207 clutter_actor_set_allocation (ClutterActor           *self,
8208                               const ClutterActorBox  *box,
8209                               ClutterAllocationFlags  flags)
8210 {
8211   ClutterActorPrivate *priv;
8212   gboolean changed;
8213
8214   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8215   g_return_if_fail (box != NULL);
8216
8217   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8218     {
8219       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8220                   "can only be called from within the implementation of "
8221                   "the ClutterActor::allocate() virtual function.");
8222       return;
8223     }
8224
8225   priv = self->priv;
8226
8227   g_object_freeze_notify (G_OBJECT (self));
8228
8229   changed = clutter_actor_set_allocation_internal (self, box, flags);
8230
8231   /* we allocate our children before we notify changes in our geometry,
8232    * so that people connecting to properties will be able to get valid
8233    * data out of the sub-tree of the scene graph that has this actor at
8234    * the root.
8235    */
8236   clutter_actor_maybe_layout_children (self, box, flags);
8237
8238   if (changed)
8239     {
8240       ClutterActorBox signal_box = priv->allocation;
8241       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8242
8243       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8244                      &signal_box,
8245                      signal_flags);
8246     }
8247
8248   g_object_thaw_notify (G_OBJECT (self));
8249 }
8250
8251 /**
8252  * clutter_actor_set_geometry:
8253  * @self: A #ClutterActor
8254  * @geometry: A #ClutterGeometry
8255  *
8256  * Sets the actor's fixed position and forces its minimum and natural
8257  * size, in pixels. This means the untransformed actor will have the
8258  * given geometry. This is the same as calling clutter_actor_set_position()
8259  * and clutter_actor_set_size().
8260  *
8261  * Deprecated: 1.10: Use clutter_actor_set_position() and
8262  *   clutter_actor_set_size() instead.
8263  */
8264 void
8265 clutter_actor_set_geometry (ClutterActor          *self,
8266                             const ClutterGeometry *geometry)
8267 {
8268   g_object_freeze_notify (G_OBJECT (self));
8269
8270   clutter_actor_set_position (self, geometry->x, geometry->y);
8271   clutter_actor_set_size (self, geometry->width, geometry->height);
8272
8273   g_object_thaw_notify (G_OBJECT (self));
8274 }
8275
8276 /**
8277  * clutter_actor_get_geometry:
8278  * @self: A #ClutterActor
8279  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8280  *
8281  * Gets the size and position of an actor relative to its parent
8282  * actor. This is the same as calling clutter_actor_get_position() and
8283  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8284  * requested size and position if the actor's allocation is invalid.
8285  *
8286  * Deprecated: 1.10: Use clutter_actor_get_position() and
8287  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8288  *   instead.
8289  */
8290 void
8291 clutter_actor_get_geometry (ClutterActor    *self,
8292                             ClutterGeometry *geometry)
8293 {
8294   gfloat x, y, width, height;
8295
8296   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8297   g_return_if_fail (geometry != NULL);
8298
8299   clutter_actor_get_position (self, &x, &y);
8300   clutter_actor_get_size (self, &width, &height);
8301
8302   geometry->x = (int) x;
8303   geometry->y = (int) y;
8304   geometry->width = (int) width;
8305   geometry->height = (int) height;
8306 }
8307
8308 /**
8309  * clutter_actor_set_position:
8310  * @self: A #ClutterActor
8311  * @x: New left position of actor in pixels.
8312  * @y: New top position of actor in pixels.
8313  *
8314  * Sets the actor's fixed position in pixels relative to any parent
8315  * actor.
8316  *
8317  * If a layout manager is in use, this position will override the
8318  * layout manager and force a fixed position.
8319  */
8320 void
8321 clutter_actor_set_position (ClutterActor *self,
8322                             gfloat        x,
8323                             gfloat        y)
8324 {
8325   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8326
8327   g_object_freeze_notify (G_OBJECT (self));
8328
8329   clutter_actor_set_x (self, x);
8330   clutter_actor_set_y (self, y);
8331
8332   g_object_thaw_notify (G_OBJECT (self));
8333 }
8334
8335 /**
8336  * clutter_actor_get_fixed_position_set:
8337  * @self: A #ClutterActor
8338  *
8339  * Checks whether an actor has a fixed position set (and will thus be
8340  * unaffected by any layout manager).
8341  *
8342  * Return value: %TRUE if the fixed position is set on the actor
8343  *
8344  * Since: 0.8
8345  */
8346 gboolean
8347 clutter_actor_get_fixed_position_set (ClutterActor *self)
8348 {
8349   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8350
8351   return self->priv->position_set;
8352 }
8353
8354 /**
8355  * clutter_actor_set_fixed_position_set:
8356  * @self: A #ClutterActor
8357  * @is_set: whether to use fixed position
8358  *
8359  * Sets whether an actor has a fixed position set (and will thus be
8360  * unaffected by any layout manager).
8361  *
8362  * Since: 0.8
8363  */
8364 void
8365 clutter_actor_set_fixed_position_set (ClutterActor *self,
8366                                       gboolean      is_set)
8367 {
8368   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8369
8370   if (self->priv->position_set == (is_set != FALSE))
8371     return;
8372
8373   self->priv->position_set = is_set != FALSE;
8374   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8375
8376   clutter_actor_queue_relayout (self);
8377 }
8378
8379 /**
8380  * clutter_actor_move_by:
8381  * @self: A #ClutterActor
8382  * @dx: Distance to move Actor on X axis.
8383  * @dy: Distance to move Actor on Y axis.
8384  *
8385  * Moves an actor by the specified distance relative to its current
8386  * position in pixels.
8387  *
8388  * This function modifies the fixed position of an actor and thus removes
8389  * it from any layout management. Another way to move an actor is with an
8390  * anchor point, see clutter_actor_set_anchor_point().
8391  *
8392  * Since: 0.2
8393  */
8394 void
8395 clutter_actor_move_by (ClutterActor *self,
8396                        gfloat        dx,
8397                        gfloat        dy)
8398 {
8399   const ClutterLayoutInfo *info;
8400   gfloat x, y;
8401
8402   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8403
8404   info = _clutter_actor_get_layout_info_or_defaults (self);
8405   x = info->fixed_x;
8406   y = info->fixed_y;
8407
8408   clutter_actor_set_position (self, x + dx, y + dy);
8409 }
8410
8411 static void
8412 clutter_actor_set_min_width (ClutterActor *self,
8413                              gfloat        min_width)
8414 {
8415   ClutterActorPrivate *priv = self->priv;
8416   ClutterActorBox old = { 0, };
8417   ClutterLayoutInfo *info;
8418
8419   /* if we are setting the size on a top-level actor and the
8420    * backend only supports static top-levels (e.g. framebuffers)
8421    * then we ignore the passed value and we override it with
8422    * the stage implementation's preferred size.
8423    */
8424   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8425       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8426     return;
8427
8428   info = _clutter_actor_get_layout_info (self);
8429
8430   if (priv->min_width_set && min_width == info->min_width)
8431     return;
8432
8433   g_object_freeze_notify (G_OBJECT (self));
8434
8435   clutter_actor_store_old_geometry (self, &old);
8436
8437   info->min_width = min_width;
8438   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8439   clutter_actor_set_min_width_set (self, TRUE);
8440
8441   clutter_actor_notify_if_geometry_changed (self, &old);
8442
8443   g_object_thaw_notify (G_OBJECT (self));
8444
8445   clutter_actor_queue_relayout (self);
8446 }
8447
8448 static void
8449 clutter_actor_set_min_height (ClutterActor *self,
8450                               gfloat        min_height)
8451
8452 {
8453   ClutterActorPrivate *priv = self->priv;
8454   ClutterActorBox old = { 0, };
8455   ClutterLayoutInfo *info;
8456
8457   /* if we are setting the size on a top-level actor and the
8458    * backend only supports static top-levels (e.g. framebuffers)
8459    * then we ignore the passed value and we override it with
8460    * the stage implementation's preferred size.
8461    */
8462   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8463       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8464     return;
8465
8466   info = _clutter_actor_get_layout_info (self);
8467
8468   if (priv->min_height_set && min_height == info->min_height)
8469     return;
8470
8471   g_object_freeze_notify (G_OBJECT (self));
8472
8473   clutter_actor_store_old_geometry (self, &old);
8474
8475   info->min_height = min_height;
8476   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8477   clutter_actor_set_min_height_set (self, TRUE);
8478
8479   clutter_actor_notify_if_geometry_changed (self, &old);
8480
8481   g_object_thaw_notify (G_OBJECT (self));
8482
8483   clutter_actor_queue_relayout (self);
8484 }
8485
8486 static void
8487 clutter_actor_set_natural_width (ClutterActor *self,
8488                                  gfloat        natural_width)
8489 {
8490   ClutterActorPrivate *priv = self->priv;
8491   ClutterActorBox old = { 0, };
8492   ClutterLayoutInfo *info;
8493
8494   /* if we are setting the size on a top-level actor and the
8495    * backend only supports static top-levels (e.g. framebuffers)
8496    * then we ignore the passed value and we override it with
8497    * the stage implementation's preferred size.
8498    */
8499   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8500       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8501     return;
8502
8503   info = _clutter_actor_get_layout_info (self);
8504
8505   if (priv->natural_width_set && natural_width == info->natural_width)
8506     return;
8507
8508   g_object_freeze_notify (G_OBJECT (self));
8509
8510   clutter_actor_store_old_geometry (self, &old);
8511
8512   info->natural_width = natural_width;
8513   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8514   clutter_actor_set_natural_width_set (self, TRUE);
8515
8516   clutter_actor_notify_if_geometry_changed (self, &old);
8517
8518   g_object_thaw_notify (G_OBJECT (self));
8519
8520   clutter_actor_queue_relayout (self);
8521 }
8522
8523 static void
8524 clutter_actor_set_natural_height (ClutterActor *self,
8525                                   gfloat        natural_height)
8526 {
8527   ClutterActorPrivate *priv = self->priv;
8528   ClutterActorBox old = { 0, };
8529   ClutterLayoutInfo *info;
8530
8531   /* if we are setting the size on a top-level actor and the
8532    * backend only supports static top-levels (e.g. framebuffers)
8533    * then we ignore the passed value and we override it with
8534    * the stage implementation's preferred size.
8535    */
8536   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8537       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8538     return;
8539
8540   info = _clutter_actor_get_layout_info (self);
8541
8542   if (priv->natural_height_set && natural_height == info->natural_height)
8543     return;
8544
8545   g_object_freeze_notify (G_OBJECT (self));
8546
8547   clutter_actor_store_old_geometry (self, &old);
8548
8549   info->natural_height = natural_height;
8550   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8551   clutter_actor_set_natural_height_set (self, TRUE);
8552
8553   clutter_actor_notify_if_geometry_changed (self, &old);
8554
8555   g_object_thaw_notify (G_OBJECT (self));
8556
8557   clutter_actor_queue_relayout (self);
8558 }
8559
8560 static void
8561 clutter_actor_set_min_width_set (ClutterActor *self,
8562                                  gboolean      use_min_width)
8563 {
8564   ClutterActorPrivate *priv = self->priv;
8565   ClutterActorBox old = { 0, };
8566
8567   if (priv->min_width_set == (use_min_width != FALSE))
8568     return;
8569
8570   clutter_actor_store_old_geometry (self, &old);
8571
8572   priv->min_width_set = use_min_width != FALSE;
8573   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8574
8575   clutter_actor_notify_if_geometry_changed (self, &old);
8576
8577   clutter_actor_queue_relayout (self);
8578 }
8579
8580 static void
8581 clutter_actor_set_min_height_set (ClutterActor *self,
8582                                   gboolean      use_min_height)
8583 {
8584   ClutterActorPrivate *priv = self->priv;
8585   ClutterActorBox old = { 0, };
8586
8587   if (priv->min_height_set == (use_min_height != FALSE))
8588     return;
8589
8590   clutter_actor_store_old_geometry (self, &old);
8591
8592   priv->min_height_set = use_min_height != FALSE;
8593   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8594
8595   clutter_actor_notify_if_geometry_changed (self, &old);
8596
8597   clutter_actor_queue_relayout (self);
8598 }
8599
8600 static void
8601 clutter_actor_set_natural_width_set (ClutterActor *self,
8602                                      gboolean      use_natural_width)
8603 {
8604   ClutterActorPrivate *priv = self->priv;
8605   ClutterActorBox old = { 0, };
8606
8607   if (priv->natural_width_set == (use_natural_width != FALSE))
8608     return;
8609
8610   clutter_actor_store_old_geometry (self, &old);
8611
8612   priv->natural_width_set = use_natural_width != FALSE;
8613   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8614
8615   clutter_actor_notify_if_geometry_changed (self, &old);
8616
8617   clutter_actor_queue_relayout (self);
8618 }
8619
8620 static void
8621 clutter_actor_set_natural_height_set (ClutterActor *self,
8622                                       gboolean      use_natural_height)
8623 {
8624   ClutterActorPrivate *priv = self->priv;
8625   ClutterActorBox old = { 0, };
8626
8627   if (priv->natural_height_set == (use_natural_height != FALSE))
8628     return;
8629
8630   clutter_actor_store_old_geometry (self, &old);
8631
8632   priv->natural_height_set = use_natural_height != FALSE;
8633   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8634
8635   clutter_actor_notify_if_geometry_changed (self, &old);
8636
8637   clutter_actor_queue_relayout (self);
8638 }
8639
8640 /**
8641  * clutter_actor_set_request_mode:
8642  * @self: a #ClutterActor
8643  * @mode: the request mode
8644  *
8645  * Sets the geometry request mode of @self.
8646  *
8647  * The @mode determines the order for invoking
8648  * clutter_actor_get_preferred_width() and
8649  * clutter_actor_get_preferred_height()
8650  *
8651  * Since: 1.2
8652  */
8653 void
8654 clutter_actor_set_request_mode (ClutterActor       *self,
8655                                 ClutterRequestMode  mode)
8656 {
8657   ClutterActorPrivate *priv;
8658
8659   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8660
8661   priv = self->priv;
8662
8663   if (priv->request_mode == mode)
8664     return;
8665
8666   priv->request_mode = mode;
8667
8668   priv->needs_width_request = TRUE;
8669   priv->needs_height_request = TRUE;
8670
8671   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8672
8673   clutter_actor_queue_relayout (self);
8674 }
8675
8676 /**
8677  * clutter_actor_get_request_mode:
8678  * @self: a #ClutterActor
8679  *
8680  * Retrieves the geometry request mode of @self
8681  *
8682  * Return value: the request mode for the actor
8683  *
8684  * Since: 1.2
8685  */
8686 ClutterRequestMode
8687 clutter_actor_get_request_mode (ClutterActor *self)
8688 {
8689   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8690                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8691
8692   return self->priv->request_mode;
8693 }
8694
8695 /* variant of set_width() without checks and without notification
8696  * freeze+thaw, for internal usage only
8697  */
8698 static inline void
8699 clutter_actor_set_width_internal (ClutterActor *self,
8700                                   gfloat        width)
8701 {
8702   if (width >= 0)
8703     {
8704       /* the Stage will use the :min-width to control the minimum
8705        * width to be resized to, so we should not be setting it
8706        * along with the :natural-width
8707        */
8708       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8709         clutter_actor_set_min_width (self, width);
8710
8711       clutter_actor_set_natural_width (self, width);
8712     }
8713   else
8714     {
8715       /* we only unset the :natural-width for the Stage */
8716       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8717         clutter_actor_set_min_width_set (self, FALSE);
8718
8719       clutter_actor_set_natural_width_set (self, FALSE);
8720     }
8721 }
8722
8723 /* variant of set_height() without checks and without notification
8724  * freeze+thaw, for internal usage only
8725  */
8726 static inline void
8727 clutter_actor_set_height_internal (ClutterActor *self,
8728                                    gfloat        height)
8729 {
8730   if (height >= 0)
8731     {
8732       /* see the comment above in set_width_internal() */
8733       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8734         clutter_actor_set_min_height (self, height);
8735
8736       clutter_actor_set_natural_height (self, height);
8737     }
8738   else
8739     {
8740       /* see the comment above in set_width_internal() */
8741       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8742         clutter_actor_set_min_height_set (self, FALSE);
8743
8744       clutter_actor_set_natural_height_set (self, FALSE);
8745     }
8746 }
8747
8748 /**
8749  * clutter_actor_set_size:
8750  * @self: A #ClutterActor
8751  * @width: New width of actor in pixels, or -1
8752  * @height: New height of actor in pixels, or -1
8753  *
8754  * Sets the actor's size request in pixels. This overrides any
8755  * "normal" size request the actor would have. For example
8756  * a text actor might normally request the size of the text;
8757  * this function would force a specific size instead.
8758  *
8759  * If @width and/or @height are -1 the actor will use its
8760  * "normal" size request instead of overriding it, i.e.
8761  * you can "unset" the size with -1.
8762  *
8763  * This function sets or unsets both the minimum and natural size.
8764  */
8765 void
8766 clutter_actor_set_size (ClutterActor *self,
8767                         gfloat        width,
8768                         gfloat        height)
8769 {
8770   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8771
8772   g_object_freeze_notify (G_OBJECT (self));
8773
8774   clutter_actor_set_width (self, width);
8775   clutter_actor_set_height (self, height);
8776
8777   g_object_thaw_notify (G_OBJECT (self));
8778 }
8779
8780 /**
8781  * clutter_actor_get_size:
8782  * @self: A #ClutterActor
8783  * @width: (out) (allow-none): return location for the width, or %NULL.
8784  * @height: (out) (allow-none): return location for the height, or %NULL.
8785  *
8786  * This function tries to "do what you mean" and return
8787  * the size an actor will have. If the actor has a valid
8788  * allocation, the allocation will be returned; otherwise,
8789  * the actors natural size request will be returned.
8790  *
8791  * If you care whether you get the request vs. the allocation, you
8792  * should probably call a different function like
8793  * clutter_actor_get_allocation_box() or
8794  * clutter_actor_get_preferred_width().
8795  *
8796  * Since: 0.2
8797  */
8798 void
8799 clutter_actor_get_size (ClutterActor *self,
8800                         gfloat       *width,
8801                         gfloat       *height)
8802 {
8803   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8804
8805   if (width)
8806     *width = clutter_actor_get_width (self);
8807
8808   if (height)
8809     *height = clutter_actor_get_height (self);
8810 }
8811
8812 /**
8813  * clutter_actor_get_position:
8814  * @self: a #ClutterActor
8815  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8816  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8817  *
8818  * This function tries to "do what you mean" and tell you where the
8819  * actor is, prior to any transformations. Retrieves the fixed
8820  * position of an actor in pixels, if one has been set; otherwise, if
8821  * the allocation is valid, returns the actor's allocated position;
8822  * otherwise, returns 0,0.
8823  *
8824  * The returned position is in pixels.
8825  *
8826  * Since: 0.6
8827  */
8828 void
8829 clutter_actor_get_position (ClutterActor *self,
8830                             gfloat       *x,
8831                             gfloat       *y)
8832 {
8833   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8834
8835   if (x)
8836     *x = clutter_actor_get_x (self);
8837
8838   if (y)
8839     *y = clutter_actor_get_y (self);
8840 }
8841
8842 /**
8843  * clutter_actor_get_transformed_position:
8844  * @self: A #ClutterActor
8845  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8846  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8847  *
8848  * Gets the absolute position of an actor, in pixels relative to the stage.
8849  *
8850  * Since: 0.8
8851  */
8852 void
8853 clutter_actor_get_transformed_position (ClutterActor *self,
8854                                         gfloat       *x,
8855                                         gfloat       *y)
8856 {
8857   ClutterVertex v1;
8858   ClutterVertex v2;
8859
8860   v1.x = v1.y = v1.z = 0;
8861   clutter_actor_apply_transform_to_point (self, &v1, &v2);
8862
8863   if (x)
8864     *x = v2.x;
8865
8866   if (y)
8867     *y = v2.y;
8868 }
8869
8870 /**
8871  * clutter_actor_get_transformed_size:
8872  * @self: A #ClutterActor
8873  * @width: (out) (allow-none): return location for the width, or %NULL
8874  * @height: (out) (allow-none): return location for the height, or %NULL
8875  *
8876  * Gets the absolute size of an actor in pixels, taking into account the
8877  * scaling factors.
8878  *
8879  * If the actor has a valid allocation, the allocated size will be used.
8880  * If the actor has not a valid allocation then the preferred size will
8881  * be transformed and returned.
8882  *
8883  * If you want the transformed allocation, see
8884  * clutter_actor_get_abs_allocation_vertices() instead.
8885  *
8886  * <note>When the actor (or one of its ancestors) is rotated around the
8887  * X or Y axis, it no longer appears as on the stage as a rectangle, but
8888  * as a generic quadrangle; in that case this function returns the size
8889  * of the smallest rectangle that encapsulates the entire quad. Please
8890  * note that in this case no assumptions can be made about the relative
8891  * position of this envelope to the absolute position of the actor, as
8892  * returned by clutter_actor_get_transformed_position(); if you need this
8893  * information, you need to use clutter_actor_get_abs_allocation_vertices()
8894  * to get the coords of the actual quadrangle.</note>
8895  *
8896  * Since: 0.8
8897  */
8898 void
8899 clutter_actor_get_transformed_size (ClutterActor *self,
8900                                     gfloat       *width,
8901                                     gfloat       *height)
8902 {
8903   ClutterActorPrivate *priv;
8904   ClutterVertex v[4];
8905   gfloat x_min, x_max, y_min, y_max;
8906   gint i;
8907
8908   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8909
8910   priv = self->priv;
8911
8912   /* if the actor hasn't been allocated yet, get the preferred
8913    * size and transform that
8914    */
8915   if (priv->needs_allocation)
8916     {
8917       gfloat natural_width, natural_height;
8918       ClutterActorBox box;
8919
8920       /* Make a fake allocation to transform.
8921        *
8922        * NB: _clutter_actor_transform_and_project_box expects a box in
8923        * the actor's coordinate space... */
8924
8925       box.x1 = 0;
8926       box.y1 = 0;
8927
8928       natural_width = natural_height = 0;
8929       clutter_actor_get_preferred_size (self, NULL, NULL,
8930                                         &natural_width,
8931                                         &natural_height);
8932
8933       box.x2 = natural_width;
8934       box.y2 = natural_height;
8935
8936       _clutter_actor_transform_and_project_box (self, &box, v);
8937     }
8938   else
8939     clutter_actor_get_abs_allocation_vertices (self, v);
8940
8941   x_min = x_max = v[0].x;
8942   y_min = y_max = v[0].y;
8943
8944   for (i = 1; i < G_N_ELEMENTS (v); ++i)
8945     {
8946       if (v[i].x < x_min)
8947         x_min = v[i].x;
8948
8949       if (v[i].x > x_max)
8950         x_max = v[i].x;
8951
8952       if (v[i].y < y_min)
8953         y_min = v[i].y;
8954
8955       if (v[i].y > y_max)
8956         y_max = v[i].y;
8957     }
8958
8959   if (width)
8960     *width  = x_max - x_min;
8961
8962   if (height)
8963     *height = y_max - y_min;
8964 }
8965
8966 /**
8967  * clutter_actor_get_width:
8968  * @self: A #ClutterActor
8969  *
8970  * Retrieves the width of a #ClutterActor.
8971  *
8972  * If the actor has a valid allocation, this function will return the
8973  * width of the allocated area given to the actor.
8974  *
8975  * If the actor does not have a valid allocation, this function will
8976  * return the actor's natural width, that is the preferred width of
8977  * the actor.
8978  *
8979  * If you care whether you get the preferred width or the width that
8980  * has been assigned to the actor, you should probably call a different
8981  * function like clutter_actor_get_allocation_box() to retrieve the
8982  * allocated size or clutter_actor_get_preferred_width() to retrieve the
8983  * preferred width.
8984  *
8985  * If an actor has a fixed width, for instance a width that has been
8986  * assigned using clutter_actor_set_width(), the width returned will
8987  * be the same value.
8988  *
8989  * Return value: the width of the actor, in pixels
8990  */
8991 gfloat
8992 clutter_actor_get_width (ClutterActor *self)
8993 {
8994   ClutterActorPrivate *priv;
8995
8996   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8997
8998   priv = self->priv;
8999
9000   if (priv->needs_allocation)
9001     {
9002       gfloat natural_width = 0;
9003
9004       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9005         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9006       else
9007         {
9008           gfloat natural_height = 0;
9009
9010           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9011           clutter_actor_get_preferred_width (self, natural_height,
9012                                              NULL,
9013                                              &natural_width);
9014         }
9015
9016       return natural_width;
9017     }
9018   else
9019     return priv->allocation.x2 - priv->allocation.x1;
9020 }
9021
9022 /**
9023  * clutter_actor_get_height:
9024  * @self: A #ClutterActor
9025  *
9026  * Retrieves the height of a #ClutterActor.
9027  *
9028  * If the actor has a valid allocation, this function will return the
9029  * height of the allocated area given to the actor.
9030  *
9031  * If the actor does not have a valid allocation, this function will
9032  * return the actor's natural height, that is the preferred height of
9033  * the actor.
9034  *
9035  * If you care whether you get the preferred height or the height that
9036  * has been assigned to the actor, you should probably call a different
9037  * function like clutter_actor_get_allocation_box() to retrieve the
9038  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9039  * preferred height.
9040  *
9041  * If an actor has a fixed height, for instance a height that has been
9042  * assigned using clutter_actor_set_height(), the height returned will
9043  * be the same value.
9044  *
9045  * Return value: the height of the actor, in pixels
9046  */
9047 gfloat
9048 clutter_actor_get_height (ClutterActor *self)
9049 {
9050   ClutterActorPrivate *priv;
9051
9052   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9053
9054   priv = self->priv;
9055
9056   if (priv->needs_allocation)
9057     {
9058       gfloat natural_height = 0;
9059
9060       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9061         {
9062           gfloat natural_width = 0;
9063
9064           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9065           clutter_actor_get_preferred_height (self, natural_width,
9066                                               NULL, &natural_height);
9067         }
9068       else
9069         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9070
9071       return natural_height;
9072     }
9073   else
9074     return priv->allocation.y2 - priv->allocation.y1;
9075 }
9076
9077 /**
9078  * clutter_actor_set_width:
9079  * @self: A #ClutterActor
9080  * @width: Requested new width for the actor, in pixels, or -1
9081  *
9082  * Forces a width on an actor, causing the actor's preferred width
9083  * and height (if any) to be ignored.
9084  *
9085  * If @width is -1 the actor will use its preferred width request
9086  * instead of overriding it, i.e. you can "unset" the width with -1.
9087  *
9088  * This function sets both the minimum and natural size of the actor.
9089  *
9090  * since: 0.2
9091  */
9092 void
9093 clutter_actor_set_width (ClutterActor *self,
9094                          gfloat        width)
9095 {
9096   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9097
9098   if (clutter_actor_get_easing_duration (self) != 0)
9099     {
9100       ClutterTransition *transition;
9101
9102       transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9103       if (transition == NULL)
9104         {
9105           float old_width = clutter_actor_get_width (self);
9106
9107           transition = _clutter_actor_create_transition (self,
9108                                                          obj_props[PROP_WIDTH],
9109                                                          old_width,
9110                                                          width);
9111           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9112         }
9113       else
9114         _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9115
9116       clutter_actor_queue_relayout (self);
9117     }
9118   else
9119     {
9120       g_object_freeze_notify (G_OBJECT (self));
9121
9122       clutter_actor_set_width_internal (self, width);
9123
9124       g_object_thaw_notify (G_OBJECT (self));
9125     }
9126 }
9127
9128 /**
9129  * clutter_actor_set_height:
9130  * @self: A #ClutterActor
9131  * @height: Requested new height for the actor, in pixels, or -1
9132  *
9133  * Forces a height on an actor, causing the actor's preferred width
9134  * and height (if any) to be ignored.
9135  *
9136  * If @height is -1 the actor will use its preferred height instead of
9137  * overriding it, i.e. you can "unset" the height with -1.
9138  *
9139  * This function sets both the minimum and natural size of the actor.
9140  *
9141  * since: 0.2
9142  */
9143 void
9144 clutter_actor_set_height (ClutterActor *self,
9145                           gfloat        height)
9146 {
9147   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9148
9149   if (clutter_actor_get_easing_duration (self) != 0)
9150     {
9151       ClutterTransition *transition;
9152
9153       transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9154       if (transition ==  NULL)
9155         {
9156           float old_height = clutter_actor_get_height (self);
9157
9158           transition = _clutter_actor_create_transition (self,
9159                                                          obj_props[PROP_HEIGHT],
9160                                                          old_height,
9161                                                          height);
9162           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9163         }
9164       else
9165         _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9166
9167       clutter_actor_queue_relayout (self);
9168     }
9169   else
9170     {
9171       g_object_freeze_notify (G_OBJECT (self));
9172
9173       clutter_actor_set_height_internal (self, height);
9174
9175       g_object_thaw_notify (G_OBJECT (self));
9176     }
9177 }
9178
9179 static inline void
9180 clutter_actor_set_x_internal (ClutterActor *self,
9181                               float         x)
9182 {
9183   ClutterActorPrivate *priv = self->priv;
9184   ClutterLayoutInfo *linfo;
9185   ClutterActorBox old = { 0, };
9186
9187   linfo = _clutter_actor_get_layout_info (self);
9188
9189   if (priv->position_set && linfo->fixed_x == x)
9190     return;
9191
9192   clutter_actor_store_old_geometry (self, &old);
9193
9194   linfo->fixed_x = x;
9195   clutter_actor_set_fixed_position_set (self, TRUE);
9196
9197   clutter_actor_notify_if_geometry_changed (self, &old);
9198
9199   clutter_actor_queue_relayout (self);
9200 }
9201
9202 static inline void
9203 clutter_actor_set_y_internal (ClutterActor *self,
9204                               float         y)
9205 {
9206   ClutterActorPrivate *priv = self->priv;
9207   ClutterLayoutInfo *linfo;
9208   ClutterActorBox old = { 0, };
9209
9210   linfo = _clutter_actor_get_layout_info (self);
9211
9212   if (priv->position_set && linfo->fixed_y == y)
9213     return;
9214
9215   clutter_actor_store_old_geometry (self, &old);
9216
9217   linfo->fixed_y = y;
9218   clutter_actor_set_fixed_position_set (self, TRUE);
9219
9220   clutter_actor_notify_if_geometry_changed (self, &old);
9221 }
9222
9223 /**
9224  * clutter_actor_set_x:
9225  * @self: a #ClutterActor
9226  * @x: the actor's position on the X axis
9227  *
9228  * Sets the actor's X coordinate, relative to its parent, in pixels.
9229  *
9230  * Overrides any layout manager and forces a fixed position for
9231  * the actor.
9232  *
9233  * The #ClutterActor:x property is animatable.
9234  *
9235  * Since: 0.6
9236  */
9237 void
9238 clutter_actor_set_x (ClutterActor *self,
9239                      gfloat        x)
9240 {
9241   const ClutterLayoutInfo *linfo;
9242
9243   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9244
9245   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9246
9247   if (clutter_actor_get_easing_duration (self) != 0)
9248     {
9249       ClutterTransition *transition;
9250
9251       transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9252       if (transition == NULL)
9253         {
9254           transition = _clutter_actor_create_transition (self,
9255                                                          obj_props[PROP_X],
9256                                                          linfo->fixed_x,
9257                                                          x);
9258
9259           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9260         }
9261       else
9262         _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9263
9264       clutter_actor_queue_relayout (self);
9265     }
9266   else
9267     clutter_actor_set_x_internal (self, x);
9268 }
9269
9270 /**
9271  * clutter_actor_set_y:
9272  * @self: a #ClutterActor
9273  * @y: the actor's position on the Y axis
9274  *
9275  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9276  *
9277  * Overrides any layout manager and forces a fixed position for
9278  * the actor.
9279  *
9280  * The #ClutterActor:y property is animatable.
9281  *
9282  * Since: 0.6
9283  */
9284 void
9285 clutter_actor_set_y (ClutterActor *self,
9286                      gfloat        y)
9287 {
9288   const ClutterLayoutInfo *linfo;
9289
9290   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9291
9292   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9293
9294   if (clutter_actor_get_easing_duration (self) != 0)
9295     {
9296       ClutterTransition *transition;
9297
9298       transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9299       if (transition == NULL)
9300         {
9301           transition = _clutter_actor_create_transition (self,
9302                                                          obj_props[PROP_Y],
9303                                                          linfo->fixed_y,
9304                                                          y);
9305
9306           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9307         }
9308       else
9309         _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9310
9311       clutter_actor_queue_relayout (self);
9312     }
9313   else
9314     clutter_actor_set_y_internal (self, y);
9315
9316   clutter_actor_queue_relayout (self);
9317 }
9318
9319 /**
9320  * clutter_actor_get_x:
9321  * @self: A #ClutterActor
9322  *
9323  * Retrieves the X coordinate of a #ClutterActor.
9324  *
9325  * This function tries to "do what you mean", by returning the
9326  * correct value depending on the actor's state.
9327  *
9328  * If the actor has a valid allocation, this function will return
9329  * the X coordinate of the origin of the allocation box.
9330  *
9331  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9332  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9333  * function will return that coordinate.
9334  *
9335  * If both the allocation and a fixed position are missing, this function
9336  * will return 0.
9337  *
9338  * Return value: the X coordinate, in pixels, ignoring any
9339  *   transformation (i.e. scaling, rotation)
9340  */
9341 gfloat
9342 clutter_actor_get_x (ClutterActor *self)
9343 {
9344   ClutterActorPrivate *priv;
9345
9346   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9347
9348   priv = self->priv;
9349
9350   if (priv->needs_allocation)
9351     {
9352       if (priv->position_set)
9353         {
9354           const ClutterLayoutInfo *info;
9355
9356           info = _clutter_actor_get_layout_info_or_defaults (self);
9357
9358           return info->fixed_x;
9359         }
9360       else
9361         return 0;
9362     }
9363   else
9364     return priv->allocation.x1;
9365 }
9366
9367 /**
9368  * clutter_actor_get_y:
9369  * @self: A #ClutterActor
9370  *
9371  * Retrieves the Y coordinate of a #ClutterActor.
9372  *
9373  * This function tries to "do what you mean", by returning the
9374  * correct value depending on the actor's state.
9375  *
9376  * If the actor has a valid allocation, this function will return
9377  * the Y coordinate of the origin of the allocation box.
9378  *
9379  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9380  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9381  * function will return that coordinate.
9382  *
9383  * If both the allocation and a fixed position are missing, this function
9384  * will return 0.
9385  *
9386  * Return value: the Y coordinate, in pixels, ignoring any
9387  *   transformation (i.e. scaling, rotation)
9388  */
9389 gfloat
9390 clutter_actor_get_y (ClutterActor *self)
9391 {
9392   ClutterActorPrivate *priv;
9393
9394   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9395
9396   priv = self->priv;
9397
9398   if (priv->needs_allocation)
9399     {
9400       if (priv->position_set)
9401         {
9402           const ClutterLayoutInfo *info;
9403
9404           info = _clutter_actor_get_layout_info_or_defaults (self);
9405
9406           return info->fixed_y;
9407         }
9408       else
9409         return 0;
9410     }
9411   else
9412     return priv->allocation.y1;
9413 }
9414
9415 /**
9416  * clutter_actor_set_scale:
9417  * @self: A #ClutterActor
9418  * @scale_x: double factor to scale actor by horizontally.
9419  * @scale_y: double factor to scale actor by vertically.
9420  *
9421  * Scales an actor with the given factors. The scaling is relative to
9422  * the scale center and the anchor point. The scale center is
9423  * unchanged by this function and defaults to 0,0.
9424  *
9425  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9426  * animatable.
9427  *
9428  * Since: 0.2
9429  */
9430 void
9431 clutter_actor_set_scale (ClutterActor *self,
9432                          gdouble       scale_x,
9433                          gdouble       scale_y)
9434 {
9435   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9436
9437   g_object_freeze_notify (G_OBJECT (self));
9438
9439   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9440   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9441
9442   g_object_thaw_notify (G_OBJECT (self));
9443 }
9444
9445 /**
9446  * clutter_actor_set_scale_full:
9447  * @self: A #ClutterActor
9448  * @scale_x: double factor to scale actor by horizontally.
9449  * @scale_y: double factor to scale actor by vertically.
9450  * @center_x: X coordinate of the center of the scale.
9451  * @center_y: Y coordinate of the center of the scale
9452  *
9453  * Scales an actor with the given factors around the given center
9454  * point. The center point is specified in pixels relative to the
9455  * anchor point (usually the top left corner of the actor).
9456  *
9457  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9458  * are animatable.
9459  *
9460  * Since: 1.0
9461  */
9462 void
9463 clutter_actor_set_scale_full (ClutterActor *self,
9464                               gdouble       scale_x,
9465                               gdouble       scale_y,
9466                               gfloat        center_x,
9467                               gfloat        center_y)
9468 {
9469   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9470
9471   g_object_freeze_notify (G_OBJECT (self));
9472
9473   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9474   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9475   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9476   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9477
9478   g_object_thaw_notify (G_OBJECT (self));
9479 }
9480
9481 /**
9482  * clutter_actor_set_scale_with_gravity:
9483  * @self: A #ClutterActor
9484  * @scale_x: double factor to scale actor by horizontally.
9485  * @scale_y: double factor to scale actor by vertically.
9486  * @gravity: the location of the scale center expressed as a compass
9487  * direction.
9488  *
9489  * Scales an actor with the given factors around the given
9490  * center point. The center point is specified as one of the compass
9491  * directions in #ClutterGravity. For example, setting it to north
9492  * will cause the top of the actor to remain unchanged and the rest of
9493  * the actor to expand left, right and downwards.
9494  *
9495  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9496  * animatable.
9497  *
9498  * Since: 1.0
9499  */
9500 void
9501 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9502                                       gdouble         scale_x,
9503                                       gdouble         scale_y,
9504                                       ClutterGravity  gravity)
9505 {
9506   ClutterTransformInfo *info;
9507   GObject *obj;
9508
9509   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9510
9511   obj = G_OBJECT (self);
9512
9513   g_object_freeze_notify (obj);
9514
9515   info = _clutter_actor_get_transform_info (self);
9516   info->scale_x = scale_x;
9517   info->scale_y = scale_y;
9518
9519   if (gravity == CLUTTER_GRAVITY_NONE)
9520     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9521   else
9522     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9523
9524   self->priv->transform_valid = FALSE;
9525
9526   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9527   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9528   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9529   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9530   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9531
9532   clutter_actor_queue_redraw (self);
9533
9534   g_object_thaw_notify (obj);
9535 }
9536
9537 /**
9538  * clutter_actor_get_scale:
9539  * @self: A #ClutterActor
9540  * @scale_x: (out) (allow-none): Location to store horizonal
9541  *   scale factor, or %NULL.
9542  * @scale_y: (out) (allow-none): Location to store vertical
9543  *   scale factor, or %NULL.
9544  *
9545  * Retrieves an actors scale factors.
9546  *
9547  * Since: 0.2
9548  */
9549 void
9550 clutter_actor_get_scale (ClutterActor *self,
9551                          gdouble      *scale_x,
9552                          gdouble      *scale_y)
9553 {
9554   const ClutterTransformInfo *info;
9555
9556   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9557
9558   info = _clutter_actor_get_transform_info_or_defaults (self);
9559
9560   if (scale_x)
9561     *scale_x = info->scale_x;
9562
9563   if (scale_y)
9564     *scale_y = info->scale_y;
9565 }
9566
9567 /**
9568  * clutter_actor_get_scale_center:
9569  * @self: A #ClutterActor
9570  * @center_x: (out) (allow-none): Location to store the X position
9571  *   of the scale center, or %NULL.
9572  * @center_y: (out) (allow-none): Location to store the Y position
9573  *   of the scale center, or %NULL.
9574  *
9575  * Retrieves the scale center coordinate in pixels relative to the top
9576  * left corner of the actor. If the scale center was specified using a
9577  * #ClutterGravity this will calculate the pixel offset using the
9578  * current size of the actor.
9579  *
9580  * Since: 1.0
9581  */
9582 void
9583 clutter_actor_get_scale_center (ClutterActor *self,
9584                                 gfloat       *center_x,
9585                                 gfloat       *center_y)
9586 {
9587   const ClutterTransformInfo *info;
9588
9589   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9590
9591   info = _clutter_actor_get_transform_info_or_defaults (self);
9592
9593   clutter_anchor_coord_get_units (self, &info->scale_center,
9594                                   center_x,
9595                                   center_y,
9596                                   NULL);
9597 }
9598
9599 /**
9600  * clutter_actor_get_scale_gravity:
9601  * @self: A #ClutterActor
9602  *
9603  * Retrieves the scale center as a compass direction. If the scale
9604  * center was specified in pixels or units this will return
9605  * %CLUTTER_GRAVITY_NONE.
9606  *
9607  * Return value: the scale gravity
9608  *
9609  * Since: 1.0
9610  */
9611 ClutterGravity
9612 clutter_actor_get_scale_gravity (ClutterActor *self)
9613 {
9614   const ClutterTransformInfo *info;
9615
9616   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9617
9618   info = _clutter_actor_get_transform_info_or_defaults (self);
9619
9620   return clutter_anchor_coord_get_gravity (&info->scale_center);
9621 }
9622
9623 static inline void
9624 clutter_actor_set_opacity_internal (ClutterActor *self,
9625                                     guint8        opacity)
9626 {
9627   ClutterActorPrivate *priv = self->priv;
9628
9629   if (priv->opacity != opacity)
9630     {
9631       priv->opacity = opacity;
9632
9633       /* Queue a redraw from the flatten effect so that it can use
9634          its cached image if available instead of having to redraw the
9635          actual actor. If it doesn't end up using the FBO then the
9636          effect is still able to continue the paint anyway. If there
9637          is no flatten effect yet then this is equivalent to queueing
9638          a full redraw */
9639       _clutter_actor_queue_redraw_full (self,
9640                                         0, /* flags */
9641                                         NULL, /* clip */
9642                                         priv->flatten_effect);
9643
9644       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9645     }
9646 }
9647
9648 /**
9649  * clutter_actor_set_opacity:
9650  * @self: A #ClutterActor
9651  * @opacity: New opacity value for the actor.
9652  *
9653  * Sets the actor's opacity, with zero being completely transparent and
9654  * 255 (0xff) being fully opaque.
9655  *
9656  * The #ClutterActor:opacity property is animatable.
9657  */
9658 void
9659 clutter_actor_set_opacity (ClutterActor *self,
9660                            guint8        opacity)
9661 {
9662   ClutterActorPrivate *priv;
9663
9664   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9665
9666   priv = self->priv;
9667
9668   if (clutter_actor_get_easing_duration (self) != 0)
9669     {
9670       ClutterTransition *transition;
9671
9672       transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9673       if (transition == NULL)
9674         {
9675           transition = _clutter_actor_create_transition (self,
9676                                                          obj_props[PROP_OPACITY],
9677                                                          priv->opacity,
9678                                                          opacity);
9679           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9680         }
9681       else
9682         _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9683
9684       clutter_actor_queue_redraw (self);
9685     }
9686   else
9687     clutter_actor_set_opacity_internal (self, opacity);
9688 }
9689
9690 /*
9691  * clutter_actor_get_paint_opacity_internal:
9692  * @self: a #ClutterActor
9693  *
9694  * Retrieves the absolute opacity of the actor, as it appears on the stage
9695  *
9696  * This function does not do type checks
9697  *
9698  * Return value: the absolute opacity of the actor
9699  */
9700 static guint8
9701 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9702 {
9703   ClutterActorPrivate *priv = self->priv;
9704   ClutterActor *parent;
9705
9706   /* override the top-level opacity to always be 255; even in
9707    * case of ClutterStage:use-alpha being TRUE we want the rest
9708    * of the scene to be painted
9709    */
9710   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9711     return 255;
9712
9713   if (priv->opacity_override >= 0)
9714     return priv->opacity_override;
9715
9716   parent = priv->parent;
9717
9718   /* Factor in the actual actors opacity with parents */
9719   if (parent != NULL)
9720     {
9721       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9722
9723       if (opacity != 0xff)
9724         return (opacity * priv->opacity) / 0xff;
9725     }
9726
9727   return priv->opacity;
9728
9729 }
9730
9731 /**
9732  * clutter_actor_get_paint_opacity:
9733  * @self: A #ClutterActor
9734  *
9735  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9736  *
9737  * This function traverses the hierarchy chain and composites the opacity of
9738  * the actor with that of its parents.
9739  *
9740  * This function is intended for subclasses to use in the paint virtual
9741  * function, to paint themselves with the correct opacity.
9742  *
9743  * Return value: The actor opacity value.
9744  *
9745  * Since: 0.8
9746  */
9747 guint8
9748 clutter_actor_get_paint_opacity (ClutterActor *self)
9749 {
9750   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9751
9752   return clutter_actor_get_paint_opacity_internal (self);
9753 }
9754
9755 /**
9756  * clutter_actor_get_opacity:
9757  * @self: a #ClutterActor
9758  *
9759  * Retrieves the opacity value of an actor, as set by
9760  * clutter_actor_set_opacity().
9761  *
9762  * For retrieving the absolute opacity of the actor inside a paint
9763  * virtual function, see clutter_actor_get_paint_opacity().
9764  *
9765  * Return value: the opacity of the actor
9766  */
9767 guint8
9768 clutter_actor_get_opacity (ClutterActor *self)
9769 {
9770   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9771
9772   return self->priv->opacity;
9773 }
9774
9775 /**
9776  * clutter_actor_set_offscreen_redirect:
9777  * @self: A #ClutterActor
9778  * @redirect: New offscreen redirect flags for the actor.
9779  *
9780  * Defines the circumstances where the actor should be redirected into
9781  * an offscreen image. The offscreen image is used to flatten the
9782  * actor into a single image while painting for two main reasons.
9783  * Firstly, when the actor is painted a second time without any of its
9784  * contents changing it can simply repaint the cached image without
9785  * descending further down the actor hierarchy. Secondly, it will make
9786  * the opacity look correct even if there are overlapping primitives
9787  * in the actor.
9788  *
9789  * Caching the actor could in some cases be a performance win and in
9790  * some cases be a performance lose so it is important to determine
9791  * which value is right for an actor before modifying this value. For
9792  * example, there is never any reason to flatten an actor that is just
9793  * a single texture (such as a #ClutterTexture) because it is
9794  * effectively already cached in an image so the offscreen would be
9795  * redundant. Also if the actor contains primitives that are far apart
9796  * with a large transparent area in the middle (such as a large
9797  * CluterGroup with a small actor in the top left and a small actor in
9798  * the bottom right) then the cached image will contain the entire
9799  * image of the large area and the paint will waste time blending all
9800  * of the transparent pixels in the middle.
9801  *
9802  * The default method of implementing opacity on a container simply
9803  * forwards on the opacity to all of the children. If the children are
9804  * overlapping then it will appear as if they are two separate glassy
9805  * objects and there will be a break in the color where they
9806  * overlap. By redirecting to an offscreen buffer it will be as if the
9807  * two opaque objects are combined into one and then made transparent
9808  * which is usually what is expected.
9809  *
9810  * The image below demonstrates the difference between redirecting and
9811  * not. The image shows two Clutter groups, each containing a red and
9812  * a green rectangle which overlap. The opacity on the group is set to
9813  * 128 (which is 50%). When the offscreen redirect is not used, the
9814  * red rectangle can be seen through the blue rectangle as if the two
9815  * rectangles were separately transparent. When the redirect is used
9816  * the group as a whole is transparent instead so the red rectangle is
9817  * not visible where they overlap.
9818  *
9819  * <figure id="offscreen-redirect">
9820  *   <title>Sample of using an offscreen redirect for transparency</title>
9821  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
9822  * </figure>
9823  *
9824  * The default value for this property is 0, so we effectively will
9825  * never redirect an actor offscreen by default. This means that there
9826  * are times that transparent actors may look glassy as described
9827  * above. The reason this is the default is because there is a
9828  * performance trade off between quality and performance here. In many
9829  * cases the default form of glassy opacity looks good enough, but if
9830  * it's not you will need to set the
9831  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9832  * redirection for opacity.
9833  *
9834  * Custom actors that don't contain any overlapping primitives are
9835  * recommended to override the has_overlaps() virtual to return %FALSE
9836  * for maximum efficiency.
9837  *
9838  * Since: 1.8
9839  */
9840 void
9841 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9842                                       ClutterOffscreenRedirect redirect)
9843 {
9844   ClutterActorPrivate *priv;
9845
9846   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9847
9848   priv = self->priv;
9849
9850   if (priv->offscreen_redirect != redirect)
9851     {
9852       priv->offscreen_redirect = redirect;
9853
9854       /* Queue a redraw from the effect so that it can use its cached
9855          image if available instead of having to redraw the actual
9856          actor. If it doesn't end up using the FBO then the effect is
9857          still able to continue the paint anyway. If there is no
9858          effect then this is equivalent to queuing a full redraw */
9859       _clutter_actor_queue_redraw_full (self,
9860                                         0, /* flags */
9861                                         NULL, /* clip */
9862                                         priv->flatten_effect);
9863
9864       g_object_notify_by_pspec (G_OBJECT (self),
9865                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
9866     }
9867 }
9868
9869 /**
9870  * clutter_actor_get_offscreen_redirect:
9871  * @self: a #ClutterActor
9872  *
9873  * Retrieves whether to redirect the actor to an offscreen buffer, as
9874  * set by clutter_actor_set_offscreen_redirect().
9875  *
9876  * Return value: the value of the offscreen-redirect property of the actor
9877  *
9878  * Since: 1.8
9879  */
9880 ClutterOffscreenRedirect
9881 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9882 {
9883   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9884
9885   return self->priv->offscreen_redirect;
9886 }
9887
9888 /**
9889  * clutter_actor_set_name:
9890  * @self: A #ClutterActor
9891  * @name: Textual tag to apply to actor
9892  *
9893  * Sets the given name to @self. The name can be used to identify
9894  * a #ClutterActor.
9895  */
9896 void
9897 clutter_actor_set_name (ClutterActor *self,
9898                         const gchar  *name)
9899 {
9900   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9901
9902   g_free (self->priv->name);
9903   self->priv->name = g_strdup (name);
9904
9905   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
9906 }
9907
9908 /**
9909  * clutter_actor_get_name:
9910  * @self: A #ClutterActor
9911  *
9912  * Retrieves the name of @self.
9913  *
9914  * Return value: the name of the actor, or %NULL. The returned string is
9915  *   owned by the actor and should not be modified or freed.
9916  */
9917 const gchar *
9918 clutter_actor_get_name (ClutterActor *self)
9919 {
9920   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9921
9922   return self->priv->name;
9923 }
9924
9925 /**
9926  * clutter_actor_get_gid:
9927  * @self: A #ClutterActor
9928  *
9929  * Retrieves the unique id for @self.
9930  *
9931  * Return value: Globally unique value for this object instance.
9932  *
9933  * Since: 0.6
9934  *
9935  * Deprecated: 1.8: The id is not used any longer.
9936  */
9937 guint32
9938 clutter_actor_get_gid (ClutterActor *self)
9939 {
9940   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9941
9942   return self->priv->id;
9943 }
9944
9945 static inline void
9946 clutter_actor_set_depth_internal (ClutterActor *self,
9947                                   float         depth)
9948 {
9949   ClutterTransformInfo *info;
9950
9951   info = _clutter_actor_get_transform_info (self);
9952
9953   if (info->depth != depth)
9954     {
9955       /* Sets Z value - XXX 2.0: should we invert? */
9956       info->depth = depth;
9957
9958       self->priv->transform_valid = FALSE;
9959
9960       /* FIXME - remove this crap; sadly, there are still containers
9961        * in Clutter that depend on this utter brain damage
9962        */
9963       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
9964
9965       clutter_actor_queue_redraw (self);
9966
9967       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
9968     }
9969 }
9970
9971 /**
9972  * clutter_actor_set_depth:
9973  * @self: a #ClutterActor
9974  * @depth: Z co-ord
9975  *
9976  * Sets the Z coordinate of @self to @depth.
9977  *
9978  * The unit used by @depth is dependant on the perspective setup. See
9979  * also clutter_stage_set_perspective().
9980  */
9981 void
9982 clutter_actor_set_depth (ClutterActor *self,
9983                          gfloat        depth)
9984 {
9985   const ClutterTransformInfo *tinfo;
9986
9987   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9988
9989   tinfo = _clutter_actor_get_transform_info_or_defaults (self);
9990
9991   if (clutter_actor_get_easing_duration (self) != 0)
9992     {
9993       ClutterTransition *transition;
9994
9995       transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
9996       if (transition == NULL)
9997         {
9998           transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
9999                                                          tinfo->depth,
10000                                                          depth);
10001           clutter_timeline_start (CLUTTER_TIMELINE (transition));
10002         }
10003       else
10004         _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10005
10006       clutter_actor_queue_redraw (self);
10007     }
10008   else
10009     clutter_actor_set_depth_internal (self, depth);
10010 }
10011
10012 /**
10013  * clutter_actor_get_depth:
10014  * @self: a #ClutterActor
10015  *
10016  * Retrieves the depth of @self.
10017  *
10018  * Return value: the depth of the actor
10019  */
10020 gfloat
10021 clutter_actor_get_depth (ClutterActor *self)
10022 {
10023   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10024
10025   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10026 }
10027
10028 /**
10029  * clutter_actor_set_rotation:
10030  * @self: a #ClutterActor
10031  * @axis: the axis of rotation
10032  * @angle: the angle of rotation
10033  * @x: X coordinate of the rotation center
10034  * @y: Y coordinate of the rotation center
10035  * @z: Z coordinate of the rotation center
10036  *
10037  * Sets the rotation angle of @self around the given axis.
10038  *
10039  * The rotation center coordinates used depend on the value of @axis:
10040  * <itemizedlist>
10041  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10042  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10043  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10044  * </itemizedlist>
10045  *
10046  * The rotation coordinates are relative to the anchor point of the
10047  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10048  * point is set, the upper left corner is assumed as the origin.
10049  *
10050  * Since: 0.8
10051  */
10052 void
10053 clutter_actor_set_rotation (ClutterActor      *self,
10054                             ClutterRotateAxis  axis,
10055                             gdouble            angle,
10056                             gfloat             x,
10057                             gfloat             y,
10058                             gfloat             z)
10059 {
10060   ClutterVertex v;
10061
10062   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10063
10064   v.x = x;
10065   v.y = y;
10066   v.z = z;
10067
10068   g_object_freeze_notify (G_OBJECT (self));
10069
10070   clutter_actor_set_rotation_angle (self, axis, angle);
10071   clutter_actor_set_rotation_center_internal (self, axis, &v);
10072
10073   g_object_thaw_notify (G_OBJECT (self));
10074 }
10075
10076 /**
10077  * clutter_actor_set_z_rotation_from_gravity:
10078  * @self: a #ClutterActor
10079  * @angle: the angle of rotation
10080  * @gravity: the center point of the rotation
10081  *
10082  * Sets the rotation angle of @self around the Z axis using the center
10083  * point specified as a compass point. For example to rotate such that
10084  * the center of the actor remains static you can use
10085  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10086  * will move accordingly.
10087  *
10088  * Since: 1.0
10089  */
10090 void
10091 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10092                                            gdouble         angle,
10093                                            ClutterGravity  gravity)
10094 {
10095   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10096
10097   if (gravity == CLUTTER_GRAVITY_NONE)
10098     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10099   else
10100     {
10101       GObject *obj = G_OBJECT (self);
10102       ClutterTransformInfo *info;
10103
10104       info = _clutter_actor_get_transform_info (self);
10105
10106       g_object_freeze_notify (obj);
10107
10108       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10109
10110       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10111       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10112       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10113
10114       g_object_thaw_notify (obj);
10115     }
10116 }
10117
10118 /**
10119  * clutter_actor_get_rotation:
10120  * @self: a #ClutterActor
10121  * @axis: the axis of rotation
10122  * @x: (out): return value for the X coordinate of the center of rotation
10123  * @y: (out): return value for the Y coordinate of the center of rotation
10124  * @z: (out): return value for the Z coordinate of the center of rotation
10125  *
10126  * Retrieves the angle and center of rotation on the given axis,
10127  * set using clutter_actor_set_rotation().
10128  *
10129  * Return value: the angle of rotation
10130  *
10131  * Since: 0.8
10132  */
10133 gdouble
10134 clutter_actor_get_rotation (ClutterActor      *self,
10135                             ClutterRotateAxis  axis,
10136                             gfloat            *x,
10137                             gfloat            *y,
10138                             gfloat            *z)
10139 {
10140   const ClutterTransformInfo *info;
10141   const AnchorCoord *anchor_coord;
10142   gdouble retval = 0;
10143
10144   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10145
10146   info = _clutter_actor_get_transform_info_or_defaults (self);
10147
10148   switch (axis)
10149     {
10150     case CLUTTER_X_AXIS:
10151       anchor_coord = &info->rx_center;
10152       retval = info->rx_angle;
10153       break;
10154
10155     case CLUTTER_Y_AXIS:
10156       anchor_coord = &info->ry_center;
10157       retval = info->ry_angle;
10158       break;
10159
10160     case CLUTTER_Z_AXIS:
10161       anchor_coord = &info->rz_center;
10162       retval = info->rz_angle;
10163       break;
10164
10165     default:
10166       anchor_coord = NULL;
10167       retval = 0.0;
10168       break;
10169     }
10170
10171   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10172
10173   return retval;
10174 }
10175
10176 /**
10177  * clutter_actor_get_z_rotation_gravity:
10178  * @self: A #ClutterActor
10179  *
10180  * Retrieves the center for the rotation around the Z axis as a
10181  * compass direction. If the center was specified in pixels or units
10182  * this will return %CLUTTER_GRAVITY_NONE.
10183  *
10184  * Return value: the Z rotation center
10185  *
10186  * Since: 1.0
10187  */
10188 ClutterGravity
10189 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10190 {
10191   const ClutterTransformInfo *info;
10192
10193   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10194
10195   info = _clutter_actor_get_transform_info_or_defaults (self);
10196
10197   return clutter_anchor_coord_get_gravity (&info->rz_center);
10198 }
10199
10200 /**
10201  * clutter_actor_set_clip:
10202  * @self: A #ClutterActor
10203  * @xoff: X offset of the clip rectangle
10204  * @yoff: Y offset of the clip rectangle
10205  * @width: Width of the clip rectangle
10206  * @height: Height of the clip rectangle
10207  *
10208  * Sets clip area for @self. The clip area is always computed from the
10209  * upper left corner of the actor, even if the anchor point is set
10210  * otherwise.
10211  *
10212  * Since: 0.6
10213  */
10214 void
10215 clutter_actor_set_clip (ClutterActor *self,
10216                         gfloat        xoff,
10217                         gfloat        yoff,
10218                         gfloat        width,
10219                         gfloat        height)
10220 {
10221   ClutterActorPrivate *priv;
10222
10223   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10224
10225   priv = self->priv;
10226
10227   if (priv->has_clip &&
10228       priv->clip.x == xoff &&
10229       priv->clip.y == yoff &&
10230       priv->clip.width == width &&
10231       priv->clip.height == height)
10232     return;
10233
10234   priv->clip.x = xoff;
10235   priv->clip.y = yoff;
10236   priv->clip.width = width;
10237   priv->clip.height = height;
10238
10239   priv->has_clip = TRUE;
10240
10241   clutter_actor_queue_redraw (self);
10242
10243   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10244   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10245 }
10246
10247 /**
10248  * clutter_actor_remove_clip:
10249  * @self: A #ClutterActor
10250  *
10251  * Removes clip area from @self.
10252  */
10253 void
10254 clutter_actor_remove_clip (ClutterActor *self)
10255 {
10256   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10257
10258   if (!self->priv->has_clip)
10259     return;
10260
10261   self->priv->has_clip = FALSE;
10262
10263   clutter_actor_queue_redraw (self);
10264
10265   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10266 }
10267
10268 /**
10269  * clutter_actor_has_clip:
10270  * @self: a #ClutterActor
10271  *
10272  * Determines whether the actor has a clip area set or not.
10273  *
10274  * Return value: %TRUE if the actor has a clip area set.
10275  *
10276  * Since: 0.1.1
10277  */
10278 gboolean
10279 clutter_actor_has_clip (ClutterActor *self)
10280 {
10281   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10282
10283   return self->priv->has_clip;
10284 }
10285
10286 /**
10287  * clutter_actor_get_clip:
10288  * @self: a #ClutterActor
10289  * @xoff: (out) (allow-none): return location for the X offset of
10290  *   the clip rectangle, or %NULL
10291  * @yoff: (out) (allow-none): return location for the Y offset of
10292  *   the clip rectangle, or %NULL
10293  * @width: (out) (allow-none): return location for the width of
10294  *   the clip rectangle, or %NULL
10295  * @height: (out) (allow-none): return location for the height of
10296  *   the clip rectangle, or %NULL
10297  *
10298  * Gets the clip area for @self, if any is set
10299  *
10300  * Since: 0.6
10301  */
10302 void
10303 clutter_actor_get_clip (ClutterActor *self,
10304                         gfloat       *xoff,
10305                         gfloat       *yoff,
10306                         gfloat       *width,
10307                         gfloat       *height)
10308 {
10309   ClutterActorPrivate *priv;
10310
10311   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10312
10313   priv = self->priv;
10314
10315   if (!priv->has_clip)
10316     return;
10317
10318   if (xoff != NULL)
10319     *xoff = priv->clip.x;
10320
10321   if (yoff != NULL)
10322     *yoff = priv->clip.y;
10323
10324   if (width != NULL)
10325     *width = priv->clip.width;
10326
10327   if (height != NULL)
10328     *height = priv->clip.height;
10329 }
10330
10331 /**
10332  * clutter_actor_get_children:
10333  * @self: a #ClutterActor
10334  *
10335  * Retrieves the list of children of @self.
10336  *
10337  * Return value: (transfer container) (element-type ClutterActor): A newly
10338  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10339  *   done.
10340  *
10341  * Since: 1.10
10342  */
10343 GList *
10344 clutter_actor_get_children (ClutterActor *self)
10345 {
10346   ClutterActor *iter;
10347   GList *res;
10348
10349   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10350
10351   /* we walk the list backward so that we can use prepend(),
10352    * which is O(1)
10353    */
10354   for (iter = self->priv->last_child, res = NULL;
10355        iter != NULL;
10356        iter = iter->priv->prev_sibling)
10357     {
10358       res = g_list_prepend (res, iter);
10359     }
10360
10361   return res;
10362 }
10363
10364 /*< private >
10365  * insert_child_at_depth:
10366  * @self: a #ClutterActor
10367  * @child: a #ClutterActor
10368  *
10369  * Inserts @child inside the list of children held by @self, using
10370  * the depth as the insertion criteria.
10371  *
10372  * This sadly makes the insertion not O(1), but we can keep the
10373  * list sorted so that the painters algorithm we use for painting
10374  * the children will work correctly.
10375  */
10376 static void
10377 insert_child_at_depth (ClutterActor *self,
10378                        ClutterActor *child,
10379                        gpointer      dummy G_GNUC_UNUSED)
10380 {
10381   ClutterActor *iter;
10382   float child_depth;
10383
10384   child->priv->parent = self;
10385
10386   child_depth =
10387     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10388
10389   /* special-case the first child */
10390   if (self->priv->n_children == 0)
10391     {
10392       self->priv->first_child = child;
10393       self->priv->last_child = child;
10394
10395       child->priv->next_sibling = NULL;
10396       child->priv->prev_sibling = NULL;
10397
10398       return;
10399     }
10400
10401   /* Find the right place to insert the child so that it will still be
10402      sorted and the child will be after all of the actors at the same
10403      dept */
10404   for (iter = self->priv->first_child;
10405        iter != NULL;
10406        iter = iter->priv->next_sibling)
10407     {
10408       float iter_depth;
10409
10410       iter_depth =
10411         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10412
10413       if (iter_depth > child_depth)
10414         break;
10415     }
10416
10417   if (iter != NULL)
10418     {
10419       ClutterActor *tmp = iter->priv->prev_sibling;
10420
10421       if (tmp != NULL)
10422         tmp->priv->next_sibling = child;
10423
10424       /* Insert the node before the found one */
10425       child->priv->prev_sibling = iter->priv->prev_sibling;
10426       child->priv->next_sibling = iter;
10427       iter->priv->prev_sibling = child;
10428     }
10429   else
10430     {
10431       ClutterActor *tmp = self->priv->last_child;
10432
10433       if (tmp != NULL)
10434         tmp->priv->next_sibling = child;
10435
10436       /* insert the node at the end of the list */
10437       child->priv->prev_sibling = self->priv->last_child;
10438       child->priv->next_sibling = NULL;
10439     }
10440
10441   if (child->priv->prev_sibling == NULL)
10442     self->priv->first_child = child;
10443
10444   if (child->priv->next_sibling == NULL)
10445     self->priv->last_child = child;
10446 }
10447
10448 static void
10449 insert_child_at_index (ClutterActor *self,
10450                        ClutterActor *child,
10451                        gpointer      data_)
10452 {
10453   gint index_ = GPOINTER_TO_INT (data_);
10454
10455   child->priv->parent = self;
10456
10457   if (index_ == 0)
10458     {
10459       ClutterActor *tmp = self->priv->first_child;
10460
10461       if (tmp != NULL)
10462         tmp->priv->prev_sibling = child;
10463
10464       child->priv->prev_sibling = NULL;
10465       child->priv->next_sibling = tmp;
10466     }
10467   else if (index_ < 0 || index_ >= self->priv->n_children)
10468     {
10469       ClutterActor *tmp = self->priv->last_child;
10470
10471       if (tmp != NULL)
10472         tmp->priv->next_sibling = child;
10473
10474       child->priv->prev_sibling = tmp;
10475       child->priv->next_sibling = NULL;
10476     }
10477   else
10478     {
10479       ClutterActor *iter;
10480       int i;
10481
10482       for (iter = self->priv->first_child, i = 0;
10483            iter != NULL;
10484            iter = iter->priv->next_sibling, i += 1)
10485         {
10486           if (index_ == i)
10487             {
10488               ClutterActor *tmp = iter->priv->prev_sibling;
10489
10490               child->priv->prev_sibling = tmp;
10491               child->priv->next_sibling = iter;
10492
10493               iter->priv->prev_sibling = child;
10494
10495               if (tmp != NULL)
10496                 tmp->priv->next_sibling = child;
10497
10498               break;
10499             }
10500         }
10501     }
10502
10503   if (child->priv->prev_sibling == NULL)
10504     self->priv->first_child = child;
10505
10506   if (child->priv->next_sibling == NULL)
10507     self->priv->last_child = child;
10508 }
10509
10510 static void
10511 insert_child_above (ClutterActor *self,
10512                     ClutterActor *child,
10513                     gpointer      data)
10514 {
10515   ClutterActor *sibling = data;
10516
10517   child->priv->parent = self;
10518
10519   if (sibling == NULL)
10520     sibling = self->priv->last_child;
10521
10522   child->priv->prev_sibling = sibling;
10523
10524   if (sibling != NULL)
10525     {
10526       ClutterActor *tmp = sibling->priv->next_sibling;
10527
10528       child->priv->next_sibling = tmp;
10529
10530       if (tmp != NULL)
10531         tmp->priv->prev_sibling = child;
10532
10533       sibling->priv->next_sibling = child;
10534     }
10535   else
10536     child->priv->next_sibling = NULL;
10537
10538   if (child->priv->prev_sibling == NULL)
10539     self->priv->first_child = child;
10540
10541   if (child->priv->next_sibling == NULL)
10542     self->priv->last_child = child;
10543 }
10544
10545 static void
10546 insert_child_below (ClutterActor *self,
10547                     ClutterActor *child,
10548                     gpointer      data)
10549 {
10550   ClutterActor *sibling = data;
10551
10552   child->priv->parent = self;
10553
10554   if (sibling == NULL)
10555     sibling = self->priv->first_child;
10556
10557   child->priv->next_sibling = sibling;
10558
10559   if (sibling != NULL)
10560     {
10561       ClutterActor *tmp = sibling->priv->prev_sibling;
10562
10563       child->priv->prev_sibling = tmp;
10564
10565       if (tmp != NULL)
10566         tmp->priv->next_sibling = child;
10567
10568       sibling->priv->prev_sibling = child;
10569     }
10570   else
10571     child->priv->prev_sibling = NULL;
10572
10573   if (child->priv->prev_sibling == NULL)
10574     self->priv->first_child = child;
10575
10576   if (child->priv->next_sibling == NULL)
10577     self->priv->last_child = child;
10578 }
10579
10580 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10581                                            ClutterActor *child,
10582                                            gpointer      data);
10583
10584 typedef enum {
10585   ADD_CHILD_CREATE_META       = 1 << 0,
10586   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10587   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10588   ADD_CHILD_CHECK_STATE       = 1 << 3,
10589   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10590
10591   /* default flags for public API */
10592   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10593                                ADD_CHILD_EMIT_PARENT_SET |
10594                                ADD_CHILD_EMIT_ACTOR_ADDED |
10595                                ADD_CHILD_CHECK_STATE |
10596                                ADD_CHILD_NOTIFY_FIRST_LAST,
10597
10598   /* flags for legacy/deprecated API */
10599   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10600                                ADD_CHILD_CHECK_STATE |
10601                                ADD_CHILD_NOTIFY_FIRST_LAST
10602 } ClutterActorAddChildFlags;
10603
10604 /*< private >
10605  * clutter_actor_add_child_internal:
10606  * @self: a #ClutterActor
10607  * @child: a #ClutterActor
10608  * @flags: control flags for actions
10609  * @add_func: delegate function
10610  * @data: (closure): data to pass to @add_func
10611  *
10612  * Adds @child to the list of children of @self.
10613  *
10614  * The actual insertion inside the list is delegated to @add_func: this
10615  * function will just set up the state, perform basic checks, and emit
10616  * signals.
10617  *
10618  * The @flags argument is used to perform additional operations.
10619  */
10620 static inline void
10621 clutter_actor_add_child_internal (ClutterActor              *self,
10622                                   ClutterActor              *child,
10623                                   ClutterActorAddChildFlags  flags,
10624                                   ClutterActorAddChildFunc   add_func,
10625                                   gpointer                   data)
10626 {
10627   ClutterTextDirection text_dir;
10628   gboolean create_meta;
10629   gboolean emit_parent_set, emit_actor_added;
10630   gboolean check_state;
10631   gboolean notify_first_last;
10632   ClutterActor *old_first_child, *old_last_child;
10633
10634   if (child->priv->parent != NULL)
10635     {
10636       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10637                  "use clutter_actor_remove_child() first.",
10638                  _clutter_actor_get_debug_name (child),
10639                  _clutter_actor_get_debug_name (child->priv->parent));
10640       return;
10641     }
10642
10643   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10644     {
10645       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10646                  "a child of another actor.",
10647                  _clutter_actor_get_debug_name (child));
10648       return;
10649     }
10650
10651 #if 0
10652   /* XXX - this check disallows calling methods that change the stacking
10653    * order within the destruction sequence, by triggering a critical
10654    * warning first, and leaving the actor in an undefined state, which
10655    * then ends up being caught by an assertion.
10656    *
10657    * the reproducible sequence is:
10658    *
10659    *   - actor gets destroyed;
10660    *   - another actor, linked to the first, will try to change the
10661    *     stacking order of the first actor;
10662    *   - changing the stacking order is a composite operation composed
10663    *     by the following steps:
10664    *     1. ref() the child;
10665    *     2. remove_child_internal(), which removes the reference;
10666    *     3. add_child_internal(), which adds a reference;
10667    *   - the state of the actor is not changed between (2) and (3), as
10668    *     it could be an expensive recomputation;
10669    *   - if (3) bails out, then the actor is in an undefined state, but
10670    *     still alive;
10671    *   - the destruction sequence terminates, but the actor is unparented
10672    *     while its state indicates being parented instead.
10673    *   - assertion failure.
10674    *
10675    * the obvious fix would be to decompose each set_child_*_sibling()
10676    * method into proper remove_child()/add_child(), with state validation;
10677    * this may cause excessive work, though, and trigger a cascade of other
10678    * bugs in code that assumes that a change in the stacking order is an
10679    * atomic operation.
10680    *
10681    * another potential fix is to just remove this check here, and let
10682    * code doing stacking order changes inside the destruction sequence
10683    * of an actor continue doing the work.
10684    *
10685    * the third fix is to silently bail out early from every
10686    * set_child_*_sibling() and set_child_at_index() method, and avoid
10687    * doing work.
10688    *
10689    * I have a preference for the second solution, since it involves the
10690    * least amount of work, and the least amount of code duplication.
10691    *
10692    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10693    */
10694   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10695     {
10696       g_warning ("The actor '%s' is currently being destroyed, and "
10697                  "cannot be added as a child of another actor.",
10698                  _clutter_actor_get_debug_name (child));
10699       return;
10700     }
10701 #endif
10702
10703   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10704   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10705   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10706   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10707   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10708
10709   old_first_child = self->priv->first_child;
10710   old_last_child = self->priv->last_child;
10711
10712   g_object_freeze_notify (G_OBJECT (self));
10713
10714   if (create_meta)
10715     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10716
10717   g_object_ref_sink (child);
10718   child->priv->parent = NULL;
10719   child->priv->next_sibling = NULL;
10720   child->priv->prev_sibling = NULL;
10721
10722   /* delegate the actual insertion */
10723   add_func (self, child, data);
10724
10725   g_assert (child->priv->parent == self);
10726
10727   self->priv->n_children += 1;
10728
10729   self->priv->age += 1;
10730
10731   /* if push_internal() has been called then we automatically set
10732    * the flag on the actor
10733    */
10734   if (self->priv->internal_child)
10735     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10736
10737   /* clutter_actor_reparent() will emit ::parent-set for us */
10738   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10739     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10740
10741   if (check_state)
10742     {
10743       /* If parent is mapped or realized, we need to also be mapped or
10744        * realized once we're inside the parent.
10745        */
10746       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10747
10748       /* propagate the parent's text direction to the child */
10749       text_dir = clutter_actor_get_text_direction (self);
10750       clutter_actor_set_text_direction (child, text_dir);
10751     }
10752
10753   if (child->priv->show_on_set_parent)
10754     clutter_actor_show (child);
10755
10756   if (CLUTTER_ACTOR_IS_MAPPED (child))
10757     clutter_actor_queue_redraw (child);
10758
10759   /* maintain the invariant that if an actor needs layout,
10760    * its parents do as well
10761    */
10762   if (child->priv->needs_width_request ||
10763       child->priv->needs_height_request ||
10764       child->priv->needs_allocation)
10765     {
10766       /* we work around the short-circuiting we do
10767        * in clutter_actor_queue_relayout() since we
10768        * want to force a relayout
10769        */
10770       child->priv->needs_width_request = TRUE;
10771       child->priv->needs_height_request = TRUE;
10772       child->priv->needs_allocation = TRUE;
10773
10774       clutter_actor_queue_relayout (child->priv->parent);
10775     }
10776
10777   if (emit_actor_added)
10778     g_signal_emit_by_name (self, "actor-added", child);
10779
10780   if (notify_first_last)
10781     {
10782       if (old_first_child != self->priv->first_child)
10783         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10784
10785       if (old_last_child != self->priv->last_child)
10786         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10787     }
10788
10789   g_object_thaw_notify (G_OBJECT (self));
10790 }
10791
10792 /**
10793  * clutter_actor_add_child:
10794  * @self: a #ClutterActor
10795  * @child: a #ClutterActor
10796  *
10797  * Adds @child to the children of @self.
10798  *
10799  * This function will acquire a reference on @child that will only
10800  * be released when calling clutter_actor_remove_child().
10801  *
10802  * This function will take into consideration the #ClutterActor:depth
10803  * of @child, and will keep the list of children sorted.
10804  *
10805  * This function will emit the #ClutterContainer::actor-added signal
10806  * on @self.
10807  *
10808  * Since: 1.10
10809  */
10810 void
10811 clutter_actor_add_child (ClutterActor *self,
10812                          ClutterActor *child)
10813 {
10814   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10815   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10816   g_return_if_fail (self != child);
10817   g_return_if_fail (child->priv->parent == NULL);
10818
10819   clutter_actor_add_child_internal (self, child,
10820                                     ADD_CHILD_DEFAULT_FLAGS,
10821                                     insert_child_at_depth,
10822                                     NULL);
10823 }
10824
10825 /**
10826  * clutter_actor_insert_child_at_index:
10827  * @self: a #ClutterActor
10828  * @child: a #ClutterActor
10829  * @index_: the index
10830  *
10831  * Inserts @child into the list of children of @self, using the
10832  * given @index_. If @index_ is greater than the number of children
10833  * in @self, or is less than 0, then the new child is added at the end.
10834  *
10835  * This function will acquire a reference on @child that will only
10836  * be released when calling clutter_actor_remove_child().
10837  *
10838  * This function will not take into consideration the #ClutterActor:depth
10839  * of @child.
10840  *
10841  * This function will emit the #ClutterContainer::actor-added signal
10842  * on @self.
10843  *
10844  * Since: 1.10
10845  */
10846 void
10847 clutter_actor_insert_child_at_index (ClutterActor *self,
10848                                      ClutterActor *child,
10849                                      gint          index_)
10850 {
10851   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10852   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10853   g_return_if_fail (self != child);
10854   g_return_if_fail (child->priv->parent == NULL);
10855
10856   clutter_actor_add_child_internal (self, child,
10857                                     ADD_CHILD_DEFAULT_FLAGS,
10858                                     insert_child_at_index,
10859                                     GINT_TO_POINTER (index_));
10860 }
10861
10862 /**
10863  * clutter_actor_insert_child_above:
10864  * @self: a #ClutterActor
10865  * @child: a #ClutterActor
10866  * @sibling: (allow-none): a child of @self, or %NULL
10867  *
10868  * Inserts @child into the list of children of @self, above another
10869  * child of @self or, if @sibling is %NULL, above all the children
10870  * of @self.
10871  *
10872  * This function will acquire a reference on @child that will only
10873  * be released when calling clutter_actor_remove_child().
10874  *
10875  * This function will not take into consideration the #ClutterActor:depth
10876  * of @child.
10877  *
10878  * This function will emit the #ClutterContainer::actor-added signal
10879  * on @self.
10880  *
10881  * Since: 1.10
10882  */
10883 void
10884 clutter_actor_insert_child_above (ClutterActor *self,
10885                                   ClutterActor *child,
10886                                   ClutterActor *sibling)
10887 {
10888   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10889   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10890   g_return_if_fail (self != child);
10891   g_return_if_fail (child != sibling);
10892   g_return_if_fail (child->priv->parent == NULL);
10893   g_return_if_fail (sibling == NULL ||
10894                     (CLUTTER_IS_ACTOR (sibling) &&
10895                      sibling->priv->parent == self));
10896
10897   clutter_actor_add_child_internal (self, child,
10898                                     ADD_CHILD_DEFAULT_FLAGS,
10899                                     insert_child_above,
10900                                     sibling);
10901 }
10902
10903 /**
10904  * clutter_actor_insert_child_below:
10905  * @self: a #ClutterActor
10906  * @child: a #ClutterActor
10907  * @sibling: (allow-none): a child of @self, or %NULL
10908  *
10909  * Inserts @child into the list of children of @self, below another
10910  * child of @self or, if @sibling is %NULL, below all the children
10911  * of @self.
10912  *
10913  * This function will acquire a reference on @child that will only
10914  * be released when calling clutter_actor_remove_child().
10915  *
10916  * This function will not take into consideration the #ClutterActor:depth
10917  * of @child.
10918  *
10919  * This function will emit the #ClutterContainer::actor-added signal
10920  * on @self.
10921  *
10922  * Since: 1.10
10923  */
10924 void
10925 clutter_actor_insert_child_below (ClutterActor *self,
10926                                   ClutterActor *child,
10927                                   ClutterActor *sibling)
10928 {
10929   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10930   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10931   g_return_if_fail (self != child);
10932   g_return_if_fail (child != sibling);
10933   g_return_if_fail (child->priv->parent == NULL);
10934   g_return_if_fail (sibling == NULL ||
10935                     (CLUTTER_IS_ACTOR (sibling) &&
10936                      sibling->priv->parent == self));
10937
10938   clutter_actor_add_child_internal (self, child,
10939                                     ADD_CHILD_DEFAULT_FLAGS,
10940                                     insert_child_below,
10941                                     sibling);
10942 }
10943
10944 /**
10945  * clutter_actor_set_parent:
10946  * @self: A #ClutterActor
10947  * @parent: A new #ClutterActor parent
10948  *
10949  * Sets the parent of @self to @parent.
10950  *
10951  * This function will result in @parent acquiring a reference on @self,
10952  * eventually by sinking its floating reference first. The reference
10953  * will be released by clutter_actor_unparent().
10954  *
10955  * This function should only be called by legacy #ClutterActor<!-- -->s
10956  * implementing the #ClutterContainer interface.
10957  *
10958  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
10959  */
10960 void
10961 clutter_actor_set_parent (ClutterActor *self,
10962                           ClutterActor *parent)
10963 {
10964   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10965   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
10966   g_return_if_fail (self != parent);
10967   g_return_if_fail (self->priv->parent == NULL);
10968
10969   /* as this function will be called inside ClutterContainer::add
10970    * implementations or when building up a composite actor, we have
10971    * to preserve the old behaviour, and not create child meta or
10972    * emit the ::actor-added signal, to avoid recursion or double
10973    * emissions
10974    */
10975   clutter_actor_add_child_internal (parent, self,
10976                                     ADD_CHILD_LEGACY_FLAGS,
10977                                     insert_child_at_depth,
10978                                     NULL);
10979 }
10980
10981 /**
10982  * clutter_actor_get_parent:
10983  * @self: A #ClutterActor
10984  *
10985  * Retrieves the parent of @self.
10986  *
10987  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
10988  *  if no parent is set
10989  */
10990 ClutterActor *
10991 clutter_actor_get_parent (ClutterActor *self)
10992 {
10993   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10994
10995   return self->priv->parent;
10996 }
10997
10998 /**
10999  * clutter_actor_get_paint_visibility:
11000  * @self: A #ClutterActor
11001  *
11002  * Retrieves the 'paint' visibility of an actor recursively checking for non
11003  * visible parents.
11004  *
11005  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11006  *
11007  * Return Value: %TRUE if the actor is visibile and will be painted.
11008  *
11009  * Since: 0.8.4
11010  */
11011 gboolean
11012 clutter_actor_get_paint_visibility (ClutterActor *actor)
11013 {
11014   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11015
11016   return CLUTTER_ACTOR_IS_MAPPED (actor);
11017 }
11018
11019 /**
11020  * clutter_actor_remove_child:
11021  * @self: a #ClutterActor
11022  * @child: a #ClutterActor
11023  *
11024  * Removes @child from the children of @self.
11025  *
11026  * This function will release the reference added by
11027  * clutter_actor_add_child(), so if you want to keep using @child
11028  * you will have to acquire a referenced on it before calling this
11029  * function.
11030  *
11031  * This function will emit the #ClutterContainer::actor-removed
11032  * signal on @self.
11033  *
11034  * Since: 1.10
11035  */
11036 void
11037 clutter_actor_remove_child (ClutterActor *self,
11038                             ClutterActor *child)
11039 {
11040   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11041   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11042   g_return_if_fail (self != child);
11043   g_return_if_fail (child->priv->parent != NULL);
11044   g_return_if_fail (child->priv->parent == self);
11045
11046   clutter_actor_remove_child_internal (self, child,
11047                                        REMOVE_CHILD_DEFAULT_FLAGS);
11048 }
11049
11050 /**
11051  * clutter_actor_remove_all_children:
11052  * @self: a #ClutterActor
11053  *
11054  * Removes all children of @self.
11055  *
11056  * This function releases the reference added by inserting a child actor
11057  * in the list of children of @self.
11058  *
11059  * If the reference count of a child drops to zero, the child will be
11060  * destroyed. If you want to ensure the destruction of all the children
11061  * of @self, use clutter_actor_destroy_all_children().
11062  *
11063  * Since: 1.10
11064  */
11065 void
11066 clutter_actor_remove_all_children (ClutterActor *self)
11067 {
11068   ClutterActorIter iter;
11069
11070   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11071
11072   if (self->priv->n_children == 0)
11073     return;
11074
11075   g_object_freeze_notify (G_OBJECT (self));
11076
11077   clutter_actor_iter_init (&iter, self);
11078   while (clutter_actor_iter_next (&iter, NULL))
11079     clutter_actor_iter_remove (&iter);
11080
11081   g_object_thaw_notify (G_OBJECT (self));
11082
11083   /* sanity check */
11084   g_assert (self->priv->first_child == NULL);
11085   g_assert (self->priv->last_child == NULL);
11086   g_assert (self->priv->n_children == 0);
11087 }
11088
11089 /**
11090  * clutter_actor_destroy_all_children:
11091  * @self: a #ClutterActor
11092  *
11093  * Destroys all children of @self.
11094  *
11095  * This function releases the reference added by inserting a child
11096  * actor in the list of children of @self, and ensures that the
11097  * #ClutterActor::destroy signal is emitted on each child of the
11098  * actor.
11099  *
11100  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11101  * when its reference count drops to 0; the default handler of the
11102  * #ClutterActor::destroy signal will destroy all the children of an
11103  * actor. This function ensures that all children are destroyed, instead
11104  * of just removed from @self, unlike clutter_actor_remove_all_children()
11105  * which will merely release the reference and remove each child.
11106  *
11107  * Unless you acquired an additional reference on each child of @self
11108  * prior to calling clutter_actor_remove_all_children() and want to reuse
11109  * the actors, you should use clutter_actor_destroy_all_children() in
11110  * order to make sure that children are destroyed and signal handlers
11111  * are disconnected even in cases where circular references prevent this
11112  * from automatically happening through reference counting alone.
11113  *
11114  * Since: 1.10
11115  */
11116 void
11117 clutter_actor_destroy_all_children (ClutterActor *self)
11118 {
11119   ClutterActorIter iter;
11120
11121   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11122
11123   if (self->priv->n_children == 0)
11124     return;
11125
11126   g_object_freeze_notify (G_OBJECT (self));
11127
11128   clutter_actor_iter_init (&iter, self);
11129   while (clutter_actor_iter_next (&iter, NULL))
11130     clutter_actor_iter_destroy (&iter);
11131
11132   g_object_thaw_notify (G_OBJECT (self));
11133
11134   /* sanity check */
11135   g_assert (self->priv->first_child == NULL);
11136   g_assert (self->priv->last_child == NULL);
11137   g_assert (self->priv->n_children == 0);
11138 }
11139
11140 typedef struct _InsertBetweenData {
11141   ClutterActor *prev_sibling;
11142   ClutterActor *next_sibling;
11143 } InsertBetweenData;
11144
11145 static void
11146 insert_child_between (ClutterActor *self,
11147                       ClutterActor *child,
11148                       gpointer      data_)
11149 {
11150   InsertBetweenData *data = data_;
11151   ClutterActor *prev_sibling = data->prev_sibling;
11152   ClutterActor *next_sibling = data->next_sibling;
11153
11154   child->priv->parent = self;
11155   child->priv->prev_sibling = prev_sibling;
11156   child->priv->next_sibling = next_sibling;
11157
11158   if (prev_sibling != NULL)
11159     prev_sibling->priv->next_sibling = child;
11160
11161   if (next_sibling != NULL)
11162     next_sibling->priv->prev_sibling = child;
11163
11164   if (child->priv->prev_sibling == NULL)
11165     self->priv->first_child = child;
11166
11167   if (child->priv->next_sibling == NULL)
11168     self->priv->last_child = child;
11169 }
11170
11171 /**
11172  * clutter_actor_replace_child:
11173  * @self: a #ClutterActor
11174  * @old_child: the child of @self to replace
11175  * @new_child: the #ClutterActor to replace @old_child
11176  *
11177  * Replaces @old_child with @new_child in the list of children of @self.
11178  *
11179  * Since: 1.10
11180  */
11181 void
11182 clutter_actor_replace_child (ClutterActor *self,
11183                              ClutterActor *old_child,
11184                              ClutterActor *new_child)
11185 {
11186   ClutterActor *prev_sibling, *next_sibling;
11187   InsertBetweenData clos;
11188
11189   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11190   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11191   g_return_if_fail (old_child->priv->parent == self);
11192   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11193   g_return_if_fail (old_child != new_child);
11194   g_return_if_fail (new_child != self);
11195   g_return_if_fail (new_child->priv->parent == NULL);
11196
11197   prev_sibling = old_child->priv->prev_sibling;
11198   next_sibling = old_child->priv->next_sibling;
11199   clutter_actor_remove_child_internal (self, old_child,
11200                                        REMOVE_CHILD_DEFAULT_FLAGS);
11201
11202   clos.prev_sibling = prev_sibling;
11203   clos.next_sibling = next_sibling;
11204   clutter_actor_add_child_internal (self, new_child,
11205                                     ADD_CHILD_DEFAULT_FLAGS,
11206                                     insert_child_between,
11207                                     &clos);
11208 }
11209
11210 /**
11211  * clutter_actor_unparent:
11212  * @self: a #ClutterActor
11213  *
11214  * Removes the parent of @self.
11215  *
11216  * This will cause the parent of @self to release the reference
11217  * acquired when calling clutter_actor_set_parent(), so if you
11218  * want to keep @self you will have to acquire a reference of
11219  * your own, through g_object_ref().
11220  *
11221  * This function should only be called by legacy #ClutterActor<!-- -->s
11222  * implementing the #ClutterContainer interface.
11223  *
11224  * Since: 0.1.1
11225  *
11226  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11227  */
11228 void
11229 clutter_actor_unparent (ClutterActor *self)
11230 {
11231   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11232
11233   if (self->priv->parent == NULL)
11234     return;
11235
11236   clutter_actor_remove_child_internal (self->priv->parent, self,
11237                                        REMOVE_CHILD_LEGACY_FLAGS);
11238 }
11239
11240 /**
11241  * clutter_actor_reparent:
11242  * @self: a #ClutterActor
11243  * @new_parent: the new #ClutterActor parent
11244  *
11245  * Resets the parent actor of @self.
11246  *
11247  * This function is logically equivalent to calling clutter_actor_unparent()
11248  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11249  * ensures the child is not finalized when unparented, and emits the
11250  * #ClutterActor::parent-set signal only once.
11251  *
11252  * In reality, calling this function is less useful than it sounds, as some
11253  * application code may rely on changes in the intermediate state between
11254  * removal and addition of the actor from its old parent to the @new_parent.
11255  * Thus, it is strongly encouraged to avoid using this function in application
11256  * code.
11257  *
11258  * Since: 0.2
11259  *
11260  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11261  *   clutter_actor_add_child() instead; remember to take a reference on
11262  *   the actor being removed before calling clutter_actor_remove_child()
11263  *   to avoid the reference count dropping to zero and the actor being
11264  *   destroyed.
11265  */
11266 void
11267 clutter_actor_reparent (ClutterActor *self,
11268                         ClutterActor *new_parent)
11269 {
11270   ClutterActorPrivate *priv;
11271
11272   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11273   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11274   g_return_if_fail (self != new_parent);
11275
11276   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11277     {
11278       g_warning ("Cannot set a parent on a toplevel actor");
11279       return;
11280     }
11281
11282   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11283     {
11284       g_warning ("Cannot set a parent currently being destroyed");
11285       return;
11286     }
11287
11288   priv = self->priv;
11289
11290   if (priv->parent != new_parent)
11291     {
11292       ClutterActor *old_parent;
11293
11294       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11295
11296       old_parent = priv->parent;
11297
11298       g_object_ref (self);
11299
11300       if (old_parent != NULL)
11301         {
11302          /* go through the Container implementation if this is a regular
11303           * child and not an internal one
11304           */
11305          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11306            {
11307              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11308
11309              /* this will have to call unparent() */
11310              clutter_container_remove_actor (parent, self);
11311            }
11312          else
11313            clutter_actor_remove_child_internal (old_parent, self,
11314                                                 REMOVE_CHILD_LEGACY_FLAGS);
11315         }
11316
11317       /* Note, will call set_parent() */
11318       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11319         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11320       else
11321         clutter_actor_add_child_internal (new_parent, self,
11322                                           ADD_CHILD_LEGACY_FLAGS,
11323                                           insert_child_at_depth,
11324                                           NULL);
11325
11326       /* we emit the ::parent-set signal once */
11327       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11328
11329       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11330
11331       /* the IN_REPARENT flag suspends state updates */
11332       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11333
11334       g_object_unref (self);
11335    }
11336 }
11337
11338 /**
11339  * clutter_actor_contains:
11340  * @self: A #ClutterActor
11341  * @descendant: A #ClutterActor, possibly contained in @self
11342  *
11343  * Determines if @descendant is contained inside @self (either as an
11344  * immediate child, or as a deeper descendant). If @self and
11345  * @descendant point to the same actor then it will also return %TRUE.
11346  *
11347  * Return value: whether @descendent is contained within @self
11348  *
11349  * Since: 1.4
11350  */
11351 gboolean
11352 clutter_actor_contains (ClutterActor *self,
11353                         ClutterActor *descendant)
11354 {
11355   ClutterActor *actor;
11356
11357   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11358   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11359
11360   for (actor = descendant; actor; actor = actor->priv->parent)
11361     if (actor == self)
11362       return TRUE;
11363
11364   return FALSE;
11365 }
11366
11367 /**
11368  * clutter_actor_set_child_above_sibling:
11369  * @self: a #ClutterActor
11370  * @child: a #ClutterActor child of @self
11371  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11372  *
11373  * Sets @child to be above @sibling in the list of children of @self.
11374  *
11375  * If @sibling is %NULL, @child will be the new last child of @self.
11376  *
11377  * This function is logically equivalent to removing @child and using
11378  * clutter_actor_insert_child_above(), but it will not emit signals
11379  * or change state on @child.
11380  *
11381  * Since: 1.10
11382  */
11383 void
11384 clutter_actor_set_child_above_sibling (ClutterActor *self,
11385                                        ClutterActor *child,
11386                                        ClutterActor *sibling)
11387 {
11388   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11389   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11390   g_return_if_fail (child->priv->parent == self);
11391   g_return_if_fail (child != sibling);
11392   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11393
11394   if (sibling != NULL)
11395     g_return_if_fail (sibling->priv->parent == self);
11396
11397   /* we don't want to change the state of child, or emit signals, or
11398    * regenerate ChildMeta instances here, but we still want to follow
11399    * the correct sequence of steps encoded in remove_child() and
11400    * add_child(), so that correctness is ensured, and we only go
11401    * through one known code path.
11402    */
11403   g_object_ref (child);
11404   clutter_actor_remove_child_internal (self, child, 0);
11405   clutter_actor_add_child_internal (self, child,
11406                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11407                                     insert_child_above,
11408                                     sibling);
11409
11410   clutter_actor_queue_relayout (self);
11411 }
11412
11413 /**
11414  * clutter_actor_set_child_below_sibling:
11415  * @self: a #ClutterActor
11416  * @child: a #ClutterActor child of @self
11417  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11418  *
11419  * Sets @child to be below @sibling in the list of children of @self.
11420  *
11421  * If @sibling is %NULL, @child will be the new first child of @self.
11422  *
11423  * This function is logically equivalent to removing @self and using
11424  * clutter_actor_insert_child_below(), but it will not emit signals
11425  * or change state on @child.
11426  *
11427  * Since: 1.10
11428  */
11429 void
11430 clutter_actor_set_child_below_sibling (ClutterActor *self,
11431                                        ClutterActor *child,
11432                                        ClutterActor *sibling)
11433 {
11434   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11435   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11436   g_return_if_fail (child->priv->parent == self);
11437   g_return_if_fail (child != sibling);
11438   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11439
11440   if (sibling != NULL)
11441     g_return_if_fail (sibling->priv->parent == self);
11442
11443   /* see the comment in set_child_above_sibling() */
11444   g_object_ref (child);
11445   clutter_actor_remove_child_internal (self, child, 0);
11446   clutter_actor_add_child_internal (self, child,
11447                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11448                                     insert_child_below,
11449                                     sibling);
11450
11451   clutter_actor_queue_relayout (self);
11452 }
11453
11454 /**
11455  * clutter_actor_set_child_at_index:
11456  * @self: a #ClutterActor
11457  * @child: a #ClutterActor child of @self
11458  * @index_: the new index for @child
11459  *
11460  * Changes the index of @child in the list of children of @self.
11461  *
11462  * This function is logically equivalent to removing @child and
11463  * calling clutter_actor_insert_child_at_index(), but it will not
11464  * emit signals or change state on @child.
11465  *
11466  * Since: 1.10
11467  */
11468 void
11469 clutter_actor_set_child_at_index (ClutterActor *self,
11470                                   ClutterActor *child,
11471                                   gint          index_)
11472 {
11473   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11474   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11475   g_return_if_fail (child->priv->parent == self);
11476   g_return_if_fail (index_ <= self->priv->n_children);
11477
11478   g_object_ref (child);
11479   clutter_actor_remove_child_internal (self, child, 0);
11480   clutter_actor_add_child_internal (self, child,
11481                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11482                                     insert_child_at_index,
11483                                     GINT_TO_POINTER (index_));
11484
11485   clutter_actor_queue_relayout (self);
11486 }
11487
11488 /**
11489  * clutter_actor_raise:
11490  * @self: A #ClutterActor
11491  * @below: (allow-none): A #ClutterActor to raise above.
11492  *
11493  * Puts @self above @below.
11494  *
11495  * Both actors must have the same parent, and the parent must implement
11496  * the #ClutterContainer interface
11497  *
11498  * This function calls clutter_container_raise_child() internally.
11499  *
11500  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11501  */
11502 void
11503 clutter_actor_raise (ClutterActor *self,
11504                      ClutterActor *below)
11505 {
11506   ClutterActor *parent;
11507
11508   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11509
11510   parent = clutter_actor_get_parent (self);
11511   if (parent == NULL)
11512     {
11513       g_warning ("%s: Actor '%s' is not inside a container",
11514                  G_STRFUNC,
11515                  _clutter_actor_get_debug_name (self));
11516       return;
11517     }
11518
11519   if (below != NULL)
11520     {
11521       if (parent != clutter_actor_get_parent (below))
11522         {
11523           g_warning ("%s Actor '%s' is not in the same container as "
11524                      "actor '%s'",
11525                      G_STRFUNC,
11526                      _clutter_actor_get_debug_name (self),
11527                      _clutter_actor_get_debug_name (below));
11528           return;
11529         }
11530     }
11531
11532   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11533 }
11534
11535 /**
11536  * clutter_actor_lower:
11537  * @self: A #ClutterActor
11538  * @above: (allow-none): A #ClutterActor to lower below
11539  *
11540  * Puts @self below @above.
11541  *
11542  * Both actors must have the same parent, and the parent must implement
11543  * the #ClutterContainer interface.
11544  *
11545  * This function calls clutter_container_lower_child() internally.
11546  *
11547  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11548  */
11549 void
11550 clutter_actor_lower (ClutterActor *self,
11551                      ClutterActor *above)
11552 {
11553   ClutterActor *parent;
11554
11555   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11556
11557   parent = clutter_actor_get_parent (self);
11558   if (parent == NULL)
11559     {
11560       g_warning ("%s: Actor of type %s is not inside a container",
11561                  G_STRFUNC,
11562                  _clutter_actor_get_debug_name (self));
11563       return;
11564     }
11565
11566   if (above)
11567     {
11568       if (parent != clutter_actor_get_parent (above))
11569         {
11570           g_warning ("%s: Actor '%s' is not in the same container as "
11571                      "actor '%s'",
11572                      G_STRFUNC,
11573                      _clutter_actor_get_debug_name (self),
11574                      _clutter_actor_get_debug_name (above));
11575           return;
11576         }
11577     }
11578
11579   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11580 }
11581
11582 /**
11583  * clutter_actor_raise_top:
11584  * @self: A #ClutterActor
11585  *
11586  * Raises @self to the top.
11587  *
11588  * This function calls clutter_actor_raise() internally.
11589  *
11590  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11591  *   a %NULL sibling, instead.
11592  */
11593 void
11594 clutter_actor_raise_top (ClutterActor *self)
11595 {
11596   clutter_actor_raise (self, NULL);
11597 }
11598
11599 /**
11600  * clutter_actor_lower_bottom:
11601  * @self: A #ClutterActor
11602  *
11603  * Lowers @self to the bottom.
11604  *
11605  * This function calls clutter_actor_lower() internally.
11606  *
11607  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11608  *   a %NULL sibling, instead.
11609  */
11610 void
11611 clutter_actor_lower_bottom (ClutterActor *self)
11612 {
11613   clutter_actor_lower (self, NULL);
11614 }
11615
11616 /*
11617  * Event handling
11618  */
11619
11620 /**
11621  * clutter_actor_event:
11622  * @actor: a #ClutterActor
11623  * @event: a #ClutterEvent
11624  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11625  *
11626  * This function is used to emit an event on the main stage.
11627  * You should rarely need to use this function, except for
11628  * synthetising events.
11629  *
11630  * Return value: the return value from the signal emission: %TRUE
11631  *   if the actor handled the event, or %FALSE if the event was
11632  *   not handled
11633  *
11634  * Since: 0.6
11635  */
11636 gboolean
11637 clutter_actor_event (ClutterActor *actor,
11638                      ClutterEvent *event,
11639                      gboolean      capture)
11640 {
11641   gboolean retval = FALSE;
11642   gint signal_num = -1;
11643
11644   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11645   g_return_val_if_fail (event != NULL, FALSE);
11646
11647   g_object_ref (actor);
11648
11649   if (capture)
11650     {
11651       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11652                      event,
11653                      &retval);
11654       goto out;
11655     }
11656
11657   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11658
11659   if (!retval)
11660     {
11661       switch (event->type)
11662         {
11663         case CLUTTER_NOTHING:
11664           break;
11665         case CLUTTER_BUTTON_PRESS:
11666           signal_num = BUTTON_PRESS_EVENT;
11667           break;
11668         case CLUTTER_BUTTON_RELEASE:
11669           signal_num = BUTTON_RELEASE_EVENT;
11670           break;
11671         case CLUTTER_SCROLL:
11672           signal_num = SCROLL_EVENT;
11673           break;
11674         case CLUTTER_KEY_PRESS:
11675           signal_num = KEY_PRESS_EVENT;
11676           break;
11677         case CLUTTER_KEY_RELEASE:
11678           signal_num = KEY_RELEASE_EVENT;
11679           break;
11680         case CLUTTER_MOTION:
11681           signal_num = MOTION_EVENT;
11682           break;
11683         case CLUTTER_ENTER:
11684           signal_num = ENTER_EVENT;
11685           break;
11686         case CLUTTER_LEAVE:
11687           signal_num = LEAVE_EVENT;
11688           break;
11689         case CLUTTER_DELETE:
11690         case CLUTTER_DESTROY_NOTIFY:
11691         case CLUTTER_CLIENT_MESSAGE:
11692         default:
11693           signal_num = -1;
11694           break;
11695         }
11696
11697       if (signal_num != -1)
11698         g_signal_emit (actor, actor_signals[signal_num], 0,
11699                        event, &retval);
11700     }
11701
11702 out:
11703   g_object_unref (actor);
11704
11705   return retval;
11706 }
11707
11708 /**
11709  * clutter_actor_set_reactive:
11710  * @actor: a #ClutterActor
11711  * @reactive: whether the actor should be reactive to events
11712  *
11713  * Sets @actor as reactive. Reactive actors will receive events.
11714  *
11715  * Since: 0.6
11716  */
11717 void
11718 clutter_actor_set_reactive (ClutterActor *actor,
11719                             gboolean      reactive)
11720 {
11721   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11722
11723   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11724     return;
11725
11726   if (reactive)
11727     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11728   else
11729     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11730
11731   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11732 }
11733
11734 /**
11735  * clutter_actor_get_reactive:
11736  * @actor: a #ClutterActor
11737  *
11738  * Checks whether @actor is marked as reactive.
11739  *
11740  * Return value: %TRUE if the actor is reactive
11741  *
11742  * Since: 0.6
11743  */
11744 gboolean
11745 clutter_actor_get_reactive (ClutterActor *actor)
11746 {
11747   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11748
11749   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11750 }
11751
11752 /**
11753  * clutter_actor_get_anchor_point:
11754  * @self: a #ClutterActor
11755  * @anchor_x: (out): return location for the X coordinate of the anchor point
11756  * @anchor_y: (out): return location for the Y coordinate of the anchor point
11757  *
11758  * Gets the current anchor point of the @actor in pixels.
11759  *
11760  * Since: 0.6
11761  */
11762 void
11763 clutter_actor_get_anchor_point (ClutterActor *self,
11764                                 gfloat       *anchor_x,
11765                                 gfloat       *anchor_y)
11766 {
11767   const ClutterTransformInfo *info;
11768
11769   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11770
11771   info = _clutter_actor_get_transform_info_or_defaults (self);
11772   clutter_anchor_coord_get_units (self, &info->anchor,
11773                                   anchor_x,
11774                                   anchor_y,
11775                                   NULL);
11776 }
11777
11778 /**
11779  * clutter_actor_set_anchor_point:
11780  * @self: a #ClutterActor
11781  * @anchor_x: X coordinate of the anchor point
11782  * @anchor_y: Y coordinate of the anchor point
11783  *
11784  * Sets an anchor point for @self. The anchor point is a point in the
11785  * coordinate space of an actor to which the actor position within its
11786  * parent is relative; the default is (0, 0), i.e. the top-left corner
11787  * of the actor.
11788  *
11789  * Since: 0.6
11790  */
11791 void
11792 clutter_actor_set_anchor_point (ClutterActor *self,
11793                                 gfloat        anchor_x,
11794                                 gfloat        anchor_y)
11795 {
11796   ClutterTransformInfo *info;
11797   ClutterActorPrivate *priv;
11798   gboolean changed = FALSE;
11799   gfloat old_anchor_x, old_anchor_y;
11800   GObject *obj;
11801
11802   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11803
11804   obj = G_OBJECT (self);
11805   priv = self->priv;
11806   info = _clutter_actor_get_transform_info (self);
11807
11808   g_object_freeze_notify (obj);
11809
11810   clutter_anchor_coord_get_units (self, &info->anchor,
11811                                   &old_anchor_x,
11812                                   &old_anchor_y,
11813                                   NULL);
11814
11815   if (info->anchor.is_fractional)
11816     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11817
11818   if (old_anchor_x != anchor_x)
11819     {
11820       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11821       changed = TRUE;
11822     }
11823
11824   if (old_anchor_y != anchor_y)
11825     {
11826       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11827       changed = TRUE;
11828     }
11829
11830   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11831
11832   if (changed)
11833     {
11834       priv->transform_valid = FALSE;
11835       clutter_actor_queue_redraw (self);
11836     }
11837
11838   g_object_thaw_notify (obj);
11839 }
11840
11841 /**
11842  * clutter_actor_get_anchor_point_gravity:
11843  * @self: a #ClutterActor
11844  *
11845  * Retrieves the anchor position expressed as a #ClutterGravity. If
11846  * the anchor point was specified using pixels or units this will
11847  * return %CLUTTER_GRAVITY_NONE.
11848  *
11849  * Return value: the #ClutterGravity used by the anchor point
11850  *
11851  * Since: 1.0
11852  */
11853 ClutterGravity
11854 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11855 {
11856   const ClutterTransformInfo *info;
11857
11858   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11859
11860   info = _clutter_actor_get_transform_info_or_defaults (self);
11861
11862   return clutter_anchor_coord_get_gravity (&info->anchor);
11863 }
11864
11865 /**
11866  * clutter_actor_move_anchor_point:
11867  * @self: a #ClutterActor
11868  * @anchor_x: X coordinate of the anchor point
11869  * @anchor_y: Y coordinate of the anchor point
11870  *
11871  * Sets an anchor point for the actor, and adjusts the actor postion so that
11872  * the relative position of the actor toward its parent remains the same.
11873  *
11874  * Since: 0.6
11875  */
11876 void
11877 clutter_actor_move_anchor_point (ClutterActor *self,
11878                                  gfloat        anchor_x,
11879                                  gfloat        anchor_y)
11880 {
11881   gfloat old_anchor_x, old_anchor_y;
11882   const ClutterTransformInfo *info;
11883
11884   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11885
11886   info = _clutter_actor_get_transform_info (self);
11887   clutter_anchor_coord_get_units (self, &info->anchor,
11888                                   &old_anchor_x,
11889                                   &old_anchor_y,
11890                                   NULL);
11891
11892   g_object_freeze_notify (G_OBJECT (self));
11893
11894   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
11895
11896   if (self->priv->position_set)
11897     clutter_actor_move_by (self,
11898                            anchor_x - old_anchor_x,
11899                            anchor_y - old_anchor_y);
11900
11901   g_object_thaw_notify (G_OBJECT (self));
11902 }
11903
11904 /**
11905  * clutter_actor_move_anchor_point_from_gravity:
11906  * @self: a #ClutterActor
11907  * @gravity: #ClutterGravity.
11908  *
11909  * Sets an anchor point on the actor based on the given gravity, adjusting the
11910  * actor postion so that its relative position within its parent remains
11911  * unchanged.
11912  *
11913  * Since version 1.0 the anchor point will be stored as a gravity so
11914  * that if the actor changes size then the anchor point will move. For
11915  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11916  * and later double the size of the actor, the anchor point will move
11917  * to the bottom right.
11918  *
11919  * Since: 0.6
11920  */
11921 void
11922 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
11923                                               ClutterGravity  gravity)
11924 {
11925   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
11926   const ClutterTransformInfo *info;
11927   ClutterActorPrivate *priv;
11928
11929   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11930
11931   priv = self->priv;
11932   info = _clutter_actor_get_transform_info (self);
11933
11934   g_object_freeze_notify (G_OBJECT (self));
11935
11936   clutter_anchor_coord_get_units (self, &info->anchor,
11937                                   &old_anchor_x,
11938                                   &old_anchor_y,
11939                                   NULL);
11940   clutter_actor_set_anchor_point_from_gravity (self, gravity);
11941   clutter_anchor_coord_get_units (self, &info->anchor,
11942                                   &new_anchor_x,
11943                                   &new_anchor_y,
11944                                   NULL);
11945
11946   if (priv->position_set)
11947     clutter_actor_move_by (self,
11948                            new_anchor_x - old_anchor_x,
11949                            new_anchor_y - old_anchor_y);
11950
11951   g_object_thaw_notify (G_OBJECT (self));
11952 }
11953
11954 /**
11955  * clutter_actor_set_anchor_point_from_gravity:
11956  * @self: a #ClutterActor
11957  * @gravity: #ClutterGravity.
11958  *
11959  * Sets an anchor point on the actor, based on the given gravity (this is a
11960  * convenience function wrapping clutter_actor_set_anchor_point()).
11961  *
11962  * Since version 1.0 the anchor point will be stored as a gravity so
11963  * that if the actor changes size then the anchor point will move. For
11964  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11965  * and later double the size of the actor, the anchor point will move
11966  * to the bottom right.
11967  *
11968  * Since: 0.6
11969  */
11970 void
11971 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
11972                                              ClutterGravity  gravity)
11973 {
11974   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11975
11976   if (gravity == CLUTTER_GRAVITY_NONE)
11977     clutter_actor_set_anchor_point (self, 0, 0);
11978   else
11979     {
11980       GObject *obj = G_OBJECT (self);
11981       ClutterTransformInfo *info;
11982
11983       g_object_freeze_notify (obj);
11984
11985       info = _clutter_actor_get_transform_info (self);
11986       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
11987
11988       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11989       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11990       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11991
11992       self->priv->transform_valid = FALSE;
11993
11994       clutter_actor_queue_redraw (self);
11995
11996       g_object_thaw_notify (obj);
11997     }
11998 }
11999
12000 static void
12001 clutter_container_iface_init (ClutterContainerIface *iface)
12002 {
12003   /* we don't override anything, as ClutterContainer already has a default
12004    * implementation that we can use, and which calls into our own API.
12005    */
12006 }
12007
12008 typedef enum
12009 {
12010   PARSE_X,
12011   PARSE_Y,
12012   PARSE_WIDTH,
12013   PARSE_HEIGHT,
12014   PARSE_ANCHOR_X,
12015   PARSE_ANCHOR_Y
12016 } ParseDimension;
12017
12018 static gfloat
12019 parse_units (ClutterActor   *self,
12020              ParseDimension  dimension,
12021              JsonNode       *node)
12022 {
12023   GValue value = { 0, };
12024   gfloat retval = 0;
12025
12026   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12027     return 0;
12028
12029   json_node_get_value (node, &value);
12030
12031   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12032     {
12033       retval = (gfloat) g_value_get_int64 (&value);
12034     }
12035   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12036     {
12037       retval = g_value_get_double (&value);
12038     }
12039   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12040     {
12041       ClutterUnits units;
12042       gboolean res;
12043
12044       res = clutter_units_from_string (&units, g_value_get_string (&value));
12045       if (res)
12046         retval = clutter_units_to_pixels (&units);
12047       else
12048         {
12049           g_warning ("Invalid value '%s': integers, strings or floating point "
12050                      "values can be used for the x, y, width and height "
12051                      "properties. Valid modifiers for strings are 'px', 'mm', "
12052                      "'pt' and 'em'.",
12053                      g_value_get_string (&value));
12054           retval = 0;
12055         }
12056     }
12057   else
12058     {
12059       g_warning ("Invalid value of type '%s': integers, strings of floating "
12060                  "point values can be used for the x, y, width, height "
12061                  "anchor-x and anchor-y properties.",
12062                  g_type_name (G_VALUE_TYPE (&value)));
12063     }
12064
12065   g_value_unset (&value);
12066
12067   return retval;
12068 }
12069
12070 typedef struct {
12071   ClutterRotateAxis axis;
12072
12073   gdouble angle;
12074
12075   gfloat center_x;
12076   gfloat center_y;
12077   gfloat center_z;
12078 } RotationInfo;
12079
12080 static inline gboolean
12081 parse_rotation_array (ClutterActor *actor,
12082                       JsonArray    *array,
12083                       RotationInfo *info)
12084 {
12085   JsonNode *element;
12086
12087   if (json_array_get_length (array) != 2)
12088     return FALSE;
12089
12090   /* angle */
12091   element = json_array_get_element (array, 0);
12092   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12093     info->angle = json_node_get_double (element);
12094   else
12095     return FALSE;
12096
12097   /* center */
12098   element = json_array_get_element (array, 1);
12099   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12100     {
12101       JsonArray *center = json_node_get_array (element);
12102
12103       if (json_array_get_length (center) != 2)
12104         return FALSE;
12105
12106       switch (info->axis)
12107         {
12108         case CLUTTER_X_AXIS:
12109           info->center_y = parse_units (actor, PARSE_Y,
12110                                         json_array_get_element (center, 0));
12111           info->center_z = parse_units (actor, PARSE_Y,
12112                                         json_array_get_element (center, 1));
12113           return TRUE;
12114
12115         case CLUTTER_Y_AXIS:
12116           info->center_x = parse_units (actor, PARSE_X,
12117                                         json_array_get_element (center, 0));
12118           info->center_z = parse_units (actor, PARSE_X,
12119                                         json_array_get_element (center, 1));
12120           return TRUE;
12121
12122         case CLUTTER_Z_AXIS:
12123           info->center_x = parse_units (actor, PARSE_X,
12124                                         json_array_get_element (center, 0));
12125           info->center_y = parse_units (actor, PARSE_Y,
12126                                         json_array_get_element (center, 1));
12127           return TRUE;
12128         }
12129     }
12130
12131   return FALSE;
12132 }
12133
12134 static gboolean
12135 parse_rotation (ClutterActor *actor,
12136                 JsonNode     *node,
12137                 RotationInfo *info)
12138 {
12139   JsonArray *array;
12140   guint len, i;
12141   gboolean retval = FALSE;
12142
12143   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12144     {
12145       g_warning ("Invalid node of type '%s' found, expecting an array",
12146                  json_node_type_name (node));
12147       return FALSE;
12148     }
12149
12150   array = json_node_get_array (node);
12151   len = json_array_get_length (array);
12152
12153   for (i = 0; i < len; i++)
12154     {
12155       JsonNode *element = json_array_get_element (array, i);
12156       JsonObject *object;
12157       JsonNode *member;
12158
12159       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12160         {
12161           g_warning ("Invalid node of type '%s' found, expecting an object",
12162                      json_node_type_name (element));
12163           return FALSE;
12164         }
12165
12166       object = json_node_get_object (element);
12167
12168       if (json_object_has_member (object, "x-axis"))
12169         {
12170           member = json_object_get_member (object, "x-axis");
12171
12172           info->axis = CLUTTER_X_AXIS;
12173
12174           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12175             {
12176               info->angle = json_node_get_double (member);
12177               retval = TRUE;
12178             }
12179           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12180             retval = parse_rotation_array (actor,
12181                                            json_node_get_array (member),
12182                                            info);
12183           else
12184             retval = FALSE;
12185         }
12186       else if (json_object_has_member (object, "y-axis"))
12187         {
12188           member = json_object_get_member (object, "y-axis");
12189
12190           info->axis = CLUTTER_Y_AXIS;
12191
12192           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12193             {
12194               info->angle = json_node_get_double (member);
12195               retval = TRUE;
12196             }
12197           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12198             retval = parse_rotation_array (actor,
12199                                            json_node_get_array (member),
12200                                            info);
12201           else
12202             retval = FALSE;
12203         }
12204       else if (json_object_has_member (object, "z-axis"))
12205         {
12206           member = json_object_get_member (object, "z-axis");
12207
12208           info->axis = CLUTTER_Z_AXIS;
12209
12210           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12211             {
12212               info->angle = json_node_get_double (member);
12213               retval = TRUE;
12214             }
12215           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12216             retval = parse_rotation_array (actor,
12217                                            json_node_get_array (member),
12218                                            info);
12219           else
12220             retval = FALSE;
12221         }
12222     }
12223
12224   return retval;
12225 }
12226
12227 static GSList *
12228 parse_actor_metas (ClutterScript *script,
12229                    ClutterActor  *actor,
12230                    JsonNode      *node)
12231 {
12232   GList *elements, *l;
12233   GSList *retval = NULL;
12234
12235   if (!JSON_NODE_HOLDS_ARRAY (node))
12236     return NULL;
12237
12238   elements = json_array_get_elements (json_node_get_array (node));
12239
12240   for (l = elements; l != NULL; l = l->next)
12241     {
12242       JsonNode *element = l->data;
12243       const gchar *id_ = _clutter_script_get_id_from_node (element);
12244       GObject *meta;
12245
12246       if (id_ == NULL || *id_ == '\0')
12247         continue;
12248
12249       meta = clutter_script_get_object (script, id_);
12250       if (meta == NULL)
12251         continue;
12252
12253       retval = g_slist_prepend (retval, meta);
12254     }
12255
12256   g_list_free (elements);
12257
12258   return g_slist_reverse (retval);
12259 }
12260
12261 static GSList *
12262 parse_behaviours (ClutterScript *script,
12263                   ClutterActor  *actor,
12264                   JsonNode      *node)
12265 {
12266   GList *elements, *l;
12267   GSList *retval = NULL;
12268
12269   if (!JSON_NODE_HOLDS_ARRAY (node))
12270     return NULL;
12271
12272   elements = json_array_get_elements (json_node_get_array (node));
12273
12274   for (l = elements; l != NULL; l = l->next)
12275     {
12276       JsonNode *element = l->data;
12277       const gchar *id_ = _clutter_script_get_id_from_node (element);
12278       GObject *behaviour;
12279
12280       if (id_ == NULL || *id_ == '\0')
12281         continue;
12282
12283       behaviour = clutter_script_get_object (script, id_);
12284       if (behaviour == NULL)
12285         continue;
12286
12287       retval = g_slist_prepend (retval, behaviour);
12288     }
12289
12290   g_list_free (elements);
12291
12292   return g_slist_reverse (retval);
12293 }
12294
12295 static gboolean
12296 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12297                                  ClutterScript     *script,
12298                                  GValue            *value,
12299                                  const gchar       *name,
12300                                  JsonNode          *node)
12301 {
12302   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12303   gboolean retval = FALSE;
12304
12305   if ((name[0] == 'x' && name[1] == '\0') ||
12306       (name[0] == 'y' && name[1] == '\0') ||
12307       (strcmp (name, "width") == 0) ||
12308       (strcmp (name, "height") == 0) ||
12309       (strcmp (name, "anchor_x") == 0) ||
12310       (strcmp (name, "anchor_y") == 0))
12311     {
12312       ParseDimension dimension;
12313       gfloat units;
12314
12315       if (name[0] == 'x')
12316         dimension = PARSE_X;
12317       else if (name[0] == 'y')
12318         dimension = PARSE_Y;
12319       else if (name[0] == 'w')
12320         dimension = PARSE_WIDTH;
12321       else if (name[0] == 'h')
12322         dimension = PARSE_HEIGHT;
12323       else if (name[0] == 'a' && name[7] == 'x')
12324         dimension = PARSE_ANCHOR_X;
12325       else if (name[0] == 'a' && name[7] == 'y')
12326         dimension = PARSE_ANCHOR_Y;
12327       else
12328         return FALSE;
12329
12330       units = parse_units (actor, dimension, node);
12331
12332       /* convert back to pixels: all properties are pixel-based */
12333       g_value_init (value, G_TYPE_FLOAT);
12334       g_value_set_float (value, units);
12335
12336       retval = TRUE;
12337     }
12338   else if (strcmp (name, "rotation") == 0)
12339     {
12340       RotationInfo *info;
12341
12342       info = g_slice_new0 (RotationInfo);
12343       retval = parse_rotation (actor, node, info);
12344
12345       if (retval)
12346         {
12347           g_value_init (value, G_TYPE_POINTER);
12348           g_value_set_pointer (value, info);
12349         }
12350       else
12351         g_slice_free (RotationInfo, info);
12352     }
12353   else if (strcmp (name, "behaviours") == 0)
12354     {
12355       GSList *l;
12356
12357 #ifdef CLUTTER_ENABLE_DEBUG
12358       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12359         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12360                                      "and it should not be used in newly "
12361                                      "written ClutterScript definitions.");
12362 #endif
12363
12364       l = parse_behaviours (script, actor, node);
12365
12366       g_value_init (value, G_TYPE_POINTER);
12367       g_value_set_pointer (value, l);
12368
12369       retval = TRUE;
12370     }
12371   else if (strcmp (name, "actions") == 0 ||
12372            strcmp (name, "constraints") == 0 ||
12373            strcmp (name, "effects") == 0)
12374     {
12375       GSList *l;
12376
12377       l = parse_actor_metas (script, actor, node);
12378
12379       g_value_init (value, G_TYPE_POINTER);
12380       g_value_set_pointer (value, l);
12381
12382       retval = TRUE;
12383     }
12384
12385   return retval;
12386 }
12387
12388 static void
12389 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12390                                    ClutterScript     *script,
12391                                    const gchar       *name,
12392                                    const GValue      *value)
12393 {
12394   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12395
12396 #ifdef CLUTTER_ENABLE_DEBUG
12397   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12398     {
12399       gchar *tmp = g_strdup_value_contents (value);
12400
12401       CLUTTER_NOTE (SCRIPT,
12402                     "in ClutterActor::set_custom_property('%s') = %s",
12403                     name,
12404                     tmp);
12405
12406       g_free (tmp);
12407     }
12408 #endif /* CLUTTER_ENABLE_DEBUG */
12409
12410   if (strcmp (name, "rotation") == 0)
12411     {
12412       RotationInfo *info;
12413
12414       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12415         return;
12416
12417       info = g_value_get_pointer (value);
12418
12419       clutter_actor_set_rotation (actor,
12420                                   info->axis, info->angle,
12421                                   info->center_x,
12422                                   info->center_y,
12423                                   info->center_z);
12424
12425       g_slice_free (RotationInfo, info);
12426
12427       return;
12428     }
12429
12430   if (strcmp (name, "behaviours") == 0)
12431     {
12432       GSList *behaviours, *l;
12433
12434       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12435         return;
12436
12437       behaviours = g_value_get_pointer (value);
12438       for (l = behaviours; l != NULL; l = l->next)
12439         {
12440           ClutterBehaviour *behaviour = l->data;
12441
12442           clutter_behaviour_apply (behaviour, actor);
12443         }
12444
12445       g_slist_free (behaviours);
12446
12447       return;
12448     }
12449
12450   if (strcmp (name, "actions") == 0 ||
12451       strcmp (name, "constraints") == 0 ||
12452       strcmp (name, "effects") == 0)
12453     {
12454       GSList *metas, *l;
12455
12456       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12457         return;
12458
12459       metas = g_value_get_pointer (value);
12460       for (l = metas; l != NULL; l = l->next)
12461         {
12462           if (name[0] == 'a')
12463             clutter_actor_add_action (actor, l->data);
12464
12465           if (name[0] == 'c')
12466             clutter_actor_add_constraint (actor, l->data);
12467
12468           if (name[0] == 'e')
12469             clutter_actor_add_effect (actor, l->data);
12470         }
12471
12472       g_slist_free (metas);
12473
12474       return;
12475     }
12476
12477   g_object_set_property (G_OBJECT (scriptable), name, value);
12478 }
12479
12480 static void
12481 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12482 {
12483   iface->parse_custom_node = clutter_actor_parse_custom_node;
12484   iface->set_custom_property = clutter_actor_set_custom_property;
12485 }
12486
12487 static ClutterActorMeta *
12488 get_meta_from_animation_property (ClutterActor  *actor,
12489                                   const gchar   *name,
12490                                   gchar        **name_p)
12491 {
12492   ClutterActorPrivate *priv = actor->priv;
12493   ClutterActorMeta *meta = NULL;
12494   gchar **tokens;
12495
12496   /* if this is not a special property, fall through */
12497   if (name[0] != '@')
12498     return NULL;
12499
12500   /* detect the properties named using the following spec:
12501    *
12502    *   @<section>.<meta-name>.<property-name>
12503    *
12504    * where <section> can be one of the following:
12505    *
12506    *   - actions
12507    *   - constraints
12508    *   - effects
12509    *
12510    * and <meta-name> is the name set on a specific ActorMeta
12511    */
12512
12513   tokens = g_strsplit (name + 1, ".", -1);
12514   if (tokens == NULL || g_strv_length (tokens) != 3)
12515     {
12516       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12517                     name + 1);
12518       g_strfreev (tokens);
12519       return NULL;
12520     }
12521
12522   if (strcmp (tokens[0], "actions") == 0)
12523     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12524
12525   if (strcmp (tokens[0], "constraints") == 0)
12526     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12527
12528   if (strcmp (tokens[0], "effects") == 0)
12529     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12530
12531   if (name_p != NULL)
12532     *name_p = g_strdup (tokens[2]);
12533
12534   CLUTTER_NOTE (ANIMATION,
12535                 "Looking for property '%s' of object '%s' in section '%s'",
12536                 tokens[2],
12537                 tokens[1],
12538                 tokens[0]);
12539
12540   g_strfreev (tokens);
12541
12542   return meta;
12543 }
12544
12545 static GParamSpec *
12546 clutter_actor_find_property (ClutterAnimatable *animatable,
12547                              const gchar       *property_name)
12548 {
12549   ClutterActorMeta *meta = NULL;
12550   GObjectClass *klass = NULL;
12551   GParamSpec *pspec = NULL;
12552   gchar *p_name = NULL;
12553
12554   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12555                                            property_name,
12556                                            &p_name);
12557
12558   if (meta != NULL)
12559     {
12560       klass = G_OBJECT_GET_CLASS (meta);
12561
12562       pspec = g_object_class_find_property (klass, p_name);
12563     }
12564   else
12565     {
12566       klass = G_OBJECT_GET_CLASS (animatable);
12567
12568       pspec = g_object_class_find_property (klass, property_name);
12569     }
12570
12571   g_free (p_name);
12572
12573   return pspec;
12574 }
12575
12576 static void
12577 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12578                                  const gchar       *property_name,
12579                                  GValue            *initial)
12580 {
12581   ClutterActorMeta *meta = NULL;
12582   gchar *p_name = NULL;
12583
12584   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12585                                            property_name,
12586                                            &p_name);
12587
12588   if (meta != NULL)
12589     g_object_get_property (G_OBJECT (meta), p_name, initial);
12590   else
12591     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12592
12593   g_free (p_name);
12594 }
12595
12596 /*
12597  * clutter_actor_set_animatable_property:
12598  * @actor: a #ClutterActor
12599  * @prop_id: the paramspec id
12600  * @value: the value to set
12601  * @pspec: the paramspec
12602  *
12603  * Sets values of animatable properties.
12604  *
12605  * This is a variant of clutter_actor_set_property() that gets called
12606  * by the #ClutterAnimatable implementation of #ClutterActor for the
12607  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12608  * #GParamSpec.
12609  *
12610  * Unlike the implementation of #GObjectClass.set_property(), this
12611  * function will not update the interval if a transition involving an
12612  * animatable property is in progress - this avoids cycles with the
12613  * transition API calling the public API.
12614  */
12615 static void
12616 clutter_actor_set_animatable_property (ClutterActor *actor,
12617                                        guint         prop_id,
12618                                        const GValue *value,
12619                                        GParamSpec   *pspec)
12620 {
12621   switch (prop_id)
12622     {
12623     case PROP_X:
12624       clutter_actor_set_x_internal (actor, g_value_get_float (value));
12625       break;
12626
12627     case PROP_Y:
12628       clutter_actor_set_y_internal (actor, g_value_get_float (value));
12629       break;
12630
12631     case PROP_WIDTH:
12632       clutter_actor_set_width_internal (actor, g_value_get_float (value));
12633       break;
12634
12635     case PROP_HEIGHT:
12636       clutter_actor_set_height_internal (actor, g_value_get_float (value));
12637       break;
12638
12639     case PROP_DEPTH:
12640       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12641       break;
12642
12643     case PROP_OPACITY:
12644       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12645       break;
12646
12647     case PROP_BACKGROUND_COLOR:
12648       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12649       break;
12650
12651     case PROP_SCALE_X:
12652       clutter_actor_set_scale_factor_internal (actor,
12653                                                g_value_get_double (value),
12654                                                pspec);
12655       break;
12656
12657     case PROP_SCALE_Y:
12658       clutter_actor_set_scale_factor_internal (actor,
12659                                                g_value_get_double (value),
12660                                                pspec);
12661       break;
12662
12663     case PROP_ROTATION_ANGLE_X:
12664       clutter_actor_set_rotation_angle_internal (actor,
12665                                                  CLUTTER_X_AXIS,
12666                                                  g_value_get_double (value));
12667       break;
12668
12669     case PROP_ROTATION_ANGLE_Y:
12670       clutter_actor_set_rotation_angle_internal (actor,
12671                                                  CLUTTER_Y_AXIS,
12672                                                  g_value_get_double (value));
12673       break;
12674
12675     case PROP_ROTATION_ANGLE_Z:
12676       clutter_actor_set_rotation_angle_internal (actor,
12677                                                  CLUTTER_Z_AXIS,
12678                                                  g_value_get_double (value));
12679       break;
12680
12681     default:
12682       g_object_set_property (G_OBJECT (actor), pspec->name, value);
12683       break;
12684     }
12685 }
12686
12687 static void
12688 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12689                                const gchar       *property_name,
12690                                const GValue      *final)
12691 {
12692   ClutterActor *actor = CLUTTER_ACTOR (animatable);
12693   ClutterActorMeta *meta = NULL;
12694   gchar *p_name = NULL;
12695
12696   meta = get_meta_from_animation_property (actor,
12697                                            property_name,
12698                                            &p_name);
12699   if (meta != NULL)
12700     g_object_set_property (G_OBJECT (meta), p_name, final);
12701   else
12702     {
12703       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12704       GParamSpec *pspec;
12705
12706       pspec = g_object_class_find_property (obj_class, property_name);
12707
12708       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12709         {
12710           /* XXX - I'm going to the special hell for this */
12711           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12712         }
12713       else
12714         g_object_set_property (G_OBJECT (animatable), property_name, final);
12715     }
12716
12717   g_free (p_name);
12718 }
12719
12720 static void
12721 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12722 {
12723   iface->find_property = clutter_actor_find_property;
12724   iface->get_initial_state = clutter_actor_get_initial_state;
12725   iface->set_final_state = clutter_actor_set_final_state;
12726 }
12727
12728 /**
12729  * clutter_actor_transform_stage_point:
12730  * @self: A #ClutterActor
12731  * @x: (in): x screen coordinate of the point to unproject
12732  * @y: (in): y screen coordinate of the point to unproject
12733  * @x_out: (out): return location for the unprojected x coordinance
12734  * @y_out: (out): return location for the unprojected y coordinance
12735  *
12736  * This function translates screen coordinates (@x, @y) to
12737  * coordinates relative to the actor. For example, it can be used to translate
12738  * screen events from global screen coordinates into actor-local coordinates.
12739  *
12740  * The conversion can fail, notably if the transform stack results in the
12741  * actor being projected on the screen as a mere line.
12742  *
12743  * The conversion should not be expected to be pixel-perfect due to the
12744  * nature of the operation. In general the error grows when the skewing
12745  * of the actor rectangle on screen increases.
12746  *
12747  * <note><para>This function can be computationally intensive.</para></note>
12748  *
12749  * <note><para>This function only works when the allocation is up-to-date,
12750  * i.e. inside of paint().</para></note>
12751  *
12752  * Return value: %TRUE if conversion was successful.
12753  *
12754  * Since: 0.6
12755  */
12756 gboolean
12757 clutter_actor_transform_stage_point (ClutterActor *self,
12758                                      gfloat        x,
12759                                      gfloat        y,
12760                                      gfloat       *x_out,
12761                                      gfloat       *y_out)
12762 {
12763   ClutterVertex v[4];
12764   float ST[3][3];
12765   float RQ[3][3];
12766   int du, dv, xi, yi;
12767   float px, py;
12768   float xf, yf, wf, det;
12769   ClutterActorPrivate *priv;
12770
12771   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12772
12773   priv = self->priv;
12774
12775   /* This implementation is based on the quad -> quad projection algorithm
12776    * described by Paul Heckbert in:
12777    *
12778    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12779    *
12780    * and the sample implementation at:
12781    *
12782    *   http://www.cs.cmu.edu/~ph/src/texfund/
12783    *
12784    * Our texture is a rectangle with origin [0, 0], so we are mapping from
12785    * quad to rectangle only, which significantly simplifies things; the
12786    * function calls have been unrolled, and most of the math is done in fixed
12787    * point.
12788    */
12789
12790   clutter_actor_get_abs_allocation_vertices (self, v);
12791
12792   /* Keeping these as ints simplifies the multiplication (no significant
12793    * loss of precision here).
12794    */
12795   du = (int) (priv->allocation.x2 - priv->allocation.x1);
12796   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12797
12798   if (!du || !dv)
12799     return FALSE;
12800
12801 #define UX2FP(x)        (x)
12802 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12803
12804   /* First, find mapping from unit uv square to xy quadrilateral; this
12805    * equivalent to the pmap_square_quad() functions in the sample
12806    * implementation, which we can simplify, since our target is always
12807    * a rectangle.
12808    */
12809   px = v[0].x - v[1].x + v[3].x - v[2].x;
12810   py = v[0].y - v[1].y + v[3].y - v[2].y;
12811
12812   if (!px && !py)
12813     {
12814       /* affine transform */
12815       RQ[0][0] = UX2FP (v[1].x - v[0].x);
12816       RQ[1][0] = UX2FP (v[3].x - v[1].x);
12817       RQ[2][0] = UX2FP (v[0].x);
12818       RQ[0][1] = UX2FP (v[1].y - v[0].y);
12819       RQ[1][1] = UX2FP (v[3].y - v[1].y);
12820       RQ[2][1] = UX2FP (v[0].y);
12821       RQ[0][2] = 0;
12822       RQ[1][2] = 0;
12823       RQ[2][2] = 1.0;
12824     }
12825   else
12826     {
12827       /* projective transform */
12828       double dx1, dx2, dy1, dy2, del;
12829
12830       dx1 = UX2FP (v[1].x - v[3].x);
12831       dx2 = UX2FP (v[2].x - v[3].x);
12832       dy1 = UX2FP (v[1].y - v[3].y);
12833       dy2 = UX2FP (v[2].y - v[3].y);
12834
12835       del = DET2FP (dx1, dx2, dy1, dy2);
12836       if (!del)
12837         return FALSE;
12838
12839       /*
12840        * The division here needs to be done in floating point for
12841        * precisions reasons.
12842        */
12843       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12844       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12845       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12846       RQ[2][2] = 1.0;
12847       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12848       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12849       RQ[2][0] = UX2FP (v[0].x);
12850       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12851       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12852       RQ[2][1] = UX2FP (v[0].y);
12853     }
12854
12855   /*
12856    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12857    * square. Since our rectangle is based at 0,0 we only need to scale.
12858    */
12859   RQ[0][0] /= du;
12860   RQ[1][0] /= dv;
12861   RQ[0][1] /= du;
12862   RQ[1][1] /= dv;
12863   RQ[0][2] /= du;
12864   RQ[1][2] /= dv;
12865
12866   /*
12867    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12868    * inverse of that.
12869    */
12870   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12871   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12872   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12873   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12874   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12875   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12876   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12877   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12878   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12879
12880   /*
12881    * Check the resulting matrix is OK.
12882    */
12883   det = (RQ[0][0] * ST[0][0])
12884       + (RQ[0][1] * ST[0][1])
12885       + (RQ[0][2] * ST[0][2]);
12886   if (!det)
12887     return FALSE;
12888
12889   /*
12890    * Now transform our point with the ST matrix; the notional w
12891    * coordinate is 1, hence the last part is simply added.
12892    */
12893   xi = (int) x;
12894   yi = (int) y;
12895
12896   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
12897   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
12898   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
12899
12900   if (x_out)
12901     *x_out = xf / wf;
12902
12903   if (y_out)
12904     *y_out = yf / wf;
12905
12906 #undef UX2FP
12907 #undef DET2FP
12908
12909   return TRUE;
12910 }
12911
12912 /*
12913  * ClutterGeometry
12914  */
12915
12916 static ClutterGeometry*
12917 clutter_geometry_copy (const ClutterGeometry *geometry)
12918 {
12919   return g_slice_dup (ClutterGeometry, geometry);
12920 }
12921
12922 static void
12923 clutter_geometry_free (ClutterGeometry *geometry)
12924 {
12925   if (G_LIKELY (geometry != NULL))
12926     g_slice_free (ClutterGeometry, geometry);
12927 }
12928
12929 /**
12930  * clutter_geometry_union:
12931  * @geometry_a: a #ClutterGeometry
12932  * @geometry_b: another #ClutterGeometry
12933  * @result: (out): location to store the result
12934  *
12935  * Find the union of two rectangles represented as #ClutterGeometry.
12936  *
12937  * Since: 1.4
12938  */
12939 void
12940 clutter_geometry_union (const ClutterGeometry *geometry_a,
12941                         const ClutterGeometry *geometry_b,
12942                         ClutterGeometry       *result)
12943 {
12944   /* We don't try to handle rectangles that can't be represented
12945    * as a signed integer box */
12946   gint x_1 = MIN (geometry_a->x, geometry_b->x);
12947   gint y_1 = MIN (geometry_a->y, geometry_b->y);
12948   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
12949                   geometry_b->x + (gint)geometry_b->width);
12950   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
12951                   geometry_b->y + (gint)geometry_b->height);
12952   result->x = x_1;
12953   result->y = y_1;
12954   result->width = x_2 - x_1;
12955   result->height = y_2 - y_1;
12956 }
12957
12958 /**
12959  * clutter_geometry_intersects:
12960  * @geometry0: The first geometry to test
12961  * @geometry1: The second geometry to test
12962  *
12963  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
12964  * they do else %FALSE.
12965  *
12966  * Return value: %TRUE of @geometry0 and geometry1 intersect else
12967  * %FALSE.
12968  *
12969  * Since: 1.4
12970  */
12971 gboolean
12972 clutter_geometry_intersects (const ClutterGeometry *geometry0,
12973                              const ClutterGeometry *geometry1)
12974 {
12975   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
12976       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
12977       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
12978       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
12979     return FALSE;
12980   else
12981     return TRUE;
12982 }
12983
12984 static gboolean
12985 clutter_geometry_progress (const GValue *a,
12986                            const GValue *b,
12987                            gdouble       progress,
12988                            GValue       *retval)
12989 {
12990   const ClutterGeometry *a_geom = g_value_get_boxed (a);
12991   const ClutterGeometry *b_geom = g_value_get_boxed (b);
12992   ClutterGeometry res = { 0, };
12993   gint a_width = a_geom->width;
12994   gint b_width = b_geom->width;
12995   gint a_height = a_geom->height;
12996   gint b_height = b_geom->height;
12997
12998   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
12999   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13000
13001   res.width = a_width + (b_width - a_width) * progress;
13002   res.height = a_height + (b_height - a_height) * progress;
13003
13004   g_value_set_boxed (retval, &res);
13005
13006   return TRUE;
13007 }
13008
13009 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13010                                clutter_geometry_copy,
13011                                clutter_geometry_free,
13012                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13013
13014 /*
13015  * ClutterVertices
13016  */
13017
13018 /**
13019  * clutter_vertex_new:
13020  * @x: X coordinate
13021  * @y: Y coordinate
13022  * @z: Z coordinate
13023  *
13024  * Creates a new #ClutterVertex for the point in 3D space
13025  * identified by the 3 coordinates @x, @y, @z
13026  *
13027  * Return value: the newly allocate #ClutterVertex. Use
13028  *   clutter_vertex_free() to free the resources
13029  *
13030  * Since: 1.0
13031  */
13032 ClutterVertex *
13033 clutter_vertex_new (gfloat x,
13034                     gfloat y,
13035                     gfloat z)
13036 {
13037   ClutterVertex *vertex;
13038
13039   vertex = g_slice_new (ClutterVertex);
13040   vertex->x = x;
13041   vertex->y = y;
13042   vertex->z = z;
13043
13044   return vertex;
13045 }
13046
13047 /**
13048  * clutter_vertex_copy:
13049  * @vertex: a #ClutterVertex
13050  *
13051  * Copies @vertex
13052  *
13053  * Return value: a newly allocated copy of #ClutterVertex. Use
13054  *   clutter_vertex_free() to free the allocated resources
13055  *
13056  * Since: 1.0
13057  */
13058 ClutterVertex *
13059 clutter_vertex_copy (const ClutterVertex *vertex)
13060 {
13061   if (G_LIKELY (vertex != NULL))
13062     return g_slice_dup (ClutterVertex, vertex);
13063
13064   return NULL;
13065 }
13066
13067 /**
13068  * clutter_vertex_free:
13069  * @vertex: a #ClutterVertex
13070  *
13071  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13072  *
13073  * Since: 1.0
13074  */
13075 void
13076 clutter_vertex_free (ClutterVertex *vertex)
13077 {
13078   if (G_UNLIKELY (vertex != NULL))
13079     g_slice_free (ClutterVertex, vertex);
13080 }
13081
13082 /**
13083  * clutter_vertex_equal:
13084  * @vertex_a: a #ClutterVertex
13085  * @vertex_b: a #ClutterVertex
13086  *
13087  * Compares @vertex_a and @vertex_b for equality
13088  *
13089  * Return value: %TRUE if the passed #ClutterVertex are equal
13090  *
13091  * Since: 1.0
13092  */
13093 gboolean
13094 clutter_vertex_equal (const ClutterVertex *vertex_a,
13095                       const ClutterVertex *vertex_b)
13096 {
13097   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13098
13099   if (vertex_a == vertex_b)
13100     return TRUE;
13101
13102   return vertex_a->x == vertex_b->x &&
13103          vertex_a->y == vertex_b->y &&
13104          vertex_a->z == vertex_b->z;
13105 }
13106
13107 static gboolean
13108 clutter_vertex_progress (const GValue *a,
13109                          const GValue *b,
13110                          gdouble       progress,
13111                          GValue       *retval)
13112 {
13113   const ClutterVertex *av = g_value_get_boxed (a);
13114   const ClutterVertex *bv = g_value_get_boxed (b);
13115   ClutterVertex res = { 0, };
13116
13117   res.x = av->x + (bv->x - av->x) * progress;
13118   res.y = av->y + (bv->y - av->y) * progress;
13119   res.z = av->z + (bv->z - av->z) * progress;
13120
13121   g_value_set_boxed (retval, &res);
13122
13123   return TRUE;
13124 }
13125
13126 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13127                                clutter_vertex_copy,
13128                                clutter_vertex_free,
13129                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13130
13131 /**
13132  * clutter_actor_is_rotated:
13133  * @self: a #ClutterActor
13134  *
13135  * Checks whether any rotation is applied to the actor.
13136  *
13137  * Return value: %TRUE if the actor is rotated.
13138  *
13139  * Since: 0.6
13140  */
13141 gboolean
13142 clutter_actor_is_rotated (ClutterActor *self)
13143 {
13144   const ClutterTransformInfo *info;
13145
13146   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13147
13148   info = _clutter_actor_get_transform_info_or_defaults (self);
13149
13150   if (info->rx_angle || info->ry_angle || info->rz_angle)
13151     return TRUE;
13152
13153   return FALSE;
13154 }
13155
13156 /**
13157  * clutter_actor_is_scaled:
13158  * @self: a #ClutterActor
13159  *
13160  * Checks whether the actor is scaled in either dimension.
13161  *
13162  * Return value: %TRUE if the actor is scaled.
13163  *
13164  * Since: 0.6
13165  */
13166 gboolean
13167 clutter_actor_is_scaled (ClutterActor *self)
13168 {
13169   const ClutterTransformInfo *info;
13170
13171   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13172
13173   info = _clutter_actor_get_transform_info_or_defaults (self);
13174
13175   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13176     return TRUE;
13177
13178   return FALSE;
13179 }
13180
13181 ClutterActor *
13182 _clutter_actor_get_stage_internal (ClutterActor *actor)
13183 {
13184   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13185     actor = actor->priv->parent;
13186
13187   return actor;
13188 }
13189
13190 /**
13191  * clutter_actor_get_stage:
13192  * @actor: a #ClutterActor
13193  *
13194  * Retrieves the #ClutterStage where @actor is contained.
13195  *
13196  * Return value: (transfer none) (type Clutter.Stage): the stage
13197  *   containing the actor, or %NULL
13198  *
13199  * Since: 0.8
13200  */
13201 ClutterActor *
13202 clutter_actor_get_stage (ClutterActor *actor)
13203 {
13204   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13205
13206   return _clutter_actor_get_stage_internal (actor);
13207 }
13208
13209 /**
13210  * clutter_actor_allocate_available_size:
13211  * @self: a #ClutterActor
13212  * @x: the actor's X coordinate
13213  * @y: the actor's Y coordinate
13214  * @available_width: the maximum available width, or -1 to use the
13215  *   actor's natural width
13216  * @available_height: the maximum available height, or -1 to use the
13217  *   actor's natural height
13218  * @flags: flags controlling the allocation
13219  *
13220  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13221  * preferred size, but limiting it to the maximum available width
13222  * and height provided.
13223  *
13224  * This function will do the right thing when dealing with the
13225  * actor's request mode.
13226  *
13227  * The implementation of this function is equivalent to:
13228  *
13229  * |[
13230  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13231  *     {
13232  *       clutter_actor_get_preferred_width (self, available_height,
13233  *                                          &amp;min_width,
13234  *                                          &amp;natural_width);
13235  *       width = CLAMP (natural_width, min_width, available_width);
13236  *
13237  *       clutter_actor_get_preferred_height (self, width,
13238  *                                           &amp;min_height,
13239  *                                           &amp;natural_height);
13240  *       height = CLAMP (natural_height, min_height, available_height);
13241  *     }
13242  *   else
13243  *     {
13244  *       clutter_actor_get_preferred_height (self, available_width,
13245  *                                           &amp;min_height,
13246  *                                           &amp;natural_height);
13247  *       height = CLAMP (natural_height, min_height, available_height);
13248  *
13249  *       clutter_actor_get_preferred_width (self, height,
13250  *                                          &amp;min_width,
13251  *                                          &amp;natural_width);
13252  *       width = CLAMP (natural_width, min_width, available_width);
13253  *     }
13254  *
13255  *   box.x1 = x; box.y1 = y;
13256  *   box.x2 = box.x1 + available_width;
13257  *   box.y2 = box.y1 + available_height;
13258  *   clutter_actor_allocate (self, &amp;box, flags);
13259  * ]|
13260  *
13261  * This function can be used by fluid layout managers to allocate
13262  * an actor's preferred size without making it bigger than the area
13263  * available for the container.
13264  *
13265  * Since: 1.0
13266  */
13267 void
13268 clutter_actor_allocate_available_size (ClutterActor           *self,
13269                                        gfloat                  x,
13270                                        gfloat                  y,
13271                                        gfloat                  available_width,
13272                                        gfloat                  available_height,
13273                                        ClutterAllocationFlags  flags)
13274 {
13275   ClutterActorPrivate *priv;
13276   gfloat width, height;
13277   gfloat min_width, min_height;
13278   gfloat natural_width, natural_height;
13279   ClutterActorBox box;
13280
13281   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13282
13283   priv = self->priv;
13284
13285   width = height = 0.0;
13286
13287   switch (priv->request_mode)
13288     {
13289     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13290       clutter_actor_get_preferred_width (self, available_height,
13291                                          &min_width,
13292                                          &natural_width);
13293       width  = CLAMP (natural_width, min_width, available_width);
13294
13295       clutter_actor_get_preferred_height (self, width,
13296                                           &min_height,
13297                                           &natural_height);
13298       height = CLAMP (natural_height, min_height, available_height);
13299       break;
13300
13301     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13302       clutter_actor_get_preferred_height (self, available_width,
13303                                           &min_height,
13304                                           &natural_height);
13305       height = CLAMP (natural_height, min_height, available_height);
13306
13307       clutter_actor_get_preferred_width (self, height,
13308                                          &min_width,
13309                                          &natural_width);
13310       width  = CLAMP (natural_width, min_width, available_width);
13311       break;
13312     }
13313
13314
13315   box.x1 = x;
13316   box.y1 = y;
13317   box.x2 = box.x1 + width;
13318   box.y2 = box.y1 + height;
13319   clutter_actor_allocate (self, &box, flags);
13320 }
13321
13322 /**
13323  * clutter_actor_allocate_preferred_size:
13324  * @self: a #ClutterActor
13325  * @flags: flags controlling the allocation
13326  *
13327  * Allocates the natural size of @self.
13328  *
13329  * This function is a utility call for #ClutterActor implementations
13330  * that allocates the actor's preferred natural size. It can be used
13331  * by fixed layout managers (like #ClutterGroup or so called
13332  * 'composite actors') inside the ClutterActor::allocate
13333  * implementation to give each child exactly how much space it
13334  * requires.
13335  *
13336  * This function is not meant to be used by applications. It is also
13337  * not meant to be used outside the implementation of the
13338  * ClutterActor::allocate virtual function.
13339  *
13340  * Since: 0.8
13341  */
13342 void
13343 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13344                                        ClutterAllocationFlags  flags)
13345 {
13346   gfloat actor_x, actor_y;
13347   gfloat natural_width, natural_height;
13348   ClutterActorBox actor_box;
13349
13350   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13351
13352   actor_x = clutter_actor_get_x (self);
13353   actor_y = clutter_actor_get_y (self);
13354
13355   clutter_actor_get_preferred_size (self,
13356                                     NULL, NULL,
13357                                     &natural_width,
13358                                     &natural_height);
13359
13360   actor_box.x1 = actor_x;
13361   actor_box.y1 = actor_y;
13362   actor_box.x2 = actor_box.x1 + natural_width;
13363   actor_box.y2 = actor_box.y1 + natural_height;
13364
13365   clutter_actor_allocate (self, &actor_box, flags);
13366 }
13367
13368 /**
13369  * clutter_actor_allocate_align_fill:
13370  * @self: a #ClutterActor
13371  * @box: a #ClutterActorBox, containing the available width and height
13372  * @x_align: the horizontal alignment, between 0 and 1
13373  * @y_align: the vertical alignment, between 0 and 1
13374  * @x_fill: whether the actor should fill horizontally
13375  * @y_fill: whether the actor should fill vertically
13376  * @flags: allocation flags to be passed to clutter_actor_allocate()
13377  *
13378  * Allocates @self by taking into consideration the available allocation
13379  * area; an alignment factor on either axis; and whether the actor should
13380  * fill the allocation on either axis.
13381  *
13382  * The @box should contain the available allocation width and height;
13383  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13384  * allocation will be offset by their value.
13385  *
13386  * This function takes into consideration the geometry request specified by
13387  * the #ClutterActor:request-mode property, and the text direction.
13388  *
13389  * This function is useful for fluid layout managers, like #ClutterBinLayout
13390  * or #ClutterTableLayout
13391  *
13392  * Since: 1.4
13393  */
13394 void
13395 clutter_actor_allocate_align_fill (ClutterActor           *self,
13396                                    const ClutterActorBox  *box,
13397                                    gdouble                 x_align,
13398                                    gdouble                 y_align,
13399                                    gboolean                x_fill,
13400                                    gboolean                y_fill,
13401                                    ClutterAllocationFlags  flags)
13402 {
13403   ClutterActorPrivate *priv;
13404   ClutterActorBox allocation = { 0, };
13405   gfloat x_offset, y_offset;
13406   gfloat available_width, available_height;
13407   gfloat child_width, child_height;
13408
13409   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13410   g_return_if_fail (box != NULL);
13411   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13412   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13413
13414   priv = self->priv;
13415
13416   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13417   clutter_actor_box_get_size (box, &available_width, &available_height);
13418
13419   if (available_width < 0)
13420     available_width = 0;
13421
13422   if (available_height < 0)
13423     available_height = 0;
13424
13425   if (x_fill)
13426     {
13427       allocation.x1 = x_offset;
13428       allocation.x2 = allocation.x1 + available_width;
13429     }
13430
13431   if (y_fill)
13432     {
13433       allocation.y1 = y_offset;
13434       allocation.y2 = allocation.y1 + available_height;
13435     }
13436
13437   /* if we are filling horizontally and vertically then we're done */
13438   if (x_fill && y_fill)
13439     goto out;
13440
13441   child_width = child_height = 0.0f;
13442
13443   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13444     {
13445       gfloat min_width, natural_width;
13446       gfloat min_height, natural_height;
13447
13448       clutter_actor_get_preferred_width (self, available_height,
13449                                          &min_width,
13450                                          &natural_width);
13451
13452       child_width = CLAMP (natural_width, min_width, available_width);
13453
13454       if (!y_fill)
13455         {
13456           clutter_actor_get_preferred_height (self, child_width,
13457                                               &min_height,
13458                                               &natural_height);
13459
13460           child_height = CLAMP (natural_height, min_height, available_height);
13461         }
13462     }
13463   else
13464     {
13465       gfloat min_width, natural_width;
13466       gfloat min_height, natural_height;
13467
13468       clutter_actor_get_preferred_height (self, available_width,
13469                                           &min_height,
13470                                           &natural_height);
13471
13472       child_height = CLAMP (natural_height, min_height, available_height);
13473
13474       if (!x_fill)
13475         {
13476           clutter_actor_get_preferred_width (self, child_height,
13477                                              &min_width,
13478                                              &natural_width);
13479
13480           child_width = CLAMP (natural_width, min_width, available_width);
13481         }
13482     }
13483
13484   /* invert the horizontal alignment for RTL languages */
13485   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13486     x_align = 1.0 - x_align;
13487
13488   if (!x_fill)
13489     {
13490       allocation.x1 = x_offset
13491                     + ((available_width - child_width) * x_align);
13492       allocation.x2 = allocation.x1 + child_width;
13493     }
13494
13495   if (!y_fill)
13496     {
13497       allocation.y1 = y_offset
13498                     + ((available_height - child_height) * y_align);
13499       allocation.y2 = allocation.y1 + child_height;
13500     }
13501
13502 out:
13503   clutter_actor_box_clamp_to_pixel (&allocation);
13504   clutter_actor_allocate (self, &allocation, flags);
13505 }
13506
13507 /**
13508  * clutter_actor_grab_key_focus:
13509  * @self: a #ClutterActor
13510  *
13511  * Sets the key focus of the #ClutterStage including @self
13512  * to this #ClutterActor.
13513  *
13514  * Since: 1.0
13515  */
13516 void
13517 clutter_actor_grab_key_focus (ClutterActor *self)
13518 {
13519   ClutterActor *stage;
13520
13521   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13522
13523   stage = _clutter_actor_get_stage_internal (self);
13524   if (stage != NULL)
13525     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13526 }
13527
13528 /**
13529  * clutter_actor_get_pango_context:
13530  * @self: a #ClutterActor
13531  *
13532  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13533  * is already configured using the appropriate font map, resolution
13534  * and font options.
13535  *
13536  * Unlike clutter_actor_create_pango_context(), this context is owend
13537  * by the #ClutterActor and it will be updated each time the options
13538  * stored by the #ClutterBackend change.
13539  *
13540  * You can use the returned #PangoContext to create a #PangoLayout
13541  * and render text using cogl_pango_render_layout() to reuse the
13542  * glyphs cache also used by Clutter.
13543  *
13544  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13545  *   The returned #PangoContext is owned by the actor and should not be
13546  *   unreferenced by the application code
13547  *
13548  * Since: 1.0
13549  */
13550 PangoContext *
13551 clutter_actor_get_pango_context (ClutterActor *self)
13552 {
13553   ClutterActorPrivate *priv;
13554
13555   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13556
13557   priv = self->priv;
13558
13559   if (priv->pango_context != NULL)
13560     return priv->pango_context;
13561
13562   priv->pango_context = _clutter_context_get_pango_context ();
13563   g_object_ref (priv->pango_context);
13564
13565   return priv->pango_context;
13566 }
13567
13568 /**
13569  * clutter_actor_create_pango_context:
13570  * @self: a #ClutterActor
13571  *
13572  * Creates a #PangoContext for the given actor. The #PangoContext
13573  * is already configured using the appropriate font map, resolution
13574  * and font options.
13575  *
13576  * See also clutter_actor_get_pango_context().
13577  *
13578  * Return value: (transfer full): the newly created #PangoContext.
13579  *   Use g_object_unref() on the returned value to deallocate its
13580  *   resources
13581  *
13582  * Since: 1.0
13583  */
13584 PangoContext *
13585 clutter_actor_create_pango_context (ClutterActor *self)
13586 {
13587   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13588
13589   return _clutter_context_create_pango_context ();
13590 }
13591
13592 /**
13593  * clutter_actor_create_pango_layout:
13594  * @self: a #ClutterActor
13595  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13596  *
13597  * Creates a new #PangoLayout from the same #PangoContext used
13598  * by the #ClutterActor. The #PangoLayout is already configured
13599  * with the font map, resolution and font options, and the
13600  * given @text.
13601  *
13602  * If you want to keep around a #PangoLayout created by this
13603  * function you will have to connect to the #ClutterBackend::font-changed
13604  * and #ClutterBackend::resolution-changed signals, and call
13605  * pango_layout_context_changed() in response to them.
13606  *
13607  * Return value: (transfer full): the newly created #PangoLayout.
13608  *   Use g_object_unref() when done
13609  *
13610  * Since: 1.0
13611  */
13612 PangoLayout *
13613 clutter_actor_create_pango_layout (ClutterActor *self,
13614                                    const gchar  *text)
13615 {
13616   PangoContext *context;
13617   PangoLayout *layout;
13618
13619   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13620
13621   context = clutter_actor_get_pango_context (self);
13622   layout = pango_layout_new (context);
13623
13624   if (text)
13625     pango_layout_set_text (layout, text, -1);
13626
13627   return layout;
13628 }
13629
13630 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13631  * ClutterOffscreenEffect.
13632  */
13633 void
13634 _clutter_actor_set_opacity_override (ClutterActor *self,
13635                                      gint          opacity)
13636 {
13637   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13638
13639   self->priv->opacity_override = opacity;
13640 }
13641
13642 gint
13643 _clutter_actor_get_opacity_override (ClutterActor *self)
13644 {
13645   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13646
13647   return self->priv->opacity_override;
13648 }
13649
13650 /* Allows you to disable applying the actors model view transform during
13651  * a paint. Used by ClutterClone. */
13652 void
13653 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13654                                                 gboolean      enable)
13655 {
13656   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13657
13658   self->priv->enable_model_view_transform = enable;
13659 }
13660
13661 void
13662 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13663                                           gboolean      enable)
13664 {
13665   ClutterActorPrivate *priv;
13666
13667   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13668
13669   priv = self->priv;
13670
13671   priv->enable_paint_unmapped = enable;
13672
13673   if (priv->enable_paint_unmapped)
13674     {
13675       /* Make sure that the parents of the widget are realized first;
13676        * otherwise checks in clutter_actor_update_map_state() will
13677        * fail.
13678        */
13679       clutter_actor_realize (self);
13680
13681       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13682     }
13683   else
13684     {
13685       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13686     }
13687 }
13688
13689 static void
13690 clutter_anchor_coord_get_units (ClutterActor      *self,
13691                                 const AnchorCoord *coord,
13692                                 gfloat            *x,
13693                                 gfloat            *y,
13694                                 gfloat            *z)
13695 {
13696   if (coord->is_fractional)
13697     {
13698       gfloat actor_width, actor_height;
13699
13700       clutter_actor_get_size (self, &actor_width, &actor_height);
13701
13702       if (x)
13703         *x = actor_width * coord->v.fraction.x;
13704
13705       if (y)
13706         *y = actor_height * coord->v.fraction.y;
13707
13708       if (z)
13709         *z = 0;
13710     }
13711   else
13712     {
13713       if (x)
13714         *x = coord->v.units.x;
13715
13716       if (y)
13717         *y = coord->v.units.y;
13718
13719       if (z)
13720         *z = coord->v.units.z;
13721     }
13722 }
13723
13724 static void
13725 clutter_anchor_coord_set_units (AnchorCoord *coord,
13726                                 gfloat       x,
13727                                 gfloat       y,
13728                                 gfloat       z)
13729 {
13730   coord->is_fractional = FALSE;
13731   coord->v.units.x = x;
13732   coord->v.units.y = y;
13733   coord->v.units.z = z;
13734 }
13735
13736 static ClutterGravity
13737 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13738 {
13739   if (coord->is_fractional)
13740     {
13741       if (coord->v.fraction.x == 0.0)
13742         {
13743           if (coord->v.fraction.y == 0.0)
13744             return CLUTTER_GRAVITY_NORTH_WEST;
13745           else if (coord->v.fraction.y == 0.5)
13746             return CLUTTER_GRAVITY_WEST;
13747           else if (coord->v.fraction.y == 1.0)
13748             return CLUTTER_GRAVITY_SOUTH_WEST;
13749           else
13750             return CLUTTER_GRAVITY_NONE;
13751         }
13752       else if (coord->v.fraction.x == 0.5)
13753         {
13754           if (coord->v.fraction.y == 0.0)
13755             return CLUTTER_GRAVITY_NORTH;
13756           else if (coord->v.fraction.y == 0.5)
13757             return CLUTTER_GRAVITY_CENTER;
13758           else if (coord->v.fraction.y == 1.0)
13759             return CLUTTER_GRAVITY_SOUTH;
13760           else
13761             return CLUTTER_GRAVITY_NONE;
13762         }
13763       else if (coord->v.fraction.x == 1.0)
13764         {
13765           if (coord->v.fraction.y == 0.0)
13766             return CLUTTER_GRAVITY_NORTH_EAST;
13767           else if (coord->v.fraction.y == 0.5)
13768             return CLUTTER_GRAVITY_EAST;
13769           else if (coord->v.fraction.y == 1.0)
13770             return CLUTTER_GRAVITY_SOUTH_EAST;
13771           else
13772             return CLUTTER_GRAVITY_NONE;
13773         }
13774       else
13775         return CLUTTER_GRAVITY_NONE;
13776     }
13777   else
13778     return CLUTTER_GRAVITY_NONE;
13779 }
13780
13781 static void
13782 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
13783                                   ClutterGravity  gravity)
13784 {
13785   switch (gravity)
13786     {
13787     case CLUTTER_GRAVITY_NORTH:
13788       coord->v.fraction.x = 0.5;
13789       coord->v.fraction.y = 0.0;
13790       break;
13791
13792     case CLUTTER_GRAVITY_NORTH_EAST:
13793       coord->v.fraction.x = 1.0;
13794       coord->v.fraction.y = 0.0;
13795       break;
13796
13797     case CLUTTER_GRAVITY_EAST:
13798       coord->v.fraction.x = 1.0;
13799       coord->v.fraction.y = 0.5;
13800       break;
13801
13802     case CLUTTER_GRAVITY_SOUTH_EAST:
13803       coord->v.fraction.x = 1.0;
13804       coord->v.fraction.y = 1.0;
13805       break;
13806
13807     case CLUTTER_GRAVITY_SOUTH:
13808       coord->v.fraction.x = 0.5;
13809       coord->v.fraction.y = 1.0;
13810       break;
13811
13812     case CLUTTER_GRAVITY_SOUTH_WEST:
13813       coord->v.fraction.x = 0.0;
13814       coord->v.fraction.y = 1.0;
13815       break;
13816
13817     case CLUTTER_GRAVITY_WEST:
13818       coord->v.fraction.x = 0.0;
13819       coord->v.fraction.y = 0.5;
13820       break;
13821
13822     case CLUTTER_GRAVITY_NORTH_WEST:
13823       coord->v.fraction.x = 0.0;
13824       coord->v.fraction.y = 0.0;
13825       break;
13826
13827     case CLUTTER_GRAVITY_CENTER:
13828       coord->v.fraction.x = 0.5;
13829       coord->v.fraction.y = 0.5;
13830       break;
13831
13832     default:
13833       coord->v.fraction.x = 0.0;
13834       coord->v.fraction.y = 0.0;
13835       break;
13836     }
13837
13838   coord->is_fractional = TRUE;
13839 }
13840
13841 static gboolean
13842 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13843 {
13844   if (coord->is_fractional)
13845     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13846   else
13847     return (coord->v.units.x == 0.0
13848             && coord->v.units.y == 0.0
13849             && coord->v.units.z == 0.0);
13850 }
13851
13852 /**
13853  * clutter_actor_get_flags:
13854  * @self: a #ClutterActor
13855  *
13856  * Retrieves the flags set on @self
13857  *
13858  * Return value: a bitwise or of #ClutterActorFlags or 0
13859  *
13860  * Since: 1.0
13861  */
13862 ClutterActorFlags
13863 clutter_actor_get_flags (ClutterActor *self)
13864 {
13865   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13866
13867   return self->flags;
13868 }
13869
13870 /**
13871  * clutter_actor_set_flags:
13872  * @self: a #ClutterActor
13873  * @flags: the flags to set
13874  *
13875  * Sets @flags on @self
13876  *
13877  * This function will emit notifications for the changed properties
13878  *
13879  * Since: 1.0
13880  */
13881 void
13882 clutter_actor_set_flags (ClutterActor      *self,
13883                          ClutterActorFlags  flags)
13884 {
13885   ClutterActorFlags old_flags;
13886   GObject *obj;
13887   gboolean was_reactive_set, reactive_set;
13888   gboolean was_realized_set, realized_set;
13889   gboolean was_mapped_set, mapped_set;
13890   gboolean was_visible_set, visible_set;
13891
13892   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13893
13894   if (self->flags == flags)
13895     return;
13896
13897   obj = G_OBJECT (self);
13898   g_object_ref (obj);
13899   g_object_freeze_notify (obj);
13900
13901   old_flags = self->flags;
13902
13903   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13904   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13905   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13906   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13907
13908   self->flags |= flags;
13909
13910   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13911   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13912   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13913   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13914
13915   if (reactive_set != was_reactive_set)
13916     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13917
13918   if (realized_set != was_realized_set)
13919     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13920
13921   if (mapped_set != was_mapped_set)
13922     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13923
13924   if (visible_set != was_visible_set)
13925     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13926
13927   g_object_thaw_notify (obj);
13928   g_object_unref (obj);
13929 }
13930
13931 /**
13932  * clutter_actor_unset_flags:
13933  * @self: a #ClutterActor
13934  * @flags: the flags to unset
13935  *
13936  * Unsets @flags on @self
13937  *
13938  * This function will emit notifications for the changed properties
13939  *
13940  * Since: 1.0
13941  */
13942 void
13943 clutter_actor_unset_flags (ClutterActor      *self,
13944                            ClutterActorFlags  flags)
13945 {
13946   ClutterActorFlags old_flags;
13947   GObject *obj;
13948   gboolean was_reactive_set, reactive_set;
13949   gboolean was_realized_set, realized_set;
13950   gboolean was_mapped_set, mapped_set;
13951   gboolean was_visible_set, visible_set;
13952
13953   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13954
13955   obj = G_OBJECT (self);
13956   g_object_freeze_notify (obj);
13957
13958   old_flags = self->flags;
13959
13960   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13961   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13962   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13963   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13964
13965   self->flags &= ~flags;
13966
13967   if (self->flags == old_flags)
13968     return;
13969
13970   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13971   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13972   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13973   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13974
13975   if (reactive_set != was_reactive_set)
13976     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13977
13978   if (realized_set != was_realized_set)
13979     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13980
13981   if (mapped_set != was_mapped_set)
13982     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13983
13984   if (visible_set != was_visible_set)
13985     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13986
13987   g_object_thaw_notify (obj);
13988 }
13989
13990 /**
13991  * clutter_actor_get_transformation_matrix:
13992  * @self: a #ClutterActor
13993  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
13994  *
13995  * Retrieves the transformations applied to @self relative to its
13996  * parent.
13997  *
13998  * Since: 1.0
13999  */
14000 void
14001 clutter_actor_get_transformation_matrix (ClutterActor *self,
14002                                          CoglMatrix   *matrix)
14003 {
14004   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14005
14006   cogl_matrix_init_identity (matrix);
14007
14008   _clutter_actor_apply_modelview_transform (self, matrix);
14009 }
14010
14011 void
14012 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14013                                    gboolean      is_in_clone_paint)
14014 {
14015   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14016   self->priv->in_clone_paint = is_in_clone_paint;
14017 }
14018
14019 /**
14020  * clutter_actor_is_in_clone_paint:
14021  * @self: a #ClutterActor
14022  *
14023  * Checks whether @self is being currently painted by a #ClutterClone
14024  *
14025  * This function is useful only inside the ::paint virtual function
14026  * implementations or within handlers for the #ClutterActor::paint
14027  * signal
14028  *
14029  * This function should not be used by applications
14030  *
14031  * Return value: %TRUE if the #ClutterActor is currently being painted
14032  *   by a #ClutterClone, and %FALSE otherwise
14033  *
14034  * Since: 1.0
14035  */
14036 gboolean
14037 clutter_actor_is_in_clone_paint (ClutterActor *self)
14038 {
14039   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14040
14041   return self->priv->in_clone_paint;
14042 }
14043
14044 static gboolean
14045 set_direction_recursive (ClutterActor *actor,
14046                          gpointer      user_data)
14047 {
14048   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14049
14050   clutter_actor_set_text_direction (actor, text_dir);
14051
14052   return TRUE;
14053 }
14054
14055 /**
14056  * clutter_actor_set_text_direction:
14057  * @self: a #ClutterActor
14058  * @text_dir: the text direction for @self
14059  *
14060  * Sets the #ClutterTextDirection for an actor
14061  *
14062  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14063  *
14064  * If @self implements #ClutterContainer then this function will recurse
14065  * inside all the children of @self (including the internal ones).
14066  *
14067  * Composite actors not implementing #ClutterContainer, or actors requiring
14068  * special handling when the text direction changes, should connect to
14069  * the #GObject::notify signal for the #ClutterActor:text-direction property
14070  *
14071  * Since: 1.2
14072  */
14073 void
14074 clutter_actor_set_text_direction (ClutterActor         *self,
14075                                   ClutterTextDirection  text_dir)
14076 {
14077   ClutterActorPrivate *priv;
14078
14079   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14080   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14081
14082   priv = self->priv;
14083
14084   if (priv->text_direction != text_dir)
14085     {
14086       priv->text_direction = text_dir;
14087
14088       /* we need to emit the notify::text-direction first, so that
14089        * the sub-classes can catch that and do specific handling of
14090        * the text direction; see clutter_text_direction_changed_cb()
14091        * inside clutter-text.c
14092        */
14093       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14094
14095       _clutter_actor_foreach_child (self, set_direction_recursive,
14096                                     GINT_TO_POINTER (text_dir));
14097
14098       clutter_actor_queue_relayout (self);
14099     }
14100 }
14101
14102 void
14103 _clutter_actor_set_has_pointer (ClutterActor *self,
14104                                 gboolean      has_pointer)
14105 {
14106   ClutterActorPrivate *priv = self->priv;
14107
14108   if (priv->has_pointer != has_pointer)
14109     {
14110       priv->has_pointer = has_pointer;
14111
14112       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14113     }
14114 }
14115
14116 /**
14117  * clutter_actor_get_text_direction:
14118  * @self: a #ClutterActor
14119  *
14120  * Retrieves the value set using clutter_actor_set_text_direction()
14121  *
14122  * If no text direction has been previously set, the default text
14123  * direction, as returned by clutter_get_default_text_direction(), will
14124  * be returned instead
14125  *
14126  * Return value: the #ClutterTextDirection for the actor
14127  *
14128  * Since: 1.2
14129  */
14130 ClutterTextDirection
14131 clutter_actor_get_text_direction (ClutterActor *self)
14132 {
14133   ClutterActorPrivate *priv;
14134
14135   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14136                         CLUTTER_TEXT_DIRECTION_LTR);
14137
14138   priv = self->priv;
14139
14140   /* if no direction has been set yet use the default */
14141   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14142     priv->text_direction = clutter_get_default_text_direction ();
14143
14144   return priv->text_direction;
14145 }
14146
14147 /**
14148  * clutter_actor_push_internal:
14149  * @self: a #ClutterActor
14150  *
14151  * Should be used by actors implementing the #ClutterContainer and with
14152  * internal children added through clutter_actor_set_parent(), for instance:
14153  *
14154  * |[
14155  *   static void
14156  *   my_actor_init (MyActor *self)
14157  *   {
14158  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14159  *
14160  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14161  *
14162  *     /&ast; calling clutter_actor_set_parent() now will result in
14163  *      &ast; the internal flag being set on a child of MyActor
14164  *      &ast;/
14165  *
14166  *     /&ast; internal child - a background texture &ast;/
14167  *     self->priv->background_tex = clutter_texture_new ();
14168  *     clutter_actor_set_parent (self->priv->background_tex,
14169  *                               CLUTTER_ACTOR (self));
14170  *
14171  *     /&ast; internal child - a label &ast;/
14172  *     self->priv->label = clutter_text_new ();
14173  *     clutter_actor_set_parent (self->priv->label,
14174  *                               CLUTTER_ACTOR (self));
14175  *
14176  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14177  *
14178  *     /&ast; calling clutter_actor_set_parent() now will not result in
14179  *      &ast; the internal flag being set on a child of MyActor
14180  *      &ast;/
14181  *   }
14182  * ]|
14183  *
14184  * This function will be used by Clutter to toggle an "internal child"
14185  * flag whenever clutter_actor_set_parent() is called; internal children
14186  * are handled differently by Clutter, specifically when destroying their
14187  * parent.
14188  *
14189  * Call clutter_actor_pop_internal() when you finished adding internal
14190  * children.
14191  *
14192  * Nested calls to clutter_actor_push_internal() are allowed, but each
14193  * one must by followed by a clutter_actor_pop_internal() call.
14194  *
14195  * Since: 1.2
14196  *
14197  * Deprecated: 1.10: All children of an actor are accessible through
14198  *   the #ClutterActor API, and #ClutterActor implements the
14199  *   #ClutterContainer interface, so this function is only useful
14200  *   for legacy containers overriding the default implementation.
14201  */
14202 void
14203 clutter_actor_push_internal (ClutterActor *self)
14204 {
14205   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14206
14207   self->priv->internal_child += 1;
14208 }
14209
14210 /**
14211  * clutter_actor_pop_internal:
14212  * @self: a #ClutterActor
14213  *
14214  * Disables the effects of clutter_actor_push_internal().
14215  *
14216  * Since: 1.2
14217  *
14218  * Deprecated: 1.10: All children of an actor are accessible through
14219  *   the #ClutterActor API. This function is only useful for legacy
14220  *   containers overriding the default implementation of the
14221  *   #ClutterContainer interface.
14222  */
14223 void
14224 clutter_actor_pop_internal (ClutterActor *self)
14225 {
14226   ClutterActorPrivate *priv;
14227
14228   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14229
14230   priv = self->priv;
14231
14232   if (priv->internal_child == 0)
14233     {
14234       g_warning ("Mismatched %s: you need to call "
14235                  "clutter_actor_push_composite() at least once before "
14236                  "calling this function", G_STRFUNC);
14237       return;
14238     }
14239
14240   priv->internal_child -= 1;
14241 }
14242
14243 /**
14244  * clutter_actor_has_pointer:
14245  * @self: a #ClutterActor
14246  *
14247  * Checks whether an actor contains the pointer of a
14248  * #ClutterInputDevice
14249  *
14250  * Return value: %TRUE if the actor contains the pointer, and
14251  *   %FALSE otherwise
14252  *
14253  * Since: 1.2
14254  */
14255 gboolean
14256 clutter_actor_has_pointer (ClutterActor *self)
14257 {
14258   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14259
14260   return self->priv->has_pointer;
14261 }
14262
14263 /* XXX: This is a workaround for not being able to break the ABI of
14264  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14265  * clutter_actor_queue_clipped_redraw() for details.
14266  */
14267 ClutterPaintVolume *
14268 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14269 {
14270   return g_object_get_data (G_OBJECT (self),
14271                             "-clutter-actor-queue-redraw-clip");
14272 }
14273
14274 void
14275 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14276                                       ClutterPaintVolume *clip)
14277 {
14278   g_object_set_data (G_OBJECT (self),
14279                      "-clutter-actor-queue-redraw-clip",
14280                      clip);
14281 }
14282
14283 /**
14284  * clutter_actor_has_allocation:
14285  * @self: a #ClutterActor
14286  *
14287  * Checks if the actor has an up-to-date allocation assigned to
14288  * it. This means that the actor should have an allocation: it's
14289  * visible and has a parent. It also means that there is no
14290  * outstanding relayout request in progress for the actor or its
14291  * children (There might be other outstanding layout requests in
14292  * progress that will cause the actor to get a new allocation
14293  * when the stage is laid out, however).
14294  *
14295  * If this function returns %FALSE, then the actor will normally
14296  * be allocated before it is next drawn on the screen.
14297  *
14298  * Return value: %TRUE if the actor has an up-to-date allocation
14299  *
14300  * Since: 1.4
14301  */
14302 gboolean
14303 clutter_actor_has_allocation (ClutterActor *self)
14304 {
14305   ClutterActorPrivate *priv;
14306
14307   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14308
14309   priv = self->priv;
14310
14311   return priv->parent != NULL &&
14312          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14313          !priv->needs_allocation;
14314 }
14315
14316 /**
14317  * clutter_actor_add_action:
14318  * @self: a #ClutterActor
14319  * @action: a #ClutterAction
14320  *
14321  * Adds @action to the list of actions applied to @self
14322  *
14323  * A #ClutterAction can only belong to one actor at a time
14324  *
14325  * The #ClutterActor will hold a reference on @action until either
14326  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14327  * is called
14328  *
14329  * Since: 1.4
14330  */
14331 void
14332 clutter_actor_add_action (ClutterActor  *self,
14333                           ClutterAction *action)
14334 {
14335   ClutterActorPrivate *priv;
14336
14337   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14338   g_return_if_fail (CLUTTER_IS_ACTION (action));
14339
14340   priv = self->priv;
14341
14342   if (priv->actions == NULL)
14343     {
14344       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14345       priv->actions->actor = self;
14346     }
14347
14348   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14349
14350   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14351 }
14352
14353 /**
14354  * clutter_actor_add_action_with_name:
14355  * @self: a #ClutterActor
14356  * @name: the name to set on the action
14357  * @action: a #ClutterAction
14358  *
14359  * A convenience function for setting the name of a #ClutterAction
14360  * while adding it to the list of actions applied to @self
14361  *
14362  * This function is the logical equivalent of:
14363  *
14364  * |[
14365  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14366  *   clutter_actor_add_action (self, action);
14367  * ]|
14368  *
14369  * Since: 1.4
14370  */
14371 void
14372 clutter_actor_add_action_with_name (ClutterActor  *self,
14373                                     const gchar   *name,
14374                                     ClutterAction *action)
14375 {
14376   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14377   g_return_if_fail (name != NULL);
14378   g_return_if_fail (CLUTTER_IS_ACTION (action));
14379
14380   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14381   clutter_actor_add_action (self, action);
14382 }
14383
14384 /**
14385  * clutter_actor_remove_action:
14386  * @self: a #ClutterActor
14387  * @action: a #ClutterAction
14388  *
14389  * Removes @action from the list of actions applied to @self
14390  *
14391  * The reference held by @self on the #ClutterAction will be released
14392  *
14393  * Since: 1.4
14394  */
14395 void
14396 clutter_actor_remove_action (ClutterActor  *self,
14397                              ClutterAction *action)
14398 {
14399   ClutterActorPrivate *priv;
14400
14401   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14402   g_return_if_fail (CLUTTER_IS_ACTION (action));
14403
14404   priv = self->priv;
14405
14406   if (priv->actions == NULL)
14407     return;
14408
14409   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14410
14411   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14412 }
14413
14414 /**
14415  * clutter_actor_remove_action_by_name:
14416  * @self: a #ClutterActor
14417  * @name: the name of the action to remove
14418  *
14419  * Removes the #ClutterAction with the given name from the list
14420  * of actions applied to @self
14421  *
14422  * Since: 1.4
14423  */
14424 void
14425 clutter_actor_remove_action_by_name (ClutterActor *self,
14426                                      const gchar  *name)
14427 {
14428   ClutterActorPrivate *priv;
14429   ClutterActorMeta *meta;
14430
14431   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14432   g_return_if_fail (name != NULL);
14433
14434   priv = self->priv;
14435
14436   if (priv->actions == NULL)
14437     return;
14438
14439   meta = _clutter_meta_group_get_meta (priv->actions, name);
14440   if (meta == NULL)
14441     return;
14442
14443   _clutter_meta_group_remove_meta (priv->actions, meta);
14444
14445   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14446 }
14447
14448 /**
14449  * clutter_actor_get_actions:
14450  * @self: a #ClutterActor
14451  *
14452  * Retrieves the list of actions applied to @self
14453  *
14454  * Return value: (transfer container) (element-type Clutter.Action): a copy
14455  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14456  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14457  *   allocated by the returned #GList
14458  *
14459  * Since: 1.4
14460  */
14461 GList *
14462 clutter_actor_get_actions (ClutterActor *self)
14463 {
14464   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14465
14466   if (self->priv->actions == NULL)
14467     return NULL;
14468
14469   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14470 }
14471
14472 /**
14473  * clutter_actor_get_action:
14474  * @self: a #ClutterActor
14475  * @name: the name of the action to retrieve
14476  *
14477  * Retrieves the #ClutterAction with the given name in the list
14478  * of actions applied to @self
14479  *
14480  * Return value: (transfer none): a #ClutterAction for the given
14481  *   name, or %NULL. The returned #ClutterAction is owned by the
14482  *   actor and it should not be unreferenced directly
14483  *
14484  * Since: 1.4
14485  */
14486 ClutterAction *
14487 clutter_actor_get_action (ClutterActor *self,
14488                           const gchar  *name)
14489 {
14490   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14491   g_return_val_if_fail (name != NULL, NULL);
14492
14493   if (self->priv->actions == NULL)
14494     return NULL;
14495
14496   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14497 }
14498
14499 /**
14500  * clutter_actor_clear_actions:
14501  * @self: a #ClutterActor
14502  *
14503  * Clears the list of actions applied to @self
14504  *
14505  * Since: 1.4
14506  */
14507 void
14508 clutter_actor_clear_actions (ClutterActor *self)
14509 {
14510   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14511
14512   if (self->priv->actions == NULL)
14513     return;
14514
14515   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14516 }
14517
14518 /**
14519  * clutter_actor_add_constraint:
14520  * @self: a #ClutterActor
14521  * @constraint: a #ClutterConstraint
14522  *
14523  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14524  * to @self
14525  *
14526  * The #ClutterActor will hold a reference on the @constraint until
14527  * either clutter_actor_remove_constraint() or
14528  * clutter_actor_clear_constraints() is called.
14529  *
14530  * Since: 1.4
14531  */
14532 void
14533 clutter_actor_add_constraint (ClutterActor      *self,
14534                               ClutterConstraint *constraint)
14535 {
14536   ClutterActorPrivate *priv;
14537
14538   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14539   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14540
14541   priv = self->priv;
14542
14543   if (priv->constraints == NULL)
14544     {
14545       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14546       priv->constraints->actor = self;
14547     }
14548
14549   _clutter_meta_group_add_meta (priv->constraints,
14550                                 CLUTTER_ACTOR_META (constraint));
14551   clutter_actor_queue_relayout (self);
14552
14553   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14554 }
14555
14556 /**
14557  * clutter_actor_add_constraint_with_name:
14558  * @self: a #ClutterActor
14559  * @name: the name to set on the constraint
14560  * @constraint: a #ClutterConstraint
14561  *
14562  * A convenience function for setting the name of a #ClutterConstraint
14563  * while adding it to the list of constraints applied to @self
14564  *
14565  * This function is the logical equivalent of:
14566  *
14567  * |[
14568  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14569  *   clutter_actor_add_constraint (self, constraint);
14570  * ]|
14571  *
14572  * Since: 1.4
14573  */
14574 void
14575 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14576                                         const gchar       *name,
14577                                         ClutterConstraint *constraint)
14578 {
14579   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14580   g_return_if_fail (name != NULL);
14581   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14582
14583   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14584   clutter_actor_add_constraint (self, constraint);
14585 }
14586
14587 /**
14588  * clutter_actor_remove_constraint:
14589  * @self: a #ClutterActor
14590  * @constraint: a #ClutterConstraint
14591  *
14592  * Removes @constraint from the list of constraints applied to @self
14593  *
14594  * The reference held by @self on the #ClutterConstraint will be released
14595  *
14596  * Since: 1.4
14597  */
14598 void
14599 clutter_actor_remove_constraint (ClutterActor      *self,
14600                                  ClutterConstraint *constraint)
14601 {
14602   ClutterActorPrivate *priv;
14603
14604   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14605   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14606
14607   priv = self->priv;
14608
14609   if (priv->constraints == NULL)
14610     return;
14611
14612   _clutter_meta_group_remove_meta (priv->constraints,
14613                                    CLUTTER_ACTOR_META (constraint));
14614   clutter_actor_queue_relayout (self);
14615
14616   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14617 }
14618
14619 /**
14620  * clutter_actor_remove_constraint_by_name:
14621  * @self: a #ClutterActor
14622  * @name: the name of the constraint to remove
14623  *
14624  * Removes the #ClutterConstraint with the given name from the list
14625  * of constraints applied to @self
14626  *
14627  * Since: 1.4
14628  */
14629 void
14630 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14631                                          const gchar  *name)
14632 {
14633   ClutterActorPrivate *priv;
14634   ClutterActorMeta *meta;
14635
14636   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14637   g_return_if_fail (name != NULL);
14638
14639   priv = self->priv;
14640
14641   if (priv->constraints == NULL)
14642     return;
14643
14644   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14645   if (meta == NULL)
14646     return;
14647
14648   _clutter_meta_group_remove_meta (priv->constraints, meta);
14649   clutter_actor_queue_relayout (self);
14650 }
14651
14652 /**
14653  * clutter_actor_get_constraints:
14654  * @self: a #ClutterActor
14655  *
14656  * Retrieves the list of constraints applied to @self
14657  *
14658  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14659  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14660  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14661  *   allocated by the returned #GList
14662  *
14663  * Since: 1.4
14664  */
14665 GList *
14666 clutter_actor_get_constraints (ClutterActor *self)
14667 {
14668   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14669
14670   if (self->priv->constraints == NULL)
14671     return NULL;
14672
14673   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14674 }
14675
14676 /**
14677  * clutter_actor_get_constraint:
14678  * @self: a #ClutterActor
14679  * @name: the name of the constraint to retrieve
14680  *
14681  * Retrieves the #ClutterConstraint with the given name in the list
14682  * of constraints applied to @self
14683  *
14684  * Return value: (transfer none): a #ClutterConstraint for the given
14685  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14686  *   actor and it should not be unreferenced directly
14687  *
14688  * Since: 1.4
14689  */
14690 ClutterConstraint *
14691 clutter_actor_get_constraint (ClutterActor *self,
14692                               const gchar  *name)
14693 {
14694   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14695   g_return_val_if_fail (name != NULL, NULL);
14696
14697   if (self->priv->constraints == NULL)
14698     return NULL;
14699
14700   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14701 }
14702
14703 /**
14704  * clutter_actor_clear_constraints:
14705  * @self: a #ClutterActor
14706  *
14707  * Clears the list of constraints applied to @self
14708  *
14709  * Since: 1.4
14710  */
14711 void
14712 clutter_actor_clear_constraints (ClutterActor *self)
14713 {
14714   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14715
14716   if (self->priv->constraints == NULL)
14717     return;
14718
14719   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14720
14721   clutter_actor_queue_relayout (self);
14722 }
14723
14724 /**
14725  * clutter_actor_set_clip_to_allocation:
14726  * @self: a #ClutterActor
14727  * @clip_set: %TRUE to apply a clip tracking the allocation
14728  *
14729  * Sets whether @self should be clipped to the same size as its
14730  * allocation
14731  *
14732  * Since: 1.4
14733  */
14734 void
14735 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14736                                       gboolean      clip_set)
14737 {
14738   ClutterActorPrivate *priv;
14739
14740   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14741
14742   clip_set = !!clip_set;
14743
14744   priv = self->priv;
14745
14746   if (priv->clip_to_allocation != clip_set)
14747     {
14748       priv->clip_to_allocation = clip_set;
14749
14750       clutter_actor_queue_redraw (self);
14751
14752       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14753     }
14754 }
14755
14756 /**
14757  * clutter_actor_get_clip_to_allocation:
14758  * @self: a #ClutterActor
14759  *
14760  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14761  *
14762  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14763  *
14764  * Since: 1.4
14765  */
14766 gboolean
14767 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14768 {
14769   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14770
14771   return self->priv->clip_to_allocation;
14772 }
14773
14774 /**
14775  * clutter_actor_add_effect:
14776  * @self: a #ClutterActor
14777  * @effect: a #ClutterEffect
14778  *
14779  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14780  *
14781  * The #ClutterActor will hold a reference on the @effect until either
14782  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14783  * called.
14784  *
14785  * Since: 1.4
14786  */
14787 void
14788 clutter_actor_add_effect (ClutterActor  *self,
14789                           ClutterEffect *effect)
14790 {
14791   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14792   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14793
14794   _clutter_actor_add_effect_internal (self, effect);
14795
14796   clutter_actor_queue_redraw (self);
14797
14798   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14799 }
14800
14801 /**
14802  * clutter_actor_add_effect_with_name:
14803  * @self: a #ClutterActor
14804  * @name: the name to set on the effect
14805  * @effect: a #ClutterEffect
14806  *
14807  * A convenience function for setting the name of a #ClutterEffect
14808  * while adding it to the list of effectss applied to @self
14809  *
14810  * This function is the logical equivalent of:
14811  *
14812  * |[
14813  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14814  *   clutter_actor_add_effect (self, effect);
14815  * ]|
14816  *
14817  * Since: 1.4
14818  */
14819 void
14820 clutter_actor_add_effect_with_name (ClutterActor  *self,
14821                                     const gchar   *name,
14822                                     ClutterEffect *effect)
14823 {
14824   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14825   g_return_if_fail (name != NULL);
14826   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14827
14828   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14829   clutter_actor_add_effect (self, effect);
14830 }
14831
14832 /**
14833  * clutter_actor_remove_effect:
14834  * @self: a #ClutterActor
14835  * @effect: a #ClutterEffect
14836  *
14837  * Removes @effect from the list of effects applied to @self
14838  *
14839  * The reference held by @self on the #ClutterEffect will be released
14840  *
14841  * Since: 1.4
14842  */
14843 void
14844 clutter_actor_remove_effect (ClutterActor  *self,
14845                              ClutterEffect *effect)
14846 {
14847   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14848   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14849
14850   _clutter_actor_remove_effect_internal (self, effect);
14851
14852   clutter_actor_queue_redraw (self);
14853
14854   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14855 }
14856
14857 /**
14858  * clutter_actor_remove_effect_by_name:
14859  * @self: a #ClutterActor
14860  * @name: the name of the effect to remove
14861  *
14862  * Removes the #ClutterEffect with the given name from the list
14863  * of effects applied to @self
14864  *
14865  * Since: 1.4
14866  */
14867 void
14868 clutter_actor_remove_effect_by_name (ClutterActor *self,
14869                                      const gchar  *name)
14870 {
14871   ClutterActorPrivate *priv;
14872   ClutterActorMeta *meta;
14873
14874   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14875   g_return_if_fail (name != NULL);
14876
14877   priv = self->priv;
14878
14879   if (priv->effects == NULL)
14880     return;
14881
14882   meta = _clutter_meta_group_get_meta (priv->effects, name);
14883   if (meta == NULL)
14884     return;
14885
14886   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
14887 }
14888
14889 /**
14890  * clutter_actor_get_effects:
14891  * @self: a #ClutterActor
14892  *
14893  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
14894  *
14895  * Return value: (transfer container) (element-type Clutter.Effect): a list
14896  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
14897  *   list are owned by Clutter and they should not be freed. You should
14898  *   free the returned list using g_list_free() when done
14899  *
14900  * Since: 1.4
14901  */
14902 GList *
14903 clutter_actor_get_effects (ClutterActor *self)
14904 {
14905   ClutterActorPrivate *priv;
14906
14907   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14908
14909   priv = self->priv;
14910
14911   if (priv->effects == NULL)
14912     return NULL;
14913
14914   return _clutter_meta_group_get_metas_no_internal (priv->effects);
14915 }
14916
14917 /**
14918  * clutter_actor_get_effect:
14919  * @self: a #ClutterActor
14920  * @name: the name of the effect to retrieve
14921  *
14922  * Retrieves the #ClutterEffect with the given name in the list
14923  * of effects applied to @self
14924  *
14925  * Return value: (transfer none): a #ClutterEffect for the given
14926  *   name, or %NULL. The returned #ClutterEffect is owned by the
14927  *   actor and it should not be unreferenced directly
14928  *
14929  * Since: 1.4
14930  */
14931 ClutterEffect *
14932 clutter_actor_get_effect (ClutterActor *self,
14933                           const gchar  *name)
14934 {
14935   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14936   g_return_val_if_fail (name != NULL, NULL);
14937
14938   if (self->priv->effects == NULL)
14939     return NULL;
14940
14941   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
14942 }
14943
14944 /**
14945  * clutter_actor_clear_effects:
14946  * @self: a #ClutterActor
14947  *
14948  * Clears the list of effects applied to @self
14949  *
14950  * Since: 1.4
14951  */
14952 void
14953 clutter_actor_clear_effects (ClutterActor *self)
14954 {
14955   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14956
14957   if (self->priv->effects == NULL)
14958     return;
14959
14960   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
14961
14962   clutter_actor_queue_redraw (self);
14963 }
14964
14965 /**
14966  * clutter_actor_has_key_focus:
14967  * @self: a #ClutterActor
14968  *
14969  * Checks whether @self is the #ClutterActor that has key focus
14970  *
14971  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
14972  *
14973  * Since: 1.4
14974  */
14975 gboolean
14976 clutter_actor_has_key_focus (ClutterActor *self)
14977 {
14978   ClutterActor *stage;
14979
14980   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14981
14982   stage = _clutter_actor_get_stage_internal (self);
14983   if (stage == NULL)
14984     return FALSE;
14985
14986   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
14987 }
14988
14989 static gboolean
14990 _clutter_actor_get_paint_volume_real (ClutterActor *self,
14991                                       ClutterPaintVolume *pv)
14992 {
14993   ClutterActorPrivate *priv = self->priv;
14994
14995   /* Actors are only expected to report a valid paint volume
14996    * while they have a valid allocation. */
14997   if (G_UNLIKELY (priv->needs_allocation))
14998     {
14999       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15000                     "Actor needs allocation",
15001                     _clutter_actor_get_debug_name (self));
15002       return FALSE;
15003     }
15004
15005   /* Check if there are any handlers connected to the paint
15006    * signal. If there are then all bets are off for what the paint
15007    * volume for this actor might possibly be!
15008    *
15009    * XXX: It's expected that this is going to end up being quite a
15010    * costly check to have to do here, but we haven't come up with
15011    * another solution that can reliably catch paint signal handlers at
15012    * the right time to either avoid artefacts due to invalid stage
15013    * clipping or due to incorrect culling.
15014    *
15015    * Previously we checked in clutter_actor_paint(), but at that time
15016    * we may already be using a stage clip that could be derived from
15017    * an invalid paint-volume. We used to try and handle that by
15018    * queuing a follow up, unclipped, redraw but still the previous
15019    * checking wasn't enough to catch invalid volumes involved in
15020    * culling (considering that containers may derive their volume from
15021    * children that haven't yet been painted)
15022    *
15023    * Longer term, improved solutions could be:
15024    * - Disallow painting in the paint signal, only allow using it
15025    *   for tracking when paints happen. We can add another API that
15026    *   allows monkey patching the paint of arbitrary actors but in a
15027    *   more controlled way and that also supports modifying the
15028    *   paint-volume.
15029    * - If we could be notified somehow when signal handlers are
15030    *   connected we wouldn't have to poll for handlers like this.
15031    */
15032   if (g_signal_has_handler_pending (self,
15033                                     actor_signals[PAINT],
15034                                     0,
15035                                     TRUE))
15036     {
15037       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15038                     "Actor has \"paint\" signal handlers",
15039                     _clutter_actor_get_debug_name (self));
15040       return FALSE;
15041     }
15042
15043   _clutter_paint_volume_init_static (pv, self);
15044
15045   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15046     {
15047       clutter_paint_volume_free (pv);
15048       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15049                     "Actor failed to report a volume",
15050                     _clutter_actor_get_debug_name (self));
15051       return FALSE;
15052     }
15053
15054   /* since effects can modify the paint volume, we allow them to actually
15055    * do this by making get_paint_volume() "context sensitive"
15056    */
15057   if (priv->effects != NULL)
15058     {
15059       if (priv->current_effect != NULL)
15060         {
15061           const GList *effects, *l;
15062
15063           /* if we are being called from within the paint sequence of
15064            * an actor, get the paint volume up to the current effect
15065            */
15066           effects = _clutter_meta_group_peek_metas (priv->effects);
15067           for (l = effects;
15068                l != NULL || (l != NULL && l->data != priv->current_effect);
15069                l = l->next)
15070             {
15071               if (!_clutter_effect_get_paint_volume (l->data, pv))
15072                 {
15073                   clutter_paint_volume_free (pv);
15074                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15075                                 "Effect (%s) failed to report a volume",
15076                                 _clutter_actor_get_debug_name (self),
15077                                 _clutter_actor_meta_get_debug_name (l->data));
15078                   return FALSE;
15079                 }
15080             }
15081         }
15082       else
15083         {
15084           const GList *effects, *l;
15085
15086           /* otherwise, get the cumulative volume */
15087           effects = _clutter_meta_group_peek_metas (priv->effects);
15088           for (l = effects; l != NULL; l = l->next)
15089             if (!_clutter_effect_get_paint_volume (l->data, pv))
15090               {
15091                 clutter_paint_volume_free (pv);
15092                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15093                               "Effect (%s) failed to report a volume",
15094                               _clutter_actor_get_debug_name (self),
15095                               _clutter_actor_meta_get_debug_name (l->data));
15096                 return FALSE;
15097               }
15098         }
15099     }
15100
15101   return TRUE;
15102 }
15103
15104 /* The public clutter_actor_get_paint_volume API returns a const
15105  * pointer since we return a pointer directly to the cached
15106  * PaintVolume associated with the actor and don't want the user to
15107  * inadvertently modify it, but for internal uses we sometimes need
15108  * access to the same PaintVolume but need to apply some book-keeping
15109  * modifications to it so we don't want a const pointer.
15110  */
15111 static ClutterPaintVolume *
15112 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15113 {
15114   ClutterActorPrivate *priv;
15115
15116   priv = self->priv;
15117
15118   if (priv->paint_volume_valid)
15119     clutter_paint_volume_free (&priv->paint_volume);
15120
15121   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15122     {
15123       priv->paint_volume_valid = TRUE;
15124       return &priv->paint_volume;
15125     }
15126   else
15127     {
15128       priv->paint_volume_valid = FALSE;
15129       return NULL;
15130     }
15131 }
15132
15133 /**
15134  * clutter_actor_get_paint_volume:
15135  * @self: a #ClutterActor
15136  *
15137  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15138  * when a paint volume can't be determined.
15139  *
15140  * The paint volume is defined as the 3D space occupied by an actor
15141  * when being painted.
15142  *
15143  * This function will call the <function>get_paint_volume()</function>
15144  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15145  * should not usually care about overriding the default implementation,
15146  * unless they are, for instance: painting outside their allocation, or
15147  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15148  * 3D depth).
15149  *
15150  * <note>2D actors overriding <function>get_paint_volume()</function>
15151  * ensure their volume has a depth of 0. (This will be true so long as
15152  * you don't call clutter_paint_volume_set_depth().)</note>
15153  *
15154  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15155  *   or %NULL if no volume could be determined. The returned pointer
15156  *   is not guaranteed to be valid across multiple frames; if you want
15157  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15158  *
15159  * Since: 1.6
15160  */
15161 const ClutterPaintVolume *
15162 clutter_actor_get_paint_volume (ClutterActor *self)
15163 {
15164   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15165
15166   return _clutter_actor_get_paint_volume_mutable (self);
15167 }
15168
15169 /**
15170  * clutter_actor_get_transformed_paint_volume:
15171  * @self: a #ClutterActor
15172  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15173  *    (or %NULL for the stage)
15174  *
15175  * Retrieves the 3D paint volume of an actor like
15176  * clutter_actor_get_paint_volume() does (Please refer to the
15177  * documentation of clutter_actor_get_paint_volume() for more
15178  * details.) and it additionally transforms the paint volume into the
15179  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15180  * is passed for @relative_to_ancestor)
15181  *
15182  * This can be used by containers that base their paint volume on
15183  * the volume of their children. Such containers can query the
15184  * transformed paint volume of all of its children and union them
15185  * together using clutter_paint_volume_union().
15186  *
15187  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15188  *   or %NULL if no volume could be determined. The returned pointer is
15189  *   not guaranteed to be valid across multiple frames; if you wish to
15190  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15191  *
15192  * Since: 1.6
15193  */
15194 const ClutterPaintVolume *
15195 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15196                                             ClutterActor *relative_to_ancestor)
15197 {
15198   const ClutterPaintVolume *volume;
15199   ClutterActor *stage;
15200   ClutterPaintVolume *transformed_volume;
15201
15202   stage = _clutter_actor_get_stage_internal (self);
15203   if (G_UNLIKELY (stage == NULL))
15204     return NULL;
15205
15206   if (relative_to_ancestor == NULL)
15207     relative_to_ancestor = stage;
15208
15209   volume = clutter_actor_get_paint_volume (self);
15210   if (volume == NULL)
15211     return NULL;
15212
15213   transformed_volume =
15214     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15215
15216   _clutter_paint_volume_copy_static (volume, transformed_volume);
15217
15218   _clutter_paint_volume_transform_relative (transformed_volume,
15219                                             relative_to_ancestor);
15220
15221   return transformed_volume;
15222 }
15223
15224 /**
15225  * clutter_actor_get_paint_box:
15226  * @self: a #ClutterActor
15227  * @box: (out): return location for a #ClutterActorBox
15228  *
15229  * Retrieves the paint volume of the passed #ClutterActor, and
15230  * transforms it into a 2D bounding box in stage coordinates.
15231  *
15232  * This function is useful to determine the on screen area occupied by
15233  * the actor. The box is only an approximation and may often be
15234  * considerably larger due to the optimizations used to calculate the
15235  * box. The box is never smaller though, so it can reliably be used
15236  * for culling.
15237  *
15238  * There are times when a 2D paint box can't be determined, e.g.
15239  * because the actor isn't yet parented under a stage or because
15240  * the actor is unable to determine a paint volume.
15241  *
15242  * Return value: %TRUE if a 2D paint box could be determined, else
15243  * %FALSE.
15244  *
15245  * Since: 1.6
15246  */
15247 gboolean
15248 clutter_actor_get_paint_box (ClutterActor    *self,
15249                              ClutterActorBox *box)
15250 {
15251   ClutterActor *stage;
15252   ClutterPaintVolume *pv;
15253
15254   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15255   g_return_val_if_fail (box != NULL, FALSE);
15256
15257   stage = _clutter_actor_get_stage_internal (self);
15258   if (G_UNLIKELY (!stage))
15259     return FALSE;
15260
15261   pv = _clutter_actor_get_paint_volume_mutable (self);
15262   if (G_UNLIKELY (!pv))
15263     return FALSE;
15264
15265   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15266
15267   return TRUE;
15268 }
15269
15270 /**
15271  * clutter_actor_has_overlaps:
15272  * @self: A #ClutterActor
15273  *
15274  * Asks the actor's implementation whether it may contain overlapping
15275  * primitives.
15276  *
15277  * For example; Clutter may use this to determine whether the painting
15278  * should be redirected to an offscreen buffer to correctly implement
15279  * the opacity property.
15280  *
15281  * Custom actors can override the default response by implementing the
15282  * #ClutterActor <function>has_overlaps</function> virtual function. See
15283  * clutter_actor_set_offscreen_redirect() for more information.
15284  *
15285  * Return value: %TRUE if the actor may have overlapping primitives, and
15286  *   %FALSE otherwise
15287  *
15288  * Since: 1.8
15289  */
15290 gboolean
15291 clutter_actor_has_overlaps (ClutterActor *self)
15292 {
15293   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15294
15295   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15296 }
15297
15298 /**
15299  * clutter_actor_has_effects:
15300  * @self: A #ClutterActor
15301  *
15302  * Returns whether the actor has any effects applied.
15303  *
15304  * Return value: %TRUE if the actor has any effects,
15305  *   %FALSE otherwise
15306  *
15307  * Since: 1.10
15308  */
15309 gboolean
15310 clutter_actor_has_effects (ClutterActor *self)
15311 {
15312   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15313
15314   if (self->priv->effects == NULL)
15315     return FALSE;
15316
15317   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15318 }
15319
15320 /**
15321  * clutter_actor_has_constraints:
15322  * @self: A #ClutterActor
15323  *
15324  * Returns whether the actor has any constraints applied.
15325  *
15326  * Return value: %TRUE if the actor has any constraints,
15327  *   %FALSE otherwise
15328  *
15329  * Since: 1.10
15330  */
15331 gboolean
15332 clutter_actor_has_constraints (ClutterActor *self)
15333 {
15334   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15335
15336   return self->priv->constraints != NULL;
15337 }
15338
15339 /**
15340  * clutter_actor_has_actions:
15341  * @self: A #ClutterActor
15342  *
15343  * Returns whether the actor has any actions applied.
15344  *
15345  * Return value: %TRUE if the actor has any actions,
15346  *   %FALSE otherwise
15347  *
15348  * Since: 1.10
15349  */
15350 gboolean
15351 clutter_actor_has_actions (ClutterActor *self)
15352 {
15353   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15354
15355   return self->priv->actions != NULL;
15356 }
15357
15358 /**
15359  * clutter_actor_get_n_children:
15360  * @self: a #ClutterActor
15361  *
15362  * Retrieves the number of children of @self.
15363  *
15364  * Return value: the number of children of an actor
15365  *
15366  * Since: 1.10
15367  */
15368 gint
15369 clutter_actor_get_n_children (ClutterActor *self)
15370 {
15371   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15372
15373   return self->priv->n_children;
15374 }
15375
15376 /**
15377  * clutter_actor_get_child_at_index:
15378  * @self: a #ClutterActor
15379  * @index_: the position in the list of children
15380  *
15381  * Retrieves the actor at the given @index_ inside the list of
15382  * children of @self.
15383  *
15384  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15385  *
15386  * Since: 1.10
15387  */
15388 ClutterActor *
15389 clutter_actor_get_child_at_index (ClutterActor *self,
15390                                   gint          index_)
15391 {
15392   ClutterActor *iter;
15393   int i;
15394
15395   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15396   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15397
15398   for (iter = self->priv->first_child, i = 0;
15399        iter != NULL && i < index_;
15400        iter = iter->priv->next_sibling, i += 1)
15401     ;
15402
15403   return iter;
15404 }
15405
15406 /*< private >
15407  * _clutter_actor_foreach_child:
15408  * @actor: The actor whos children you want to iterate
15409  * @callback: The function to call for each child
15410  * @user_data: Private data to pass to @callback
15411  *
15412  * Calls a given @callback once for each child of the specified @actor and
15413  * passing the @user_data pointer each time.
15414  *
15415  * Return value: returns %TRUE if all children were iterated, else
15416  *    %FALSE if a callback broke out of iteration early.
15417  */
15418 gboolean
15419 _clutter_actor_foreach_child (ClutterActor           *self,
15420                               ClutterForeachCallback  callback,
15421                               gpointer                user_data)
15422 {
15423   ClutterActorPrivate *priv = self->priv;
15424   ClutterActor *iter;
15425   gboolean cont;
15426
15427   for (cont = TRUE, iter = priv->first_child;
15428        cont && iter != NULL;
15429        iter = iter->priv->next_sibling)
15430     {
15431       cont = callback (iter, user_data);
15432     }
15433
15434   return cont;
15435 }
15436
15437 #if 0
15438 /* For debugging purposes this gives us a simple way to print out
15439  * the scenegraph e.g in gdb using:
15440  * [|
15441  *   _clutter_actor_traverse (stage,
15442  *                            0,
15443  *                            clutter_debug_print_actor_cb,
15444  *                            NULL,
15445  *                            NULL);
15446  * |]
15447  */
15448 static ClutterActorTraverseVisitFlags
15449 clutter_debug_print_actor_cb (ClutterActor *actor,
15450                               int depth,
15451                               void *user_data)
15452 {
15453   g_print ("%*s%s:%p\n",
15454            depth * 2, "",
15455            _clutter_actor_get_debug_name (actor),
15456            actor);
15457
15458   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15459 }
15460 #endif
15461
15462 static void
15463 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15464                                  ClutterTraverseCallback callback,
15465                                  gpointer                user_data)
15466 {
15467   GQueue *queue = g_queue_new ();
15468   ClutterActor dummy;
15469   int current_depth = 0;
15470
15471   g_queue_push_tail (queue, actor);
15472   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15473
15474   while ((actor = g_queue_pop_head (queue)))
15475     {
15476       ClutterActorTraverseVisitFlags flags;
15477
15478       if (actor == &dummy)
15479         {
15480           current_depth++;
15481           g_queue_push_tail (queue, &dummy);
15482           continue;
15483         }
15484
15485       flags = callback (actor, current_depth, user_data);
15486       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15487         break;
15488       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15489         {
15490           ClutterActor *iter;
15491
15492           for (iter = actor->priv->first_child;
15493                iter != NULL;
15494                iter = iter->priv->next_sibling)
15495             {
15496               g_queue_push_tail (queue, iter);
15497             }
15498         }
15499     }
15500
15501   g_queue_free (queue);
15502 }
15503
15504 static ClutterActorTraverseVisitFlags
15505 _clutter_actor_traverse_depth (ClutterActor           *actor,
15506                                ClutterTraverseCallback before_children_callback,
15507                                ClutterTraverseCallback after_children_callback,
15508                                int                     current_depth,
15509                                gpointer                user_data)
15510 {
15511   ClutterActorTraverseVisitFlags flags;
15512
15513   flags = before_children_callback (actor, current_depth, user_data);
15514   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15515     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15516
15517   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15518     {
15519       ClutterActor *iter;
15520
15521       for (iter = actor->priv->first_child;
15522            iter != NULL;
15523            iter = iter->priv->next_sibling)
15524         {
15525           flags = _clutter_actor_traverse_depth (iter,
15526                                                  before_children_callback,
15527                                                  after_children_callback,
15528                                                  current_depth + 1,
15529                                                  user_data);
15530
15531           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15532             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15533         }
15534     }
15535
15536   if (after_children_callback)
15537     return after_children_callback (actor, current_depth, user_data);
15538   else
15539     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15540 }
15541
15542 /* _clutter_actor_traverse:
15543  * @actor: The actor to start traversing the graph from
15544  * @flags: These flags may affect how the traversal is done
15545  * @before_children_callback: A function to call before visiting the
15546  *   children of the current actor.
15547  * @after_children_callback: A function to call after visiting the
15548  *   children of the current actor. (Ignored if
15549  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15550  * @user_data: The private data to pass to the callbacks
15551  *
15552  * Traverses the scenegraph starting at the specified @actor and
15553  * descending through all its children and its children's children.
15554  * For each actor traversed @before_children_callback and
15555  * @after_children_callback are called with the specified
15556  * @user_data, before and after visiting that actor's children.
15557  *
15558  * The callbacks can return flags that affect the ongoing traversal
15559  * such as by skipping over an actors children or bailing out of
15560  * any further traversing.
15561  */
15562 void
15563 _clutter_actor_traverse (ClutterActor              *actor,
15564                          ClutterActorTraverseFlags  flags,
15565                          ClutterTraverseCallback    before_children_callback,
15566                          ClutterTraverseCallback    after_children_callback,
15567                          gpointer                   user_data)
15568 {
15569   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15570     _clutter_actor_traverse_breadth (actor,
15571                                      before_children_callback,
15572                                      user_data);
15573   else /* DEPTH_FIRST */
15574     _clutter_actor_traverse_depth (actor,
15575                                    before_children_callback,
15576                                    after_children_callback,
15577                                    0, /* start depth */
15578                                    user_data);
15579 }
15580
15581 static void
15582 on_layout_manager_changed (ClutterLayoutManager *manager,
15583                            ClutterActor         *self)
15584 {
15585   clutter_actor_queue_relayout (self);
15586 }
15587
15588 /**
15589  * clutter_actor_set_layout_manager:
15590  * @self: a #ClutterActor
15591  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15592  *
15593  * Sets the #ClutterLayoutManager delegate object that will be used to
15594  * lay out the children of @self.
15595  *
15596  * The #ClutterActor will take a reference on the passed @manager which
15597  * will be released either when the layout manager is removed, or when
15598  * the actor is destroyed.
15599  *
15600  * Since: 1.10
15601  */
15602 void
15603 clutter_actor_set_layout_manager (ClutterActor         *self,
15604                                   ClutterLayoutManager *manager)
15605 {
15606   ClutterActorPrivate *priv;
15607
15608   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15609   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15610
15611   priv = self->priv;
15612
15613   if (priv->layout_manager != NULL)
15614     {
15615       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15616                                             G_CALLBACK (on_layout_manager_changed),
15617                                             self);
15618       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15619       g_object_unref (priv->layout_manager);
15620     }
15621
15622   priv->layout_manager = manager;
15623
15624   if (priv->layout_manager != NULL)
15625     {
15626       g_object_ref_sink (priv->layout_manager);
15627       clutter_layout_manager_set_container (priv->layout_manager,
15628                                             CLUTTER_CONTAINER (self));
15629       g_signal_connect (priv->layout_manager, "layout-changed",
15630                         G_CALLBACK (on_layout_manager_changed),
15631                         self);
15632     }
15633
15634   clutter_actor_queue_relayout (self);
15635
15636   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15637 }
15638
15639 /**
15640  * clutter_actor_get_layout_manager:
15641  * @self: a #ClutterActor
15642  *
15643  * Retrieves the #ClutterLayoutManager used by @self.
15644  *
15645  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15646  *   or %NULL
15647  *
15648  * Since: 1.10
15649  */
15650 ClutterLayoutManager *
15651 clutter_actor_get_layout_manager (ClutterActor *self)
15652 {
15653   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15654
15655   return self->priv->layout_manager;
15656 }
15657
15658 static const ClutterLayoutInfo default_layout_info = {
15659   0.f,                          /* fixed-x */
15660   0.f,                          /* fixed-y */
15661   { 0, 0, 0, 0 },               /* margin */
15662   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15663   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15664   0.f, 0.f,                     /* min_width, natural_width */
15665   0.f, 0.f,                     /* natual_width, natural_height */
15666 };
15667
15668 static void
15669 layout_info_free (gpointer data)
15670 {
15671   if (G_LIKELY (data != NULL))
15672     g_slice_free (ClutterLayoutInfo, data);
15673 }
15674
15675 /*< private >
15676  * _clutter_actor_get_layout_info:
15677  * @self: a #ClutterActor
15678  *
15679  * Retrieves a pointer to the ClutterLayoutInfo structure.
15680  *
15681  * If the actor does not have a ClutterLayoutInfo associated to it, one
15682  * will be created and initialized to the default values.
15683  *
15684  * This function should be used for setters.
15685  *
15686  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15687  * instead.
15688  *
15689  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15690  */
15691 ClutterLayoutInfo *
15692 _clutter_actor_get_layout_info (ClutterActor *self)
15693 {
15694   ClutterLayoutInfo *retval;
15695
15696   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15697   if (retval == NULL)
15698     {
15699       retval = g_slice_new (ClutterLayoutInfo);
15700
15701       *retval = default_layout_info;
15702
15703       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15704                                retval,
15705                                layout_info_free);
15706     }
15707
15708   return retval;
15709 }
15710
15711 /*< private >
15712  * _clutter_actor_get_layout_info_or_defaults:
15713  * @self: a #ClutterActor
15714  *
15715  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15716  *
15717  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15718  * then the default structure will be returned.
15719  *
15720  * This function should only be used for getters.
15721  *
15722  * Return value: a const pointer to the ClutterLayoutInfo structure
15723  */
15724 const ClutterLayoutInfo *
15725 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15726 {
15727   const ClutterLayoutInfo *info;
15728
15729   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15730   if (info == NULL)
15731     return &default_layout_info;
15732
15733   return info;
15734 }
15735
15736 /**
15737  * clutter_actor_set_x_align:
15738  * @self: a #ClutterActor
15739  * @x_align: the horizontal alignment policy
15740  *
15741  * Sets the horizontal alignment policy of a #ClutterActor, in case the
15742  * actor received extra horizontal space.
15743  *
15744  * See also the #ClutterActor:x-align property.
15745  *
15746  * Since: 1.10
15747  */
15748 void
15749 clutter_actor_set_x_align (ClutterActor      *self,
15750                            ClutterActorAlign  x_align)
15751 {
15752   ClutterLayoutInfo *info;
15753
15754   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15755
15756   info = _clutter_actor_get_layout_info (self);
15757
15758   if (info->x_align != x_align)
15759     {
15760       info->x_align = x_align;
15761
15762       clutter_actor_queue_relayout (self);
15763
15764       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15765     }
15766 }
15767
15768 /**
15769  * clutter_actor_get_x_align:
15770  * @self: a #ClutterActor
15771  *
15772  * Retrieves the horizontal alignment policy set using
15773  * clutter_actor_set_x_align().
15774  *
15775  * Return value: the horizontal alignment policy.
15776  *
15777  * Since: 1.10
15778  */
15779 ClutterActorAlign
15780 clutter_actor_get_x_align (ClutterActor *self)
15781 {
15782   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15783
15784   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15785 }
15786
15787 /**
15788  * clutter_actor_set_y_align:
15789  * @self: a #ClutterActor
15790  * @y_align: the vertical alignment policy
15791  *
15792  * Sets the vertical alignment policy of a #ClutterActor, in case the
15793  * actor received extra vertical space.
15794  *
15795  * See also the #ClutterActor:y-align property.
15796  *
15797  * Since: 1.10
15798  */
15799 void
15800 clutter_actor_set_y_align (ClutterActor      *self,
15801                            ClutterActorAlign  y_align)
15802 {
15803   ClutterLayoutInfo *info;
15804
15805   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15806
15807   info = _clutter_actor_get_layout_info (self);
15808
15809   if (info->y_align != y_align)
15810     {
15811       info->y_align = y_align;
15812
15813       clutter_actor_queue_relayout (self);
15814
15815       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15816     }
15817 }
15818
15819 /**
15820  * clutter_actor_get_y_align:
15821  * @self: a #ClutterActor
15822  *
15823  * Retrieves the vertical alignment policy set using
15824  * clutter_actor_set_y_align().
15825  *
15826  * Return value: the vertical alignment policy.
15827  *
15828  * Since: 1.10
15829  */
15830 ClutterActorAlign
15831 clutter_actor_get_y_align (ClutterActor *self)
15832 {
15833   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15834
15835   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15836 }
15837
15838
15839 /**
15840  * clutter_margin_new:
15841  *
15842  * Creates a new #ClutterMargin.
15843  *
15844  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15845  *   clutter_margin_free() to free the resources associated with it when
15846  *   done.
15847  *
15848  * Since: 1.10
15849  */
15850 ClutterMargin *
15851 clutter_margin_new (void)
15852 {
15853   return g_slice_new0 (ClutterMargin);
15854 }
15855
15856 /**
15857  * clutter_margin_copy:
15858  * @margin_: a #ClutterMargin
15859  *
15860  * Creates a new #ClutterMargin and copies the contents of @margin_ into
15861  * the newly created structure.
15862  *
15863  * Return value: (transfer full): a copy of the #ClutterMargin.
15864  *
15865  * Since: 1.10
15866  */
15867 ClutterMargin *
15868 clutter_margin_copy (const ClutterMargin *margin_)
15869 {
15870   if (G_LIKELY (margin_ != NULL))
15871     return g_slice_dup (ClutterMargin, margin_);
15872
15873   return NULL;
15874 }
15875
15876 /**
15877  * clutter_margin_free:
15878  * @margin_: a #ClutterMargin
15879  *
15880  * Frees the resources allocated by clutter_margin_new() and
15881  * clutter_margin_copy().
15882  *
15883  * Since: 1.10
15884  */
15885 void
15886 clutter_margin_free (ClutterMargin *margin_)
15887 {
15888   if (G_LIKELY (margin_ != NULL))
15889     g_slice_free (ClutterMargin, margin_);
15890 }
15891
15892 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
15893                      clutter_margin_copy,
15894                      clutter_margin_free)
15895
15896 /**
15897  * clutter_actor_set_margin:
15898  * @self: a #ClutterActor
15899  * @margin: a #ClutterMargin
15900  *
15901  * Sets all the components of the margin of a #ClutterActor.
15902  *
15903  * Since: 1.10
15904  */
15905 void
15906 clutter_actor_set_margin (ClutterActor        *self,
15907                           const ClutterMargin *margin)
15908 {
15909   ClutterLayoutInfo *info;
15910   gboolean changed;
15911   GObject *obj;
15912
15913   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15914   g_return_if_fail (margin != NULL);
15915
15916   obj = G_OBJECT (self);
15917   changed = FALSE;
15918
15919   g_object_freeze_notify (obj);
15920
15921   info = _clutter_actor_get_layout_info (self);
15922
15923   if (info->margin.top != margin->top)
15924     {
15925       info->margin.top = margin->top;
15926       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
15927       changed = TRUE;
15928     }
15929
15930   if (info->margin.right != margin->right)
15931     {
15932       info->margin.right = margin->right;
15933       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
15934       changed = TRUE;
15935     }
15936
15937   if (info->margin.bottom != margin->bottom)
15938     {
15939       info->margin.bottom = margin->bottom;
15940       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
15941       changed = TRUE;
15942     }
15943
15944   if (info->margin.left != margin->left)
15945     {
15946       info->margin.left = margin->left;
15947       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
15948       changed = TRUE;
15949     }
15950
15951   if (changed)
15952     clutter_actor_queue_relayout (self);
15953
15954   g_object_thaw_notify (obj);
15955 }
15956
15957 /**
15958  * clutter_actor_get_margin:
15959  * @self: a #ClutterActor
15960  * @margin: (out caller-allocates): return location for a #ClutterMargin
15961  *
15962  * Retrieves all the components of the margin of a #ClutterActor.
15963  *
15964  * Since: 1.10
15965  */
15966 void
15967 clutter_actor_get_margin (ClutterActor  *self,
15968                           ClutterMargin *margin)
15969 {
15970   const ClutterLayoutInfo *info;
15971
15972   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15973   g_return_if_fail (margin != NULL);
15974
15975   info = _clutter_actor_get_layout_info_or_defaults (self);
15976
15977   *margin = info->margin;
15978 }
15979
15980 /**
15981  * clutter_actor_set_margin_top:
15982  * @self: a #ClutterActor
15983  * @margin: the top margin
15984  *
15985  * Sets the margin from the top of a #ClutterActor.
15986  *
15987  * Since: 1.10
15988  */
15989 void
15990 clutter_actor_set_margin_top (ClutterActor *self,
15991                               gfloat        margin)
15992 {
15993   ClutterLayoutInfo *info;
15994
15995   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15996   g_return_if_fail (margin >= 0.f);
15997
15998   info = _clutter_actor_get_layout_info (self);
15999
16000   if (info->margin.top == margin)
16001     return;
16002
16003   info->margin.top = margin;
16004
16005   clutter_actor_queue_relayout (self);
16006
16007   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16008 }
16009
16010 /**
16011  * clutter_actor_get_margin_top:
16012  * @self: a #ClutterActor
16013  *
16014  * Retrieves the top margin of a #ClutterActor.
16015  *
16016  * Return value: the top margin
16017  *
16018  * Since: 1.10
16019  */
16020 gfloat
16021 clutter_actor_get_margin_top (ClutterActor *self)
16022 {
16023   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16024
16025   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16026 }
16027
16028 /**
16029  * clutter_actor_set_margin_bottom:
16030  * @self: a #ClutterActor
16031  * @margin: the bottom margin
16032  *
16033  * Sets the margin from the bottom of a #ClutterActor.
16034  *
16035  * Since: 1.10
16036  */
16037 void
16038 clutter_actor_set_margin_bottom (ClutterActor *self,
16039                                  gfloat        margin)
16040 {
16041   ClutterLayoutInfo *info;
16042
16043   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16044   g_return_if_fail (margin >= 0.f);
16045
16046   info = _clutter_actor_get_layout_info (self);
16047
16048   if (info->margin.bottom == margin)
16049     return;
16050
16051   info->margin.bottom = margin;
16052
16053   clutter_actor_queue_relayout (self);
16054
16055   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16056 }
16057
16058 /**
16059  * clutter_actor_get_margin_bottom:
16060  * @self: a #ClutterActor
16061  *
16062  * Retrieves the bottom margin of a #ClutterActor.
16063  *
16064  * Return value: the bottom margin
16065  *
16066  * Since: 1.10
16067  */
16068 gfloat
16069 clutter_actor_get_margin_bottom (ClutterActor *self)
16070 {
16071   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16072
16073   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16074 }
16075
16076 /**
16077  * clutter_actor_set_margin_left:
16078  * @self: a #ClutterActor
16079  * @margin: the left margin
16080  *
16081  * Sets the margin from the left of a #ClutterActor.
16082  *
16083  * Since: 1.10
16084  */
16085 void
16086 clutter_actor_set_margin_left (ClutterActor *self,
16087                                gfloat        margin)
16088 {
16089   ClutterLayoutInfo *info;
16090
16091   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16092   g_return_if_fail (margin >= 0.f);
16093
16094   info = _clutter_actor_get_layout_info (self);
16095
16096   if (info->margin.left == margin)
16097     return;
16098
16099   info->margin.left = margin;
16100
16101   clutter_actor_queue_relayout (self);
16102
16103   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16104 }
16105
16106 /**
16107  * clutter_actor_get_margin_left:
16108  * @self: a #ClutterActor
16109  *
16110  * Retrieves the left margin of a #ClutterActor.
16111  *
16112  * Return value: the left margin
16113  *
16114  * Since: 1.10
16115  */
16116 gfloat
16117 clutter_actor_get_margin_left (ClutterActor *self)
16118 {
16119   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16120
16121   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16122 }
16123
16124 /**
16125  * clutter_actor_set_margin_right:
16126  * @self: a #ClutterActor
16127  * @margin: the right margin
16128  *
16129  * Sets the margin from the right of a #ClutterActor.
16130  *
16131  * Since: 1.10
16132  */
16133 void
16134 clutter_actor_set_margin_right (ClutterActor *self,
16135                                 gfloat        margin)
16136 {
16137   ClutterLayoutInfo *info;
16138
16139   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16140   g_return_if_fail (margin >= 0.f);
16141
16142   info = _clutter_actor_get_layout_info (self);
16143
16144   if (info->margin.right == margin)
16145     return;
16146
16147   info->margin.right = margin;
16148
16149   clutter_actor_queue_relayout (self);
16150
16151   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16152 }
16153
16154 /**
16155  * clutter_actor_get_margin_right:
16156  * @self: a #ClutterActor
16157  *
16158  * Retrieves the right margin of a #ClutterActor.
16159  *
16160  * Return value: the right margin
16161  *
16162  * Since: 1.10
16163  */
16164 gfloat
16165 clutter_actor_get_margin_right (ClutterActor *self)
16166 {
16167   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16168
16169   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16170 }
16171
16172 static inline void
16173 clutter_actor_set_background_color_internal (ClutterActor *self,
16174                                              const ClutterColor *color)
16175 {
16176   ClutterActorPrivate *priv = self->priv;
16177   GObject *obj;
16178
16179   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16180     return;
16181
16182   obj = G_OBJECT (self);
16183
16184   priv->bg_color = *color;
16185   priv->bg_color_set = TRUE;
16186
16187   clutter_actor_queue_redraw (self);
16188
16189   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16190   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16191 }
16192
16193 /**
16194  * clutter_actor_set_background_color:
16195  * @self: a #ClutterActor
16196  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16197  *  set color
16198  *
16199  * Sets the background color of a #ClutterActor.
16200  *
16201  * The background color will be used to cover the whole allocation of the
16202  * actor. The default background color of an actor is transparent.
16203  *
16204  * To check whether an actor has a background color, you can use the
16205  * #ClutterActor:background-color-set actor property.
16206  *
16207  * The #ClutterActor:background-color property is animatable.
16208  *
16209  * Since: 1.10
16210  */
16211 void
16212 clutter_actor_set_background_color (ClutterActor       *self,
16213                                     const ClutterColor *color)
16214 {
16215   ClutterActorPrivate *priv;
16216   GObject *obj;
16217   GParamSpec *bg_color_pspec;
16218
16219   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16220
16221   obj = G_OBJECT (self);
16222
16223   priv = self->priv;
16224
16225   if (color == NULL)
16226     {
16227       priv->bg_color_set = FALSE;
16228       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16229       clutter_actor_queue_redraw (self);
16230       return;
16231     }
16232
16233   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16234   if (clutter_actor_get_easing_duration (self) != 0)
16235     {
16236       ClutterTransition *transition;
16237
16238       transition = _clutter_actor_get_transition (self, bg_color_pspec);
16239       if (transition == NULL)
16240         {
16241           transition = _clutter_actor_create_transition (self, bg_color_pspec,
16242                                                          &priv->bg_color,
16243                                                          color);
16244           clutter_timeline_start (CLUTTER_TIMELINE (transition));
16245         }
16246       else
16247         _clutter_actor_update_transition (self, bg_color_pspec, color);
16248
16249       clutter_actor_queue_redraw (self);
16250     }
16251   else
16252     clutter_actor_set_background_color_internal (self, color);
16253 }
16254
16255 /**
16256  * clutter_actor_get_background_color:
16257  * @self: a #ClutterActor
16258  * @color: (out caller-allocates): return location for a #ClutterColor
16259  *
16260  * Retrieves the color set using clutter_actor_set_background_color().
16261  *
16262  * Since: 1.10
16263  */
16264 void
16265 clutter_actor_get_background_color (ClutterActor *self,
16266                                     ClutterColor *color)
16267 {
16268   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16269   g_return_if_fail (color != NULL);
16270
16271   *color = self->priv->bg_color;
16272 }
16273
16274 /**
16275  * clutter_actor_get_previous_sibling:
16276  * @self: a #ClutterActor
16277  *
16278  * Retrieves the sibling of @self that comes before it in the list
16279  * of children of @self's parent.
16280  *
16281  * The returned pointer is only valid until the scene graph changes; it
16282  * is not safe to modify the list of children of @self while iterating
16283  * it.
16284  *
16285  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16286  *
16287  * Since: 1.10
16288  */
16289 ClutterActor *
16290 clutter_actor_get_previous_sibling (ClutterActor *self)
16291 {
16292   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16293
16294   return self->priv->prev_sibling;
16295 }
16296
16297 /**
16298  * clutter_actor_get_next_sibling:
16299  * @self: a #ClutterActor
16300  *
16301  * Retrieves the sibling of @self that comes after it in the list
16302  * of children of @self's parent.
16303  *
16304  * The returned pointer is only valid until the scene graph changes; it
16305  * is not safe to modify the list of children of @self while iterating
16306  * it.
16307  *
16308  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16309  *
16310  * Since: 1.10
16311  */
16312 ClutterActor *
16313 clutter_actor_get_next_sibling (ClutterActor *self)
16314 {
16315   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16316
16317   return self->priv->next_sibling;
16318 }
16319
16320 /**
16321  * clutter_actor_get_first_child:
16322  * @self: a #ClutterActor
16323  *
16324  * Retrieves the first child of @self.
16325  *
16326  * The returned pointer is only valid until the scene graph changes; it
16327  * is not safe to modify the list of children of @self while iterating
16328  * it.
16329  *
16330  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16331  *
16332  * Since: 1.10
16333  */
16334 ClutterActor *
16335 clutter_actor_get_first_child (ClutterActor *self)
16336 {
16337   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16338
16339   return self->priv->first_child;
16340 }
16341
16342 /**
16343  * clutter_actor_get_last_child:
16344  * @self: a #ClutterActor
16345  *
16346  * Retrieves the last child of @self.
16347  *
16348  * The returned pointer is only valid until the scene graph changes; it
16349  * is not safe to modify the list of children of @self while iterating
16350  * it.
16351  *
16352  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16353  *
16354  * Since: 1.10
16355  */
16356 ClutterActor *
16357 clutter_actor_get_last_child (ClutterActor *self)
16358 {
16359   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16360
16361   return self->priv->last_child;
16362 }
16363
16364 /* easy way to have properly named fields instead of the dummy ones
16365  * we use in the public structure
16366  */
16367 typedef struct _RealActorIter
16368 {
16369   ClutterActor *root;           /* dummy1 */
16370   ClutterActor *current;        /* dummy2 */
16371   gpointer padding_1;           /* dummy3 */
16372   gint age;                     /* dummy4 */
16373   gpointer padding_2;           /* dummy5 */
16374 } RealActorIter;
16375
16376 /**
16377  * clutter_actor_iter_init:
16378  * @iter: a #ClutterActorIter
16379  * @root: a #ClutterActor
16380  *
16381  * Initializes a #ClutterActorIter, which can then be used to iterate
16382  * efficiently over a section of the scene graph, and associates it
16383  * with @root.
16384  *
16385  * Modifying the scene graph section that contains @root will invalidate
16386  * the iterator.
16387  *
16388  * |[
16389  *   ClutterActorIter iter;
16390  *   ClutterActor *child;
16391  *
16392  *   clutter_actor_iter_init (&iter, container);
16393  *   while (clutter_actor_iter_next (&iter, &child))
16394  *     {
16395  *       /&ast; do something with child &ast;/
16396  *     }
16397  * ]|
16398  *
16399  * Since: 1.10
16400  */
16401 void
16402 clutter_actor_iter_init (ClutterActorIter *iter,
16403                          ClutterActor     *root)
16404 {
16405   RealActorIter *ri = (RealActorIter *) iter;
16406
16407   g_return_if_fail (iter != NULL);
16408   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16409
16410   ri->root = root;
16411   ri->current = NULL;
16412   ri->age = root->priv->age;
16413 }
16414
16415 /**
16416  * clutter_actor_iter_next:
16417  * @iter: a #ClutterActorIter
16418  * @child: (out): return location for a #ClutterActor
16419  *
16420  * Advances the @iter and retrieves the next child of the root #ClutterActor
16421  * that was used to initialize the #ClutterActorIterator.
16422  *
16423  * If the iterator can advance, this function returns %TRUE and sets the
16424  * @child argument.
16425  *
16426  * If the iterator cannot advance, this function returns %FALSE, and
16427  * the contents of @child are undefined.
16428  *
16429  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16430  *
16431  * Since: 1.10
16432  */
16433 gboolean
16434 clutter_actor_iter_next (ClutterActorIter  *iter,
16435                          ClutterActor     **child)
16436 {
16437   RealActorIter *ri = (RealActorIter *) iter;
16438
16439   g_return_val_if_fail (iter != NULL, FALSE);
16440   g_return_val_if_fail (ri->root != NULL, FALSE);
16441 #ifndef G_DISABLE_ASSERT
16442   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16443 #endif
16444
16445   if (ri->current == NULL)
16446     ri->current = ri->root->priv->first_child;
16447   else
16448     ri->current = ri->current->priv->next_sibling;
16449
16450   if (child != NULL)
16451     *child = ri->current;
16452
16453   return ri->current != NULL;
16454 }
16455
16456 /**
16457  * clutter_actor_iter_prev:
16458  * @iter: a #ClutterActorIter
16459  * @child: (out): return location for a #ClutterActor
16460  *
16461  * Advances the @iter and retrieves the previous child of the root
16462  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16463  *
16464  * If the iterator can advance, this function returns %TRUE and sets the
16465  * @child argument.
16466  *
16467  * If the iterator cannot advance, this function returns %FALSE, and
16468  * the contents of @child are undefined.
16469  *
16470  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16471  *
16472  * Since: 1.10
16473  */
16474 gboolean
16475 clutter_actor_iter_prev (ClutterActorIter  *iter,
16476                          ClutterActor     **child)
16477 {
16478   RealActorIter *ri = (RealActorIter *) iter;
16479
16480   g_return_val_if_fail (iter != NULL, FALSE);
16481   g_return_val_if_fail (ri->root != NULL, FALSE);
16482 #ifndef G_DISABLE_ASSERT
16483   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16484 #endif
16485
16486   if (ri->current == NULL)
16487     ri->current = ri->root->priv->last_child;
16488   else
16489     ri->current = ri->current->priv->prev_sibling;
16490
16491   if (child != NULL)
16492     *child = ri->current;
16493
16494   return ri->current != NULL;
16495 }
16496
16497 /**
16498  * clutter_actor_iter_remove:
16499  * @iter: a #ClutterActorIter
16500  *
16501  * Safely removes the #ClutterActor currently pointer to by the iterator
16502  * from its parent.
16503  *
16504  * This function can only be called after clutter_actor_iter_next() or
16505  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16506  * than once for the same actor.
16507  *
16508  * This function will call clutter_actor_remove_child() internally.
16509  *
16510  * Since: 1.10
16511  */
16512 void
16513 clutter_actor_iter_remove (ClutterActorIter *iter)
16514 {
16515   RealActorIter *ri = (RealActorIter *) iter;
16516   ClutterActor *cur;
16517
16518   g_return_if_fail (iter != NULL);
16519   g_return_if_fail (ri->root != NULL);
16520 #ifndef G_DISABLE_ASSERT
16521   g_return_if_fail (ri->age == ri->root->priv->age);
16522 #endif
16523   g_return_if_fail (ri->current != NULL);
16524
16525   cur = ri->current;
16526
16527   if (cur != NULL)
16528     {
16529       ri->current = cur->priv->prev_sibling;
16530
16531       clutter_actor_remove_child_internal (ri->root, cur,
16532                                            REMOVE_CHILD_DEFAULT_FLAGS);
16533
16534       ri->age += 1;
16535     }
16536 }
16537
16538 /**
16539  * clutter_actor_iter_destroy:
16540  * @iter: a #ClutterActorIter
16541  *
16542  * Safely destroys the #ClutterActor currently pointer to by the iterator
16543  * from its parent.
16544  *
16545  * This function can only be called after clutter_actor_iter_next() or
16546  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16547  * than once for the same actor.
16548  *
16549  * This function will call clutter_actor_destroy() internally.
16550  *
16551  * Since: 1.10
16552  */
16553 void
16554 clutter_actor_iter_destroy (ClutterActorIter *iter)
16555 {
16556   RealActorIter *ri = (RealActorIter *) iter;
16557   ClutterActor *cur;
16558
16559   g_return_if_fail (iter != NULL);
16560   g_return_if_fail (ri->root != NULL);
16561 #ifndef G_DISABLE_ASSERT
16562   g_return_if_fail (ri->age == ri->root->priv->age);
16563 #endif
16564   g_return_if_fail (ri->current != NULL);
16565
16566   cur = ri->current;
16567
16568   if (cur != NULL)
16569     {
16570       ri->current = cur->priv->prev_sibling;
16571
16572       clutter_actor_destroy (cur);
16573
16574       ri->age += 1;
16575     }
16576 }
16577
16578 static const ClutterAnimationInfo default_animation_info = {
16579   NULL,         /* transitions */
16580   NULL,         /* states */
16581   NULL,         /* cur_state */
16582 };
16583
16584 static void
16585 clutter_animation_info_free (gpointer data)
16586 {
16587   if (data != NULL)
16588     {
16589       ClutterAnimationInfo *info = data;
16590
16591       if (info->transitions != NULL)
16592         g_hash_table_unref (info->transitions);
16593
16594       if (info->states != NULL)
16595         g_array_unref (info->states);
16596
16597       g_slice_free (ClutterAnimationInfo, info);
16598     }
16599 }
16600
16601 const ClutterAnimationInfo *
16602 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16603 {
16604   const ClutterAnimationInfo *res;
16605   GObject *obj = G_OBJECT (self);
16606
16607   res = g_object_get_qdata (obj, quark_actor_animation_info);
16608   if (res != NULL)
16609     return res;
16610
16611   return &default_animation_info;
16612 }
16613
16614 ClutterAnimationInfo *
16615 _clutter_actor_get_animation_info (ClutterActor *self)
16616 {
16617   GObject *obj = G_OBJECT (self);
16618   ClutterAnimationInfo *res;
16619
16620   res = g_object_get_qdata (obj, quark_actor_animation_info);
16621   if (res == NULL)
16622     {
16623       res = g_slice_new (ClutterAnimationInfo);
16624
16625       *res = default_animation_info;
16626
16627       g_object_set_qdata_full (obj, quark_actor_animation_info,
16628                                res,
16629                                clutter_animation_info_free);
16630     }
16631
16632   return res;
16633 }
16634
16635 ClutterTransition *
16636 _clutter_actor_get_transition (ClutterActor *actor,
16637                                GParamSpec   *pspec)
16638 {
16639   const ClutterAnimationInfo *info;
16640
16641   info = _clutter_actor_get_animation_info_or_defaults (actor);
16642
16643   if (info->transitions == NULL)
16644     return NULL;
16645
16646   return g_hash_table_lookup (info->transitions, pspec->name);
16647 }
16648
16649 typedef struct _TransitionClosure
16650 {
16651   ClutterActor *actor;
16652   ClutterTransition *transition;
16653   gchar *name;
16654   gulong completed_id;
16655 } TransitionClosure;
16656
16657 static void
16658 transition_closure_free (gpointer data)
16659 {
16660   if (G_LIKELY (data != NULL))
16661     {
16662       TransitionClosure *clos = data;
16663
16664       g_signal_handler_disconnect (clos->transition, clos->completed_id);
16665       g_free (clos->name);
16666
16667       g_slice_free (TransitionClosure, clos);
16668     }
16669 }
16670
16671 static void
16672 on_transition_completed (ClutterTransition *transition,
16673                          TransitionClosure *clos)
16674 {
16675   ClutterAnimationInfo *info;
16676
16677   info = _clutter_actor_get_animation_info (clos->actor);
16678
16679   /* this will take care of cleaning clos for us */
16680   g_hash_table_remove (info->transitions, clos->name);
16681 }
16682
16683 void
16684 _clutter_actor_update_transition (ClutterActor *actor,
16685                                   GParamSpec   *pspec,
16686                                   ...)
16687 {
16688   TransitionClosure *clos;
16689   ClutterInterval *interval;
16690   const ClutterAnimationInfo *info;
16691   va_list var_args;
16692   GType ptype;
16693   GValue initial = G_VALUE_INIT;
16694   GValue final = G_VALUE_INIT;
16695   char *error = NULL;
16696
16697   info = _clutter_actor_get_animation_info_or_defaults (actor);
16698
16699   if (info->transitions == NULL)
16700     return;
16701
16702   clos = g_hash_table_lookup (info->transitions, pspec->name);
16703   if (clos == NULL)
16704     return;
16705
16706   va_start (var_args, pspec);
16707
16708   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16709
16710   g_value_init (&initial, ptype);
16711   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
16712                                         pspec->name,
16713                                         &initial);
16714
16715   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
16716   if (error != NULL)
16717     {
16718       g_critical ("%s: %s", G_STRLOC, error);
16719       g_free (error);
16720       goto out;
16721     }
16722
16723   interval = clutter_transition_get_interval (clos->transition);
16724   clutter_interval_set_initial_value (interval, &initial);
16725   clutter_interval_set_final_value (interval, &final);
16726
16727   clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
16728
16729 out:
16730   g_value_unset (&initial);
16731   g_value_unset (&final);
16732
16733   va_end (var_args);
16734 }
16735
16736 /*< private >*
16737  * _clutter_actor_create_transition:
16738  * @actor: a #ClutterActor
16739  * @pspec: the property used for the transition
16740  * @...: initial and final state
16741  *
16742  * Creates a #ClutterTransition for the property represented by @pspec.
16743  *
16744  * Return value: a #ClutterTransition
16745  */
16746 ClutterTransition *
16747 _clutter_actor_create_transition (ClutterActor *actor,
16748                                   GParamSpec   *pspec,
16749                                   ...)
16750 {
16751   ClutterAnimationInfo *info;
16752   ClutterTransition *res = NULL;
16753   gboolean call_restore = FALSE;
16754   TransitionClosure *clos;
16755   va_list var_args;
16756
16757   info = _clutter_actor_get_animation_info (actor);
16758
16759   if (info->states == NULL)
16760     {
16761       clutter_actor_save_easing_state (actor);
16762       call_restore = TRUE;
16763     }
16764
16765   if (info->transitions == NULL)
16766     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
16767                                                NULL,
16768                                                transition_closure_free);
16769
16770   va_start (var_args, pspec);
16771
16772   clos = g_hash_table_lookup (info->transitions, pspec->name);
16773   if (clos == NULL)
16774     {
16775       ClutterInterval *interval;
16776       GValue initial = G_VALUE_INIT;
16777       GValue final = G_VALUE_INIT;
16778       GType ptype;
16779       char *error;
16780
16781       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16782
16783       G_VALUE_COLLECT_INIT (&initial, ptype,
16784                             var_args, 0,
16785                             &error);
16786       if (error != NULL)
16787         {
16788           g_critical ("%s: %s", G_STRLOC, error);
16789           g_free (error);
16790           goto out;
16791         }
16792
16793       G_VALUE_COLLECT_INIT (&final, ptype,
16794                             var_args, 0,
16795                             &error);
16796
16797       if (error != NULL)
16798         {
16799           g_critical ("%s: %s", G_STRLOC, error);
16800           g_value_unset (&initial);
16801           g_free (error);
16802           goto out;
16803         }
16804
16805       interval = clutter_interval_new_with_values (ptype, &initial, &final);
16806
16807       g_value_unset (&initial);
16808       g_value_unset (&final);
16809
16810       res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
16811                                              pspec->name);
16812
16813       clutter_transition_set_interval (res, interval);
16814       clutter_transition_set_remove_on_complete (res, TRUE);
16815
16816       clutter_actor_add_transition (actor, pspec->name, res);
16817     }
16818   else
16819     res = clos->transition;
16820
16821 out:
16822   if (call_restore)
16823     clutter_actor_restore_easing_state (actor);
16824
16825   va_end (var_args);
16826
16827   return res;
16828 }
16829
16830 /**
16831  * clutter_actor_add_transition:
16832  * @self: a #ClutterActor
16833  * @name: the name of the transition to add
16834  * @transition: the #ClutterTransition to add
16835  *
16836  * Adds a @transition to the #ClutterActor's list of animations.
16837  *
16838  * The @name string is a per-actor unique identifier of the @transition: only
16839  * one #ClutterTransition can be associated to the specified @name.
16840  *
16841  * The @transition will be given the easing duration, mode, and delay
16842  * associated to the actor's current easing state; it is possible to modify
16843  * these values after calling clutter_actor_add_transition().
16844  *
16845  * This function is usually called implicitly when modifying an animatable
16846  * property.
16847  *
16848  * Since: 1.10
16849  */
16850 void
16851 clutter_actor_add_transition (ClutterActor      *self,
16852                               const char        *name,
16853                               ClutterTransition *transition)
16854 {
16855   ClutterTimeline *timeline;
16856   TransitionClosure *clos;
16857   ClutterAnimationInfo *info;
16858
16859   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16860   g_return_if_fail (name != NULL);
16861   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
16862
16863   info = _clutter_actor_get_animation_info (self);
16864
16865   if (info->cur_state == NULL)
16866     {
16867       g_warning ("No easing state is defined for the actor '%s'; you "
16868                  "must call clutter_actor_save_easing_state() before "
16869                  "calling clutter_actor_add_transition().",
16870                  _clutter_actor_get_debug_name (self));
16871       return;
16872     }
16873
16874   if (info->transitions == NULL)
16875     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
16876                                                NULL,
16877                                                transition_closure_free);
16878
16879   if (g_hash_table_lookup (info->transitions, name) != NULL)
16880     {
16881       g_warning ("A transition with name '%s' already exists for "
16882                  "the actor '%s'",
16883                  name,
16884                  _clutter_actor_get_debug_name (self));
16885       return;
16886     }
16887
16888   timeline = CLUTTER_TIMELINE (transition);
16889
16890   clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
16891   clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
16892   clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
16893
16894   clos = g_slice_new (TransitionClosure);
16895   clos->actor = self;
16896   clos->transition = transition;
16897   clos->name = g_strdup (name);
16898   clos->completed_id = g_signal_connect (timeline, "completed",
16899                                          G_CALLBACK (on_transition_completed),
16900                                          clos);
16901
16902   g_hash_table_insert (info->transitions, clos->name, clos);
16903 }
16904
16905 /**
16906  * clutter_actor_remove_transition:
16907  * @self: a #ClutterActor
16908  * @name: the name of the transition to remove
16909  *
16910  * Removes the transition stored inside a #ClutterActor using @name
16911  * identifier.
16912  *
16913  * Since: 1.10
16914  */
16915 void
16916 clutter_actor_remove_transition (ClutterActor *self,
16917                                  const char   *name)
16918 {
16919   const ClutterAnimationInfo *info;
16920
16921   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16922   g_return_if_fail (name != NULL);
16923
16924   info = _clutter_actor_get_animation_info_or_defaults (self);
16925
16926   if (info->transitions == NULL)
16927     return;
16928
16929   g_hash_table_remove (info->transitions, name);
16930 }
16931
16932 /**
16933  * clutter_actor_remove_all_transitions:
16934  * @self: a #ClutterActor
16935  *
16936  * Removes all transitions associated to @self.
16937  *
16938  * Since: 1.10
16939  */
16940 void
16941 clutter_actor_remove_all_transitions (ClutterActor *self)
16942 {
16943   const ClutterAnimationInfo *info;
16944
16945   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16946
16947   info = _clutter_actor_get_animation_info_or_defaults (self);
16948   if (info->transitions == NULL)
16949     return;
16950
16951   g_hash_table_remove_all (info->transitions);
16952 }
16953
16954 /**
16955  * clutter_actor_set_easing_duration:
16956  * @self: a #ClutterActor
16957  * @msecs: the duration of the easing, or %NULL
16958  *
16959  * Sets the duration of the tweening for animatable properties
16960  * of @self for the current easing state.
16961  *
16962  * Calling this function will implicitly call
16963  * clutter_actor_save_easing_state() if no previous call to
16964  * that function was made.
16965  *
16966  * Since: 1.10
16967  */
16968 void
16969 clutter_actor_set_easing_duration (ClutterActor *self,
16970                                    guint         msecs)
16971 {
16972   ClutterAnimationInfo *info;
16973
16974   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16975
16976   info = _clutter_actor_get_animation_info (self);
16977
16978   if (info->states == NULL)
16979     clutter_actor_save_easing_state (self);
16980
16981   if (info->cur_state->easing_duration != msecs)
16982     info->cur_state->easing_duration = msecs;
16983 }
16984
16985 /**
16986  * clutter_actor_get_easing_duration:
16987  * @self: a #ClutterActor
16988  *
16989  * Retrieves the duration of the tweening for animatable
16990  * properties of @self for the current easing state.
16991  *
16992  * Return value: the duration of the tweening, in milliseconds
16993  *
16994  * Since: 1.10
16995  */
16996 guint
16997 clutter_actor_get_easing_duration (ClutterActor *self)
16998 {
16999   const ClutterAnimationInfo *info;
17000
17001   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17002
17003   info = _clutter_actor_get_animation_info_or_defaults (self);
17004
17005   if (info->cur_state != NULL)
17006     return info->cur_state->easing_duration;
17007
17008   return 0;
17009 }
17010
17011 /**
17012  * clutter_actor_set_easing_mode:
17013  * @self: a #ClutterActor
17014  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17015  *
17016  * Sets the easing mode for the tweening of animatable properties
17017  * of @self.
17018  *
17019  * Calling this function will implicitly call
17020  * clutter_actor_save_easing_state() if no previous calls to
17021  * that function were made.
17022  *
17023  * Since: 1.10
17024  */
17025 void
17026 clutter_actor_set_easing_mode (ClutterActor         *self,
17027                                ClutterAnimationMode  mode)
17028 {
17029   ClutterAnimationInfo *info;
17030
17031   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17032   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17033   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17034
17035   info = _clutter_actor_get_animation_info (self);
17036
17037   if (info->states == NULL)
17038     clutter_actor_save_easing_state (self);
17039
17040   if (info->cur_state->easing_mode != mode)
17041     info->cur_state->easing_mode = mode;
17042 }
17043
17044 /**
17045  * clutter_actor_get_easing_mode:
17046  * @self: a #ClutterActor
17047  *
17048  * Retrieves the easing mode for the tweening of animatable properties
17049  * of @self for the current easing state.
17050  *
17051  * Return value: an easing mode
17052  *
17053  * Since: 1.10
17054  */
17055 ClutterAnimationMode
17056 clutter_actor_get_easing_mode (ClutterActor *self)
17057 {
17058   const ClutterAnimationInfo *info;
17059
17060   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17061
17062   info = _clutter_actor_get_animation_info_or_defaults (self);
17063
17064   if (info->cur_state != NULL)
17065     return info->cur_state->easing_mode;
17066
17067   return CLUTTER_EASE_OUT_CUBIC;
17068 }
17069
17070 /**
17071  * clutter_actor_set_easing_delay:
17072  * @self: a #ClutterActor
17073  * @msecs: the delay before the start of the tweening, in milliseconds
17074  *
17075  * Sets the delay that should be applied before tweening animatable
17076  * properties.
17077  *
17078  * Calling this function will implicitly call
17079  * clutter_actor_save_easing_state() if no previous calls to
17080  * that function were made.
17081  *
17082  * Since: 1.10
17083  */
17084 void
17085 clutter_actor_set_easing_delay (ClutterActor *self,
17086                                 guint         msecs)
17087 {
17088   ClutterAnimationInfo *info;
17089
17090   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17091
17092   info = _clutter_actor_get_animation_info (self);
17093
17094   if (info->states == NULL)
17095     clutter_actor_save_easing_state (self);
17096
17097   if (info->cur_state->easing_delay != msecs)
17098     info->cur_state->easing_delay = msecs;
17099 }
17100
17101 /**
17102  * clutter_actor_get_easing_delay:
17103  * @self: a #ClutterActor
17104  *
17105  * Retrieves the delay that should be applied when tweening animatable
17106  * properties.
17107  *
17108  * Return value: a delay, in milliseconds
17109  *
17110  * Since: 1.10
17111  */
17112 guint
17113 clutter_actor_get_easing_delay (ClutterActor *self)
17114 {
17115   const ClutterAnimationInfo *info;
17116
17117   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17118
17119   info = _clutter_actor_get_animation_info_or_defaults (self);
17120
17121   if (info->cur_state != NULL)
17122     return info->cur_state->easing_delay;
17123
17124   return 0;
17125 }
17126
17127 /**
17128  * clutter_actor_get_transition:
17129  * @self: a #ClutterActor
17130  * @name: the name of the transition
17131  *
17132  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17133  * transition @name.
17134  *
17135  * Transitions created for animatable properties use the name of the
17136  * property itself, for instance the code below:
17137  *
17138  * |[
17139  *   clutter_actor_set_easing_duration (actor, 1000);
17140  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17141  *
17142  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17143  *   g_signal_connect (transition, "completed",
17144  *                     G_CALLBACK (on_transition_complete),
17145  *                     actor);
17146  * ]|
17147  *
17148  * will call the <function>on_transition_complete</function> callback when
17149  * the transition is complete.
17150  *
17151  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17152  *   was found to match the passed name; the returned instance is owned
17153  *   by Clutter and it should not be freed
17154  *
17155  * Since: 1.10
17156  */
17157 ClutterTransition *
17158 clutter_actor_get_transition (ClutterActor *self,
17159                               const char   *name)
17160 {
17161   TransitionClosure *clos;
17162   const ClutterAnimationInfo *info;
17163
17164   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17165   g_return_val_if_fail (name != NULL, NULL);
17166
17167   info = _clutter_actor_get_animation_info_or_defaults (self);
17168
17169   if (info->transitions == NULL)
17170     return NULL;
17171
17172   clos = g_hash_table_lookup (info->transitions, name);
17173   if (clos == NULL)
17174     return NULL;
17175
17176   return clos->transition;
17177 }
17178
17179 /**
17180  * clutter_actor_save_easing_state:
17181  * @self: a #ClutterActor
17182  *
17183  * Saves the current easing state for animatable properties, and creates
17184  * a new state with the default values for easing mode and duration.
17185  *
17186  * Since: 1.10
17187  */
17188 void
17189 clutter_actor_save_easing_state (ClutterActor *self)
17190 {
17191   ClutterAnimationInfo *info;
17192   AState new_state;
17193
17194   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17195
17196   info = _clutter_actor_get_animation_info (self);
17197
17198   if (info->states == NULL)
17199     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17200
17201   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17202   new_state.easing_duration = 250;
17203   new_state.easing_delay = 0;
17204
17205   g_array_append_val (info->states, new_state);
17206
17207   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17208 }
17209
17210 /**
17211  * clutter_actor_restore_easing_state:
17212  * @self: a #ClutterActor
17213  *
17214  * Restores the easing state as it was prior to a call to
17215  * clutter_actor_save_easing_state().
17216  *
17217  * Since: 1.10
17218  */
17219 void
17220 clutter_actor_restore_easing_state (ClutterActor *self)
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     {
17230       g_critical ("The function clutter_actor_restore_easing_state() has "
17231                   "called without a previous call to "
17232                   "clutter_actor_save_easing_state().");
17233       return;
17234     }
17235
17236   g_array_remove_index (info->states, info->states->len - 1);
17237   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17238 }