Add ClutterContent
[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-content-private.h"
384 #include "clutter-debug.h"
385 #include "clutter-effect-private.h"
386 #include "clutter-enum-types.h"
387 #include "clutter-fixed-layout.h"
388 #include "clutter-flatten-effect.h"
389 #include "clutter-interval.h"
390 #include "clutter-main.h"
391 #include "clutter-marshal.h"
392 #include "clutter-paint-nodes.h"
393 #include "clutter-paint-node-private.h"
394 #include "clutter-paint-volume-private.h"
395 #include "clutter-private.h"
396 #include "clutter-profile.h"
397 #include "clutter-property-transition.h"
398 #include "clutter-scriptable.h"
399 #include "clutter-script-private.h"
400 #include "clutter-stage-private.h"
401 #include "clutter-timeline.h"
402 #include "clutter-transition.h"
403 #include "clutter-units.h"
404
405 #include "deprecated/clutter-actor.h"
406 #include "deprecated/clutter-behaviour.h"
407 #include "deprecated/clutter-container.h"
408
409 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
410 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
411
412 /* Internal enum used to control mapped state update.  This is a hint
413  * which indicates when to do something other than just enforce
414  * invariants.
415  */
416 typedef enum {
417   MAP_STATE_CHECK,           /* just enforce invariants. */
418   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
419                               * used when about to unparent.
420                               */
421   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
422                               * used to set mapped on toplevels.
423                               */
424   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
425                               * used just before unmapping parent.
426                               */
427 } MapStateChange;
428
429 /* 3 entries should be a good compromise, few layout managers
430  * will ask for 3 different preferred size in each allocation cycle */
431 #define N_CACHED_SIZE_REQUESTS 3
432
433 struct _ClutterActorPrivate
434 {
435   /* request mode */
436   ClutterRequestMode request_mode;
437
438   /* our cached size requests for different width / height */
439   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
440   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
441
442   /* An age of 0 means the entry is not set */
443   guint cached_height_age;
444   guint cached_width_age;
445
446   /* the bounding box of the actor, relative to the parent's
447    * allocation
448    */
449   ClutterActorBox allocation;
450   ClutterAllocationFlags allocation_flags;
451
452   /* clip, in actor coordinates */
453   cairo_rectangle_t clip;
454
455   /* the cached transformation matrix; see apply_transform() */
456   CoglMatrix transform;
457
458   guint8 opacity;
459   gint opacity_override;
460
461   ClutterOffscreenRedirect offscreen_redirect;
462
463   /* This is an internal effect used to implement the
464      offscreen-redirect property */
465   ClutterEffect *flatten_effect;
466
467   /* scene graph */
468   ClutterActor *parent;
469   ClutterActor *prev_sibling;
470   ClutterActor *next_sibling;
471   ClutterActor *first_child;
472   ClutterActor *last_child;
473
474   gint n_children;
475
476   /* tracks whenever the children of an actor are changed; the
477    * age is incremented by 1 whenever an actor is added or
478    * removed. the age is not incremented when the first or the
479    * last child pointers are changed, or when grandchildren of
480    * an actor are changed.
481    */
482   gint age;
483
484   gchar *name; /* a non-unique name, used for debugging */
485   guint32 id; /* unique id, used for backward compatibility */
486
487   gint32 pick_id; /* per-stage unique id, used for picking */
488
489   /* a back-pointer to the Pango context that we can use
490    * to create pre-configured PangoLayout
491    */
492   PangoContext *pango_context;
493
494   /* the text direction configured for this child - either by
495    * application code, or by the actor's parent
496    */
497   ClutterTextDirection text_direction;
498
499   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
500   gint internal_child;
501
502   /* meta classes */
503   ClutterMetaGroup *actions;
504   ClutterMetaGroup *constraints;
505   ClutterMetaGroup *effects;
506
507   /* delegate object used to allocate the children of this actor */
508   ClutterLayoutManager *layout_manager;
509
510   /* delegate object used to paint the contents of this actor */
511   ClutterContent *content;
512
513   ClutterContentGravity content_gravity;
514
515   /* used when painting, to update the paint volume */
516   ClutterEffect *current_effect;
517
518   /* This is used to store an effect which needs to be redrawn. A
519      redraw can be queued to start from a particular effect. This is
520      used by parametrised effects that can cache an image of the
521      actor. If a parameter of the effect changes then it only needs to
522      redraw the cached image, not the actual actor. The pointer is
523      only valid if is_dirty == TRUE. If the pointer is NULL then the
524      whole actor is dirty. */
525   ClutterEffect *effect_to_redraw;
526
527   /* This is used when painting effects to implement the
528      clutter_actor_continue_paint() function. It points to the node in
529      the list of effects that is next in the chain */
530   const GList *next_effect_to_paint;
531
532   ClutterPaintVolume paint_volume;
533
534   /* NB: This volume isn't relative to this actor, it is in eye
535    * coordinates so that it can remain valid after the actor changes.
536    */
537   ClutterPaintVolume last_paint_volume;
538
539   ClutterStageQueueRedrawEntry *queue_redraw_entry;
540
541   ClutterColor bg_color;
542
543   /* bitfields */
544
545   /* fixed position and sizes */
546   guint position_set                : 1;
547   guint min_width_set               : 1;
548   guint min_height_set              : 1;
549   guint natural_width_set           : 1;
550   guint natural_height_set          : 1;
551   /* cached request is invalid (implies allocation is too) */
552   guint needs_width_request         : 1;
553   /* cached request is invalid (implies allocation is too) */
554   guint needs_height_request        : 1;
555   /* cached allocation is invalid (request has changed, probably) */
556   guint needs_allocation            : 1;
557   guint show_on_set_parent          : 1;
558   guint has_clip                    : 1;
559   guint clip_to_allocation          : 1;
560   guint enable_model_view_transform : 1;
561   guint enable_paint_unmapped       : 1;
562   guint has_pointer                 : 1;
563   guint propagated_one_redraw       : 1;
564   guint paint_volume_valid          : 1;
565   guint last_paint_volume_valid     : 1;
566   guint in_clone_paint              : 1;
567   guint transform_valid             : 1;
568   /* This is TRUE if anything has queued a redraw since we were last
569      painted. In this case effect_to_redraw will point to an effect
570      the redraw was queued from or it will be NULL if the redraw was
571      queued without an effect. */
572   guint is_dirty                    : 1;
573   guint bg_color_set                : 1;
574 };
575
576 enum
577 {
578   PROP_0,
579
580   PROP_NAME,
581
582   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
583    * when set they force a size request, when gotten they
584    * get the allocation if the allocation is valid, and the
585    * request otherwise
586    */
587   PROP_X,
588   PROP_Y,
589   PROP_WIDTH,
590   PROP_HEIGHT,
591
592   /* Then the rest of these size-related properties are the "actual"
593    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
594    */
595   PROP_FIXED_X,
596   PROP_FIXED_Y,
597
598   PROP_FIXED_POSITION_SET,
599
600   PROP_MIN_WIDTH,
601   PROP_MIN_WIDTH_SET,
602
603   PROP_MIN_HEIGHT,
604   PROP_MIN_HEIGHT_SET,
605
606   PROP_NATURAL_WIDTH,
607   PROP_NATURAL_WIDTH_SET,
608
609   PROP_NATURAL_HEIGHT,
610   PROP_NATURAL_HEIGHT_SET,
611
612   PROP_REQUEST_MODE,
613
614   /* Allocation properties are read-only */
615   PROP_ALLOCATION,
616
617   PROP_DEPTH,
618
619   PROP_CLIP,
620   PROP_HAS_CLIP,
621   PROP_CLIP_TO_ALLOCATION,
622
623   PROP_OPACITY,
624
625   PROP_OFFSCREEN_REDIRECT,
626
627   PROP_VISIBLE,
628   PROP_MAPPED,
629   PROP_REALIZED,
630   PROP_REACTIVE,
631
632   PROP_SCALE_X,
633   PROP_SCALE_Y,
634   PROP_SCALE_CENTER_X,
635   PROP_SCALE_CENTER_Y,
636   PROP_SCALE_GRAVITY,
637
638   PROP_ROTATION_ANGLE_X,
639   PROP_ROTATION_ANGLE_Y,
640   PROP_ROTATION_ANGLE_Z,
641   PROP_ROTATION_CENTER_X,
642   PROP_ROTATION_CENTER_Y,
643   PROP_ROTATION_CENTER_Z,
644   /* This property only makes sense for the z rotation because the
645      others would depend on the actor having a size along the
646      z-axis */
647   PROP_ROTATION_CENTER_Z_GRAVITY,
648
649   PROP_ANCHOR_X,
650   PROP_ANCHOR_Y,
651   PROP_ANCHOR_GRAVITY,
652
653   PROP_SHOW_ON_SET_PARENT,
654
655   PROP_TEXT_DIRECTION,
656   PROP_HAS_POINTER,
657
658   PROP_ACTIONS,
659   PROP_CONSTRAINTS,
660   PROP_EFFECT,
661
662   PROP_LAYOUT_MANAGER,
663
664   PROP_X_ALIGN,
665   PROP_Y_ALIGN,
666   PROP_MARGIN_TOP,
667   PROP_MARGIN_BOTTOM,
668   PROP_MARGIN_LEFT,
669   PROP_MARGIN_RIGHT,
670
671   PROP_BACKGROUND_COLOR,
672   PROP_BACKGROUND_COLOR_SET,
673
674   PROP_FIRST_CHILD,
675   PROP_LAST_CHILD,
676
677   PROP_CONTENT,
678   PROP_CONTENT_GRAVITY,
679   PROP_CONTENT_BOX,
680
681   PROP_LAST
682 };
683
684 static GParamSpec *obj_props[PROP_LAST];
685
686 enum
687 {
688   SHOW,
689   HIDE,
690   DESTROY,
691   PARENT_SET,
692   KEY_FOCUS_IN,
693   KEY_FOCUS_OUT,
694   PAINT,
695   PICK,
696   REALIZE,
697   UNREALIZE,
698   QUEUE_REDRAW,
699   QUEUE_RELAYOUT,
700   EVENT,
701   CAPTURED_EVENT,
702   BUTTON_PRESS_EVENT,
703   BUTTON_RELEASE_EVENT,
704   SCROLL_EVENT,
705   KEY_PRESS_EVENT,
706   KEY_RELEASE_EVENT,
707   MOTION_EVENT,
708   ENTER_EVENT,
709   LEAVE_EVENT,
710   ALLOCATION_CHANGED,
711
712   LAST_SIGNAL
713 };
714
715 static guint actor_signals[LAST_SIGNAL] = { 0, };
716
717 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
718 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
719 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
720 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
721
722 /* These setters are all static for now, maybe they should be in the
723  * public API, but they are perhaps obscure enough to leave only as
724  * properties
725  */
726 static void clutter_actor_set_min_width          (ClutterActor *self,
727                                                   gfloat        min_width);
728 static void clutter_actor_set_min_height         (ClutterActor *self,
729                                                   gfloat        min_height);
730 static void clutter_actor_set_natural_width      (ClutterActor *self,
731                                                   gfloat        natural_width);
732 static void clutter_actor_set_natural_height     (ClutterActor *self,
733                                                   gfloat        natural_height);
734 static void clutter_actor_set_min_width_set      (ClutterActor *self,
735                                                   gboolean      use_min_width);
736 static void clutter_actor_set_min_height_set     (ClutterActor *self,
737                                                   gboolean      use_min_height);
738 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
739                                                   gboolean  use_natural_width);
740 static void clutter_actor_set_natural_height_set (ClutterActor *self,
741                                                   gboolean  use_natural_height);
742 static void clutter_actor_update_map_state       (ClutterActor  *self,
743                                                   MapStateChange change);
744 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
745
746 /* Helper routines for managing anchor coords */
747 static void clutter_anchor_coord_get_units (ClutterActor      *self,
748                                             const AnchorCoord *coord,
749                                             gfloat            *x,
750                                             gfloat            *y,
751                                             gfloat            *z);
752 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
753                                             gfloat             x,
754                                             gfloat             y,
755                                             gfloat             z);
756
757 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
758 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
759                                                         ClutterGravity     gravity);
760
761 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
762
763 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
764
765 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
766                                                                ClutterActor *ancestor,
767                                                                CoglMatrix *matrix);
768
769 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
770
771 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
772
773 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
774                                                                 const ClutterColor *color);
775
776 static void on_layout_manager_changed (ClutterLayoutManager *manager,
777                                        ClutterActor         *self);
778
779 /* Helper macro which translates by the anchor coord, applies the
780    given transformation and then translates back */
781 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
782   gfloat _tx, _ty, _tz;                                                \
783   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
784   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
785   { _transform; }                                                      \
786   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
787
788 static GQuark quark_shader_data = 0;
789 static GQuark quark_actor_layout_info = 0;
790 static GQuark quark_actor_transform_info = 0;
791 static GQuark quark_actor_animation_info = 0;
792
793 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
794                          clutter_actor,
795                          G_TYPE_INITIALLY_UNOWNED,
796                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
797                                                 clutter_container_iface_init)
798                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
799                                                 clutter_scriptable_iface_init)
800                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
801                                                 clutter_animatable_iface_init)
802                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
803                                                 atk_implementor_iface_init));
804
805 /*< private >
806  * clutter_actor_get_debug_name:
807  * @actor: a #ClutterActor
808  *
809  * Retrieves a printable name of @actor for debugging messages
810  *
811  * Return value: a string with a printable name
812  */
813 const gchar *
814 _clutter_actor_get_debug_name (ClutterActor *actor)
815 {
816   return actor->priv->name != NULL ? actor->priv->name
817                                    : G_OBJECT_TYPE_NAME (actor);
818 }
819
820 #ifdef CLUTTER_ENABLE_DEBUG
821 /* XXX - this is for debugging only, remove once working (or leave
822  * in only in some debug mode). Should leave it for a little while
823  * until we're confident in the new map/realize/visible handling.
824  */
825 static inline void
826 clutter_actor_verify_map_state (ClutterActor *self)
827 {
828   ClutterActorPrivate *priv = self->priv;
829
830   if (CLUTTER_ACTOR_IS_REALIZED (self))
831     {
832       /* all bets are off during reparent when we're potentially realized,
833        * but should not be according to invariants
834        */
835       if (!CLUTTER_ACTOR_IN_REPARENT (self))
836         {
837           if (priv->parent == NULL)
838             {
839               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
840                 {
841                 }
842               else
843                 g_warning ("Realized non-toplevel actor '%s' should "
844                            "have a parent",
845                            _clutter_actor_get_debug_name (self));
846             }
847           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
848             {
849               g_warning ("Realized actor %s has an unrealized parent %s",
850                          _clutter_actor_get_debug_name (self),
851                          _clutter_actor_get_debug_name (priv->parent));
852             }
853         }
854     }
855
856   if (CLUTTER_ACTOR_IS_MAPPED (self))
857     {
858       if (!CLUTTER_ACTOR_IS_REALIZED (self))
859         g_warning ("Actor '%s' is mapped but not realized",
860                    _clutter_actor_get_debug_name (self));
861
862       /* remaining bets are off during reparent when we're potentially
863        * mapped, but should not be according to invariants
864        */
865       if (!CLUTTER_ACTOR_IN_REPARENT (self))
866         {
867           if (priv->parent == NULL)
868             {
869               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
870                 {
871                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
872                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
873                     {
874                       g_warning ("Toplevel actor '%s' is mapped "
875                                  "but not visible",
876                                  _clutter_actor_get_debug_name (self));
877                     }
878                 }
879               else
880                 {
881                   g_warning ("Mapped actor '%s' should have a parent",
882                              _clutter_actor_get_debug_name (self));
883                 }
884             }
885           else
886             {
887               ClutterActor *iter = self;
888
889               /* check for the enable_paint_unmapped flag on the actor
890                * and parents; if the flag is enabled at any point of this
891                * branch of the scene graph then all the later checks
892                * become pointless
893                */
894               while (iter != NULL)
895                 {
896                   if (iter->priv->enable_paint_unmapped)
897                     return;
898
899                   iter = iter->priv->parent;
900                 }
901
902               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
903                 {
904                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
905                              "is not visible",
906                              _clutter_actor_get_debug_name (self),
907                              _clutter_actor_get_debug_name (priv->parent));
908                 }
909
910               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
911                 {
912                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
913                              "is not realized",
914                              _clutter_actor_get_debug_name (self),
915                              _clutter_actor_get_debug_name (priv->parent));
916                 }
917
918               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
919                 {
920                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
921                     g_warning ("Actor '%s' is mapped but its non-toplevel "
922                                "parent '%s' is not mapped",
923                                _clutter_actor_get_debug_name (self),
924                                _clutter_actor_get_debug_name (priv->parent));
925                 }
926             }
927         }
928     }
929 }
930
931 #endif /* CLUTTER_ENABLE_DEBUG */
932
933 static void
934 clutter_actor_set_mapped (ClutterActor *self,
935                           gboolean      mapped)
936 {
937   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
938     return;
939
940   if (mapped)
941     {
942       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
943       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
944     }
945   else
946     {
947       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
948       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
949     }
950 }
951
952 /* this function updates the mapped and realized states according to
953  * invariants, in the appropriate order.
954  */
955 static void
956 clutter_actor_update_map_state (ClutterActor  *self,
957                                 MapStateChange change)
958 {
959   gboolean was_mapped;
960
961   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
962
963   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
964     {
965       /* the mapped flag on top-level actors must be set by the
966        * per-backend implementation because it might be asynchronous.
967        *
968        * That is, the MAPPED flag on toplevels currently tracks the X
969        * server mapped-ness of the window, while the expected behavior
970        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
971        * This creates some weird complexity by breaking the invariant
972        * that if we're visible and all ancestors shown then we are
973        * also mapped - instead, we are mapped if all ancestors
974        * _possibly excepting_ the stage are mapped. The stage
975        * will map/unmap for example when it is minimized or
976        * moved to another workspace.
977        *
978        * So, the only invariant on the stage is that if visible it
979        * should be realized, and that it has to be visible to be
980        * mapped.
981        */
982       if (CLUTTER_ACTOR_IS_VISIBLE (self))
983         clutter_actor_realize (self);
984
985       switch (change)
986         {
987         case MAP_STATE_CHECK:
988           break;
989
990         case MAP_STATE_MAKE_MAPPED:
991           g_assert (!was_mapped);
992           clutter_actor_set_mapped (self, TRUE);
993           break;
994
995         case MAP_STATE_MAKE_UNMAPPED:
996           g_assert (was_mapped);
997           clutter_actor_set_mapped (self, FALSE);
998           break;
999
1000         case MAP_STATE_MAKE_UNREALIZED:
1001           /* we only use MAKE_UNREALIZED in unparent,
1002            * and unparenting a stage isn't possible.
1003            * If someone wants to just unrealize a stage
1004            * then clutter_actor_unrealize() doesn't
1005            * go through this codepath.
1006            */
1007           g_warning ("Trying to force unrealize stage is not allowed");
1008           break;
1009         }
1010
1011       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1012           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1013           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1014         {
1015           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1016                      "it is somehow still mapped",
1017                      _clutter_actor_get_debug_name (self));
1018         }
1019     }
1020   else
1021     {
1022       ClutterActorPrivate *priv = self->priv;
1023       ClutterActor *parent = priv->parent;
1024       gboolean should_be_mapped;
1025       gboolean may_be_realized;
1026       gboolean must_be_realized;
1027
1028       should_be_mapped = FALSE;
1029       may_be_realized = TRUE;
1030       must_be_realized = FALSE;
1031
1032       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1033         {
1034           may_be_realized = FALSE;
1035         }
1036       else
1037         {
1038           /* Maintain invariant that if parent is mapped, and we are
1039            * visible, then we are mapped ...  unless parent is a
1040            * stage, in which case we map regardless of parent's map
1041            * state but do require stage to be visible and realized.
1042            *
1043            * If parent is realized, that does not force us to be
1044            * realized; but if parent is unrealized, that does force
1045            * us to be unrealized.
1046            *
1047            * The reason we don't force children to realize with
1048            * parents is _clutter_actor_rerealize(); if we require that
1049            * a realized parent means children are realized, then to
1050            * unrealize an actor we would have to unrealize its
1051            * parents, which would end up meaning unrealizing and
1052            * hiding the entire stage. So we allow unrealizing a
1053            * child (as long as that child is not mapped) while that
1054            * child still has a realized parent.
1055            *
1056            * Also, if we unrealize from leaf nodes to root, and
1057            * realize from root to leaf, the invariants are never
1058            * violated if we allow children to be unrealized
1059            * while parents are realized.
1060            *
1061            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1062            * to force us to unmap, even though parent is still
1063            * mapped. This is because we're unmapping from leaf nodes
1064            * up to root nodes.
1065            */
1066           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1067               change != MAP_STATE_MAKE_UNMAPPED)
1068             {
1069               gboolean parent_is_visible_realized_toplevel;
1070
1071               parent_is_visible_realized_toplevel =
1072                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1073                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1074                  CLUTTER_ACTOR_IS_REALIZED (parent));
1075
1076               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1077                   parent_is_visible_realized_toplevel)
1078                 {
1079                   must_be_realized = TRUE;
1080                   should_be_mapped = TRUE;
1081                 }
1082             }
1083
1084           /* if the actor has been set to be painted even if unmapped
1085            * then we should map it and check for realization as well;
1086            * this is an override for the branch of the scene graph
1087            * which begins with this node
1088            */
1089           if (priv->enable_paint_unmapped)
1090             {
1091               if (priv->parent == NULL)
1092                 g_warning ("Attempting to map an unparented actor '%s'",
1093                            _clutter_actor_get_debug_name (self));
1094
1095               should_be_mapped = TRUE;
1096               must_be_realized = TRUE;
1097             }
1098
1099           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1100             may_be_realized = FALSE;
1101         }
1102
1103       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1104         {
1105           if (parent == NULL)
1106             g_warning ("Attempting to map a child that does not "
1107                        "meet the necessary invariants: the actor '%s' "
1108                        "has no parent",
1109                        _clutter_actor_get_debug_name (self));
1110           else
1111             g_warning ("Attempting to map a child that does not "
1112                        "meet the necessary invariants: the actor '%s' "
1113                        "is parented to an unmapped actor '%s'",
1114                        _clutter_actor_get_debug_name (self),
1115                        _clutter_actor_get_debug_name (priv->parent));
1116         }
1117
1118       /* If in reparent, we temporarily suspend unmap and unrealize.
1119        *
1120        * We want to go in the order "realize, map" and "unmap, unrealize"
1121        */
1122
1123       /* Unmap */
1124       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1125         clutter_actor_set_mapped (self, FALSE);
1126
1127       /* Realize */
1128       if (must_be_realized)
1129         clutter_actor_realize (self);
1130
1131       /* if we must be realized then we may be, presumably */
1132       g_assert (!(must_be_realized && !may_be_realized));
1133
1134       /* Unrealize */
1135       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1136         clutter_actor_unrealize_not_hiding (self);
1137
1138       /* Map */
1139       if (should_be_mapped)
1140         {
1141           if (!must_be_realized)
1142             g_warning ("Somehow we think actor '%s' should be mapped but "
1143                        "not realized, which isn't allowed",
1144                        _clutter_actor_get_debug_name (self));
1145
1146           /* realization is allowed to fail (though I don't know what
1147            * an app is supposed to do about that - shouldn't it just
1148            * be a g_error? anyway, we have to avoid mapping if this
1149            * happens)
1150            */
1151           if (CLUTTER_ACTOR_IS_REALIZED (self))
1152             clutter_actor_set_mapped (self, TRUE);
1153         }
1154     }
1155
1156 #ifdef CLUTTER_ENABLE_DEBUG
1157   /* check all invariants were kept */
1158   clutter_actor_verify_map_state (self);
1159 #endif
1160 }
1161
1162 static void
1163 clutter_actor_real_map (ClutterActor *self)
1164 {
1165   ClutterActorPrivate *priv = self->priv;
1166   ClutterActor *stage, *iter;
1167
1168   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1169
1170   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1171                 _clutter_actor_get_debug_name (self));
1172
1173   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1174
1175   stage = _clutter_actor_get_stage_internal (self);
1176   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1177
1178   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1179                 priv->pick_id,
1180                 _clutter_actor_get_debug_name (self));
1181
1182   /* notify on parent mapped before potentially mapping
1183    * children, so apps see a top-down notification.
1184    */
1185   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1186
1187   for (iter = self->priv->first_child;
1188        iter != NULL;
1189        iter = iter->priv->next_sibling)
1190     {
1191       clutter_actor_map (iter);
1192     }
1193 }
1194
1195 /**
1196  * clutter_actor_map:
1197  * @self: A #ClutterActor
1198  *
1199  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1200  * and realizes its children if they are visible. Does nothing if the
1201  * actor is not visible.
1202  *
1203  * Calling this function is strongly disencouraged: the default
1204  * implementation of #ClutterActorClass.map() will map all the children
1205  * of an actor when mapping its parent.
1206  *
1207  * When overriding map, it is mandatory to chain up to the parent
1208  * implementation.
1209  *
1210  * Since: 1.0
1211  */
1212 void
1213 clutter_actor_map (ClutterActor *self)
1214 {
1215   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1216
1217   if (CLUTTER_ACTOR_IS_MAPPED (self))
1218     return;
1219
1220   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1221     return;
1222
1223   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1224 }
1225
1226 static void
1227 clutter_actor_real_unmap (ClutterActor *self)
1228 {
1229   ClutterActorPrivate *priv = self->priv;
1230   ClutterActor *iter;
1231
1232   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1233
1234   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1235                 _clutter_actor_get_debug_name (self));
1236
1237   for (iter = self->priv->first_child;
1238        iter != NULL;
1239        iter = iter->priv->next_sibling)
1240     {
1241       clutter_actor_unmap (iter);
1242     }
1243
1244   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1245
1246   /* clear the contents of the last paint volume, so that hiding + moving +
1247    * showing will not result in the wrong area being repainted
1248    */
1249   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1250   priv->last_paint_volume_valid = TRUE;
1251
1252   /* notify on parent mapped after potentially unmapping
1253    * children, so apps see a bottom-up notification.
1254    */
1255   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1256
1257   /* relinquish keyboard focus if we were unmapped while owning it */
1258   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1259     {
1260       ClutterStage *stage;
1261
1262       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1263
1264       if (stage != NULL)
1265         _clutter_stage_release_pick_id (stage, priv->pick_id);
1266
1267       priv->pick_id = -1;
1268
1269       if (stage != NULL &&
1270           clutter_stage_get_key_focus (stage) == self)
1271         {
1272           clutter_stage_set_key_focus (stage, NULL);
1273         }
1274     }
1275 }
1276
1277 /**
1278  * clutter_actor_unmap:
1279  * @self: A #ClutterActor
1280  *
1281  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1282  * unmaps its children if they were mapped.
1283  *
1284  * Calling this function is not encouraged: the default #ClutterActor
1285  * implementation of #ClutterActorClass.unmap() will also unmap any
1286  * eventual children by default when their parent is unmapped.
1287  *
1288  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1289  * chain up to the parent implementation.
1290  *
1291  * <note>It is important to note that the implementation of the
1292  * #ClutterActorClass.unmap() virtual function may be called after
1293  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1294  * implementation, but it is guaranteed to be called before the
1295  * #GObjectClass.finalize() implementation.</note>
1296  *
1297  * Since: 1.0
1298  */
1299 void
1300 clutter_actor_unmap (ClutterActor *self)
1301 {
1302   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1303
1304   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1305     return;
1306
1307   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1308 }
1309
1310 static void
1311 clutter_actor_real_show (ClutterActor *self)
1312 {
1313   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1314     {
1315       ClutterActorPrivate *priv = self->priv;
1316
1317       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1318
1319       /* we notify on the "visible" flag in the clutter_actor_show()
1320        * wrapper so the entire show signal emission completes first
1321        * (?)
1322        */
1323       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1324
1325       /* we queue a relayout unless the actor is inside a
1326        * container that explicitly told us not to
1327        */
1328       if (priv->parent != NULL &&
1329           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1330         {
1331           /* While an actor is hidden the parent may not have
1332            * allocated/requested so we need to start from scratch
1333            * and avoid the short-circuiting in
1334            * clutter_actor_queue_relayout().
1335            */
1336           priv->needs_width_request  = FALSE;
1337           priv->needs_height_request = FALSE;
1338           priv->needs_allocation     = FALSE;
1339           clutter_actor_queue_relayout (self);
1340         }
1341     }
1342 }
1343
1344 static inline void
1345 set_show_on_set_parent (ClutterActor *self,
1346                         gboolean      set_show)
1347 {
1348   ClutterActorPrivate *priv = self->priv;
1349
1350   set_show = !!set_show;
1351
1352   if (priv->show_on_set_parent == set_show)
1353     return;
1354
1355   if (priv->parent == NULL)
1356     {
1357       priv->show_on_set_parent = set_show;
1358       g_object_notify_by_pspec (G_OBJECT (self),
1359                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1360     }
1361 }
1362
1363 /**
1364  * clutter_actor_show:
1365  * @self: A #ClutterActor
1366  *
1367  * Flags an actor to be displayed. An actor that isn't shown will not
1368  * be rendered on the stage.
1369  *
1370  * Actors are visible by default.
1371  *
1372  * If this function is called on an actor without a parent, the
1373  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1374  * effect.
1375  */
1376 void
1377 clutter_actor_show (ClutterActor *self)
1378 {
1379   ClutterActorPrivate *priv;
1380
1381   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1382
1383   /* simple optimization */
1384   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1385     {
1386       /* we still need to set the :show-on-set-parent property, in
1387        * case show() is called on an unparented actor
1388        */
1389       set_show_on_set_parent (self, TRUE);
1390       return;
1391     }
1392
1393 #ifdef CLUTTER_ENABLE_DEBUG
1394   clutter_actor_verify_map_state (self);
1395 #endif
1396
1397   priv = self->priv;
1398
1399   g_object_freeze_notify (G_OBJECT (self));
1400
1401   set_show_on_set_parent (self, TRUE);
1402
1403   g_signal_emit (self, actor_signals[SHOW], 0);
1404   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1405
1406   if (priv->parent != NULL)
1407     clutter_actor_queue_redraw (priv->parent);
1408
1409   g_object_thaw_notify (G_OBJECT (self));
1410 }
1411
1412 /**
1413  * clutter_actor_show_all:
1414  * @self: a #ClutterActor
1415  *
1416  * Calls clutter_actor_show() on all children of an actor (if any).
1417  *
1418  * Since: 0.2
1419  *
1420  * Deprecated: 1.10: Actors are visible by default
1421  */
1422 void
1423 clutter_actor_show_all (ClutterActor *self)
1424 {
1425   ClutterActorClass *klass;
1426
1427   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1428
1429   klass = CLUTTER_ACTOR_GET_CLASS (self);
1430   if (klass->show_all)
1431     klass->show_all (self);
1432 }
1433
1434 static void
1435 clutter_actor_real_hide (ClutterActor *self)
1436 {
1437   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1438     {
1439       ClutterActorPrivate *priv = self->priv;
1440
1441       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1442
1443       /* we notify on the "visible" flag in the clutter_actor_hide()
1444        * wrapper so the entire hide signal emission completes first
1445        * (?)
1446        */
1447       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1448
1449       /* we queue a relayout unless the actor is inside a
1450        * container that explicitly told us not to
1451        */
1452       if (priv->parent != NULL &&
1453           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1454         clutter_actor_queue_relayout (priv->parent);
1455     }
1456 }
1457
1458 /**
1459  * clutter_actor_hide:
1460  * @self: A #ClutterActor
1461  *
1462  * Flags an actor to be hidden. A hidden actor will not be
1463  * rendered on the stage.
1464  *
1465  * Actors are visible by default.
1466  *
1467  * If this function is called on an actor without a parent, the
1468  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1469  * as a side-effect.
1470  */
1471 void
1472 clutter_actor_hide (ClutterActor *self)
1473 {
1474   ClutterActorPrivate *priv;
1475
1476   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1477
1478   /* simple optimization */
1479   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1480     {
1481       /* we still need to set the :show-on-set-parent property, in
1482        * case hide() is called on an unparented actor
1483        */
1484       set_show_on_set_parent (self, FALSE);
1485       return;
1486     }
1487
1488 #ifdef CLUTTER_ENABLE_DEBUG
1489   clutter_actor_verify_map_state (self);
1490 #endif
1491
1492   priv = self->priv;
1493
1494   g_object_freeze_notify (G_OBJECT (self));
1495
1496   set_show_on_set_parent (self, FALSE);
1497
1498   g_signal_emit (self, actor_signals[HIDE], 0);
1499   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1500
1501   if (priv->parent != NULL)
1502     clutter_actor_queue_redraw (priv->parent);
1503
1504   g_object_thaw_notify (G_OBJECT (self));
1505 }
1506
1507 /**
1508  * clutter_actor_hide_all:
1509  * @self: a #ClutterActor
1510  *
1511  * Calls clutter_actor_hide() on all child actors (if any).
1512  *
1513  * Since: 0.2
1514  *
1515  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1516  *   prevent its children from being painted as well.
1517  */
1518 void
1519 clutter_actor_hide_all (ClutterActor *self)
1520 {
1521   ClutterActorClass *klass;
1522
1523   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1524
1525   klass = CLUTTER_ACTOR_GET_CLASS (self);
1526   if (klass->hide_all)
1527     klass->hide_all (self);
1528 }
1529
1530 /**
1531  * clutter_actor_realize:
1532  * @self: A #ClutterActor
1533  *
1534  * Realization informs the actor that it is attached to a stage. It
1535  * can use this to allocate resources if it wanted to delay allocation
1536  * until it would be rendered. However it is perfectly acceptable for
1537  * an actor to create resources before being realized because Clutter
1538  * only ever has a single rendering context so that actor is free to
1539  * be moved from one stage to another.
1540  *
1541  * This function does nothing if the actor is already realized.
1542  *
1543  * Because a realized actor must have realized parent actors, calling
1544  * clutter_actor_realize() will also realize all parents of the actor.
1545  *
1546  * This function does not realize child actors, except in the special
1547  * case that realizing the stage, when the stage is visible, will
1548  * suddenly map (and thus realize) the children of the stage.
1549  **/
1550 void
1551 clutter_actor_realize (ClutterActor *self)
1552 {
1553   ClutterActorPrivate *priv;
1554
1555   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1556
1557   priv = self->priv;
1558
1559 #ifdef CLUTTER_ENABLE_DEBUG
1560   clutter_actor_verify_map_state (self);
1561 #endif
1562
1563   if (CLUTTER_ACTOR_IS_REALIZED (self))
1564     return;
1565
1566   /* To be realized, our parent actors must be realized first.
1567    * This will only succeed if we're inside a toplevel.
1568    */
1569   if (priv->parent != NULL)
1570     clutter_actor_realize (priv->parent);
1571
1572   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1573     {
1574       /* toplevels can be realized at any time */
1575     }
1576   else
1577     {
1578       /* "Fail" the realization if parent is missing or unrealized;
1579        * this should really be a g_warning() not some kind of runtime
1580        * failure; how can an app possibly recover? Instead it's a bug
1581        * in the app and the app should get an explanatory warning so
1582        * someone can fix it. But for now it's too hard to fix this
1583        * because e.g. ClutterTexture needs reworking.
1584        */
1585       if (priv->parent == NULL ||
1586           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1587         return;
1588     }
1589
1590   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1591
1592   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1593   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1594
1595   g_signal_emit (self, actor_signals[REALIZE], 0);
1596
1597   /* Stage actor is allowed to unset the realized flag again in its
1598    * default signal handler, though that is a pathological situation.
1599    */
1600
1601   /* If realization "failed" we'll have to update child state. */
1602   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1603 }
1604
1605 static void
1606 clutter_actor_real_unrealize (ClutterActor *self)
1607 {
1608   /* we must be unmapped (implying our children are also unmapped) */
1609   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1610 }
1611
1612 /**
1613  * clutter_actor_unrealize:
1614  * @self: A #ClutterActor
1615  *
1616  * Unrealization informs the actor that it may be being destroyed or
1617  * moved to another stage. The actor may want to destroy any
1618  * underlying graphics resources at this point. However it is
1619  * perfectly acceptable for it to retain the resources until the actor
1620  * is destroyed because Clutter only ever uses a single rendering
1621  * context and all of the graphics resources are valid on any stage.
1622  *
1623  * Because mapped actors must be realized, actors may not be
1624  * unrealized if they are mapped. This function hides the actor to be
1625  * sure it isn't mapped, an application-visible side effect that you
1626  * may not be expecting.
1627  *
1628  * This function should not be called by application code.
1629  */
1630 void
1631 clutter_actor_unrealize (ClutterActor *self)
1632 {
1633   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1634   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1635
1636 /* This function should not really be in the public API, because
1637  * there isn't a good reason to call it. ClutterActor will already
1638  * unrealize things for you when it's important to do so.
1639  *
1640  * If you were using clutter_actor_unrealize() in a dispose
1641  * implementation, then don't, just chain up to ClutterActor's
1642  * dispose.
1643  *
1644  * If you were using clutter_actor_unrealize() to implement
1645  * unrealizing children of your container, then don't, ClutterActor
1646  * will already take care of that.
1647  *
1648  * If you were using clutter_actor_unrealize() to re-realize to
1649  * create your resources in a different way, then use
1650  * _clutter_actor_rerealize() (inside Clutter) or just call your
1651  * code that recreates your resources directly (outside Clutter).
1652  */
1653
1654 #ifdef CLUTTER_ENABLE_DEBUG
1655   clutter_actor_verify_map_state (self);
1656 #endif
1657
1658   clutter_actor_hide (self);
1659
1660   clutter_actor_unrealize_not_hiding (self);
1661 }
1662
1663 static ClutterActorTraverseVisitFlags
1664 unrealize_actor_before_children_cb (ClutterActor *self,
1665                                     int depth,
1666                                     void *user_data)
1667 {
1668   /* If an actor is already unrealized we know its children have also
1669    * already been unrealized... */
1670   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1671     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1672
1673   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1674
1675   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1676 }
1677
1678 static ClutterActorTraverseVisitFlags
1679 unrealize_actor_after_children_cb (ClutterActor *self,
1680                                    int depth,
1681                                    void *user_data)
1682 {
1683   /* We want to unset the realized flag only _after_
1684    * child actors are unrealized, to maintain invariants.
1685    */
1686   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1687   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1688   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1689 }
1690
1691 /*
1692  * clutter_actor_unrealize_not_hiding:
1693  * @self: A #ClutterActor
1694  *
1695  * Unrealization informs the actor that it may be being destroyed or
1696  * moved to another stage. The actor may want to destroy any
1697  * underlying graphics resources at this point. However it is
1698  * perfectly acceptable for it to retain the resources until the actor
1699  * is destroyed because Clutter only ever uses a single rendering
1700  * context and all of the graphics resources are valid on any stage.
1701  *
1702  * Because mapped actors must be realized, actors may not be
1703  * unrealized if they are mapped. You must hide the actor or one of
1704  * its parents before attempting to unrealize.
1705  *
1706  * This function is separate from clutter_actor_unrealize() because it
1707  * does not automatically hide the actor.
1708  * Actors need not be hidden to be unrealized, they just need to
1709  * be unmapped. In fact we don't want to mess up the application's
1710  * setting of the "visible" flag, so hiding is very undesirable.
1711  *
1712  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1713  * backward compatibility.
1714  */
1715 static void
1716 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1717 {
1718   _clutter_actor_traverse (self,
1719                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1720                            unrealize_actor_before_children_cb,
1721                            unrealize_actor_after_children_cb,
1722                            NULL);
1723 }
1724
1725 /*
1726  * _clutter_actor_rerealize:
1727  * @self: A #ClutterActor
1728  * @callback: Function to call while unrealized
1729  * @data: data for callback
1730  *
1731  * If an actor is already unrealized, this just calls the callback.
1732  *
1733  * If it is realized, it unrealizes temporarily, calls the callback,
1734  * and then re-realizes the actor.
1735  *
1736  * As a side effect, leaves all children of the actor unrealized if
1737  * the actor was realized but not showing.  This is because when we
1738  * unrealize the actor temporarily we must unrealize its children
1739  * (e.g. children of a stage can't be realized if stage window is
1740  * gone). And we aren't clever enough to save the realization state of
1741  * all children. In most cases this should not matter, because
1742  * the children will automatically realize when they next become mapped.
1743  */
1744 void
1745 _clutter_actor_rerealize (ClutterActor    *self,
1746                           ClutterCallback  callback,
1747                           void            *data)
1748 {
1749   gboolean was_mapped;
1750   gboolean was_showing;
1751   gboolean was_realized;
1752
1753   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1754
1755 #ifdef CLUTTER_ENABLE_DEBUG
1756   clutter_actor_verify_map_state (self);
1757 #endif
1758
1759   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1760   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1761   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1762
1763   /* Must be unmapped to unrealize. Note we only have to hide this
1764    * actor if it was mapped (if all parents were showing).  If actor
1765    * is merely visible (but not mapped), then that's fine, we can
1766    * leave it visible.
1767    */
1768   if (was_mapped)
1769     clutter_actor_hide (self);
1770
1771   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1772
1773   /* unrealize self and all children */
1774   clutter_actor_unrealize_not_hiding (self);
1775
1776   if (callback != NULL)
1777     {
1778       (* callback) (self, data);
1779     }
1780
1781   if (was_showing)
1782     clutter_actor_show (self); /* will realize only if mapping implies it */
1783   else if (was_realized)
1784     clutter_actor_realize (self); /* realize self and all parents */
1785 }
1786
1787 static void
1788 clutter_actor_real_pick (ClutterActor       *self,
1789                          const ClutterColor *color)
1790 {
1791   /* the default implementation is just to paint a rectangle
1792    * with the same size of the actor using the passed color
1793    */
1794   if (clutter_actor_should_pick_paint (self))
1795     {
1796       ClutterActorBox box = { 0, };
1797       float width, height;
1798
1799       clutter_actor_get_allocation_box (self, &box);
1800
1801       width = box.x2 - box.x1;
1802       height = box.y2 - box.y1;
1803
1804       cogl_set_source_color4ub (color->red,
1805                                 color->green,
1806                                 color->blue,
1807                                 color->alpha);
1808
1809       cogl_rectangle (0, 0, width, height);
1810     }
1811
1812   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1813    * with existing container classes that override the pick() virtual
1814    * and chain up to the default implementation - otherwise we'll end up
1815    * painting our children twice.
1816    *
1817    * this has to go away for 2.0; hopefully along the pick() itself.
1818    */
1819   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1820     {
1821       ClutterActor *iter;
1822
1823       for (iter = self->priv->first_child;
1824            iter != NULL;
1825            iter = iter->priv->next_sibling)
1826         clutter_actor_paint (iter);
1827     }
1828 }
1829
1830 /**
1831  * clutter_actor_should_pick_paint:
1832  * @self: A #ClutterActor
1833  *
1834  * Should be called inside the implementation of the
1835  * #ClutterActor::pick virtual function in order to check whether
1836  * the actor should paint itself in pick mode or not.
1837  *
1838  * This function should never be called directly by applications.
1839  *
1840  * Return value: %TRUE if the actor should paint its silhouette,
1841  *   %FALSE otherwise
1842  */
1843 gboolean
1844 clutter_actor_should_pick_paint (ClutterActor *self)
1845 {
1846   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1847
1848   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1849       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1850        CLUTTER_ACTOR_IS_REACTIVE (self)))
1851     return TRUE;
1852
1853   return FALSE;
1854 }
1855
1856 static void
1857 clutter_actor_real_get_preferred_width (ClutterActor *self,
1858                                         gfloat        for_height,
1859                                         gfloat       *min_width_p,
1860                                         gfloat       *natural_width_p)
1861 {
1862   ClutterActorPrivate *priv = self->priv;
1863
1864   if (priv->n_children != 0 &&
1865       priv->layout_manager != NULL)
1866     {
1867       ClutterContainer *container = CLUTTER_CONTAINER (self);
1868
1869       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1870                     "for the preferred width",
1871                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1872                     priv->layout_manager);
1873
1874       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1875                                                   container,
1876                                                   for_height,
1877                                                   min_width_p,
1878                                                   natural_width_p);
1879
1880       return;
1881     }
1882
1883   /* Default implementation is always 0x0, usually an actor
1884    * using this default is relying on someone to set the
1885    * request manually
1886    */
1887   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1888
1889   if (min_width_p)
1890     *min_width_p = 0;
1891
1892   if (natural_width_p)
1893     *natural_width_p = 0;
1894 }
1895
1896 static void
1897 clutter_actor_real_get_preferred_height (ClutterActor *self,
1898                                          gfloat        for_width,
1899                                          gfloat       *min_height_p,
1900                                          gfloat       *natural_height_p)
1901 {
1902   ClutterActorPrivate *priv = self->priv;
1903
1904   if (priv->n_children != 0 &&
1905       priv->layout_manager != NULL)
1906     {
1907       ClutterContainer *container = CLUTTER_CONTAINER (self);
1908
1909       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1910                     "for the preferred height",
1911                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1912                     priv->layout_manager);
1913
1914       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1915                                                    container,
1916                                                    for_width,
1917                                                    min_height_p,
1918                                                    natural_height_p);
1919
1920       return;
1921     }
1922   /* Default implementation is always 0x0, usually an actor
1923    * using this default is relying on someone to set the
1924    * request manually
1925    */
1926   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1927
1928   if (min_height_p)
1929     *min_height_p = 0;
1930
1931   if (natural_height_p)
1932     *natural_height_p = 0;
1933 }
1934
1935 static void
1936 clutter_actor_store_old_geometry (ClutterActor    *self,
1937                                   ClutterActorBox *box)
1938 {
1939   *box = self->priv->allocation;
1940 }
1941
1942 static inline void
1943 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
1944                                           const ClutterActorBox *old)
1945 {
1946   ClutterActorPrivate *priv = self->priv;
1947   GObject *obj = G_OBJECT (self);
1948
1949   g_object_freeze_notify (obj);
1950
1951   /* to avoid excessive requisition or allocation cycles we
1952    * use the cached values.
1953    *
1954    * - if we don't have an allocation we assume that we need
1955    *   to notify anyway
1956    * - if we don't have a width or a height request we notify
1957    *   width and height
1958    * - if we have a valid allocation then we check the old
1959    *   bounding box with the current allocation and we notify
1960    *   the changes
1961    */
1962   if (priv->needs_allocation)
1963     {
1964       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1965       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1966       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1967       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1968     }
1969   else if (priv->needs_width_request || priv->needs_height_request)
1970     {
1971       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1972       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1973     }
1974   else
1975     {
1976       gfloat xu, yu;
1977       gfloat widthu, heightu;
1978
1979       xu = priv->allocation.x1;
1980       yu = priv->allocation.y1;
1981       widthu = priv->allocation.x2 - priv->allocation.x1;
1982       heightu = priv->allocation.y2 - priv->allocation.y1;
1983
1984       if (xu != old->x1)
1985         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1986
1987       if (yu != old->y1)
1988         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1989
1990       if (widthu != (old->x2 - old->x1))
1991         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1992
1993       if (heightu != (old->y2 - old->y1))
1994         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1995     }
1996
1997   g_object_thaw_notify (obj);
1998 }
1999
2000 /*< private >
2001  * clutter_actor_set_allocation_internal:
2002  * @self: a #ClutterActor
2003  * @box: a #ClutterActorBox
2004  * @flags: allocation flags
2005  *
2006  * Stores the allocation of @self.
2007  *
2008  * This function only performs basic storage and property notification.
2009  *
2010  * This function should be called by clutter_actor_set_allocation()
2011  * and by the default implementation of #ClutterActorClass.allocate().
2012  *
2013  * Return value: %TRUE if the allocation of the #ClutterActor has been
2014  *   changed, and %FALSE otherwise
2015  */
2016 static inline gboolean
2017 clutter_actor_set_allocation_internal (ClutterActor           *self,
2018                                        const ClutterActorBox  *box,
2019                                        ClutterAllocationFlags  flags)
2020 {
2021   ClutterActorPrivate *priv = self->priv;
2022   GObject *obj;
2023   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2024   gboolean flags_changed;
2025   gboolean retval;
2026   ClutterActorBox old_alloc = { 0, };
2027
2028   obj = G_OBJECT (self);
2029
2030   g_object_freeze_notify (obj);
2031
2032   clutter_actor_store_old_geometry (self, &old_alloc);
2033
2034   x1_changed = priv->allocation.x1 != box->x1;
2035   y1_changed = priv->allocation.y1 != box->y1;
2036   x2_changed = priv->allocation.x2 != box->x2;
2037   y2_changed = priv->allocation.y2 != box->y2;
2038
2039   flags_changed = priv->allocation_flags != flags;
2040
2041   priv->allocation = *box;
2042   priv->allocation_flags = flags;
2043
2044   /* allocation is authoritative */
2045   priv->needs_width_request = FALSE;
2046   priv->needs_height_request = FALSE;
2047   priv->needs_allocation = FALSE;
2048
2049   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
2050     {
2051       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2052                     _clutter_actor_get_debug_name (self));
2053
2054       priv->transform_valid = FALSE;
2055
2056       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2057
2058       /* if the allocation changes, so does the content box */
2059       if (priv->content != NULL)
2060         g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2061
2062       retval = TRUE;
2063     }
2064   else
2065     retval = FALSE;
2066
2067   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2068
2069   g_object_thaw_notify (obj);
2070
2071   return retval;
2072 }
2073
2074 static void clutter_actor_real_allocate (ClutterActor           *self,
2075                                          const ClutterActorBox  *box,
2076                                          ClutterAllocationFlags  flags);
2077
2078 static inline void
2079 clutter_actor_maybe_layout_children (ClutterActor           *self,
2080                                      const ClutterActorBox  *allocation,
2081                                      ClutterAllocationFlags  flags)
2082 {
2083   ClutterActorPrivate *priv = self->priv;
2084
2085   /* this is going to be a bit hard to follow, so let's put an explanation
2086    * here.
2087    *
2088    * we want ClutterActor to have a default layout manager if the actor was
2089    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2090    *
2091    * we also want any subclass of ClutterActor that does not override the
2092    * ::allocate() virtual function to delegate to a layout manager.
2093    *
2094    * finally, we want to allow people subclassing ClutterActor and overriding
2095    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2096    *
2097    * on the other hand, we want existing actor subclasses overriding the
2098    * ::allocate() virtual function and chaining up to the parent's
2099    * implementation to continue working without allocating their children
2100    * twice, or without entering an allocation loop.
2101    *
2102    * for the first two points, we check if the class of the actor is
2103    * overridding the ::allocate() virtual function; if it isn't, then we
2104    * follow through with checking whether we have children and a layout
2105    * manager, and eventually calling clutter_layout_manager_allocate().
2106    *
2107    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2108    * allocation flags that we got passed, and if it is present, we continue
2109    * with the check above.
2110    *
2111    * if neither of these two checks yields a positive result, we just
2112    * assume that the ::allocate() virtual function that resulted in this
2113    * function being called will also allocate the children of the actor.
2114    */
2115
2116   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2117     goto check_layout;
2118
2119   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2120     goto check_layout;
2121
2122   return;
2123
2124 check_layout:
2125   if (priv->n_children != 0 &&
2126       priv->layout_manager != NULL)
2127     {
2128       ClutterContainer *container = CLUTTER_CONTAINER (self);
2129       ClutterAllocationFlags children_flags;
2130       ClutterActorBox children_box;
2131
2132       /* normalize the box passed to the layout manager */
2133       children_box.x1 = children_box.y1 = 0.f;
2134       children_box.x2 = (allocation->x2 - allocation->x1);
2135       children_box.y2 = (allocation->y2 - allocation->y1);
2136
2137       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2138        * the actor's children, since it refers only to the current
2139        * actor's allocation.
2140        */
2141       children_flags = flags;
2142       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2143
2144       CLUTTER_NOTE (LAYOUT,
2145                     "Allocating %d children of %s "
2146                     "at { %.2f, %.2f - %.2f x %.2f } "
2147                     "using %s",
2148                     priv->n_children,
2149                     _clutter_actor_get_debug_name (self),
2150                     allocation->x1,
2151                     allocation->y1,
2152                     (allocation->x2 - allocation->x1),
2153                     (allocation->y2 - allocation->y1),
2154                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2155
2156       clutter_layout_manager_allocate (priv->layout_manager,
2157                                        container,
2158                                        &children_box,
2159                                        children_flags);
2160     }
2161 }
2162
2163 static void
2164 clutter_actor_real_allocate (ClutterActor           *self,
2165                              const ClutterActorBox  *box,
2166                              ClutterAllocationFlags  flags)
2167 {
2168   ClutterActorPrivate *priv = self->priv;
2169   gboolean changed;
2170
2171   g_object_freeze_notify (G_OBJECT (self));
2172
2173   changed = clutter_actor_set_allocation_internal (self, box, flags);
2174
2175   /* we allocate our children before we notify changes in our geometry,
2176    * so that people connecting to properties will be able to get valid
2177    * data out of the sub-tree of the scene graph that has this actor at
2178    * the root.
2179    */
2180   clutter_actor_maybe_layout_children (self, box, flags);
2181
2182   if (changed)
2183     {
2184       ClutterActorBox signal_box = priv->allocation;
2185       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2186
2187       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2188                      &signal_box,
2189                      signal_flags);
2190     }
2191
2192   g_object_thaw_notify (G_OBJECT (self));
2193 }
2194
2195 static void
2196 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2197                                     ClutterActor *origin)
2198 {
2199   /* no point in queuing a redraw on a destroyed actor */
2200   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2201     return;
2202
2203   /* NB: We can't bail out early here if the actor is hidden in case
2204    * the actor bas been cloned. In this case the clone will need to
2205    * receive the signal so it can queue its own redraw.
2206    */
2207
2208   /* calls klass->queue_redraw in default handler */
2209   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2210 }
2211
2212 static void
2213 clutter_actor_real_queue_redraw (ClutterActor *self,
2214                                  ClutterActor *origin)
2215 {
2216   ClutterActor *parent;
2217
2218   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2219                 _clutter_actor_get_debug_name (self),
2220                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2221                                : "same actor");
2222
2223   /* no point in queuing a redraw on a destroyed actor */
2224   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2225     return;
2226
2227   /* If the queue redraw is coming from a child then the actor has
2228      become dirty and any queued effect is no longer valid */
2229   if (self != origin)
2230     {
2231       self->priv->is_dirty = TRUE;
2232       self->priv->effect_to_redraw = NULL;
2233     }
2234
2235   /* If the actor isn't visible, we still had to emit the signal
2236    * to allow for a ClutterClone, but the appearance of the parent
2237    * won't change so we don't have to propagate up the hierarchy.
2238    */
2239   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2240     return;
2241
2242   /* Although we could determine here that a full stage redraw
2243    * has already been queued and immediately bail out, we actually
2244    * guarantee that we will propagate a queue-redraw signal to our
2245    * parent at least once so that it's possible to implement a
2246    * container that tracks which of its children have queued a
2247    * redraw.
2248    */
2249   if (self->priv->propagated_one_redraw)
2250     {
2251       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2252       if (stage != NULL &&
2253           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2254         return;
2255     }
2256
2257   self->priv->propagated_one_redraw = TRUE;
2258
2259   /* notify parents, if they are all visible eventually we'll
2260    * queue redraw on the stage, which queues the redraw idle.
2261    */
2262   parent = clutter_actor_get_parent (self);
2263   if (parent != NULL)
2264     {
2265       /* this will go up recursively */
2266       _clutter_actor_signal_queue_redraw (parent, origin);
2267     }
2268 }
2269
2270 static void
2271 clutter_actor_real_queue_relayout (ClutterActor *self)
2272 {
2273   ClutterActorPrivate *priv = self->priv;
2274
2275   /* no point in queueing a redraw on a destroyed actor */
2276   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2277     return;
2278
2279   priv->needs_width_request  = TRUE;
2280   priv->needs_height_request = TRUE;
2281   priv->needs_allocation     = TRUE;
2282
2283   /* reset the cached size requests */
2284   memset (priv->width_requests, 0,
2285           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2286   memset (priv->height_requests, 0,
2287           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2288
2289   /* We need to go all the way up the hierarchy */
2290   if (priv->parent != NULL)
2291     _clutter_actor_queue_only_relayout (priv->parent);
2292 }
2293
2294 /**
2295  * clutter_actor_apply_relative_transform_to_point:
2296  * @self: A #ClutterActor
2297  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2298  *   default #ClutterStage
2299  * @point: A point as #ClutterVertex
2300  * @vertex: (out caller-allocates): The translated #ClutterVertex
2301  *
2302  * Transforms @point in coordinates relative to the actor into
2303  * ancestor-relative coordinates using the relevant transform
2304  * stack (i.e. scale, rotation, etc).
2305  *
2306  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2307  * this case, the coordinates returned will be the coordinates on
2308  * the stage before the projection is applied. This is different from
2309  * the behaviour of clutter_actor_apply_transform_to_point().
2310  *
2311  * Since: 0.6
2312  */
2313 void
2314 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2315                                                  ClutterActor        *ancestor,
2316                                                  const ClutterVertex *point,
2317                                                  ClutterVertex       *vertex)
2318 {
2319   gfloat w;
2320   CoglMatrix matrix;
2321
2322   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2323   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2324   g_return_if_fail (point != NULL);
2325   g_return_if_fail (vertex != NULL);
2326
2327   *vertex = *point;
2328   w = 1.0;
2329
2330   if (ancestor == NULL)
2331     ancestor = _clutter_actor_get_stage_internal (self);
2332
2333   if (ancestor == NULL)
2334     {
2335       *vertex = *point;
2336       return;
2337     }
2338
2339   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2340   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2341 }
2342
2343 static gboolean
2344 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2345                                          const ClutterVertex *vertices_in,
2346                                          ClutterVertex *vertices_out,
2347                                          int n_vertices)
2348 {
2349   ClutterActor *stage;
2350   CoglMatrix modelview;
2351   CoglMatrix projection;
2352   float viewport[4];
2353
2354   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2355
2356   stage = _clutter_actor_get_stage_internal (self);
2357
2358   /* We really can't do anything meaningful in this case so don't try
2359    * to do any transform */
2360   if (stage == NULL)
2361     return FALSE;
2362
2363   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2364    * that gets us to stage coordinates, we want to go all the way to eye
2365    * coordinates */
2366   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2367
2368   /* Fetch the projection and viewport */
2369   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2370   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2371                                &viewport[0],
2372                                &viewport[1],
2373                                &viewport[2],
2374                                &viewport[3]);
2375
2376   _clutter_util_fully_transform_vertices (&modelview,
2377                                           &projection,
2378                                           viewport,
2379                                           vertices_in,
2380                                           vertices_out,
2381                                           n_vertices);
2382
2383   return TRUE;
2384 }
2385
2386 /**
2387  * clutter_actor_apply_transform_to_point:
2388  * @self: A #ClutterActor
2389  * @point: A point as #ClutterVertex
2390  * @vertex: (out caller-allocates): The translated #ClutterVertex
2391  *
2392  * Transforms @point in coordinates relative to the actor
2393  * into screen-relative coordinates with the current actor
2394  * transformation (i.e. scale, rotation, etc)
2395  *
2396  * Since: 0.4
2397  **/
2398 void
2399 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2400                                         const ClutterVertex *point,
2401                                         ClutterVertex       *vertex)
2402 {
2403   g_return_if_fail (point != NULL);
2404   g_return_if_fail (vertex != NULL);
2405   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2406 }
2407
2408 /*
2409  * _clutter_actor_get_relative_transformation_matrix:
2410  * @self: The actor whose coordinate space you want to transform from.
2411  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2412  *            or %NULL if you want to transform all the way to eye coordinates.
2413  * @matrix: A #CoglMatrix to store the transformation
2414  *
2415  * This gets a transformation @matrix that will transform coordinates from the
2416  * coordinate space of @self into the coordinate space of @ancestor.
2417  *
2418  * For example if you need a matrix that can transform the local actor
2419  * coordinates of @self into stage coordinates you would pass the actor's stage
2420  * pointer as the @ancestor.
2421  *
2422  * If you pass %NULL then the transformation will take you all the way through
2423  * to eye coordinates. This can be useful if you want to extract the entire
2424  * modelview transform that Clutter applies before applying the projection
2425  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2426  * using cogl_set_modelview_matrix() for example then you would want a matrix
2427  * that transforms into eye coordinates.
2428  *
2429  * <note><para>This function explicitly initializes the given @matrix. If you just
2430  * want clutter to multiply a relative transformation with an existing matrix
2431  * you can use clutter_actor_apply_relative_transformation_matrix()
2432  * instead.</para></note>
2433  *
2434  */
2435 /* XXX: We should consider caching the stage relative modelview along with
2436  * the actor itself */
2437 static void
2438 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2439                                                    ClutterActor *ancestor,
2440                                                    CoglMatrix *matrix)
2441 {
2442   cogl_matrix_init_identity (matrix);
2443
2444   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2445 }
2446
2447 /* Project the given @box into stage window coordinates, writing the
2448  * transformed vertices to @verts[]. */
2449 static gboolean
2450 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2451                                           const ClutterActorBox *box,
2452                                           ClutterVertex          verts[])
2453 {
2454   ClutterVertex box_vertices[4];
2455
2456   box_vertices[0].x = box->x1;
2457   box_vertices[0].y = box->y1;
2458   box_vertices[0].z = 0;
2459   box_vertices[1].x = box->x2;
2460   box_vertices[1].y = box->y1;
2461   box_vertices[1].z = 0;
2462   box_vertices[2].x = box->x1;
2463   box_vertices[2].y = box->y2;
2464   box_vertices[2].z = 0;
2465   box_vertices[3].x = box->x2;
2466   box_vertices[3].y = box->y2;
2467   box_vertices[3].z = 0;
2468
2469   return
2470     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2471 }
2472
2473 /**
2474  * clutter_actor_get_allocation_vertices:
2475  * @self: A #ClutterActor
2476  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2477  *   against, or %NULL to use the #ClutterStage
2478  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2479  *   location for an array of 4 #ClutterVertex in which to store the result
2480  *
2481  * Calculates the transformed coordinates of the four corners of the
2482  * actor in the plane of @ancestor. The returned vertices relate to
2483  * the #ClutterActorBox coordinates as follows:
2484  * <itemizedlist>
2485  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2486  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2487  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2488  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2489  * </itemizedlist>
2490  *
2491  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2492  * this case, the coordinates returned will be the coordinates on
2493  * the stage before the projection is applied. This is different from
2494  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2495  *
2496  * Since: 0.6
2497  */
2498 void
2499 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2500                                        ClutterActor  *ancestor,
2501                                        ClutterVertex  verts[])
2502 {
2503   ClutterActorPrivate *priv;
2504   ClutterActorBox box;
2505   ClutterVertex vertices[4];
2506   CoglMatrix modelview;
2507
2508   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2509   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2510
2511   if (ancestor == NULL)
2512     ancestor = _clutter_actor_get_stage_internal (self);
2513
2514   /* Fallback to a NOP transform if the actor isn't parented under a
2515    * stage. */
2516   if (ancestor == NULL)
2517     ancestor = self;
2518
2519   priv = self->priv;
2520
2521   /* if the actor needs to be allocated we force a relayout, so that
2522    * we will have valid values to use in the transformations */
2523   if (priv->needs_allocation)
2524     {
2525       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2526       if (stage)
2527         _clutter_stage_maybe_relayout (stage);
2528       else
2529         {
2530           box.x1 = box.y1 = 0;
2531           /* The result isn't really meaningful in this case but at
2532            * least try to do something *vaguely* reasonable... */
2533           clutter_actor_get_size (self, &box.x2, &box.y2);
2534         }
2535     }
2536
2537   clutter_actor_get_allocation_box (self, &box);
2538
2539   vertices[0].x = box.x1;
2540   vertices[0].y = box.y1;
2541   vertices[0].z = 0;
2542   vertices[1].x = box.x2;
2543   vertices[1].y = box.y1;
2544   vertices[1].z = 0;
2545   vertices[2].x = box.x1;
2546   vertices[2].y = box.y2;
2547   vertices[2].z = 0;
2548   vertices[3].x = box.x2;
2549   vertices[3].y = box.y2;
2550   vertices[3].z = 0;
2551
2552   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2553                                                      &modelview);
2554
2555   cogl_matrix_transform_points (&modelview,
2556                                 3,
2557                                 sizeof (ClutterVertex),
2558                                 vertices,
2559                                 sizeof (ClutterVertex),
2560                                 vertices,
2561                                 4);
2562 }
2563
2564 /**
2565  * clutter_actor_get_abs_allocation_vertices:
2566  * @self: A #ClutterActor
2567  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2568  *   of 4 #ClutterVertex where to store the result.
2569  *
2570  * Calculates the transformed screen coordinates of the four corners of
2571  * the actor; the returned vertices relate to the #ClutterActorBox
2572  * coordinates  as follows:
2573  * <itemizedlist>
2574  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2575  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2576  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2577  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2578  * </itemizedlist>
2579  *
2580  * Since: 0.4
2581  */
2582 void
2583 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2584                                            ClutterVertex  verts[])
2585 {
2586   ClutterActorPrivate *priv;
2587   ClutterActorBox actor_space_allocation;
2588
2589   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2590
2591   priv = self->priv;
2592
2593   /* if the actor needs to be allocated we force a relayout, so that
2594    * the actor allocation box will be valid for
2595    * _clutter_actor_transform_and_project_box()
2596    */
2597   if (priv->needs_allocation)
2598     {
2599       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2600       /* There's nothing meaningful we can do now */
2601       if (!stage)
2602         return;
2603
2604       _clutter_stage_maybe_relayout (stage);
2605     }
2606
2607   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2608    * own coordinate space... */
2609   actor_space_allocation.x1 = 0;
2610   actor_space_allocation.y1 = 0;
2611   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2612   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2613   _clutter_actor_transform_and_project_box (self,
2614                                             &actor_space_allocation,
2615                                             verts);
2616 }
2617
2618 static void
2619 clutter_actor_real_apply_transform (ClutterActor *self,
2620                                     CoglMatrix   *matrix)
2621 {
2622   ClutterActorPrivate *priv = self->priv;
2623
2624   if (!priv->transform_valid)
2625     {
2626       CoglMatrix *transform = &priv->transform;
2627       const ClutterTransformInfo *info;
2628
2629       info = _clutter_actor_get_transform_info_or_defaults (self);
2630
2631       cogl_matrix_init_identity (transform);
2632
2633       cogl_matrix_translate (transform,
2634                              priv->allocation.x1,
2635                              priv->allocation.y1,
2636                              0.0);
2637
2638       if (info->depth)
2639         cogl_matrix_translate (transform, 0, 0, info->depth);
2640
2641       /*
2642        * because the rotation involves translations, we must scale
2643        * before applying the rotations (if we apply the scale after
2644        * the rotations, the translations included in the rotation are
2645        * not scaled and so the entire object will move on the screen
2646        * as a result of rotating it).
2647        */
2648       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2649         {
2650           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2651                                         &info->scale_center,
2652                                         cogl_matrix_scale (transform,
2653                                                            info->scale_x,
2654                                                            info->scale_y,
2655                                                            1.0));
2656         }
2657
2658       if (info->rz_angle)
2659         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2660                                       &info->rz_center,
2661                                       cogl_matrix_rotate (transform,
2662                                                           info->rz_angle,
2663                                                           0, 0, 1.0));
2664
2665       if (info->ry_angle)
2666         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2667                                       &info->ry_center,
2668                                       cogl_matrix_rotate (transform,
2669                                                           info->ry_angle,
2670                                                           0, 1.0, 0));
2671
2672       if (info->rx_angle)
2673         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2674                                       &info->rx_center,
2675                                       cogl_matrix_rotate (transform,
2676                                                           info->rx_angle,
2677                                                           1.0, 0, 0));
2678
2679       if (!clutter_anchor_coord_is_zero (&info->anchor))
2680         {
2681           gfloat x, y, z;
2682
2683           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2684           cogl_matrix_translate (transform, -x, -y, -z);
2685         }
2686
2687       priv->transform_valid = TRUE;
2688     }
2689
2690   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2691 }
2692
2693 /* Applies the transforms associated with this actor to the given
2694  * matrix. */
2695 void
2696 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2697                                           CoglMatrix *matrix)
2698 {
2699   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2700 }
2701
2702 /*
2703  * clutter_actor_apply_relative_transformation_matrix:
2704  * @self: The actor whose coordinate space you want to transform from.
2705  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2706  *            or %NULL if you want to transform all the way to eye coordinates.
2707  * @matrix: A #CoglMatrix to apply the transformation too.
2708  *
2709  * This multiplies a transform with @matrix that will transform coordinates
2710  * from the coordinate space of @self into the coordinate space of @ancestor.
2711  *
2712  * For example if you need a matrix that can transform the local actor
2713  * coordinates of @self into stage coordinates you would pass the actor's stage
2714  * pointer as the @ancestor.
2715  *
2716  * If you pass %NULL then the transformation will take you all the way through
2717  * to eye coordinates. This can be useful if you want to extract the entire
2718  * modelview transform that Clutter applies before applying the projection
2719  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2720  * using cogl_set_modelview_matrix() for example then you would want a matrix
2721  * that transforms into eye coordinates.
2722  *
2723  * <note>This function doesn't initialize the given @matrix, it simply
2724  * multiplies the requested transformation matrix with the existing contents of
2725  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2726  * before calling this function, or you can use
2727  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2728  */
2729 void
2730 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2731                                                      ClutterActor *ancestor,
2732                                                      CoglMatrix *matrix)
2733 {
2734   ClutterActor *parent;
2735
2736   /* Note we terminate before ever calling stage->apply_transform()
2737    * since that would conceptually be relative to the underlying
2738    * window OpenGL coordinates so we'd need a special @ancestor
2739    * value to represent the fake parent of the stage. */
2740   if (self == ancestor)
2741     return;
2742
2743   parent = clutter_actor_get_parent (self);
2744
2745   if (parent != NULL)
2746     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2747                                                          matrix);
2748
2749   _clutter_actor_apply_modelview_transform (self, matrix);
2750 }
2751
2752 static void
2753 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2754                                        ClutterPaintVolume *pv,
2755                                        const char *label,
2756                                        const CoglColor *color)
2757 {
2758   static CoglPipeline *outline = NULL;
2759   CoglPrimitive *prim;
2760   ClutterVertex line_ends[12 * 2];
2761   int n_vertices;
2762   CoglContext *ctx =
2763     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2764   /* XXX: at some point we'll query this from the stage but we can't
2765    * do that until the osx backend uses Cogl natively. */
2766   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2767
2768   if (outline == NULL)
2769     outline = cogl_pipeline_new (ctx);
2770
2771   _clutter_paint_volume_complete (pv);
2772
2773   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2774
2775   /* Front face */
2776   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2777   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2778   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2779   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2780
2781   if (!pv->is_2d)
2782     {
2783       /* Back face */
2784       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2785       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2786       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2787       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2788
2789       /* Lines connecting front face to back face */
2790       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2791       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2792       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2793       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2794     }
2795
2796   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2797                                 n_vertices,
2798                                 (CoglVertexP3 *)line_ends);
2799
2800   cogl_pipeline_set_color (outline, color);
2801   cogl_framebuffer_draw_primitive (fb, outline, prim);
2802   cogl_object_unref (prim);
2803
2804   if (label)
2805     {
2806       PangoLayout *layout;
2807       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2808       pango_layout_set_text (layout, label, -1);
2809       cogl_pango_render_layout (layout,
2810                                 pv->vertices[0].x,
2811                                 pv->vertices[0].y,
2812                                 color,
2813                                 0);
2814       g_object_unref (layout);
2815     }
2816 }
2817
2818 static void
2819 _clutter_actor_draw_paint_volume (ClutterActor *self)
2820 {
2821   ClutterPaintVolume *pv;
2822   CoglColor color;
2823
2824   pv = _clutter_actor_get_paint_volume_mutable (self);
2825   if (!pv)
2826     {
2827       gfloat width, height;
2828       ClutterPaintVolume fake_pv;
2829
2830       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2831       _clutter_paint_volume_init_static (&fake_pv, stage);
2832
2833       clutter_actor_get_size (self, &width, &height);
2834       clutter_paint_volume_set_width (&fake_pv, width);
2835       clutter_paint_volume_set_height (&fake_pv, height);
2836
2837       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2838       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2839                                              _clutter_actor_get_debug_name (self),
2840                                              &color);
2841
2842       clutter_paint_volume_free (&fake_pv);
2843     }
2844   else
2845     {
2846       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2847       _clutter_actor_draw_paint_volume_full (self, pv,
2848                                              _clutter_actor_get_debug_name (self),
2849                                              &color);
2850     }
2851 }
2852
2853 static void
2854 _clutter_actor_paint_cull_result (ClutterActor *self,
2855                                   gboolean success,
2856                                   ClutterCullResult result)
2857 {
2858   ClutterPaintVolume *pv;
2859   CoglColor color;
2860
2861   if (success)
2862     {
2863       if (result == CLUTTER_CULL_RESULT_IN)
2864         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2865       else if (result == CLUTTER_CULL_RESULT_OUT)
2866         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2867       else
2868         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2869     }
2870   else
2871     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2872
2873   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2874     _clutter_actor_draw_paint_volume_full (self, pv,
2875                                            _clutter_actor_get_debug_name (self),
2876                                            &color);
2877   else
2878     {
2879       PangoLayout *layout;
2880       char *label =
2881         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2882       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2883       cogl_set_source_color (&color);
2884
2885       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2886       pango_layout_set_text (layout, label, -1);
2887       cogl_pango_render_layout (layout,
2888                                 0,
2889                                 0,
2890                                 &color,
2891                                 0);
2892       g_free (label);
2893       g_object_unref (layout);
2894     }
2895 }
2896
2897 static int clone_paint_level = 0;
2898
2899 void
2900 _clutter_actor_push_clone_paint (void)
2901 {
2902   clone_paint_level++;
2903 }
2904
2905 void
2906 _clutter_actor_pop_clone_paint (void)
2907 {
2908   clone_paint_level--;
2909 }
2910
2911 static gboolean
2912 in_clone_paint (void)
2913 {
2914   return clone_paint_level > 0;
2915 }
2916
2917 /* Returns TRUE if the actor can be ignored */
2918 /* FIXME: we should return a ClutterCullResult, and
2919  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2920  * means there's no point in trying to cull descendants of the current
2921  * node. */
2922 static gboolean
2923 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2924 {
2925   ClutterActorPrivate *priv = self->priv;
2926   ClutterActor *stage;
2927   const ClutterPlane *stage_clip;
2928
2929   if (!priv->last_paint_volume_valid)
2930     {
2931       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2932                     "->last_paint_volume_valid == FALSE",
2933                     _clutter_actor_get_debug_name (self));
2934       return FALSE;
2935     }
2936
2937   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2938     return FALSE;
2939
2940   stage = _clutter_actor_get_stage_internal (self);
2941   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2942   if (G_UNLIKELY (!stage_clip))
2943     {
2944       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2945                     "No stage clip set",
2946                     _clutter_actor_get_debug_name (self));
2947       return FALSE;
2948     }
2949
2950   if (cogl_get_draw_framebuffer () !=
2951       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2952     {
2953       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2954                     "Current framebuffer doesn't correspond to stage",
2955                     _clutter_actor_get_debug_name (self));
2956       return FALSE;
2957     }
2958
2959   *result_out =
2960     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2961   return TRUE;
2962 }
2963
2964 static void
2965 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2966 {
2967   ClutterActorPrivate *priv = self->priv;
2968   const ClutterPaintVolume *pv;
2969
2970   if (priv->last_paint_volume_valid)
2971     {
2972       clutter_paint_volume_free (&priv->last_paint_volume);
2973       priv->last_paint_volume_valid = FALSE;
2974     }
2975
2976   pv = clutter_actor_get_paint_volume (self);
2977   if (!pv)
2978     {
2979       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2980                     "Actor failed to report a paint volume",
2981                     _clutter_actor_get_debug_name (self));
2982       return;
2983     }
2984
2985   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2986
2987   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2988                                             NULL); /* eye coordinates */
2989
2990   priv->last_paint_volume_valid = TRUE;
2991 }
2992
2993 static inline gboolean
2994 actor_has_shader_data (ClutterActor *self)
2995 {
2996   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
2997 }
2998
2999 guint32
3000 _clutter_actor_get_pick_id (ClutterActor *self)
3001 {
3002   if (self->priv->pick_id < 0)
3003     return 0;
3004
3005   return self->priv->pick_id;
3006 }
3007
3008 /* This is the same as clutter_actor_add_effect except that it doesn't
3009    queue a redraw and it doesn't notify on the effect property */
3010 static void
3011 _clutter_actor_add_effect_internal (ClutterActor  *self,
3012                                     ClutterEffect *effect)
3013 {
3014   ClutterActorPrivate *priv = self->priv;
3015
3016   if (priv->effects == NULL)
3017     {
3018       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3019       priv->effects->actor = self;
3020     }
3021
3022   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3023 }
3024
3025 /* This is the same as clutter_actor_remove_effect except that it doesn't
3026    queue a redraw and it doesn't notify on the effect property */
3027 static void
3028 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3029                                        ClutterEffect *effect)
3030 {
3031   ClutterActorPrivate *priv = self->priv;
3032
3033   if (priv->effects == NULL)
3034     return;
3035
3036   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3037 }
3038
3039 static gboolean
3040 needs_flatten_effect (ClutterActor *self)
3041 {
3042   ClutterActorPrivate *priv = self->priv;
3043
3044   if (G_UNLIKELY (clutter_paint_debug_flags &
3045                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3046     return FALSE;
3047
3048   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3049     return TRUE;
3050   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3051     {
3052       if (clutter_actor_get_paint_opacity (self) < 255 &&
3053           clutter_actor_has_overlaps (self))
3054         return TRUE;
3055     }
3056
3057   return FALSE;
3058 }
3059
3060 static void
3061 add_or_remove_flatten_effect (ClutterActor *self)
3062 {
3063   ClutterActorPrivate *priv = self->priv;
3064
3065   /* Add or remove the flatten effect depending on the
3066      offscreen-redirect property. */
3067   if (needs_flatten_effect (self))
3068     {
3069       if (priv->flatten_effect == NULL)
3070         {
3071           ClutterActorMeta *actor_meta;
3072           gint priority;
3073
3074           priv->flatten_effect = _clutter_flatten_effect_new ();
3075           /* Keep a reference to the effect so that we can queue
3076              redraws from it */
3077           g_object_ref_sink (priv->flatten_effect);
3078
3079           /* Set the priority of the effect to high so that it will
3080              always be applied to the actor first. It uses an internal
3081              priority so that it won't be visible to applications */
3082           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3083           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3084           _clutter_actor_meta_set_priority (actor_meta, priority);
3085
3086           /* This will add the effect without queueing a redraw */
3087           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3088         }
3089     }
3090   else
3091     {
3092       if (priv->flatten_effect != NULL)
3093         {
3094           /* Destroy the effect so that it will lose its fbo cache of
3095              the actor */
3096           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3097           g_object_unref (priv->flatten_effect);
3098           priv->flatten_effect = NULL;
3099         }
3100     }
3101 }
3102
3103 static void
3104 clutter_actor_paint_node (ClutterActor     *actor,
3105                           ClutterPaintNode *root)
3106 {
3107   ClutterActorPrivate *priv = actor->priv;
3108
3109   if (priv->bg_color_set)
3110     {
3111       ClutterPaintNode *node;
3112       ClutterColor bg_color;
3113
3114       bg_color = priv->bg_color;
3115       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3116                      * priv->bg_color.alpha
3117                      / 255;
3118
3119       node = clutter_color_node_new (&bg_color);
3120       clutter_paint_node_set_name (node, "backgroundColor");
3121       clutter_paint_node_add_rectangle (node, &priv->allocation);
3122       clutter_paint_node_add_child (root, node);
3123       clutter_paint_node_unref (node);
3124     }
3125
3126   if (priv->content != NULL)
3127     _clutter_content_paint_content (priv->content, actor, root);
3128
3129   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3130     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3131
3132   if (clutter_paint_node_get_n_children (root) == 0)
3133     return;
3134
3135   _clutter_paint_node_paint (root);
3136 }
3137
3138 static void
3139 clutter_actor_real_paint (ClutterActor *actor)
3140 {
3141   ClutterActorPrivate *priv = actor->priv;
3142   ClutterActor *iter;
3143
3144   for (iter = priv->first_child;
3145        iter != NULL;
3146        iter = iter->priv->next_sibling)
3147     {
3148       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3149                     _clutter_actor_get_debug_name (iter),
3150                     _clutter_actor_get_debug_name (actor),
3151                     iter->priv->allocation.x1,
3152                     iter->priv->allocation.y1,
3153                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3154                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3155
3156       clutter_actor_paint (iter);
3157     }
3158 }
3159
3160 /**
3161  * clutter_actor_paint:
3162  * @self: A #ClutterActor
3163  *
3164  * Renders the actor to display.
3165  *
3166  * This function should not be called directly by applications.
3167  * Call clutter_actor_queue_redraw() to queue paints, instead.
3168  *
3169  * This function is context-aware, and will either cause a
3170  * regular paint or a pick paint.
3171  *
3172  * This function will emit the #ClutterActor::paint signal or
3173  * the #ClutterActor::pick signal, depending on the context.
3174  *
3175  * This function does not paint the actor if the actor is set to 0,
3176  * unless it is performing a pick paint.
3177  */
3178 void
3179 clutter_actor_paint (ClutterActor *self)
3180 {
3181   ClutterActorPrivate *priv;
3182   ClutterPickMode pick_mode;
3183   gboolean clip_set = FALSE;
3184   gboolean shader_applied = FALSE;
3185
3186   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3187                           "Actor real-paint counter",
3188                           "Increments each time any actor is painted",
3189                           0 /* no application private data */);
3190   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3191                           "Actor pick-paint counter",
3192                           "Increments each time any actor is painted "
3193                           "for picking",
3194                           0 /* no application private data */);
3195
3196   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3197
3198   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3199     return;
3200
3201   priv = self->priv;
3202
3203   pick_mode = _clutter_context_get_pick_mode ();
3204
3205   if (pick_mode == CLUTTER_PICK_NONE)
3206     priv->propagated_one_redraw = FALSE;
3207
3208   /* It's an important optimization that we consider painting of
3209    * actors with 0 opacity to be a NOP... */
3210   if (pick_mode == CLUTTER_PICK_NONE &&
3211       /* ignore top-levels, since they might be transparent */
3212       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3213       /* Use the override opacity if its been set */
3214       ((priv->opacity_override >= 0) ?
3215        priv->opacity_override : priv->opacity) == 0)
3216     return;
3217
3218   /* if we aren't paintable (not in a toplevel with all
3219    * parents paintable) then do nothing.
3220    */
3221   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3222     return;
3223
3224   /* mark that we are in the paint process */
3225   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3226
3227   cogl_push_matrix();
3228
3229   if (priv->enable_model_view_transform)
3230     {
3231       CoglMatrix matrix;
3232
3233       /* XXX: It could be better to cache the modelview with the actor
3234        * instead of progressively building up the transformations on
3235        * the matrix stack every time we paint. */
3236       cogl_get_modelview_matrix (&matrix);
3237       _clutter_actor_apply_modelview_transform (self, &matrix);
3238
3239 #ifdef CLUTTER_ENABLE_DEBUG
3240       /* Catch when out-of-band transforms have been made by actors not as part
3241        * of an apply_transform vfunc... */
3242       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3243         {
3244           CoglMatrix expected_matrix;
3245
3246           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3247                                                              &expected_matrix);
3248
3249           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3250             {
3251               GString *buf = g_string_sized_new (1024);
3252               ClutterActor *parent;
3253
3254               parent = self;
3255               while (parent != NULL)
3256                 {
3257                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3258
3259                   if (parent->priv->parent != NULL)
3260                     g_string_append (buf, "->");
3261
3262                   parent = parent->priv->parent;
3263                 }
3264
3265               g_warning ("Unexpected transform found when painting actor "
3266                          "\"%s\". This will be caused by one of the actor's "
3267                          "ancestors (%s) using the Cogl API directly to transform "
3268                          "children instead of using ::apply_transform().",
3269                          _clutter_actor_get_debug_name (self),
3270                          buf->str);
3271
3272               g_string_free (buf, TRUE);
3273             }
3274         }
3275 #endif /* CLUTTER_ENABLE_DEBUG */
3276
3277       cogl_set_modelview_matrix (&matrix);
3278     }
3279
3280   if (priv->has_clip)
3281     {
3282       cogl_clip_push_rectangle (priv->clip.x,
3283                                 priv->clip.y,
3284                                 priv->clip.x + priv->clip.width,
3285                                 priv->clip.y + priv->clip.height);
3286       clip_set = TRUE;
3287     }
3288   else if (priv->clip_to_allocation)
3289     {
3290       gfloat width, height;
3291
3292       width  = priv->allocation.x2 - priv->allocation.x1;
3293       height = priv->allocation.y2 - priv->allocation.y1;
3294
3295       cogl_clip_push_rectangle (0, 0, width, height);
3296       clip_set = TRUE;
3297     }
3298
3299   if (pick_mode == CLUTTER_PICK_NONE)
3300     {
3301       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3302
3303       /* We check whether we need to add the flatten effect before
3304          each paint so that we can avoid having a mechanism for
3305          applications to notify when the value of the
3306          has_overlaps virtual changes. */
3307       add_or_remove_flatten_effect (self);
3308     }
3309   else
3310     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3311
3312   /* We save the current paint volume so that the next time the
3313    * actor queues a redraw we can constrain the redraw to just
3314    * cover the union of the new bounding box and the old.
3315    *
3316    * We also fetch the current paint volume to perform culling so
3317    * we can avoid painting actors outside the current clip region.
3318    *
3319    * If we are painting inside a clone, we should neither update
3320    * the paint volume or use it to cull painting, since the paint
3321    * box represents the location of the source actor on the
3322    * screen.
3323    *
3324    * XXX: We are starting to do a lot of vertex transforms on
3325    * the CPU in a typical paint, so at some point we should
3326    * audit these and consider caching some things.
3327    *
3328    * NB: We don't perform culling while picking at this point because
3329    * clutter-stage.c doesn't setup the clipping planes appropriately.
3330    *
3331    * NB: We don't want to update the last-paint-volume during picking
3332    * because the last-paint-volume is used to determine the old screen
3333    * space location of an actor that has moved so we can know the
3334    * minimal region to redraw to clear an old view of the actor. If we
3335    * update this during picking then by the time we come around to
3336    * paint then the last-paint-volume would likely represent the new
3337    * actor position not the old.
3338    */
3339   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3340     {
3341       gboolean success;
3342       /* annoyingly gcc warns if uninitialized even though
3343        * the initialization is redundant :-( */
3344       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3345
3346       if (G_LIKELY ((clutter_paint_debug_flags &
3347                      (CLUTTER_DEBUG_DISABLE_CULLING |
3348                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3349                     (CLUTTER_DEBUG_DISABLE_CULLING |
3350                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3351         _clutter_actor_update_last_paint_volume (self);
3352
3353       success = cull_actor (self, &result);
3354
3355       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3356         _clutter_actor_paint_cull_result (self, success, result);
3357       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3358         goto done;
3359     }
3360
3361   if (priv->effects == NULL)
3362     {
3363       if (pick_mode == CLUTTER_PICK_NONE &&
3364           actor_has_shader_data (self))
3365         {
3366           _clutter_actor_shader_pre_paint (self, FALSE);
3367           shader_applied = TRUE;
3368         }
3369
3370       priv->next_effect_to_paint = NULL;
3371     }
3372   else
3373     priv->next_effect_to_paint =
3374       _clutter_meta_group_peek_metas (priv->effects);
3375
3376   clutter_actor_continue_paint (self);
3377
3378   if (shader_applied)
3379     _clutter_actor_shader_post_paint (self);
3380
3381   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3382                   pick_mode == CLUTTER_PICK_NONE))
3383     _clutter_actor_draw_paint_volume (self);
3384
3385 done:
3386   /* If we make it here then the actor has run through a complete
3387      paint run including all the effects so it's no longer dirty */
3388   if (pick_mode == CLUTTER_PICK_NONE)
3389     priv->is_dirty = FALSE;
3390
3391   if (clip_set)
3392     cogl_clip_pop();
3393
3394   cogl_pop_matrix();
3395
3396   /* paint sequence complete */
3397   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3398 }
3399
3400 /**
3401  * clutter_actor_continue_paint:
3402  * @self: A #ClutterActor
3403  *
3404  * Run the next stage of the paint sequence. This function should only
3405  * be called within the implementation of the ‘run’ virtual of a
3406  * #ClutterEffect. It will cause the run method of the next effect to
3407  * be applied, or it will paint the actual actor if the current effect
3408  * is the last effect in the chain.
3409  *
3410  * Since: 1.8
3411  */
3412 void
3413 clutter_actor_continue_paint (ClutterActor *self)
3414 {
3415   ClutterActorPrivate *priv;
3416
3417   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3418   /* This should only be called from with in the ‘run’ implementation
3419      of a ClutterEffect */
3420   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3421
3422   priv = self->priv;
3423
3424   /* Skip any effects that are disabled */
3425   while (priv->next_effect_to_paint &&
3426          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3427     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3428
3429   /* If this has come from the last effect then we'll just paint the
3430      actual actor */
3431   if (priv->next_effect_to_paint == NULL)
3432     {
3433       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3434         {
3435           ClutterPaintNode *dummy;
3436
3437           /* XXX - this will go away in 2.0, when we can get rid of this
3438            * stuff and switch to a pure retained render tree of PaintNodes
3439            * for the entire frame, starting from the Stage.
3440            */
3441           dummy = _clutter_dummy_node_new ();
3442           clutter_paint_node_set_name (dummy, "Root");
3443           clutter_actor_paint_node (self, dummy);
3444
3445           if (clutter_paint_node_get_n_children (dummy) != 0)
3446             {
3447 #ifdef CLUTTER_ENABLE_DEBUG
3448               if (CLUTTER_HAS_DEBUG (PAINT))
3449                 {
3450                   /* dump the tree only if we have one */
3451                   _clutter_paint_node_dump_tree (dummy);
3452                 }
3453 #endif /* CLUTTER_ENABLE_DEBUG */
3454
3455               _clutter_paint_node_paint (dummy);
3456             }
3457
3458           clutter_paint_node_unref (dummy);
3459
3460           g_signal_emit (self, actor_signals[PAINT], 0);
3461         }
3462       else
3463         {
3464           ClutterColor col = { 0, };
3465
3466           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3467
3468           /* Actor will then paint silhouette of itself in supplied
3469            * color.  See clutter_stage_get_actor_at_pos() for where
3470            * picking is enabled.
3471            */
3472           g_signal_emit (self, actor_signals[PICK], 0, &col);
3473         }
3474     }
3475   else
3476     {
3477       ClutterEffect *old_current_effect;
3478       ClutterEffectPaintFlags run_flags = 0;
3479
3480       /* Cache the current effect so that we can put it back before
3481          returning */
3482       old_current_effect = priv->current_effect;
3483
3484       priv->current_effect = priv->next_effect_to_paint->data;
3485       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3486
3487       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3488         {
3489           if (priv->is_dirty)
3490             {
3491               /* If there's an effect queued with this redraw then all
3492                  effects up to that one will be considered dirty. It
3493                  is expected the queued effect will paint the cached
3494                  image and not call clutter_actor_continue_paint again
3495                  (although it should work ok if it does) */
3496               if (priv->effect_to_redraw == NULL ||
3497                   priv->current_effect != priv->effect_to_redraw)
3498                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3499             }
3500
3501           _clutter_effect_paint (priv->current_effect, run_flags);
3502         }
3503       else
3504         {
3505           /* We can't determine when an actor has been modified since
3506              its last pick so lets just assume it has always been
3507              modified */
3508           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3509
3510           _clutter_effect_pick (priv->current_effect, run_flags);
3511         }
3512
3513       priv->current_effect = old_current_effect;
3514     }
3515 }
3516
3517 static ClutterActorTraverseVisitFlags
3518 invalidate_queue_redraw_entry (ClutterActor *self,
3519                                int           depth,
3520                                gpointer      user_data)
3521 {
3522   ClutterActorPrivate *priv = self->priv;
3523
3524   if (priv->queue_redraw_entry != NULL)
3525     {
3526       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3527       priv->queue_redraw_entry = NULL;
3528     }
3529
3530   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3531 }
3532
3533 static inline void
3534 remove_child (ClutterActor *self,
3535               ClutterActor *child)
3536 {
3537   ClutterActor *prev_sibling, *next_sibling;
3538
3539   prev_sibling = child->priv->prev_sibling;
3540   next_sibling = child->priv->next_sibling;
3541
3542   if (prev_sibling != NULL)
3543     prev_sibling->priv->next_sibling = next_sibling;
3544
3545   if (next_sibling != NULL)
3546     next_sibling->priv->prev_sibling = prev_sibling;
3547
3548   if (self->priv->first_child == child)
3549     self->priv->first_child = next_sibling;
3550
3551   if (self->priv->last_child == child)
3552     self->priv->last_child = prev_sibling;
3553
3554   child->priv->parent = NULL;
3555   child->priv->prev_sibling = NULL;
3556   child->priv->next_sibling = NULL;
3557 }
3558
3559 typedef enum {
3560   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3561   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3562   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3563   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3564   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3565   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3566
3567   /* default flags for public API */
3568   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3569                                     REMOVE_CHILD_EMIT_PARENT_SET |
3570                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3571                                     REMOVE_CHILD_CHECK_STATE |
3572                                     REMOVE_CHILD_FLUSH_QUEUE |
3573                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3574
3575   /* flags for legacy/deprecated API */
3576   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3577                                     REMOVE_CHILD_FLUSH_QUEUE |
3578                                     REMOVE_CHILD_EMIT_PARENT_SET |
3579                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3580 } ClutterActorRemoveChildFlags;
3581
3582 /*< private >
3583  * clutter_actor_remove_child_internal:
3584  * @self: a #ClutterActor
3585  * @child: the child of @self that has to be removed
3586  * @flags: control the removal operations
3587  *
3588  * Removes @child from the list of children of @self.
3589  */
3590 static void
3591 clutter_actor_remove_child_internal (ClutterActor                 *self,
3592                                      ClutterActor                 *child,
3593                                      ClutterActorRemoveChildFlags  flags)
3594 {
3595   ClutterActor *old_first, *old_last;
3596   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3597   gboolean flush_queue;
3598   gboolean notify_first_last;
3599   gboolean was_mapped;
3600
3601   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3602   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3603   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3604   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3605   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3606   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3607
3608   g_object_freeze_notify (G_OBJECT (self));
3609
3610   if (destroy_meta)
3611     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3612
3613   if (check_state)
3614     {
3615       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3616
3617       /* we need to unrealize *before* we set parent_actor to NULL,
3618        * because in an unrealize method actors are dissociating from the
3619        * stage, which means they need to be able to
3620        * clutter_actor_get_stage().
3621        *
3622        * yhis should unmap and unrealize, unless we're reparenting.
3623        */
3624       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3625     }
3626   else
3627     was_mapped = FALSE;
3628
3629   if (flush_queue)
3630     {
3631       /* We take this opportunity to invalidate any queue redraw entry
3632        * associated with the actor and descendants since we won't be able to
3633        * determine the appropriate stage after this.
3634        *
3635        * we do this after we updated the mapped state because actors might
3636        * end up queueing redraws inside their mapped/unmapped virtual
3637        * functions, and if we invalidate the redraw entry we could end up
3638        * with an inconsistent state and weird memory corruption. see
3639        * bugs:
3640        *
3641        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3642        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3643        */
3644       _clutter_actor_traverse (child,
3645                                0,
3646                                invalidate_queue_redraw_entry,
3647                                NULL,
3648                                NULL);
3649     }
3650
3651   old_first = self->priv->first_child;
3652   old_last = self->priv->last_child;
3653
3654   remove_child (self, child);
3655
3656   self->priv->n_children -= 1;
3657
3658   self->priv->age += 1;
3659
3660   /* clutter_actor_reparent() will emit ::parent-set for us */
3661   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3662     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3663
3664   /* if the child was mapped then we need to relayout ourselves to account
3665    * for the removed child
3666    */
3667   if (was_mapped)
3668     clutter_actor_queue_relayout (self);
3669
3670   /* we need to emit the signal before dropping the reference */
3671   if (emit_actor_removed)
3672     g_signal_emit_by_name (self, "actor-removed", child);
3673
3674   if (notify_first_last)
3675     {
3676       if (old_first != self->priv->first_child)
3677         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3678
3679       if (old_last != self->priv->last_child)
3680         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3681     }
3682
3683   g_object_thaw_notify (G_OBJECT (self));
3684
3685   /* remove the reference we acquired in clutter_actor_add_child() */
3686   g_object_unref (child);
3687 }
3688
3689 static const ClutterTransformInfo default_transform_info = {
3690   0.0, { 0, },          /* rotation-x */
3691   0.0, { 0, },          /* rotation-y */
3692   0.0, { 0, },          /* rotation-z */
3693
3694   1.0, 1.0, { 0, },     /* scale */
3695
3696   { 0, },               /* anchor */
3697
3698   0.0,                  /* depth */
3699 };
3700
3701 /*< private >
3702  * _clutter_actor_get_transform_info_or_defaults:
3703  * @self: a #ClutterActor
3704  *
3705  * Retrieves the ClutterTransformInfo structure associated to an actor.
3706  *
3707  * If the actor does not have a ClutterTransformInfo structure associated
3708  * to it, then the default structure will be returned.
3709  *
3710  * This function should only be used for getters.
3711  *
3712  * Return value: a const pointer to the ClutterTransformInfo structure
3713  */
3714 const ClutterTransformInfo *
3715 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3716 {
3717   ClutterTransformInfo *info;
3718
3719   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3720   if (info != NULL)
3721     return info;
3722
3723   return &default_transform_info;
3724 }
3725
3726 static void
3727 clutter_transform_info_free (gpointer data)
3728 {
3729   if (data != NULL)
3730     g_slice_free (ClutterTransformInfo, data);
3731 }
3732
3733 /*< private >
3734  * _clutter_actor_get_transform_info:
3735  * @self: a #ClutterActor
3736  *
3737  * Retrieves a pointer to the ClutterTransformInfo structure.
3738  *
3739  * If the actor does not have a ClutterTransformInfo associated to it, one
3740  * will be created and initialized to the default values.
3741  *
3742  * This function should be used for setters.
3743  *
3744  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3745  * instead.
3746  *
3747  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3748  *   structure
3749  */
3750 ClutterTransformInfo *
3751 _clutter_actor_get_transform_info (ClutterActor *self)
3752 {
3753   ClutterTransformInfo *info;
3754
3755   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3756   if (info == NULL)
3757     {
3758       info = g_slice_new (ClutterTransformInfo);
3759
3760       *info = default_transform_info;
3761
3762       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3763                                info,
3764                                clutter_transform_info_free);
3765     }
3766
3767   return info;
3768 }
3769
3770 /*< private >
3771  * clutter_actor_set_rotation_angle_internal:
3772  * @self: a #ClutterActor
3773  * @axis: the axis of the angle to change
3774  * @angle: the angle of rotation
3775  *
3776  * Sets the rotation angle on the given axis without affecting the
3777  * rotation center point.
3778  */
3779 static inline void
3780 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3781                                            ClutterRotateAxis  axis,
3782                                            gdouble            angle)
3783 {
3784   GObject *obj = G_OBJECT (self);
3785   ClutterTransformInfo *info;
3786
3787   info = _clutter_actor_get_transform_info (self);
3788
3789   g_object_freeze_notify (obj);
3790
3791   switch (axis)
3792     {
3793     case CLUTTER_X_AXIS:
3794       info->rx_angle = angle;
3795       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3796       break;
3797
3798     case CLUTTER_Y_AXIS:
3799       info->ry_angle = angle;
3800       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3801       break;
3802
3803     case CLUTTER_Z_AXIS:
3804       info->rz_angle = angle;
3805       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3806       break;
3807     }
3808
3809   self->priv->transform_valid = FALSE;
3810
3811   g_object_thaw_notify (obj);
3812
3813   clutter_actor_queue_redraw (self);
3814 }
3815
3816 static inline void
3817 clutter_actor_set_rotation_angle (ClutterActor      *self,
3818                                   ClutterRotateAxis  axis,
3819                                   gdouble            angle)
3820 {
3821   ClutterTransformInfo *info;
3822
3823   info = _clutter_actor_get_transform_info (self);
3824
3825   if (clutter_actor_get_easing_duration (self) != 0)
3826     {
3827       ClutterTransition *transition;
3828       GParamSpec *pspec = NULL;
3829       double *cur_angle_p = NULL;
3830
3831       switch (axis)
3832         {
3833         case CLUTTER_X_AXIS:
3834           cur_angle_p = &info->rx_angle;
3835           pspec = obj_props[PROP_ROTATION_ANGLE_X];
3836           break;
3837
3838         case CLUTTER_Y_AXIS:
3839           cur_angle_p = &info->ry_angle;
3840           pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3841           break;
3842
3843         case CLUTTER_Z_AXIS:
3844           cur_angle_p = &info->rz_angle;
3845           pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3846           break;
3847         }
3848
3849       g_assert (pspec != NULL);
3850       g_assert (cur_angle_p != NULL);
3851
3852       transition = _clutter_actor_get_transition (self, pspec);
3853       if (transition == NULL)
3854         {
3855           transition = _clutter_actor_create_transition (self, pspec,
3856                                                          *cur_angle_p,
3857                                                          angle);
3858           clutter_timeline_start (CLUTTER_TIMELINE (transition));
3859         }
3860       else
3861         _clutter_actor_update_transition (self, pspec, angle);
3862
3863       self->priv->transform_valid = FALSE;
3864       clutter_actor_queue_redraw (self);
3865     }
3866   else
3867     clutter_actor_set_rotation_angle_internal (self, axis, angle);
3868 }
3869
3870 /*< private >
3871  * clutter_actor_set_rotation_center_internal:
3872  * @self: a #ClutterActor
3873  * @axis: the axis of the center to change
3874  * @center: the coordinates of the rotation center
3875  *
3876  * Sets the rotation center on the given axis without affecting the
3877  * rotation angle.
3878  */
3879 static inline void
3880 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3881                                             ClutterRotateAxis    axis,
3882                                             const ClutterVertex *center)
3883 {
3884   GObject *obj = G_OBJECT (self);
3885   ClutterTransformInfo *info;
3886   ClutterVertex v = { 0, 0, 0 };
3887
3888   info = _clutter_actor_get_transform_info (self);
3889
3890   if (center != NULL)
3891     v = *center;
3892
3893   g_object_freeze_notify (obj);
3894
3895   switch (axis)
3896     {
3897     case CLUTTER_X_AXIS:
3898       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3899       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3900       break;
3901
3902     case CLUTTER_Y_AXIS:
3903       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3904       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3905       break;
3906
3907     case CLUTTER_Z_AXIS:
3908       /* if the previously set rotation center was fractional, then
3909        * setting explicit coordinates will have to notify the
3910        * :rotation-center-z-gravity property as well
3911        */
3912       if (info->rz_center.is_fractional)
3913         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3914
3915       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3916       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3917       break;
3918     }
3919
3920   self->priv->transform_valid = FALSE;
3921
3922   g_object_thaw_notify (obj);
3923
3924   clutter_actor_queue_redraw (self);
3925 }
3926
3927 static void
3928 clutter_actor_animate_scale_factor (ClutterActor *self,
3929                                     double        old_factor,
3930                                     double        new_factor,
3931                                     GParamSpec   *pspec)
3932 {
3933   ClutterTransition *transition;
3934
3935   transition = _clutter_actor_get_transition (self, pspec);
3936   if (transition == NULL)
3937     {
3938       transition = _clutter_actor_create_transition (self, pspec,
3939                                                      old_factor,
3940                                                      new_factor);
3941       clutter_timeline_start (CLUTTER_TIMELINE (transition));
3942     }
3943   else
3944     _clutter_actor_update_transition (self, pspec, new_factor);
3945
3946
3947   self->priv->transform_valid = FALSE;
3948   clutter_actor_queue_redraw (self);
3949 }
3950
3951 static void
3952 clutter_actor_set_scale_factor_internal (ClutterActor *self,
3953                                          double factor,
3954                                          GParamSpec *pspec)
3955 {
3956   GObject *obj = G_OBJECT (self);
3957   ClutterTransformInfo *info;
3958
3959   info = _clutter_actor_get_transform_info (self);
3960
3961   if (pspec == obj_props[PROP_SCALE_X])
3962     info->scale_x = factor;
3963   else
3964     info->scale_y = factor;
3965
3966   self->priv->transform_valid = FALSE;
3967   clutter_actor_queue_redraw (self);
3968   g_object_notify_by_pspec (obj, pspec);
3969 }
3970
3971 static inline void
3972 clutter_actor_set_scale_factor (ClutterActor      *self,
3973                                 ClutterRotateAxis  axis,
3974                                 gdouble            factor)
3975 {
3976   GObject *obj = G_OBJECT (self);
3977   ClutterTransformInfo *info;
3978   GParamSpec *pspec;
3979
3980   info = _clutter_actor_get_transform_info (self);
3981
3982   g_object_freeze_notify (obj);
3983
3984   switch (axis)
3985     {
3986     case CLUTTER_X_AXIS:
3987       pspec = obj_props[PROP_SCALE_X];
3988
3989       if (clutter_actor_get_easing_duration (self) != 0)
3990         clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
3991       else
3992         clutter_actor_set_scale_factor_internal (self, factor, pspec);
3993       break;
3994
3995     case CLUTTER_Y_AXIS:
3996       pspec = obj_props[PROP_SCALE_Y];
3997
3998       if (clutter_actor_get_easing_duration (self) != 0)
3999         clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4000       else
4001         clutter_actor_set_scale_factor_internal (self, factor, pspec);
4002       break;
4003
4004     default:
4005       g_assert_not_reached ();
4006     }
4007
4008   g_object_thaw_notify (obj);
4009 }
4010
4011 static inline void
4012 clutter_actor_set_scale_center (ClutterActor      *self,
4013                                 ClutterRotateAxis  axis,
4014                                 gfloat             coord)
4015 {
4016   GObject *obj = G_OBJECT (self);
4017   ClutterTransformInfo *info;
4018   gfloat center_x, center_y;
4019
4020   info = _clutter_actor_get_transform_info (self);
4021
4022   g_object_freeze_notify (obj);
4023
4024   /* get the current scale center coordinates */
4025   clutter_anchor_coord_get_units (self, &info->scale_center,
4026                                   &center_x,
4027                                   &center_y,
4028                                   NULL);
4029
4030   /* we need to notify this too, because setting explicit coordinates will
4031    * change the gravity as a side effect
4032    */
4033   if (info->scale_center.is_fractional)
4034     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4035
4036   switch (axis)
4037     {
4038     case CLUTTER_X_AXIS:
4039       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4040       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4041       break;
4042
4043     case CLUTTER_Y_AXIS:
4044       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4045       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4046       break;
4047
4048     default:
4049       g_assert_not_reached ();
4050     }
4051
4052   self->priv->transform_valid = FALSE;
4053
4054   clutter_actor_queue_redraw (self);
4055
4056   g_object_thaw_notify (obj);
4057 }
4058
4059 static inline void
4060 clutter_actor_set_anchor_coord (ClutterActor      *self,
4061                                 ClutterRotateAxis  axis,
4062                                 gfloat             coord)
4063 {
4064   GObject *obj = G_OBJECT (self);
4065   ClutterTransformInfo *info;
4066   gfloat anchor_x, anchor_y;
4067
4068   info = _clutter_actor_get_transform_info (self);
4069
4070   g_object_freeze_notify (obj);
4071
4072   clutter_anchor_coord_get_units (self, &info->anchor,
4073                                   &anchor_x,
4074                                   &anchor_y,
4075                                   NULL);
4076
4077   if (info->anchor.is_fractional)
4078     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4079
4080   switch (axis)
4081     {
4082     case CLUTTER_X_AXIS:
4083       clutter_anchor_coord_set_units (&info->anchor,
4084                                       coord,
4085                                       anchor_y,
4086                                       0.0);
4087       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4088       break;
4089
4090     case CLUTTER_Y_AXIS:
4091       clutter_anchor_coord_set_units (&info->anchor,
4092                                       anchor_x,
4093                                       coord,
4094                                       0.0);
4095       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4096       break;
4097
4098     default:
4099       g_assert_not_reached ();
4100     }
4101
4102   self->priv->transform_valid = FALSE;
4103
4104   clutter_actor_queue_redraw (self);
4105
4106   g_object_thaw_notify (obj);
4107 }
4108
4109 static void
4110 clutter_actor_set_property (GObject      *object,
4111                             guint         prop_id,
4112                             const GValue *value,
4113                             GParamSpec   *pspec)
4114 {
4115   ClutterActor *actor = CLUTTER_ACTOR (object);
4116   ClutterActorPrivate *priv = actor->priv;
4117
4118   switch (prop_id)
4119     {
4120     case PROP_X:
4121       clutter_actor_set_x (actor, g_value_get_float (value));
4122       break;
4123
4124     case PROP_Y:
4125       clutter_actor_set_y (actor, g_value_get_float (value));
4126       break;
4127
4128     case PROP_WIDTH:
4129       clutter_actor_set_width (actor, g_value_get_float (value));
4130       break;
4131
4132     case PROP_HEIGHT:
4133       clutter_actor_set_height (actor, g_value_get_float (value));
4134       break;
4135
4136     case PROP_FIXED_X:
4137       clutter_actor_set_x (actor, g_value_get_float (value));
4138       break;
4139
4140     case PROP_FIXED_Y:
4141       clutter_actor_set_y (actor, g_value_get_float (value));
4142       break;
4143
4144     case PROP_FIXED_POSITION_SET:
4145       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4146       break;
4147
4148     case PROP_MIN_WIDTH:
4149       clutter_actor_set_min_width (actor, g_value_get_float (value));
4150       break;
4151
4152     case PROP_MIN_HEIGHT:
4153       clutter_actor_set_min_height (actor, g_value_get_float (value));
4154       break;
4155
4156     case PROP_NATURAL_WIDTH:
4157       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4158       break;
4159
4160     case PROP_NATURAL_HEIGHT:
4161       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4162       break;
4163
4164     case PROP_MIN_WIDTH_SET:
4165       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4166       break;
4167
4168     case PROP_MIN_HEIGHT_SET:
4169       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4170       break;
4171
4172     case PROP_NATURAL_WIDTH_SET:
4173       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4174       break;
4175
4176     case PROP_NATURAL_HEIGHT_SET:
4177       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4178       break;
4179
4180     case PROP_REQUEST_MODE:
4181       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4182       break;
4183
4184     case PROP_DEPTH:
4185       clutter_actor_set_depth (actor, g_value_get_float (value));
4186       break;
4187
4188     case PROP_OPACITY:
4189       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4190       break;
4191
4192     case PROP_OFFSCREEN_REDIRECT:
4193       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4194       break;
4195
4196     case PROP_NAME:
4197       clutter_actor_set_name (actor, g_value_get_string (value));
4198       break;
4199
4200     case PROP_VISIBLE:
4201       if (g_value_get_boolean (value) == TRUE)
4202         clutter_actor_show (actor);
4203       else
4204         clutter_actor_hide (actor);
4205       break;
4206
4207     case PROP_SCALE_X:
4208       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4209                                       g_value_get_double (value));
4210       break;
4211
4212     case PROP_SCALE_Y:
4213       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4214                                       g_value_get_double (value));
4215       break;
4216
4217     case PROP_SCALE_CENTER_X:
4218       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4219                                       g_value_get_float (value));
4220       break;
4221
4222     case PROP_SCALE_CENTER_Y:
4223       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4224                                       g_value_get_float (value));
4225       break;
4226
4227     case PROP_SCALE_GRAVITY:
4228       {
4229         const ClutterTransformInfo *info;
4230         ClutterGravity gravity;
4231
4232         info = _clutter_actor_get_transform_info_or_defaults (actor);
4233         gravity = g_value_get_enum (value);
4234
4235         clutter_actor_set_scale_with_gravity (actor,
4236                                               info->scale_x,
4237                                               info->scale_y,
4238                                               gravity);
4239       }
4240       break;
4241
4242     case PROP_CLIP:
4243       {
4244         const ClutterGeometry *geom = g_value_get_boxed (value);
4245
4246         clutter_actor_set_clip (actor,
4247                                 geom->x, geom->y,
4248                                 geom->width, geom->height);
4249       }
4250       break;
4251
4252     case PROP_CLIP_TO_ALLOCATION:
4253       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4254       break;
4255
4256     case PROP_REACTIVE:
4257       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4258       break;
4259
4260     case PROP_ROTATION_ANGLE_X:
4261       clutter_actor_set_rotation_angle (actor,
4262                                         CLUTTER_X_AXIS,
4263                                         g_value_get_double (value));
4264       break;
4265
4266     case PROP_ROTATION_ANGLE_Y:
4267       clutter_actor_set_rotation_angle (actor,
4268                                         CLUTTER_Y_AXIS,
4269                                         g_value_get_double (value));
4270       break;
4271
4272     case PROP_ROTATION_ANGLE_Z:
4273       clutter_actor_set_rotation_angle (actor,
4274                                         CLUTTER_Z_AXIS,
4275                                         g_value_get_double (value));
4276       break;
4277
4278     case PROP_ROTATION_CENTER_X:
4279       clutter_actor_set_rotation_center_internal (actor,
4280                                                   CLUTTER_X_AXIS,
4281                                                   g_value_get_boxed (value));
4282       break;
4283
4284     case PROP_ROTATION_CENTER_Y:
4285       clutter_actor_set_rotation_center_internal (actor,
4286                                                   CLUTTER_Y_AXIS,
4287                                                   g_value_get_boxed (value));
4288       break;
4289
4290     case PROP_ROTATION_CENTER_Z:
4291       clutter_actor_set_rotation_center_internal (actor,
4292                                                   CLUTTER_Z_AXIS,
4293                                                   g_value_get_boxed (value));
4294       break;
4295
4296     case PROP_ROTATION_CENTER_Z_GRAVITY:
4297       {
4298         const ClutterTransformInfo *info;
4299
4300         info = _clutter_actor_get_transform_info_or_defaults (actor);
4301         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4302                                                    g_value_get_enum (value));
4303       }
4304       break;
4305
4306     case PROP_ANCHOR_X:
4307       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4308                                       g_value_get_float (value));
4309       break;
4310
4311     case PROP_ANCHOR_Y:
4312       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4313                                       g_value_get_float (value));
4314       break;
4315
4316     case PROP_ANCHOR_GRAVITY:
4317       clutter_actor_set_anchor_point_from_gravity (actor,
4318                                                    g_value_get_enum (value));
4319       break;
4320
4321     case PROP_SHOW_ON_SET_PARENT:
4322       priv->show_on_set_parent = g_value_get_boolean (value);
4323       break;
4324
4325     case PROP_TEXT_DIRECTION:
4326       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4327       break;
4328
4329     case PROP_ACTIONS:
4330       clutter_actor_add_action (actor, g_value_get_object (value));
4331       break;
4332
4333     case PROP_CONSTRAINTS:
4334       clutter_actor_add_constraint (actor, g_value_get_object (value));
4335       break;
4336
4337     case PROP_EFFECT:
4338       clutter_actor_add_effect (actor, g_value_get_object (value));
4339       break;
4340
4341     case PROP_LAYOUT_MANAGER:
4342       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4343       break;
4344
4345     case PROP_X_ALIGN:
4346       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4347       break;
4348
4349     case PROP_Y_ALIGN:
4350       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4351       break;
4352
4353     case PROP_MARGIN_TOP:
4354       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4355       break;
4356
4357     case PROP_MARGIN_BOTTOM:
4358       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4359       break;
4360
4361     case PROP_MARGIN_LEFT:
4362       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4363       break;
4364
4365     case PROP_MARGIN_RIGHT:
4366       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4367       break;
4368
4369     case PROP_BACKGROUND_COLOR:
4370       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4371       break;
4372
4373     case PROP_CONTENT:
4374       clutter_actor_set_content (actor, g_value_get_object (value));
4375       break;
4376
4377     case PROP_CONTENT_GRAVITY:
4378       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4379       break;
4380
4381     default:
4382       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4383       break;
4384     }
4385 }
4386
4387 static void
4388 clutter_actor_get_property (GObject    *object,
4389                             guint       prop_id,
4390                             GValue     *value,
4391                             GParamSpec *pspec)
4392 {
4393   ClutterActor *actor = CLUTTER_ACTOR (object);
4394   ClutterActorPrivate *priv = actor->priv;
4395
4396   switch (prop_id)
4397     {
4398     case PROP_X:
4399       g_value_set_float (value, clutter_actor_get_x (actor));
4400       break;
4401
4402     case PROP_Y:
4403       g_value_set_float (value, clutter_actor_get_y (actor));
4404       break;
4405
4406     case PROP_WIDTH:
4407       g_value_set_float (value, clutter_actor_get_width (actor));
4408       break;
4409
4410     case PROP_HEIGHT:
4411       g_value_set_float (value, clutter_actor_get_height (actor));
4412       break;
4413
4414     case PROP_FIXED_X:
4415       {
4416         const ClutterLayoutInfo *info;
4417
4418         info = _clutter_actor_get_layout_info_or_defaults (actor);
4419         g_value_set_float (value, info->fixed_x);
4420       }
4421       break;
4422
4423     case PROP_FIXED_Y:
4424       {
4425         const ClutterLayoutInfo *info;
4426
4427         info = _clutter_actor_get_layout_info_or_defaults (actor);
4428         g_value_set_float (value, info->fixed_y);
4429       }
4430       break;
4431
4432     case PROP_FIXED_POSITION_SET:
4433       g_value_set_boolean (value, priv->position_set);
4434       break;
4435
4436     case PROP_MIN_WIDTH:
4437       {
4438         const ClutterLayoutInfo *info;
4439
4440         info = _clutter_actor_get_layout_info_or_defaults (actor);
4441         g_value_set_float (value, info->min_width);
4442       }
4443       break;
4444
4445     case PROP_MIN_HEIGHT:
4446       {
4447         const ClutterLayoutInfo *info;
4448
4449         info = _clutter_actor_get_layout_info_or_defaults (actor);
4450         g_value_set_float (value, info->min_height);
4451       }
4452       break;
4453
4454     case PROP_NATURAL_WIDTH:
4455       {
4456         const ClutterLayoutInfo *info;
4457
4458         info = _clutter_actor_get_layout_info_or_defaults (actor);
4459         g_value_set_float (value, info->natural_width);
4460       }
4461       break;
4462
4463     case PROP_NATURAL_HEIGHT:
4464       {
4465         const ClutterLayoutInfo *info;
4466
4467         info = _clutter_actor_get_layout_info_or_defaults (actor);
4468         g_value_set_float (value, info->natural_height);
4469       }
4470       break;
4471
4472     case PROP_MIN_WIDTH_SET:
4473       g_value_set_boolean (value, priv->min_width_set);
4474       break;
4475
4476     case PROP_MIN_HEIGHT_SET:
4477       g_value_set_boolean (value, priv->min_height_set);
4478       break;
4479
4480     case PROP_NATURAL_WIDTH_SET:
4481       g_value_set_boolean (value, priv->natural_width_set);
4482       break;
4483
4484     case PROP_NATURAL_HEIGHT_SET:
4485       g_value_set_boolean (value, priv->natural_height_set);
4486       break;
4487
4488     case PROP_REQUEST_MODE:
4489       g_value_set_enum (value, priv->request_mode);
4490       break;
4491
4492     case PROP_ALLOCATION:
4493       g_value_set_boxed (value, &priv->allocation);
4494       break;
4495
4496     case PROP_DEPTH:
4497       g_value_set_float (value, clutter_actor_get_depth (actor));
4498       break;
4499
4500     case PROP_OPACITY:
4501       g_value_set_uint (value, priv->opacity);
4502       break;
4503
4504     case PROP_OFFSCREEN_REDIRECT:
4505       g_value_set_enum (value, priv->offscreen_redirect);
4506       break;
4507
4508     case PROP_NAME:
4509       g_value_set_string (value, priv->name);
4510       break;
4511
4512     case PROP_VISIBLE:
4513       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4514       break;
4515
4516     case PROP_MAPPED:
4517       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4518       break;
4519
4520     case PROP_REALIZED:
4521       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4522       break;
4523
4524     case PROP_HAS_CLIP:
4525       g_value_set_boolean (value, priv->has_clip);
4526       break;
4527
4528     case PROP_CLIP:
4529       {
4530         ClutterGeometry clip;
4531
4532         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4533         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4534         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4535         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4536
4537         g_value_set_boxed (value, &clip);
4538       }
4539       break;
4540
4541     case PROP_CLIP_TO_ALLOCATION:
4542       g_value_set_boolean (value, priv->clip_to_allocation);
4543       break;
4544
4545     case PROP_SCALE_X:
4546       {
4547         const ClutterTransformInfo *info;
4548
4549         info = _clutter_actor_get_transform_info_or_defaults (actor);
4550         g_value_set_double (value, info->scale_x);
4551       }
4552       break;
4553
4554     case PROP_SCALE_Y:
4555       {
4556         const ClutterTransformInfo *info;
4557
4558         info = _clutter_actor_get_transform_info_or_defaults (actor);
4559         g_value_set_double (value, info->scale_y);
4560       }
4561       break;
4562
4563     case PROP_SCALE_CENTER_X:
4564       {
4565         gfloat center;
4566
4567         clutter_actor_get_scale_center (actor, &center, NULL);
4568
4569         g_value_set_float (value, center);
4570       }
4571       break;
4572
4573     case PROP_SCALE_CENTER_Y:
4574       {
4575         gfloat center;
4576
4577         clutter_actor_get_scale_center (actor, NULL, &center);
4578
4579         g_value_set_float (value, center);
4580       }
4581       break;
4582
4583     case PROP_SCALE_GRAVITY:
4584       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4585       break;
4586
4587     case PROP_REACTIVE:
4588       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4589       break;
4590
4591     case PROP_ROTATION_ANGLE_X:
4592       {
4593         const ClutterTransformInfo *info;
4594
4595         info = _clutter_actor_get_transform_info_or_defaults (actor);
4596         g_value_set_double (value, info->rx_angle);
4597       }
4598       break;
4599
4600     case PROP_ROTATION_ANGLE_Y:
4601       {
4602         const ClutterTransformInfo *info;
4603
4604         info = _clutter_actor_get_transform_info_or_defaults (actor);
4605         g_value_set_double (value, info->ry_angle);
4606       }
4607       break;
4608
4609     case PROP_ROTATION_ANGLE_Z:
4610       {
4611         const ClutterTransformInfo *info;
4612
4613         info = _clutter_actor_get_transform_info_or_defaults (actor);
4614         g_value_set_double (value, info->rz_angle);
4615       }
4616       break;
4617
4618     case PROP_ROTATION_CENTER_X:
4619       {
4620         ClutterVertex center;
4621
4622         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4623                                     &center.x,
4624                                     &center.y,
4625                                     &center.z);
4626
4627         g_value_set_boxed (value, &center);
4628       }
4629       break;
4630
4631     case PROP_ROTATION_CENTER_Y:
4632       {
4633         ClutterVertex center;
4634
4635         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4636                                     &center.x,
4637                                     &center.y,
4638                                     &center.z);
4639
4640         g_value_set_boxed (value, &center);
4641       }
4642       break;
4643
4644     case PROP_ROTATION_CENTER_Z:
4645       {
4646         ClutterVertex center;
4647
4648         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4649                                     &center.x,
4650                                     &center.y,
4651                                     &center.z);
4652
4653         g_value_set_boxed (value, &center);
4654       }
4655       break;
4656
4657     case PROP_ROTATION_CENTER_Z_GRAVITY:
4658       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4659       break;
4660
4661     case PROP_ANCHOR_X:
4662       {
4663         const ClutterTransformInfo *info;
4664         gfloat anchor_x;
4665
4666         info = _clutter_actor_get_transform_info_or_defaults (actor);
4667         clutter_anchor_coord_get_units (actor, &info->anchor,
4668                                         &anchor_x,
4669                                         NULL,
4670                                         NULL);
4671         g_value_set_float (value, anchor_x);
4672       }
4673       break;
4674
4675     case PROP_ANCHOR_Y:
4676       {
4677         const ClutterTransformInfo *info;
4678         gfloat anchor_y;
4679
4680         info = _clutter_actor_get_transform_info_or_defaults (actor);
4681         clutter_anchor_coord_get_units (actor, &info->anchor,
4682                                         NULL,
4683                                         &anchor_y,
4684                                         NULL);
4685         g_value_set_float (value, anchor_y);
4686       }
4687       break;
4688
4689     case PROP_ANCHOR_GRAVITY:
4690       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4691       break;
4692
4693     case PROP_SHOW_ON_SET_PARENT:
4694       g_value_set_boolean (value, priv->show_on_set_parent);
4695       break;
4696
4697     case PROP_TEXT_DIRECTION:
4698       g_value_set_enum (value, priv->text_direction);
4699       break;
4700
4701     case PROP_HAS_POINTER:
4702       g_value_set_boolean (value, priv->has_pointer);
4703       break;
4704
4705     case PROP_LAYOUT_MANAGER:
4706       g_value_set_object (value, priv->layout_manager);
4707       break;
4708
4709     case PROP_X_ALIGN:
4710       {
4711         const ClutterLayoutInfo *info;
4712
4713         info = _clutter_actor_get_layout_info_or_defaults (actor);
4714         g_value_set_enum (value, info->x_align);
4715       }
4716       break;
4717
4718     case PROP_Y_ALIGN:
4719       {
4720         const ClutterLayoutInfo *info;
4721
4722         info = _clutter_actor_get_layout_info_or_defaults (actor);
4723         g_value_set_enum (value, info->y_align);
4724       }
4725       break;
4726
4727     case PROP_MARGIN_TOP:
4728       {
4729         const ClutterLayoutInfo *info;
4730
4731         info = _clutter_actor_get_layout_info_or_defaults (actor);
4732         g_value_set_float (value, info->margin.top);
4733       }
4734       break;
4735
4736     case PROP_MARGIN_BOTTOM:
4737       {
4738         const ClutterLayoutInfo *info;
4739
4740         info = _clutter_actor_get_layout_info_or_defaults (actor);
4741         g_value_set_float (value, info->margin.bottom);
4742       }
4743       break;
4744
4745     case PROP_MARGIN_LEFT:
4746       {
4747         const ClutterLayoutInfo *info;
4748
4749         info = _clutter_actor_get_layout_info_or_defaults (actor);
4750         g_value_set_float (value, info->margin.left);
4751       }
4752       break;
4753
4754     case PROP_MARGIN_RIGHT:
4755       {
4756         const ClutterLayoutInfo *info;
4757
4758         info = _clutter_actor_get_layout_info_or_defaults (actor);
4759         g_value_set_float (value, info->margin.right);
4760       }
4761       break;
4762
4763     case PROP_BACKGROUND_COLOR_SET:
4764       g_value_set_boolean (value, priv->bg_color_set);
4765       break;
4766
4767     case PROP_BACKGROUND_COLOR:
4768       g_value_set_boxed (value, &priv->bg_color);
4769       break;
4770
4771     case PROP_FIRST_CHILD:
4772       g_value_set_object (value, priv->first_child);
4773       break;
4774
4775     case PROP_LAST_CHILD:
4776       g_value_set_object (value, priv->last_child);
4777       break;
4778
4779     case PROP_CONTENT:
4780       g_value_set_object (value, priv->content);
4781       break;
4782
4783     case PROP_CONTENT_GRAVITY:
4784       g_value_set_enum (value, priv->content_gravity);
4785       break;
4786
4787     case PROP_CONTENT_BOX:
4788       {
4789         ClutterActorBox box = { 0, };
4790
4791         clutter_actor_get_content_box (actor, &box);
4792         g_value_set_boxed (value, &box);
4793       }
4794       break;
4795
4796     default:
4797       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4798       break;
4799     }
4800 }
4801
4802 static void
4803 clutter_actor_dispose (GObject *object)
4804 {
4805   ClutterActor *self = CLUTTER_ACTOR (object);
4806   ClutterActorPrivate *priv = self->priv;
4807
4808   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4809                 priv->id,
4810                 g_type_name (G_OBJECT_TYPE (self)),
4811                 object->ref_count);
4812
4813   g_signal_emit (self, actor_signals[DESTROY], 0);
4814
4815   /* avoid recursing when called from clutter_actor_destroy() */
4816   if (priv->parent != NULL)
4817     {
4818       ClutterActor *parent = priv->parent;
4819
4820       /* go through the Container implementation unless this
4821        * is an internal child and has been marked as such.
4822        *
4823        * removing the actor from its parent will reset the
4824        * realized and mapped states.
4825        */
4826       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4827         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4828       else
4829         clutter_actor_remove_child_internal (parent, self,
4830                                              REMOVE_CHILD_LEGACY_FLAGS);
4831     }
4832
4833   /* parent must be gone at this point */
4834   g_assert (priv->parent == NULL);
4835
4836   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4837     {
4838       /* can't be mapped or realized with no parent */
4839       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4840       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4841     }
4842
4843   g_clear_object (&priv->pango_context);
4844   g_clear_object (&priv->actions);
4845   g_clear_object (&priv->constraints);
4846   g_clear_object (&priv->effects);
4847   g_clear_object (&priv->flatten_effect);
4848
4849   if (priv->layout_manager != NULL)
4850     {
4851       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4852       g_clear_object (&priv->layout_manager);
4853     }
4854
4855   if (priv->content != NULL)
4856     {
4857       _clutter_content_detached (priv->content, self);
4858       g_clear_object (&priv->content);
4859     }
4860
4861   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4862 }
4863
4864 static void
4865 clutter_actor_finalize (GObject *object)
4866 {
4867   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4868
4869   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4870                 priv->name != NULL ? priv->name : "<none>",
4871                 priv->id,
4872                 g_type_name (G_OBJECT_TYPE (object)));
4873
4874   _clutter_context_release_id (priv->id);
4875
4876   g_free (priv->name);
4877
4878   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4879 }
4880
4881
4882 /**
4883  * clutter_actor_get_accessible:
4884  * @self: a #ClutterActor
4885  *
4886  * Returns the accessible object that describes the actor to an
4887  * assistive technology.
4888  *
4889  * If no class-specific #AtkObject implementation is available for the
4890  * actor instance in question, it will inherit an #AtkObject
4891  * implementation from the first ancestor class for which such an
4892  * implementation is defined.
4893  *
4894  * The documentation of the <ulink
4895  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4896  * library contains more information about accessible objects and
4897  * their uses.
4898  *
4899  * Returns: (transfer none): the #AtkObject associated with @actor
4900  */
4901 AtkObject *
4902 clutter_actor_get_accessible (ClutterActor *self)
4903 {
4904   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4905
4906   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4907 }
4908
4909 static AtkObject *
4910 clutter_actor_real_get_accessible (ClutterActor *actor)
4911 {
4912   return atk_gobject_accessible_for_object (G_OBJECT (actor));
4913 }
4914
4915 static AtkObject *
4916 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4917 {
4918   AtkObject *accessible;
4919
4920   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4921   if (accessible != NULL)
4922     g_object_ref (accessible);
4923
4924   return accessible;
4925 }
4926
4927 static void
4928 atk_implementor_iface_init (AtkImplementorIface *iface)
4929 {
4930   iface->ref_accessible = _clutter_actor_ref_accessible;
4931 }
4932
4933 static gboolean
4934 clutter_actor_update_default_paint_volume (ClutterActor       *self,
4935                                            ClutterPaintVolume *volume)
4936 {
4937   ClutterActorPrivate *priv = self->priv;
4938   gboolean res = FALSE;
4939
4940   /* we start from the allocation */
4941   clutter_paint_volume_set_width (volume,
4942                                   priv->allocation.x2 - priv->allocation.x1);
4943   clutter_paint_volume_set_height (volume,
4944                                    priv->allocation.y2 - priv->allocation.y1);
4945
4946   /* if the actor has a clip set then we have a pretty definite
4947    * size for the paint volume: the actor cannot possibly paint
4948    * outside the clip region.
4949    */
4950   if (priv->clip_to_allocation)
4951     {
4952       /* the allocation has already been set, so we just flip the
4953        * return value
4954        */
4955       res = TRUE;
4956     }
4957   else
4958     {
4959       ClutterActor *child;
4960
4961       if (priv->has_clip &&
4962           priv->clip.width >= 0 &&
4963           priv->clip.height >= 0)
4964         {
4965           ClutterVertex origin;
4966
4967           origin.x = priv->clip.x;
4968           origin.y = priv->clip.y;
4969           origin.z = 0;
4970
4971           clutter_paint_volume_set_origin (volume, &origin);
4972           clutter_paint_volume_set_width (volume, priv->clip.width);
4973           clutter_paint_volume_set_height (volume, priv->clip.height);
4974
4975           res = TRUE;
4976         }
4977
4978       /* if we don't have children we just bail out here... */
4979       if (priv->n_children == 0)
4980         return res;
4981
4982       /* ...but if we have children then we ask for their paint volume in
4983        * our coordinates. if any of our children replies that it doesn't
4984        * have a paint volume, we bail out
4985        */
4986       for (child = priv->first_child;
4987            child != NULL;
4988            child = child->priv->next_sibling)
4989         {
4990           const ClutterPaintVolume *child_volume;
4991
4992           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4993           if (child_volume == NULL)
4994             {
4995               res = FALSE;
4996               break;
4997             }
4998
4999           clutter_paint_volume_union (volume, child_volume);
5000           res = TRUE;
5001         }
5002     }
5003
5004   return res;
5005
5006 }
5007
5008 static gboolean
5009 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5010                                      ClutterPaintVolume *volume)
5011 {
5012   ClutterActorClass *klass;
5013   gboolean res;
5014
5015   klass = CLUTTER_ACTOR_GET_CLASS (self);
5016
5017   /* XXX - this thoroughly sucks, but we don't want to penalize users
5018    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5019    * redraw. This should go away in 2.0.
5020    */
5021   if (klass->paint == clutter_actor_real_paint &&
5022       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5023     {
5024       res = TRUE;
5025     }
5026   else
5027     {
5028       /* this is the default return value: we cannot know if a class
5029        * is going to paint outside its allocation, so we take the
5030        * conservative approach.
5031        */
5032       res = FALSE;
5033     }
5034
5035   if (clutter_actor_update_default_paint_volume (self, volume))
5036     return res;
5037
5038   return FALSE;
5039 }
5040
5041 /**
5042  * clutter_actor_get_default_paint_volume:
5043  * @self: a #ClutterActor
5044  *
5045  * Retrieves the default paint volume for @self.
5046  *
5047  * This function provides the same #ClutterPaintVolume that would be
5048  * computed by the default implementation inside #ClutterActor of the
5049  * #ClutterActorClass.get_paint_volume() virtual function.
5050  *
5051  * This function should only be used by #ClutterActor subclasses that
5052  * cannot chain up to the parent implementation when computing their
5053  * paint volume.
5054  *
5055  * Return value: (transfer none): a pointer to the default
5056  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5057  *   the actor could not compute a valid paint volume. The returned value
5058  *   is not guaranteed to be stable across multiple frames, so if you
5059  *   want to retain it, you will need to copy it using
5060  *   clutter_paint_volume_copy().
5061  *
5062  * Since: 1.10
5063  */
5064 const ClutterPaintVolume *
5065 clutter_actor_get_default_paint_volume (ClutterActor *self)
5066 {
5067   ClutterPaintVolume volume;
5068   ClutterPaintVolume *res;
5069
5070   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5071
5072   res = NULL;
5073   _clutter_paint_volume_init_static (&volume, self);
5074   if (clutter_actor_update_default_paint_volume (self, &volume))
5075     {
5076       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5077
5078       if (stage != NULL)
5079         {
5080           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5081           _clutter_paint_volume_copy_static (&volume, res);
5082         }
5083     }
5084
5085   clutter_paint_volume_free (&volume);
5086
5087   return res;
5088 }
5089
5090 static gboolean
5091 clutter_actor_real_has_overlaps (ClutterActor *self)
5092 {
5093   /* By default we'll assume that all actors need an offscreen redirect to get
5094    * the correct opacity. Actors such as ClutterTexture that would never need
5095    * an offscreen redirect can override this to return FALSE. */
5096   return TRUE;
5097 }
5098
5099 static void
5100 clutter_actor_real_destroy (ClutterActor *actor)
5101 {
5102   ClutterActorIter iter;
5103
5104   clutter_actor_iter_init (&iter, actor);
5105   while (clutter_actor_iter_next (&iter, NULL))
5106     clutter_actor_iter_destroy (&iter);
5107 }
5108
5109 static GObject *
5110 clutter_actor_constructor (GType gtype,
5111                            guint n_props,
5112                            GObjectConstructParam *props)
5113 {
5114   GObjectClass *gobject_class;
5115   ClutterActor *self;
5116   GObject *retval;
5117
5118   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5119   retval = gobject_class->constructor (gtype, n_props, props);
5120   self = CLUTTER_ACTOR (retval);
5121
5122   if (self->priv->layout_manager == NULL)
5123     {
5124       ClutterLayoutManager *default_layout;
5125
5126       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5127
5128       default_layout = clutter_fixed_layout_new ();
5129       clutter_actor_set_layout_manager (self, default_layout);
5130     }
5131
5132   return retval;
5133 }
5134
5135 static void
5136 clutter_actor_class_init (ClutterActorClass *klass)
5137 {
5138   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5139
5140   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5141   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5142   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5143   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5144
5145   object_class->constructor = clutter_actor_constructor;
5146   object_class->set_property = clutter_actor_set_property;
5147   object_class->get_property = clutter_actor_get_property;
5148   object_class->dispose = clutter_actor_dispose;
5149   object_class->finalize = clutter_actor_finalize;
5150
5151   klass->show = clutter_actor_real_show;
5152   klass->show_all = clutter_actor_show;
5153   klass->hide = clutter_actor_real_hide;
5154   klass->hide_all = clutter_actor_hide;
5155   klass->map = clutter_actor_real_map;
5156   klass->unmap = clutter_actor_real_unmap;
5157   klass->unrealize = clutter_actor_real_unrealize;
5158   klass->pick = clutter_actor_real_pick;
5159   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5160   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5161   klass->allocate = clutter_actor_real_allocate;
5162   klass->queue_redraw = clutter_actor_real_queue_redraw;
5163   klass->queue_relayout = clutter_actor_real_queue_relayout;
5164   klass->apply_transform = clutter_actor_real_apply_transform;
5165   klass->get_accessible = clutter_actor_real_get_accessible;
5166   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5167   klass->has_overlaps = clutter_actor_real_has_overlaps;
5168   klass->paint = clutter_actor_real_paint;
5169   klass->destroy = clutter_actor_real_destroy;
5170
5171   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5172
5173   /**
5174    * ClutterActor:x:
5175    *
5176    * X coordinate of the actor in pixels. If written, forces a fixed
5177    * position for the actor. If read, returns the fixed position if any,
5178    * otherwise the allocation if available, otherwise 0.
5179    *
5180    * The #ClutterActor:x property is animatable.
5181    */
5182   obj_props[PROP_X] =
5183     g_param_spec_float ("x",
5184                         P_("X coordinate"),
5185                         P_("X coordinate of the actor"),
5186                         -G_MAXFLOAT, G_MAXFLOAT,
5187                         0.0,
5188                         G_PARAM_READWRITE |
5189                         G_PARAM_STATIC_STRINGS |
5190                         CLUTTER_PARAM_ANIMATABLE);
5191
5192   /**
5193    * ClutterActor:y:
5194    *
5195    * Y coordinate of the actor in pixels. If written, forces a fixed
5196    * position for the actor.  If read, returns the fixed position if
5197    * any, otherwise the allocation if available, otherwise 0.
5198    *
5199    * The #ClutterActor:y property is animatable.
5200    */
5201   obj_props[PROP_Y] =
5202     g_param_spec_float ("y",
5203                         P_("Y coordinate"),
5204                         P_("Y coordinate of the actor"),
5205                         -G_MAXFLOAT, G_MAXFLOAT,
5206                         0.0,
5207                         G_PARAM_READWRITE |
5208                         G_PARAM_STATIC_STRINGS |
5209                         CLUTTER_PARAM_ANIMATABLE);
5210
5211   /**
5212    * ClutterActor:width:
5213    *
5214    * Width of the actor (in pixels). If written, forces the minimum and
5215    * natural size request of the actor to the given width. If read, returns
5216    * the allocated width if available, otherwise the width request.
5217    *
5218    * The #ClutterActor:width property is animatable.
5219    */
5220   obj_props[PROP_WIDTH] =
5221     g_param_spec_float ("width",
5222                         P_("Width"),
5223                         P_("Width of the actor"),
5224                         0.0, G_MAXFLOAT,
5225                         0.0,
5226                         G_PARAM_READWRITE |
5227                         G_PARAM_STATIC_STRINGS |
5228                         CLUTTER_PARAM_ANIMATABLE);
5229
5230   /**
5231    * ClutterActor:height:
5232    *
5233    * Height of the actor (in pixels).  If written, forces the minimum and
5234    * natural size request of the actor to the given height. If read, returns
5235    * the allocated height if available, otherwise the height request.
5236    *
5237    * The #ClutterActor:height property is animatable.
5238    */
5239   obj_props[PROP_HEIGHT] =
5240     g_param_spec_float ("height",
5241                         P_("Height"),
5242                         P_("Height of the actor"),
5243                         0.0, G_MAXFLOAT,
5244                         0.0,
5245                         G_PARAM_READWRITE |
5246                         G_PARAM_STATIC_STRINGS |
5247                         CLUTTER_PARAM_ANIMATABLE);
5248
5249   /**
5250    * ClutterActor:fixed-x:
5251    *
5252    * The fixed X position of the actor in pixels.
5253    *
5254    * Writing this property sets #ClutterActor:fixed-position-set
5255    * property as well, as a side effect
5256    *
5257    * Since: 0.8
5258    */
5259   obj_props[PROP_FIXED_X] =
5260     g_param_spec_float ("fixed-x",
5261                         P_("Fixed X"),
5262                         P_("Forced X position of the actor"),
5263                         -G_MAXFLOAT, G_MAXFLOAT,
5264                         0.0,
5265                         CLUTTER_PARAM_READWRITE);
5266
5267   /**
5268    * ClutterActor:fixed-y:
5269    *
5270    * The fixed Y position of the actor in pixels.
5271    *
5272    * Writing this property sets the #ClutterActor:fixed-position-set
5273    * property as well, as a side effect
5274    *
5275    * Since: 0.8
5276    */
5277   obj_props[PROP_FIXED_Y] =
5278     g_param_spec_float ("fixed-y",
5279                         P_("Fixed Y"),
5280                         P_("Forced Y position of the actor"),
5281                         -G_MAXFLOAT, G_MAXFLOAT,
5282                         0,
5283                         CLUTTER_PARAM_READWRITE);
5284
5285   /**
5286    * ClutterActor:fixed-position-set:
5287    *
5288    * This flag controls whether the #ClutterActor:fixed-x and
5289    * #ClutterActor:fixed-y properties are used
5290    *
5291    * Since: 0.8
5292    */
5293   obj_props[PROP_FIXED_POSITION_SET] =
5294     g_param_spec_boolean ("fixed-position-set",
5295                           P_("Fixed position set"),
5296                           P_("Whether to use fixed positioning for the actor"),
5297                           FALSE,
5298                           CLUTTER_PARAM_READWRITE);
5299
5300   /**
5301    * ClutterActor:min-width:
5302    *
5303    * A forced minimum width request for the actor, in pixels
5304    *
5305    * Writing this property sets the #ClutterActor:min-width-set property
5306    * as well, as a side effect.
5307    *
5308    *This property overrides the usual width request of the actor.
5309    *
5310    * Since: 0.8
5311    */
5312   obj_props[PROP_MIN_WIDTH] =
5313     g_param_spec_float ("min-width",
5314                         P_("Min Width"),
5315                         P_("Forced minimum width request for the actor"),
5316                         0.0, G_MAXFLOAT,
5317                         0.0,
5318                         CLUTTER_PARAM_READWRITE);
5319
5320   /**
5321    * ClutterActor:min-height:
5322    *
5323    * A forced minimum height request for the actor, in pixels
5324    *
5325    * Writing this property sets the #ClutterActor:min-height-set property
5326    * as well, as a side effect. This property overrides the usual height
5327    * request of the actor.
5328    *
5329    * Since: 0.8
5330    */
5331   obj_props[PROP_MIN_HEIGHT] =
5332     g_param_spec_float ("min-height",
5333                         P_("Min Height"),
5334                         P_("Forced minimum height request for the actor"),
5335                         0.0, G_MAXFLOAT,
5336                         0.0,
5337                         CLUTTER_PARAM_READWRITE);
5338
5339   /**
5340    * ClutterActor:natural-width:
5341    *
5342    * A forced natural width request for the actor, in pixels
5343    *
5344    * Writing this property sets the #ClutterActor:natural-width-set
5345    * property as well, as a side effect. This property overrides the
5346    * usual width request of the actor
5347    *
5348    * Since: 0.8
5349    */
5350   obj_props[PROP_NATURAL_WIDTH] =
5351     g_param_spec_float ("natural-width",
5352                         P_("Natural Width"),
5353                         P_("Forced natural width request for the actor"),
5354                         0.0, G_MAXFLOAT,
5355                         0.0,
5356                         CLUTTER_PARAM_READWRITE);
5357
5358   /**
5359    * ClutterActor:natural-height:
5360    *
5361    * A forced natural height request for the actor, in pixels
5362    *
5363    * Writing this property sets the #ClutterActor:natural-height-set
5364    * property as well, as a side effect. This property overrides the
5365    * usual height request of the actor
5366    *
5367    * Since: 0.8
5368    */
5369   obj_props[PROP_NATURAL_HEIGHT] =
5370     g_param_spec_float ("natural-height",
5371                         P_("Natural Height"),
5372                         P_("Forced natural height request for the actor"),
5373                         0.0, G_MAXFLOAT,
5374                         0.0,
5375                         CLUTTER_PARAM_READWRITE);
5376
5377   /**
5378    * ClutterActor:min-width-set:
5379    *
5380    * This flag controls whether the #ClutterActor:min-width property
5381    * is used
5382    *
5383    * Since: 0.8
5384    */
5385   obj_props[PROP_MIN_WIDTH_SET] =
5386     g_param_spec_boolean ("min-width-set",
5387                           P_("Minimum width set"),
5388                           P_("Whether to use the min-width property"),
5389                           FALSE,
5390                           CLUTTER_PARAM_READWRITE);
5391
5392   /**
5393    * ClutterActor:min-height-set:
5394    *
5395    * This flag controls whether the #ClutterActor:min-height property
5396    * is used
5397    *
5398    * Since: 0.8
5399    */
5400   obj_props[PROP_MIN_HEIGHT_SET] =
5401     g_param_spec_boolean ("min-height-set",
5402                           P_("Minimum height set"),
5403                           P_("Whether to use the min-height property"),
5404                           FALSE,
5405                           CLUTTER_PARAM_READWRITE);
5406
5407   /**
5408    * ClutterActor:natural-width-set:
5409    *
5410    * This flag controls whether the #ClutterActor:natural-width property
5411    * is used
5412    *
5413    * Since: 0.8
5414    */
5415   obj_props[PROP_NATURAL_WIDTH_SET] =
5416     g_param_spec_boolean ("natural-width-set",
5417                           P_("Natural width set"),
5418                           P_("Whether to use the natural-width property"),
5419                           FALSE,
5420                           CLUTTER_PARAM_READWRITE);
5421
5422   /**
5423    * ClutterActor:natural-height-set:
5424    *
5425    * This flag controls whether the #ClutterActor:natural-height property
5426    * is used
5427    *
5428    * Since: 0.8
5429    */
5430   obj_props[PROP_NATURAL_HEIGHT_SET] =
5431     g_param_spec_boolean ("natural-height-set",
5432                           P_("Natural height set"),
5433                           P_("Whether to use the natural-height property"),
5434                           FALSE,
5435                           CLUTTER_PARAM_READWRITE);
5436
5437   /**
5438    * ClutterActor:allocation:
5439    *
5440    * The allocation for the actor, in pixels
5441    *
5442    * This is property is read-only, but you might monitor it to know when an
5443    * actor moves or resizes
5444    *
5445    * Since: 0.8
5446    */
5447   obj_props[PROP_ALLOCATION] =
5448     g_param_spec_boxed ("allocation",
5449                         P_("Allocation"),
5450                         P_("The actor's allocation"),
5451                         CLUTTER_TYPE_ACTOR_BOX,
5452                         CLUTTER_PARAM_READABLE);
5453
5454   /**
5455    * ClutterActor:request-mode:
5456    *
5457    * Request mode for the #ClutterActor. The request mode determines the
5458    * type of geometry management used by the actor, either height for width
5459    * (the default) or width for height.
5460    *
5461    * For actors implementing height for width, the parent container should get
5462    * the preferred width first, and then the preferred height for that width.
5463    *
5464    * For actors implementing width for height, the parent container should get
5465    * the preferred height first, and then the preferred width for that height.
5466    *
5467    * For instance:
5468    *
5469    * |[
5470    *   ClutterRequestMode mode;
5471    *   gfloat natural_width, min_width;
5472    *   gfloat natural_height, min_height;
5473    *
5474    *   mode = clutter_actor_get_request_mode (child);
5475    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5476    *     {
5477    *       clutter_actor_get_preferred_width (child, -1,
5478    *                                          &amp;min_width,
5479    *                                          &amp;natural_width);
5480    *       clutter_actor_get_preferred_height (child, natural_width,
5481    *                                           &amp;min_height,
5482    *                                           &amp;natural_height);
5483    *     }
5484    *   else
5485    *     {
5486    *       clutter_actor_get_preferred_height (child, -1,
5487    *                                           &amp;min_height,
5488    *                                           &amp;natural_height);
5489    *       clutter_actor_get_preferred_width (child, natural_height,
5490    *                                          &amp;min_width,
5491    *                                          &amp;natural_width);
5492    *     }
5493    * ]|
5494    *
5495    * will retrieve the minimum and natural width and height depending on the
5496    * preferred request mode of the #ClutterActor "child".
5497    *
5498    * The clutter_actor_get_preferred_size() function will implement this
5499    * check for you.
5500    *
5501    * Since: 0.8
5502    */
5503   obj_props[PROP_REQUEST_MODE] =
5504     g_param_spec_enum ("request-mode",
5505                        P_("Request Mode"),
5506                        P_("The actor's request mode"),
5507                        CLUTTER_TYPE_REQUEST_MODE,
5508                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5509                        CLUTTER_PARAM_READWRITE);
5510
5511   /**
5512    * ClutterActor:depth:
5513    *
5514    * The position of the actor on the Z axis.
5515    *
5516    * The #ClutterActor:depth property is relative to the parent's
5517    * modelview matrix.
5518    *
5519    * The #ClutterActor:depth property is animatable.
5520    *
5521    * Since: 0.6
5522    */
5523   obj_props[PROP_DEPTH] =
5524     g_param_spec_float ("depth",
5525                         P_("Depth"),
5526                         P_("Position on the Z axis"),
5527                         -G_MAXFLOAT, G_MAXFLOAT,
5528                         0.0,
5529                         G_PARAM_READWRITE |
5530                         G_PARAM_STATIC_STRINGS |
5531                         CLUTTER_PARAM_ANIMATABLE);
5532
5533   /**
5534    * ClutterActor:opacity:
5535    *
5536    * Opacity of an actor, between 0 (fully transparent) and
5537    * 255 (fully opaque)
5538    *
5539    * The #ClutterActor:opacity property is animatable.
5540    */
5541   obj_props[PROP_OPACITY] =
5542     g_param_spec_uint ("opacity",
5543                        P_("Opacity"),
5544                        P_("Opacity of an actor"),
5545                        0, 255,
5546                        255,
5547                        G_PARAM_READWRITE |
5548                        G_PARAM_STATIC_STRINGS |
5549                        CLUTTER_PARAM_ANIMATABLE);
5550
5551   /**
5552    * ClutterActor:offscreen-redirect:
5553    *
5554    * Determines the conditions in which the actor will be redirected
5555    * to an offscreen framebuffer while being painted. For example this
5556    * can be used to cache an actor in a framebuffer or for improved
5557    * handling of transparent actors. See
5558    * clutter_actor_set_offscreen_redirect() for details.
5559    *
5560    * Since: 1.8
5561    */
5562   obj_props[PROP_OFFSCREEN_REDIRECT] =
5563     g_param_spec_flags ("offscreen-redirect",
5564                         P_("Offscreen redirect"),
5565                         P_("Flags controlling when to flatten the actor into a single image"),
5566                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5567                         0,
5568                         CLUTTER_PARAM_READWRITE);
5569
5570   /**
5571    * ClutterActor:visible:
5572    *
5573    * Whether the actor is set to be visible or not
5574    *
5575    * See also #ClutterActor:mapped
5576    */
5577   obj_props[PROP_VISIBLE] =
5578     g_param_spec_boolean ("visible",
5579                           P_("Visible"),
5580                           P_("Whether the actor is visible or not"),
5581                           FALSE,
5582                           CLUTTER_PARAM_READWRITE);
5583
5584   /**
5585    * ClutterActor:mapped:
5586    *
5587    * Whether the actor is mapped (will be painted when the stage
5588    * to which it belongs is mapped)
5589    *
5590    * Since: 1.0
5591    */
5592   obj_props[PROP_MAPPED] =
5593     g_param_spec_boolean ("mapped",
5594                           P_("Mapped"),
5595                           P_("Whether the actor will be painted"),
5596                           FALSE,
5597                           CLUTTER_PARAM_READABLE);
5598
5599   /**
5600    * ClutterActor:realized:
5601    *
5602    * Whether the actor has been realized
5603    *
5604    * Since: 1.0
5605    */
5606   obj_props[PROP_REALIZED] =
5607     g_param_spec_boolean ("realized",
5608                           P_("Realized"),
5609                           P_("Whether the actor has been realized"),
5610                           FALSE,
5611                           CLUTTER_PARAM_READABLE);
5612
5613   /**
5614    * ClutterActor:reactive:
5615    *
5616    * Whether the actor is reactive to events or not
5617    *
5618    * Only reactive actors will emit event-related signals
5619    *
5620    * Since: 0.6
5621    */
5622   obj_props[PROP_REACTIVE] =
5623     g_param_spec_boolean ("reactive",
5624                           P_("Reactive"),
5625                           P_("Whether the actor is reactive to events"),
5626                           FALSE,
5627                           CLUTTER_PARAM_READWRITE);
5628
5629   /**
5630    * ClutterActor:has-clip:
5631    *
5632    * Whether the actor has the #ClutterActor:clip property set or not
5633    */
5634   obj_props[PROP_HAS_CLIP] =
5635     g_param_spec_boolean ("has-clip",
5636                           P_("Has Clip"),
5637                           P_("Whether the actor has a clip set"),
5638                           FALSE,
5639                           CLUTTER_PARAM_READABLE);
5640
5641   /**
5642    * ClutterActor:clip:
5643    *
5644    * The clip region for the actor, in actor-relative coordinates
5645    *
5646    * Every part of the actor outside the clip region will not be
5647    * painted
5648    */
5649   obj_props[PROP_CLIP] =
5650     g_param_spec_boxed ("clip",
5651                         P_("Clip"),
5652                         P_("The clip region for the actor"),
5653                         CLUTTER_TYPE_GEOMETRY,
5654                         CLUTTER_PARAM_READWRITE);
5655
5656   /**
5657    * ClutterActor:name:
5658    *
5659    * The name of the actor
5660    *
5661    * Since: 0.2
5662    */
5663   obj_props[PROP_NAME] =
5664     g_param_spec_string ("name",
5665                          P_("Name"),
5666                          P_("Name of the actor"),
5667                          NULL,
5668                          CLUTTER_PARAM_READWRITE);
5669
5670   /**
5671    * ClutterActor:scale-x:
5672    *
5673    * The horizontal scale of the actor.
5674    *
5675    * The #ClutterActor:scale-x property is animatable.
5676    *
5677    * Since: 0.6
5678    */
5679   obj_props[PROP_SCALE_X] =
5680     g_param_spec_double ("scale-x",
5681                          P_("Scale X"),
5682                          P_("Scale factor on the X axis"),
5683                          0.0, G_MAXDOUBLE,
5684                          1.0,
5685                          G_PARAM_READWRITE |
5686                          G_PARAM_STATIC_STRINGS |
5687                          CLUTTER_PARAM_ANIMATABLE);
5688
5689   /**
5690    * ClutterActor:scale-y:
5691    *
5692    * The vertical scale of the actor.
5693    *
5694    * The #ClutterActor:scale-y property is animatable.
5695    *
5696    * Since: 0.6
5697    */
5698   obj_props[PROP_SCALE_Y] =
5699     g_param_spec_double ("scale-y",
5700                          P_("Scale Y"),
5701                          P_("Scale factor on the Y axis"),
5702                          0.0, G_MAXDOUBLE,
5703                          1.0,
5704                          G_PARAM_READWRITE |
5705                          G_PARAM_STATIC_STRINGS |
5706                          CLUTTER_PARAM_ANIMATABLE);
5707
5708   /**
5709    * ClutterActor:scale-center-x:
5710    *
5711    * The horizontal center point for scaling
5712    *
5713    * Since: 1.0
5714    */
5715   obj_props[PROP_SCALE_CENTER_X] =
5716     g_param_spec_float ("scale-center-x",
5717                         P_("Scale Center X"),
5718                         P_("Horizontal scale center"),
5719                         -G_MAXFLOAT, G_MAXFLOAT,
5720                         0.0,
5721                         CLUTTER_PARAM_READWRITE);
5722
5723   /**
5724    * ClutterActor:scale-center-y:
5725    *
5726    * The vertical center point for scaling
5727    *
5728    * Since: 1.0
5729    */
5730   obj_props[PROP_SCALE_CENTER_Y] =
5731     g_param_spec_float ("scale-center-y",
5732                         P_("Scale Center Y"),
5733                         P_("Vertical scale center"),
5734                         -G_MAXFLOAT, G_MAXFLOAT,
5735                         0.0,
5736                         CLUTTER_PARAM_READWRITE);
5737
5738   /**
5739    * ClutterActor:scale-gravity:
5740    *
5741    * The center point for scaling expressed as a #ClutterGravity
5742    *
5743    * Since: 1.0
5744    */
5745   obj_props[PROP_SCALE_GRAVITY] =
5746     g_param_spec_enum ("scale-gravity",
5747                        P_("Scale Gravity"),
5748                        P_("The center of scaling"),
5749                        CLUTTER_TYPE_GRAVITY,
5750                        CLUTTER_GRAVITY_NONE,
5751                        CLUTTER_PARAM_READWRITE);
5752
5753   /**
5754    * ClutterActor:rotation-angle-x:
5755    *
5756    * The rotation angle on the X axis.
5757    *
5758    * The #ClutterActor:rotation-angle-x property is animatable.
5759    *
5760    * Since: 0.6
5761    */
5762   obj_props[PROP_ROTATION_ANGLE_X] =
5763     g_param_spec_double ("rotation-angle-x",
5764                          P_("Rotation Angle X"),
5765                          P_("The rotation angle on the X axis"),
5766                          -G_MAXDOUBLE, G_MAXDOUBLE,
5767                          0.0,
5768                          G_PARAM_READWRITE |
5769                          G_PARAM_STATIC_STRINGS |
5770                          CLUTTER_PARAM_ANIMATABLE);
5771
5772   /**
5773    * ClutterActor:rotation-angle-y:
5774    *
5775    * The rotation angle on the Y axis
5776    *
5777    * The #ClutterActor:rotation-angle-y property is animatable.
5778    *
5779    * Since: 0.6
5780    */
5781   obj_props[PROP_ROTATION_ANGLE_Y] =
5782     g_param_spec_double ("rotation-angle-y",
5783                          P_("Rotation Angle Y"),
5784                          P_("The rotation angle on the Y axis"),
5785                          -G_MAXDOUBLE, G_MAXDOUBLE,
5786                          0.0,
5787                          G_PARAM_READWRITE |
5788                          G_PARAM_STATIC_STRINGS |
5789                          CLUTTER_PARAM_ANIMATABLE);
5790
5791   /**
5792    * ClutterActor:rotation-angle-z:
5793    *
5794    * The rotation angle on the Z axis
5795    *
5796    * The #ClutterActor:rotation-angle-z property is animatable.
5797    *
5798    * Since: 0.6
5799    */
5800   obj_props[PROP_ROTATION_ANGLE_Z] =
5801     g_param_spec_double ("rotation-angle-z",
5802                          P_("Rotation Angle Z"),
5803                          P_("The rotation angle on the Z axis"),
5804                          -G_MAXDOUBLE, G_MAXDOUBLE,
5805                          0.0,
5806                          G_PARAM_READWRITE |
5807                          G_PARAM_STATIC_STRINGS |
5808                          CLUTTER_PARAM_ANIMATABLE);
5809
5810   /**
5811    * ClutterActor:rotation-center-x:
5812    *
5813    * The rotation center on the X axis.
5814    *
5815    * Since: 0.6
5816    */
5817   obj_props[PROP_ROTATION_CENTER_X] =
5818     g_param_spec_boxed ("rotation-center-x",
5819                         P_("Rotation Center X"),
5820                         P_("The rotation center on the X axis"),
5821                         CLUTTER_TYPE_VERTEX,
5822                         CLUTTER_PARAM_READWRITE);
5823
5824   /**
5825    * ClutterActor:rotation-center-y:
5826    *
5827    * The rotation center on the Y axis.
5828    *
5829    * Since: 0.6
5830    */
5831   obj_props[PROP_ROTATION_CENTER_Y] =
5832     g_param_spec_boxed ("rotation-center-y",
5833                         P_("Rotation Center Y"),
5834                         P_("The rotation center on the Y axis"),
5835                         CLUTTER_TYPE_VERTEX,
5836                         CLUTTER_PARAM_READWRITE);
5837
5838   /**
5839    * ClutterActor:rotation-center-z:
5840    *
5841    * The rotation center on the Z axis.
5842    *
5843    * Since: 0.6
5844    */
5845   obj_props[PROP_ROTATION_CENTER_Z] =
5846     g_param_spec_boxed ("rotation-center-z",
5847                         P_("Rotation Center Z"),
5848                         P_("The rotation center on the Z axis"),
5849                         CLUTTER_TYPE_VERTEX,
5850                         CLUTTER_PARAM_READWRITE);
5851
5852   /**
5853    * ClutterActor:rotation-center-z-gravity:
5854    *
5855    * The rotation center on the Z axis expressed as a #ClutterGravity.
5856    *
5857    * Since: 1.0
5858    */
5859   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5860     g_param_spec_enum ("rotation-center-z-gravity",
5861                        P_("Rotation Center Z Gravity"),
5862                        P_("Center point for rotation around the Z axis"),
5863                        CLUTTER_TYPE_GRAVITY,
5864                        CLUTTER_GRAVITY_NONE,
5865                        CLUTTER_PARAM_READWRITE);
5866
5867   /**
5868    * ClutterActor:anchor-x:
5869    *
5870    * The X coordinate of an actor's anchor point, relative to
5871    * the actor coordinate space, in pixels
5872    *
5873    * Since: 0.8
5874    */
5875   obj_props[PROP_ANCHOR_X] =
5876     g_param_spec_float ("anchor-x",
5877                         P_("Anchor X"),
5878                         P_("X coordinate of the anchor point"),
5879                         -G_MAXFLOAT, G_MAXFLOAT,
5880                         0,
5881                         CLUTTER_PARAM_READWRITE);
5882
5883   /**
5884    * ClutterActor:anchor-y:
5885    *
5886    * The Y coordinate of an actor's anchor point, relative to
5887    * the actor coordinate space, in pixels
5888    *
5889    * Since: 0.8
5890    */
5891   obj_props[PROP_ANCHOR_Y] =
5892     g_param_spec_float ("anchor-y",
5893                         P_("Anchor Y"),
5894                         P_("Y coordinate of the anchor point"),
5895                         -G_MAXFLOAT, G_MAXFLOAT,
5896                         0,
5897                         CLUTTER_PARAM_READWRITE);
5898
5899   /**
5900    * ClutterActor:anchor-gravity:
5901    *
5902    * The anchor point expressed as a #ClutterGravity
5903    *
5904    * Since: 1.0
5905    */
5906   obj_props[PROP_ANCHOR_GRAVITY] =
5907     g_param_spec_enum ("anchor-gravity",
5908                        P_("Anchor Gravity"),
5909                        P_("The anchor point as a ClutterGravity"),
5910                        CLUTTER_TYPE_GRAVITY,
5911                        CLUTTER_GRAVITY_NONE,
5912                        CLUTTER_PARAM_READWRITE);
5913
5914   /**
5915    * ClutterActor:show-on-set-parent:
5916    *
5917    * If %TRUE, the actor is automatically shown when parented.
5918    *
5919    * Calling clutter_actor_hide() on an actor which has not been
5920    * parented will set this property to %FALSE as a side effect.
5921    *
5922    * Since: 0.8
5923    */
5924   obj_props[PROP_SHOW_ON_SET_PARENT] =
5925     g_param_spec_boolean ("show-on-set-parent",
5926                           P_("Show on set parent"),
5927                           P_("Whether the actor is shown when parented"),
5928                           TRUE,
5929                           CLUTTER_PARAM_READWRITE);
5930
5931   /**
5932    * ClutterActor:clip-to-allocation:
5933    *
5934    * Whether the clip region should track the allocated area
5935    * of the actor.
5936    *
5937    * This property is ignored if a clip area has been explicitly
5938    * set using clutter_actor_set_clip().
5939    *
5940    * Since: 1.0
5941    */
5942   obj_props[PROP_CLIP_TO_ALLOCATION] =
5943     g_param_spec_boolean ("clip-to-allocation",
5944                           P_("Clip to Allocation"),
5945                           P_("Sets the clip region to track the actor's allocation"),
5946                           FALSE,
5947                           CLUTTER_PARAM_READWRITE);
5948
5949   /**
5950    * ClutterActor:text-direction:
5951    *
5952    * The direction of the text inside a #ClutterActor.
5953    *
5954    * Since: 1.0
5955    */
5956   obj_props[PROP_TEXT_DIRECTION] =
5957     g_param_spec_enum ("text-direction",
5958                        P_("Text Direction"),
5959                        P_("Direction of the text"),
5960                        CLUTTER_TYPE_TEXT_DIRECTION,
5961                        CLUTTER_TEXT_DIRECTION_LTR,
5962                        CLUTTER_PARAM_READWRITE);
5963
5964   /**
5965    * ClutterActor:has-pointer:
5966    *
5967    * Whether the actor contains the pointer of a #ClutterInputDevice
5968    * or not.
5969    *
5970    * Since: 1.2
5971    */
5972   obj_props[PROP_HAS_POINTER] =
5973     g_param_spec_boolean ("has-pointer",
5974                           P_("Has Pointer"),
5975                           P_("Whether the actor contains the pointer of an input device"),
5976                           FALSE,
5977                           CLUTTER_PARAM_READABLE);
5978
5979   /**
5980    * ClutterActor:actions:
5981    *
5982    * Adds a #ClutterAction to the actor
5983    *
5984    * Since: 1.4
5985    */
5986   obj_props[PROP_ACTIONS] =
5987     g_param_spec_object ("actions",
5988                          P_("Actions"),
5989                          P_("Adds an action to the actor"),
5990                          CLUTTER_TYPE_ACTION,
5991                          CLUTTER_PARAM_WRITABLE);
5992
5993   /**
5994    * ClutterActor:constraints:
5995    *
5996    * Adds a #ClutterConstraint to the actor
5997    *
5998    * Since: 1.4
5999    */
6000   obj_props[PROP_CONSTRAINTS] =
6001     g_param_spec_object ("constraints",
6002                          P_("Constraints"),
6003                          P_("Adds a constraint to the actor"),
6004                          CLUTTER_TYPE_CONSTRAINT,
6005                          CLUTTER_PARAM_WRITABLE);
6006
6007   /**
6008    * ClutterActor:effect:
6009    *
6010    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6011    *
6012    * Since: 1.4
6013    */
6014   obj_props[PROP_EFFECT] =
6015     g_param_spec_object ("effect",
6016                          P_("Effect"),
6017                          P_("Add an effect to be applied on the actor"),
6018                          CLUTTER_TYPE_EFFECT,
6019                          CLUTTER_PARAM_WRITABLE);
6020
6021   /**
6022    * ClutterActor:layout-manager:
6023    *
6024    * A delegate object for controlling the layout of the children of
6025    * an actor.
6026    *
6027    * Since: 1.10
6028    */
6029   obj_props[PROP_LAYOUT_MANAGER] =
6030     g_param_spec_object ("layout-manager",
6031                          P_("Layout Manager"),
6032                          P_("The object controlling the layout of an actor's children"),
6033                          CLUTTER_TYPE_LAYOUT_MANAGER,
6034                          CLUTTER_PARAM_READWRITE);
6035
6036
6037   /**
6038    * ClutterActor:x-align:
6039    *
6040    * The alignment of an actor on the X axis, if the actor has been given
6041    * extra space for its allocation.
6042    *
6043    * Since: 1.10
6044    */
6045   obj_props[PROP_X_ALIGN] =
6046     g_param_spec_enum ("x-align",
6047                        P_("X Alignment"),
6048                        P_("The alignment of the actor on the X axis within its allocation"),
6049                        CLUTTER_TYPE_ACTOR_ALIGN,
6050                        CLUTTER_ACTOR_ALIGN_FILL,
6051                        CLUTTER_PARAM_READWRITE);
6052
6053   /**
6054    * ClutterActor:y-align:
6055    *
6056    * The alignment of an actor on the Y axis, if the actor has been given
6057    * extra space for its allocation.
6058    *
6059    * Since: 1.10
6060    */
6061   obj_props[PROP_Y_ALIGN] =
6062     g_param_spec_enum ("y-align",
6063                        P_("Y Alignment"),
6064                        P_("The alignment of the actor on the Y axis within its allocation"),
6065                        CLUTTER_TYPE_ACTOR_ALIGN,
6066                        CLUTTER_ACTOR_ALIGN_FILL,
6067                        CLUTTER_PARAM_READWRITE);
6068
6069   /**
6070    * ClutterActor:margin-top:
6071    *
6072    * The margin (in pixels) from the top of the actor.
6073    *
6074    * This property adds a margin to the actor's preferred size; the margin
6075    * will be automatically taken into account when allocating the actor.
6076    *
6077    * Since: 1.10
6078    */
6079   obj_props[PROP_MARGIN_TOP] =
6080     g_param_spec_float ("margin-top",
6081                         P_("Margin Top"),
6082                         P_("Extra space at the top"),
6083                         0.0, G_MAXFLOAT,
6084                         0.0,
6085                         CLUTTER_PARAM_READWRITE);
6086
6087   /**
6088    * ClutterActor:margin-bottom:
6089    *
6090    * The margin (in pixels) from the bottom of the actor.
6091    *
6092    * This property adds a margin to the actor's preferred size; the margin
6093    * will be automatically taken into account when allocating the actor.
6094    *
6095    * Since: 1.10
6096    */
6097   obj_props[PROP_MARGIN_BOTTOM] =
6098     g_param_spec_float ("margin-bottom",
6099                         P_("Margin Bottom"),
6100                         P_("Extra space at the bottom"),
6101                         0.0, G_MAXFLOAT,
6102                         0.0,
6103                         CLUTTER_PARAM_READWRITE);
6104
6105   /**
6106    * ClutterActor:margin-left:
6107    *
6108    * The margin (in pixels) from the left of the actor.
6109    *
6110    * This property adds a margin to the actor's preferred size; the margin
6111    * will be automatically taken into account when allocating the actor.
6112    *
6113    * Since: 1.10
6114    */
6115   obj_props[PROP_MARGIN_LEFT] =
6116     g_param_spec_float ("margin-left",
6117                         P_("Margin Left"),
6118                         P_("Extra space at the left"),
6119                         0.0, G_MAXFLOAT,
6120                         0.0,
6121                         CLUTTER_PARAM_READWRITE);
6122
6123   /**
6124    * ClutterActor:margin-right:
6125    *
6126    * The margin (in pixels) from the right of the actor.
6127    *
6128    * This property adds a margin to the actor's preferred size; the margin
6129    * will be automatically taken into account when allocating the actor.
6130    *
6131    * Since: 1.10
6132    */
6133   obj_props[PROP_MARGIN_RIGHT] =
6134     g_param_spec_float ("margin-right",
6135                         P_("Margin Right"),
6136                         P_("Extra space at the right"),
6137                         0.0, G_MAXFLOAT,
6138                         0.0,
6139                         CLUTTER_PARAM_READWRITE);
6140
6141   /**
6142    * ClutterActor:background-color-set:
6143    *
6144    * Whether the #ClutterActor:background-color property has been set.
6145    *
6146    * Since: 1.10
6147    */
6148   obj_props[PROP_BACKGROUND_COLOR_SET] =
6149     g_param_spec_boolean ("background-color-set",
6150                           P_("Background Color Set"),
6151                           P_("Whether the background color is set"),
6152                           FALSE,
6153                           CLUTTER_PARAM_READABLE);
6154
6155   /**
6156    * ClutterActor:background-color:
6157    *
6158    * Paints a solid fill of the actor's allocation using the specified
6159    * color.
6160    *
6161    * The #ClutterActor:background-color property is animatable.
6162    *
6163    * Since: 1.10
6164    */
6165   obj_props[PROP_BACKGROUND_COLOR] =
6166     clutter_param_spec_color ("background-color",
6167                               P_("Background color"),
6168                               P_("The actor's background color"),
6169                               CLUTTER_COLOR_Transparent,
6170                               G_PARAM_READWRITE |
6171                               G_PARAM_STATIC_STRINGS |
6172                               CLUTTER_PARAM_ANIMATABLE);
6173
6174   /**
6175    * ClutterActor:first-child:
6176    *
6177    * The actor's first child.
6178    *
6179    * Since: 1.10
6180    */
6181   obj_props[PROP_FIRST_CHILD] =
6182     g_param_spec_object ("first-child",
6183                          P_("First Child"),
6184                          P_("The actor's first child"),
6185                          CLUTTER_TYPE_ACTOR,
6186                          CLUTTER_PARAM_READABLE);
6187
6188   /**
6189    * ClutterActor:last-child:
6190    *
6191    * The actor's last child.
6192    *
6193    * Since: 1.10
6194    */
6195   obj_props[PROP_LAST_CHILD] =
6196     g_param_spec_object ("last-child",
6197                          P_("Last Child"),
6198                          P_("The actor's last child"),
6199                          CLUTTER_TYPE_ACTOR,
6200                          CLUTTER_PARAM_READABLE);
6201
6202   /**
6203    * ClutterActor:content:
6204    *
6205    * The #ClutterContent implementation that controls the content
6206    * of the actor.
6207    *
6208    * Since: 1.10
6209    */
6210   obj_props[PROP_CONTENT] =
6211     g_param_spec_object ("content",
6212                          P_("Content"),
6213                          P_("Delegate object for painting the actor's content"),
6214                          CLUTTER_TYPE_CONTENT,
6215                          CLUTTER_PARAM_READWRITE);
6216
6217   /**
6218    * ClutterActor:content-gravity:
6219    *
6220    * The alignment that should be honoured by the #ClutterContent
6221    * set with the #ClutterActor:content property.
6222    *
6223    * Changing the value of this property will change the bounding box of
6224    * the content; you can use the #ClutterActor:content-box property to
6225    * get the position and size of the content within the actor's
6226    * allocation.
6227    *
6228    * This property is meaningful only for #ClutterContent implementations
6229    * that have a preferred size, and if the preferred size is smaller than
6230    * the actor's allocation.
6231    *
6232    * Since: 1.10
6233    */
6234   obj_props[PROP_CONTENT_GRAVITY] =
6235     g_param_spec_enum ("content-gravity",
6236                        P_("Content Gravity"),
6237                        P_("Alignment of the actor's content"),
6238                        CLUTTER_TYPE_CONTENT_GRAVITY,
6239                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6240                        CLUTTER_PARAM_READWRITE);
6241
6242   /**
6243    * ClutterActor:content-box:
6244    *
6245    * The bounding box for the #ClutterContent used by the actor.
6246    *
6247    * The value of this property is controlled by the #ClutterActor:allocation
6248    * and #ClutterActor:content-gravity properties of #ClutterActor.
6249    *
6250    * The bounding box for the content is guaranteed to never exceed the
6251    * allocation's of the actor.
6252    *
6253    * Since: 1.10
6254    */
6255   obj_props[PROP_CONTENT_BOX] =
6256     g_param_spec_boxed ("content-box",
6257                         P_("Content Box"),
6258                         P_("The bounding box of the actor's content"),
6259                         CLUTTER_TYPE_ACTOR_BOX,
6260                         CLUTTER_PARAM_READABLE);
6261
6262   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6263
6264   /**
6265    * ClutterActor::destroy:
6266    * @actor: the #ClutterActor which emitted the signal
6267    *
6268    * The ::destroy signal notifies that all references held on the
6269    * actor which emitted it should be released.
6270    *
6271    * The ::destroy signal should be used by all holders of a reference
6272    * on @actor.
6273    *
6274    * This signal might result in the finalization of the #ClutterActor
6275    * if all references are released.
6276    *
6277    * Composite actors and actors implementing the #ClutterContainer
6278    * interface should override the default implementation of the
6279    * class handler of this signal and call clutter_actor_destroy() on
6280    * their children. When overriding the default class handler, it is
6281    * required to chain up to the parent's implementation.
6282    *
6283    * Since: 0.2
6284    */
6285   actor_signals[DESTROY] =
6286     g_signal_new (I_("destroy"),
6287                   G_TYPE_FROM_CLASS (object_class),
6288                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6289                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6290                   NULL, NULL,
6291                   _clutter_marshal_VOID__VOID,
6292                   G_TYPE_NONE, 0);
6293   /**
6294    * ClutterActor::show:
6295    * @actor: the object which received the signal
6296    *
6297    * The ::show signal is emitted when an actor is visible and
6298    * rendered on the stage.
6299    *
6300    * Since: 0.2
6301    */
6302   actor_signals[SHOW] =
6303     g_signal_new (I_("show"),
6304                   G_TYPE_FROM_CLASS (object_class),
6305                   G_SIGNAL_RUN_FIRST,
6306                   G_STRUCT_OFFSET (ClutterActorClass, show),
6307                   NULL, NULL,
6308                   _clutter_marshal_VOID__VOID,
6309                   G_TYPE_NONE, 0);
6310   /**
6311    * ClutterActor::hide:
6312    * @actor: the object which received the signal
6313    *
6314    * The ::hide signal is emitted when an actor is no longer rendered
6315    * on the stage.
6316    *
6317    * Since: 0.2
6318    */
6319   actor_signals[HIDE] =
6320     g_signal_new (I_("hide"),
6321                   G_TYPE_FROM_CLASS (object_class),
6322                   G_SIGNAL_RUN_FIRST,
6323                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6324                   NULL, NULL,
6325                   _clutter_marshal_VOID__VOID,
6326                   G_TYPE_NONE, 0);
6327   /**
6328    * ClutterActor::parent-set:
6329    * @actor: the object which received the signal
6330    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6331    *
6332    * This signal is emitted when the parent of the actor changes.
6333    *
6334    * Since: 0.2
6335    */
6336   actor_signals[PARENT_SET] =
6337     g_signal_new (I_("parent-set"),
6338                   G_TYPE_FROM_CLASS (object_class),
6339                   G_SIGNAL_RUN_LAST,
6340                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6341                   NULL, NULL,
6342                   _clutter_marshal_VOID__OBJECT,
6343                   G_TYPE_NONE, 1,
6344                   CLUTTER_TYPE_ACTOR);
6345
6346   /**
6347    * ClutterActor::queue-redraw:
6348    * @actor: the actor we're bubbling the redraw request through
6349    * @origin: the actor which initiated the redraw request
6350    *
6351    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6352    * is called on @origin.
6353    *
6354    * The default implementation for #ClutterActor chains up to the
6355    * parent actor and queues a redraw on the parent, thus "bubbling"
6356    * the redraw queue up through the actor graph. The default
6357    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6358    * in a main loop idle handler.
6359    *
6360    * Note that the @origin actor may be the stage, or a container; it
6361    * does not have to be a leaf node in the actor graph.
6362    *
6363    * Toolkits embedding a #ClutterStage which require a redraw and
6364    * relayout cycle can stop the emission of this signal using the
6365    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6366    * themselves, like:
6367    *
6368    * |[
6369    *   static void
6370    *   on_redraw_complete (gpointer data)
6371    *   {
6372    *     ClutterStage *stage = data;
6373    *
6374    *     /&ast; execute the Clutter drawing pipeline &ast;/
6375    *     clutter_stage_ensure_redraw (stage);
6376    *   }
6377    *
6378    *   static void
6379    *   on_stage_queue_redraw (ClutterStage *stage)
6380    *   {
6381    *     /&ast; this prevents the default handler to run &ast;/
6382    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6383    *
6384    *     /&ast; queue a redraw with the host toolkit and call
6385    *      &ast; a function when the redraw has been completed
6386    *      &ast;/
6387    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6388    *   }
6389    * ]|
6390    *
6391    * <note><para>This signal is emitted before the Clutter paint
6392    * pipeline is executed. If you want to know when the pipeline has
6393    * been completed you should connect to the ::paint signal on the
6394    * Stage with g_signal_connect_after().</para></note>
6395    *
6396    * Since: 1.0
6397    */
6398   actor_signals[QUEUE_REDRAW] =
6399     g_signal_new (I_("queue-redraw"),
6400                   G_TYPE_FROM_CLASS (object_class),
6401                   G_SIGNAL_RUN_LAST |
6402                   G_SIGNAL_NO_HOOKS,
6403                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6404                   NULL, NULL,
6405                   _clutter_marshal_VOID__OBJECT,
6406                   G_TYPE_NONE, 1,
6407                   CLUTTER_TYPE_ACTOR);
6408
6409   /**
6410    * ClutterActor::queue-relayout
6411    * @actor: the actor being queued for relayout
6412    *
6413    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6414    * is called on an actor.
6415    *
6416    * The default implementation for #ClutterActor chains up to the
6417    * parent actor and queues a relayout on the parent, thus "bubbling"
6418    * the relayout queue up through the actor graph.
6419    *
6420    * The main purpose of this signal is to allow relayout to be propagated
6421    * properly in the procense of #ClutterClone actors. Applications will
6422    * not normally need to connect to this signal.
6423    *
6424    * Since: 1.2
6425    */
6426   actor_signals[QUEUE_RELAYOUT] =
6427     g_signal_new (I_("queue-relayout"),
6428                   G_TYPE_FROM_CLASS (object_class),
6429                   G_SIGNAL_RUN_LAST |
6430                   G_SIGNAL_NO_HOOKS,
6431                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6432                   NULL, NULL,
6433                   _clutter_marshal_VOID__VOID,
6434                   G_TYPE_NONE, 0);
6435
6436   /**
6437    * ClutterActor::event:
6438    * @actor: the actor which received the event
6439    * @event: a #ClutterEvent
6440    *
6441    * The ::event signal is emitted each time an event is received
6442    * by the @actor. This signal will be emitted on every actor,
6443    * following the hierarchy chain, until it reaches the top-level
6444    * container (the #ClutterStage).
6445    *
6446    * Return value: %TRUE if the event has been handled by the actor,
6447    *   or %FALSE to continue the emission.
6448    *
6449    * Since: 0.6
6450    */
6451   actor_signals[EVENT] =
6452     g_signal_new (I_("event"),
6453                   G_TYPE_FROM_CLASS (object_class),
6454                   G_SIGNAL_RUN_LAST,
6455                   G_STRUCT_OFFSET (ClutterActorClass, event),
6456                   _clutter_boolean_handled_accumulator, NULL,
6457                   _clutter_marshal_BOOLEAN__BOXED,
6458                   G_TYPE_BOOLEAN, 1,
6459                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6460   /**
6461    * ClutterActor::button-press-event:
6462    * @actor: the actor which received the event
6463    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6464    *
6465    * The ::button-press-event signal is emitted each time a mouse button
6466    * is pressed on @actor.
6467    *
6468    * Return value: %TRUE if the event has been handled by the actor,
6469    *   or %FALSE to continue the emission.
6470    *
6471    * Since: 0.6
6472    */
6473   actor_signals[BUTTON_PRESS_EVENT] =
6474     g_signal_new (I_("button-press-event"),
6475                   G_TYPE_FROM_CLASS (object_class),
6476                   G_SIGNAL_RUN_LAST,
6477                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6478                   _clutter_boolean_handled_accumulator, NULL,
6479                   _clutter_marshal_BOOLEAN__BOXED,
6480                   G_TYPE_BOOLEAN, 1,
6481                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6482   /**
6483    * ClutterActor::button-release-event:
6484    * @actor: the actor which received the event
6485    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6486    *
6487    * The ::button-release-event signal is emitted each time a mouse button
6488    * is released on @actor.
6489    *
6490    * Return value: %TRUE if the event has been handled by the actor,
6491    *   or %FALSE to continue the emission.
6492    *
6493    * Since: 0.6
6494    */
6495   actor_signals[BUTTON_RELEASE_EVENT] =
6496     g_signal_new (I_("button-release-event"),
6497                   G_TYPE_FROM_CLASS (object_class),
6498                   G_SIGNAL_RUN_LAST,
6499                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6500                   _clutter_boolean_handled_accumulator, NULL,
6501                   _clutter_marshal_BOOLEAN__BOXED,
6502                   G_TYPE_BOOLEAN, 1,
6503                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6504   /**
6505    * ClutterActor::scroll-event:
6506    * @actor: the actor which received the event
6507    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6508    *
6509    * The ::scroll-event signal is emitted each time the mouse is
6510    * scrolled on @actor
6511    *
6512    * Return value: %TRUE if the event has been handled by the actor,
6513    *   or %FALSE to continue the emission.
6514    *
6515    * Since: 0.6
6516    */
6517   actor_signals[SCROLL_EVENT] =
6518     g_signal_new (I_("scroll-event"),
6519                   G_TYPE_FROM_CLASS (object_class),
6520                   G_SIGNAL_RUN_LAST,
6521                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6522                   _clutter_boolean_handled_accumulator, NULL,
6523                   _clutter_marshal_BOOLEAN__BOXED,
6524                   G_TYPE_BOOLEAN, 1,
6525                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6526   /**
6527    * ClutterActor::key-press-event:
6528    * @actor: the actor which received the event
6529    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6530    *
6531    * The ::key-press-event signal is emitted each time a keyboard button
6532    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6533    *
6534    * Return value: %TRUE if the event has been handled by the actor,
6535    *   or %FALSE to continue the emission.
6536    *
6537    * Since: 0.6
6538    */
6539   actor_signals[KEY_PRESS_EVENT] =
6540     g_signal_new (I_("key-press-event"),
6541                   G_TYPE_FROM_CLASS (object_class),
6542                   G_SIGNAL_RUN_LAST,
6543                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6544                   _clutter_boolean_handled_accumulator, NULL,
6545                   _clutter_marshal_BOOLEAN__BOXED,
6546                   G_TYPE_BOOLEAN, 1,
6547                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6548   /**
6549    * ClutterActor::key-release-event:
6550    * @actor: the actor which received the event
6551    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6552    *
6553    * The ::key-release-event signal is emitted each time a keyboard button
6554    * is released while @actor has key focus (see
6555    * clutter_stage_set_key_focus()).
6556    *
6557    * Return value: %TRUE if the event has been handled by the actor,
6558    *   or %FALSE to continue the emission.
6559    *
6560    * Since: 0.6
6561    */
6562   actor_signals[KEY_RELEASE_EVENT] =
6563     g_signal_new (I_("key-release-event"),
6564                   G_TYPE_FROM_CLASS (object_class),
6565                   G_SIGNAL_RUN_LAST,
6566                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6567                   _clutter_boolean_handled_accumulator, NULL,
6568                   _clutter_marshal_BOOLEAN__BOXED,
6569                   G_TYPE_BOOLEAN, 1,
6570                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6571   /**
6572    * ClutterActor::motion-event:
6573    * @actor: the actor which received the event
6574    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6575    *
6576    * The ::motion-event signal is emitted each time the mouse pointer is
6577    * moved over @actor.
6578    *
6579    * Return value: %TRUE if the event has been handled by the actor,
6580    *   or %FALSE to continue the emission.
6581    *
6582    * Since: 0.6
6583    */
6584   actor_signals[MOTION_EVENT] =
6585     g_signal_new (I_("motion-event"),
6586                   G_TYPE_FROM_CLASS (object_class),
6587                   G_SIGNAL_RUN_LAST,
6588                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6589                   _clutter_boolean_handled_accumulator, NULL,
6590                   _clutter_marshal_BOOLEAN__BOXED,
6591                   G_TYPE_BOOLEAN, 1,
6592                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6593
6594   /**
6595    * ClutterActor::key-focus-in:
6596    * @actor: the actor which now has key focus
6597    *
6598    * The ::key-focus-in signal is emitted when @actor receives key focus.
6599    *
6600    * Since: 0.6
6601    */
6602   actor_signals[KEY_FOCUS_IN] =
6603     g_signal_new (I_("key-focus-in"),
6604                   G_TYPE_FROM_CLASS (object_class),
6605                   G_SIGNAL_RUN_LAST,
6606                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6607                   NULL, NULL,
6608                   _clutter_marshal_VOID__VOID,
6609                   G_TYPE_NONE, 0);
6610
6611   /**
6612    * ClutterActor::key-focus-out:
6613    * @actor: the actor which now has key focus
6614    *
6615    * The ::key-focus-out signal is emitted when @actor loses key focus.
6616    *
6617    * Since: 0.6
6618    */
6619   actor_signals[KEY_FOCUS_OUT] =
6620     g_signal_new (I_("key-focus-out"),
6621                   G_TYPE_FROM_CLASS (object_class),
6622                   G_SIGNAL_RUN_LAST,
6623                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6624                   NULL, NULL,
6625                   _clutter_marshal_VOID__VOID,
6626                   G_TYPE_NONE, 0);
6627
6628   /**
6629    * ClutterActor::enter-event:
6630    * @actor: the actor which the pointer has entered.
6631    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6632    *
6633    * The ::enter-event signal is emitted when the pointer enters the @actor
6634    *
6635    * Return value: %TRUE if the event has been handled by the actor,
6636    *   or %FALSE to continue the emission.
6637    *
6638    * Since: 0.6
6639    */
6640   actor_signals[ENTER_EVENT] =
6641     g_signal_new (I_("enter-event"),
6642                   G_TYPE_FROM_CLASS (object_class),
6643                   G_SIGNAL_RUN_LAST,
6644                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6645                   _clutter_boolean_handled_accumulator, NULL,
6646                   _clutter_marshal_BOOLEAN__BOXED,
6647                   G_TYPE_BOOLEAN, 1,
6648                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6649
6650   /**
6651    * ClutterActor::leave-event:
6652    * @actor: the actor which the pointer has left
6653    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6654    *
6655    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6656    *
6657    * Return value: %TRUE if the event has been handled by the actor,
6658    *   or %FALSE to continue the emission.
6659    *
6660    * Since: 0.6
6661    */
6662   actor_signals[LEAVE_EVENT] =
6663     g_signal_new (I_("leave-event"),
6664                   G_TYPE_FROM_CLASS (object_class),
6665                   G_SIGNAL_RUN_LAST,
6666                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6667                   _clutter_boolean_handled_accumulator, NULL,
6668                   _clutter_marshal_BOOLEAN__BOXED,
6669                   G_TYPE_BOOLEAN, 1,
6670                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6671
6672   /**
6673    * ClutterActor::captured-event:
6674    * @actor: the actor which received the signal
6675    * @event: a #ClutterEvent
6676    *
6677    * The ::captured-event signal is emitted when an event is captured
6678    * by Clutter. This signal will be emitted starting from the top-level
6679    * container (the #ClutterStage) to the actor which received the event
6680    * going down the hierarchy. This signal can be used to intercept every
6681    * event before the specialized events (like
6682    * ClutterActor::button-press-event or ::key-released-event) are
6683    * emitted.
6684    *
6685    * Return value: %TRUE if the event has been handled by the actor,
6686    *   or %FALSE to continue the emission.
6687    *
6688    * Since: 0.6
6689    */
6690   actor_signals[CAPTURED_EVENT] =
6691     g_signal_new (I_("captured-event"),
6692                   G_TYPE_FROM_CLASS (object_class),
6693                   G_SIGNAL_RUN_LAST,
6694                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6695                   _clutter_boolean_handled_accumulator, NULL,
6696                   _clutter_marshal_BOOLEAN__BOXED,
6697                   G_TYPE_BOOLEAN, 1,
6698                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6699
6700   /**
6701    * ClutterActor::paint:
6702    * @actor: the #ClutterActor that received the signal
6703    *
6704    * The ::paint signal is emitted each time an actor is being painted.
6705    *
6706    * Subclasses of #ClutterActor should override the class signal handler
6707    * and paint themselves in that function.
6708    *
6709    * It is possible to connect a handler to the ::paint signal in order
6710    * to set up some custom aspect of a paint.
6711    *
6712    * Since: 0.8
6713    */
6714   actor_signals[PAINT] =
6715     g_signal_new (I_("paint"),
6716                   G_TYPE_FROM_CLASS (object_class),
6717                   G_SIGNAL_RUN_LAST |
6718                   G_SIGNAL_NO_HOOKS,
6719                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6720                   NULL, NULL,
6721                   _clutter_marshal_VOID__VOID,
6722                   G_TYPE_NONE, 0);
6723   /**
6724    * ClutterActor::realize:
6725    * @actor: the #ClutterActor that received the signal
6726    *
6727    * The ::realize signal is emitted each time an actor is being
6728    * realized.
6729    *
6730    * Since: 0.8
6731    */
6732   actor_signals[REALIZE] =
6733     g_signal_new (I_("realize"),
6734                   G_TYPE_FROM_CLASS (object_class),
6735                   G_SIGNAL_RUN_LAST,
6736                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6737                   NULL, NULL,
6738                   _clutter_marshal_VOID__VOID,
6739                   G_TYPE_NONE, 0);
6740   /**
6741    * ClutterActor::unrealize:
6742    * @actor: the #ClutterActor that received the signal
6743    *
6744    * The ::unrealize signal is emitted each time an actor is being
6745    * unrealized.
6746    *
6747    * Since: 0.8
6748    */
6749   actor_signals[UNREALIZE] =
6750     g_signal_new (I_("unrealize"),
6751                   G_TYPE_FROM_CLASS (object_class),
6752                   G_SIGNAL_RUN_LAST,
6753                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6754                   NULL, NULL,
6755                   _clutter_marshal_VOID__VOID,
6756                   G_TYPE_NONE, 0);
6757
6758   /**
6759    * ClutterActor::pick:
6760    * @actor: the #ClutterActor that received the signal
6761    * @color: the #ClutterColor to be used when picking
6762    *
6763    * The ::pick signal is emitted each time an actor is being painted
6764    * in "pick mode". The pick mode is used to identify the actor during
6765    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6766    * The actor should paint its shape using the passed @pick_color.
6767    *
6768    * Subclasses of #ClutterActor should override the class signal handler
6769    * and paint themselves in that function.
6770    *
6771    * It is possible to connect a handler to the ::pick signal in order
6772    * to set up some custom aspect of a paint in pick mode.
6773    *
6774    * Since: 1.0
6775    */
6776   actor_signals[PICK] =
6777     g_signal_new (I_("pick"),
6778                   G_TYPE_FROM_CLASS (object_class),
6779                   G_SIGNAL_RUN_LAST,
6780                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6781                   NULL, NULL,
6782                   _clutter_marshal_VOID__BOXED,
6783                   G_TYPE_NONE, 1,
6784                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6785
6786   /**
6787    * ClutterActor::allocation-changed:
6788    * @actor: the #ClutterActor that emitted the signal
6789    * @box: a #ClutterActorBox with the new allocation
6790    * @flags: #ClutterAllocationFlags for the allocation
6791    *
6792    * The ::allocation-changed signal is emitted when the
6793    * #ClutterActor:allocation property changes. Usually, application
6794    * code should just use the notifications for the :allocation property
6795    * but if you want to track the allocation flags as well, for instance
6796    * to know whether the absolute origin of @actor changed, then you might
6797    * want use this signal instead.
6798    *
6799    * Since: 1.0
6800    */
6801   actor_signals[ALLOCATION_CHANGED] =
6802     g_signal_new (I_("allocation-changed"),
6803                   G_TYPE_FROM_CLASS (object_class),
6804                   G_SIGNAL_RUN_LAST,
6805                   0,
6806                   NULL, NULL,
6807                   _clutter_marshal_VOID__BOXED_FLAGS,
6808                   G_TYPE_NONE, 2,
6809                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6810                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6811 }
6812
6813 static void
6814 clutter_actor_init (ClutterActor *self)
6815 {
6816   ClutterActorPrivate *priv;
6817
6818   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6819
6820   priv->id = _clutter_context_acquire_id (self);
6821   priv->pick_id = -1;
6822
6823   priv->opacity = 0xff;
6824   priv->show_on_set_parent = TRUE;
6825
6826   priv->needs_width_request = TRUE;
6827   priv->needs_height_request = TRUE;
6828   priv->needs_allocation = TRUE;
6829
6830   priv->cached_width_age = 1;
6831   priv->cached_height_age = 1;
6832
6833   priv->opacity_override = -1;
6834   priv->enable_model_view_transform = TRUE;
6835
6836   /* Initialize an empty paint volume to start with */
6837   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6838   priv->last_paint_volume_valid = TRUE;
6839
6840   priv->transform_valid = FALSE;
6841
6842   /* the default is to stretch the content, to match the
6843    * current behaviour of basically all actors. also, it's
6844    * the easiest thing to compute.
6845    */
6846   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
6847 }
6848
6849 /**
6850  * clutter_actor_new:
6851  *
6852  * Creates a new #ClutterActor.
6853  *
6854  * A newly created actor has a floating reference, which will be sunk
6855  * when it is added to another actor.
6856  *
6857  * Return value: (transfer full): the newly created #ClutterActor
6858  *
6859  * Since: 1.10
6860  */
6861 ClutterActor *
6862 clutter_actor_new (void)
6863 {
6864   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6865 }
6866
6867 /**
6868  * clutter_actor_destroy:
6869  * @self: a #ClutterActor
6870  *
6871  * Destroys an actor.  When an actor is destroyed, it will break any
6872  * references it holds to other objects.  If the actor is inside a
6873  * container, the actor will be removed.
6874  *
6875  * When you destroy a container, its children will be destroyed as well.
6876  *
6877  * Note: you cannot destroy the #ClutterStage returned by
6878  * clutter_stage_get_default().
6879  */
6880 void
6881 clutter_actor_destroy (ClutterActor *self)
6882 {
6883   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6884
6885   g_object_ref (self);
6886
6887   /* avoid recursion while destroying */
6888   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6889     {
6890       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6891
6892       g_object_run_dispose (G_OBJECT (self));
6893
6894       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6895     }
6896
6897   g_object_unref (self);
6898 }
6899
6900 void
6901 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6902                                     ClutterPaintVolume *clip)
6903 {
6904   ClutterActorPrivate *priv = self->priv;
6905   ClutterPaintVolume *pv;
6906   gboolean clipped;
6907
6908   /* Remove queue entry early in the process, otherwise a new
6909      queue_redraw() during signal handling could put back this
6910      object in the stage redraw list (but the entry is freed as
6911      soon as we return from this function, causing a segfault
6912      later)
6913   */
6914   priv->queue_redraw_entry = NULL;
6915
6916   /* If we've been explicitly passed a clip volume then there's
6917    * nothing more to calculate, but otherwise the only thing we know
6918    * is that the change is constrained to the given actor.
6919    *
6920    * The idea is that if we know the paint volume for where the actor
6921    * was last drawn (in eye coordinates) and we also have the paint
6922    * volume for where it will be drawn next (in actor coordinates)
6923    * then if we queue a redraw for both these volumes that will cover
6924    * everything that needs to be redrawn to clear the old view and
6925    * show the latest view of the actor.
6926    *
6927    * Don't clip this redraw if we don't know what position we had for
6928    * the previous redraw since we don't know where to set the clip so
6929    * it will clear the actor as it is currently.
6930    */
6931   if (clip)
6932     {
6933       _clutter_actor_set_queue_redraw_clip (self, clip);
6934       clipped = TRUE;
6935     }
6936   else if (G_LIKELY (priv->last_paint_volume_valid))
6937     {
6938       pv = _clutter_actor_get_paint_volume_mutable (self);
6939       if (pv)
6940         {
6941           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6942
6943           /* make sure we redraw the actors old position... */
6944           _clutter_actor_set_queue_redraw_clip (stage,
6945                                                 &priv->last_paint_volume);
6946           _clutter_actor_signal_queue_redraw (stage, stage);
6947           _clutter_actor_set_queue_redraw_clip (stage, NULL);
6948
6949           /* XXX: Ideally the redraw signal would take a clip volume
6950            * argument, but that would be an ABI break. Until we can
6951            * break the ABI we pass the argument out-of-band
6952            */
6953
6954           /* setup the clip for the actors new position... */
6955           _clutter_actor_set_queue_redraw_clip (self, pv);
6956           clipped = TRUE;
6957         }
6958       else
6959         clipped = FALSE;
6960     }
6961   else
6962     clipped = FALSE;
6963
6964   _clutter_actor_signal_queue_redraw (self, self);
6965
6966   /* Just in case anyone is manually firing redraw signals without
6967    * using the public queue_redraw() API we are careful to ensure that
6968    * our out-of-band clip member is cleared before returning...
6969    *
6970    * Note: A NULL clip denotes a full-stage, un-clipped redraw
6971    */
6972   if (G_LIKELY (clipped))
6973     _clutter_actor_set_queue_redraw_clip (self, NULL);
6974 }
6975
6976 static void
6977 _clutter_actor_get_allocation_clip (ClutterActor *self,
6978                                     ClutterActorBox *clip)
6979 {
6980   ClutterActorBox allocation;
6981
6982   /* XXX: we don't care if we get an out of date allocation here
6983    * because clutter_actor_queue_redraw_with_clip knows to ignore
6984    * the clip if the actor's allocation is invalid.
6985    *
6986    * This is noted because clutter_actor_get_allocation_box does some
6987    * unnecessary work to support buggy code with a comment suggesting
6988    * that it could be changed later which would be good for this use
6989    * case!
6990    */
6991   clutter_actor_get_allocation_box (self, &allocation);
6992
6993   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6994    * actor's own coordinate space but the allocation is in parent
6995    * coordinates */
6996   clip->x1 = 0;
6997   clip->y1 = 0;
6998   clip->x2 = allocation.x2 - allocation.x1;
6999   clip->y2 = allocation.y2 - allocation.y1;
7000 }
7001
7002 void
7003 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7004                                   ClutterRedrawFlags  flags,
7005                                   ClutterPaintVolume *volume,
7006                                   ClutterEffect      *effect)
7007 {
7008   ClutterActorPrivate *priv = self->priv;
7009   ClutterPaintVolume allocation_pv;
7010   ClutterPaintVolume *pv;
7011   gboolean should_free_pv;
7012   ClutterActor *stage;
7013
7014   /* Here's an outline of the actor queue redraw mechanism:
7015    *
7016    * The process starts in one of the following two functions which
7017    * are wrappers for this function:
7018    * clutter_actor_queue_redraw
7019    * _clutter_actor_queue_redraw_with_clip
7020    *
7021    * additionally, an effect can queue a redraw by wrapping this
7022    * function in clutter_effect_queue_rerun
7023    *
7024    * This functions queues an entry in a list associated with the
7025    * stage which is a list of actors that queued a redraw while
7026    * updating the timelines, performing layouting and processing other
7027    * mainloop sources before the next paint starts.
7028    *
7029    * We aim to minimize the processing done at this point because
7030    * there is a good chance other events will happen while updating
7031    * the scenegraph that would invalidate any expensive work we might
7032    * otherwise try to do here. For example we don't try and resolve
7033    * the screen space bounding box of an actor at this stage so as to
7034    * minimize how much of the screen redraw because it's possible
7035    * something else will happen which will force a full redraw anyway.
7036    *
7037    * When all updates are complete and we come to paint the stage then
7038    * we iterate this list and actually emit the "queue-redraw" signals
7039    * for each of the listed actors which will bubble up to the stage
7040    * for each actor and at that point we will transform the actors
7041    * paint volume into screen coordinates to determine the clip region
7042    * for what needs to be redrawn in the next paint.
7043    *
7044    * Besides minimizing redundant work another reason for this
7045    * deferred design is that it's more likely we will be able to
7046    * determine the paint volume of an actor once we've finished
7047    * updating the scenegraph because its allocation should be up to
7048    * date. NB: If we can't determine an actors paint volume then we
7049    * can't automatically queue a clipped redraw which can make a big
7050    * difference to performance.
7051    *
7052    * So the control flow goes like this:
7053    * One of clutter_actor_queue_redraw,
7054    *        _clutter_actor_queue_redraw_with_clip
7055    *     or clutter_effect_queue_rerun
7056    *
7057    * then control moves to:
7058    *   _clutter_stage_queue_actor_redraw
7059    *
7060    * later during _clutter_stage_do_update, once relayouting is done
7061    * and the scenegraph has been updated we will call:
7062    * _clutter_stage_finish_queue_redraws
7063    *
7064    * _clutter_stage_finish_queue_redraws will call
7065    * _clutter_actor_finish_queue_redraw for each listed actor.
7066    * Note: actors *are* allowed to queue further redraws during this
7067    * process (considering clone actors or texture_new_from_actor which
7068    * respond to their source queueing a redraw by queuing a redraw
7069    * themselves). We repeat the process until the list is empty.
7070    *
7071    * This will result in the "queue-redraw" signal being fired for
7072    * each actor which will pass control to the default signal handler:
7073    * clutter_actor_real_queue_redraw
7074    *
7075    * This will bubble up to the stages handler:
7076    * clutter_stage_real_queue_redraw
7077    *
7078    * clutter_stage_real_queue_redraw will transform the actors paint
7079    * volume into screen space and add it as a clip region for the next
7080    * paint.
7081    */
7082
7083   /* ignore queueing a redraw for actors being destroyed */
7084   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7085     return;
7086
7087   stage = _clutter_actor_get_stage_internal (self);
7088
7089   /* Ignore queueing a redraw for actors not descended from a stage */
7090   if (stage == NULL)
7091     return;
7092
7093   /* ignore queueing a redraw on stages that are being destroyed */
7094   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7095     return;
7096
7097   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7098     {
7099       ClutterActorBox allocation_clip;
7100       ClutterVertex origin;
7101
7102       /* If the actor doesn't have a valid allocation then we will
7103        * queue a full stage redraw. */
7104       if (priv->needs_allocation)
7105         {
7106           /* NB: NULL denotes an undefined clip which will result in a
7107            * full redraw... */
7108           _clutter_actor_set_queue_redraw_clip (self, NULL);
7109           _clutter_actor_signal_queue_redraw (self, self);
7110           return;
7111         }
7112
7113       _clutter_paint_volume_init_static (&allocation_pv, self);
7114       pv = &allocation_pv;
7115
7116       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7117
7118       origin.x = allocation_clip.x1;
7119       origin.y = allocation_clip.y1;
7120       origin.z = 0;
7121       clutter_paint_volume_set_origin (pv, &origin);
7122       clutter_paint_volume_set_width (pv,
7123                                       allocation_clip.x2 - allocation_clip.x1);
7124       clutter_paint_volume_set_height (pv,
7125                                        allocation_clip.y2 -
7126                                        allocation_clip.y1);
7127       should_free_pv = TRUE;
7128     }
7129   else
7130     {
7131       pv = volume;
7132       should_free_pv = FALSE;
7133     }
7134
7135   self->priv->queue_redraw_entry =
7136     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7137                                        priv->queue_redraw_entry,
7138                                        self,
7139                                        pv);
7140
7141   if (should_free_pv)
7142     clutter_paint_volume_free (pv);
7143
7144   /* If this is the first redraw queued then we can directly use the
7145      effect parameter */
7146   if (!priv->is_dirty)
7147     priv->effect_to_redraw = effect;
7148   /* Otherwise we need to merge it with the existing effect parameter */
7149   else if (effect != NULL)
7150     {
7151       /* If there's already an effect then we need to use whichever is
7152          later in the chain of actors. Otherwise a full redraw has
7153          already been queued on the actor so we need to ignore the
7154          effect parameter */
7155       if (priv->effect_to_redraw != NULL)
7156         {
7157           if (priv->effects == NULL)
7158             g_warning ("Redraw queued with an effect that is "
7159                        "not applied to the actor");
7160           else
7161             {
7162               const GList *l;
7163
7164               for (l = _clutter_meta_group_peek_metas (priv->effects);
7165                    l != NULL;
7166                    l = l->next)
7167                 {
7168                   if (l->data == priv->effect_to_redraw ||
7169                       l->data == effect)
7170                     priv->effect_to_redraw = l->data;
7171                 }
7172             }
7173         }
7174     }
7175   else
7176     {
7177       /* If no effect is specified then we need to redraw the whole
7178          actor */
7179       priv->effect_to_redraw = NULL;
7180     }
7181
7182   priv->is_dirty = TRUE;
7183 }
7184
7185 /**
7186  * clutter_actor_queue_redraw:
7187  * @self: A #ClutterActor
7188  *
7189  * Queues up a redraw of an actor and any children. The redraw occurs
7190  * once the main loop becomes idle (after the current batch of events
7191  * has been processed, roughly).
7192  *
7193  * Applications rarely need to call this, as redraws are handled
7194  * automatically by modification functions.
7195  *
7196  * This function will not do anything if @self is not visible, or
7197  * if the actor is inside an invisible part of the scenegraph.
7198  *
7199  * Also be aware that painting is a NOP for actors with an opacity of
7200  * 0
7201  *
7202  * When you are implementing a custom actor you must queue a redraw
7203  * whenever some private state changes that will affect painting or
7204  * picking of your actor.
7205  */
7206 void
7207 clutter_actor_queue_redraw (ClutterActor *self)
7208 {
7209   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7210
7211   _clutter_actor_queue_redraw_full (self,
7212                                     0, /* flags */
7213                                     NULL, /* clip volume */
7214                                     NULL /* effect */);
7215 }
7216
7217 /*< private >
7218  * _clutter_actor_queue_redraw_with_clip:
7219  * @self: A #ClutterActor
7220  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7221  *   this queue redraw.
7222  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7223  *   redrawn or %NULL if you are just using a @flag to state your
7224  *   desired clipping.
7225  *
7226  * Queues up a clipped redraw of an actor and any children. The redraw
7227  * occurs once the main loop becomes idle (after the current batch of
7228  * events has been processed, roughly).
7229  *
7230  * If no flags are given the clip volume is defined by @volume
7231  * specified in actor coordinates and tells Clutter that only content
7232  * within this volume has been changed so Clutter can optionally
7233  * optimize the redraw.
7234  *
7235  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7236  * should be %NULL and this tells Clutter to use the actor's current
7237  * allocation as a clip box. This flag can only be used for 2D actors,
7238  * because any actor with depth may be projected outside its
7239  * allocation.
7240  *
7241  * Applications rarely need to call this, as redraws are handled
7242  * automatically by modification functions.
7243  *
7244  * This function will not do anything if @self is not visible, or if
7245  * the actor is inside an invisible part of the scenegraph.
7246  *
7247  * Also be aware that painting is a NOP for actors with an opacity of
7248  * 0
7249  *
7250  * When you are implementing a custom actor you must queue a redraw
7251  * whenever some private state changes that will affect painting or
7252  * picking of your actor.
7253  */
7254 void
7255 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7256                                        ClutterRedrawFlags  flags,
7257                                        ClutterPaintVolume *volume)
7258 {
7259   _clutter_actor_queue_redraw_full (self,
7260                                     flags, /* flags */
7261                                     volume, /* clip volume */
7262                                     NULL /* effect */);
7263 }
7264
7265 static void
7266 _clutter_actor_queue_only_relayout (ClutterActor *self)
7267 {
7268   ClutterActorPrivate *priv = self->priv;
7269
7270   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7271     return;
7272
7273   if (priv->needs_width_request &&
7274       priv->needs_height_request &&
7275       priv->needs_allocation)
7276     return; /* save some cpu cycles */
7277
7278 #if CLUTTER_ENABLE_DEBUG
7279   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7280     {
7281       g_warning ("The actor '%s' is currently inside an allocation "
7282                  "cycle; calling clutter_actor_queue_relayout() is "
7283                  "not recommended",
7284                  _clutter_actor_get_debug_name (self));
7285     }
7286 #endif /* CLUTTER_ENABLE_DEBUG */
7287
7288   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7289 }
7290
7291 /**
7292  * clutter_actor_queue_redraw_with_clip:
7293  * @self: a #ClutterActor
7294  * @clip: (allow-none): a rectangular clip region, or %NULL
7295  *
7296  * Queues a redraw on @self limited to a specific, actor-relative
7297  * rectangular area.
7298  *
7299  * If @clip is %NULL this function is equivalent to
7300  * clutter_actor_queue_redraw().
7301  *
7302  * Since: 1.10
7303  */
7304 void
7305 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7306                                       const cairo_rectangle_int_t *clip)
7307 {
7308   ClutterPaintVolume volume;
7309   ClutterVertex origin;
7310
7311   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7312
7313   if (clip == NULL)
7314     {
7315       clutter_actor_queue_redraw (self);
7316       return;
7317     }
7318
7319   _clutter_paint_volume_init_static (&volume, self);
7320
7321   origin.x = clip->x;
7322   origin.y = clip->y;
7323   origin.z = 0.0f;
7324
7325   clutter_paint_volume_set_origin (&volume, &origin);
7326   clutter_paint_volume_set_width (&volume, clip->width);
7327   clutter_paint_volume_set_height (&volume, clip->height);
7328
7329   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7330
7331   clutter_paint_volume_free (&volume);
7332 }
7333
7334 /**
7335  * clutter_actor_queue_relayout:
7336  * @self: A #ClutterActor
7337  *
7338  * Indicates that the actor's size request or other layout-affecting
7339  * properties may have changed. This function is used inside #ClutterActor
7340  * subclass implementations, not by applications directly.
7341  *
7342  * Queueing a new layout automatically queues a redraw as well.
7343  *
7344  * Since: 0.8
7345  */
7346 void
7347 clutter_actor_queue_relayout (ClutterActor *self)
7348 {
7349   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7350
7351   _clutter_actor_queue_only_relayout (self);
7352   clutter_actor_queue_redraw (self);
7353 }
7354
7355 /**
7356  * clutter_actor_get_preferred_size:
7357  * @self: a #ClutterActor
7358  * @min_width_p: (out) (allow-none): return location for the minimum
7359  *   width, or %NULL
7360  * @min_height_p: (out) (allow-none): return location for the minimum
7361  *   height, or %NULL
7362  * @natural_width_p: (out) (allow-none): return location for the natural
7363  *   width, or %NULL
7364  * @natural_height_p: (out) (allow-none): return location for the natural
7365  *   height, or %NULL
7366  *
7367  * Computes the preferred minimum and natural size of an actor, taking into
7368  * account the actor's geometry management (either height-for-width
7369  * or width-for-height).
7370  *
7371  * The width and height used to compute the preferred height and preferred
7372  * width are the actor's natural ones.
7373  *
7374  * If you need to control the height for the preferred width, or the width for
7375  * the preferred height, you should use clutter_actor_get_preferred_width()
7376  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7377  * geometry management using the #ClutterActor:request-mode property.
7378  *
7379  * Since: 0.8
7380  */
7381 void
7382 clutter_actor_get_preferred_size (ClutterActor *self,
7383                                   gfloat       *min_width_p,
7384                                   gfloat       *min_height_p,
7385                                   gfloat       *natural_width_p,
7386                                   gfloat       *natural_height_p)
7387 {
7388   ClutterActorPrivate *priv;
7389   gfloat min_width, min_height;
7390   gfloat natural_width, natural_height;
7391
7392   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7393
7394   priv = self->priv;
7395
7396   min_width = min_height = 0;
7397   natural_width = natural_height = 0;
7398
7399   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7400     {
7401       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7402       clutter_actor_get_preferred_width (self, -1,
7403                                          &min_width,
7404                                          &natural_width);
7405       clutter_actor_get_preferred_height (self, natural_width,
7406                                           &min_height,
7407                                           &natural_height);
7408     }
7409   else
7410     {
7411       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7412       clutter_actor_get_preferred_height (self, -1,
7413                                           &min_height,
7414                                           &natural_height);
7415       clutter_actor_get_preferred_width (self, natural_height,
7416                                          &min_width,
7417                                          &natural_width);
7418     }
7419
7420   if (min_width_p)
7421     *min_width_p = min_width;
7422
7423   if (min_height_p)
7424     *min_height_p = min_height;
7425
7426   if (natural_width_p)
7427     *natural_width_p = natural_width;
7428
7429   if (natural_height_p)
7430     *natural_height_p = natural_height;
7431 }
7432
7433 /*< private >
7434  * effective_align:
7435  * @align: a #ClutterActorAlign
7436  * @direction: a #ClutterTextDirection
7437  *
7438  * Retrieves the correct alignment depending on the text direction
7439  *
7440  * Return value: the effective alignment
7441  */
7442 static ClutterActorAlign
7443 effective_align (ClutterActorAlign    align,
7444                  ClutterTextDirection direction)
7445 {
7446   ClutterActorAlign res;
7447
7448   switch (align)
7449     {
7450     case CLUTTER_ACTOR_ALIGN_START:
7451       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7452           ? CLUTTER_ACTOR_ALIGN_END
7453           : CLUTTER_ACTOR_ALIGN_START;
7454       break;
7455
7456     case CLUTTER_ACTOR_ALIGN_END:
7457       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7458           ? CLUTTER_ACTOR_ALIGN_START
7459           : CLUTTER_ACTOR_ALIGN_END;
7460       break;
7461
7462     default:
7463       res = align;
7464       break;
7465     }
7466
7467   return res;
7468 }
7469
7470 static inline void
7471 adjust_for_margin (float  margin_start,
7472                    float  margin_end,
7473                    float *minimum_size,
7474                    float *natural_size,
7475                    float *allocated_start,
7476                    float *allocated_end)
7477 {
7478   *minimum_size -= (margin_start + margin_end);
7479   *natural_size -= (margin_start + margin_end);
7480   *allocated_start += margin_start;
7481   *allocated_end -= margin_end;
7482 }
7483
7484 static inline void
7485 adjust_for_alignment (ClutterActorAlign  alignment,
7486                       float              natural_size,
7487                       float             *allocated_start,
7488                       float             *allocated_end)
7489 {
7490   float allocated_size = *allocated_end - *allocated_start;
7491
7492   switch (alignment)
7493     {
7494     case CLUTTER_ACTOR_ALIGN_FILL:
7495       /* do nothing */
7496       break;
7497
7498     case CLUTTER_ACTOR_ALIGN_START:
7499       /* keep start */
7500       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7501       break;
7502
7503     case CLUTTER_ACTOR_ALIGN_END:
7504       if (allocated_size > natural_size)
7505         {
7506           *allocated_start += (allocated_size - natural_size);
7507           *allocated_end = *allocated_start + natural_size;
7508         }
7509       break;
7510
7511     case CLUTTER_ACTOR_ALIGN_CENTER:
7512       if (allocated_size > natural_size)
7513         {
7514           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7515           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7516         }
7517       break;
7518     }
7519 }
7520
7521 /*< private >
7522  * clutter_actor_adjust_width:
7523  * @self: a #ClutterActor
7524  * @minimum_width: (inout): the actor's preferred minimum width, which
7525  *   will be adjusted depending on the margin
7526  * @natural_width: (inout): the actor's preferred natural width, which
7527  *   will be adjusted depending on the margin
7528  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7529  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7530  *
7531  * Adjusts the preferred and allocated position and size of an actor,
7532  * depending on the margin and alignment properties.
7533  */
7534 static void
7535 clutter_actor_adjust_width (ClutterActor *self,
7536                             gfloat       *minimum_width,
7537                             gfloat       *natural_width,
7538                             gfloat       *adjusted_x1,
7539                             gfloat       *adjusted_x2)
7540 {
7541   ClutterTextDirection text_dir;
7542   const ClutterLayoutInfo *info;
7543
7544   info = _clutter_actor_get_layout_info_or_defaults (self);
7545   text_dir = clutter_actor_get_text_direction (self);
7546
7547   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7548
7549   /* this will tweak natural_width to remove the margin, so that
7550    * adjust_for_alignment() will use the correct size
7551    */
7552   adjust_for_margin (info->margin.left, info->margin.right,
7553                      minimum_width, natural_width,
7554                      adjusted_x1, adjusted_x2);
7555
7556   adjust_for_alignment (effective_align (info->x_align, text_dir),
7557                         *natural_width,
7558                         adjusted_x1, adjusted_x2);
7559 }
7560
7561 /*< private >
7562  * clutter_actor_adjust_height:
7563  * @self: a #ClutterActor
7564  * @minimum_height: (inout): the actor's preferred minimum height, which
7565  *   will be adjusted depending on the margin
7566  * @natural_height: (inout): the actor's preferred natural height, which
7567  *   will be adjusted depending on the margin
7568  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7569  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7570  *
7571  * Adjusts the preferred and allocated position and size of an actor,
7572  * depending on the margin and alignment properties.
7573  */
7574 static void
7575 clutter_actor_adjust_height (ClutterActor *self,
7576                              gfloat       *minimum_height,
7577                              gfloat       *natural_height,
7578                              gfloat       *adjusted_y1,
7579                              gfloat       *adjusted_y2)
7580 {
7581   const ClutterLayoutInfo *info;
7582
7583   info = _clutter_actor_get_layout_info_or_defaults (self);
7584
7585   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7586
7587   /* this will tweak natural_height to remove the margin, so that
7588    * adjust_for_alignment() will use the correct size
7589    */
7590   adjust_for_margin (info->margin.top, info->margin.bottom,
7591                      minimum_height, natural_height,
7592                      adjusted_y1,
7593                      adjusted_y2);
7594
7595   /* we don't use effective_align() here, because text direction
7596    * only affects the horizontal axis
7597    */
7598   adjust_for_alignment (info->y_align,
7599                         *natural_height,
7600                         adjusted_y1,
7601                         adjusted_y2);
7602
7603 }
7604
7605 /* looks for a cached size request for this for_size. If not
7606  * found, returns the oldest entry so it can be overwritten */
7607 static gboolean
7608 _clutter_actor_get_cached_size_request (gfloat         for_size,
7609                                         SizeRequest   *cached_size_requests,
7610                                         SizeRequest  **result)
7611 {
7612   guint i;
7613
7614   *result = &cached_size_requests[0];
7615
7616   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7617     {
7618       SizeRequest *sr;
7619
7620       sr = &cached_size_requests[i];
7621
7622       if (sr->age > 0 &&
7623           sr->for_size == for_size)
7624         {
7625           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7626           *result = sr;
7627           return TRUE;
7628         }
7629       else if (sr->age < (*result)->age)
7630         {
7631           *result = sr;
7632         }
7633     }
7634
7635   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7636
7637   return FALSE;
7638 }
7639
7640 /**
7641  * clutter_actor_get_preferred_width:
7642  * @self: A #ClutterActor
7643  * @for_height: available height when computing the preferred width,
7644  *   or a negative value to indicate that no height is defined
7645  * @min_width_p: (out) (allow-none): return location for minimum width,
7646  *   or %NULL
7647  * @natural_width_p: (out) (allow-none): return location for the natural
7648  *   width, or %NULL
7649  *
7650  * Computes the requested minimum and natural widths for an actor,
7651  * optionally depending on the specified height, or if they are
7652  * already computed, returns the cached values.
7653  *
7654  * An actor may not get its request - depending on the layout
7655  * manager that's in effect.
7656  *
7657  * A request should not incorporate the actor's scale or anchor point;
7658  * those transformations do not affect layout, only rendering.
7659  *
7660  * Since: 0.8
7661  */
7662 void
7663 clutter_actor_get_preferred_width (ClutterActor *self,
7664                                    gfloat        for_height,
7665                                    gfloat       *min_width_p,
7666                                    gfloat       *natural_width_p)
7667 {
7668   float request_min_width, request_natural_width;
7669   SizeRequest *cached_size_request;
7670   const ClutterLayoutInfo *info;
7671   ClutterActorPrivate *priv;
7672   gboolean found_in_cache;
7673
7674   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7675
7676   priv = self->priv;
7677
7678   info = _clutter_actor_get_layout_info_or_defaults (self);
7679
7680   /* we shortcircuit the case of a fixed size set using set_width() */
7681   if (priv->min_width_set && priv->natural_width_set)
7682     {
7683       if (min_width_p != NULL)
7684         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7685
7686       if (natural_width_p != NULL)
7687         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7688
7689       return;
7690     }
7691
7692   /* the remaining cases are:
7693    *
7694    *   - either min_width or natural_width have been set
7695    *   - neither min_width or natural_width have been set
7696    *
7697    * in both cases, we go through the cache (and through the actor in case
7698    * of cache misses) and determine the authoritative value depending on
7699    * the *_set flags.
7700    */
7701
7702   if (!priv->needs_width_request)
7703     {
7704       found_in_cache =
7705         _clutter_actor_get_cached_size_request (for_height,
7706                                                 priv->width_requests,
7707                                                 &cached_size_request);
7708     }
7709   else
7710     {
7711       /* if the actor needs a width request we use the first slot */
7712       found_in_cache = FALSE;
7713       cached_size_request = &priv->width_requests[0];
7714     }
7715
7716   if (!found_in_cache)
7717     {
7718       gfloat minimum_width, natural_width;
7719       ClutterActorClass *klass;
7720
7721       minimum_width = natural_width = 0;
7722
7723       /* adjust for the margin */
7724       if (for_height >= 0)
7725         {
7726           for_height -= (info->margin.top + info->margin.bottom);
7727           if (for_height < 0)
7728             for_height = 0;
7729         }
7730
7731       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7732
7733       klass = CLUTTER_ACTOR_GET_CLASS (self);
7734       klass->get_preferred_width (self, for_height,
7735                                   &minimum_width,
7736                                   &natural_width);
7737
7738       /* adjust for the margin */
7739       minimum_width += (info->margin.left + info->margin.right);
7740       natural_width += (info->margin.left + info->margin.right);
7741
7742       /* Due to accumulated float errors, it's better not to warn
7743        * on this, but just fix it.
7744        */
7745       if (natural_width < minimum_width)
7746         natural_width = minimum_width;
7747
7748       cached_size_request->min_size = minimum_width;
7749       cached_size_request->natural_size = natural_width;
7750       cached_size_request->for_size = for_height;
7751       cached_size_request->age = priv->cached_width_age;
7752
7753       priv->cached_width_age += 1;
7754       priv->needs_width_request = FALSE;
7755     }
7756
7757   if (!priv->min_width_set)
7758     request_min_width = cached_size_request->min_size;
7759   else
7760     request_min_width = info->min_width;
7761
7762   if (!priv->natural_width_set)
7763     request_natural_width = cached_size_request->natural_size;
7764   else
7765     request_natural_width = info->natural_width;
7766
7767   if (min_width_p)
7768     *min_width_p = request_min_width;
7769
7770   if (natural_width_p)
7771     *natural_width_p = request_natural_width;
7772 }
7773
7774 /**
7775  * clutter_actor_get_preferred_height:
7776  * @self: A #ClutterActor
7777  * @for_width: available width to assume in computing desired height,
7778  *   or a negative value to indicate that no width is defined
7779  * @min_height_p: (out) (allow-none): return location for minimum height,
7780  *   or %NULL
7781  * @natural_height_p: (out) (allow-none): return location for natural
7782  *   height, or %NULL
7783  *
7784  * Computes the requested minimum and natural heights for an actor,
7785  * or if they are already computed, returns the cached values.
7786  *
7787  * An actor may not get its request - depending on the layout
7788  * manager that's in effect.
7789  *
7790  * A request should not incorporate the actor's scale or anchor point;
7791  * those transformations do not affect layout, only rendering.
7792  *
7793  * Since: 0.8
7794  */
7795 void
7796 clutter_actor_get_preferred_height (ClutterActor *self,
7797                                     gfloat        for_width,
7798                                     gfloat       *min_height_p,
7799                                     gfloat       *natural_height_p)
7800 {
7801   float request_min_height, request_natural_height;
7802   SizeRequest *cached_size_request;
7803   const ClutterLayoutInfo *info;
7804   ClutterActorPrivate *priv;
7805   gboolean found_in_cache;
7806
7807   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7808
7809   priv = self->priv;
7810
7811   info = _clutter_actor_get_layout_info_or_defaults (self);
7812
7813   /* we shortcircuit the case of a fixed size set using set_height() */
7814   if (priv->min_height_set && priv->natural_height_set)
7815     {
7816       if (min_height_p != NULL)
7817         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7818
7819       if (natural_height_p != NULL)
7820         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7821
7822       return;
7823     }
7824
7825   /* the remaining cases are:
7826    *
7827    *   - either min_height or natural_height have been set
7828    *   - neither min_height or natural_height have been set
7829    *
7830    * in both cases, we go through the cache (and through the actor in case
7831    * of cache misses) and determine the authoritative value depending on
7832    * the *_set flags.
7833    */
7834
7835   if (!priv->needs_height_request)
7836     {
7837       found_in_cache =
7838         _clutter_actor_get_cached_size_request (for_width,
7839                                                 priv->height_requests,
7840                                                 &cached_size_request);
7841     }
7842   else
7843     {
7844       found_in_cache = FALSE;
7845       cached_size_request = &priv->height_requests[0];
7846     }
7847
7848   if (!found_in_cache)
7849     {
7850       gfloat minimum_height, natural_height;
7851       ClutterActorClass *klass;
7852
7853       minimum_height = natural_height = 0;
7854
7855       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7856
7857       /* adjust for margin */
7858       if (for_width >= 0)
7859         {
7860           for_width -= (info->margin.left + info->margin.right);
7861           if (for_width < 0)
7862             for_width = 0;
7863         }
7864
7865       klass = CLUTTER_ACTOR_GET_CLASS (self);
7866       klass->get_preferred_height (self, for_width,
7867                                    &minimum_height,
7868                                    &natural_height);
7869
7870       /* adjust for margin */
7871       minimum_height += (info->margin.top + info->margin.bottom);
7872       natural_height += (info->margin.top + info->margin.bottom);
7873
7874       /* Due to accumulated float errors, it's better not to warn
7875        * on this, but just fix it.
7876        */
7877       if (natural_height < minimum_height)
7878         natural_height = minimum_height;
7879
7880       cached_size_request->min_size = minimum_height;
7881       cached_size_request->natural_size = natural_height;
7882       cached_size_request->for_size = for_width;
7883       cached_size_request->age = priv->cached_height_age;
7884
7885       priv->cached_height_age += 1;
7886       priv->needs_height_request = FALSE;
7887     }
7888
7889   if (!priv->min_height_set)
7890     request_min_height = cached_size_request->min_size;
7891   else
7892     request_min_height = info->min_height;
7893
7894   if (!priv->natural_height_set)
7895     request_natural_height = cached_size_request->natural_size;
7896   else
7897     request_natural_height = info->natural_height;
7898
7899   if (min_height_p)
7900     *min_height_p = request_min_height;
7901
7902   if (natural_height_p)
7903     *natural_height_p = request_natural_height;
7904 }
7905
7906 /**
7907  * clutter_actor_get_allocation_box:
7908  * @self: A #ClutterActor
7909  * @box: (out): the function fills this in with the actor's allocation
7910  *
7911  * Gets the layout box an actor has been assigned. The allocation can
7912  * only be assumed valid inside a paint() method; anywhere else, it
7913  * may be out-of-date.
7914  *
7915  * An allocation does not incorporate the actor's scale or anchor point;
7916  * those transformations do not affect layout, only rendering.
7917  *
7918  * <note>Do not call any of the clutter_actor_get_allocation_*() family
7919  * of functions inside the implementation of the get_preferred_width()
7920  * or get_preferred_height() virtual functions.</note>
7921  *
7922  * Since: 0.8
7923  */
7924 void
7925 clutter_actor_get_allocation_box (ClutterActor    *self,
7926                                   ClutterActorBox *box)
7927 {
7928   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7929
7930   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7931    * which limits calling get_allocation to inside paint() basically; or
7932    * we can 2) force a layout, which could be expensive if someone calls
7933    * get_allocation somewhere silly; or we can 3) just return the latest
7934    * value, allowing it to be out-of-date, and assume people know what
7935    * they are doing.
7936    *
7937    * The least-surprises approach that keeps existing code working is
7938    * likely to be 2). People can end up doing some inefficient things,
7939    * though, and in general code that requires 2) is probably broken.
7940    */
7941
7942   /* this implements 2) */
7943   if (G_UNLIKELY (self->priv->needs_allocation))
7944     {
7945       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7946
7947       /* do not queue a relayout on an unparented actor */
7948       if (stage)
7949         _clutter_stage_maybe_relayout (stage);
7950     }
7951
7952   /* commenting out the code above and just keeping this assigment
7953    * implements 3)
7954    */
7955   *box = self->priv->allocation;
7956 }
7957
7958 /**
7959  * clutter_actor_get_allocation_geometry:
7960  * @self: A #ClutterActor
7961  * @geom: (out): allocation geometry in pixels
7962  *
7963  * Gets the layout box an actor has been assigned.  The allocation can
7964  * only be assumed valid inside a paint() method; anywhere else, it
7965  * may be out-of-date.
7966  *
7967  * An allocation does not incorporate the actor's scale or anchor point;
7968  * those transformations do not affect layout, only rendering.
7969  *
7970  * The returned rectangle is in pixels.
7971  *
7972  * Since: 0.8
7973  */
7974 void
7975 clutter_actor_get_allocation_geometry (ClutterActor    *self,
7976                                        ClutterGeometry *geom)
7977 {
7978   ClutterActorBox box;
7979
7980   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7981   g_return_if_fail (geom != NULL);
7982
7983   clutter_actor_get_allocation_box (self, &box);
7984
7985   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7986   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7987   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7988   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7989 }
7990
7991 static void
7992 clutter_actor_update_constraints (ClutterActor    *self,
7993                                   ClutterActorBox *allocation)
7994 {
7995   ClutterActorPrivate *priv = self->priv;
7996   const GList *constraints, *l;
7997
7998   if (priv->constraints == NULL)
7999     return;
8000
8001   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8002   for (l = constraints; l != NULL; l = l->next)
8003     {
8004       ClutterConstraint *constraint = l->data;
8005       ClutterActorMeta *meta = l->data;
8006
8007       if (clutter_actor_meta_get_enabled (meta))
8008         {
8009           _clutter_constraint_update_allocation (constraint,
8010                                                  self,
8011                                                  allocation);
8012         }
8013     }
8014 }
8015
8016 /*< private >
8017  * clutter_actor_adjust_allocation:
8018  * @self: a #ClutterActor
8019  * @allocation: (inout): the allocation to adjust
8020  *
8021  * Adjusts the passed allocation box taking into account the actor's
8022  * layout information, like alignment, expansion, and margin.
8023  */
8024 static void
8025 clutter_actor_adjust_allocation (ClutterActor    *self,
8026                                  ClutterActorBox *allocation)
8027 {
8028   ClutterActorBox adj_allocation;
8029   float alloc_width, alloc_height;
8030   float min_width, min_height;
8031   float nat_width, nat_height;
8032   ClutterRequestMode req_mode;
8033
8034   adj_allocation = *allocation;
8035
8036   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8037
8038   /* we want to hit the cache, so we use the public API */
8039   req_mode = clutter_actor_get_request_mode (self);
8040
8041   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8042     {
8043       clutter_actor_get_preferred_width (self, -1,
8044                                          &min_width,
8045                                          &nat_width);
8046       clutter_actor_get_preferred_height (self, alloc_width,
8047                                           &min_height,
8048                                           &nat_height);
8049     }
8050   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8051     {
8052       clutter_actor_get_preferred_height (self, -1,
8053                                           &min_height,
8054                                           &nat_height);
8055       clutter_actor_get_preferred_height (self, alloc_height,
8056                                           &min_width,
8057                                           &nat_width);
8058     }
8059
8060 #ifdef CLUTTER_ENABLE_DEBUG
8061   /* warn about underallocations */
8062   if (_clutter_diagnostic_enabled () &&
8063       (floorf (min_width - alloc_width) > 0 ||
8064        floorf (min_height - alloc_height) > 0))
8065     {
8066       ClutterActor *parent = clutter_actor_get_parent (self);
8067
8068       /* the only actors that are allowed to be underallocated are the Stage,
8069        * as it doesn't have an implicit size, and Actors that specifically
8070        * told us that they want to opt-out from layout control mechanisms
8071        * through the NO_LAYOUT escape hatch.
8072        */
8073       if (parent != NULL &&
8074           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8075         {
8076           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8077                      "of %.2f x %.2f from its parent actor '%s', but its "
8078                      "requested minimum size is of %.2f x %.2f",
8079                      _clutter_actor_get_debug_name (self),
8080                      alloc_width, alloc_height,
8081                      _clutter_actor_get_debug_name (parent),
8082                      min_width, min_height);
8083         }
8084     }
8085 #endif
8086
8087   clutter_actor_adjust_width (self,
8088                               &min_width,
8089                               &nat_width,
8090                               &adj_allocation.x1,
8091                               &adj_allocation.x2);
8092
8093   clutter_actor_adjust_height (self,
8094                                &min_height,
8095                                &nat_height,
8096                                &adj_allocation.y1,
8097                                &adj_allocation.y2);
8098
8099   /* we maintain the invariant that an allocation cannot be adjusted
8100    * to be outside the parent-given box
8101    */
8102   if (adj_allocation.x1 < allocation->x1 ||
8103       adj_allocation.y1 < allocation->y1 ||
8104       adj_allocation.x2 > allocation->x2 ||
8105       adj_allocation.y2 > allocation->y2)
8106     {
8107       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8108                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8109                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8110                  _clutter_actor_get_debug_name (self),
8111                  adj_allocation.x1, adj_allocation.y1,
8112                  adj_allocation.x2 - adj_allocation.x1,
8113                  adj_allocation.y2 - adj_allocation.y1,
8114                  allocation->x1, allocation->y1,
8115                  allocation->x2 - allocation->x1,
8116                  allocation->y2 - allocation->y1);
8117       return;
8118     }
8119
8120   *allocation = adj_allocation;
8121 }
8122
8123 /**
8124  * clutter_actor_allocate:
8125  * @self: A #ClutterActor
8126  * @box: new allocation of the actor, in parent-relative coordinates
8127  * @flags: flags that control the allocation
8128  *
8129  * Called by the parent of an actor to assign the actor its size.
8130  * Should never be called by applications (except when implementing
8131  * a container or layout manager).
8132  *
8133  * Actors can know from their allocation box whether they have moved
8134  * with respect to their parent actor. The @flags parameter describes
8135  * additional information about the allocation, for instance whether
8136  * the parent has moved with respect to the stage, for example because
8137  * a grandparent's origin has moved.
8138  *
8139  * Since: 0.8
8140  */
8141 void
8142 clutter_actor_allocate (ClutterActor           *self,
8143                         const ClutterActorBox  *box,
8144                         ClutterAllocationFlags  flags)
8145 {
8146   ClutterActorPrivate *priv;
8147   ClutterActorClass *klass;
8148   ClutterActorBox old_allocation, real_allocation;
8149   gboolean origin_changed, child_moved, size_changed;
8150   gboolean stage_allocation_changed;
8151
8152   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8153   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8154     {
8155       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8156                  "which isn't a descendent of the stage!\n",
8157                  self, _clutter_actor_get_debug_name (self));
8158       return;
8159     }
8160
8161   priv = self->priv;
8162
8163   old_allocation = priv->allocation;
8164   real_allocation = *box;
8165
8166   /* constraints are allowed to modify the allocation only here; we do
8167    * this prior to all the other checks so that we can bail out if the
8168    * allocation did not change
8169    */
8170   clutter_actor_update_constraints (self, &real_allocation);
8171
8172   /* adjust the allocation depending on the align/margin properties */
8173   clutter_actor_adjust_allocation (self, &real_allocation);
8174
8175   if (real_allocation.x2 < real_allocation.x1 ||
8176       real_allocation.y2 < real_allocation.y1)
8177     {
8178       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8179                  _clutter_actor_get_debug_name (self),
8180                  real_allocation.x2 - real_allocation.x1,
8181                  real_allocation.y2 - real_allocation.y1);
8182     }
8183
8184   /* we allow 0-sized actors, but not negative-sized ones */
8185   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8186   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8187
8188   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8189
8190   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8191                  real_allocation.y1 != old_allocation.y1);
8192
8193   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8194                   real_allocation.y2 != old_allocation.y2);
8195
8196   if (origin_changed || child_moved || size_changed)
8197     stage_allocation_changed = TRUE;
8198   else
8199     stage_allocation_changed = FALSE;
8200
8201   /* If we get an allocation "out of the blue"
8202    * (we did not queue relayout), then we want to
8203    * ignore it. But if we have needs_allocation set,
8204    * we want to guarantee that allocate() virtual
8205    * method is always called, i.e. that queue_relayout()
8206    * always results in an allocate() invocation on
8207    * an actor.
8208    *
8209    * The optimization here is to avoid re-allocating
8210    * actors that did not queue relayout and were
8211    * not moved.
8212    */
8213   if (!priv->needs_allocation && !stage_allocation_changed)
8214     {
8215       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8216       return;
8217     }
8218
8219   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8220    * clutter_actor_allocate(), it indicates whether the parent has its
8221    * absolute origin moved; when passed in to ClutterActor::allocate()
8222    * virtual method though, it indicates whether the child has its
8223    * absolute origin moved.  So we set it when child_moved is TRUE
8224    */
8225   if (child_moved)
8226     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8227
8228   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8229
8230   klass = CLUTTER_ACTOR_GET_CLASS (self);
8231   klass->allocate (self, &real_allocation, flags);
8232
8233   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8234
8235   if (stage_allocation_changed)
8236     clutter_actor_queue_redraw (self);
8237 }
8238
8239 /**
8240  * clutter_actor_set_allocation:
8241  * @self: a #ClutterActor
8242  * @box: a #ClutterActorBox
8243  * @flags: allocation flags
8244  *
8245  * Stores the allocation of @self as defined by @box.
8246  *
8247  * This function can only be called from within the implementation of
8248  * the #ClutterActorClass.allocate() virtual function.
8249  *
8250  * The allocation should have been adjusted to take into account constraints,
8251  * alignment, and margin properties. If you are implementing a #ClutterActor
8252  * subclass that provides its own layout management policy for its children
8253  * instead of using a #ClutterLayoutManager delegate, you should not call
8254  * this function on the children of @self; instead, you should call
8255  * clutter_actor_allocate(), which will adjust the allocation box for
8256  * you.
8257  *
8258  * This function should only be used by subclasses of #ClutterActor
8259  * that wish to store their allocation but cannot chain up to the
8260  * parent's implementation; the default implementation of the
8261  * #ClutterActorClass.allocate() virtual function will call this
8262  * function.
8263  *
8264  * It is important to note that, while chaining up was the recommended
8265  * behaviour for #ClutterActor subclasses prior to the introduction of
8266  * this function, it is recommended to call clutter_actor_set_allocation()
8267  * instead.
8268  *
8269  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8270  * to handle the allocation of its children, this function will call
8271  * the clutter_layout_manager_allocate() function only if the
8272  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8273  * expected that the subclass will call clutter_layout_manager_allocate()
8274  * by itself. For instance, the following code:
8275  *
8276  * |[
8277  * static void
8278  * my_actor_allocate (ClutterActor *actor,
8279  *                    const ClutterActorBox *allocation,
8280  *                    ClutterAllocationFlags flags)
8281  * {
8282  *   ClutterActorBox new_alloc;
8283  *   ClutterAllocationFlags new_flags;
8284  *
8285  *   adjust_allocation (allocation, &amp;new_alloc);
8286  *
8287  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8288  *
8289  *   /&ast; this will use the layout manager set on the actor &ast;/
8290  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8291  * }
8292  * ]|
8293  *
8294  * is equivalent to this:
8295  *
8296  * |[
8297  * static void
8298  * my_actor_allocate (ClutterActor *actor,
8299  *                    const ClutterActorBox *allocation,
8300  *                    ClutterAllocationFlags flags)
8301  * {
8302  *   ClutterLayoutManager *layout;
8303  *   ClutterActorBox new_alloc;
8304  *
8305  *   adjust_allocation (allocation, &amp;new_alloc);
8306  *
8307  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8308  *
8309  *   layout = clutter_actor_get_layout_manager (actor);
8310  *   clutter_layout_manager_allocate (layout,
8311  *                                    CLUTTER_CONTAINER (actor),
8312  *                                    &amp;new_alloc,
8313  *                                    flags);
8314  * }
8315  * ]|
8316  *
8317  * Since: 1.10
8318  */
8319 void
8320 clutter_actor_set_allocation (ClutterActor           *self,
8321                               const ClutterActorBox  *box,
8322                               ClutterAllocationFlags  flags)
8323 {
8324   ClutterActorPrivate *priv;
8325   gboolean changed;
8326
8327   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8328   g_return_if_fail (box != NULL);
8329
8330   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8331     {
8332       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8333                   "can only be called from within the implementation of "
8334                   "the ClutterActor::allocate() virtual function.");
8335       return;
8336     }
8337
8338   priv = self->priv;
8339
8340   g_object_freeze_notify (G_OBJECT (self));
8341
8342   changed = clutter_actor_set_allocation_internal (self, box, flags);
8343
8344   /* we allocate our children before we notify changes in our geometry,
8345    * so that people connecting to properties will be able to get valid
8346    * data out of the sub-tree of the scene graph that has this actor at
8347    * the root.
8348    */
8349   clutter_actor_maybe_layout_children (self, box, flags);
8350
8351   if (changed)
8352     {
8353       ClutterActorBox signal_box = priv->allocation;
8354       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8355
8356       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8357                      &signal_box,
8358                      signal_flags);
8359     }
8360
8361   g_object_thaw_notify (G_OBJECT (self));
8362 }
8363
8364 /**
8365  * clutter_actor_set_geometry:
8366  * @self: A #ClutterActor
8367  * @geometry: A #ClutterGeometry
8368  *
8369  * Sets the actor's fixed position and forces its minimum and natural
8370  * size, in pixels. This means the untransformed actor will have the
8371  * given geometry. This is the same as calling clutter_actor_set_position()
8372  * and clutter_actor_set_size().
8373  *
8374  * Deprecated: 1.10: Use clutter_actor_set_position() and
8375  *   clutter_actor_set_size() instead.
8376  */
8377 void
8378 clutter_actor_set_geometry (ClutterActor          *self,
8379                             const ClutterGeometry *geometry)
8380 {
8381   g_object_freeze_notify (G_OBJECT (self));
8382
8383   clutter_actor_set_position (self, geometry->x, geometry->y);
8384   clutter_actor_set_size (self, geometry->width, geometry->height);
8385
8386   g_object_thaw_notify (G_OBJECT (self));
8387 }
8388
8389 /**
8390  * clutter_actor_get_geometry:
8391  * @self: A #ClutterActor
8392  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8393  *
8394  * Gets the size and position of an actor relative to its parent
8395  * actor. This is the same as calling clutter_actor_get_position() and
8396  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8397  * requested size and position if the actor's allocation is invalid.
8398  *
8399  * Deprecated: 1.10: Use clutter_actor_get_position() and
8400  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8401  *   instead.
8402  */
8403 void
8404 clutter_actor_get_geometry (ClutterActor    *self,
8405                             ClutterGeometry *geometry)
8406 {
8407   gfloat x, y, width, height;
8408
8409   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8410   g_return_if_fail (geometry != NULL);
8411
8412   clutter_actor_get_position (self, &x, &y);
8413   clutter_actor_get_size (self, &width, &height);
8414
8415   geometry->x = (int) x;
8416   geometry->y = (int) y;
8417   geometry->width = (int) width;
8418   geometry->height = (int) height;
8419 }
8420
8421 /**
8422  * clutter_actor_set_position:
8423  * @self: A #ClutterActor
8424  * @x: New left position of actor in pixels.
8425  * @y: New top position of actor in pixels.
8426  *
8427  * Sets the actor's fixed position in pixels relative to any parent
8428  * actor.
8429  *
8430  * If a layout manager is in use, this position will override the
8431  * layout manager and force a fixed position.
8432  */
8433 void
8434 clutter_actor_set_position (ClutterActor *self,
8435                             gfloat        x,
8436                             gfloat        y)
8437 {
8438   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8439
8440   g_object_freeze_notify (G_OBJECT (self));
8441
8442   clutter_actor_set_x (self, x);
8443   clutter_actor_set_y (self, y);
8444
8445   g_object_thaw_notify (G_OBJECT (self));
8446 }
8447
8448 /**
8449  * clutter_actor_get_fixed_position_set:
8450  * @self: A #ClutterActor
8451  *
8452  * Checks whether an actor has a fixed position set (and will thus be
8453  * unaffected by any layout manager).
8454  *
8455  * Return value: %TRUE if the fixed position is set on the actor
8456  *
8457  * Since: 0.8
8458  */
8459 gboolean
8460 clutter_actor_get_fixed_position_set (ClutterActor *self)
8461 {
8462   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8463
8464   return self->priv->position_set;
8465 }
8466
8467 /**
8468  * clutter_actor_set_fixed_position_set:
8469  * @self: A #ClutterActor
8470  * @is_set: whether to use fixed position
8471  *
8472  * Sets whether an actor has a fixed position set (and will thus be
8473  * unaffected by any layout manager).
8474  *
8475  * Since: 0.8
8476  */
8477 void
8478 clutter_actor_set_fixed_position_set (ClutterActor *self,
8479                                       gboolean      is_set)
8480 {
8481   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8482
8483   if (self->priv->position_set == (is_set != FALSE))
8484     return;
8485
8486   self->priv->position_set = is_set != FALSE;
8487   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8488
8489   clutter_actor_queue_relayout (self);
8490 }
8491
8492 /**
8493  * clutter_actor_move_by:
8494  * @self: A #ClutterActor
8495  * @dx: Distance to move Actor on X axis.
8496  * @dy: Distance to move Actor on Y axis.
8497  *
8498  * Moves an actor by the specified distance relative to its current
8499  * position in pixels.
8500  *
8501  * This function modifies the fixed position of an actor and thus removes
8502  * it from any layout management. Another way to move an actor is with an
8503  * anchor point, see clutter_actor_set_anchor_point().
8504  *
8505  * Since: 0.2
8506  */
8507 void
8508 clutter_actor_move_by (ClutterActor *self,
8509                        gfloat        dx,
8510                        gfloat        dy)
8511 {
8512   const ClutterLayoutInfo *info;
8513   gfloat x, y;
8514
8515   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8516
8517   info = _clutter_actor_get_layout_info_or_defaults (self);
8518   x = info->fixed_x;
8519   y = info->fixed_y;
8520
8521   clutter_actor_set_position (self, x + dx, y + dy);
8522 }
8523
8524 static void
8525 clutter_actor_set_min_width (ClutterActor *self,
8526                              gfloat        min_width)
8527 {
8528   ClutterActorPrivate *priv = self->priv;
8529   ClutterActorBox old = { 0, };
8530   ClutterLayoutInfo *info;
8531
8532   /* if we are setting the size on a top-level actor and the
8533    * backend only supports static top-levels (e.g. framebuffers)
8534    * then we ignore the passed value and we override it with
8535    * the stage implementation's preferred size.
8536    */
8537   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8538       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8539     return;
8540
8541   info = _clutter_actor_get_layout_info (self);
8542
8543   if (priv->min_width_set && min_width == info->min_width)
8544     return;
8545
8546   g_object_freeze_notify (G_OBJECT (self));
8547
8548   clutter_actor_store_old_geometry (self, &old);
8549
8550   info->min_width = min_width;
8551   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8552   clutter_actor_set_min_width_set (self, TRUE);
8553
8554   clutter_actor_notify_if_geometry_changed (self, &old);
8555
8556   g_object_thaw_notify (G_OBJECT (self));
8557
8558   clutter_actor_queue_relayout (self);
8559 }
8560
8561 static void
8562 clutter_actor_set_min_height (ClutterActor *self,
8563                               gfloat        min_height)
8564
8565 {
8566   ClutterActorPrivate *priv = self->priv;
8567   ClutterActorBox old = { 0, };
8568   ClutterLayoutInfo *info;
8569
8570   /* if we are setting the size on a top-level actor and the
8571    * backend only supports static top-levels (e.g. framebuffers)
8572    * then we ignore the passed value and we override it with
8573    * the stage implementation's preferred size.
8574    */
8575   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8576       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8577     return;
8578
8579   info = _clutter_actor_get_layout_info (self);
8580
8581   if (priv->min_height_set && min_height == info->min_height)
8582     return;
8583
8584   g_object_freeze_notify (G_OBJECT (self));
8585
8586   clutter_actor_store_old_geometry (self, &old);
8587
8588   info->min_height = min_height;
8589   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8590   clutter_actor_set_min_height_set (self, TRUE);
8591
8592   clutter_actor_notify_if_geometry_changed (self, &old);
8593
8594   g_object_thaw_notify (G_OBJECT (self));
8595
8596   clutter_actor_queue_relayout (self);
8597 }
8598
8599 static void
8600 clutter_actor_set_natural_width (ClutterActor *self,
8601                                  gfloat        natural_width)
8602 {
8603   ClutterActorPrivate *priv = self->priv;
8604   ClutterActorBox old = { 0, };
8605   ClutterLayoutInfo *info;
8606
8607   /* if we are setting the size on a top-level actor and the
8608    * backend only supports static top-levels (e.g. framebuffers)
8609    * then we ignore the passed value and we override it with
8610    * the stage implementation's preferred size.
8611    */
8612   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8613       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8614     return;
8615
8616   info = _clutter_actor_get_layout_info (self);
8617
8618   if (priv->natural_width_set && natural_width == info->natural_width)
8619     return;
8620
8621   g_object_freeze_notify (G_OBJECT (self));
8622
8623   clutter_actor_store_old_geometry (self, &old);
8624
8625   info->natural_width = natural_width;
8626   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8627   clutter_actor_set_natural_width_set (self, TRUE);
8628
8629   clutter_actor_notify_if_geometry_changed (self, &old);
8630
8631   g_object_thaw_notify (G_OBJECT (self));
8632
8633   clutter_actor_queue_relayout (self);
8634 }
8635
8636 static void
8637 clutter_actor_set_natural_height (ClutterActor *self,
8638                                   gfloat        natural_height)
8639 {
8640   ClutterActorPrivate *priv = self->priv;
8641   ClutterActorBox old = { 0, };
8642   ClutterLayoutInfo *info;
8643
8644   /* if we are setting the size on a top-level actor and the
8645    * backend only supports static top-levels (e.g. framebuffers)
8646    * then we ignore the passed value and we override it with
8647    * the stage implementation's preferred size.
8648    */
8649   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8650       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8651     return;
8652
8653   info = _clutter_actor_get_layout_info (self);
8654
8655   if (priv->natural_height_set && natural_height == info->natural_height)
8656     return;
8657
8658   g_object_freeze_notify (G_OBJECT (self));
8659
8660   clutter_actor_store_old_geometry (self, &old);
8661
8662   info->natural_height = natural_height;
8663   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8664   clutter_actor_set_natural_height_set (self, TRUE);
8665
8666   clutter_actor_notify_if_geometry_changed (self, &old);
8667
8668   g_object_thaw_notify (G_OBJECT (self));
8669
8670   clutter_actor_queue_relayout (self);
8671 }
8672
8673 static void
8674 clutter_actor_set_min_width_set (ClutterActor *self,
8675                                  gboolean      use_min_width)
8676 {
8677   ClutterActorPrivate *priv = self->priv;
8678   ClutterActorBox old = { 0, };
8679
8680   if (priv->min_width_set == (use_min_width != FALSE))
8681     return;
8682
8683   clutter_actor_store_old_geometry (self, &old);
8684
8685   priv->min_width_set = use_min_width != FALSE;
8686   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8687
8688   clutter_actor_notify_if_geometry_changed (self, &old);
8689
8690   clutter_actor_queue_relayout (self);
8691 }
8692
8693 static void
8694 clutter_actor_set_min_height_set (ClutterActor *self,
8695                                   gboolean      use_min_height)
8696 {
8697   ClutterActorPrivate *priv = self->priv;
8698   ClutterActorBox old = { 0, };
8699
8700   if (priv->min_height_set == (use_min_height != FALSE))
8701     return;
8702
8703   clutter_actor_store_old_geometry (self, &old);
8704
8705   priv->min_height_set = use_min_height != FALSE;
8706   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8707
8708   clutter_actor_notify_if_geometry_changed (self, &old);
8709
8710   clutter_actor_queue_relayout (self);
8711 }
8712
8713 static void
8714 clutter_actor_set_natural_width_set (ClutterActor *self,
8715                                      gboolean      use_natural_width)
8716 {
8717   ClutterActorPrivate *priv = self->priv;
8718   ClutterActorBox old = { 0, };
8719
8720   if (priv->natural_width_set == (use_natural_width != FALSE))
8721     return;
8722
8723   clutter_actor_store_old_geometry (self, &old);
8724
8725   priv->natural_width_set = use_natural_width != FALSE;
8726   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8727
8728   clutter_actor_notify_if_geometry_changed (self, &old);
8729
8730   clutter_actor_queue_relayout (self);
8731 }
8732
8733 static void
8734 clutter_actor_set_natural_height_set (ClutterActor *self,
8735                                       gboolean      use_natural_height)
8736 {
8737   ClutterActorPrivate *priv = self->priv;
8738   ClutterActorBox old = { 0, };
8739
8740   if (priv->natural_height_set == (use_natural_height != FALSE))
8741     return;
8742
8743   clutter_actor_store_old_geometry (self, &old);
8744
8745   priv->natural_height_set = use_natural_height != FALSE;
8746   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8747
8748   clutter_actor_notify_if_geometry_changed (self, &old);
8749
8750   clutter_actor_queue_relayout (self);
8751 }
8752
8753 /**
8754  * clutter_actor_set_request_mode:
8755  * @self: a #ClutterActor
8756  * @mode: the request mode
8757  *
8758  * Sets the geometry request mode of @self.
8759  *
8760  * The @mode determines the order for invoking
8761  * clutter_actor_get_preferred_width() and
8762  * clutter_actor_get_preferred_height()
8763  *
8764  * Since: 1.2
8765  */
8766 void
8767 clutter_actor_set_request_mode (ClutterActor       *self,
8768                                 ClutterRequestMode  mode)
8769 {
8770   ClutterActorPrivate *priv;
8771
8772   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8773
8774   priv = self->priv;
8775
8776   if (priv->request_mode == mode)
8777     return;
8778
8779   priv->request_mode = mode;
8780
8781   priv->needs_width_request = TRUE;
8782   priv->needs_height_request = TRUE;
8783
8784   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8785
8786   clutter_actor_queue_relayout (self);
8787 }
8788
8789 /**
8790  * clutter_actor_get_request_mode:
8791  * @self: a #ClutterActor
8792  *
8793  * Retrieves the geometry request mode of @self
8794  *
8795  * Return value: the request mode for the actor
8796  *
8797  * Since: 1.2
8798  */
8799 ClutterRequestMode
8800 clutter_actor_get_request_mode (ClutterActor *self)
8801 {
8802   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8803                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8804
8805   return self->priv->request_mode;
8806 }
8807
8808 /* variant of set_width() without checks and without notification
8809  * freeze+thaw, for internal usage only
8810  */
8811 static inline void
8812 clutter_actor_set_width_internal (ClutterActor *self,
8813                                   gfloat        width)
8814 {
8815   if (width >= 0)
8816     {
8817       /* the Stage will use the :min-width to control the minimum
8818        * width to be resized to, so we should not be setting it
8819        * along with the :natural-width
8820        */
8821       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8822         clutter_actor_set_min_width (self, width);
8823
8824       clutter_actor_set_natural_width (self, width);
8825     }
8826   else
8827     {
8828       /* we only unset the :natural-width for the Stage */
8829       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8830         clutter_actor_set_min_width_set (self, FALSE);
8831
8832       clutter_actor_set_natural_width_set (self, FALSE);
8833     }
8834 }
8835
8836 /* variant of set_height() without checks and without notification
8837  * freeze+thaw, for internal usage only
8838  */
8839 static inline void
8840 clutter_actor_set_height_internal (ClutterActor *self,
8841                                    gfloat        height)
8842 {
8843   if (height >= 0)
8844     {
8845       /* see the comment above in set_width_internal() */
8846       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8847         clutter_actor_set_min_height (self, height);
8848
8849       clutter_actor_set_natural_height (self, height);
8850     }
8851   else
8852     {
8853       /* see the comment above in set_width_internal() */
8854       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8855         clutter_actor_set_min_height_set (self, FALSE);
8856
8857       clutter_actor_set_natural_height_set (self, FALSE);
8858     }
8859 }
8860
8861 /**
8862  * clutter_actor_set_size:
8863  * @self: A #ClutterActor
8864  * @width: New width of actor in pixels, or -1
8865  * @height: New height of actor in pixels, or -1
8866  *
8867  * Sets the actor's size request in pixels. This overrides any
8868  * "normal" size request the actor would have. For example
8869  * a text actor might normally request the size of the text;
8870  * this function would force a specific size instead.
8871  *
8872  * If @width and/or @height are -1 the actor will use its
8873  * "normal" size request instead of overriding it, i.e.
8874  * you can "unset" the size with -1.
8875  *
8876  * This function sets or unsets both the minimum and natural size.
8877  */
8878 void
8879 clutter_actor_set_size (ClutterActor *self,
8880                         gfloat        width,
8881                         gfloat        height)
8882 {
8883   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8884
8885   g_object_freeze_notify (G_OBJECT (self));
8886
8887   clutter_actor_set_width (self, width);
8888   clutter_actor_set_height (self, height);
8889
8890   g_object_thaw_notify (G_OBJECT (self));
8891 }
8892
8893 /**
8894  * clutter_actor_get_size:
8895  * @self: A #ClutterActor
8896  * @width: (out) (allow-none): return location for the width, or %NULL.
8897  * @height: (out) (allow-none): return location for the height, or %NULL.
8898  *
8899  * This function tries to "do what you mean" and return
8900  * the size an actor will have. If the actor has a valid
8901  * allocation, the allocation will be returned; otherwise,
8902  * the actors natural size request will be returned.
8903  *
8904  * If you care whether you get the request vs. the allocation, you
8905  * should probably call a different function like
8906  * clutter_actor_get_allocation_box() or
8907  * clutter_actor_get_preferred_width().
8908  *
8909  * Since: 0.2
8910  */
8911 void
8912 clutter_actor_get_size (ClutterActor *self,
8913                         gfloat       *width,
8914                         gfloat       *height)
8915 {
8916   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8917
8918   if (width)
8919     *width = clutter_actor_get_width (self);
8920
8921   if (height)
8922     *height = clutter_actor_get_height (self);
8923 }
8924
8925 /**
8926  * clutter_actor_get_position:
8927  * @self: a #ClutterActor
8928  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8929  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8930  *
8931  * This function tries to "do what you mean" and tell you where the
8932  * actor is, prior to any transformations. Retrieves the fixed
8933  * position of an actor in pixels, if one has been set; otherwise, if
8934  * the allocation is valid, returns the actor's allocated position;
8935  * otherwise, returns 0,0.
8936  *
8937  * The returned position is in pixels.
8938  *
8939  * Since: 0.6
8940  */
8941 void
8942 clutter_actor_get_position (ClutterActor *self,
8943                             gfloat       *x,
8944                             gfloat       *y)
8945 {
8946   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8947
8948   if (x)
8949     *x = clutter_actor_get_x (self);
8950
8951   if (y)
8952     *y = clutter_actor_get_y (self);
8953 }
8954
8955 /**
8956  * clutter_actor_get_transformed_position:
8957  * @self: A #ClutterActor
8958  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8959  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8960  *
8961  * Gets the absolute position of an actor, in pixels relative to the stage.
8962  *
8963  * Since: 0.8
8964  */
8965 void
8966 clutter_actor_get_transformed_position (ClutterActor *self,
8967                                         gfloat       *x,
8968                                         gfloat       *y)
8969 {
8970   ClutterVertex v1;
8971   ClutterVertex v2;
8972
8973   v1.x = v1.y = v1.z = 0;
8974   clutter_actor_apply_transform_to_point (self, &v1, &v2);
8975
8976   if (x)
8977     *x = v2.x;
8978
8979   if (y)
8980     *y = v2.y;
8981 }
8982
8983 /**
8984  * clutter_actor_get_transformed_size:
8985  * @self: A #ClutterActor
8986  * @width: (out) (allow-none): return location for the width, or %NULL
8987  * @height: (out) (allow-none): return location for the height, or %NULL
8988  *
8989  * Gets the absolute size of an actor in pixels, taking into account the
8990  * scaling factors.
8991  *
8992  * If the actor has a valid allocation, the allocated size will be used.
8993  * If the actor has not a valid allocation then the preferred size will
8994  * be transformed and returned.
8995  *
8996  * If you want the transformed allocation, see
8997  * clutter_actor_get_abs_allocation_vertices() instead.
8998  *
8999  * <note>When the actor (or one of its ancestors) is rotated around the
9000  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9001  * as a generic quadrangle; in that case this function returns the size
9002  * of the smallest rectangle that encapsulates the entire quad. Please
9003  * note that in this case no assumptions can be made about the relative
9004  * position of this envelope to the absolute position of the actor, as
9005  * returned by clutter_actor_get_transformed_position(); if you need this
9006  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9007  * to get the coords of the actual quadrangle.</note>
9008  *
9009  * Since: 0.8
9010  */
9011 void
9012 clutter_actor_get_transformed_size (ClutterActor *self,
9013                                     gfloat       *width,
9014                                     gfloat       *height)
9015 {
9016   ClutterActorPrivate *priv;
9017   ClutterVertex v[4];
9018   gfloat x_min, x_max, y_min, y_max;
9019   gint i;
9020
9021   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9022
9023   priv = self->priv;
9024
9025   /* if the actor hasn't been allocated yet, get the preferred
9026    * size and transform that
9027    */
9028   if (priv->needs_allocation)
9029     {
9030       gfloat natural_width, natural_height;
9031       ClutterActorBox box;
9032
9033       /* Make a fake allocation to transform.
9034        *
9035        * NB: _clutter_actor_transform_and_project_box expects a box in
9036        * the actor's coordinate space... */
9037
9038       box.x1 = 0;
9039       box.y1 = 0;
9040
9041       natural_width = natural_height = 0;
9042       clutter_actor_get_preferred_size (self, NULL, NULL,
9043                                         &natural_width,
9044                                         &natural_height);
9045
9046       box.x2 = natural_width;
9047       box.y2 = natural_height;
9048
9049       _clutter_actor_transform_and_project_box (self, &box, v);
9050     }
9051   else
9052     clutter_actor_get_abs_allocation_vertices (self, v);
9053
9054   x_min = x_max = v[0].x;
9055   y_min = y_max = v[0].y;
9056
9057   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9058     {
9059       if (v[i].x < x_min)
9060         x_min = v[i].x;
9061
9062       if (v[i].x > x_max)
9063         x_max = v[i].x;
9064
9065       if (v[i].y < y_min)
9066         y_min = v[i].y;
9067
9068       if (v[i].y > y_max)
9069         y_max = v[i].y;
9070     }
9071
9072   if (width)
9073     *width  = x_max - x_min;
9074
9075   if (height)
9076     *height = y_max - y_min;
9077 }
9078
9079 /**
9080  * clutter_actor_get_width:
9081  * @self: A #ClutterActor
9082  *
9083  * Retrieves the width of a #ClutterActor.
9084  *
9085  * If the actor has a valid allocation, this function will return the
9086  * width of the allocated area given to the actor.
9087  *
9088  * If the actor does not have a valid allocation, this function will
9089  * return the actor's natural width, that is the preferred width of
9090  * the actor.
9091  *
9092  * If you care whether you get the preferred width or the width that
9093  * has been assigned to the actor, you should probably call a different
9094  * function like clutter_actor_get_allocation_box() to retrieve the
9095  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9096  * preferred width.
9097  *
9098  * If an actor has a fixed width, for instance a width that has been
9099  * assigned using clutter_actor_set_width(), the width returned will
9100  * be the same value.
9101  *
9102  * Return value: the width of the actor, in pixels
9103  */
9104 gfloat
9105 clutter_actor_get_width (ClutterActor *self)
9106 {
9107   ClutterActorPrivate *priv;
9108
9109   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9110
9111   priv = self->priv;
9112
9113   if (priv->needs_allocation)
9114     {
9115       gfloat natural_width = 0;
9116
9117       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9118         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9119       else
9120         {
9121           gfloat natural_height = 0;
9122
9123           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9124           clutter_actor_get_preferred_width (self, natural_height,
9125                                              NULL,
9126                                              &natural_width);
9127         }
9128
9129       return natural_width;
9130     }
9131   else
9132     return priv->allocation.x2 - priv->allocation.x1;
9133 }
9134
9135 /**
9136  * clutter_actor_get_height:
9137  * @self: A #ClutterActor
9138  *
9139  * Retrieves the height of a #ClutterActor.
9140  *
9141  * If the actor has a valid allocation, this function will return the
9142  * height of the allocated area given to the actor.
9143  *
9144  * If the actor does not have a valid allocation, this function will
9145  * return the actor's natural height, that is the preferred height of
9146  * the actor.
9147  *
9148  * If you care whether you get the preferred height or the height that
9149  * has been assigned to the actor, you should probably call a different
9150  * function like clutter_actor_get_allocation_box() to retrieve the
9151  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9152  * preferred height.
9153  *
9154  * If an actor has a fixed height, for instance a height that has been
9155  * assigned using clutter_actor_set_height(), the height returned will
9156  * be the same value.
9157  *
9158  * Return value: the height of the actor, in pixels
9159  */
9160 gfloat
9161 clutter_actor_get_height (ClutterActor *self)
9162 {
9163   ClutterActorPrivate *priv;
9164
9165   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9166
9167   priv = self->priv;
9168
9169   if (priv->needs_allocation)
9170     {
9171       gfloat natural_height = 0;
9172
9173       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9174         {
9175           gfloat natural_width = 0;
9176
9177           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9178           clutter_actor_get_preferred_height (self, natural_width,
9179                                               NULL, &natural_height);
9180         }
9181       else
9182         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9183
9184       return natural_height;
9185     }
9186   else
9187     return priv->allocation.y2 - priv->allocation.y1;
9188 }
9189
9190 /**
9191  * clutter_actor_set_width:
9192  * @self: A #ClutterActor
9193  * @width: Requested new width for the actor, in pixels, or -1
9194  *
9195  * Forces a width on an actor, causing the actor's preferred width
9196  * and height (if any) to be ignored.
9197  *
9198  * If @width is -1 the actor will use its preferred width request
9199  * instead of overriding it, i.e. you can "unset" the width with -1.
9200  *
9201  * This function sets both the minimum and natural size of the actor.
9202  *
9203  * since: 0.2
9204  */
9205 void
9206 clutter_actor_set_width (ClutterActor *self,
9207                          gfloat        width)
9208 {
9209   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9210
9211   if (clutter_actor_get_easing_duration (self) != 0)
9212     {
9213       ClutterTransition *transition;
9214
9215       transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9216       if (transition == NULL)
9217         {
9218           float old_width = clutter_actor_get_width (self);
9219
9220           transition = _clutter_actor_create_transition (self,
9221                                                          obj_props[PROP_WIDTH],
9222                                                          old_width,
9223                                                          width);
9224           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9225         }
9226       else
9227         _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9228
9229       clutter_actor_queue_relayout (self);
9230     }
9231   else
9232     {
9233       g_object_freeze_notify (G_OBJECT (self));
9234
9235       clutter_actor_set_width_internal (self, width);
9236
9237       g_object_thaw_notify (G_OBJECT (self));
9238     }
9239 }
9240
9241 /**
9242  * clutter_actor_set_height:
9243  * @self: A #ClutterActor
9244  * @height: Requested new height for the actor, in pixels, or -1
9245  *
9246  * Forces a height on an actor, causing the actor's preferred width
9247  * and height (if any) to be ignored.
9248  *
9249  * If @height is -1 the actor will use its preferred height instead of
9250  * overriding it, i.e. you can "unset" the height with -1.
9251  *
9252  * This function sets both the minimum and natural size of the actor.
9253  *
9254  * since: 0.2
9255  */
9256 void
9257 clutter_actor_set_height (ClutterActor *self,
9258                           gfloat        height)
9259 {
9260   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9261
9262   if (clutter_actor_get_easing_duration (self) != 0)
9263     {
9264       ClutterTransition *transition;
9265
9266       transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9267       if (transition ==  NULL)
9268         {
9269           float old_height = clutter_actor_get_height (self);
9270
9271           transition = _clutter_actor_create_transition (self,
9272                                                          obj_props[PROP_HEIGHT],
9273                                                          old_height,
9274                                                          height);
9275           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9276         }
9277       else
9278         _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9279
9280       clutter_actor_queue_relayout (self);
9281     }
9282   else
9283     {
9284       g_object_freeze_notify (G_OBJECT (self));
9285
9286       clutter_actor_set_height_internal (self, height);
9287
9288       g_object_thaw_notify (G_OBJECT (self));
9289     }
9290 }
9291
9292 static inline void
9293 clutter_actor_set_x_internal (ClutterActor *self,
9294                               float         x)
9295 {
9296   ClutterActorPrivate *priv = self->priv;
9297   ClutterLayoutInfo *linfo;
9298   ClutterActorBox old = { 0, };
9299
9300   linfo = _clutter_actor_get_layout_info (self);
9301
9302   if (priv->position_set && linfo->fixed_x == x)
9303     return;
9304
9305   clutter_actor_store_old_geometry (self, &old);
9306
9307   linfo->fixed_x = x;
9308   clutter_actor_set_fixed_position_set (self, TRUE);
9309
9310   clutter_actor_notify_if_geometry_changed (self, &old);
9311
9312   clutter_actor_queue_relayout (self);
9313 }
9314
9315 static inline void
9316 clutter_actor_set_y_internal (ClutterActor *self,
9317                               float         y)
9318 {
9319   ClutterActorPrivate *priv = self->priv;
9320   ClutterLayoutInfo *linfo;
9321   ClutterActorBox old = { 0, };
9322
9323   linfo = _clutter_actor_get_layout_info (self);
9324
9325   if (priv->position_set && linfo->fixed_y == y)
9326     return;
9327
9328   clutter_actor_store_old_geometry (self, &old);
9329
9330   linfo->fixed_y = y;
9331   clutter_actor_set_fixed_position_set (self, TRUE);
9332
9333   clutter_actor_notify_if_geometry_changed (self, &old);
9334 }
9335
9336 /**
9337  * clutter_actor_set_x:
9338  * @self: a #ClutterActor
9339  * @x: the actor's position on the X axis
9340  *
9341  * Sets the actor's X coordinate, relative to its parent, in pixels.
9342  *
9343  * Overrides any layout manager and forces a fixed position for
9344  * the actor.
9345  *
9346  * The #ClutterActor:x property is animatable.
9347  *
9348  * Since: 0.6
9349  */
9350 void
9351 clutter_actor_set_x (ClutterActor *self,
9352                      gfloat        x)
9353 {
9354   const ClutterLayoutInfo *linfo;
9355
9356   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9357
9358   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9359
9360   if (clutter_actor_get_easing_duration (self) != 0)
9361     {
9362       ClutterTransition *transition;
9363
9364       transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9365       if (transition == NULL)
9366         {
9367           transition = _clutter_actor_create_transition (self,
9368                                                          obj_props[PROP_X],
9369                                                          linfo->fixed_x,
9370                                                          x);
9371
9372           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9373         }
9374       else
9375         _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9376
9377       clutter_actor_queue_relayout (self);
9378     }
9379   else
9380     clutter_actor_set_x_internal (self, x);
9381 }
9382
9383 /**
9384  * clutter_actor_set_y:
9385  * @self: a #ClutterActor
9386  * @y: the actor's position on the Y axis
9387  *
9388  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9389  *
9390  * Overrides any layout manager and forces a fixed position for
9391  * the actor.
9392  *
9393  * The #ClutterActor:y property is animatable.
9394  *
9395  * Since: 0.6
9396  */
9397 void
9398 clutter_actor_set_y (ClutterActor *self,
9399                      gfloat        y)
9400 {
9401   const ClutterLayoutInfo *linfo;
9402
9403   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9404
9405   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9406
9407   if (clutter_actor_get_easing_duration (self) != 0)
9408     {
9409       ClutterTransition *transition;
9410
9411       transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9412       if (transition == NULL)
9413         {
9414           transition = _clutter_actor_create_transition (self,
9415                                                          obj_props[PROP_Y],
9416                                                          linfo->fixed_y,
9417                                                          y);
9418
9419           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9420         }
9421       else
9422         _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9423
9424       clutter_actor_queue_relayout (self);
9425     }
9426   else
9427     clutter_actor_set_y_internal (self, y);
9428
9429   clutter_actor_queue_relayout (self);
9430 }
9431
9432 /**
9433  * clutter_actor_get_x:
9434  * @self: A #ClutterActor
9435  *
9436  * Retrieves the X coordinate of a #ClutterActor.
9437  *
9438  * This function tries to "do what you mean", by returning the
9439  * correct value depending on the actor's state.
9440  *
9441  * If the actor has a valid allocation, this function will return
9442  * the X coordinate of the origin of the allocation box.
9443  *
9444  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9445  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9446  * function will return that coordinate.
9447  *
9448  * If both the allocation and a fixed position are missing, this function
9449  * will return 0.
9450  *
9451  * Return value: the X coordinate, in pixels, ignoring any
9452  *   transformation (i.e. scaling, rotation)
9453  */
9454 gfloat
9455 clutter_actor_get_x (ClutterActor *self)
9456 {
9457   ClutterActorPrivate *priv;
9458
9459   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9460
9461   priv = self->priv;
9462
9463   if (priv->needs_allocation)
9464     {
9465       if (priv->position_set)
9466         {
9467           const ClutterLayoutInfo *info;
9468
9469           info = _clutter_actor_get_layout_info_or_defaults (self);
9470
9471           return info->fixed_x;
9472         }
9473       else
9474         return 0;
9475     }
9476   else
9477     return priv->allocation.x1;
9478 }
9479
9480 /**
9481  * clutter_actor_get_y:
9482  * @self: A #ClutterActor
9483  *
9484  * Retrieves the Y coordinate of a #ClutterActor.
9485  *
9486  * This function tries to "do what you mean", by returning the
9487  * correct value depending on the actor's state.
9488  *
9489  * If the actor has a valid allocation, this function will return
9490  * the Y coordinate of the origin of the allocation box.
9491  *
9492  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9493  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9494  * function will return that coordinate.
9495  *
9496  * If both the allocation and a fixed position are missing, this function
9497  * will return 0.
9498  *
9499  * Return value: the Y coordinate, in pixels, ignoring any
9500  *   transformation (i.e. scaling, rotation)
9501  */
9502 gfloat
9503 clutter_actor_get_y (ClutterActor *self)
9504 {
9505   ClutterActorPrivate *priv;
9506
9507   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9508
9509   priv = self->priv;
9510
9511   if (priv->needs_allocation)
9512     {
9513       if (priv->position_set)
9514         {
9515           const ClutterLayoutInfo *info;
9516
9517           info = _clutter_actor_get_layout_info_or_defaults (self);
9518
9519           return info->fixed_y;
9520         }
9521       else
9522         return 0;
9523     }
9524   else
9525     return priv->allocation.y1;
9526 }
9527
9528 /**
9529  * clutter_actor_set_scale:
9530  * @self: A #ClutterActor
9531  * @scale_x: double factor to scale actor by horizontally.
9532  * @scale_y: double factor to scale actor by vertically.
9533  *
9534  * Scales an actor with the given factors. The scaling is relative to
9535  * the scale center and the anchor point. The scale center is
9536  * unchanged by this function and defaults to 0,0.
9537  *
9538  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9539  * animatable.
9540  *
9541  * Since: 0.2
9542  */
9543 void
9544 clutter_actor_set_scale (ClutterActor *self,
9545                          gdouble       scale_x,
9546                          gdouble       scale_y)
9547 {
9548   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9549
9550   g_object_freeze_notify (G_OBJECT (self));
9551
9552   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9553   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9554
9555   g_object_thaw_notify (G_OBJECT (self));
9556 }
9557
9558 /**
9559  * clutter_actor_set_scale_full:
9560  * @self: A #ClutterActor
9561  * @scale_x: double factor to scale actor by horizontally.
9562  * @scale_y: double factor to scale actor by vertically.
9563  * @center_x: X coordinate of the center of the scale.
9564  * @center_y: Y coordinate of the center of the scale
9565  *
9566  * Scales an actor with the given factors around the given center
9567  * point. The center point is specified in pixels relative to the
9568  * anchor point (usually the top left corner of the actor).
9569  *
9570  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9571  * are animatable.
9572  *
9573  * Since: 1.0
9574  */
9575 void
9576 clutter_actor_set_scale_full (ClutterActor *self,
9577                               gdouble       scale_x,
9578                               gdouble       scale_y,
9579                               gfloat        center_x,
9580                               gfloat        center_y)
9581 {
9582   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9583
9584   g_object_freeze_notify (G_OBJECT (self));
9585
9586   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9587   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9588   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9589   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9590
9591   g_object_thaw_notify (G_OBJECT (self));
9592 }
9593
9594 /**
9595  * clutter_actor_set_scale_with_gravity:
9596  * @self: A #ClutterActor
9597  * @scale_x: double factor to scale actor by horizontally.
9598  * @scale_y: double factor to scale actor by vertically.
9599  * @gravity: the location of the scale center expressed as a compass
9600  * direction.
9601  *
9602  * Scales an actor with the given factors around the given
9603  * center point. The center point is specified as one of the compass
9604  * directions in #ClutterGravity. For example, setting it to north
9605  * will cause the top of the actor to remain unchanged and the rest of
9606  * the actor to expand left, right and downwards.
9607  *
9608  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9609  * animatable.
9610  *
9611  * Since: 1.0
9612  */
9613 void
9614 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9615                                       gdouble         scale_x,
9616                                       gdouble         scale_y,
9617                                       ClutterGravity  gravity)
9618 {
9619   ClutterTransformInfo *info;
9620   GObject *obj;
9621
9622   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9623
9624   obj = G_OBJECT (self);
9625
9626   g_object_freeze_notify (obj);
9627
9628   info = _clutter_actor_get_transform_info (self);
9629   info->scale_x = scale_x;
9630   info->scale_y = scale_y;
9631
9632   if (gravity == CLUTTER_GRAVITY_NONE)
9633     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9634   else
9635     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9636
9637   self->priv->transform_valid = FALSE;
9638
9639   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9640   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9641   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9642   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9643   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9644
9645   clutter_actor_queue_redraw (self);
9646
9647   g_object_thaw_notify (obj);
9648 }
9649
9650 /**
9651  * clutter_actor_get_scale:
9652  * @self: A #ClutterActor
9653  * @scale_x: (out) (allow-none): Location to store horizonal
9654  *   scale factor, or %NULL.
9655  * @scale_y: (out) (allow-none): Location to store vertical
9656  *   scale factor, or %NULL.
9657  *
9658  * Retrieves an actors scale factors.
9659  *
9660  * Since: 0.2
9661  */
9662 void
9663 clutter_actor_get_scale (ClutterActor *self,
9664                          gdouble      *scale_x,
9665                          gdouble      *scale_y)
9666 {
9667   const ClutterTransformInfo *info;
9668
9669   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9670
9671   info = _clutter_actor_get_transform_info_or_defaults (self);
9672
9673   if (scale_x)
9674     *scale_x = info->scale_x;
9675
9676   if (scale_y)
9677     *scale_y = info->scale_y;
9678 }
9679
9680 /**
9681  * clutter_actor_get_scale_center:
9682  * @self: A #ClutterActor
9683  * @center_x: (out) (allow-none): Location to store the X position
9684  *   of the scale center, or %NULL.
9685  * @center_y: (out) (allow-none): Location to store the Y position
9686  *   of the scale center, or %NULL.
9687  *
9688  * Retrieves the scale center coordinate in pixels relative to the top
9689  * left corner of the actor. If the scale center was specified using a
9690  * #ClutterGravity this will calculate the pixel offset using the
9691  * current size of the actor.
9692  *
9693  * Since: 1.0
9694  */
9695 void
9696 clutter_actor_get_scale_center (ClutterActor *self,
9697                                 gfloat       *center_x,
9698                                 gfloat       *center_y)
9699 {
9700   const ClutterTransformInfo *info;
9701
9702   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9703
9704   info = _clutter_actor_get_transform_info_or_defaults (self);
9705
9706   clutter_anchor_coord_get_units (self, &info->scale_center,
9707                                   center_x,
9708                                   center_y,
9709                                   NULL);
9710 }
9711
9712 /**
9713  * clutter_actor_get_scale_gravity:
9714  * @self: A #ClutterActor
9715  *
9716  * Retrieves the scale center as a compass direction. If the scale
9717  * center was specified in pixels or units this will return
9718  * %CLUTTER_GRAVITY_NONE.
9719  *
9720  * Return value: the scale gravity
9721  *
9722  * Since: 1.0
9723  */
9724 ClutterGravity
9725 clutter_actor_get_scale_gravity (ClutterActor *self)
9726 {
9727   const ClutterTransformInfo *info;
9728
9729   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9730
9731   info = _clutter_actor_get_transform_info_or_defaults (self);
9732
9733   return clutter_anchor_coord_get_gravity (&info->scale_center);
9734 }
9735
9736 static inline void
9737 clutter_actor_set_opacity_internal (ClutterActor *self,
9738                                     guint8        opacity)
9739 {
9740   ClutterActorPrivate *priv = self->priv;
9741
9742   if (priv->opacity != opacity)
9743     {
9744       priv->opacity = opacity;
9745
9746       /* Queue a redraw from the flatten effect so that it can use
9747          its cached image if available instead of having to redraw the
9748          actual actor. If it doesn't end up using the FBO then the
9749          effect is still able to continue the paint anyway. If there
9750          is no flatten effect yet then this is equivalent to queueing
9751          a full redraw */
9752       _clutter_actor_queue_redraw_full (self,
9753                                         0, /* flags */
9754                                         NULL, /* clip */
9755                                         priv->flatten_effect);
9756
9757       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9758     }
9759 }
9760
9761 /**
9762  * clutter_actor_set_opacity:
9763  * @self: A #ClutterActor
9764  * @opacity: New opacity value for the actor.
9765  *
9766  * Sets the actor's opacity, with zero being completely transparent and
9767  * 255 (0xff) being fully opaque.
9768  *
9769  * The #ClutterActor:opacity property is animatable.
9770  */
9771 void
9772 clutter_actor_set_opacity (ClutterActor *self,
9773                            guint8        opacity)
9774 {
9775   ClutterActorPrivate *priv;
9776
9777   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9778
9779   priv = self->priv;
9780
9781   if (clutter_actor_get_easing_duration (self) != 0)
9782     {
9783       ClutterTransition *transition;
9784
9785       transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9786       if (transition == NULL)
9787         {
9788           transition = _clutter_actor_create_transition (self,
9789                                                          obj_props[PROP_OPACITY],
9790                                                          priv->opacity,
9791                                                          opacity);
9792           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9793         }
9794       else
9795         _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9796
9797       clutter_actor_queue_redraw (self);
9798     }
9799   else
9800     clutter_actor_set_opacity_internal (self, opacity);
9801 }
9802
9803 /*
9804  * clutter_actor_get_paint_opacity_internal:
9805  * @self: a #ClutterActor
9806  *
9807  * Retrieves the absolute opacity of the actor, as it appears on the stage
9808  *
9809  * This function does not do type checks
9810  *
9811  * Return value: the absolute opacity of the actor
9812  */
9813 static guint8
9814 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9815 {
9816   ClutterActorPrivate *priv = self->priv;
9817   ClutterActor *parent;
9818
9819   /* override the top-level opacity to always be 255; even in
9820    * case of ClutterStage:use-alpha being TRUE we want the rest
9821    * of the scene to be painted
9822    */
9823   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9824     return 255;
9825
9826   if (priv->opacity_override >= 0)
9827     return priv->opacity_override;
9828
9829   parent = priv->parent;
9830
9831   /* Factor in the actual actors opacity with parents */
9832   if (parent != NULL)
9833     {
9834       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9835
9836       if (opacity != 0xff)
9837         return (opacity * priv->opacity) / 0xff;
9838     }
9839
9840   return priv->opacity;
9841
9842 }
9843
9844 /**
9845  * clutter_actor_get_paint_opacity:
9846  * @self: A #ClutterActor
9847  *
9848  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9849  *
9850  * This function traverses the hierarchy chain and composites the opacity of
9851  * the actor with that of its parents.
9852  *
9853  * This function is intended for subclasses to use in the paint virtual
9854  * function, to paint themselves with the correct opacity.
9855  *
9856  * Return value: The actor opacity value.
9857  *
9858  * Since: 0.8
9859  */
9860 guint8
9861 clutter_actor_get_paint_opacity (ClutterActor *self)
9862 {
9863   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9864
9865   return clutter_actor_get_paint_opacity_internal (self);
9866 }
9867
9868 /**
9869  * clutter_actor_get_opacity:
9870  * @self: a #ClutterActor
9871  *
9872  * Retrieves the opacity value of an actor, as set by
9873  * clutter_actor_set_opacity().
9874  *
9875  * For retrieving the absolute opacity of the actor inside a paint
9876  * virtual function, see clutter_actor_get_paint_opacity().
9877  *
9878  * Return value: the opacity of the actor
9879  */
9880 guint8
9881 clutter_actor_get_opacity (ClutterActor *self)
9882 {
9883   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9884
9885   return self->priv->opacity;
9886 }
9887
9888 /**
9889  * clutter_actor_set_offscreen_redirect:
9890  * @self: A #ClutterActor
9891  * @redirect: New offscreen redirect flags for the actor.
9892  *
9893  * Defines the circumstances where the actor should be redirected into
9894  * an offscreen image. The offscreen image is used to flatten the
9895  * actor into a single image while painting for two main reasons.
9896  * Firstly, when the actor is painted a second time without any of its
9897  * contents changing it can simply repaint the cached image without
9898  * descending further down the actor hierarchy. Secondly, it will make
9899  * the opacity look correct even if there are overlapping primitives
9900  * in the actor.
9901  *
9902  * Caching the actor could in some cases be a performance win and in
9903  * some cases be a performance lose so it is important to determine
9904  * which value is right for an actor before modifying this value. For
9905  * example, there is never any reason to flatten an actor that is just
9906  * a single texture (such as a #ClutterTexture) because it is
9907  * effectively already cached in an image so the offscreen would be
9908  * redundant. Also if the actor contains primitives that are far apart
9909  * with a large transparent area in the middle (such as a large
9910  * CluterGroup with a small actor in the top left and a small actor in
9911  * the bottom right) then the cached image will contain the entire
9912  * image of the large area and the paint will waste time blending all
9913  * of the transparent pixels in the middle.
9914  *
9915  * The default method of implementing opacity on a container simply
9916  * forwards on the opacity to all of the children. If the children are
9917  * overlapping then it will appear as if they are two separate glassy
9918  * objects and there will be a break in the color where they
9919  * overlap. By redirecting to an offscreen buffer it will be as if the
9920  * two opaque objects are combined into one and then made transparent
9921  * which is usually what is expected.
9922  *
9923  * The image below demonstrates the difference between redirecting and
9924  * not. The image shows two Clutter groups, each containing a red and
9925  * a green rectangle which overlap. The opacity on the group is set to
9926  * 128 (which is 50%). When the offscreen redirect is not used, the
9927  * red rectangle can be seen through the blue rectangle as if the two
9928  * rectangles were separately transparent. When the redirect is used
9929  * the group as a whole is transparent instead so the red rectangle is
9930  * not visible where they overlap.
9931  *
9932  * <figure id="offscreen-redirect">
9933  *   <title>Sample of using an offscreen redirect for transparency</title>
9934  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
9935  * </figure>
9936  *
9937  * The default value for this property is 0, so we effectively will
9938  * never redirect an actor offscreen by default. This means that there
9939  * are times that transparent actors may look glassy as described
9940  * above. The reason this is the default is because there is a
9941  * performance trade off between quality and performance here. In many
9942  * cases the default form of glassy opacity looks good enough, but if
9943  * it's not you will need to set the
9944  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9945  * redirection for opacity.
9946  *
9947  * Custom actors that don't contain any overlapping primitives are
9948  * recommended to override the has_overlaps() virtual to return %FALSE
9949  * for maximum efficiency.
9950  *
9951  * Since: 1.8
9952  */
9953 void
9954 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9955                                       ClutterOffscreenRedirect redirect)
9956 {
9957   ClutterActorPrivate *priv;
9958
9959   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9960
9961   priv = self->priv;
9962
9963   if (priv->offscreen_redirect != redirect)
9964     {
9965       priv->offscreen_redirect = redirect;
9966
9967       /* Queue a redraw from the effect so that it can use its cached
9968          image if available instead of having to redraw the actual
9969          actor. If it doesn't end up using the FBO then the effect is
9970          still able to continue the paint anyway. If there is no
9971          effect then this is equivalent to queuing a full redraw */
9972       _clutter_actor_queue_redraw_full (self,
9973                                         0, /* flags */
9974                                         NULL, /* clip */
9975                                         priv->flatten_effect);
9976
9977       g_object_notify_by_pspec (G_OBJECT (self),
9978                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
9979     }
9980 }
9981
9982 /**
9983  * clutter_actor_get_offscreen_redirect:
9984  * @self: a #ClutterActor
9985  *
9986  * Retrieves whether to redirect the actor to an offscreen buffer, as
9987  * set by clutter_actor_set_offscreen_redirect().
9988  *
9989  * Return value: the value of the offscreen-redirect property of the actor
9990  *
9991  * Since: 1.8
9992  */
9993 ClutterOffscreenRedirect
9994 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9995 {
9996   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9997
9998   return self->priv->offscreen_redirect;
9999 }
10000
10001 /**
10002  * clutter_actor_set_name:
10003  * @self: A #ClutterActor
10004  * @name: Textual tag to apply to actor
10005  *
10006  * Sets the given name to @self. The name can be used to identify
10007  * a #ClutterActor.
10008  */
10009 void
10010 clutter_actor_set_name (ClutterActor *self,
10011                         const gchar  *name)
10012 {
10013   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10014
10015   g_free (self->priv->name);
10016   self->priv->name = g_strdup (name);
10017
10018   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10019 }
10020
10021 /**
10022  * clutter_actor_get_name:
10023  * @self: A #ClutterActor
10024  *
10025  * Retrieves the name of @self.
10026  *
10027  * Return value: the name of the actor, or %NULL. The returned string is
10028  *   owned by the actor and should not be modified or freed.
10029  */
10030 const gchar *
10031 clutter_actor_get_name (ClutterActor *self)
10032 {
10033   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10034
10035   return self->priv->name;
10036 }
10037
10038 /**
10039  * clutter_actor_get_gid:
10040  * @self: A #ClutterActor
10041  *
10042  * Retrieves the unique id for @self.
10043  *
10044  * Return value: Globally unique value for this object instance.
10045  *
10046  * Since: 0.6
10047  *
10048  * Deprecated: 1.8: The id is not used any longer.
10049  */
10050 guint32
10051 clutter_actor_get_gid (ClutterActor *self)
10052 {
10053   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10054
10055   return self->priv->id;
10056 }
10057
10058 static inline void
10059 clutter_actor_set_depth_internal (ClutterActor *self,
10060                                   float         depth)
10061 {
10062   ClutterTransformInfo *info;
10063
10064   info = _clutter_actor_get_transform_info (self);
10065
10066   if (info->depth != depth)
10067     {
10068       /* Sets Z value - XXX 2.0: should we invert? */
10069       info->depth = depth;
10070
10071       self->priv->transform_valid = FALSE;
10072
10073       /* FIXME - remove this crap; sadly, there are still containers
10074        * in Clutter that depend on this utter brain damage
10075        */
10076       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10077
10078       clutter_actor_queue_redraw (self);
10079
10080       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10081     }
10082 }
10083
10084 /**
10085  * clutter_actor_set_depth:
10086  * @self: a #ClutterActor
10087  * @depth: Z co-ord
10088  *
10089  * Sets the Z coordinate of @self to @depth.
10090  *
10091  * The unit used by @depth is dependant on the perspective setup. See
10092  * also clutter_stage_set_perspective().
10093  */
10094 void
10095 clutter_actor_set_depth (ClutterActor *self,
10096                          gfloat        depth)
10097 {
10098   const ClutterTransformInfo *tinfo;
10099
10100   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10101
10102   tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10103
10104   if (clutter_actor_get_easing_duration (self) != 0)
10105     {
10106       ClutterTransition *transition;
10107
10108       transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10109       if (transition == NULL)
10110         {
10111           transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10112                                                          tinfo->depth,
10113                                                          depth);
10114           clutter_timeline_start (CLUTTER_TIMELINE (transition));
10115         }
10116       else
10117         _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10118
10119       clutter_actor_queue_redraw (self);
10120     }
10121   else
10122     clutter_actor_set_depth_internal (self, depth);
10123 }
10124
10125 /**
10126  * clutter_actor_get_depth:
10127  * @self: a #ClutterActor
10128  *
10129  * Retrieves the depth of @self.
10130  *
10131  * Return value: the depth of the actor
10132  */
10133 gfloat
10134 clutter_actor_get_depth (ClutterActor *self)
10135 {
10136   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10137
10138   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10139 }
10140
10141 /**
10142  * clutter_actor_set_rotation:
10143  * @self: a #ClutterActor
10144  * @axis: the axis of rotation
10145  * @angle: the angle of rotation
10146  * @x: X coordinate of the rotation center
10147  * @y: Y coordinate of the rotation center
10148  * @z: Z coordinate of the rotation center
10149  *
10150  * Sets the rotation angle of @self around the given axis.
10151  *
10152  * The rotation center coordinates used depend on the value of @axis:
10153  * <itemizedlist>
10154  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10155  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10156  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10157  * </itemizedlist>
10158  *
10159  * The rotation coordinates are relative to the anchor point of the
10160  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10161  * point is set, the upper left corner is assumed as the origin.
10162  *
10163  * Since: 0.8
10164  */
10165 void
10166 clutter_actor_set_rotation (ClutterActor      *self,
10167                             ClutterRotateAxis  axis,
10168                             gdouble            angle,
10169                             gfloat             x,
10170                             gfloat             y,
10171                             gfloat             z)
10172 {
10173   ClutterVertex v;
10174
10175   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10176
10177   v.x = x;
10178   v.y = y;
10179   v.z = z;
10180
10181   g_object_freeze_notify (G_OBJECT (self));
10182
10183   clutter_actor_set_rotation_angle (self, axis, angle);
10184   clutter_actor_set_rotation_center_internal (self, axis, &v);
10185
10186   g_object_thaw_notify (G_OBJECT (self));
10187 }
10188
10189 /**
10190  * clutter_actor_set_z_rotation_from_gravity:
10191  * @self: a #ClutterActor
10192  * @angle: the angle of rotation
10193  * @gravity: the center point of the rotation
10194  *
10195  * Sets the rotation angle of @self around the Z axis using the center
10196  * point specified as a compass point. For example to rotate such that
10197  * the center of the actor remains static you can use
10198  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10199  * will move accordingly.
10200  *
10201  * Since: 1.0
10202  */
10203 void
10204 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10205                                            gdouble         angle,
10206                                            ClutterGravity  gravity)
10207 {
10208   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10209
10210   if (gravity == CLUTTER_GRAVITY_NONE)
10211     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10212   else
10213     {
10214       GObject *obj = G_OBJECT (self);
10215       ClutterTransformInfo *info;
10216
10217       info = _clutter_actor_get_transform_info (self);
10218
10219       g_object_freeze_notify (obj);
10220
10221       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10222
10223       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10224       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10225       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10226
10227       g_object_thaw_notify (obj);
10228     }
10229 }
10230
10231 /**
10232  * clutter_actor_get_rotation:
10233  * @self: a #ClutterActor
10234  * @axis: the axis of rotation
10235  * @x: (out): return value for the X coordinate of the center of rotation
10236  * @y: (out): return value for the Y coordinate of the center of rotation
10237  * @z: (out): return value for the Z coordinate of the center of rotation
10238  *
10239  * Retrieves the angle and center of rotation on the given axis,
10240  * set using clutter_actor_set_rotation().
10241  *
10242  * Return value: the angle of rotation
10243  *
10244  * Since: 0.8
10245  */
10246 gdouble
10247 clutter_actor_get_rotation (ClutterActor      *self,
10248                             ClutterRotateAxis  axis,
10249                             gfloat            *x,
10250                             gfloat            *y,
10251                             gfloat            *z)
10252 {
10253   const ClutterTransformInfo *info;
10254   const AnchorCoord *anchor_coord;
10255   gdouble retval = 0;
10256
10257   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10258
10259   info = _clutter_actor_get_transform_info_or_defaults (self);
10260
10261   switch (axis)
10262     {
10263     case CLUTTER_X_AXIS:
10264       anchor_coord = &info->rx_center;
10265       retval = info->rx_angle;
10266       break;
10267
10268     case CLUTTER_Y_AXIS:
10269       anchor_coord = &info->ry_center;
10270       retval = info->ry_angle;
10271       break;
10272
10273     case CLUTTER_Z_AXIS:
10274       anchor_coord = &info->rz_center;
10275       retval = info->rz_angle;
10276       break;
10277
10278     default:
10279       anchor_coord = NULL;
10280       retval = 0.0;
10281       break;
10282     }
10283
10284   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10285
10286   return retval;
10287 }
10288
10289 /**
10290  * clutter_actor_get_z_rotation_gravity:
10291  * @self: A #ClutterActor
10292  *
10293  * Retrieves the center for the rotation around the Z axis as a
10294  * compass direction. If the center was specified in pixels or units
10295  * this will return %CLUTTER_GRAVITY_NONE.
10296  *
10297  * Return value: the Z rotation center
10298  *
10299  * Since: 1.0
10300  */
10301 ClutterGravity
10302 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10303 {
10304   const ClutterTransformInfo *info;
10305
10306   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10307
10308   info = _clutter_actor_get_transform_info_or_defaults (self);
10309
10310   return clutter_anchor_coord_get_gravity (&info->rz_center);
10311 }
10312
10313 /**
10314  * clutter_actor_set_clip:
10315  * @self: A #ClutterActor
10316  * @xoff: X offset of the clip rectangle
10317  * @yoff: Y offset of the clip rectangle
10318  * @width: Width of the clip rectangle
10319  * @height: Height of the clip rectangle
10320  *
10321  * Sets clip area for @self. The clip area is always computed from the
10322  * upper left corner of the actor, even if the anchor point is set
10323  * otherwise.
10324  *
10325  * Since: 0.6
10326  */
10327 void
10328 clutter_actor_set_clip (ClutterActor *self,
10329                         gfloat        xoff,
10330                         gfloat        yoff,
10331                         gfloat        width,
10332                         gfloat        height)
10333 {
10334   ClutterActorPrivate *priv;
10335
10336   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10337
10338   priv = self->priv;
10339
10340   if (priv->has_clip &&
10341       priv->clip.x == xoff &&
10342       priv->clip.y == yoff &&
10343       priv->clip.width == width &&
10344       priv->clip.height == height)
10345     return;
10346
10347   priv->clip.x = xoff;
10348   priv->clip.y = yoff;
10349   priv->clip.width = width;
10350   priv->clip.height = height;
10351
10352   priv->has_clip = TRUE;
10353
10354   clutter_actor_queue_redraw (self);
10355
10356   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10357   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10358 }
10359
10360 /**
10361  * clutter_actor_remove_clip:
10362  * @self: A #ClutterActor
10363  *
10364  * Removes clip area from @self.
10365  */
10366 void
10367 clutter_actor_remove_clip (ClutterActor *self)
10368 {
10369   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10370
10371   if (!self->priv->has_clip)
10372     return;
10373
10374   self->priv->has_clip = FALSE;
10375
10376   clutter_actor_queue_redraw (self);
10377
10378   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10379 }
10380
10381 /**
10382  * clutter_actor_has_clip:
10383  * @self: a #ClutterActor
10384  *
10385  * Determines whether the actor has a clip area set or not.
10386  *
10387  * Return value: %TRUE if the actor has a clip area set.
10388  *
10389  * Since: 0.1.1
10390  */
10391 gboolean
10392 clutter_actor_has_clip (ClutterActor *self)
10393 {
10394   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10395
10396   return self->priv->has_clip;
10397 }
10398
10399 /**
10400  * clutter_actor_get_clip:
10401  * @self: a #ClutterActor
10402  * @xoff: (out) (allow-none): return location for the X offset of
10403  *   the clip rectangle, or %NULL
10404  * @yoff: (out) (allow-none): return location for the Y offset of
10405  *   the clip rectangle, or %NULL
10406  * @width: (out) (allow-none): return location for the width of
10407  *   the clip rectangle, or %NULL
10408  * @height: (out) (allow-none): return location for the height of
10409  *   the clip rectangle, or %NULL
10410  *
10411  * Gets the clip area for @self, if any is set
10412  *
10413  * Since: 0.6
10414  */
10415 void
10416 clutter_actor_get_clip (ClutterActor *self,
10417                         gfloat       *xoff,
10418                         gfloat       *yoff,
10419                         gfloat       *width,
10420                         gfloat       *height)
10421 {
10422   ClutterActorPrivate *priv;
10423
10424   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10425
10426   priv = self->priv;
10427
10428   if (!priv->has_clip)
10429     return;
10430
10431   if (xoff != NULL)
10432     *xoff = priv->clip.x;
10433
10434   if (yoff != NULL)
10435     *yoff = priv->clip.y;
10436
10437   if (width != NULL)
10438     *width = priv->clip.width;
10439
10440   if (height != NULL)
10441     *height = priv->clip.height;
10442 }
10443
10444 /**
10445  * clutter_actor_get_children:
10446  * @self: a #ClutterActor
10447  *
10448  * Retrieves the list of children of @self.
10449  *
10450  * Return value: (transfer container) (element-type ClutterActor): A newly
10451  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10452  *   done.
10453  *
10454  * Since: 1.10
10455  */
10456 GList *
10457 clutter_actor_get_children (ClutterActor *self)
10458 {
10459   ClutterActor *iter;
10460   GList *res;
10461
10462   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10463
10464   /* we walk the list backward so that we can use prepend(),
10465    * which is O(1)
10466    */
10467   for (iter = self->priv->last_child, res = NULL;
10468        iter != NULL;
10469        iter = iter->priv->prev_sibling)
10470     {
10471       res = g_list_prepend (res, iter);
10472     }
10473
10474   return res;
10475 }
10476
10477 /*< private >
10478  * insert_child_at_depth:
10479  * @self: a #ClutterActor
10480  * @child: a #ClutterActor
10481  *
10482  * Inserts @child inside the list of children held by @self, using
10483  * the depth as the insertion criteria.
10484  *
10485  * This sadly makes the insertion not O(1), but we can keep the
10486  * list sorted so that the painters algorithm we use for painting
10487  * the children will work correctly.
10488  */
10489 static void
10490 insert_child_at_depth (ClutterActor *self,
10491                        ClutterActor *child,
10492                        gpointer      dummy G_GNUC_UNUSED)
10493 {
10494   ClutterActor *iter;
10495   float child_depth;
10496
10497   child->priv->parent = self;
10498
10499   child_depth =
10500     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10501
10502   /* special-case the first child */
10503   if (self->priv->n_children == 0)
10504     {
10505       self->priv->first_child = child;
10506       self->priv->last_child = child;
10507
10508       child->priv->next_sibling = NULL;
10509       child->priv->prev_sibling = NULL;
10510
10511       return;
10512     }
10513
10514   /* Find the right place to insert the child so that it will still be
10515      sorted and the child will be after all of the actors at the same
10516      dept */
10517   for (iter = self->priv->first_child;
10518        iter != NULL;
10519        iter = iter->priv->next_sibling)
10520     {
10521       float iter_depth;
10522
10523       iter_depth =
10524         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10525
10526       if (iter_depth > child_depth)
10527         break;
10528     }
10529
10530   if (iter != NULL)
10531     {
10532       ClutterActor *tmp = iter->priv->prev_sibling;
10533
10534       if (tmp != NULL)
10535         tmp->priv->next_sibling = child;
10536
10537       /* Insert the node before the found one */
10538       child->priv->prev_sibling = iter->priv->prev_sibling;
10539       child->priv->next_sibling = iter;
10540       iter->priv->prev_sibling = child;
10541     }
10542   else
10543     {
10544       ClutterActor *tmp = self->priv->last_child;
10545
10546       if (tmp != NULL)
10547         tmp->priv->next_sibling = child;
10548
10549       /* insert the node at the end of the list */
10550       child->priv->prev_sibling = self->priv->last_child;
10551       child->priv->next_sibling = NULL;
10552     }
10553
10554   if (child->priv->prev_sibling == NULL)
10555     self->priv->first_child = child;
10556
10557   if (child->priv->next_sibling == NULL)
10558     self->priv->last_child = child;
10559 }
10560
10561 static void
10562 insert_child_at_index (ClutterActor *self,
10563                        ClutterActor *child,
10564                        gpointer      data_)
10565 {
10566   gint index_ = GPOINTER_TO_INT (data_);
10567
10568   child->priv->parent = self;
10569
10570   if (index_ == 0)
10571     {
10572       ClutterActor *tmp = self->priv->first_child;
10573
10574       if (tmp != NULL)
10575         tmp->priv->prev_sibling = child;
10576
10577       child->priv->prev_sibling = NULL;
10578       child->priv->next_sibling = tmp;
10579     }
10580   else if (index_ < 0 || index_ >= self->priv->n_children)
10581     {
10582       ClutterActor *tmp = self->priv->last_child;
10583
10584       if (tmp != NULL)
10585         tmp->priv->next_sibling = child;
10586
10587       child->priv->prev_sibling = tmp;
10588       child->priv->next_sibling = NULL;
10589     }
10590   else
10591     {
10592       ClutterActor *iter;
10593       int i;
10594
10595       for (iter = self->priv->first_child, i = 0;
10596            iter != NULL;
10597            iter = iter->priv->next_sibling, i += 1)
10598         {
10599           if (index_ == i)
10600             {
10601               ClutterActor *tmp = iter->priv->prev_sibling;
10602
10603               child->priv->prev_sibling = tmp;
10604               child->priv->next_sibling = iter;
10605
10606               iter->priv->prev_sibling = child;
10607
10608               if (tmp != NULL)
10609                 tmp->priv->next_sibling = child;
10610
10611               break;
10612             }
10613         }
10614     }
10615
10616   if (child->priv->prev_sibling == NULL)
10617     self->priv->first_child = child;
10618
10619   if (child->priv->next_sibling == NULL)
10620     self->priv->last_child = child;
10621 }
10622
10623 static void
10624 insert_child_above (ClutterActor *self,
10625                     ClutterActor *child,
10626                     gpointer      data)
10627 {
10628   ClutterActor *sibling = data;
10629
10630   child->priv->parent = self;
10631
10632   if (sibling == NULL)
10633     sibling = self->priv->last_child;
10634
10635   child->priv->prev_sibling = sibling;
10636
10637   if (sibling != NULL)
10638     {
10639       ClutterActor *tmp = sibling->priv->next_sibling;
10640
10641       child->priv->next_sibling = tmp;
10642
10643       if (tmp != NULL)
10644         tmp->priv->prev_sibling = child;
10645
10646       sibling->priv->next_sibling = child;
10647     }
10648   else
10649     child->priv->next_sibling = NULL;
10650
10651   if (child->priv->prev_sibling == NULL)
10652     self->priv->first_child = child;
10653
10654   if (child->priv->next_sibling == NULL)
10655     self->priv->last_child = child;
10656 }
10657
10658 static void
10659 insert_child_below (ClutterActor *self,
10660                     ClutterActor *child,
10661                     gpointer      data)
10662 {
10663   ClutterActor *sibling = data;
10664
10665   child->priv->parent = self;
10666
10667   if (sibling == NULL)
10668     sibling = self->priv->first_child;
10669
10670   child->priv->next_sibling = sibling;
10671
10672   if (sibling != NULL)
10673     {
10674       ClutterActor *tmp = sibling->priv->prev_sibling;
10675
10676       child->priv->prev_sibling = tmp;
10677
10678       if (tmp != NULL)
10679         tmp->priv->next_sibling = child;
10680
10681       sibling->priv->prev_sibling = child;
10682     }
10683   else
10684     child->priv->prev_sibling = NULL;
10685
10686   if (child->priv->prev_sibling == NULL)
10687     self->priv->first_child = child;
10688
10689   if (child->priv->next_sibling == NULL)
10690     self->priv->last_child = child;
10691 }
10692
10693 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10694                                            ClutterActor *child,
10695                                            gpointer      data);
10696
10697 typedef enum {
10698   ADD_CHILD_CREATE_META       = 1 << 0,
10699   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10700   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10701   ADD_CHILD_CHECK_STATE       = 1 << 3,
10702   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10703
10704   /* default flags for public API */
10705   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10706                                ADD_CHILD_EMIT_PARENT_SET |
10707                                ADD_CHILD_EMIT_ACTOR_ADDED |
10708                                ADD_CHILD_CHECK_STATE |
10709                                ADD_CHILD_NOTIFY_FIRST_LAST,
10710
10711   /* flags for legacy/deprecated API */
10712   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10713                                ADD_CHILD_CHECK_STATE |
10714                                ADD_CHILD_NOTIFY_FIRST_LAST
10715 } ClutterActorAddChildFlags;
10716
10717 /*< private >
10718  * clutter_actor_add_child_internal:
10719  * @self: a #ClutterActor
10720  * @child: a #ClutterActor
10721  * @flags: control flags for actions
10722  * @add_func: delegate function
10723  * @data: (closure): data to pass to @add_func
10724  *
10725  * Adds @child to the list of children of @self.
10726  *
10727  * The actual insertion inside the list is delegated to @add_func: this
10728  * function will just set up the state, perform basic checks, and emit
10729  * signals.
10730  *
10731  * The @flags argument is used to perform additional operations.
10732  */
10733 static inline void
10734 clutter_actor_add_child_internal (ClutterActor              *self,
10735                                   ClutterActor              *child,
10736                                   ClutterActorAddChildFlags  flags,
10737                                   ClutterActorAddChildFunc   add_func,
10738                                   gpointer                   data)
10739 {
10740   ClutterTextDirection text_dir;
10741   gboolean create_meta;
10742   gboolean emit_parent_set, emit_actor_added;
10743   gboolean check_state;
10744   gboolean notify_first_last;
10745   ClutterActor *old_first_child, *old_last_child;
10746
10747   if (child->priv->parent != NULL)
10748     {
10749       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10750                  "use clutter_actor_remove_child() first.",
10751                  _clutter_actor_get_debug_name (child),
10752                  _clutter_actor_get_debug_name (child->priv->parent));
10753       return;
10754     }
10755
10756   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10757     {
10758       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10759                  "a child of another actor.",
10760                  _clutter_actor_get_debug_name (child));
10761       return;
10762     }
10763
10764 #if 0
10765   /* XXX - this check disallows calling methods that change the stacking
10766    * order within the destruction sequence, by triggering a critical
10767    * warning first, and leaving the actor in an undefined state, which
10768    * then ends up being caught by an assertion.
10769    *
10770    * the reproducible sequence is:
10771    *
10772    *   - actor gets destroyed;
10773    *   - another actor, linked to the first, will try to change the
10774    *     stacking order of the first actor;
10775    *   - changing the stacking order is a composite operation composed
10776    *     by the following steps:
10777    *     1. ref() the child;
10778    *     2. remove_child_internal(), which removes the reference;
10779    *     3. add_child_internal(), which adds a reference;
10780    *   - the state of the actor is not changed between (2) and (3), as
10781    *     it could be an expensive recomputation;
10782    *   - if (3) bails out, then the actor is in an undefined state, but
10783    *     still alive;
10784    *   - the destruction sequence terminates, but the actor is unparented
10785    *     while its state indicates being parented instead.
10786    *   - assertion failure.
10787    *
10788    * the obvious fix would be to decompose each set_child_*_sibling()
10789    * method into proper remove_child()/add_child(), with state validation;
10790    * this may cause excessive work, though, and trigger a cascade of other
10791    * bugs in code that assumes that a change in the stacking order is an
10792    * atomic operation.
10793    *
10794    * another potential fix is to just remove this check here, and let
10795    * code doing stacking order changes inside the destruction sequence
10796    * of an actor continue doing the work.
10797    *
10798    * the third fix is to silently bail out early from every
10799    * set_child_*_sibling() and set_child_at_index() method, and avoid
10800    * doing work.
10801    *
10802    * I have a preference for the second solution, since it involves the
10803    * least amount of work, and the least amount of code duplication.
10804    *
10805    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10806    */
10807   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10808     {
10809       g_warning ("The actor '%s' is currently being destroyed, and "
10810                  "cannot be added as a child of another actor.",
10811                  _clutter_actor_get_debug_name (child));
10812       return;
10813     }
10814 #endif
10815
10816   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10817   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10818   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10819   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10820   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10821
10822   old_first_child = self->priv->first_child;
10823   old_last_child = self->priv->last_child;
10824
10825   g_object_freeze_notify (G_OBJECT (self));
10826
10827   if (create_meta)
10828     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10829
10830   g_object_ref_sink (child);
10831   child->priv->parent = NULL;
10832   child->priv->next_sibling = NULL;
10833   child->priv->prev_sibling = NULL;
10834
10835   /* delegate the actual insertion */
10836   add_func (self, child, data);
10837
10838   g_assert (child->priv->parent == self);
10839
10840   self->priv->n_children += 1;
10841
10842   self->priv->age += 1;
10843
10844   /* if push_internal() has been called then we automatically set
10845    * the flag on the actor
10846    */
10847   if (self->priv->internal_child)
10848     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10849
10850   /* clutter_actor_reparent() will emit ::parent-set for us */
10851   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10852     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10853
10854   if (check_state)
10855     {
10856       /* If parent is mapped or realized, we need to also be mapped or
10857        * realized once we're inside the parent.
10858        */
10859       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10860
10861       /* propagate the parent's text direction to the child */
10862       text_dir = clutter_actor_get_text_direction (self);
10863       clutter_actor_set_text_direction (child, text_dir);
10864     }
10865
10866   if (child->priv->show_on_set_parent)
10867     clutter_actor_show (child);
10868
10869   if (CLUTTER_ACTOR_IS_MAPPED (child))
10870     clutter_actor_queue_redraw (child);
10871
10872   /* maintain the invariant that if an actor needs layout,
10873    * its parents do as well
10874    */
10875   if (child->priv->needs_width_request ||
10876       child->priv->needs_height_request ||
10877       child->priv->needs_allocation)
10878     {
10879       /* we work around the short-circuiting we do
10880        * in clutter_actor_queue_relayout() since we
10881        * want to force a relayout
10882        */
10883       child->priv->needs_width_request = TRUE;
10884       child->priv->needs_height_request = TRUE;
10885       child->priv->needs_allocation = TRUE;
10886
10887       clutter_actor_queue_relayout (child->priv->parent);
10888     }
10889
10890   if (emit_actor_added)
10891     g_signal_emit_by_name (self, "actor-added", child);
10892
10893   if (notify_first_last)
10894     {
10895       if (old_first_child != self->priv->first_child)
10896         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10897
10898       if (old_last_child != self->priv->last_child)
10899         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10900     }
10901
10902   g_object_thaw_notify (G_OBJECT (self));
10903 }
10904
10905 /**
10906  * clutter_actor_add_child:
10907  * @self: a #ClutterActor
10908  * @child: a #ClutterActor
10909  *
10910  * Adds @child to the children of @self.
10911  *
10912  * This function will acquire a reference on @child that will only
10913  * be released when calling clutter_actor_remove_child().
10914  *
10915  * This function will take into consideration the #ClutterActor:depth
10916  * of @child, and will keep the list of children sorted.
10917  *
10918  * This function will emit the #ClutterContainer::actor-added signal
10919  * on @self.
10920  *
10921  * Since: 1.10
10922  */
10923 void
10924 clutter_actor_add_child (ClutterActor *self,
10925                          ClutterActor *child)
10926 {
10927   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10928   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10929   g_return_if_fail (self != child);
10930   g_return_if_fail (child->priv->parent == NULL);
10931
10932   clutter_actor_add_child_internal (self, child,
10933                                     ADD_CHILD_DEFAULT_FLAGS,
10934                                     insert_child_at_depth,
10935                                     NULL);
10936 }
10937
10938 /**
10939  * clutter_actor_insert_child_at_index:
10940  * @self: a #ClutterActor
10941  * @child: a #ClutterActor
10942  * @index_: the index
10943  *
10944  * Inserts @child into the list of children of @self, using the
10945  * given @index_. If @index_ is greater than the number of children
10946  * in @self, or is less than 0, then the new child is added at the end.
10947  *
10948  * This function will acquire a reference on @child that will only
10949  * be released when calling clutter_actor_remove_child().
10950  *
10951  * This function will not take into consideration the #ClutterActor:depth
10952  * of @child.
10953  *
10954  * This function will emit the #ClutterContainer::actor-added signal
10955  * on @self.
10956  *
10957  * Since: 1.10
10958  */
10959 void
10960 clutter_actor_insert_child_at_index (ClutterActor *self,
10961                                      ClutterActor *child,
10962                                      gint          index_)
10963 {
10964   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10965   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10966   g_return_if_fail (self != child);
10967   g_return_if_fail (child->priv->parent == NULL);
10968
10969   clutter_actor_add_child_internal (self, child,
10970                                     ADD_CHILD_DEFAULT_FLAGS,
10971                                     insert_child_at_index,
10972                                     GINT_TO_POINTER (index_));
10973 }
10974
10975 /**
10976  * clutter_actor_insert_child_above:
10977  * @self: a #ClutterActor
10978  * @child: a #ClutterActor
10979  * @sibling: (allow-none): a child of @self, or %NULL
10980  *
10981  * Inserts @child into the list of children of @self, above another
10982  * child of @self or, if @sibling is %NULL, above all the children
10983  * of @self.
10984  *
10985  * This function will acquire a reference on @child that will only
10986  * be released when calling clutter_actor_remove_child().
10987  *
10988  * This function will not take into consideration the #ClutterActor:depth
10989  * of @child.
10990  *
10991  * This function will emit the #ClutterContainer::actor-added signal
10992  * on @self.
10993  *
10994  * Since: 1.10
10995  */
10996 void
10997 clutter_actor_insert_child_above (ClutterActor *self,
10998                                   ClutterActor *child,
10999                                   ClutterActor *sibling)
11000 {
11001   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11002   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11003   g_return_if_fail (self != child);
11004   g_return_if_fail (child != sibling);
11005   g_return_if_fail (child->priv->parent == NULL);
11006   g_return_if_fail (sibling == NULL ||
11007                     (CLUTTER_IS_ACTOR (sibling) &&
11008                      sibling->priv->parent == self));
11009
11010   clutter_actor_add_child_internal (self, child,
11011                                     ADD_CHILD_DEFAULT_FLAGS,
11012                                     insert_child_above,
11013                                     sibling);
11014 }
11015
11016 /**
11017  * clutter_actor_insert_child_below:
11018  * @self: a #ClutterActor
11019  * @child: a #ClutterActor
11020  * @sibling: (allow-none): a child of @self, or %NULL
11021  *
11022  * Inserts @child into the list of children of @self, below another
11023  * child of @self or, if @sibling is %NULL, below all the children
11024  * of @self.
11025  *
11026  * This function will acquire a reference on @child that will only
11027  * be released when calling clutter_actor_remove_child().
11028  *
11029  * This function will not take into consideration the #ClutterActor:depth
11030  * of @child.
11031  *
11032  * This function will emit the #ClutterContainer::actor-added signal
11033  * on @self.
11034  *
11035  * Since: 1.10
11036  */
11037 void
11038 clutter_actor_insert_child_below (ClutterActor *self,
11039                                   ClutterActor *child,
11040                                   ClutterActor *sibling)
11041 {
11042   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11043   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11044   g_return_if_fail (self != child);
11045   g_return_if_fail (child != sibling);
11046   g_return_if_fail (child->priv->parent == NULL);
11047   g_return_if_fail (sibling == NULL ||
11048                     (CLUTTER_IS_ACTOR (sibling) &&
11049                      sibling->priv->parent == self));
11050
11051   clutter_actor_add_child_internal (self, child,
11052                                     ADD_CHILD_DEFAULT_FLAGS,
11053                                     insert_child_below,
11054                                     sibling);
11055 }
11056
11057 /**
11058  * clutter_actor_set_parent:
11059  * @self: A #ClutterActor
11060  * @parent: A new #ClutterActor parent
11061  *
11062  * Sets the parent of @self to @parent.
11063  *
11064  * This function will result in @parent acquiring a reference on @self,
11065  * eventually by sinking its floating reference first. The reference
11066  * will be released by clutter_actor_unparent().
11067  *
11068  * This function should only be called by legacy #ClutterActor<!-- -->s
11069  * implementing the #ClutterContainer interface.
11070  *
11071  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11072  */
11073 void
11074 clutter_actor_set_parent (ClutterActor *self,
11075                           ClutterActor *parent)
11076 {
11077   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11078   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11079   g_return_if_fail (self != parent);
11080   g_return_if_fail (self->priv->parent == NULL);
11081
11082   /* as this function will be called inside ClutterContainer::add
11083    * implementations or when building up a composite actor, we have
11084    * to preserve the old behaviour, and not create child meta or
11085    * emit the ::actor-added signal, to avoid recursion or double
11086    * emissions
11087    */
11088   clutter_actor_add_child_internal (parent, self,
11089                                     ADD_CHILD_LEGACY_FLAGS,
11090                                     insert_child_at_depth,
11091                                     NULL);
11092 }
11093
11094 /**
11095  * clutter_actor_get_parent:
11096  * @self: A #ClutterActor
11097  *
11098  * Retrieves the parent of @self.
11099  *
11100  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11101  *  if no parent is set
11102  */
11103 ClutterActor *
11104 clutter_actor_get_parent (ClutterActor *self)
11105 {
11106   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11107
11108   return self->priv->parent;
11109 }
11110
11111 /**
11112  * clutter_actor_get_paint_visibility:
11113  * @self: A #ClutterActor
11114  *
11115  * Retrieves the 'paint' visibility of an actor recursively checking for non
11116  * visible parents.
11117  *
11118  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11119  *
11120  * Return Value: %TRUE if the actor is visibile and will be painted.
11121  *
11122  * Since: 0.8.4
11123  */
11124 gboolean
11125 clutter_actor_get_paint_visibility (ClutterActor *actor)
11126 {
11127   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11128
11129   return CLUTTER_ACTOR_IS_MAPPED (actor);
11130 }
11131
11132 /**
11133  * clutter_actor_remove_child:
11134  * @self: a #ClutterActor
11135  * @child: a #ClutterActor
11136  *
11137  * Removes @child from the children of @self.
11138  *
11139  * This function will release the reference added by
11140  * clutter_actor_add_child(), so if you want to keep using @child
11141  * you will have to acquire a referenced on it before calling this
11142  * function.
11143  *
11144  * This function will emit the #ClutterContainer::actor-removed
11145  * signal on @self.
11146  *
11147  * Since: 1.10
11148  */
11149 void
11150 clutter_actor_remove_child (ClutterActor *self,
11151                             ClutterActor *child)
11152 {
11153   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11154   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11155   g_return_if_fail (self != child);
11156   g_return_if_fail (child->priv->parent != NULL);
11157   g_return_if_fail (child->priv->parent == self);
11158
11159   clutter_actor_remove_child_internal (self, child,
11160                                        REMOVE_CHILD_DEFAULT_FLAGS);
11161 }
11162
11163 /**
11164  * clutter_actor_remove_all_children:
11165  * @self: a #ClutterActor
11166  *
11167  * Removes all children of @self.
11168  *
11169  * This function releases the reference added by inserting a child actor
11170  * in the list of children of @self.
11171  *
11172  * If the reference count of a child drops to zero, the child will be
11173  * destroyed. If you want to ensure the destruction of all the children
11174  * of @self, use clutter_actor_destroy_all_children().
11175  *
11176  * Since: 1.10
11177  */
11178 void
11179 clutter_actor_remove_all_children (ClutterActor *self)
11180 {
11181   ClutterActorIter iter;
11182
11183   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11184
11185   if (self->priv->n_children == 0)
11186     return;
11187
11188   g_object_freeze_notify (G_OBJECT (self));
11189
11190   clutter_actor_iter_init (&iter, self);
11191   while (clutter_actor_iter_next (&iter, NULL))
11192     clutter_actor_iter_remove (&iter);
11193
11194   g_object_thaw_notify (G_OBJECT (self));
11195
11196   /* sanity check */
11197   g_assert (self->priv->first_child == NULL);
11198   g_assert (self->priv->last_child == NULL);
11199   g_assert (self->priv->n_children == 0);
11200 }
11201
11202 /**
11203  * clutter_actor_destroy_all_children:
11204  * @self: a #ClutterActor
11205  *
11206  * Destroys all children of @self.
11207  *
11208  * This function releases the reference added by inserting a child
11209  * actor in the list of children of @self, and ensures that the
11210  * #ClutterActor::destroy signal is emitted on each child of the
11211  * actor.
11212  *
11213  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11214  * when its reference count drops to 0; the default handler of the
11215  * #ClutterActor::destroy signal will destroy all the children of an
11216  * actor. This function ensures that all children are destroyed, instead
11217  * of just removed from @self, unlike clutter_actor_remove_all_children()
11218  * which will merely release the reference and remove each child.
11219  *
11220  * Unless you acquired an additional reference on each child of @self
11221  * prior to calling clutter_actor_remove_all_children() and want to reuse
11222  * the actors, you should use clutter_actor_destroy_all_children() in
11223  * order to make sure that children are destroyed and signal handlers
11224  * are disconnected even in cases where circular references prevent this
11225  * from automatically happening through reference counting alone.
11226  *
11227  * Since: 1.10
11228  */
11229 void
11230 clutter_actor_destroy_all_children (ClutterActor *self)
11231 {
11232   ClutterActorIter iter;
11233
11234   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11235
11236   if (self->priv->n_children == 0)
11237     return;
11238
11239   g_object_freeze_notify (G_OBJECT (self));
11240
11241   clutter_actor_iter_init (&iter, self);
11242   while (clutter_actor_iter_next (&iter, NULL))
11243     clutter_actor_iter_destroy (&iter);
11244
11245   g_object_thaw_notify (G_OBJECT (self));
11246
11247   /* sanity check */
11248   g_assert (self->priv->first_child == NULL);
11249   g_assert (self->priv->last_child == NULL);
11250   g_assert (self->priv->n_children == 0);
11251 }
11252
11253 typedef struct _InsertBetweenData {
11254   ClutterActor *prev_sibling;
11255   ClutterActor *next_sibling;
11256 } InsertBetweenData;
11257
11258 static void
11259 insert_child_between (ClutterActor *self,
11260                       ClutterActor *child,
11261                       gpointer      data_)
11262 {
11263   InsertBetweenData *data = data_;
11264   ClutterActor *prev_sibling = data->prev_sibling;
11265   ClutterActor *next_sibling = data->next_sibling;
11266
11267   child->priv->parent = self;
11268   child->priv->prev_sibling = prev_sibling;
11269   child->priv->next_sibling = next_sibling;
11270
11271   if (prev_sibling != NULL)
11272     prev_sibling->priv->next_sibling = child;
11273
11274   if (next_sibling != NULL)
11275     next_sibling->priv->prev_sibling = child;
11276
11277   if (child->priv->prev_sibling == NULL)
11278     self->priv->first_child = child;
11279
11280   if (child->priv->next_sibling == NULL)
11281     self->priv->last_child = child;
11282 }
11283
11284 /**
11285  * clutter_actor_replace_child:
11286  * @self: a #ClutterActor
11287  * @old_child: the child of @self to replace
11288  * @new_child: the #ClutterActor to replace @old_child
11289  *
11290  * Replaces @old_child with @new_child in the list of children of @self.
11291  *
11292  * Since: 1.10
11293  */
11294 void
11295 clutter_actor_replace_child (ClutterActor *self,
11296                              ClutterActor *old_child,
11297                              ClutterActor *new_child)
11298 {
11299   ClutterActor *prev_sibling, *next_sibling;
11300   InsertBetweenData clos;
11301
11302   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11303   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11304   g_return_if_fail (old_child->priv->parent == self);
11305   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11306   g_return_if_fail (old_child != new_child);
11307   g_return_if_fail (new_child != self);
11308   g_return_if_fail (new_child->priv->parent == NULL);
11309
11310   prev_sibling = old_child->priv->prev_sibling;
11311   next_sibling = old_child->priv->next_sibling;
11312   clutter_actor_remove_child_internal (self, old_child,
11313                                        REMOVE_CHILD_DEFAULT_FLAGS);
11314
11315   clos.prev_sibling = prev_sibling;
11316   clos.next_sibling = next_sibling;
11317   clutter_actor_add_child_internal (self, new_child,
11318                                     ADD_CHILD_DEFAULT_FLAGS,
11319                                     insert_child_between,
11320                                     &clos);
11321 }
11322
11323 /**
11324  * clutter_actor_unparent:
11325  * @self: a #ClutterActor
11326  *
11327  * Removes the parent of @self.
11328  *
11329  * This will cause the parent of @self to release the reference
11330  * acquired when calling clutter_actor_set_parent(), so if you
11331  * want to keep @self you will have to acquire a reference of
11332  * your own, through g_object_ref().
11333  *
11334  * This function should only be called by legacy #ClutterActor<!-- -->s
11335  * implementing the #ClutterContainer interface.
11336  *
11337  * Since: 0.1.1
11338  *
11339  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11340  */
11341 void
11342 clutter_actor_unparent (ClutterActor *self)
11343 {
11344   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11345
11346   if (self->priv->parent == NULL)
11347     return;
11348
11349   clutter_actor_remove_child_internal (self->priv->parent, self,
11350                                        REMOVE_CHILD_LEGACY_FLAGS);
11351 }
11352
11353 /**
11354  * clutter_actor_reparent:
11355  * @self: a #ClutterActor
11356  * @new_parent: the new #ClutterActor parent
11357  *
11358  * Resets the parent actor of @self.
11359  *
11360  * This function is logically equivalent to calling clutter_actor_unparent()
11361  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11362  * ensures the child is not finalized when unparented, and emits the
11363  * #ClutterActor::parent-set signal only once.
11364  *
11365  * In reality, calling this function is less useful than it sounds, as some
11366  * application code may rely on changes in the intermediate state between
11367  * removal and addition of the actor from its old parent to the @new_parent.
11368  * Thus, it is strongly encouraged to avoid using this function in application
11369  * code.
11370  *
11371  * Since: 0.2
11372  *
11373  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11374  *   clutter_actor_add_child() instead; remember to take a reference on
11375  *   the actor being removed before calling clutter_actor_remove_child()
11376  *   to avoid the reference count dropping to zero and the actor being
11377  *   destroyed.
11378  */
11379 void
11380 clutter_actor_reparent (ClutterActor *self,
11381                         ClutterActor *new_parent)
11382 {
11383   ClutterActorPrivate *priv;
11384
11385   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11386   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11387   g_return_if_fail (self != new_parent);
11388
11389   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11390     {
11391       g_warning ("Cannot set a parent on a toplevel actor");
11392       return;
11393     }
11394
11395   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11396     {
11397       g_warning ("Cannot set a parent currently being destroyed");
11398       return;
11399     }
11400
11401   priv = self->priv;
11402
11403   if (priv->parent != new_parent)
11404     {
11405       ClutterActor *old_parent;
11406
11407       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11408
11409       old_parent = priv->parent;
11410
11411       g_object_ref (self);
11412
11413       if (old_parent != NULL)
11414         {
11415          /* go through the Container implementation if this is a regular
11416           * child and not an internal one
11417           */
11418          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11419            {
11420              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11421
11422              /* this will have to call unparent() */
11423              clutter_container_remove_actor (parent, self);
11424            }
11425          else
11426            clutter_actor_remove_child_internal (old_parent, self,
11427                                                 REMOVE_CHILD_LEGACY_FLAGS);
11428         }
11429
11430       /* Note, will call set_parent() */
11431       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11432         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11433       else
11434         clutter_actor_add_child_internal (new_parent, self,
11435                                           ADD_CHILD_LEGACY_FLAGS,
11436                                           insert_child_at_depth,
11437                                           NULL);
11438
11439       /* we emit the ::parent-set signal once */
11440       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11441
11442       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11443
11444       /* the IN_REPARENT flag suspends state updates */
11445       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11446
11447       g_object_unref (self);
11448    }
11449 }
11450
11451 /**
11452  * clutter_actor_contains:
11453  * @self: A #ClutterActor
11454  * @descendant: A #ClutterActor, possibly contained in @self
11455  *
11456  * Determines if @descendant is contained inside @self (either as an
11457  * immediate child, or as a deeper descendant). If @self and
11458  * @descendant point to the same actor then it will also return %TRUE.
11459  *
11460  * Return value: whether @descendent is contained within @self
11461  *
11462  * Since: 1.4
11463  */
11464 gboolean
11465 clutter_actor_contains (ClutterActor *self,
11466                         ClutterActor *descendant)
11467 {
11468   ClutterActor *actor;
11469
11470   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11471   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11472
11473   for (actor = descendant; actor; actor = actor->priv->parent)
11474     if (actor == self)
11475       return TRUE;
11476
11477   return FALSE;
11478 }
11479
11480 /**
11481  * clutter_actor_set_child_above_sibling:
11482  * @self: a #ClutterActor
11483  * @child: a #ClutterActor child of @self
11484  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11485  *
11486  * Sets @child to be above @sibling in the list of children of @self.
11487  *
11488  * If @sibling is %NULL, @child will be the new last child of @self.
11489  *
11490  * This function is logically equivalent to removing @child and using
11491  * clutter_actor_insert_child_above(), but it will not emit signals
11492  * or change state on @child.
11493  *
11494  * Since: 1.10
11495  */
11496 void
11497 clutter_actor_set_child_above_sibling (ClutterActor *self,
11498                                        ClutterActor *child,
11499                                        ClutterActor *sibling)
11500 {
11501   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11502   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11503   g_return_if_fail (child->priv->parent == self);
11504   g_return_if_fail (child != sibling);
11505   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11506
11507   if (sibling != NULL)
11508     g_return_if_fail (sibling->priv->parent == self);
11509
11510   /* we don't want to change the state of child, or emit signals, or
11511    * regenerate ChildMeta instances here, but we still want to follow
11512    * the correct sequence of steps encoded in remove_child() and
11513    * add_child(), so that correctness is ensured, and we only go
11514    * through one known code path.
11515    */
11516   g_object_ref (child);
11517   clutter_actor_remove_child_internal (self, child, 0);
11518   clutter_actor_add_child_internal (self, child,
11519                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11520                                     insert_child_above,
11521                                     sibling);
11522
11523   clutter_actor_queue_relayout (self);
11524 }
11525
11526 /**
11527  * clutter_actor_set_child_below_sibling:
11528  * @self: a #ClutterActor
11529  * @child: a #ClutterActor child of @self
11530  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11531  *
11532  * Sets @child to be below @sibling in the list of children of @self.
11533  *
11534  * If @sibling is %NULL, @child will be the new first child of @self.
11535  *
11536  * This function is logically equivalent to removing @self and using
11537  * clutter_actor_insert_child_below(), but it will not emit signals
11538  * or change state on @child.
11539  *
11540  * Since: 1.10
11541  */
11542 void
11543 clutter_actor_set_child_below_sibling (ClutterActor *self,
11544                                        ClutterActor *child,
11545                                        ClutterActor *sibling)
11546 {
11547   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11548   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11549   g_return_if_fail (child->priv->parent == self);
11550   g_return_if_fail (child != sibling);
11551   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11552
11553   if (sibling != NULL)
11554     g_return_if_fail (sibling->priv->parent == self);
11555
11556   /* see the comment in set_child_above_sibling() */
11557   g_object_ref (child);
11558   clutter_actor_remove_child_internal (self, child, 0);
11559   clutter_actor_add_child_internal (self, child,
11560                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11561                                     insert_child_below,
11562                                     sibling);
11563
11564   clutter_actor_queue_relayout (self);
11565 }
11566
11567 /**
11568  * clutter_actor_set_child_at_index:
11569  * @self: a #ClutterActor
11570  * @child: a #ClutterActor child of @self
11571  * @index_: the new index for @child
11572  *
11573  * Changes the index of @child in the list of children of @self.
11574  *
11575  * This function is logically equivalent to removing @child and
11576  * calling clutter_actor_insert_child_at_index(), but it will not
11577  * emit signals or change state on @child.
11578  *
11579  * Since: 1.10
11580  */
11581 void
11582 clutter_actor_set_child_at_index (ClutterActor *self,
11583                                   ClutterActor *child,
11584                                   gint          index_)
11585 {
11586   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11587   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11588   g_return_if_fail (child->priv->parent == self);
11589   g_return_if_fail (index_ <= self->priv->n_children);
11590
11591   g_object_ref (child);
11592   clutter_actor_remove_child_internal (self, child, 0);
11593   clutter_actor_add_child_internal (self, child,
11594                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11595                                     insert_child_at_index,
11596                                     GINT_TO_POINTER (index_));
11597
11598   clutter_actor_queue_relayout (self);
11599 }
11600
11601 /**
11602  * clutter_actor_raise:
11603  * @self: A #ClutterActor
11604  * @below: (allow-none): A #ClutterActor to raise above.
11605  *
11606  * Puts @self above @below.
11607  *
11608  * Both actors must have the same parent, and the parent must implement
11609  * the #ClutterContainer interface
11610  *
11611  * This function calls clutter_container_raise_child() internally.
11612  *
11613  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11614  */
11615 void
11616 clutter_actor_raise (ClutterActor *self,
11617                      ClutterActor *below)
11618 {
11619   ClutterActor *parent;
11620
11621   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11622
11623   parent = clutter_actor_get_parent (self);
11624   if (parent == NULL)
11625     {
11626       g_warning ("%s: Actor '%s' is not inside a container",
11627                  G_STRFUNC,
11628                  _clutter_actor_get_debug_name (self));
11629       return;
11630     }
11631
11632   if (below != NULL)
11633     {
11634       if (parent != clutter_actor_get_parent (below))
11635         {
11636           g_warning ("%s Actor '%s' is not in the same container as "
11637                      "actor '%s'",
11638                      G_STRFUNC,
11639                      _clutter_actor_get_debug_name (self),
11640                      _clutter_actor_get_debug_name (below));
11641           return;
11642         }
11643     }
11644
11645   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11646 }
11647
11648 /**
11649  * clutter_actor_lower:
11650  * @self: A #ClutterActor
11651  * @above: (allow-none): A #ClutterActor to lower below
11652  *
11653  * Puts @self below @above.
11654  *
11655  * Both actors must have the same parent, and the parent must implement
11656  * the #ClutterContainer interface.
11657  *
11658  * This function calls clutter_container_lower_child() internally.
11659  *
11660  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11661  */
11662 void
11663 clutter_actor_lower (ClutterActor *self,
11664                      ClutterActor *above)
11665 {
11666   ClutterActor *parent;
11667
11668   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11669
11670   parent = clutter_actor_get_parent (self);
11671   if (parent == NULL)
11672     {
11673       g_warning ("%s: Actor of type %s is not inside a container",
11674                  G_STRFUNC,
11675                  _clutter_actor_get_debug_name (self));
11676       return;
11677     }
11678
11679   if (above)
11680     {
11681       if (parent != clutter_actor_get_parent (above))
11682         {
11683           g_warning ("%s: Actor '%s' is not in the same container as "
11684                      "actor '%s'",
11685                      G_STRFUNC,
11686                      _clutter_actor_get_debug_name (self),
11687                      _clutter_actor_get_debug_name (above));
11688           return;
11689         }
11690     }
11691
11692   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11693 }
11694
11695 /**
11696  * clutter_actor_raise_top:
11697  * @self: A #ClutterActor
11698  *
11699  * Raises @self to the top.
11700  *
11701  * This function calls clutter_actor_raise() internally.
11702  *
11703  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11704  *   a %NULL sibling, instead.
11705  */
11706 void
11707 clutter_actor_raise_top (ClutterActor *self)
11708 {
11709   clutter_actor_raise (self, NULL);
11710 }
11711
11712 /**
11713  * clutter_actor_lower_bottom:
11714  * @self: A #ClutterActor
11715  *
11716  * Lowers @self to the bottom.
11717  *
11718  * This function calls clutter_actor_lower() internally.
11719  *
11720  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11721  *   a %NULL sibling, instead.
11722  */
11723 void
11724 clutter_actor_lower_bottom (ClutterActor *self)
11725 {
11726   clutter_actor_lower (self, NULL);
11727 }
11728
11729 /*
11730  * Event handling
11731  */
11732
11733 /**
11734  * clutter_actor_event:
11735  * @actor: a #ClutterActor
11736  * @event: a #ClutterEvent
11737  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11738  *
11739  * This function is used to emit an event on the main stage.
11740  * You should rarely need to use this function, except for
11741  * synthetising events.
11742  *
11743  * Return value: the return value from the signal emission: %TRUE
11744  *   if the actor handled the event, or %FALSE if the event was
11745  *   not handled
11746  *
11747  * Since: 0.6
11748  */
11749 gboolean
11750 clutter_actor_event (ClutterActor *actor,
11751                      ClutterEvent *event,
11752                      gboolean      capture)
11753 {
11754   gboolean retval = FALSE;
11755   gint signal_num = -1;
11756
11757   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11758   g_return_val_if_fail (event != NULL, FALSE);
11759
11760   g_object_ref (actor);
11761
11762   if (capture)
11763     {
11764       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11765                      event,
11766                      &retval);
11767       goto out;
11768     }
11769
11770   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11771
11772   if (!retval)
11773     {
11774       switch (event->type)
11775         {
11776         case CLUTTER_NOTHING:
11777           break;
11778         case CLUTTER_BUTTON_PRESS:
11779           signal_num = BUTTON_PRESS_EVENT;
11780           break;
11781         case CLUTTER_BUTTON_RELEASE:
11782           signal_num = BUTTON_RELEASE_EVENT;
11783           break;
11784         case CLUTTER_SCROLL:
11785           signal_num = SCROLL_EVENT;
11786           break;
11787         case CLUTTER_KEY_PRESS:
11788           signal_num = KEY_PRESS_EVENT;
11789           break;
11790         case CLUTTER_KEY_RELEASE:
11791           signal_num = KEY_RELEASE_EVENT;
11792           break;
11793         case CLUTTER_MOTION:
11794           signal_num = MOTION_EVENT;
11795           break;
11796         case CLUTTER_ENTER:
11797           signal_num = ENTER_EVENT;
11798           break;
11799         case CLUTTER_LEAVE:
11800           signal_num = LEAVE_EVENT;
11801           break;
11802         case CLUTTER_DELETE:
11803         case CLUTTER_DESTROY_NOTIFY:
11804         case CLUTTER_CLIENT_MESSAGE:
11805         default:
11806           signal_num = -1;
11807           break;
11808         }
11809
11810       if (signal_num != -1)
11811         g_signal_emit (actor, actor_signals[signal_num], 0,
11812                        event, &retval);
11813     }
11814
11815 out:
11816   g_object_unref (actor);
11817
11818   return retval;
11819 }
11820
11821 /**
11822  * clutter_actor_set_reactive:
11823  * @actor: a #ClutterActor
11824  * @reactive: whether the actor should be reactive to events
11825  *
11826  * Sets @actor as reactive. Reactive actors will receive events.
11827  *
11828  * Since: 0.6
11829  */
11830 void
11831 clutter_actor_set_reactive (ClutterActor *actor,
11832                             gboolean      reactive)
11833 {
11834   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11835
11836   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11837     return;
11838
11839   if (reactive)
11840     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11841   else
11842     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11843
11844   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11845 }
11846
11847 /**
11848  * clutter_actor_get_reactive:
11849  * @actor: a #ClutterActor
11850  *
11851  * Checks whether @actor is marked as reactive.
11852  *
11853  * Return value: %TRUE if the actor is reactive
11854  *
11855  * Since: 0.6
11856  */
11857 gboolean
11858 clutter_actor_get_reactive (ClutterActor *actor)
11859 {
11860   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11861
11862   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11863 }
11864
11865 /**
11866  * clutter_actor_get_anchor_point:
11867  * @self: a #ClutterActor
11868  * @anchor_x: (out): return location for the X coordinate of the anchor point
11869  * @anchor_y: (out): return location for the Y coordinate of the anchor point
11870  *
11871  * Gets the current anchor point of the @actor in pixels.
11872  *
11873  * Since: 0.6
11874  */
11875 void
11876 clutter_actor_get_anchor_point (ClutterActor *self,
11877                                 gfloat       *anchor_x,
11878                                 gfloat       *anchor_y)
11879 {
11880   const ClutterTransformInfo *info;
11881
11882   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11883
11884   info = _clutter_actor_get_transform_info_or_defaults (self);
11885   clutter_anchor_coord_get_units (self, &info->anchor,
11886                                   anchor_x,
11887                                   anchor_y,
11888                                   NULL);
11889 }
11890
11891 /**
11892  * clutter_actor_set_anchor_point:
11893  * @self: a #ClutterActor
11894  * @anchor_x: X coordinate of the anchor point
11895  * @anchor_y: Y coordinate of the anchor point
11896  *
11897  * Sets an anchor point for @self. The anchor point is a point in the
11898  * coordinate space of an actor to which the actor position within its
11899  * parent is relative; the default is (0, 0), i.e. the top-left corner
11900  * of the actor.
11901  *
11902  * Since: 0.6
11903  */
11904 void
11905 clutter_actor_set_anchor_point (ClutterActor *self,
11906                                 gfloat        anchor_x,
11907                                 gfloat        anchor_y)
11908 {
11909   ClutterTransformInfo *info;
11910   ClutterActorPrivate *priv;
11911   gboolean changed = FALSE;
11912   gfloat old_anchor_x, old_anchor_y;
11913   GObject *obj;
11914
11915   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11916
11917   obj = G_OBJECT (self);
11918   priv = self->priv;
11919   info = _clutter_actor_get_transform_info (self);
11920
11921   g_object_freeze_notify (obj);
11922
11923   clutter_anchor_coord_get_units (self, &info->anchor,
11924                                   &old_anchor_x,
11925                                   &old_anchor_y,
11926                                   NULL);
11927
11928   if (info->anchor.is_fractional)
11929     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11930
11931   if (old_anchor_x != anchor_x)
11932     {
11933       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11934       changed = TRUE;
11935     }
11936
11937   if (old_anchor_y != anchor_y)
11938     {
11939       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11940       changed = TRUE;
11941     }
11942
11943   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11944
11945   if (changed)
11946     {
11947       priv->transform_valid = FALSE;
11948       clutter_actor_queue_redraw (self);
11949     }
11950
11951   g_object_thaw_notify (obj);
11952 }
11953
11954 /**
11955  * clutter_actor_get_anchor_point_gravity:
11956  * @self: a #ClutterActor
11957  *
11958  * Retrieves the anchor position expressed as a #ClutterGravity. If
11959  * the anchor point was specified using pixels or units this will
11960  * return %CLUTTER_GRAVITY_NONE.
11961  *
11962  * Return value: the #ClutterGravity used by the anchor point
11963  *
11964  * Since: 1.0
11965  */
11966 ClutterGravity
11967 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11968 {
11969   const ClutterTransformInfo *info;
11970
11971   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11972
11973   info = _clutter_actor_get_transform_info_or_defaults (self);
11974
11975   return clutter_anchor_coord_get_gravity (&info->anchor);
11976 }
11977
11978 /**
11979  * clutter_actor_move_anchor_point:
11980  * @self: a #ClutterActor
11981  * @anchor_x: X coordinate of the anchor point
11982  * @anchor_y: Y coordinate of the anchor point
11983  *
11984  * Sets an anchor point for the actor, and adjusts the actor postion so that
11985  * the relative position of the actor toward its parent remains the same.
11986  *
11987  * Since: 0.6
11988  */
11989 void
11990 clutter_actor_move_anchor_point (ClutterActor *self,
11991                                  gfloat        anchor_x,
11992                                  gfloat        anchor_y)
11993 {
11994   gfloat old_anchor_x, old_anchor_y;
11995   const ClutterTransformInfo *info;
11996
11997   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11998
11999   info = _clutter_actor_get_transform_info (self);
12000   clutter_anchor_coord_get_units (self, &info->anchor,
12001                                   &old_anchor_x,
12002                                   &old_anchor_y,
12003                                   NULL);
12004
12005   g_object_freeze_notify (G_OBJECT (self));
12006
12007   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12008
12009   if (self->priv->position_set)
12010     clutter_actor_move_by (self,
12011                            anchor_x - old_anchor_x,
12012                            anchor_y - old_anchor_y);
12013
12014   g_object_thaw_notify (G_OBJECT (self));
12015 }
12016
12017 /**
12018  * clutter_actor_move_anchor_point_from_gravity:
12019  * @self: a #ClutterActor
12020  * @gravity: #ClutterGravity.
12021  *
12022  * Sets an anchor point on the actor based on the given gravity, adjusting the
12023  * actor postion so that its relative position within its parent remains
12024  * unchanged.
12025  *
12026  * Since version 1.0 the anchor point will be stored as a gravity so
12027  * that if the actor changes size then the anchor point will move. For
12028  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12029  * and later double the size of the actor, the anchor point will move
12030  * to the bottom right.
12031  *
12032  * Since: 0.6
12033  */
12034 void
12035 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12036                                               ClutterGravity  gravity)
12037 {
12038   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12039   const ClutterTransformInfo *info;
12040   ClutterActorPrivate *priv;
12041
12042   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12043
12044   priv = self->priv;
12045   info = _clutter_actor_get_transform_info (self);
12046
12047   g_object_freeze_notify (G_OBJECT (self));
12048
12049   clutter_anchor_coord_get_units (self, &info->anchor,
12050                                   &old_anchor_x,
12051                                   &old_anchor_y,
12052                                   NULL);
12053   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12054   clutter_anchor_coord_get_units (self, &info->anchor,
12055                                   &new_anchor_x,
12056                                   &new_anchor_y,
12057                                   NULL);
12058
12059   if (priv->position_set)
12060     clutter_actor_move_by (self,
12061                            new_anchor_x - old_anchor_x,
12062                            new_anchor_y - old_anchor_y);
12063
12064   g_object_thaw_notify (G_OBJECT (self));
12065 }
12066
12067 /**
12068  * clutter_actor_set_anchor_point_from_gravity:
12069  * @self: a #ClutterActor
12070  * @gravity: #ClutterGravity.
12071  *
12072  * Sets an anchor point on the actor, based on the given gravity (this is a
12073  * convenience function wrapping clutter_actor_set_anchor_point()).
12074  *
12075  * Since version 1.0 the anchor point will be stored as a gravity so
12076  * that if the actor changes size then the anchor point will move. For
12077  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12078  * and later double the size of the actor, the anchor point will move
12079  * to the bottom right.
12080  *
12081  * Since: 0.6
12082  */
12083 void
12084 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12085                                              ClutterGravity  gravity)
12086 {
12087   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12088
12089   if (gravity == CLUTTER_GRAVITY_NONE)
12090     clutter_actor_set_anchor_point (self, 0, 0);
12091   else
12092     {
12093       GObject *obj = G_OBJECT (self);
12094       ClutterTransformInfo *info;
12095
12096       g_object_freeze_notify (obj);
12097
12098       info = _clutter_actor_get_transform_info (self);
12099       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12100
12101       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12102       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12103       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12104
12105       self->priv->transform_valid = FALSE;
12106
12107       clutter_actor_queue_redraw (self);
12108
12109       g_object_thaw_notify (obj);
12110     }
12111 }
12112
12113 static void
12114 clutter_container_iface_init (ClutterContainerIface *iface)
12115 {
12116   /* we don't override anything, as ClutterContainer already has a default
12117    * implementation that we can use, and which calls into our own API.
12118    */
12119 }
12120
12121 typedef enum
12122 {
12123   PARSE_X,
12124   PARSE_Y,
12125   PARSE_WIDTH,
12126   PARSE_HEIGHT,
12127   PARSE_ANCHOR_X,
12128   PARSE_ANCHOR_Y
12129 } ParseDimension;
12130
12131 static gfloat
12132 parse_units (ClutterActor   *self,
12133              ParseDimension  dimension,
12134              JsonNode       *node)
12135 {
12136   GValue value = { 0, };
12137   gfloat retval = 0;
12138
12139   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12140     return 0;
12141
12142   json_node_get_value (node, &value);
12143
12144   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12145     {
12146       retval = (gfloat) g_value_get_int64 (&value);
12147     }
12148   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12149     {
12150       retval = g_value_get_double (&value);
12151     }
12152   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12153     {
12154       ClutterUnits units;
12155       gboolean res;
12156
12157       res = clutter_units_from_string (&units, g_value_get_string (&value));
12158       if (res)
12159         retval = clutter_units_to_pixels (&units);
12160       else
12161         {
12162           g_warning ("Invalid value '%s': integers, strings or floating point "
12163                      "values can be used for the x, y, width and height "
12164                      "properties. Valid modifiers for strings are 'px', 'mm', "
12165                      "'pt' and 'em'.",
12166                      g_value_get_string (&value));
12167           retval = 0;
12168         }
12169     }
12170   else
12171     {
12172       g_warning ("Invalid value of type '%s': integers, strings of floating "
12173                  "point values can be used for the x, y, width, height "
12174                  "anchor-x and anchor-y properties.",
12175                  g_type_name (G_VALUE_TYPE (&value)));
12176     }
12177
12178   g_value_unset (&value);
12179
12180   return retval;
12181 }
12182
12183 typedef struct {
12184   ClutterRotateAxis axis;
12185
12186   gdouble angle;
12187
12188   gfloat center_x;
12189   gfloat center_y;
12190   gfloat center_z;
12191 } RotationInfo;
12192
12193 static inline gboolean
12194 parse_rotation_array (ClutterActor *actor,
12195                       JsonArray    *array,
12196                       RotationInfo *info)
12197 {
12198   JsonNode *element;
12199
12200   if (json_array_get_length (array) != 2)
12201     return FALSE;
12202
12203   /* angle */
12204   element = json_array_get_element (array, 0);
12205   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12206     info->angle = json_node_get_double (element);
12207   else
12208     return FALSE;
12209
12210   /* center */
12211   element = json_array_get_element (array, 1);
12212   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12213     {
12214       JsonArray *center = json_node_get_array (element);
12215
12216       if (json_array_get_length (center) != 2)
12217         return FALSE;
12218
12219       switch (info->axis)
12220         {
12221         case CLUTTER_X_AXIS:
12222           info->center_y = parse_units (actor, PARSE_Y,
12223                                         json_array_get_element (center, 0));
12224           info->center_z = parse_units (actor, PARSE_Y,
12225                                         json_array_get_element (center, 1));
12226           return TRUE;
12227
12228         case CLUTTER_Y_AXIS:
12229           info->center_x = parse_units (actor, PARSE_X,
12230                                         json_array_get_element (center, 0));
12231           info->center_z = parse_units (actor, PARSE_X,
12232                                         json_array_get_element (center, 1));
12233           return TRUE;
12234
12235         case CLUTTER_Z_AXIS:
12236           info->center_x = parse_units (actor, PARSE_X,
12237                                         json_array_get_element (center, 0));
12238           info->center_y = parse_units (actor, PARSE_Y,
12239                                         json_array_get_element (center, 1));
12240           return TRUE;
12241         }
12242     }
12243
12244   return FALSE;
12245 }
12246
12247 static gboolean
12248 parse_rotation (ClutterActor *actor,
12249                 JsonNode     *node,
12250                 RotationInfo *info)
12251 {
12252   JsonArray *array;
12253   guint len, i;
12254   gboolean retval = FALSE;
12255
12256   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12257     {
12258       g_warning ("Invalid node of type '%s' found, expecting an array",
12259                  json_node_type_name (node));
12260       return FALSE;
12261     }
12262
12263   array = json_node_get_array (node);
12264   len = json_array_get_length (array);
12265
12266   for (i = 0; i < len; i++)
12267     {
12268       JsonNode *element = json_array_get_element (array, i);
12269       JsonObject *object;
12270       JsonNode *member;
12271
12272       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12273         {
12274           g_warning ("Invalid node of type '%s' found, expecting an object",
12275                      json_node_type_name (element));
12276           return FALSE;
12277         }
12278
12279       object = json_node_get_object (element);
12280
12281       if (json_object_has_member (object, "x-axis"))
12282         {
12283           member = json_object_get_member (object, "x-axis");
12284
12285           info->axis = CLUTTER_X_AXIS;
12286
12287           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12288             {
12289               info->angle = json_node_get_double (member);
12290               retval = TRUE;
12291             }
12292           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12293             retval = parse_rotation_array (actor,
12294                                            json_node_get_array (member),
12295                                            info);
12296           else
12297             retval = FALSE;
12298         }
12299       else if (json_object_has_member (object, "y-axis"))
12300         {
12301           member = json_object_get_member (object, "y-axis");
12302
12303           info->axis = CLUTTER_Y_AXIS;
12304
12305           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12306             {
12307               info->angle = json_node_get_double (member);
12308               retval = TRUE;
12309             }
12310           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12311             retval = parse_rotation_array (actor,
12312                                            json_node_get_array (member),
12313                                            info);
12314           else
12315             retval = FALSE;
12316         }
12317       else if (json_object_has_member (object, "z-axis"))
12318         {
12319           member = json_object_get_member (object, "z-axis");
12320
12321           info->axis = CLUTTER_Z_AXIS;
12322
12323           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12324             {
12325               info->angle = json_node_get_double (member);
12326               retval = TRUE;
12327             }
12328           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12329             retval = parse_rotation_array (actor,
12330                                            json_node_get_array (member),
12331                                            info);
12332           else
12333             retval = FALSE;
12334         }
12335     }
12336
12337   return retval;
12338 }
12339
12340 static GSList *
12341 parse_actor_metas (ClutterScript *script,
12342                    ClutterActor  *actor,
12343                    JsonNode      *node)
12344 {
12345   GList *elements, *l;
12346   GSList *retval = NULL;
12347
12348   if (!JSON_NODE_HOLDS_ARRAY (node))
12349     return NULL;
12350
12351   elements = json_array_get_elements (json_node_get_array (node));
12352
12353   for (l = elements; l != NULL; l = l->next)
12354     {
12355       JsonNode *element = l->data;
12356       const gchar *id_ = _clutter_script_get_id_from_node (element);
12357       GObject *meta;
12358
12359       if (id_ == NULL || *id_ == '\0')
12360         continue;
12361
12362       meta = clutter_script_get_object (script, id_);
12363       if (meta == NULL)
12364         continue;
12365
12366       retval = g_slist_prepend (retval, meta);
12367     }
12368
12369   g_list_free (elements);
12370
12371   return g_slist_reverse (retval);
12372 }
12373
12374 static GSList *
12375 parse_behaviours (ClutterScript *script,
12376                   ClutterActor  *actor,
12377                   JsonNode      *node)
12378 {
12379   GList *elements, *l;
12380   GSList *retval = NULL;
12381
12382   if (!JSON_NODE_HOLDS_ARRAY (node))
12383     return NULL;
12384
12385   elements = json_array_get_elements (json_node_get_array (node));
12386
12387   for (l = elements; l != NULL; l = l->next)
12388     {
12389       JsonNode *element = l->data;
12390       const gchar *id_ = _clutter_script_get_id_from_node (element);
12391       GObject *behaviour;
12392
12393       if (id_ == NULL || *id_ == '\0')
12394         continue;
12395
12396       behaviour = clutter_script_get_object (script, id_);
12397       if (behaviour == NULL)
12398         continue;
12399
12400       retval = g_slist_prepend (retval, behaviour);
12401     }
12402
12403   g_list_free (elements);
12404
12405   return g_slist_reverse (retval);
12406 }
12407
12408 static gboolean
12409 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12410                                  ClutterScript     *script,
12411                                  GValue            *value,
12412                                  const gchar       *name,
12413                                  JsonNode          *node)
12414 {
12415   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12416   gboolean retval = FALSE;
12417
12418   if ((name[0] == 'x' && name[1] == '\0') ||
12419       (name[0] == 'y' && name[1] == '\0') ||
12420       (strcmp (name, "width") == 0) ||
12421       (strcmp (name, "height") == 0) ||
12422       (strcmp (name, "anchor_x") == 0) ||
12423       (strcmp (name, "anchor_y") == 0))
12424     {
12425       ParseDimension dimension;
12426       gfloat units;
12427
12428       if (name[0] == 'x')
12429         dimension = PARSE_X;
12430       else if (name[0] == 'y')
12431         dimension = PARSE_Y;
12432       else if (name[0] == 'w')
12433         dimension = PARSE_WIDTH;
12434       else if (name[0] == 'h')
12435         dimension = PARSE_HEIGHT;
12436       else if (name[0] == 'a' && name[7] == 'x')
12437         dimension = PARSE_ANCHOR_X;
12438       else if (name[0] == 'a' && name[7] == 'y')
12439         dimension = PARSE_ANCHOR_Y;
12440       else
12441         return FALSE;
12442
12443       units = parse_units (actor, dimension, node);
12444
12445       /* convert back to pixels: all properties are pixel-based */
12446       g_value_init (value, G_TYPE_FLOAT);
12447       g_value_set_float (value, units);
12448
12449       retval = TRUE;
12450     }
12451   else if (strcmp (name, "rotation") == 0)
12452     {
12453       RotationInfo *info;
12454
12455       info = g_slice_new0 (RotationInfo);
12456       retval = parse_rotation (actor, node, info);
12457
12458       if (retval)
12459         {
12460           g_value_init (value, G_TYPE_POINTER);
12461           g_value_set_pointer (value, info);
12462         }
12463       else
12464         g_slice_free (RotationInfo, info);
12465     }
12466   else if (strcmp (name, "behaviours") == 0)
12467     {
12468       GSList *l;
12469
12470 #ifdef CLUTTER_ENABLE_DEBUG
12471       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12472         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12473                                      "and it should not be used in newly "
12474                                      "written ClutterScript definitions.");
12475 #endif
12476
12477       l = parse_behaviours (script, actor, node);
12478
12479       g_value_init (value, G_TYPE_POINTER);
12480       g_value_set_pointer (value, l);
12481
12482       retval = TRUE;
12483     }
12484   else if (strcmp (name, "actions") == 0 ||
12485            strcmp (name, "constraints") == 0 ||
12486            strcmp (name, "effects") == 0)
12487     {
12488       GSList *l;
12489
12490       l = parse_actor_metas (script, actor, node);
12491
12492       g_value_init (value, G_TYPE_POINTER);
12493       g_value_set_pointer (value, l);
12494
12495       retval = TRUE;
12496     }
12497
12498   return retval;
12499 }
12500
12501 static void
12502 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12503                                    ClutterScript     *script,
12504                                    const gchar       *name,
12505                                    const GValue      *value)
12506 {
12507   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12508
12509 #ifdef CLUTTER_ENABLE_DEBUG
12510   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12511     {
12512       gchar *tmp = g_strdup_value_contents (value);
12513
12514       CLUTTER_NOTE (SCRIPT,
12515                     "in ClutterActor::set_custom_property('%s') = %s",
12516                     name,
12517                     tmp);
12518
12519       g_free (tmp);
12520     }
12521 #endif /* CLUTTER_ENABLE_DEBUG */
12522
12523   if (strcmp (name, "rotation") == 0)
12524     {
12525       RotationInfo *info;
12526
12527       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12528         return;
12529
12530       info = g_value_get_pointer (value);
12531
12532       clutter_actor_set_rotation (actor,
12533                                   info->axis, info->angle,
12534                                   info->center_x,
12535                                   info->center_y,
12536                                   info->center_z);
12537
12538       g_slice_free (RotationInfo, info);
12539
12540       return;
12541     }
12542
12543   if (strcmp (name, "behaviours") == 0)
12544     {
12545       GSList *behaviours, *l;
12546
12547       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12548         return;
12549
12550       behaviours = g_value_get_pointer (value);
12551       for (l = behaviours; l != NULL; l = l->next)
12552         {
12553           ClutterBehaviour *behaviour = l->data;
12554
12555           clutter_behaviour_apply (behaviour, actor);
12556         }
12557
12558       g_slist_free (behaviours);
12559
12560       return;
12561     }
12562
12563   if (strcmp (name, "actions") == 0 ||
12564       strcmp (name, "constraints") == 0 ||
12565       strcmp (name, "effects") == 0)
12566     {
12567       GSList *metas, *l;
12568
12569       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12570         return;
12571
12572       metas = g_value_get_pointer (value);
12573       for (l = metas; l != NULL; l = l->next)
12574         {
12575           if (name[0] == 'a')
12576             clutter_actor_add_action (actor, l->data);
12577
12578           if (name[0] == 'c')
12579             clutter_actor_add_constraint (actor, l->data);
12580
12581           if (name[0] == 'e')
12582             clutter_actor_add_effect (actor, l->data);
12583         }
12584
12585       g_slist_free (metas);
12586
12587       return;
12588     }
12589
12590   g_object_set_property (G_OBJECT (scriptable), name, value);
12591 }
12592
12593 static void
12594 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12595 {
12596   iface->parse_custom_node = clutter_actor_parse_custom_node;
12597   iface->set_custom_property = clutter_actor_set_custom_property;
12598 }
12599
12600 static ClutterActorMeta *
12601 get_meta_from_animation_property (ClutterActor  *actor,
12602                                   const gchar   *name,
12603                                   gchar        **name_p)
12604 {
12605   ClutterActorPrivate *priv = actor->priv;
12606   ClutterActorMeta *meta = NULL;
12607   gchar **tokens;
12608
12609   /* if this is not a special property, fall through */
12610   if (name[0] != '@')
12611     return NULL;
12612
12613   /* detect the properties named using the following spec:
12614    *
12615    *   @<section>.<meta-name>.<property-name>
12616    *
12617    * where <section> can be one of the following:
12618    *
12619    *   - actions
12620    *   - constraints
12621    *   - effects
12622    *
12623    * and <meta-name> is the name set on a specific ActorMeta
12624    */
12625
12626   tokens = g_strsplit (name + 1, ".", -1);
12627   if (tokens == NULL || g_strv_length (tokens) != 3)
12628     {
12629       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12630                     name + 1);
12631       g_strfreev (tokens);
12632       return NULL;
12633     }
12634
12635   if (strcmp (tokens[0], "actions") == 0)
12636     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12637
12638   if (strcmp (tokens[0], "constraints") == 0)
12639     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12640
12641   if (strcmp (tokens[0], "effects") == 0)
12642     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12643
12644   if (name_p != NULL)
12645     *name_p = g_strdup (tokens[2]);
12646
12647   CLUTTER_NOTE (ANIMATION,
12648                 "Looking for property '%s' of object '%s' in section '%s'",
12649                 tokens[2],
12650                 tokens[1],
12651                 tokens[0]);
12652
12653   g_strfreev (tokens);
12654
12655   return meta;
12656 }
12657
12658 static GParamSpec *
12659 clutter_actor_find_property (ClutterAnimatable *animatable,
12660                              const gchar       *property_name)
12661 {
12662   ClutterActorMeta *meta = NULL;
12663   GObjectClass *klass = NULL;
12664   GParamSpec *pspec = NULL;
12665   gchar *p_name = NULL;
12666
12667   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12668                                            property_name,
12669                                            &p_name);
12670
12671   if (meta != NULL)
12672     {
12673       klass = G_OBJECT_GET_CLASS (meta);
12674
12675       pspec = g_object_class_find_property (klass, p_name);
12676     }
12677   else
12678     {
12679       klass = G_OBJECT_GET_CLASS (animatable);
12680
12681       pspec = g_object_class_find_property (klass, property_name);
12682     }
12683
12684   g_free (p_name);
12685
12686   return pspec;
12687 }
12688
12689 static void
12690 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12691                                  const gchar       *property_name,
12692                                  GValue            *initial)
12693 {
12694   ClutterActorMeta *meta = NULL;
12695   gchar *p_name = NULL;
12696
12697   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12698                                            property_name,
12699                                            &p_name);
12700
12701   if (meta != NULL)
12702     g_object_get_property (G_OBJECT (meta), p_name, initial);
12703   else
12704     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12705
12706   g_free (p_name);
12707 }
12708
12709 /*
12710  * clutter_actor_set_animatable_property:
12711  * @actor: a #ClutterActor
12712  * @prop_id: the paramspec id
12713  * @value: the value to set
12714  * @pspec: the paramspec
12715  *
12716  * Sets values of animatable properties.
12717  *
12718  * This is a variant of clutter_actor_set_property() that gets called
12719  * by the #ClutterAnimatable implementation of #ClutterActor for the
12720  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12721  * #GParamSpec.
12722  *
12723  * Unlike the implementation of #GObjectClass.set_property(), this
12724  * function will not update the interval if a transition involving an
12725  * animatable property is in progress - this avoids cycles with the
12726  * transition API calling the public API.
12727  */
12728 static void
12729 clutter_actor_set_animatable_property (ClutterActor *actor,
12730                                        guint         prop_id,
12731                                        const GValue *value,
12732                                        GParamSpec   *pspec)
12733 {
12734   switch (prop_id)
12735     {
12736     case PROP_X:
12737       clutter_actor_set_x_internal (actor, g_value_get_float (value));
12738       break;
12739
12740     case PROP_Y:
12741       clutter_actor_set_y_internal (actor, g_value_get_float (value));
12742       break;
12743
12744     case PROP_WIDTH:
12745       clutter_actor_set_width_internal (actor, g_value_get_float (value));
12746       break;
12747
12748     case PROP_HEIGHT:
12749       clutter_actor_set_height_internal (actor, g_value_get_float (value));
12750       break;
12751
12752     case PROP_DEPTH:
12753       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12754       break;
12755
12756     case PROP_OPACITY:
12757       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12758       break;
12759
12760     case PROP_BACKGROUND_COLOR:
12761       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12762       break;
12763
12764     case PROP_SCALE_X:
12765       clutter_actor_set_scale_factor_internal (actor,
12766                                                g_value_get_double (value),
12767                                                pspec);
12768       break;
12769
12770     case PROP_SCALE_Y:
12771       clutter_actor_set_scale_factor_internal (actor,
12772                                                g_value_get_double (value),
12773                                                pspec);
12774       break;
12775
12776     case PROP_ROTATION_ANGLE_X:
12777       clutter_actor_set_rotation_angle_internal (actor,
12778                                                  CLUTTER_X_AXIS,
12779                                                  g_value_get_double (value));
12780       break;
12781
12782     case PROP_ROTATION_ANGLE_Y:
12783       clutter_actor_set_rotation_angle_internal (actor,
12784                                                  CLUTTER_Y_AXIS,
12785                                                  g_value_get_double (value));
12786       break;
12787
12788     case PROP_ROTATION_ANGLE_Z:
12789       clutter_actor_set_rotation_angle_internal (actor,
12790                                                  CLUTTER_Z_AXIS,
12791                                                  g_value_get_double (value));
12792       break;
12793
12794     default:
12795       g_object_set_property (G_OBJECT (actor), pspec->name, value);
12796       break;
12797     }
12798 }
12799
12800 static void
12801 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12802                                const gchar       *property_name,
12803                                const GValue      *final)
12804 {
12805   ClutterActor *actor = CLUTTER_ACTOR (animatable);
12806   ClutterActorMeta *meta = NULL;
12807   gchar *p_name = NULL;
12808
12809   meta = get_meta_from_animation_property (actor,
12810                                            property_name,
12811                                            &p_name);
12812   if (meta != NULL)
12813     g_object_set_property (G_OBJECT (meta), p_name, final);
12814   else
12815     {
12816       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12817       GParamSpec *pspec;
12818
12819       pspec = g_object_class_find_property (obj_class, property_name);
12820
12821       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12822         {
12823           /* XXX - I'm going to the special hell for this */
12824           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12825         }
12826       else
12827         g_object_set_property (G_OBJECT (animatable), property_name, final);
12828     }
12829
12830   g_free (p_name);
12831 }
12832
12833 static void
12834 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12835 {
12836   iface->find_property = clutter_actor_find_property;
12837   iface->get_initial_state = clutter_actor_get_initial_state;
12838   iface->set_final_state = clutter_actor_set_final_state;
12839 }
12840
12841 /**
12842  * clutter_actor_transform_stage_point:
12843  * @self: A #ClutterActor
12844  * @x: (in): x screen coordinate of the point to unproject
12845  * @y: (in): y screen coordinate of the point to unproject
12846  * @x_out: (out): return location for the unprojected x coordinance
12847  * @y_out: (out): return location for the unprojected y coordinance
12848  *
12849  * This function translates screen coordinates (@x, @y) to
12850  * coordinates relative to the actor. For example, it can be used to translate
12851  * screen events from global screen coordinates into actor-local coordinates.
12852  *
12853  * The conversion can fail, notably if the transform stack results in the
12854  * actor being projected on the screen as a mere line.
12855  *
12856  * The conversion should not be expected to be pixel-perfect due to the
12857  * nature of the operation. In general the error grows when the skewing
12858  * of the actor rectangle on screen increases.
12859  *
12860  * <note><para>This function can be computationally intensive.</para></note>
12861  *
12862  * <note><para>This function only works when the allocation is up-to-date,
12863  * i.e. inside of paint().</para></note>
12864  *
12865  * Return value: %TRUE if conversion was successful.
12866  *
12867  * Since: 0.6
12868  */
12869 gboolean
12870 clutter_actor_transform_stage_point (ClutterActor *self,
12871                                      gfloat        x,
12872                                      gfloat        y,
12873                                      gfloat       *x_out,
12874                                      gfloat       *y_out)
12875 {
12876   ClutterVertex v[4];
12877   float ST[3][3];
12878   float RQ[3][3];
12879   int du, dv, xi, yi;
12880   float px, py;
12881   float xf, yf, wf, det;
12882   ClutterActorPrivate *priv;
12883
12884   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12885
12886   priv = self->priv;
12887
12888   /* This implementation is based on the quad -> quad projection algorithm
12889    * described by Paul Heckbert in:
12890    *
12891    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12892    *
12893    * and the sample implementation at:
12894    *
12895    *   http://www.cs.cmu.edu/~ph/src/texfund/
12896    *
12897    * Our texture is a rectangle with origin [0, 0], so we are mapping from
12898    * quad to rectangle only, which significantly simplifies things; the
12899    * function calls have been unrolled, and most of the math is done in fixed
12900    * point.
12901    */
12902
12903   clutter_actor_get_abs_allocation_vertices (self, v);
12904
12905   /* Keeping these as ints simplifies the multiplication (no significant
12906    * loss of precision here).
12907    */
12908   du = (int) (priv->allocation.x2 - priv->allocation.x1);
12909   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12910
12911   if (!du || !dv)
12912     return FALSE;
12913
12914 #define UX2FP(x)        (x)
12915 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12916
12917   /* First, find mapping from unit uv square to xy quadrilateral; this
12918    * equivalent to the pmap_square_quad() functions in the sample
12919    * implementation, which we can simplify, since our target is always
12920    * a rectangle.
12921    */
12922   px = v[0].x - v[1].x + v[3].x - v[2].x;
12923   py = v[0].y - v[1].y + v[3].y - v[2].y;
12924
12925   if (!px && !py)
12926     {
12927       /* affine transform */
12928       RQ[0][0] = UX2FP (v[1].x - v[0].x);
12929       RQ[1][0] = UX2FP (v[3].x - v[1].x);
12930       RQ[2][0] = UX2FP (v[0].x);
12931       RQ[0][1] = UX2FP (v[1].y - v[0].y);
12932       RQ[1][1] = UX2FP (v[3].y - v[1].y);
12933       RQ[2][1] = UX2FP (v[0].y);
12934       RQ[0][2] = 0;
12935       RQ[1][2] = 0;
12936       RQ[2][2] = 1.0;
12937     }
12938   else
12939     {
12940       /* projective transform */
12941       double dx1, dx2, dy1, dy2, del;
12942
12943       dx1 = UX2FP (v[1].x - v[3].x);
12944       dx2 = UX2FP (v[2].x - v[3].x);
12945       dy1 = UX2FP (v[1].y - v[3].y);
12946       dy2 = UX2FP (v[2].y - v[3].y);
12947
12948       del = DET2FP (dx1, dx2, dy1, dy2);
12949       if (!del)
12950         return FALSE;
12951
12952       /*
12953        * The division here needs to be done in floating point for
12954        * precisions reasons.
12955        */
12956       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12957       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12958       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12959       RQ[2][2] = 1.0;
12960       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12961       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12962       RQ[2][0] = UX2FP (v[0].x);
12963       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12964       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12965       RQ[2][1] = UX2FP (v[0].y);
12966     }
12967
12968   /*
12969    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12970    * square. Since our rectangle is based at 0,0 we only need to scale.
12971    */
12972   RQ[0][0] /= du;
12973   RQ[1][0] /= dv;
12974   RQ[0][1] /= du;
12975   RQ[1][1] /= dv;
12976   RQ[0][2] /= du;
12977   RQ[1][2] /= dv;
12978
12979   /*
12980    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12981    * inverse of that.
12982    */
12983   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12984   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12985   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12986   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12987   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12988   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12989   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12990   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12991   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12992
12993   /*
12994    * Check the resulting matrix is OK.
12995    */
12996   det = (RQ[0][0] * ST[0][0])
12997       + (RQ[0][1] * ST[0][1])
12998       + (RQ[0][2] * ST[0][2]);
12999   if (!det)
13000     return FALSE;
13001
13002   /*
13003    * Now transform our point with the ST matrix; the notional w
13004    * coordinate is 1, hence the last part is simply added.
13005    */
13006   xi = (int) x;
13007   yi = (int) y;
13008
13009   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13010   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13011   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13012
13013   if (x_out)
13014     *x_out = xf / wf;
13015
13016   if (y_out)
13017     *y_out = yf / wf;
13018
13019 #undef UX2FP
13020 #undef DET2FP
13021
13022   return TRUE;
13023 }
13024
13025 /*
13026  * ClutterGeometry
13027  */
13028
13029 static ClutterGeometry*
13030 clutter_geometry_copy (const ClutterGeometry *geometry)
13031 {
13032   return g_slice_dup (ClutterGeometry, geometry);
13033 }
13034
13035 static void
13036 clutter_geometry_free (ClutterGeometry *geometry)
13037 {
13038   if (G_LIKELY (geometry != NULL))
13039     g_slice_free (ClutterGeometry, geometry);
13040 }
13041
13042 /**
13043  * clutter_geometry_union:
13044  * @geometry_a: a #ClutterGeometry
13045  * @geometry_b: another #ClutterGeometry
13046  * @result: (out): location to store the result
13047  *
13048  * Find the union of two rectangles represented as #ClutterGeometry.
13049  *
13050  * Since: 1.4
13051  */
13052 void
13053 clutter_geometry_union (const ClutterGeometry *geometry_a,
13054                         const ClutterGeometry *geometry_b,
13055                         ClutterGeometry       *result)
13056 {
13057   /* We don't try to handle rectangles that can't be represented
13058    * as a signed integer box */
13059   gint x_1 = MIN (geometry_a->x, geometry_b->x);
13060   gint y_1 = MIN (geometry_a->y, geometry_b->y);
13061   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13062                   geometry_b->x + (gint)geometry_b->width);
13063   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13064                   geometry_b->y + (gint)geometry_b->height);
13065   result->x = x_1;
13066   result->y = y_1;
13067   result->width = x_2 - x_1;
13068   result->height = y_2 - y_1;
13069 }
13070
13071 /**
13072  * clutter_geometry_intersects:
13073  * @geometry0: The first geometry to test
13074  * @geometry1: The second geometry to test
13075  *
13076  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13077  * they do else %FALSE.
13078  *
13079  * Return value: %TRUE of @geometry0 and geometry1 intersect else
13080  * %FALSE.
13081  *
13082  * Since: 1.4
13083  */
13084 gboolean
13085 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13086                              const ClutterGeometry *geometry1)
13087 {
13088   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13089       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13090       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13091       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13092     return FALSE;
13093   else
13094     return TRUE;
13095 }
13096
13097 static gboolean
13098 clutter_geometry_progress (const GValue *a,
13099                            const GValue *b,
13100                            gdouble       progress,
13101                            GValue       *retval)
13102 {
13103   const ClutterGeometry *a_geom = g_value_get_boxed (a);
13104   const ClutterGeometry *b_geom = g_value_get_boxed (b);
13105   ClutterGeometry res = { 0, };
13106   gint a_width = a_geom->width;
13107   gint b_width = b_geom->width;
13108   gint a_height = a_geom->height;
13109   gint b_height = b_geom->height;
13110
13111   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13112   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13113
13114   res.width = a_width + (b_width - a_width) * progress;
13115   res.height = a_height + (b_height - a_height) * progress;
13116
13117   g_value_set_boxed (retval, &res);
13118
13119   return TRUE;
13120 }
13121
13122 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13123                                clutter_geometry_copy,
13124                                clutter_geometry_free,
13125                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13126
13127 /*
13128  * ClutterVertices
13129  */
13130
13131 /**
13132  * clutter_vertex_new:
13133  * @x: X coordinate
13134  * @y: Y coordinate
13135  * @z: Z coordinate
13136  *
13137  * Creates a new #ClutterVertex for the point in 3D space
13138  * identified by the 3 coordinates @x, @y, @z
13139  *
13140  * Return value: the newly allocate #ClutterVertex. Use
13141  *   clutter_vertex_free() to free the resources
13142  *
13143  * Since: 1.0
13144  */
13145 ClutterVertex *
13146 clutter_vertex_new (gfloat x,
13147                     gfloat y,
13148                     gfloat z)
13149 {
13150   ClutterVertex *vertex;
13151
13152   vertex = g_slice_new (ClutterVertex);
13153   vertex->x = x;
13154   vertex->y = y;
13155   vertex->z = z;
13156
13157   return vertex;
13158 }
13159
13160 /**
13161  * clutter_vertex_copy:
13162  * @vertex: a #ClutterVertex
13163  *
13164  * Copies @vertex
13165  *
13166  * Return value: a newly allocated copy of #ClutterVertex. Use
13167  *   clutter_vertex_free() to free the allocated resources
13168  *
13169  * Since: 1.0
13170  */
13171 ClutterVertex *
13172 clutter_vertex_copy (const ClutterVertex *vertex)
13173 {
13174   if (G_LIKELY (vertex != NULL))
13175     return g_slice_dup (ClutterVertex, vertex);
13176
13177   return NULL;
13178 }
13179
13180 /**
13181  * clutter_vertex_free:
13182  * @vertex: a #ClutterVertex
13183  *
13184  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13185  *
13186  * Since: 1.0
13187  */
13188 void
13189 clutter_vertex_free (ClutterVertex *vertex)
13190 {
13191   if (G_UNLIKELY (vertex != NULL))
13192     g_slice_free (ClutterVertex, vertex);
13193 }
13194
13195 /**
13196  * clutter_vertex_equal:
13197  * @vertex_a: a #ClutterVertex
13198  * @vertex_b: a #ClutterVertex
13199  *
13200  * Compares @vertex_a and @vertex_b for equality
13201  *
13202  * Return value: %TRUE if the passed #ClutterVertex are equal
13203  *
13204  * Since: 1.0
13205  */
13206 gboolean
13207 clutter_vertex_equal (const ClutterVertex *vertex_a,
13208                       const ClutterVertex *vertex_b)
13209 {
13210   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13211
13212   if (vertex_a == vertex_b)
13213     return TRUE;
13214
13215   return vertex_a->x == vertex_b->x &&
13216          vertex_a->y == vertex_b->y &&
13217          vertex_a->z == vertex_b->z;
13218 }
13219
13220 static gboolean
13221 clutter_vertex_progress (const GValue *a,
13222                          const GValue *b,
13223                          gdouble       progress,
13224                          GValue       *retval)
13225 {
13226   const ClutterVertex *av = g_value_get_boxed (a);
13227   const ClutterVertex *bv = g_value_get_boxed (b);
13228   ClutterVertex res = { 0, };
13229
13230   res.x = av->x + (bv->x - av->x) * progress;
13231   res.y = av->y + (bv->y - av->y) * progress;
13232   res.z = av->z + (bv->z - av->z) * progress;
13233
13234   g_value_set_boxed (retval, &res);
13235
13236   return TRUE;
13237 }
13238
13239 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13240                                clutter_vertex_copy,
13241                                clutter_vertex_free,
13242                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13243
13244 /**
13245  * clutter_actor_is_rotated:
13246  * @self: a #ClutterActor
13247  *
13248  * Checks whether any rotation is applied to the actor.
13249  *
13250  * Return value: %TRUE if the actor is rotated.
13251  *
13252  * Since: 0.6
13253  */
13254 gboolean
13255 clutter_actor_is_rotated (ClutterActor *self)
13256 {
13257   const ClutterTransformInfo *info;
13258
13259   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13260
13261   info = _clutter_actor_get_transform_info_or_defaults (self);
13262
13263   if (info->rx_angle || info->ry_angle || info->rz_angle)
13264     return TRUE;
13265
13266   return FALSE;
13267 }
13268
13269 /**
13270  * clutter_actor_is_scaled:
13271  * @self: a #ClutterActor
13272  *
13273  * Checks whether the actor is scaled in either dimension.
13274  *
13275  * Return value: %TRUE if the actor is scaled.
13276  *
13277  * Since: 0.6
13278  */
13279 gboolean
13280 clutter_actor_is_scaled (ClutterActor *self)
13281 {
13282   const ClutterTransformInfo *info;
13283
13284   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13285
13286   info = _clutter_actor_get_transform_info_or_defaults (self);
13287
13288   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13289     return TRUE;
13290
13291   return FALSE;
13292 }
13293
13294 ClutterActor *
13295 _clutter_actor_get_stage_internal (ClutterActor *actor)
13296 {
13297   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13298     actor = actor->priv->parent;
13299
13300   return actor;
13301 }
13302
13303 /**
13304  * clutter_actor_get_stage:
13305  * @actor: a #ClutterActor
13306  *
13307  * Retrieves the #ClutterStage where @actor is contained.
13308  *
13309  * Return value: (transfer none) (type Clutter.Stage): the stage
13310  *   containing the actor, or %NULL
13311  *
13312  * Since: 0.8
13313  */
13314 ClutterActor *
13315 clutter_actor_get_stage (ClutterActor *actor)
13316 {
13317   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13318
13319   return _clutter_actor_get_stage_internal (actor);
13320 }
13321
13322 /**
13323  * clutter_actor_allocate_available_size:
13324  * @self: a #ClutterActor
13325  * @x: the actor's X coordinate
13326  * @y: the actor's Y coordinate
13327  * @available_width: the maximum available width, or -1 to use the
13328  *   actor's natural width
13329  * @available_height: the maximum available height, or -1 to use the
13330  *   actor's natural height
13331  * @flags: flags controlling the allocation
13332  *
13333  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13334  * preferred size, but limiting it to the maximum available width
13335  * and height provided.
13336  *
13337  * This function will do the right thing when dealing with the
13338  * actor's request mode.
13339  *
13340  * The implementation of this function is equivalent to:
13341  *
13342  * |[
13343  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13344  *     {
13345  *       clutter_actor_get_preferred_width (self, available_height,
13346  *                                          &amp;min_width,
13347  *                                          &amp;natural_width);
13348  *       width = CLAMP (natural_width, min_width, available_width);
13349  *
13350  *       clutter_actor_get_preferred_height (self, width,
13351  *                                           &amp;min_height,
13352  *                                           &amp;natural_height);
13353  *       height = CLAMP (natural_height, min_height, available_height);
13354  *     }
13355  *   else
13356  *     {
13357  *       clutter_actor_get_preferred_height (self, available_width,
13358  *                                           &amp;min_height,
13359  *                                           &amp;natural_height);
13360  *       height = CLAMP (natural_height, min_height, available_height);
13361  *
13362  *       clutter_actor_get_preferred_width (self, height,
13363  *                                          &amp;min_width,
13364  *                                          &amp;natural_width);
13365  *       width = CLAMP (natural_width, min_width, available_width);
13366  *     }
13367  *
13368  *   box.x1 = x; box.y1 = y;
13369  *   box.x2 = box.x1 + available_width;
13370  *   box.y2 = box.y1 + available_height;
13371  *   clutter_actor_allocate (self, &amp;box, flags);
13372  * ]|
13373  *
13374  * This function can be used by fluid layout managers to allocate
13375  * an actor's preferred size without making it bigger than the area
13376  * available for the container.
13377  *
13378  * Since: 1.0
13379  */
13380 void
13381 clutter_actor_allocate_available_size (ClutterActor           *self,
13382                                        gfloat                  x,
13383                                        gfloat                  y,
13384                                        gfloat                  available_width,
13385                                        gfloat                  available_height,
13386                                        ClutterAllocationFlags  flags)
13387 {
13388   ClutterActorPrivate *priv;
13389   gfloat width, height;
13390   gfloat min_width, min_height;
13391   gfloat natural_width, natural_height;
13392   ClutterActorBox box;
13393
13394   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13395
13396   priv = self->priv;
13397
13398   width = height = 0.0;
13399
13400   switch (priv->request_mode)
13401     {
13402     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13403       clutter_actor_get_preferred_width (self, available_height,
13404                                          &min_width,
13405                                          &natural_width);
13406       width  = CLAMP (natural_width, min_width, available_width);
13407
13408       clutter_actor_get_preferred_height (self, width,
13409                                           &min_height,
13410                                           &natural_height);
13411       height = CLAMP (natural_height, min_height, available_height);
13412       break;
13413
13414     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13415       clutter_actor_get_preferred_height (self, available_width,
13416                                           &min_height,
13417                                           &natural_height);
13418       height = CLAMP (natural_height, min_height, available_height);
13419
13420       clutter_actor_get_preferred_width (self, height,
13421                                          &min_width,
13422                                          &natural_width);
13423       width  = CLAMP (natural_width, min_width, available_width);
13424       break;
13425     }
13426
13427
13428   box.x1 = x;
13429   box.y1 = y;
13430   box.x2 = box.x1 + width;
13431   box.y2 = box.y1 + height;
13432   clutter_actor_allocate (self, &box, flags);
13433 }
13434
13435 /**
13436  * clutter_actor_allocate_preferred_size:
13437  * @self: a #ClutterActor
13438  * @flags: flags controlling the allocation
13439  *
13440  * Allocates the natural size of @self.
13441  *
13442  * This function is a utility call for #ClutterActor implementations
13443  * that allocates the actor's preferred natural size. It can be used
13444  * by fixed layout managers (like #ClutterGroup or so called
13445  * 'composite actors') inside the ClutterActor::allocate
13446  * implementation to give each child exactly how much space it
13447  * requires.
13448  *
13449  * This function is not meant to be used by applications. It is also
13450  * not meant to be used outside the implementation of the
13451  * ClutterActor::allocate virtual function.
13452  *
13453  * Since: 0.8
13454  */
13455 void
13456 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13457                                        ClutterAllocationFlags  flags)
13458 {
13459   gfloat actor_x, actor_y;
13460   gfloat natural_width, natural_height;
13461   ClutterActorBox actor_box;
13462
13463   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13464
13465   actor_x = clutter_actor_get_x (self);
13466   actor_y = clutter_actor_get_y (self);
13467
13468   clutter_actor_get_preferred_size (self,
13469                                     NULL, NULL,
13470                                     &natural_width,
13471                                     &natural_height);
13472
13473   actor_box.x1 = actor_x;
13474   actor_box.y1 = actor_y;
13475   actor_box.x2 = actor_box.x1 + natural_width;
13476   actor_box.y2 = actor_box.y1 + natural_height;
13477
13478   clutter_actor_allocate (self, &actor_box, flags);
13479 }
13480
13481 /**
13482  * clutter_actor_allocate_align_fill:
13483  * @self: a #ClutterActor
13484  * @box: a #ClutterActorBox, containing the available width and height
13485  * @x_align: the horizontal alignment, between 0 and 1
13486  * @y_align: the vertical alignment, between 0 and 1
13487  * @x_fill: whether the actor should fill horizontally
13488  * @y_fill: whether the actor should fill vertically
13489  * @flags: allocation flags to be passed to clutter_actor_allocate()
13490  *
13491  * Allocates @self by taking into consideration the available allocation
13492  * area; an alignment factor on either axis; and whether the actor should
13493  * fill the allocation on either axis.
13494  *
13495  * The @box should contain the available allocation width and height;
13496  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13497  * allocation will be offset by their value.
13498  *
13499  * This function takes into consideration the geometry request specified by
13500  * the #ClutterActor:request-mode property, and the text direction.
13501  *
13502  * This function is useful for fluid layout managers, like #ClutterBinLayout
13503  * or #ClutterTableLayout
13504  *
13505  * Since: 1.4
13506  */
13507 void
13508 clutter_actor_allocate_align_fill (ClutterActor           *self,
13509                                    const ClutterActorBox  *box,
13510                                    gdouble                 x_align,
13511                                    gdouble                 y_align,
13512                                    gboolean                x_fill,
13513                                    gboolean                y_fill,
13514                                    ClutterAllocationFlags  flags)
13515 {
13516   ClutterActorPrivate *priv;
13517   ClutterActorBox allocation = { 0, };
13518   gfloat x_offset, y_offset;
13519   gfloat available_width, available_height;
13520   gfloat child_width, child_height;
13521
13522   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13523   g_return_if_fail (box != NULL);
13524   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13525   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13526
13527   priv = self->priv;
13528
13529   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13530   clutter_actor_box_get_size (box, &available_width, &available_height);
13531
13532   if (available_width < 0)
13533     available_width = 0;
13534
13535   if (available_height < 0)
13536     available_height = 0;
13537
13538   if (x_fill)
13539     {
13540       allocation.x1 = x_offset;
13541       allocation.x2 = allocation.x1 + available_width;
13542     }
13543
13544   if (y_fill)
13545     {
13546       allocation.y1 = y_offset;
13547       allocation.y2 = allocation.y1 + available_height;
13548     }
13549
13550   /* if we are filling horizontally and vertically then we're done */
13551   if (x_fill && y_fill)
13552     goto out;
13553
13554   child_width = child_height = 0.0f;
13555
13556   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13557     {
13558       gfloat min_width, natural_width;
13559       gfloat min_height, natural_height;
13560
13561       clutter_actor_get_preferred_width (self, available_height,
13562                                          &min_width,
13563                                          &natural_width);
13564
13565       child_width = CLAMP (natural_width, min_width, available_width);
13566
13567       if (!y_fill)
13568         {
13569           clutter_actor_get_preferred_height (self, child_width,
13570                                               &min_height,
13571                                               &natural_height);
13572
13573           child_height = CLAMP (natural_height, min_height, available_height);
13574         }
13575     }
13576   else
13577     {
13578       gfloat min_width, natural_width;
13579       gfloat min_height, natural_height;
13580
13581       clutter_actor_get_preferred_height (self, available_width,
13582                                           &min_height,
13583                                           &natural_height);
13584
13585       child_height = CLAMP (natural_height, min_height, available_height);
13586
13587       if (!x_fill)
13588         {
13589           clutter_actor_get_preferred_width (self, child_height,
13590                                              &min_width,
13591                                              &natural_width);
13592
13593           child_width = CLAMP (natural_width, min_width, available_width);
13594         }
13595     }
13596
13597   /* invert the horizontal alignment for RTL languages */
13598   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13599     x_align = 1.0 - x_align;
13600
13601   if (!x_fill)
13602     {
13603       allocation.x1 = x_offset
13604                     + ((available_width - child_width) * x_align);
13605       allocation.x2 = allocation.x1 + child_width;
13606     }
13607
13608   if (!y_fill)
13609     {
13610       allocation.y1 = y_offset
13611                     + ((available_height - child_height) * y_align);
13612       allocation.y2 = allocation.y1 + child_height;
13613     }
13614
13615 out:
13616   clutter_actor_box_clamp_to_pixel (&allocation);
13617   clutter_actor_allocate (self, &allocation, flags);
13618 }
13619
13620 /**
13621  * clutter_actor_grab_key_focus:
13622  * @self: a #ClutterActor
13623  *
13624  * Sets the key focus of the #ClutterStage including @self
13625  * to this #ClutterActor.
13626  *
13627  * Since: 1.0
13628  */
13629 void
13630 clutter_actor_grab_key_focus (ClutterActor *self)
13631 {
13632   ClutterActor *stage;
13633
13634   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13635
13636   stage = _clutter_actor_get_stage_internal (self);
13637   if (stage != NULL)
13638     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13639 }
13640
13641 /**
13642  * clutter_actor_get_pango_context:
13643  * @self: a #ClutterActor
13644  *
13645  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13646  * is already configured using the appropriate font map, resolution
13647  * and font options.
13648  *
13649  * Unlike clutter_actor_create_pango_context(), this context is owend
13650  * by the #ClutterActor and it will be updated each time the options
13651  * stored by the #ClutterBackend change.
13652  *
13653  * You can use the returned #PangoContext to create a #PangoLayout
13654  * and render text using cogl_pango_render_layout() to reuse the
13655  * glyphs cache also used by Clutter.
13656  *
13657  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13658  *   The returned #PangoContext is owned by the actor and should not be
13659  *   unreferenced by the application code
13660  *
13661  * Since: 1.0
13662  */
13663 PangoContext *
13664 clutter_actor_get_pango_context (ClutterActor *self)
13665 {
13666   ClutterActorPrivate *priv;
13667
13668   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13669
13670   priv = self->priv;
13671
13672   if (priv->pango_context != NULL)
13673     return priv->pango_context;
13674
13675   priv->pango_context = _clutter_context_get_pango_context ();
13676   g_object_ref (priv->pango_context);
13677
13678   return priv->pango_context;
13679 }
13680
13681 /**
13682  * clutter_actor_create_pango_context:
13683  * @self: a #ClutterActor
13684  *
13685  * Creates a #PangoContext for the given actor. The #PangoContext
13686  * is already configured using the appropriate font map, resolution
13687  * and font options.
13688  *
13689  * See also clutter_actor_get_pango_context().
13690  *
13691  * Return value: (transfer full): the newly created #PangoContext.
13692  *   Use g_object_unref() on the returned value to deallocate its
13693  *   resources
13694  *
13695  * Since: 1.0
13696  */
13697 PangoContext *
13698 clutter_actor_create_pango_context (ClutterActor *self)
13699 {
13700   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13701
13702   return _clutter_context_create_pango_context ();
13703 }
13704
13705 /**
13706  * clutter_actor_create_pango_layout:
13707  * @self: a #ClutterActor
13708  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13709  *
13710  * Creates a new #PangoLayout from the same #PangoContext used
13711  * by the #ClutterActor. The #PangoLayout is already configured
13712  * with the font map, resolution and font options, and the
13713  * given @text.
13714  *
13715  * If you want to keep around a #PangoLayout created by this
13716  * function you will have to connect to the #ClutterBackend::font-changed
13717  * and #ClutterBackend::resolution-changed signals, and call
13718  * pango_layout_context_changed() in response to them.
13719  *
13720  * Return value: (transfer full): the newly created #PangoLayout.
13721  *   Use g_object_unref() when done
13722  *
13723  * Since: 1.0
13724  */
13725 PangoLayout *
13726 clutter_actor_create_pango_layout (ClutterActor *self,
13727                                    const gchar  *text)
13728 {
13729   PangoContext *context;
13730   PangoLayout *layout;
13731
13732   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13733
13734   context = clutter_actor_get_pango_context (self);
13735   layout = pango_layout_new (context);
13736
13737   if (text)
13738     pango_layout_set_text (layout, text, -1);
13739
13740   return layout;
13741 }
13742
13743 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13744  * ClutterOffscreenEffect.
13745  */
13746 void
13747 _clutter_actor_set_opacity_override (ClutterActor *self,
13748                                      gint          opacity)
13749 {
13750   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13751
13752   self->priv->opacity_override = opacity;
13753 }
13754
13755 gint
13756 _clutter_actor_get_opacity_override (ClutterActor *self)
13757 {
13758   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13759
13760   return self->priv->opacity_override;
13761 }
13762
13763 /* Allows you to disable applying the actors model view transform during
13764  * a paint. Used by ClutterClone. */
13765 void
13766 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13767                                                 gboolean      enable)
13768 {
13769   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13770
13771   self->priv->enable_model_view_transform = enable;
13772 }
13773
13774 void
13775 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13776                                           gboolean      enable)
13777 {
13778   ClutterActorPrivate *priv;
13779
13780   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13781
13782   priv = self->priv;
13783
13784   priv->enable_paint_unmapped = enable;
13785
13786   if (priv->enable_paint_unmapped)
13787     {
13788       /* Make sure that the parents of the widget are realized first;
13789        * otherwise checks in clutter_actor_update_map_state() will
13790        * fail.
13791        */
13792       clutter_actor_realize (self);
13793
13794       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13795     }
13796   else
13797     {
13798       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13799     }
13800 }
13801
13802 static void
13803 clutter_anchor_coord_get_units (ClutterActor      *self,
13804                                 const AnchorCoord *coord,
13805                                 gfloat            *x,
13806                                 gfloat            *y,
13807                                 gfloat            *z)
13808 {
13809   if (coord->is_fractional)
13810     {
13811       gfloat actor_width, actor_height;
13812
13813       clutter_actor_get_size (self, &actor_width, &actor_height);
13814
13815       if (x)
13816         *x = actor_width * coord->v.fraction.x;
13817
13818       if (y)
13819         *y = actor_height * coord->v.fraction.y;
13820
13821       if (z)
13822         *z = 0;
13823     }
13824   else
13825     {
13826       if (x)
13827         *x = coord->v.units.x;
13828
13829       if (y)
13830         *y = coord->v.units.y;
13831
13832       if (z)
13833         *z = coord->v.units.z;
13834     }
13835 }
13836
13837 static void
13838 clutter_anchor_coord_set_units (AnchorCoord *coord,
13839                                 gfloat       x,
13840                                 gfloat       y,
13841                                 gfloat       z)
13842 {
13843   coord->is_fractional = FALSE;
13844   coord->v.units.x = x;
13845   coord->v.units.y = y;
13846   coord->v.units.z = z;
13847 }
13848
13849 static ClutterGravity
13850 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13851 {
13852   if (coord->is_fractional)
13853     {
13854       if (coord->v.fraction.x == 0.0)
13855         {
13856           if (coord->v.fraction.y == 0.0)
13857             return CLUTTER_GRAVITY_NORTH_WEST;
13858           else if (coord->v.fraction.y == 0.5)
13859             return CLUTTER_GRAVITY_WEST;
13860           else if (coord->v.fraction.y == 1.0)
13861             return CLUTTER_GRAVITY_SOUTH_WEST;
13862           else
13863             return CLUTTER_GRAVITY_NONE;
13864         }
13865       else if (coord->v.fraction.x == 0.5)
13866         {
13867           if (coord->v.fraction.y == 0.0)
13868             return CLUTTER_GRAVITY_NORTH;
13869           else if (coord->v.fraction.y == 0.5)
13870             return CLUTTER_GRAVITY_CENTER;
13871           else if (coord->v.fraction.y == 1.0)
13872             return CLUTTER_GRAVITY_SOUTH;
13873           else
13874             return CLUTTER_GRAVITY_NONE;
13875         }
13876       else if (coord->v.fraction.x == 1.0)
13877         {
13878           if (coord->v.fraction.y == 0.0)
13879             return CLUTTER_GRAVITY_NORTH_EAST;
13880           else if (coord->v.fraction.y == 0.5)
13881             return CLUTTER_GRAVITY_EAST;
13882           else if (coord->v.fraction.y == 1.0)
13883             return CLUTTER_GRAVITY_SOUTH_EAST;
13884           else
13885             return CLUTTER_GRAVITY_NONE;
13886         }
13887       else
13888         return CLUTTER_GRAVITY_NONE;
13889     }
13890   else
13891     return CLUTTER_GRAVITY_NONE;
13892 }
13893
13894 static void
13895 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
13896                                   ClutterGravity  gravity)
13897 {
13898   switch (gravity)
13899     {
13900     case CLUTTER_GRAVITY_NORTH:
13901       coord->v.fraction.x = 0.5;
13902       coord->v.fraction.y = 0.0;
13903       break;
13904
13905     case CLUTTER_GRAVITY_NORTH_EAST:
13906       coord->v.fraction.x = 1.0;
13907       coord->v.fraction.y = 0.0;
13908       break;
13909
13910     case CLUTTER_GRAVITY_EAST:
13911       coord->v.fraction.x = 1.0;
13912       coord->v.fraction.y = 0.5;
13913       break;
13914
13915     case CLUTTER_GRAVITY_SOUTH_EAST:
13916       coord->v.fraction.x = 1.0;
13917       coord->v.fraction.y = 1.0;
13918       break;
13919
13920     case CLUTTER_GRAVITY_SOUTH:
13921       coord->v.fraction.x = 0.5;
13922       coord->v.fraction.y = 1.0;
13923       break;
13924
13925     case CLUTTER_GRAVITY_SOUTH_WEST:
13926       coord->v.fraction.x = 0.0;
13927       coord->v.fraction.y = 1.0;
13928       break;
13929
13930     case CLUTTER_GRAVITY_WEST:
13931       coord->v.fraction.x = 0.0;
13932       coord->v.fraction.y = 0.5;
13933       break;
13934
13935     case CLUTTER_GRAVITY_NORTH_WEST:
13936       coord->v.fraction.x = 0.0;
13937       coord->v.fraction.y = 0.0;
13938       break;
13939
13940     case CLUTTER_GRAVITY_CENTER:
13941       coord->v.fraction.x = 0.5;
13942       coord->v.fraction.y = 0.5;
13943       break;
13944
13945     default:
13946       coord->v.fraction.x = 0.0;
13947       coord->v.fraction.y = 0.0;
13948       break;
13949     }
13950
13951   coord->is_fractional = TRUE;
13952 }
13953
13954 static gboolean
13955 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13956 {
13957   if (coord->is_fractional)
13958     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13959   else
13960     return (coord->v.units.x == 0.0
13961             && coord->v.units.y == 0.0
13962             && coord->v.units.z == 0.0);
13963 }
13964
13965 /**
13966  * clutter_actor_get_flags:
13967  * @self: a #ClutterActor
13968  *
13969  * Retrieves the flags set on @self
13970  *
13971  * Return value: a bitwise or of #ClutterActorFlags or 0
13972  *
13973  * Since: 1.0
13974  */
13975 ClutterActorFlags
13976 clutter_actor_get_flags (ClutterActor *self)
13977 {
13978   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13979
13980   return self->flags;
13981 }
13982
13983 /**
13984  * clutter_actor_set_flags:
13985  * @self: a #ClutterActor
13986  * @flags: the flags to set
13987  *
13988  * Sets @flags on @self
13989  *
13990  * This function will emit notifications for the changed properties
13991  *
13992  * Since: 1.0
13993  */
13994 void
13995 clutter_actor_set_flags (ClutterActor      *self,
13996                          ClutterActorFlags  flags)
13997 {
13998   ClutterActorFlags old_flags;
13999   GObject *obj;
14000   gboolean was_reactive_set, reactive_set;
14001   gboolean was_realized_set, realized_set;
14002   gboolean was_mapped_set, mapped_set;
14003   gboolean was_visible_set, visible_set;
14004
14005   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14006
14007   if (self->flags == flags)
14008     return;
14009
14010   obj = G_OBJECT (self);
14011   g_object_ref (obj);
14012   g_object_freeze_notify (obj);
14013
14014   old_flags = self->flags;
14015
14016   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14017   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14018   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14019   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14020
14021   self->flags |= flags;
14022
14023   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14024   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14025   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14026   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14027
14028   if (reactive_set != was_reactive_set)
14029     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14030
14031   if (realized_set != was_realized_set)
14032     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14033
14034   if (mapped_set != was_mapped_set)
14035     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14036
14037   if (visible_set != was_visible_set)
14038     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14039
14040   g_object_thaw_notify (obj);
14041   g_object_unref (obj);
14042 }
14043
14044 /**
14045  * clutter_actor_unset_flags:
14046  * @self: a #ClutterActor
14047  * @flags: the flags to unset
14048  *
14049  * Unsets @flags on @self
14050  *
14051  * This function will emit notifications for the changed properties
14052  *
14053  * Since: 1.0
14054  */
14055 void
14056 clutter_actor_unset_flags (ClutterActor      *self,
14057                            ClutterActorFlags  flags)
14058 {
14059   ClutterActorFlags old_flags;
14060   GObject *obj;
14061   gboolean was_reactive_set, reactive_set;
14062   gboolean was_realized_set, realized_set;
14063   gboolean was_mapped_set, mapped_set;
14064   gboolean was_visible_set, visible_set;
14065
14066   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14067
14068   obj = G_OBJECT (self);
14069   g_object_freeze_notify (obj);
14070
14071   old_flags = self->flags;
14072
14073   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14074   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14075   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14076   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14077
14078   self->flags &= ~flags;
14079
14080   if (self->flags == old_flags)
14081     return;
14082
14083   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14084   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14085   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14086   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14087
14088   if (reactive_set != was_reactive_set)
14089     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14090
14091   if (realized_set != was_realized_set)
14092     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14093
14094   if (mapped_set != was_mapped_set)
14095     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14096
14097   if (visible_set != was_visible_set)
14098     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14099
14100   g_object_thaw_notify (obj);
14101 }
14102
14103 /**
14104  * clutter_actor_get_transformation_matrix:
14105  * @self: a #ClutterActor
14106  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14107  *
14108  * Retrieves the transformations applied to @self relative to its
14109  * parent.
14110  *
14111  * Since: 1.0
14112  */
14113 void
14114 clutter_actor_get_transformation_matrix (ClutterActor *self,
14115                                          CoglMatrix   *matrix)
14116 {
14117   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14118
14119   cogl_matrix_init_identity (matrix);
14120
14121   _clutter_actor_apply_modelview_transform (self, matrix);
14122 }
14123
14124 void
14125 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14126                                    gboolean      is_in_clone_paint)
14127 {
14128   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14129   self->priv->in_clone_paint = is_in_clone_paint;
14130 }
14131
14132 /**
14133  * clutter_actor_is_in_clone_paint:
14134  * @self: a #ClutterActor
14135  *
14136  * Checks whether @self is being currently painted by a #ClutterClone
14137  *
14138  * This function is useful only inside the ::paint virtual function
14139  * implementations or within handlers for the #ClutterActor::paint
14140  * signal
14141  *
14142  * This function should not be used by applications
14143  *
14144  * Return value: %TRUE if the #ClutterActor is currently being painted
14145  *   by a #ClutterClone, and %FALSE otherwise
14146  *
14147  * Since: 1.0
14148  */
14149 gboolean
14150 clutter_actor_is_in_clone_paint (ClutterActor *self)
14151 {
14152   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14153
14154   return self->priv->in_clone_paint;
14155 }
14156
14157 static gboolean
14158 set_direction_recursive (ClutterActor *actor,
14159                          gpointer      user_data)
14160 {
14161   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14162
14163   clutter_actor_set_text_direction (actor, text_dir);
14164
14165   return TRUE;
14166 }
14167
14168 /**
14169  * clutter_actor_set_text_direction:
14170  * @self: a #ClutterActor
14171  * @text_dir: the text direction for @self
14172  *
14173  * Sets the #ClutterTextDirection for an actor
14174  *
14175  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14176  *
14177  * If @self implements #ClutterContainer then this function will recurse
14178  * inside all the children of @self (including the internal ones).
14179  *
14180  * Composite actors not implementing #ClutterContainer, or actors requiring
14181  * special handling when the text direction changes, should connect to
14182  * the #GObject::notify signal for the #ClutterActor:text-direction property
14183  *
14184  * Since: 1.2
14185  */
14186 void
14187 clutter_actor_set_text_direction (ClutterActor         *self,
14188                                   ClutterTextDirection  text_dir)
14189 {
14190   ClutterActorPrivate *priv;
14191
14192   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14193   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14194
14195   priv = self->priv;
14196
14197   if (priv->text_direction != text_dir)
14198     {
14199       priv->text_direction = text_dir;
14200
14201       /* we need to emit the notify::text-direction first, so that
14202        * the sub-classes can catch that and do specific handling of
14203        * the text direction; see clutter_text_direction_changed_cb()
14204        * inside clutter-text.c
14205        */
14206       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14207
14208       _clutter_actor_foreach_child (self, set_direction_recursive,
14209                                     GINT_TO_POINTER (text_dir));
14210
14211       clutter_actor_queue_relayout (self);
14212     }
14213 }
14214
14215 void
14216 _clutter_actor_set_has_pointer (ClutterActor *self,
14217                                 gboolean      has_pointer)
14218 {
14219   ClutterActorPrivate *priv = self->priv;
14220
14221   if (priv->has_pointer != has_pointer)
14222     {
14223       priv->has_pointer = has_pointer;
14224
14225       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14226     }
14227 }
14228
14229 /**
14230  * clutter_actor_get_text_direction:
14231  * @self: a #ClutterActor
14232  *
14233  * Retrieves the value set using clutter_actor_set_text_direction()
14234  *
14235  * If no text direction has been previously set, the default text
14236  * direction, as returned by clutter_get_default_text_direction(), will
14237  * be returned instead
14238  *
14239  * Return value: the #ClutterTextDirection for the actor
14240  *
14241  * Since: 1.2
14242  */
14243 ClutterTextDirection
14244 clutter_actor_get_text_direction (ClutterActor *self)
14245 {
14246   ClutterActorPrivate *priv;
14247
14248   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14249                         CLUTTER_TEXT_DIRECTION_LTR);
14250
14251   priv = self->priv;
14252
14253   /* if no direction has been set yet use the default */
14254   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14255     priv->text_direction = clutter_get_default_text_direction ();
14256
14257   return priv->text_direction;
14258 }
14259
14260 /**
14261  * clutter_actor_push_internal:
14262  * @self: a #ClutterActor
14263  *
14264  * Should be used by actors implementing the #ClutterContainer and with
14265  * internal children added through clutter_actor_set_parent(), for instance:
14266  *
14267  * |[
14268  *   static void
14269  *   my_actor_init (MyActor *self)
14270  *   {
14271  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14272  *
14273  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14274  *
14275  *     /&ast; calling clutter_actor_set_parent() now will result in
14276  *      &ast; the internal flag being set on a child of MyActor
14277  *      &ast;/
14278  *
14279  *     /&ast; internal child - a background texture &ast;/
14280  *     self->priv->background_tex = clutter_texture_new ();
14281  *     clutter_actor_set_parent (self->priv->background_tex,
14282  *                               CLUTTER_ACTOR (self));
14283  *
14284  *     /&ast; internal child - a label &ast;/
14285  *     self->priv->label = clutter_text_new ();
14286  *     clutter_actor_set_parent (self->priv->label,
14287  *                               CLUTTER_ACTOR (self));
14288  *
14289  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14290  *
14291  *     /&ast; calling clutter_actor_set_parent() now will not result in
14292  *      &ast; the internal flag being set on a child of MyActor
14293  *      &ast;/
14294  *   }
14295  * ]|
14296  *
14297  * This function will be used by Clutter to toggle an "internal child"
14298  * flag whenever clutter_actor_set_parent() is called; internal children
14299  * are handled differently by Clutter, specifically when destroying their
14300  * parent.
14301  *
14302  * Call clutter_actor_pop_internal() when you finished adding internal
14303  * children.
14304  *
14305  * Nested calls to clutter_actor_push_internal() are allowed, but each
14306  * one must by followed by a clutter_actor_pop_internal() call.
14307  *
14308  * Since: 1.2
14309  *
14310  * Deprecated: 1.10: All children of an actor are accessible through
14311  *   the #ClutterActor API, and #ClutterActor implements the
14312  *   #ClutterContainer interface, so this function is only useful
14313  *   for legacy containers overriding the default implementation.
14314  */
14315 void
14316 clutter_actor_push_internal (ClutterActor *self)
14317 {
14318   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14319
14320   self->priv->internal_child += 1;
14321 }
14322
14323 /**
14324  * clutter_actor_pop_internal:
14325  * @self: a #ClutterActor
14326  *
14327  * Disables the effects of clutter_actor_push_internal().
14328  *
14329  * Since: 1.2
14330  *
14331  * Deprecated: 1.10: All children of an actor are accessible through
14332  *   the #ClutterActor API. This function is only useful for legacy
14333  *   containers overriding the default implementation of the
14334  *   #ClutterContainer interface.
14335  */
14336 void
14337 clutter_actor_pop_internal (ClutterActor *self)
14338 {
14339   ClutterActorPrivate *priv;
14340
14341   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14342
14343   priv = self->priv;
14344
14345   if (priv->internal_child == 0)
14346     {
14347       g_warning ("Mismatched %s: you need to call "
14348                  "clutter_actor_push_composite() at least once before "
14349                  "calling this function", G_STRFUNC);
14350       return;
14351     }
14352
14353   priv->internal_child -= 1;
14354 }
14355
14356 /**
14357  * clutter_actor_has_pointer:
14358  * @self: a #ClutterActor
14359  *
14360  * Checks whether an actor contains the pointer of a
14361  * #ClutterInputDevice
14362  *
14363  * Return value: %TRUE if the actor contains the pointer, and
14364  *   %FALSE otherwise
14365  *
14366  * Since: 1.2
14367  */
14368 gboolean
14369 clutter_actor_has_pointer (ClutterActor *self)
14370 {
14371   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14372
14373   return self->priv->has_pointer;
14374 }
14375
14376 /* XXX: This is a workaround for not being able to break the ABI of
14377  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14378  * clutter_actor_queue_clipped_redraw() for details.
14379  */
14380 ClutterPaintVolume *
14381 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14382 {
14383   return g_object_get_data (G_OBJECT (self),
14384                             "-clutter-actor-queue-redraw-clip");
14385 }
14386
14387 void
14388 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14389                                       ClutterPaintVolume *clip)
14390 {
14391   g_object_set_data (G_OBJECT (self),
14392                      "-clutter-actor-queue-redraw-clip",
14393                      clip);
14394 }
14395
14396 /**
14397  * clutter_actor_has_allocation:
14398  * @self: a #ClutterActor
14399  *
14400  * Checks if the actor has an up-to-date allocation assigned to
14401  * it. This means that the actor should have an allocation: it's
14402  * visible and has a parent. It also means that there is no
14403  * outstanding relayout request in progress for the actor or its
14404  * children (There might be other outstanding layout requests in
14405  * progress that will cause the actor to get a new allocation
14406  * when the stage is laid out, however).
14407  *
14408  * If this function returns %FALSE, then the actor will normally
14409  * be allocated before it is next drawn on the screen.
14410  *
14411  * Return value: %TRUE if the actor has an up-to-date allocation
14412  *
14413  * Since: 1.4
14414  */
14415 gboolean
14416 clutter_actor_has_allocation (ClutterActor *self)
14417 {
14418   ClutterActorPrivate *priv;
14419
14420   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14421
14422   priv = self->priv;
14423
14424   return priv->parent != NULL &&
14425          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14426          !priv->needs_allocation;
14427 }
14428
14429 /**
14430  * clutter_actor_add_action:
14431  * @self: a #ClutterActor
14432  * @action: a #ClutterAction
14433  *
14434  * Adds @action to the list of actions applied to @self
14435  *
14436  * A #ClutterAction can only belong to one actor at a time
14437  *
14438  * The #ClutterActor will hold a reference on @action until either
14439  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14440  * is called
14441  *
14442  * Since: 1.4
14443  */
14444 void
14445 clutter_actor_add_action (ClutterActor  *self,
14446                           ClutterAction *action)
14447 {
14448   ClutterActorPrivate *priv;
14449
14450   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14451   g_return_if_fail (CLUTTER_IS_ACTION (action));
14452
14453   priv = self->priv;
14454
14455   if (priv->actions == NULL)
14456     {
14457       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14458       priv->actions->actor = self;
14459     }
14460
14461   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14462
14463   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14464 }
14465
14466 /**
14467  * clutter_actor_add_action_with_name:
14468  * @self: a #ClutterActor
14469  * @name: the name to set on the action
14470  * @action: a #ClutterAction
14471  *
14472  * A convenience function for setting the name of a #ClutterAction
14473  * while adding it to the list of actions applied to @self
14474  *
14475  * This function is the logical equivalent of:
14476  *
14477  * |[
14478  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14479  *   clutter_actor_add_action (self, action);
14480  * ]|
14481  *
14482  * Since: 1.4
14483  */
14484 void
14485 clutter_actor_add_action_with_name (ClutterActor  *self,
14486                                     const gchar   *name,
14487                                     ClutterAction *action)
14488 {
14489   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14490   g_return_if_fail (name != NULL);
14491   g_return_if_fail (CLUTTER_IS_ACTION (action));
14492
14493   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14494   clutter_actor_add_action (self, action);
14495 }
14496
14497 /**
14498  * clutter_actor_remove_action:
14499  * @self: a #ClutterActor
14500  * @action: a #ClutterAction
14501  *
14502  * Removes @action from the list of actions applied to @self
14503  *
14504  * The reference held by @self on the #ClutterAction will be released
14505  *
14506  * Since: 1.4
14507  */
14508 void
14509 clutter_actor_remove_action (ClutterActor  *self,
14510                              ClutterAction *action)
14511 {
14512   ClutterActorPrivate *priv;
14513
14514   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14515   g_return_if_fail (CLUTTER_IS_ACTION (action));
14516
14517   priv = self->priv;
14518
14519   if (priv->actions == NULL)
14520     return;
14521
14522   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14523
14524   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14525 }
14526
14527 /**
14528  * clutter_actor_remove_action_by_name:
14529  * @self: a #ClutterActor
14530  * @name: the name of the action to remove
14531  *
14532  * Removes the #ClutterAction with the given name from the list
14533  * of actions applied to @self
14534  *
14535  * Since: 1.4
14536  */
14537 void
14538 clutter_actor_remove_action_by_name (ClutterActor *self,
14539                                      const gchar  *name)
14540 {
14541   ClutterActorPrivate *priv;
14542   ClutterActorMeta *meta;
14543
14544   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14545   g_return_if_fail (name != NULL);
14546
14547   priv = self->priv;
14548
14549   if (priv->actions == NULL)
14550     return;
14551
14552   meta = _clutter_meta_group_get_meta (priv->actions, name);
14553   if (meta == NULL)
14554     return;
14555
14556   _clutter_meta_group_remove_meta (priv->actions, meta);
14557
14558   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14559 }
14560
14561 /**
14562  * clutter_actor_get_actions:
14563  * @self: a #ClutterActor
14564  *
14565  * Retrieves the list of actions applied to @self
14566  *
14567  * Return value: (transfer container) (element-type Clutter.Action): a copy
14568  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14569  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14570  *   allocated by the returned #GList
14571  *
14572  * Since: 1.4
14573  */
14574 GList *
14575 clutter_actor_get_actions (ClutterActor *self)
14576 {
14577   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14578
14579   if (self->priv->actions == NULL)
14580     return NULL;
14581
14582   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14583 }
14584
14585 /**
14586  * clutter_actor_get_action:
14587  * @self: a #ClutterActor
14588  * @name: the name of the action to retrieve
14589  *
14590  * Retrieves the #ClutterAction with the given name in the list
14591  * of actions applied to @self
14592  *
14593  * Return value: (transfer none): a #ClutterAction for the given
14594  *   name, or %NULL. The returned #ClutterAction is owned by the
14595  *   actor and it should not be unreferenced directly
14596  *
14597  * Since: 1.4
14598  */
14599 ClutterAction *
14600 clutter_actor_get_action (ClutterActor *self,
14601                           const gchar  *name)
14602 {
14603   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14604   g_return_val_if_fail (name != NULL, NULL);
14605
14606   if (self->priv->actions == NULL)
14607     return NULL;
14608
14609   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14610 }
14611
14612 /**
14613  * clutter_actor_clear_actions:
14614  * @self: a #ClutterActor
14615  *
14616  * Clears the list of actions applied to @self
14617  *
14618  * Since: 1.4
14619  */
14620 void
14621 clutter_actor_clear_actions (ClutterActor *self)
14622 {
14623   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14624
14625   if (self->priv->actions == NULL)
14626     return;
14627
14628   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14629 }
14630
14631 /**
14632  * clutter_actor_add_constraint:
14633  * @self: a #ClutterActor
14634  * @constraint: a #ClutterConstraint
14635  *
14636  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14637  * to @self
14638  *
14639  * The #ClutterActor will hold a reference on the @constraint until
14640  * either clutter_actor_remove_constraint() or
14641  * clutter_actor_clear_constraints() is called.
14642  *
14643  * Since: 1.4
14644  */
14645 void
14646 clutter_actor_add_constraint (ClutterActor      *self,
14647                               ClutterConstraint *constraint)
14648 {
14649   ClutterActorPrivate *priv;
14650
14651   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14652   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14653
14654   priv = self->priv;
14655
14656   if (priv->constraints == NULL)
14657     {
14658       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14659       priv->constraints->actor = self;
14660     }
14661
14662   _clutter_meta_group_add_meta (priv->constraints,
14663                                 CLUTTER_ACTOR_META (constraint));
14664   clutter_actor_queue_relayout (self);
14665
14666   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14667 }
14668
14669 /**
14670  * clutter_actor_add_constraint_with_name:
14671  * @self: a #ClutterActor
14672  * @name: the name to set on the constraint
14673  * @constraint: a #ClutterConstraint
14674  *
14675  * A convenience function for setting the name of a #ClutterConstraint
14676  * while adding it to the list of constraints applied to @self
14677  *
14678  * This function is the logical equivalent of:
14679  *
14680  * |[
14681  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14682  *   clutter_actor_add_constraint (self, constraint);
14683  * ]|
14684  *
14685  * Since: 1.4
14686  */
14687 void
14688 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14689                                         const gchar       *name,
14690                                         ClutterConstraint *constraint)
14691 {
14692   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14693   g_return_if_fail (name != NULL);
14694   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14695
14696   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14697   clutter_actor_add_constraint (self, constraint);
14698 }
14699
14700 /**
14701  * clutter_actor_remove_constraint:
14702  * @self: a #ClutterActor
14703  * @constraint: a #ClutterConstraint
14704  *
14705  * Removes @constraint from the list of constraints applied to @self
14706  *
14707  * The reference held by @self on the #ClutterConstraint will be released
14708  *
14709  * Since: 1.4
14710  */
14711 void
14712 clutter_actor_remove_constraint (ClutterActor      *self,
14713                                  ClutterConstraint *constraint)
14714 {
14715   ClutterActorPrivate *priv;
14716
14717   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14718   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14719
14720   priv = self->priv;
14721
14722   if (priv->constraints == NULL)
14723     return;
14724
14725   _clutter_meta_group_remove_meta (priv->constraints,
14726                                    CLUTTER_ACTOR_META (constraint));
14727   clutter_actor_queue_relayout (self);
14728
14729   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14730 }
14731
14732 /**
14733  * clutter_actor_remove_constraint_by_name:
14734  * @self: a #ClutterActor
14735  * @name: the name of the constraint to remove
14736  *
14737  * Removes the #ClutterConstraint with the given name from the list
14738  * of constraints applied to @self
14739  *
14740  * Since: 1.4
14741  */
14742 void
14743 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14744                                          const gchar  *name)
14745 {
14746   ClutterActorPrivate *priv;
14747   ClutterActorMeta *meta;
14748
14749   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14750   g_return_if_fail (name != NULL);
14751
14752   priv = self->priv;
14753
14754   if (priv->constraints == NULL)
14755     return;
14756
14757   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14758   if (meta == NULL)
14759     return;
14760
14761   _clutter_meta_group_remove_meta (priv->constraints, meta);
14762   clutter_actor_queue_relayout (self);
14763 }
14764
14765 /**
14766  * clutter_actor_get_constraints:
14767  * @self: a #ClutterActor
14768  *
14769  * Retrieves the list of constraints applied to @self
14770  *
14771  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14772  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14773  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14774  *   allocated by the returned #GList
14775  *
14776  * Since: 1.4
14777  */
14778 GList *
14779 clutter_actor_get_constraints (ClutterActor *self)
14780 {
14781   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14782
14783   if (self->priv->constraints == NULL)
14784     return NULL;
14785
14786   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14787 }
14788
14789 /**
14790  * clutter_actor_get_constraint:
14791  * @self: a #ClutterActor
14792  * @name: the name of the constraint to retrieve
14793  *
14794  * Retrieves the #ClutterConstraint with the given name in the list
14795  * of constraints applied to @self
14796  *
14797  * Return value: (transfer none): a #ClutterConstraint for the given
14798  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14799  *   actor and it should not be unreferenced directly
14800  *
14801  * Since: 1.4
14802  */
14803 ClutterConstraint *
14804 clutter_actor_get_constraint (ClutterActor *self,
14805                               const gchar  *name)
14806 {
14807   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14808   g_return_val_if_fail (name != NULL, NULL);
14809
14810   if (self->priv->constraints == NULL)
14811     return NULL;
14812
14813   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14814 }
14815
14816 /**
14817  * clutter_actor_clear_constraints:
14818  * @self: a #ClutterActor
14819  *
14820  * Clears the list of constraints applied to @self
14821  *
14822  * Since: 1.4
14823  */
14824 void
14825 clutter_actor_clear_constraints (ClutterActor *self)
14826 {
14827   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14828
14829   if (self->priv->constraints == NULL)
14830     return;
14831
14832   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14833
14834   clutter_actor_queue_relayout (self);
14835 }
14836
14837 /**
14838  * clutter_actor_set_clip_to_allocation:
14839  * @self: a #ClutterActor
14840  * @clip_set: %TRUE to apply a clip tracking the allocation
14841  *
14842  * Sets whether @self should be clipped to the same size as its
14843  * allocation
14844  *
14845  * Since: 1.4
14846  */
14847 void
14848 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14849                                       gboolean      clip_set)
14850 {
14851   ClutterActorPrivate *priv;
14852
14853   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14854
14855   clip_set = !!clip_set;
14856
14857   priv = self->priv;
14858
14859   if (priv->clip_to_allocation != clip_set)
14860     {
14861       priv->clip_to_allocation = clip_set;
14862
14863       clutter_actor_queue_redraw (self);
14864
14865       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14866     }
14867 }
14868
14869 /**
14870  * clutter_actor_get_clip_to_allocation:
14871  * @self: a #ClutterActor
14872  *
14873  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14874  *
14875  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14876  *
14877  * Since: 1.4
14878  */
14879 gboolean
14880 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14881 {
14882   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14883
14884   return self->priv->clip_to_allocation;
14885 }
14886
14887 /**
14888  * clutter_actor_add_effect:
14889  * @self: a #ClutterActor
14890  * @effect: a #ClutterEffect
14891  *
14892  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14893  *
14894  * The #ClutterActor will hold a reference on the @effect until either
14895  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14896  * called.
14897  *
14898  * Since: 1.4
14899  */
14900 void
14901 clutter_actor_add_effect (ClutterActor  *self,
14902                           ClutterEffect *effect)
14903 {
14904   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14905   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14906
14907   _clutter_actor_add_effect_internal (self, effect);
14908
14909   clutter_actor_queue_redraw (self);
14910
14911   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14912 }
14913
14914 /**
14915  * clutter_actor_add_effect_with_name:
14916  * @self: a #ClutterActor
14917  * @name: the name to set on the effect
14918  * @effect: a #ClutterEffect
14919  *
14920  * A convenience function for setting the name of a #ClutterEffect
14921  * while adding it to the list of effectss applied to @self
14922  *
14923  * This function is the logical equivalent of:
14924  *
14925  * |[
14926  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14927  *   clutter_actor_add_effect (self, effect);
14928  * ]|
14929  *
14930  * Since: 1.4
14931  */
14932 void
14933 clutter_actor_add_effect_with_name (ClutterActor  *self,
14934                                     const gchar   *name,
14935                                     ClutterEffect *effect)
14936 {
14937   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14938   g_return_if_fail (name != NULL);
14939   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14940
14941   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14942   clutter_actor_add_effect (self, effect);
14943 }
14944
14945 /**
14946  * clutter_actor_remove_effect:
14947  * @self: a #ClutterActor
14948  * @effect: a #ClutterEffect
14949  *
14950  * Removes @effect from the list of effects applied to @self
14951  *
14952  * The reference held by @self on the #ClutterEffect will be released
14953  *
14954  * Since: 1.4
14955  */
14956 void
14957 clutter_actor_remove_effect (ClutterActor  *self,
14958                              ClutterEffect *effect)
14959 {
14960   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14961   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14962
14963   _clutter_actor_remove_effect_internal (self, effect);
14964
14965   clutter_actor_queue_redraw (self);
14966
14967   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14968 }
14969
14970 /**
14971  * clutter_actor_remove_effect_by_name:
14972  * @self: a #ClutterActor
14973  * @name: the name of the effect to remove
14974  *
14975  * Removes the #ClutterEffect with the given name from the list
14976  * of effects applied to @self
14977  *
14978  * Since: 1.4
14979  */
14980 void
14981 clutter_actor_remove_effect_by_name (ClutterActor *self,
14982                                      const gchar  *name)
14983 {
14984   ClutterActorPrivate *priv;
14985   ClutterActorMeta *meta;
14986
14987   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14988   g_return_if_fail (name != NULL);
14989
14990   priv = self->priv;
14991
14992   if (priv->effects == NULL)
14993     return;
14994
14995   meta = _clutter_meta_group_get_meta (priv->effects, name);
14996   if (meta == NULL)
14997     return;
14998
14999   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15000 }
15001
15002 /**
15003  * clutter_actor_get_effects:
15004  * @self: a #ClutterActor
15005  *
15006  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15007  *
15008  * Return value: (transfer container) (element-type Clutter.Effect): a list
15009  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15010  *   list are owned by Clutter and they should not be freed. You should
15011  *   free the returned list using g_list_free() when done
15012  *
15013  * Since: 1.4
15014  */
15015 GList *
15016 clutter_actor_get_effects (ClutterActor *self)
15017 {
15018   ClutterActorPrivate *priv;
15019
15020   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15021
15022   priv = self->priv;
15023
15024   if (priv->effects == NULL)
15025     return NULL;
15026
15027   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15028 }
15029
15030 /**
15031  * clutter_actor_get_effect:
15032  * @self: a #ClutterActor
15033  * @name: the name of the effect to retrieve
15034  *
15035  * Retrieves the #ClutterEffect with the given name in the list
15036  * of effects applied to @self
15037  *
15038  * Return value: (transfer none): a #ClutterEffect for the given
15039  *   name, or %NULL. The returned #ClutterEffect is owned by the
15040  *   actor and it should not be unreferenced directly
15041  *
15042  * Since: 1.4
15043  */
15044 ClutterEffect *
15045 clutter_actor_get_effect (ClutterActor *self,
15046                           const gchar  *name)
15047 {
15048   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15049   g_return_val_if_fail (name != NULL, NULL);
15050
15051   if (self->priv->effects == NULL)
15052     return NULL;
15053
15054   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15055 }
15056
15057 /**
15058  * clutter_actor_clear_effects:
15059  * @self: a #ClutterActor
15060  *
15061  * Clears the list of effects applied to @self
15062  *
15063  * Since: 1.4
15064  */
15065 void
15066 clutter_actor_clear_effects (ClutterActor *self)
15067 {
15068   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15069
15070   if (self->priv->effects == NULL)
15071     return;
15072
15073   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15074
15075   clutter_actor_queue_redraw (self);
15076 }
15077
15078 /**
15079  * clutter_actor_has_key_focus:
15080  * @self: a #ClutterActor
15081  *
15082  * Checks whether @self is the #ClutterActor that has key focus
15083  *
15084  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15085  *
15086  * Since: 1.4
15087  */
15088 gboolean
15089 clutter_actor_has_key_focus (ClutterActor *self)
15090 {
15091   ClutterActor *stage;
15092
15093   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15094
15095   stage = _clutter_actor_get_stage_internal (self);
15096   if (stage == NULL)
15097     return FALSE;
15098
15099   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15100 }
15101
15102 static gboolean
15103 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15104                                       ClutterPaintVolume *pv)
15105 {
15106   ClutterActorPrivate *priv = self->priv;
15107
15108   /* Actors are only expected to report a valid paint volume
15109    * while they have a valid allocation. */
15110   if (G_UNLIKELY (priv->needs_allocation))
15111     {
15112       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15113                     "Actor needs allocation",
15114                     _clutter_actor_get_debug_name (self));
15115       return FALSE;
15116     }
15117
15118   /* Check if there are any handlers connected to the paint
15119    * signal. If there are then all bets are off for what the paint
15120    * volume for this actor might possibly be!
15121    *
15122    * XXX: It's expected that this is going to end up being quite a
15123    * costly check to have to do here, but we haven't come up with
15124    * another solution that can reliably catch paint signal handlers at
15125    * the right time to either avoid artefacts due to invalid stage
15126    * clipping or due to incorrect culling.
15127    *
15128    * Previously we checked in clutter_actor_paint(), but at that time
15129    * we may already be using a stage clip that could be derived from
15130    * an invalid paint-volume. We used to try and handle that by
15131    * queuing a follow up, unclipped, redraw but still the previous
15132    * checking wasn't enough to catch invalid volumes involved in
15133    * culling (considering that containers may derive their volume from
15134    * children that haven't yet been painted)
15135    *
15136    * Longer term, improved solutions could be:
15137    * - Disallow painting in the paint signal, only allow using it
15138    *   for tracking when paints happen. We can add another API that
15139    *   allows monkey patching the paint of arbitrary actors but in a
15140    *   more controlled way and that also supports modifying the
15141    *   paint-volume.
15142    * - If we could be notified somehow when signal handlers are
15143    *   connected we wouldn't have to poll for handlers like this.
15144    */
15145   if (g_signal_has_handler_pending (self,
15146                                     actor_signals[PAINT],
15147                                     0,
15148                                     TRUE))
15149     {
15150       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15151                     "Actor has \"paint\" signal handlers",
15152                     _clutter_actor_get_debug_name (self));
15153       return FALSE;
15154     }
15155
15156   _clutter_paint_volume_init_static (pv, self);
15157
15158   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15159     {
15160       clutter_paint_volume_free (pv);
15161       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15162                     "Actor failed to report a volume",
15163                     _clutter_actor_get_debug_name (self));
15164       return FALSE;
15165     }
15166
15167   /* since effects can modify the paint volume, we allow them to actually
15168    * do this by making get_paint_volume() "context sensitive"
15169    */
15170   if (priv->effects != NULL)
15171     {
15172       if (priv->current_effect != NULL)
15173         {
15174           const GList *effects, *l;
15175
15176           /* if we are being called from within the paint sequence of
15177            * an actor, get the paint volume up to the current effect
15178            */
15179           effects = _clutter_meta_group_peek_metas (priv->effects);
15180           for (l = effects;
15181                l != NULL || (l != NULL && l->data != priv->current_effect);
15182                l = l->next)
15183             {
15184               if (!_clutter_effect_get_paint_volume (l->data, pv))
15185                 {
15186                   clutter_paint_volume_free (pv);
15187                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15188                                 "Effect (%s) failed to report a volume",
15189                                 _clutter_actor_get_debug_name (self),
15190                                 _clutter_actor_meta_get_debug_name (l->data));
15191                   return FALSE;
15192                 }
15193             }
15194         }
15195       else
15196         {
15197           const GList *effects, *l;
15198
15199           /* otherwise, get the cumulative volume */
15200           effects = _clutter_meta_group_peek_metas (priv->effects);
15201           for (l = effects; l != NULL; l = l->next)
15202             if (!_clutter_effect_get_paint_volume (l->data, pv))
15203               {
15204                 clutter_paint_volume_free (pv);
15205                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15206                               "Effect (%s) failed to report a volume",
15207                               _clutter_actor_get_debug_name (self),
15208                               _clutter_actor_meta_get_debug_name (l->data));
15209                 return FALSE;
15210               }
15211         }
15212     }
15213
15214   return TRUE;
15215 }
15216
15217 /* The public clutter_actor_get_paint_volume API returns a const
15218  * pointer since we return a pointer directly to the cached
15219  * PaintVolume associated with the actor and don't want the user to
15220  * inadvertently modify it, but for internal uses we sometimes need
15221  * access to the same PaintVolume but need to apply some book-keeping
15222  * modifications to it so we don't want a const pointer.
15223  */
15224 static ClutterPaintVolume *
15225 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15226 {
15227   ClutterActorPrivate *priv;
15228
15229   priv = self->priv;
15230
15231   if (priv->paint_volume_valid)
15232     clutter_paint_volume_free (&priv->paint_volume);
15233
15234   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15235     {
15236       priv->paint_volume_valid = TRUE;
15237       return &priv->paint_volume;
15238     }
15239   else
15240     {
15241       priv->paint_volume_valid = FALSE;
15242       return NULL;
15243     }
15244 }
15245
15246 /**
15247  * clutter_actor_get_paint_volume:
15248  * @self: a #ClutterActor
15249  *
15250  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15251  * when a paint volume can't be determined.
15252  *
15253  * The paint volume is defined as the 3D space occupied by an actor
15254  * when being painted.
15255  *
15256  * This function will call the <function>get_paint_volume()</function>
15257  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15258  * should not usually care about overriding the default implementation,
15259  * unless they are, for instance: painting outside their allocation, or
15260  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15261  * 3D depth).
15262  *
15263  * <note>2D actors overriding <function>get_paint_volume()</function>
15264  * ensure their volume has a depth of 0. (This will be true so long as
15265  * you don't call clutter_paint_volume_set_depth().)</note>
15266  *
15267  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15268  *   or %NULL if no volume could be determined. The returned pointer
15269  *   is not guaranteed to be valid across multiple frames; if you want
15270  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15271  *
15272  * Since: 1.6
15273  */
15274 const ClutterPaintVolume *
15275 clutter_actor_get_paint_volume (ClutterActor *self)
15276 {
15277   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15278
15279   return _clutter_actor_get_paint_volume_mutable (self);
15280 }
15281
15282 /**
15283  * clutter_actor_get_transformed_paint_volume:
15284  * @self: a #ClutterActor
15285  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15286  *    (or %NULL for the stage)
15287  *
15288  * Retrieves the 3D paint volume of an actor like
15289  * clutter_actor_get_paint_volume() does (Please refer to the
15290  * documentation of clutter_actor_get_paint_volume() for more
15291  * details.) and it additionally transforms the paint volume into the
15292  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15293  * is passed for @relative_to_ancestor)
15294  *
15295  * This can be used by containers that base their paint volume on
15296  * the volume of their children. Such containers can query the
15297  * transformed paint volume of all of its children and union them
15298  * together using clutter_paint_volume_union().
15299  *
15300  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15301  *   or %NULL if no volume could be determined. The returned pointer is
15302  *   not guaranteed to be valid across multiple frames; if you wish to
15303  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15304  *
15305  * Since: 1.6
15306  */
15307 const ClutterPaintVolume *
15308 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15309                                             ClutterActor *relative_to_ancestor)
15310 {
15311   const ClutterPaintVolume *volume;
15312   ClutterActor *stage;
15313   ClutterPaintVolume *transformed_volume;
15314
15315   stage = _clutter_actor_get_stage_internal (self);
15316   if (G_UNLIKELY (stage == NULL))
15317     return NULL;
15318
15319   if (relative_to_ancestor == NULL)
15320     relative_to_ancestor = stage;
15321
15322   volume = clutter_actor_get_paint_volume (self);
15323   if (volume == NULL)
15324     return NULL;
15325
15326   transformed_volume =
15327     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15328
15329   _clutter_paint_volume_copy_static (volume, transformed_volume);
15330
15331   _clutter_paint_volume_transform_relative (transformed_volume,
15332                                             relative_to_ancestor);
15333
15334   return transformed_volume;
15335 }
15336
15337 /**
15338  * clutter_actor_get_paint_box:
15339  * @self: a #ClutterActor
15340  * @box: (out): return location for a #ClutterActorBox
15341  *
15342  * Retrieves the paint volume of the passed #ClutterActor, and
15343  * transforms it into a 2D bounding box in stage coordinates.
15344  *
15345  * This function is useful to determine the on screen area occupied by
15346  * the actor. The box is only an approximation and may often be
15347  * considerably larger due to the optimizations used to calculate the
15348  * box. The box is never smaller though, so it can reliably be used
15349  * for culling.
15350  *
15351  * There are times when a 2D paint box can't be determined, e.g.
15352  * because the actor isn't yet parented under a stage or because
15353  * the actor is unable to determine a paint volume.
15354  *
15355  * Return value: %TRUE if a 2D paint box could be determined, else
15356  * %FALSE.
15357  *
15358  * Since: 1.6
15359  */
15360 gboolean
15361 clutter_actor_get_paint_box (ClutterActor    *self,
15362                              ClutterActorBox *box)
15363 {
15364   ClutterActor *stage;
15365   ClutterPaintVolume *pv;
15366
15367   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15368   g_return_val_if_fail (box != NULL, FALSE);
15369
15370   stage = _clutter_actor_get_stage_internal (self);
15371   if (G_UNLIKELY (!stage))
15372     return FALSE;
15373
15374   pv = _clutter_actor_get_paint_volume_mutable (self);
15375   if (G_UNLIKELY (!pv))
15376     return FALSE;
15377
15378   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15379
15380   return TRUE;
15381 }
15382
15383 /**
15384  * clutter_actor_has_overlaps:
15385  * @self: A #ClutterActor
15386  *
15387  * Asks the actor's implementation whether it may contain overlapping
15388  * primitives.
15389  *
15390  * For example; Clutter may use this to determine whether the painting
15391  * should be redirected to an offscreen buffer to correctly implement
15392  * the opacity property.
15393  *
15394  * Custom actors can override the default response by implementing the
15395  * #ClutterActor <function>has_overlaps</function> virtual function. See
15396  * clutter_actor_set_offscreen_redirect() for more information.
15397  *
15398  * Return value: %TRUE if the actor may have overlapping primitives, and
15399  *   %FALSE otherwise
15400  *
15401  * Since: 1.8
15402  */
15403 gboolean
15404 clutter_actor_has_overlaps (ClutterActor *self)
15405 {
15406   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15407
15408   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15409 }
15410
15411 /**
15412  * clutter_actor_has_effects:
15413  * @self: A #ClutterActor
15414  *
15415  * Returns whether the actor has any effects applied.
15416  *
15417  * Return value: %TRUE if the actor has any effects,
15418  *   %FALSE otherwise
15419  *
15420  * Since: 1.10
15421  */
15422 gboolean
15423 clutter_actor_has_effects (ClutterActor *self)
15424 {
15425   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15426
15427   if (self->priv->effects == NULL)
15428     return FALSE;
15429
15430   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15431 }
15432
15433 /**
15434  * clutter_actor_has_constraints:
15435  * @self: A #ClutterActor
15436  *
15437  * Returns whether the actor has any constraints applied.
15438  *
15439  * Return value: %TRUE if the actor has any constraints,
15440  *   %FALSE otherwise
15441  *
15442  * Since: 1.10
15443  */
15444 gboolean
15445 clutter_actor_has_constraints (ClutterActor *self)
15446 {
15447   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15448
15449   return self->priv->constraints != NULL;
15450 }
15451
15452 /**
15453  * clutter_actor_has_actions:
15454  * @self: A #ClutterActor
15455  *
15456  * Returns whether the actor has any actions applied.
15457  *
15458  * Return value: %TRUE if the actor has any actions,
15459  *   %FALSE otherwise
15460  *
15461  * Since: 1.10
15462  */
15463 gboolean
15464 clutter_actor_has_actions (ClutterActor *self)
15465 {
15466   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15467
15468   return self->priv->actions != NULL;
15469 }
15470
15471 /**
15472  * clutter_actor_get_n_children:
15473  * @self: a #ClutterActor
15474  *
15475  * Retrieves the number of children of @self.
15476  *
15477  * Return value: the number of children of an actor
15478  *
15479  * Since: 1.10
15480  */
15481 gint
15482 clutter_actor_get_n_children (ClutterActor *self)
15483 {
15484   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15485
15486   return self->priv->n_children;
15487 }
15488
15489 /**
15490  * clutter_actor_get_child_at_index:
15491  * @self: a #ClutterActor
15492  * @index_: the position in the list of children
15493  *
15494  * Retrieves the actor at the given @index_ inside the list of
15495  * children of @self.
15496  *
15497  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15498  *
15499  * Since: 1.10
15500  */
15501 ClutterActor *
15502 clutter_actor_get_child_at_index (ClutterActor *self,
15503                                   gint          index_)
15504 {
15505   ClutterActor *iter;
15506   int i;
15507
15508   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15509   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15510
15511   for (iter = self->priv->first_child, i = 0;
15512        iter != NULL && i < index_;
15513        iter = iter->priv->next_sibling, i += 1)
15514     ;
15515
15516   return iter;
15517 }
15518
15519 /*< private >
15520  * _clutter_actor_foreach_child:
15521  * @actor: The actor whos children you want to iterate
15522  * @callback: The function to call for each child
15523  * @user_data: Private data to pass to @callback
15524  *
15525  * Calls a given @callback once for each child of the specified @actor and
15526  * passing the @user_data pointer each time.
15527  *
15528  * Return value: returns %TRUE if all children were iterated, else
15529  *    %FALSE if a callback broke out of iteration early.
15530  */
15531 gboolean
15532 _clutter_actor_foreach_child (ClutterActor           *self,
15533                               ClutterForeachCallback  callback,
15534                               gpointer                user_data)
15535 {
15536   ClutterActorPrivate *priv = self->priv;
15537   ClutterActor *iter;
15538   gboolean cont;
15539
15540   for (cont = TRUE, iter = priv->first_child;
15541        cont && iter != NULL;
15542        iter = iter->priv->next_sibling)
15543     {
15544       cont = callback (iter, user_data);
15545     }
15546
15547   return cont;
15548 }
15549
15550 #if 0
15551 /* For debugging purposes this gives us a simple way to print out
15552  * the scenegraph e.g in gdb using:
15553  * [|
15554  *   _clutter_actor_traverse (stage,
15555  *                            0,
15556  *                            clutter_debug_print_actor_cb,
15557  *                            NULL,
15558  *                            NULL);
15559  * |]
15560  */
15561 static ClutterActorTraverseVisitFlags
15562 clutter_debug_print_actor_cb (ClutterActor *actor,
15563                               int depth,
15564                               void *user_data)
15565 {
15566   g_print ("%*s%s:%p\n",
15567            depth * 2, "",
15568            _clutter_actor_get_debug_name (actor),
15569            actor);
15570
15571   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15572 }
15573 #endif
15574
15575 static void
15576 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15577                                  ClutterTraverseCallback callback,
15578                                  gpointer                user_data)
15579 {
15580   GQueue *queue = g_queue_new ();
15581   ClutterActor dummy;
15582   int current_depth = 0;
15583
15584   g_queue_push_tail (queue, actor);
15585   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15586
15587   while ((actor = g_queue_pop_head (queue)))
15588     {
15589       ClutterActorTraverseVisitFlags flags;
15590
15591       if (actor == &dummy)
15592         {
15593           current_depth++;
15594           g_queue_push_tail (queue, &dummy);
15595           continue;
15596         }
15597
15598       flags = callback (actor, current_depth, user_data);
15599       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15600         break;
15601       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15602         {
15603           ClutterActor *iter;
15604
15605           for (iter = actor->priv->first_child;
15606                iter != NULL;
15607                iter = iter->priv->next_sibling)
15608             {
15609               g_queue_push_tail (queue, iter);
15610             }
15611         }
15612     }
15613
15614   g_queue_free (queue);
15615 }
15616
15617 static ClutterActorTraverseVisitFlags
15618 _clutter_actor_traverse_depth (ClutterActor           *actor,
15619                                ClutterTraverseCallback before_children_callback,
15620                                ClutterTraverseCallback after_children_callback,
15621                                int                     current_depth,
15622                                gpointer                user_data)
15623 {
15624   ClutterActorTraverseVisitFlags flags;
15625
15626   flags = before_children_callback (actor, current_depth, user_data);
15627   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15628     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15629
15630   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15631     {
15632       ClutterActor *iter;
15633
15634       for (iter = actor->priv->first_child;
15635            iter != NULL;
15636            iter = iter->priv->next_sibling)
15637         {
15638           flags = _clutter_actor_traverse_depth (iter,
15639                                                  before_children_callback,
15640                                                  after_children_callback,
15641                                                  current_depth + 1,
15642                                                  user_data);
15643
15644           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15645             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15646         }
15647     }
15648
15649   if (after_children_callback)
15650     return after_children_callback (actor, current_depth, user_data);
15651   else
15652     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15653 }
15654
15655 /* _clutter_actor_traverse:
15656  * @actor: The actor to start traversing the graph from
15657  * @flags: These flags may affect how the traversal is done
15658  * @before_children_callback: A function to call before visiting the
15659  *   children of the current actor.
15660  * @after_children_callback: A function to call after visiting the
15661  *   children of the current actor. (Ignored if
15662  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15663  * @user_data: The private data to pass to the callbacks
15664  *
15665  * Traverses the scenegraph starting at the specified @actor and
15666  * descending through all its children and its children's children.
15667  * For each actor traversed @before_children_callback and
15668  * @after_children_callback are called with the specified
15669  * @user_data, before and after visiting that actor's children.
15670  *
15671  * The callbacks can return flags that affect the ongoing traversal
15672  * such as by skipping over an actors children or bailing out of
15673  * any further traversing.
15674  */
15675 void
15676 _clutter_actor_traverse (ClutterActor              *actor,
15677                          ClutterActorTraverseFlags  flags,
15678                          ClutterTraverseCallback    before_children_callback,
15679                          ClutterTraverseCallback    after_children_callback,
15680                          gpointer                   user_data)
15681 {
15682   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15683     _clutter_actor_traverse_breadth (actor,
15684                                      before_children_callback,
15685                                      user_data);
15686   else /* DEPTH_FIRST */
15687     _clutter_actor_traverse_depth (actor,
15688                                    before_children_callback,
15689                                    after_children_callback,
15690                                    0, /* start depth */
15691                                    user_data);
15692 }
15693
15694 static void
15695 on_layout_manager_changed (ClutterLayoutManager *manager,
15696                            ClutterActor         *self)
15697 {
15698   clutter_actor_queue_relayout (self);
15699 }
15700
15701 /**
15702  * clutter_actor_set_layout_manager:
15703  * @self: a #ClutterActor
15704  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15705  *
15706  * Sets the #ClutterLayoutManager delegate object that will be used to
15707  * lay out the children of @self.
15708  *
15709  * The #ClutterActor will take a reference on the passed @manager which
15710  * will be released either when the layout manager is removed, or when
15711  * the actor is destroyed.
15712  *
15713  * Since: 1.10
15714  */
15715 void
15716 clutter_actor_set_layout_manager (ClutterActor         *self,
15717                                   ClutterLayoutManager *manager)
15718 {
15719   ClutterActorPrivate *priv;
15720
15721   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15722   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15723
15724   priv = self->priv;
15725
15726   if (priv->layout_manager != NULL)
15727     {
15728       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15729                                             G_CALLBACK (on_layout_manager_changed),
15730                                             self);
15731       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15732       g_object_unref (priv->layout_manager);
15733     }
15734
15735   priv->layout_manager = manager;
15736
15737   if (priv->layout_manager != NULL)
15738     {
15739       g_object_ref_sink (priv->layout_manager);
15740       clutter_layout_manager_set_container (priv->layout_manager,
15741                                             CLUTTER_CONTAINER (self));
15742       g_signal_connect (priv->layout_manager, "layout-changed",
15743                         G_CALLBACK (on_layout_manager_changed),
15744                         self);
15745     }
15746
15747   clutter_actor_queue_relayout (self);
15748
15749   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15750 }
15751
15752 /**
15753  * clutter_actor_get_layout_manager:
15754  * @self: a #ClutterActor
15755  *
15756  * Retrieves the #ClutterLayoutManager used by @self.
15757  *
15758  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15759  *   or %NULL
15760  *
15761  * Since: 1.10
15762  */
15763 ClutterLayoutManager *
15764 clutter_actor_get_layout_manager (ClutterActor *self)
15765 {
15766   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15767
15768   return self->priv->layout_manager;
15769 }
15770
15771 static const ClutterLayoutInfo default_layout_info = {
15772   0.f,                          /* fixed-x */
15773   0.f,                          /* fixed-y */
15774   { 0, 0, 0, 0 },               /* margin */
15775   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15776   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15777   0.f, 0.f,                     /* min_width, natural_width */
15778   0.f, 0.f,                     /* natual_width, natural_height */
15779 };
15780
15781 static void
15782 layout_info_free (gpointer data)
15783 {
15784   if (G_LIKELY (data != NULL))
15785     g_slice_free (ClutterLayoutInfo, data);
15786 }
15787
15788 /*< private >
15789  * _clutter_actor_get_layout_info:
15790  * @self: a #ClutterActor
15791  *
15792  * Retrieves a pointer to the ClutterLayoutInfo structure.
15793  *
15794  * If the actor does not have a ClutterLayoutInfo associated to it, one
15795  * will be created and initialized to the default values.
15796  *
15797  * This function should be used for setters.
15798  *
15799  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15800  * instead.
15801  *
15802  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15803  */
15804 ClutterLayoutInfo *
15805 _clutter_actor_get_layout_info (ClutterActor *self)
15806 {
15807   ClutterLayoutInfo *retval;
15808
15809   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15810   if (retval == NULL)
15811     {
15812       retval = g_slice_new (ClutterLayoutInfo);
15813
15814       *retval = default_layout_info;
15815
15816       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15817                                retval,
15818                                layout_info_free);
15819     }
15820
15821   return retval;
15822 }
15823
15824 /*< private >
15825  * _clutter_actor_get_layout_info_or_defaults:
15826  * @self: a #ClutterActor
15827  *
15828  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15829  *
15830  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15831  * then the default structure will be returned.
15832  *
15833  * This function should only be used for getters.
15834  *
15835  * Return value: a const pointer to the ClutterLayoutInfo structure
15836  */
15837 const ClutterLayoutInfo *
15838 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15839 {
15840   const ClutterLayoutInfo *info;
15841
15842   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15843   if (info == NULL)
15844     return &default_layout_info;
15845
15846   return info;
15847 }
15848
15849 /**
15850  * clutter_actor_set_x_align:
15851  * @self: a #ClutterActor
15852  * @x_align: the horizontal alignment policy
15853  *
15854  * Sets the horizontal alignment policy of a #ClutterActor, in case the
15855  * actor received extra horizontal space.
15856  *
15857  * See also the #ClutterActor:x-align property.
15858  *
15859  * Since: 1.10
15860  */
15861 void
15862 clutter_actor_set_x_align (ClutterActor      *self,
15863                            ClutterActorAlign  x_align)
15864 {
15865   ClutterLayoutInfo *info;
15866
15867   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15868
15869   info = _clutter_actor_get_layout_info (self);
15870
15871   if (info->x_align != x_align)
15872     {
15873       info->x_align = x_align;
15874
15875       clutter_actor_queue_relayout (self);
15876
15877       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15878     }
15879 }
15880
15881 /**
15882  * clutter_actor_get_x_align:
15883  * @self: a #ClutterActor
15884  *
15885  * Retrieves the horizontal alignment policy set using
15886  * clutter_actor_set_x_align().
15887  *
15888  * Return value: the horizontal alignment policy.
15889  *
15890  * Since: 1.10
15891  */
15892 ClutterActorAlign
15893 clutter_actor_get_x_align (ClutterActor *self)
15894 {
15895   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15896
15897   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15898 }
15899
15900 /**
15901  * clutter_actor_set_y_align:
15902  * @self: a #ClutterActor
15903  * @y_align: the vertical alignment policy
15904  *
15905  * Sets the vertical alignment policy of a #ClutterActor, in case the
15906  * actor received extra vertical space.
15907  *
15908  * See also the #ClutterActor:y-align property.
15909  *
15910  * Since: 1.10
15911  */
15912 void
15913 clutter_actor_set_y_align (ClutterActor      *self,
15914                            ClutterActorAlign  y_align)
15915 {
15916   ClutterLayoutInfo *info;
15917
15918   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15919
15920   info = _clutter_actor_get_layout_info (self);
15921
15922   if (info->y_align != y_align)
15923     {
15924       info->y_align = y_align;
15925
15926       clutter_actor_queue_relayout (self);
15927
15928       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15929     }
15930 }
15931
15932 /**
15933  * clutter_actor_get_y_align:
15934  * @self: a #ClutterActor
15935  *
15936  * Retrieves the vertical alignment policy set using
15937  * clutter_actor_set_y_align().
15938  *
15939  * Return value: the vertical alignment policy.
15940  *
15941  * Since: 1.10
15942  */
15943 ClutterActorAlign
15944 clutter_actor_get_y_align (ClutterActor *self)
15945 {
15946   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15947
15948   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15949 }
15950
15951
15952 /**
15953  * clutter_margin_new:
15954  *
15955  * Creates a new #ClutterMargin.
15956  *
15957  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15958  *   clutter_margin_free() to free the resources associated with it when
15959  *   done.
15960  *
15961  * Since: 1.10
15962  */
15963 ClutterMargin *
15964 clutter_margin_new (void)
15965 {
15966   return g_slice_new0 (ClutterMargin);
15967 }
15968
15969 /**
15970  * clutter_margin_copy:
15971  * @margin_: a #ClutterMargin
15972  *
15973  * Creates a new #ClutterMargin and copies the contents of @margin_ into
15974  * the newly created structure.
15975  *
15976  * Return value: (transfer full): a copy of the #ClutterMargin.
15977  *
15978  * Since: 1.10
15979  */
15980 ClutterMargin *
15981 clutter_margin_copy (const ClutterMargin *margin_)
15982 {
15983   if (G_LIKELY (margin_ != NULL))
15984     return g_slice_dup (ClutterMargin, margin_);
15985
15986   return NULL;
15987 }
15988
15989 /**
15990  * clutter_margin_free:
15991  * @margin_: a #ClutterMargin
15992  *
15993  * Frees the resources allocated by clutter_margin_new() and
15994  * clutter_margin_copy().
15995  *
15996  * Since: 1.10
15997  */
15998 void
15999 clutter_margin_free (ClutterMargin *margin_)
16000 {
16001   if (G_LIKELY (margin_ != NULL))
16002     g_slice_free (ClutterMargin, margin_);
16003 }
16004
16005 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16006                      clutter_margin_copy,
16007                      clutter_margin_free)
16008
16009 /**
16010  * clutter_actor_set_margin:
16011  * @self: a #ClutterActor
16012  * @margin: a #ClutterMargin
16013  *
16014  * Sets all the components of the margin of a #ClutterActor.
16015  *
16016  * Since: 1.10
16017  */
16018 void
16019 clutter_actor_set_margin (ClutterActor        *self,
16020                           const ClutterMargin *margin)
16021 {
16022   ClutterLayoutInfo *info;
16023   gboolean changed;
16024   GObject *obj;
16025
16026   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16027   g_return_if_fail (margin != NULL);
16028
16029   obj = G_OBJECT (self);
16030   changed = FALSE;
16031
16032   g_object_freeze_notify (obj);
16033
16034   info = _clutter_actor_get_layout_info (self);
16035
16036   if (info->margin.top != margin->top)
16037     {
16038       info->margin.top = margin->top;
16039       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16040       changed = TRUE;
16041     }
16042
16043   if (info->margin.right != margin->right)
16044     {
16045       info->margin.right = margin->right;
16046       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16047       changed = TRUE;
16048     }
16049
16050   if (info->margin.bottom != margin->bottom)
16051     {
16052       info->margin.bottom = margin->bottom;
16053       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16054       changed = TRUE;
16055     }
16056
16057   if (info->margin.left != margin->left)
16058     {
16059       info->margin.left = margin->left;
16060       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16061       changed = TRUE;
16062     }
16063
16064   if (changed)
16065     clutter_actor_queue_relayout (self);
16066
16067   g_object_thaw_notify (obj);
16068 }
16069
16070 /**
16071  * clutter_actor_get_margin:
16072  * @self: a #ClutterActor
16073  * @margin: (out caller-allocates): return location for a #ClutterMargin
16074  *
16075  * Retrieves all the components of the margin of a #ClutterActor.
16076  *
16077  * Since: 1.10
16078  */
16079 void
16080 clutter_actor_get_margin (ClutterActor  *self,
16081                           ClutterMargin *margin)
16082 {
16083   const ClutterLayoutInfo *info;
16084
16085   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16086   g_return_if_fail (margin != NULL);
16087
16088   info = _clutter_actor_get_layout_info_or_defaults (self);
16089
16090   *margin = info->margin;
16091 }
16092
16093 /**
16094  * clutter_actor_set_margin_top:
16095  * @self: a #ClutterActor
16096  * @margin: the top margin
16097  *
16098  * Sets the margin from the top of a #ClutterActor.
16099  *
16100  * Since: 1.10
16101  */
16102 void
16103 clutter_actor_set_margin_top (ClutterActor *self,
16104                               gfloat        margin)
16105 {
16106   ClutterLayoutInfo *info;
16107
16108   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16109   g_return_if_fail (margin >= 0.f);
16110
16111   info = _clutter_actor_get_layout_info (self);
16112
16113   if (info->margin.top == margin)
16114     return;
16115
16116   info->margin.top = margin;
16117
16118   clutter_actor_queue_relayout (self);
16119
16120   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16121 }
16122
16123 /**
16124  * clutter_actor_get_margin_top:
16125  * @self: a #ClutterActor
16126  *
16127  * Retrieves the top margin of a #ClutterActor.
16128  *
16129  * Return value: the top margin
16130  *
16131  * Since: 1.10
16132  */
16133 gfloat
16134 clutter_actor_get_margin_top (ClutterActor *self)
16135 {
16136   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16137
16138   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16139 }
16140
16141 /**
16142  * clutter_actor_set_margin_bottom:
16143  * @self: a #ClutterActor
16144  * @margin: the bottom margin
16145  *
16146  * Sets the margin from the bottom of a #ClutterActor.
16147  *
16148  * Since: 1.10
16149  */
16150 void
16151 clutter_actor_set_margin_bottom (ClutterActor *self,
16152                                  gfloat        margin)
16153 {
16154   ClutterLayoutInfo *info;
16155
16156   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16157   g_return_if_fail (margin >= 0.f);
16158
16159   info = _clutter_actor_get_layout_info (self);
16160
16161   if (info->margin.bottom == margin)
16162     return;
16163
16164   info->margin.bottom = margin;
16165
16166   clutter_actor_queue_relayout (self);
16167
16168   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16169 }
16170
16171 /**
16172  * clutter_actor_get_margin_bottom:
16173  * @self: a #ClutterActor
16174  *
16175  * Retrieves the bottom margin of a #ClutterActor.
16176  *
16177  * Return value: the bottom margin
16178  *
16179  * Since: 1.10
16180  */
16181 gfloat
16182 clutter_actor_get_margin_bottom (ClutterActor *self)
16183 {
16184   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16185
16186   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16187 }
16188
16189 /**
16190  * clutter_actor_set_margin_left:
16191  * @self: a #ClutterActor
16192  * @margin: the left margin
16193  *
16194  * Sets the margin from the left of a #ClutterActor.
16195  *
16196  * Since: 1.10
16197  */
16198 void
16199 clutter_actor_set_margin_left (ClutterActor *self,
16200                                gfloat        margin)
16201 {
16202   ClutterLayoutInfo *info;
16203
16204   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16205   g_return_if_fail (margin >= 0.f);
16206
16207   info = _clutter_actor_get_layout_info (self);
16208
16209   if (info->margin.left == margin)
16210     return;
16211
16212   info->margin.left = margin;
16213
16214   clutter_actor_queue_relayout (self);
16215
16216   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16217 }
16218
16219 /**
16220  * clutter_actor_get_margin_left:
16221  * @self: a #ClutterActor
16222  *
16223  * Retrieves the left margin of a #ClutterActor.
16224  *
16225  * Return value: the left margin
16226  *
16227  * Since: 1.10
16228  */
16229 gfloat
16230 clutter_actor_get_margin_left (ClutterActor *self)
16231 {
16232   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16233
16234   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16235 }
16236
16237 /**
16238  * clutter_actor_set_margin_right:
16239  * @self: a #ClutterActor
16240  * @margin: the right margin
16241  *
16242  * Sets the margin from the right of a #ClutterActor.
16243  *
16244  * Since: 1.10
16245  */
16246 void
16247 clutter_actor_set_margin_right (ClutterActor *self,
16248                                 gfloat        margin)
16249 {
16250   ClutterLayoutInfo *info;
16251
16252   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16253   g_return_if_fail (margin >= 0.f);
16254
16255   info = _clutter_actor_get_layout_info (self);
16256
16257   if (info->margin.right == margin)
16258     return;
16259
16260   info->margin.right = margin;
16261
16262   clutter_actor_queue_relayout (self);
16263
16264   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16265 }
16266
16267 /**
16268  * clutter_actor_get_margin_right:
16269  * @self: a #ClutterActor
16270  *
16271  * Retrieves the right margin of a #ClutterActor.
16272  *
16273  * Return value: the right margin
16274  *
16275  * Since: 1.10
16276  */
16277 gfloat
16278 clutter_actor_get_margin_right (ClutterActor *self)
16279 {
16280   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16281
16282   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16283 }
16284
16285 static inline void
16286 clutter_actor_set_background_color_internal (ClutterActor *self,
16287                                              const ClutterColor *color)
16288 {
16289   ClutterActorPrivate *priv = self->priv;
16290   GObject *obj;
16291
16292   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16293     return;
16294
16295   obj = G_OBJECT (self);
16296
16297   priv->bg_color = *color;
16298   priv->bg_color_set = TRUE;
16299
16300   clutter_actor_queue_redraw (self);
16301
16302   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16303   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16304 }
16305
16306 /**
16307  * clutter_actor_set_background_color:
16308  * @self: a #ClutterActor
16309  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16310  *  set color
16311  *
16312  * Sets the background color of a #ClutterActor.
16313  *
16314  * The background color will be used to cover the whole allocation of the
16315  * actor. The default background color of an actor is transparent.
16316  *
16317  * To check whether an actor has a background color, you can use the
16318  * #ClutterActor:background-color-set actor property.
16319  *
16320  * The #ClutterActor:background-color property is animatable.
16321  *
16322  * Since: 1.10
16323  */
16324 void
16325 clutter_actor_set_background_color (ClutterActor       *self,
16326                                     const ClutterColor *color)
16327 {
16328   ClutterActorPrivate *priv;
16329   GObject *obj;
16330   GParamSpec *bg_color_pspec;
16331
16332   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16333
16334   obj = G_OBJECT (self);
16335
16336   priv = self->priv;
16337
16338   if (color == NULL)
16339     {
16340       priv->bg_color_set = FALSE;
16341       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16342       clutter_actor_queue_redraw (self);
16343       return;
16344     }
16345
16346   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16347   if (clutter_actor_get_easing_duration (self) != 0)
16348     {
16349       ClutterTransition *transition;
16350
16351       transition = _clutter_actor_get_transition (self, bg_color_pspec);
16352       if (transition == NULL)
16353         {
16354           transition = _clutter_actor_create_transition (self, bg_color_pspec,
16355                                                          &priv->bg_color,
16356                                                          color);
16357           clutter_timeline_start (CLUTTER_TIMELINE (transition));
16358         }
16359       else
16360         _clutter_actor_update_transition (self, bg_color_pspec, color);
16361
16362       clutter_actor_queue_redraw (self);
16363     }
16364   else
16365     clutter_actor_set_background_color_internal (self, color);
16366 }
16367
16368 /**
16369  * clutter_actor_get_background_color:
16370  * @self: a #ClutterActor
16371  * @color: (out caller-allocates): return location for a #ClutterColor
16372  *
16373  * Retrieves the color set using clutter_actor_set_background_color().
16374  *
16375  * Since: 1.10
16376  */
16377 void
16378 clutter_actor_get_background_color (ClutterActor *self,
16379                                     ClutterColor *color)
16380 {
16381   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16382   g_return_if_fail (color != NULL);
16383
16384   *color = self->priv->bg_color;
16385 }
16386
16387 /**
16388  * clutter_actor_get_previous_sibling:
16389  * @self: a #ClutterActor
16390  *
16391  * Retrieves the sibling of @self that comes before it in the list
16392  * of children of @self's parent.
16393  *
16394  * The returned pointer is only valid until the scene graph changes; it
16395  * is not safe to modify the list of children of @self while iterating
16396  * it.
16397  *
16398  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16399  *
16400  * Since: 1.10
16401  */
16402 ClutterActor *
16403 clutter_actor_get_previous_sibling (ClutterActor *self)
16404 {
16405   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16406
16407   return self->priv->prev_sibling;
16408 }
16409
16410 /**
16411  * clutter_actor_get_next_sibling:
16412  * @self: a #ClutterActor
16413  *
16414  * Retrieves the sibling of @self that comes after it in the list
16415  * of children of @self's parent.
16416  *
16417  * The returned pointer is only valid until the scene graph changes; it
16418  * is not safe to modify the list of children of @self while iterating
16419  * it.
16420  *
16421  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16422  *
16423  * Since: 1.10
16424  */
16425 ClutterActor *
16426 clutter_actor_get_next_sibling (ClutterActor *self)
16427 {
16428   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16429
16430   return self->priv->next_sibling;
16431 }
16432
16433 /**
16434  * clutter_actor_get_first_child:
16435  * @self: a #ClutterActor
16436  *
16437  * Retrieves the first child of @self.
16438  *
16439  * The returned pointer is only valid until the scene graph changes; it
16440  * is not safe to modify the list of children of @self while iterating
16441  * it.
16442  *
16443  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16444  *
16445  * Since: 1.10
16446  */
16447 ClutterActor *
16448 clutter_actor_get_first_child (ClutterActor *self)
16449 {
16450   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16451
16452   return self->priv->first_child;
16453 }
16454
16455 /**
16456  * clutter_actor_get_last_child:
16457  * @self: a #ClutterActor
16458  *
16459  * Retrieves the last child of @self.
16460  *
16461  * The returned pointer is only valid until the scene graph changes; it
16462  * is not safe to modify the list of children of @self while iterating
16463  * it.
16464  *
16465  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16466  *
16467  * Since: 1.10
16468  */
16469 ClutterActor *
16470 clutter_actor_get_last_child (ClutterActor *self)
16471 {
16472   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16473
16474   return self->priv->last_child;
16475 }
16476
16477 /* easy way to have properly named fields instead of the dummy ones
16478  * we use in the public structure
16479  */
16480 typedef struct _RealActorIter
16481 {
16482   ClutterActor *root;           /* dummy1 */
16483   ClutterActor *current;        /* dummy2 */
16484   gpointer padding_1;           /* dummy3 */
16485   gint age;                     /* dummy4 */
16486   gpointer padding_2;           /* dummy5 */
16487 } RealActorIter;
16488
16489 /**
16490  * clutter_actor_iter_init:
16491  * @iter: a #ClutterActorIter
16492  * @root: a #ClutterActor
16493  *
16494  * Initializes a #ClutterActorIter, which can then be used to iterate
16495  * efficiently over a section of the scene graph, and associates it
16496  * with @root.
16497  *
16498  * Modifying the scene graph section that contains @root will invalidate
16499  * the iterator.
16500  *
16501  * |[
16502  *   ClutterActorIter iter;
16503  *   ClutterActor *child;
16504  *
16505  *   clutter_actor_iter_init (&iter, container);
16506  *   while (clutter_actor_iter_next (&iter, &child))
16507  *     {
16508  *       /&ast; do something with child &ast;/
16509  *     }
16510  * ]|
16511  *
16512  * Since: 1.10
16513  */
16514 void
16515 clutter_actor_iter_init (ClutterActorIter *iter,
16516                          ClutterActor     *root)
16517 {
16518   RealActorIter *ri = (RealActorIter *) iter;
16519
16520   g_return_if_fail (iter != NULL);
16521   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16522
16523   ri->root = root;
16524   ri->current = NULL;
16525   ri->age = root->priv->age;
16526 }
16527
16528 /**
16529  * clutter_actor_iter_next:
16530  * @iter: a #ClutterActorIter
16531  * @child: (out): return location for a #ClutterActor
16532  *
16533  * Advances the @iter and retrieves the next child of the root #ClutterActor
16534  * that was used to initialize the #ClutterActorIterator.
16535  *
16536  * If the iterator can advance, this function returns %TRUE and sets the
16537  * @child argument.
16538  *
16539  * If the iterator cannot advance, this function returns %FALSE, and
16540  * the contents of @child are undefined.
16541  *
16542  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16543  *
16544  * Since: 1.10
16545  */
16546 gboolean
16547 clutter_actor_iter_next (ClutterActorIter  *iter,
16548                          ClutterActor     **child)
16549 {
16550   RealActorIter *ri = (RealActorIter *) iter;
16551
16552   g_return_val_if_fail (iter != NULL, FALSE);
16553   g_return_val_if_fail (ri->root != NULL, FALSE);
16554 #ifndef G_DISABLE_ASSERT
16555   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16556 #endif
16557
16558   if (ri->current == NULL)
16559     ri->current = ri->root->priv->first_child;
16560   else
16561     ri->current = ri->current->priv->next_sibling;
16562
16563   if (child != NULL)
16564     *child = ri->current;
16565
16566   return ri->current != NULL;
16567 }
16568
16569 /**
16570  * clutter_actor_iter_prev:
16571  * @iter: a #ClutterActorIter
16572  * @child: (out): return location for a #ClutterActor
16573  *
16574  * Advances the @iter and retrieves the previous child of the root
16575  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16576  *
16577  * If the iterator can advance, this function returns %TRUE and sets the
16578  * @child argument.
16579  *
16580  * If the iterator cannot advance, this function returns %FALSE, and
16581  * the contents of @child are undefined.
16582  *
16583  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16584  *
16585  * Since: 1.10
16586  */
16587 gboolean
16588 clutter_actor_iter_prev (ClutterActorIter  *iter,
16589                          ClutterActor     **child)
16590 {
16591   RealActorIter *ri = (RealActorIter *) iter;
16592
16593   g_return_val_if_fail (iter != NULL, FALSE);
16594   g_return_val_if_fail (ri->root != NULL, FALSE);
16595 #ifndef G_DISABLE_ASSERT
16596   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16597 #endif
16598
16599   if (ri->current == NULL)
16600     ri->current = ri->root->priv->last_child;
16601   else
16602     ri->current = ri->current->priv->prev_sibling;
16603
16604   if (child != NULL)
16605     *child = ri->current;
16606
16607   return ri->current != NULL;
16608 }
16609
16610 /**
16611  * clutter_actor_iter_remove:
16612  * @iter: a #ClutterActorIter
16613  *
16614  * Safely removes the #ClutterActor currently pointer to by the iterator
16615  * from its parent.
16616  *
16617  * This function can only be called after clutter_actor_iter_next() or
16618  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16619  * than once for the same actor.
16620  *
16621  * This function will call clutter_actor_remove_child() internally.
16622  *
16623  * Since: 1.10
16624  */
16625 void
16626 clutter_actor_iter_remove (ClutterActorIter *iter)
16627 {
16628   RealActorIter *ri = (RealActorIter *) iter;
16629   ClutterActor *cur;
16630
16631   g_return_if_fail (iter != NULL);
16632   g_return_if_fail (ri->root != NULL);
16633 #ifndef G_DISABLE_ASSERT
16634   g_return_if_fail (ri->age == ri->root->priv->age);
16635 #endif
16636   g_return_if_fail (ri->current != NULL);
16637
16638   cur = ri->current;
16639
16640   if (cur != NULL)
16641     {
16642       ri->current = cur->priv->prev_sibling;
16643
16644       clutter_actor_remove_child_internal (ri->root, cur,
16645                                            REMOVE_CHILD_DEFAULT_FLAGS);
16646
16647       ri->age += 1;
16648     }
16649 }
16650
16651 /**
16652  * clutter_actor_iter_destroy:
16653  * @iter: a #ClutterActorIter
16654  *
16655  * Safely destroys the #ClutterActor currently pointer to by the iterator
16656  * from its parent.
16657  *
16658  * This function can only be called after clutter_actor_iter_next() or
16659  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16660  * than once for the same actor.
16661  *
16662  * This function will call clutter_actor_destroy() internally.
16663  *
16664  * Since: 1.10
16665  */
16666 void
16667 clutter_actor_iter_destroy (ClutterActorIter *iter)
16668 {
16669   RealActorIter *ri = (RealActorIter *) iter;
16670   ClutterActor *cur;
16671
16672   g_return_if_fail (iter != NULL);
16673   g_return_if_fail (ri->root != NULL);
16674 #ifndef G_DISABLE_ASSERT
16675   g_return_if_fail (ri->age == ri->root->priv->age);
16676 #endif
16677   g_return_if_fail (ri->current != NULL);
16678
16679   cur = ri->current;
16680
16681   if (cur != NULL)
16682     {
16683       ri->current = cur->priv->prev_sibling;
16684
16685       clutter_actor_destroy (cur);
16686
16687       ri->age += 1;
16688     }
16689 }
16690
16691 static const ClutterAnimationInfo default_animation_info = {
16692   NULL,         /* transitions */
16693   NULL,         /* states */
16694   NULL,         /* cur_state */
16695 };
16696
16697 static void
16698 clutter_animation_info_free (gpointer data)
16699 {
16700   if (data != NULL)
16701     {
16702       ClutterAnimationInfo *info = data;
16703
16704       if (info->transitions != NULL)
16705         g_hash_table_unref (info->transitions);
16706
16707       if (info->states != NULL)
16708         g_array_unref (info->states);
16709
16710       g_slice_free (ClutterAnimationInfo, info);
16711     }
16712 }
16713
16714 const ClutterAnimationInfo *
16715 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16716 {
16717   const ClutterAnimationInfo *res;
16718   GObject *obj = G_OBJECT (self);
16719
16720   res = g_object_get_qdata (obj, quark_actor_animation_info);
16721   if (res != NULL)
16722     return res;
16723
16724   return &default_animation_info;
16725 }
16726
16727 ClutterAnimationInfo *
16728 _clutter_actor_get_animation_info (ClutterActor *self)
16729 {
16730   GObject *obj = G_OBJECT (self);
16731   ClutterAnimationInfo *res;
16732
16733   res = g_object_get_qdata (obj, quark_actor_animation_info);
16734   if (res == NULL)
16735     {
16736       res = g_slice_new (ClutterAnimationInfo);
16737
16738       *res = default_animation_info;
16739
16740       g_object_set_qdata_full (obj, quark_actor_animation_info,
16741                                res,
16742                                clutter_animation_info_free);
16743     }
16744
16745   return res;
16746 }
16747
16748 ClutterTransition *
16749 _clutter_actor_get_transition (ClutterActor *actor,
16750                                GParamSpec   *pspec)
16751 {
16752   const ClutterAnimationInfo *info;
16753
16754   info = _clutter_actor_get_animation_info_or_defaults (actor);
16755
16756   if (info->transitions == NULL)
16757     return NULL;
16758
16759   return g_hash_table_lookup (info->transitions, pspec->name);
16760 }
16761
16762 typedef struct _TransitionClosure
16763 {
16764   ClutterActor *actor;
16765   ClutterTransition *transition;
16766   gchar *name;
16767   gulong completed_id;
16768 } TransitionClosure;
16769
16770 static void
16771 transition_closure_free (gpointer data)
16772 {
16773   if (G_LIKELY (data != NULL))
16774     {
16775       TransitionClosure *clos = data;
16776
16777       g_signal_handler_disconnect (clos->transition, clos->completed_id);
16778       g_free (clos->name);
16779
16780       g_slice_free (TransitionClosure, clos);
16781     }
16782 }
16783
16784 static void
16785 on_transition_completed (ClutterTransition *transition,
16786                          TransitionClosure *clos)
16787 {
16788   ClutterAnimationInfo *info;
16789
16790   info = _clutter_actor_get_animation_info (clos->actor);
16791
16792   /* this will take care of cleaning clos for us */
16793   g_hash_table_remove (info->transitions, clos->name);
16794 }
16795
16796 void
16797 _clutter_actor_update_transition (ClutterActor *actor,
16798                                   GParamSpec   *pspec,
16799                                   ...)
16800 {
16801   TransitionClosure *clos;
16802   ClutterInterval *interval;
16803   const ClutterAnimationInfo *info;
16804   va_list var_args;
16805   GType ptype;
16806   GValue initial = G_VALUE_INIT;
16807   GValue final = G_VALUE_INIT;
16808   char *error = NULL;
16809
16810   info = _clutter_actor_get_animation_info_or_defaults (actor);
16811
16812   if (info->transitions == NULL)
16813     return;
16814
16815   clos = g_hash_table_lookup (info->transitions, pspec->name);
16816   if (clos == NULL)
16817     return;
16818
16819   va_start (var_args, pspec);
16820
16821   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16822
16823   g_value_init (&initial, ptype);
16824   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
16825                                         pspec->name,
16826                                         &initial);
16827
16828   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
16829   if (error != NULL)
16830     {
16831       g_critical ("%s: %s", G_STRLOC, error);
16832       g_free (error);
16833       goto out;
16834     }
16835
16836   interval = clutter_transition_get_interval (clos->transition);
16837   clutter_interval_set_initial_value (interval, &initial);
16838   clutter_interval_set_final_value (interval, &final);
16839
16840   clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
16841
16842 out:
16843   g_value_unset (&initial);
16844   g_value_unset (&final);
16845
16846   va_end (var_args);
16847 }
16848
16849 /*< private >*
16850  * _clutter_actor_create_transition:
16851  * @actor: a #ClutterActor
16852  * @pspec: the property used for the transition
16853  * @...: initial and final state
16854  *
16855  * Creates a #ClutterTransition for the property represented by @pspec.
16856  *
16857  * Return value: a #ClutterTransition
16858  */
16859 ClutterTransition *
16860 _clutter_actor_create_transition (ClutterActor *actor,
16861                                   GParamSpec   *pspec,
16862                                   ...)
16863 {
16864   ClutterAnimationInfo *info;
16865   ClutterTransition *res = NULL;
16866   gboolean call_restore = FALSE;
16867   TransitionClosure *clos;
16868   va_list var_args;
16869
16870   info = _clutter_actor_get_animation_info (actor);
16871
16872   if (info->states == NULL)
16873     {
16874       clutter_actor_save_easing_state (actor);
16875       call_restore = TRUE;
16876     }
16877
16878   if (info->transitions == NULL)
16879     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
16880                                                NULL,
16881                                                transition_closure_free);
16882
16883   va_start (var_args, pspec);
16884
16885   clos = g_hash_table_lookup (info->transitions, pspec->name);
16886   if (clos == NULL)
16887     {
16888       ClutterInterval *interval;
16889       GValue initial = G_VALUE_INIT;
16890       GValue final = G_VALUE_INIT;
16891       GType ptype;
16892       char *error;
16893
16894       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16895
16896       G_VALUE_COLLECT_INIT (&initial, ptype,
16897                             var_args, 0,
16898                             &error);
16899       if (error != NULL)
16900         {
16901           g_critical ("%s: %s", G_STRLOC, error);
16902           g_free (error);
16903           goto out;
16904         }
16905
16906       G_VALUE_COLLECT_INIT (&final, ptype,
16907                             var_args, 0,
16908                             &error);
16909
16910       if (error != NULL)
16911         {
16912           g_critical ("%s: %s", G_STRLOC, error);
16913           g_value_unset (&initial);
16914           g_free (error);
16915           goto out;
16916         }
16917
16918       interval = clutter_interval_new_with_values (ptype, &initial, &final);
16919
16920       g_value_unset (&initial);
16921       g_value_unset (&final);
16922
16923       res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
16924                                              pspec->name);
16925
16926       clutter_transition_set_interval (res, interval);
16927       clutter_transition_set_remove_on_complete (res, TRUE);
16928
16929       clutter_actor_add_transition (actor, pspec->name, res);
16930     }
16931   else
16932     res = clos->transition;
16933
16934 out:
16935   if (call_restore)
16936     clutter_actor_restore_easing_state (actor);
16937
16938   va_end (var_args);
16939
16940   return res;
16941 }
16942
16943 /**
16944  * clutter_actor_add_transition:
16945  * @self: a #ClutterActor
16946  * @name: the name of the transition to add
16947  * @transition: the #ClutterTransition to add
16948  *
16949  * Adds a @transition to the #ClutterActor's list of animations.
16950  *
16951  * The @name string is a per-actor unique identifier of the @transition: only
16952  * one #ClutterTransition can be associated to the specified @name.
16953  *
16954  * The @transition will be given the easing duration, mode, and delay
16955  * associated to the actor's current easing state; it is possible to modify
16956  * these values after calling clutter_actor_add_transition().
16957  *
16958  * This function is usually called implicitly when modifying an animatable
16959  * property.
16960  *
16961  * Since: 1.10
16962  */
16963 void
16964 clutter_actor_add_transition (ClutterActor      *self,
16965                               const char        *name,
16966                               ClutterTransition *transition)
16967 {
16968   ClutterTimeline *timeline;
16969   TransitionClosure *clos;
16970   ClutterAnimationInfo *info;
16971
16972   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16973   g_return_if_fail (name != NULL);
16974   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
16975
16976   info = _clutter_actor_get_animation_info (self);
16977
16978   if (info->cur_state == NULL)
16979     {
16980       g_warning ("No easing state is defined for the actor '%s'; you "
16981                  "must call clutter_actor_save_easing_state() before "
16982                  "calling clutter_actor_add_transition().",
16983                  _clutter_actor_get_debug_name (self));
16984       return;
16985     }
16986
16987   if (info->transitions == NULL)
16988     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
16989                                                NULL,
16990                                                transition_closure_free);
16991
16992   if (g_hash_table_lookup (info->transitions, name) != NULL)
16993     {
16994       g_warning ("A transition with name '%s' already exists for "
16995                  "the actor '%s'",
16996                  name,
16997                  _clutter_actor_get_debug_name (self));
16998       return;
16999     }
17000
17001   timeline = CLUTTER_TIMELINE (transition);
17002
17003   clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17004   clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17005   clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17006
17007   clos = g_slice_new (TransitionClosure);
17008   clos->actor = self;
17009   clos->transition = transition;
17010   clos->name = g_strdup (name);
17011   clos->completed_id = g_signal_connect (timeline, "completed",
17012                                          G_CALLBACK (on_transition_completed),
17013                                          clos);
17014
17015   g_hash_table_insert (info->transitions, clos->name, clos);
17016 }
17017
17018 /**
17019  * clutter_actor_remove_transition:
17020  * @self: a #ClutterActor
17021  * @name: the name of the transition to remove
17022  *
17023  * Removes the transition stored inside a #ClutterActor using @name
17024  * identifier.
17025  *
17026  * Since: 1.10
17027  */
17028 void
17029 clutter_actor_remove_transition (ClutterActor *self,
17030                                  const char   *name)
17031 {
17032   const ClutterAnimationInfo *info;
17033
17034   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17035   g_return_if_fail (name != NULL);
17036
17037   info = _clutter_actor_get_animation_info_or_defaults (self);
17038
17039   if (info->transitions == NULL)
17040     return;
17041
17042   g_hash_table_remove (info->transitions, name);
17043 }
17044
17045 /**
17046  * clutter_actor_remove_all_transitions:
17047  * @self: a #ClutterActor
17048  *
17049  * Removes all transitions associated to @self.
17050  *
17051  * Since: 1.10
17052  */
17053 void
17054 clutter_actor_remove_all_transitions (ClutterActor *self)
17055 {
17056   const ClutterAnimationInfo *info;
17057
17058   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17059
17060   info = _clutter_actor_get_animation_info_or_defaults (self);
17061   if (info->transitions == NULL)
17062     return;
17063
17064   g_hash_table_remove_all (info->transitions);
17065 }
17066
17067 /**
17068  * clutter_actor_set_easing_duration:
17069  * @self: a #ClutterActor
17070  * @msecs: the duration of the easing, or %NULL
17071  *
17072  * Sets the duration of the tweening for animatable properties
17073  * of @self for the current easing state.
17074  *
17075  * Calling this function will implicitly call
17076  * clutter_actor_save_easing_state() if no previous call to
17077  * that function was made.
17078  *
17079  * Since: 1.10
17080  */
17081 void
17082 clutter_actor_set_easing_duration (ClutterActor *self,
17083                                    guint         msecs)
17084 {
17085   ClutterAnimationInfo *info;
17086
17087   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17088
17089   info = _clutter_actor_get_animation_info (self);
17090
17091   if (info->states == NULL)
17092     clutter_actor_save_easing_state (self);
17093
17094   if (info->cur_state->easing_duration != msecs)
17095     info->cur_state->easing_duration = msecs;
17096 }
17097
17098 /**
17099  * clutter_actor_get_easing_duration:
17100  * @self: a #ClutterActor
17101  *
17102  * Retrieves the duration of the tweening for animatable
17103  * properties of @self for the current easing state.
17104  *
17105  * Return value: the duration of the tweening, in milliseconds
17106  *
17107  * Since: 1.10
17108  */
17109 guint
17110 clutter_actor_get_easing_duration (ClutterActor *self)
17111 {
17112   const ClutterAnimationInfo *info;
17113
17114   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17115
17116   info = _clutter_actor_get_animation_info_or_defaults (self);
17117
17118   if (info->cur_state != NULL)
17119     return info->cur_state->easing_duration;
17120
17121   return 0;
17122 }
17123
17124 /**
17125  * clutter_actor_set_easing_mode:
17126  * @self: a #ClutterActor
17127  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17128  *
17129  * Sets the easing mode for the tweening of animatable properties
17130  * of @self.
17131  *
17132  * Calling this function will implicitly call
17133  * clutter_actor_save_easing_state() if no previous calls to
17134  * that function were made.
17135  *
17136  * Since: 1.10
17137  */
17138 void
17139 clutter_actor_set_easing_mode (ClutterActor         *self,
17140                                ClutterAnimationMode  mode)
17141 {
17142   ClutterAnimationInfo *info;
17143
17144   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17145   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17146   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17147
17148   info = _clutter_actor_get_animation_info (self);
17149
17150   if (info->states == NULL)
17151     clutter_actor_save_easing_state (self);
17152
17153   if (info->cur_state->easing_mode != mode)
17154     info->cur_state->easing_mode = mode;
17155 }
17156
17157 /**
17158  * clutter_actor_get_easing_mode:
17159  * @self: a #ClutterActor
17160  *
17161  * Retrieves the easing mode for the tweening of animatable properties
17162  * of @self for the current easing state.
17163  *
17164  * Return value: an easing mode
17165  *
17166  * Since: 1.10
17167  */
17168 ClutterAnimationMode
17169 clutter_actor_get_easing_mode (ClutterActor *self)
17170 {
17171   const ClutterAnimationInfo *info;
17172
17173   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17174
17175   info = _clutter_actor_get_animation_info_or_defaults (self);
17176
17177   if (info->cur_state != NULL)
17178     return info->cur_state->easing_mode;
17179
17180   return CLUTTER_EASE_OUT_CUBIC;
17181 }
17182
17183 /**
17184  * clutter_actor_set_easing_delay:
17185  * @self: a #ClutterActor
17186  * @msecs: the delay before the start of the tweening, in milliseconds
17187  *
17188  * Sets the delay that should be applied before tweening animatable
17189  * properties.
17190  *
17191  * Calling this function will implicitly call
17192  * clutter_actor_save_easing_state() if no previous calls to
17193  * that function were made.
17194  *
17195  * Since: 1.10
17196  */
17197 void
17198 clutter_actor_set_easing_delay (ClutterActor *self,
17199                                 guint         msecs)
17200 {
17201   ClutterAnimationInfo *info;
17202
17203   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17204
17205   info = _clutter_actor_get_animation_info (self);
17206
17207   if (info->states == NULL)
17208     clutter_actor_save_easing_state (self);
17209
17210   if (info->cur_state->easing_delay != msecs)
17211     info->cur_state->easing_delay = msecs;
17212 }
17213
17214 /**
17215  * clutter_actor_get_easing_delay:
17216  * @self: a #ClutterActor
17217  *
17218  * Retrieves the delay that should be applied when tweening animatable
17219  * properties.
17220  *
17221  * Return value: a delay, in milliseconds
17222  *
17223  * Since: 1.10
17224  */
17225 guint
17226 clutter_actor_get_easing_delay (ClutterActor *self)
17227 {
17228   const ClutterAnimationInfo *info;
17229
17230   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17231
17232   info = _clutter_actor_get_animation_info_or_defaults (self);
17233
17234   if (info->cur_state != NULL)
17235     return info->cur_state->easing_delay;
17236
17237   return 0;
17238 }
17239
17240 /**
17241  * clutter_actor_get_transition:
17242  * @self: a #ClutterActor
17243  * @name: the name of the transition
17244  *
17245  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17246  * transition @name.
17247  *
17248  * Transitions created for animatable properties use the name of the
17249  * property itself, for instance the code below:
17250  *
17251  * |[
17252  *   clutter_actor_set_easing_duration (actor, 1000);
17253  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17254  *
17255  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17256  *   g_signal_connect (transition, "completed",
17257  *                     G_CALLBACK (on_transition_complete),
17258  *                     actor);
17259  * ]|
17260  *
17261  * will call the <function>on_transition_complete</function> callback when
17262  * the transition is complete.
17263  *
17264  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17265  *   was found to match the passed name; the returned instance is owned
17266  *   by Clutter and it should not be freed
17267  *
17268  * Since: 1.10
17269  */
17270 ClutterTransition *
17271 clutter_actor_get_transition (ClutterActor *self,
17272                               const char   *name)
17273 {
17274   TransitionClosure *clos;
17275   const ClutterAnimationInfo *info;
17276
17277   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17278   g_return_val_if_fail (name != NULL, NULL);
17279
17280   info = _clutter_actor_get_animation_info_or_defaults (self);
17281
17282   if (info->transitions == NULL)
17283     return NULL;
17284
17285   clos = g_hash_table_lookup (info->transitions, name);
17286   if (clos == NULL)
17287     return NULL;
17288
17289   return clos->transition;
17290 }
17291
17292 /**
17293  * clutter_actor_save_easing_state:
17294  * @self: a #ClutterActor
17295  *
17296  * Saves the current easing state for animatable properties, and creates
17297  * a new state with the default values for easing mode and duration.
17298  *
17299  * Since: 1.10
17300  */
17301 void
17302 clutter_actor_save_easing_state (ClutterActor *self)
17303 {
17304   ClutterAnimationInfo *info;
17305   AState new_state;
17306
17307   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17308
17309   info = _clutter_actor_get_animation_info (self);
17310
17311   if (info->states == NULL)
17312     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17313
17314   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17315   new_state.easing_duration = 250;
17316   new_state.easing_delay = 0;
17317
17318   g_array_append_val (info->states, new_state);
17319
17320   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17321 }
17322
17323 /**
17324  * clutter_actor_restore_easing_state:
17325  * @self: a #ClutterActor
17326  *
17327  * Restores the easing state as it was prior to a call to
17328  * clutter_actor_save_easing_state().
17329  *
17330  * Since: 1.10
17331  */
17332 void
17333 clutter_actor_restore_easing_state (ClutterActor *self)
17334 {
17335   ClutterAnimationInfo *info;
17336
17337   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17338
17339   info = _clutter_actor_get_animation_info (self);
17340
17341   if (info->states == NULL)
17342     {
17343       g_critical ("The function clutter_actor_restore_easing_state() has "
17344                   "called without a previous call to "
17345                   "clutter_actor_save_easing_state().");
17346       return;
17347     }
17348
17349   g_array_remove_index (info->states, info->states->len - 1);
17350   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17351 }
17352
17353 /**
17354  * clutter_actor_set_content:
17355  * @self: a #ClutterActor
17356  * @content: (allow-none): a #ClutterContent, or %NULL
17357  *
17358  * Sets the contents of a #ClutterActor.
17359  *
17360  * Since: 1.10
17361  */
17362 void
17363 clutter_actor_set_content (ClutterActor   *self,
17364                            ClutterContent *content)
17365 {
17366   ClutterActorPrivate *priv;
17367
17368   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17369   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17370
17371   priv = self->priv;
17372
17373   if (priv->content != NULL)
17374     {
17375       _clutter_content_detached (priv->content, self);
17376       g_object_unref (priv->content);
17377     }
17378
17379   priv->content = content;
17380
17381   if (priv->content != NULL)
17382     {
17383       g_object_ref (priv->content);
17384       _clutter_content_attached (priv->content, self);
17385     }
17386
17387   /* given that the content is always painted within the allocation,
17388    * we only need to queue a redraw here
17389    */
17390   clutter_actor_queue_redraw (self);
17391
17392   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17393
17394   /* if the content gravity is not resize-fill, and the new content has a
17395    * different preferred size than the previous one, then the content box
17396    * may have been changed. since we compute that lazily, we just notify
17397    * here, and let whomever watches :content-box do whatever they need to
17398    * do.
17399    */
17400   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17401     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17402 }
17403
17404 /**
17405  * clutter_actor_get_content:
17406  * @self: a #ClutterActor
17407  *
17408  * Retrieves the contents of @self.
17409  *
17410  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17411  *   or %NULL if none was set
17412  *
17413  * Since: 1.10
17414  */
17415 ClutterContent *
17416 clutter_actor_get_content (ClutterActor *self)
17417 {
17418   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17419
17420   return self->priv->content;
17421 }
17422
17423 /**
17424  * clutter_actor_set_content_gravity:
17425  * @self: a #ClutterActor
17426  * @gravity: the #ClutterContentGravity
17427  *
17428  * Sets the gravity of the #ClutterContent used by @self.
17429  *
17430  * See the description of the #ClutterActor:content-gravity property for
17431  * more information.
17432  *
17433  * Since: 1.10
17434  */
17435 void
17436 clutter_actor_set_content_gravity (ClutterActor *self,
17437                                    ClutterContentGravity  gravity)
17438 {
17439   ClutterActorPrivate *priv;
17440
17441   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17442
17443   priv = self->priv;
17444
17445   if (priv->content_gravity == gravity)
17446     return;
17447
17448   priv->content_gravity = gravity;
17449
17450   clutter_actor_queue_redraw (self);
17451
17452   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17453   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17454 }
17455
17456 /**
17457  * clutter_actor_get_content_gravity:
17458  * @self: a #ClutterActor
17459  *
17460  * Retrieves the content gravity as set using
17461  * clutter_actor_get_content_gravity().
17462  *
17463  * Return value: the content gravity
17464  *
17465  * Since: 1.10
17466  */
17467 ClutterContentGravity
17468 clutter_actor_get_content_gravity (ClutterActor *self)
17469 {
17470   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17471                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17472
17473   return self->priv->content_gravity;
17474 }
17475
17476 /**
17477  * clutter_actor_get_content_box:
17478  * @self: a #ClutterActor
17479  * @box: (out caller-allocates): the return location for the bounding
17480  *   box for the #ClutterContent
17481  *
17482  * Retrieves the bounding box for the #ClutterContent of @self.
17483  *
17484  * If no #ClutterContent is set for @self, or if @self has not been
17485  * allocated yet, then the result is undefined.
17486  *
17487  * The content box is guaranteed to be, at most, as big as the allocation
17488  * of the #ClutterActor.
17489  *
17490  * If the #ClutterContent used by the actor has a preferred size, then
17491  * it is possible to modify the content box by using the
17492  * #ClutterActor:content-gravity property.
17493  *
17494  * Since: 1.10
17495  */
17496 void
17497 clutter_actor_get_content_box (ClutterActor    *self,
17498                                ClutterActorBox *box)
17499 {
17500   ClutterActorPrivate *priv;
17501   gfloat content_w, content_h;
17502   gfloat alloc_w, alloc_h;
17503
17504   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17505   g_return_if_fail (box != NULL);
17506
17507   priv = self->priv;
17508
17509   if (!clutter_actor_has_allocation (self))
17510     return;
17511
17512   if (priv->content == NULL)
17513     return;
17514
17515   *box = priv->allocation;
17516
17517   /* no need to do any more work */
17518   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17519     return;
17520
17521   /* if the content does not have a preferred size then there is
17522    * no point in computing the content box
17523    */
17524   if (!_clutter_content_get_preferred_size (priv->content,
17525                                             &content_w,
17526                                             &content_h))
17527     return;
17528
17529   clutter_actor_box_get_size (&priv->allocation, &alloc_w, &alloc_h);
17530
17531   switch (priv->content_gravity)
17532     {
17533     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17534       box->x2 = box->x1 + MIN (content_w, alloc_w);
17535       box->y2 = box->y1 + MIN (content_h, alloc_h);
17536       break;
17537
17538     case CLUTTER_CONTENT_GRAVITY_TOP:
17539       if (alloc_w > content_w)
17540         {
17541           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17542           box->x2 = box->x1 + content_w;
17543         }
17544       box->y2 = box->y1 + MIN (content_h, alloc_h);
17545       break;
17546
17547     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17548       if (alloc_w > content_w)
17549         {
17550           box->x1 += (alloc_w - content_w);
17551           box->x2 = box->x1 + content_w;
17552         }
17553       box->y2 = box->y1 + MIN (content_h, alloc_h);
17554       break;
17555
17556     case CLUTTER_CONTENT_GRAVITY_LEFT:
17557       box->x2 = box->x1 + MIN (content_w, alloc_w);
17558       if (alloc_h > content_h)
17559         {
17560           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17561           box->y2 = box->y1 + content_h;
17562         }
17563       break;
17564
17565     case CLUTTER_CONTENT_GRAVITY_CENTER:
17566       if (alloc_w > content_w)
17567         {
17568           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17569           box->x2 = box->x1 + content_w;
17570         }
17571       if (alloc_h > content_h)
17572         {
17573           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17574           box->y2 = box->y1 + content_h;
17575         }
17576       break;
17577
17578     case CLUTTER_CONTENT_GRAVITY_RIGHT:
17579       if (alloc_w > content_w)
17580         {
17581           box->x1 += (alloc_w - content_w);
17582           box->x2 = box->x1 + content_w;
17583         }
17584       if (alloc_h > content_h)
17585         {
17586           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17587           box->y2 = box->y1 + content_h;
17588         }
17589       break;
17590
17591     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17592       box->x2 = box->x1 + MIN (content_w, alloc_w);
17593       if (alloc_h > content_h)
17594         {
17595           box->y1 += (alloc_h - content_h);
17596           box->y2 = box->y1 + content_h;
17597         }
17598       break;
17599
17600     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17601       if (alloc_w > content_w)
17602         {
17603           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17604           box->x2 = box->x1 + content_w;
17605         }
17606       if (alloc_h > content_h)
17607         {
17608           box->y1 += (alloc_h - content_h);
17609           box->y2 = box->y1 + content_h;
17610         }
17611       break;
17612
17613     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17614       if (alloc_w > content_w)
17615         {
17616           box->x1 += (alloc_w - content_w);
17617           box->x2 = box->x1 + content_w;
17618         }
17619       if (alloc_h > content_h)
17620         {
17621           box->y1 += (alloc_h - content_h);
17622           box->y2 = box->y1 + content_h;
17623         }
17624       break;
17625
17626     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17627       g_assert_not_reached ();
17628       break;
17629
17630     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17631       if (content_w >= content_h && content_h > 0)
17632         {
17633           double ratio = content_w / content_h;
17634
17635           box->x2 = box->x1 + alloc_w;
17636
17637           box->y1 += ceilf ((alloc_h - (alloc_h / ratio)) / 2.0);
17638           box->y2 = box->y1 + (alloc_h / ratio);
17639         }
17640       else if (content_h > content_w && content_w > 0)
17641         {
17642           double ratio = content_h / content_w;
17643
17644           box->x1 += ceilf ((alloc_w - (alloc_w / ratio)) / 2.0);
17645           box->x2 = box->x2 + (alloc_w / ratio);
17646
17647           box->y2 = box->x1 + alloc_h;
17648         }
17649       break;
17650     }
17651 }