docs: Update the actor example image
[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 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
244 /**
245  * CLUTTER_ACTOR_IS_MAPPED:
246  * @a: a #ClutterActor
247  *
248  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
249  *
250  * The mapped state is set when the actor is visible and all its parents up
251  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
252  *
253  * This check can be used to see if an actor is going to be painted, as only
254  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
255  *
256  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
257  * not be checked directly; instead, the recommended usage is to connect a
258  * handler on the #GObject::notify signal for the #ClutterActor:mapped
259  * property of #ClutterActor, and check the presence of
260  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
261  *
262  * It is also important to note that Clutter may delay the changes of
263  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
264  * limitations, or during the reparenting of an actor, to optimize
265  * unnecessary (and potentially expensive) state changes.
266  *
267  * Since: 0.2
268  */
269
270 /**
271  * CLUTTER_ACTOR_IS_REALIZED:
272  * @a: a #ClutterActor
273  *
274  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
275  *
276  * The realized state has an actor-dependant interpretation. If an
277  * actor wants to delay allocating resources until it is attached to a
278  * stage, it may use the realize state to do so. However it is
279  * perfectly acceptable for an actor to allocate Cogl resources before
280  * being realized because there is only one drawing context used by Clutter
281  * so any resources will work on any stage.  If an actor is mapped it
282  * must also be realized, but an actor can be realized and unmapped
283  * (this is so hiding an actor temporarily doesn't do an expensive
284  * unrealize/realize).
285  *
286  * To be realized an actor must be inside a stage, and all its parents
287  * must be realized.
288  *
289  * Since: 0.2
290  */
291
292 /**
293  * CLUTTER_ACTOR_IS_VISIBLE:
294  * @a: a #ClutterActor
295  *
296  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
297  * Equivalent to the ClutterActor::visible object property.
298  *
299  * Note that an actor is only painted onscreen if it's mapped, which
300  * means it's visible, and all its parents are visible, and one of the
301  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
302  *
303  * Since: 0.2
304  */
305
306 /**
307  * CLUTTER_ACTOR_IS_REACTIVE:
308  * @a: a #ClutterActor
309  *
310  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
311  *
312  * Only reactive actors will receive event-related signals.
313  *
314  * Since: 0.6
315  */
316
317 #ifdef HAVE_CONFIG_H
318 #include "config.h"
319 #endif
320
321 #include <math.h>
322
323 #include "cogl/cogl.h"
324
325 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
326 #define CLUTTER_ENABLE_EXPERIMENTAL_API
327
328 #include "clutter-actor-private.h"
329
330 #include "clutter-action.h"
331 #include "clutter-actor-meta-private.h"
332 #include "clutter-animatable.h"
333 #include "clutter-color-static.h"
334 #include "clutter-color.h"
335 #include "clutter-constraint.h"
336 #include "clutter-container.h"
337 #include "clutter-debug.h"
338 #include "clutter-effect-private.h"
339 #include "clutter-enum-types.h"
340 #include "clutter-fixed-layout.h"
341 #include "clutter-flatten-effect.h"
342 #include "clutter-interval.h"
343 #include "clutter-main.h"
344 #include "clutter-marshal.h"
345 #include "clutter-paint-volume-private.h"
346 #include "clutter-private.h"
347 #include "clutter-profile.h"
348 #include "clutter-scriptable.h"
349 #include "clutter-script-private.h"
350 #include "clutter-stage-private.h"
351 #include "clutter-units.h"
352
353 #include "deprecated/clutter-behaviour.h"
354 #include "deprecated/clutter-container.h"
355
356 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
357 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
358
359 /* Internal enum used to control mapped state update.  This is a hint
360  * which indicates when to do something other than just enforce
361  * invariants.
362  */
363 typedef enum {
364   MAP_STATE_CHECK,           /* just enforce invariants. */
365   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
366                               * used when about to unparent.
367                               */
368   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
369                               * used to set mapped on toplevels.
370                               */
371   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
372                               * used just before unmapping parent.
373                               */
374 } MapStateChange;
375
376 /* 3 entries should be a good compromise, few layout managers
377  * will ask for 3 different preferred size in each allocation cycle */
378 #define N_CACHED_SIZE_REQUESTS 3
379
380 struct _ClutterActorPrivate
381 {
382   /* request mode */
383   ClutterRequestMode request_mode;
384
385   /* our cached size requests for different width / height */
386   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
387   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
388
389   /* An age of 0 means the entry is not set */
390   guint cached_height_age;
391   guint cached_width_age;
392
393   /* the bounding box of the actor, relative to the parent's
394    * allocation
395    */
396   ClutterActorBox allocation;
397   ClutterAllocationFlags allocation_flags;
398
399   /* depth */
400   gfloat z;
401
402   /* clip, in actor coordinates */
403   cairo_rectangle_t clip;
404
405   /* the cached transformation matrix; see apply_transform() */
406   CoglMatrix transform;
407
408   guint8 opacity;
409   gint opacity_override;
410
411   ClutterOffscreenRedirect offscreen_redirect;
412
413   /* This is an internal effect used to implement the
414      offscreen-redirect property */
415   ClutterEffect *flatten_effect;
416
417   /* scene graph */
418   ClutterActor *parent;
419   ClutterActor *prev_sibling;
420   ClutterActor *next_sibling;
421   ClutterActor *first_child;
422   ClutterActor *last_child;
423
424   gint n_children;
425
426   /* tracks whenever the children of an actor are changed; the
427    * age is incremented by 1 whenever an actor is added or
428    * removed. the age is not incremented when the first or the
429    * last child pointers are changed, or when grandchildren of
430    * an actor are changed.
431    */
432   gint age;
433
434   gchar *name; /* a non-unique name, used for debugging */
435   guint32 id; /* unique id, used for backward compatibility */
436
437   gint32 pick_id; /* per-stage unique id, used for picking */
438
439   /* a back-pointer to the Pango context that we can use
440    * to create pre-configured PangoLayout
441    */
442   PangoContext *pango_context;
443
444   /* the text direction configured for this child - either by
445    * application code, or by the actor's parent
446    */
447   ClutterTextDirection text_direction;
448
449   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
450   gint internal_child;
451
452   /* meta classes */
453   ClutterMetaGroup *actions;
454   ClutterMetaGroup *constraints;
455   ClutterMetaGroup *effects;
456
457   /* delegate object used to allocate the children of this actor */
458   ClutterLayoutManager *layout_manager;
459
460   /* used when painting, to update the paint volume */
461   ClutterEffect *current_effect;
462
463   /* This is used to store an effect which needs to be redrawn. A
464      redraw can be queued to start from a particular effect. This is
465      used by parametrised effects that can cache an image of the
466      actor. If a parameter of the effect changes then it only needs to
467      redraw the cached image, not the actual actor. The pointer is
468      only valid if is_dirty == TRUE. If the pointer is NULL then the
469      whole actor is dirty. */
470   ClutterEffect *effect_to_redraw;
471
472   /* This is used when painting effects to implement the
473      clutter_actor_continue_paint() function. It points to the node in
474      the list of effects that is next in the chain */
475   const GList *next_effect_to_paint;
476
477   ClutterPaintVolume paint_volume;
478
479   /* NB: This volume isn't relative to this actor, it is in eye
480    * coordinates so that it can remain valid after the actor changes.
481    */
482   ClutterPaintVolume last_paint_volume;
483
484   ClutterStageQueueRedrawEntry *queue_redraw_entry;
485
486   ClutterColor bg_color;
487
488   /* bitfields */
489
490   /* fixed position and sizes */
491   guint position_set                : 1;
492   guint min_width_set               : 1;
493   guint min_height_set              : 1;
494   guint natural_width_set           : 1;
495   guint natural_height_set          : 1;
496   /* cached request is invalid (implies allocation is too) */
497   guint needs_width_request         : 1;
498   /* cached request is invalid (implies allocation is too) */
499   guint needs_height_request        : 1;
500   /* cached allocation is invalid (request has changed, probably) */
501   guint needs_allocation            : 1;
502   guint show_on_set_parent          : 1;
503   guint has_clip                    : 1;
504   guint clip_to_allocation          : 1;
505   guint enable_model_view_transform : 1;
506   guint enable_paint_unmapped       : 1;
507   guint has_pointer                 : 1;
508   guint propagated_one_redraw       : 1;
509   guint paint_volume_valid          : 1;
510   guint last_paint_volume_valid     : 1;
511   guint in_clone_paint              : 1;
512   guint transform_valid             : 1;
513   /* This is TRUE if anything has queued a redraw since we were last
514      painted. In this case effect_to_redraw will point to an effect
515      the redraw was queued from or it will be NULL if the redraw was
516      queued without an effect. */
517   guint is_dirty                    : 1;
518   guint bg_color_set                : 1;
519 };
520
521 enum
522 {
523   PROP_0,
524
525   PROP_NAME,
526
527   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
528    * when set they force a size request, when gotten they
529    * get the allocation if the allocation is valid, and the
530    * request otherwise
531    */
532   PROP_X,
533   PROP_Y,
534   PROP_WIDTH,
535   PROP_HEIGHT,
536
537   /* Then the rest of these size-related properties are the "actual"
538    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
539    */
540   PROP_FIXED_X,
541   PROP_FIXED_Y,
542
543   PROP_FIXED_POSITION_SET,
544
545   PROP_MIN_WIDTH,
546   PROP_MIN_WIDTH_SET,
547
548   PROP_MIN_HEIGHT,
549   PROP_MIN_HEIGHT_SET,
550
551   PROP_NATURAL_WIDTH,
552   PROP_NATURAL_WIDTH_SET,
553
554   PROP_NATURAL_HEIGHT,
555   PROP_NATURAL_HEIGHT_SET,
556
557   PROP_REQUEST_MODE,
558
559   /* Allocation properties are read-only */
560   PROP_ALLOCATION,
561
562   PROP_DEPTH,
563
564   PROP_CLIP,
565   PROP_HAS_CLIP,
566   PROP_CLIP_TO_ALLOCATION,
567
568   PROP_OPACITY,
569
570   PROP_OFFSCREEN_REDIRECT,
571
572   PROP_VISIBLE,
573   PROP_MAPPED,
574   PROP_REALIZED,
575   PROP_REACTIVE,
576
577   PROP_SCALE_X,
578   PROP_SCALE_Y,
579   PROP_SCALE_CENTER_X,
580   PROP_SCALE_CENTER_Y,
581   PROP_SCALE_GRAVITY,
582
583   PROP_ROTATION_ANGLE_X,
584   PROP_ROTATION_ANGLE_Y,
585   PROP_ROTATION_ANGLE_Z,
586   PROP_ROTATION_CENTER_X,
587   PROP_ROTATION_CENTER_Y,
588   PROP_ROTATION_CENTER_Z,
589   /* This property only makes sense for the z rotation because the
590      others would depend on the actor having a size along the
591      z-axis */
592   PROP_ROTATION_CENTER_Z_GRAVITY,
593
594   PROP_ANCHOR_X,
595   PROP_ANCHOR_Y,
596   PROP_ANCHOR_GRAVITY,
597
598   PROP_SHOW_ON_SET_PARENT,
599
600   PROP_TEXT_DIRECTION,
601   PROP_HAS_POINTER,
602
603   PROP_ACTIONS,
604   PROP_CONSTRAINTS,
605   PROP_EFFECT,
606
607   PROP_LAYOUT_MANAGER,
608
609   PROP_X_ALIGN,
610   PROP_Y_ALIGN,
611   PROP_MARGIN_TOP,
612   PROP_MARGIN_BOTTOM,
613   PROP_MARGIN_LEFT,
614   PROP_MARGIN_RIGHT,
615
616   PROP_BACKGROUND_COLOR,
617   PROP_BACKGROUND_COLOR_SET,
618
619   PROP_FIRST_CHILD,
620   PROP_LAST_CHILD,
621
622   PROP_LAST
623 };
624
625 static GParamSpec *obj_props[PROP_LAST];
626
627 enum
628 {
629   SHOW,
630   HIDE,
631   DESTROY,
632   PARENT_SET,
633   KEY_FOCUS_IN,
634   KEY_FOCUS_OUT,
635   PAINT,
636   PICK,
637   REALIZE,
638   UNREALIZE,
639   QUEUE_REDRAW,
640   QUEUE_RELAYOUT,
641   EVENT,
642   CAPTURED_EVENT,
643   BUTTON_PRESS_EVENT,
644   BUTTON_RELEASE_EVENT,
645   SCROLL_EVENT,
646   KEY_PRESS_EVENT,
647   KEY_RELEASE_EVENT,
648   MOTION_EVENT,
649   ENTER_EVENT,
650   LEAVE_EVENT,
651   ALLOCATION_CHANGED,
652
653   LAST_SIGNAL
654 };
655
656 static guint actor_signals[LAST_SIGNAL] = { 0, };
657
658 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
659 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
660 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
661 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
662
663 /* These setters are all static for now, maybe they should be in the
664  * public API, but they are perhaps obscure enough to leave only as
665  * properties
666  */
667 static void clutter_actor_set_min_width          (ClutterActor *self,
668                                                   gfloat        min_width);
669 static void clutter_actor_set_min_height         (ClutterActor *self,
670                                                   gfloat        min_height);
671 static void clutter_actor_set_natural_width      (ClutterActor *self,
672                                                   gfloat        natural_width);
673 static void clutter_actor_set_natural_height     (ClutterActor *self,
674                                                   gfloat        natural_height);
675 static void clutter_actor_set_min_width_set      (ClutterActor *self,
676                                                   gboolean      use_min_width);
677 static void clutter_actor_set_min_height_set     (ClutterActor *self,
678                                                   gboolean      use_min_height);
679 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
680                                                   gboolean  use_natural_width);
681 static void clutter_actor_set_natural_height_set (ClutterActor *self,
682                                                   gboolean  use_natural_height);
683 static void clutter_actor_update_map_state       (ClutterActor  *self,
684                                                   MapStateChange change);
685 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
686
687 /* Helper routines for managing anchor coords */
688 static void clutter_anchor_coord_get_units (ClutterActor      *self,
689                                             const AnchorCoord *coord,
690                                             gfloat            *x,
691                                             gfloat            *y,
692                                             gfloat            *z);
693 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
694                                             gfloat             x,
695                                             gfloat             y,
696                                             gfloat             z);
697
698 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
699 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
700                                                         ClutterGravity     gravity);
701
702 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
703
704 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
705
706 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
707                                                                ClutterActor *ancestor,
708                                                                CoglMatrix *matrix);
709
710 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
711
712 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
713
714 static void on_layout_manager_changed (ClutterLayoutManager *manager,
715                                        ClutterActor         *self);
716
717 /* Helper macro which translates by the anchor coord, applies the
718    given transformation and then translates back */
719 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
720   gfloat _tx, _ty, _tz;                                                \
721   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
722   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
723   { _transform; }                                                      \
724   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
725
726 static GQuark quark_shader_data = 0;
727 static GQuark quark_actor_layout_info = 0;
728 static GQuark quark_actor_transform_info = 0;
729
730 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
731                          clutter_actor,
732                          G_TYPE_INITIALLY_UNOWNED,
733                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
734                                                 clutter_container_iface_init)
735                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
736                                                 clutter_scriptable_iface_init)
737                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
738                                                 clutter_animatable_iface_init)
739                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
740                                                 atk_implementor_iface_init));
741
742 /*< private >
743  * clutter_actor_get_debug_name:
744  * @actor: a #ClutterActor
745  *
746  * Retrieves a printable name of @actor for debugging messages
747  *
748  * Return value: a string with a printable name
749  */
750 const gchar *
751 _clutter_actor_get_debug_name (ClutterActor *actor)
752 {
753   return actor->priv->name != NULL ? actor->priv->name
754                                    : G_OBJECT_TYPE_NAME (actor);
755 }
756
757 #ifdef CLUTTER_ENABLE_DEBUG
758 /* XXX - this is for debugging only, remove once working (or leave
759  * in only in some debug mode). Should leave it for a little while
760  * until we're confident in the new map/realize/visible handling.
761  */
762 static inline void
763 clutter_actor_verify_map_state (ClutterActor *self)
764 {
765   ClutterActorPrivate *priv = self->priv;
766
767   if (CLUTTER_ACTOR_IS_REALIZED (self))
768     {
769       /* all bets are off during reparent when we're potentially realized,
770        * but should not be according to invariants
771        */
772       if (!CLUTTER_ACTOR_IN_REPARENT (self))
773         {
774           if (priv->parent == NULL)
775             {
776               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
777                 {
778                 }
779               else
780                 g_warning ("Realized non-toplevel actor '%s' should "
781                            "have a parent",
782                            _clutter_actor_get_debug_name (self));
783             }
784           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
785             {
786               g_warning ("Realized actor %s has an unrealized parent %s",
787                          _clutter_actor_get_debug_name (self),
788                          _clutter_actor_get_debug_name (priv->parent));
789             }
790         }
791     }
792
793   if (CLUTTER_ACTOR_IS_MAPPED (self))
794     {
795       if (!CLUTTER_ACTOR_IS_REALIZED (self))
796         g_warning ("Actor '%s' is mapped but not realized",
797                    _clutter_actor_get_debug_name (self));
798
799       /* remaining bets are off during reparent when we're potentially
800        * mapped, but should not be according to invariants
801        */
802       if (!CLUTTER_ACTOR_IN_REPARENT (self))
803         {
804           if (priv->parent == NULL)
805             {
806               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
807                 {
808                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
809                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
810                     {
811                       g_warning ("Toplevel actor '%s' is mapped "
812                                  "but not visible",
813                                  _clutter_actor_get_debug_name (self));
814                     }
815                 }
816               else
817                 {
818                   g_warning ("Mapped actor '%s' should have a parent",
819                              _clutter_actor_get_debug_name (self));
820                 }
821             }
822           else
823             {
824               ClutterActor *iter = self;
825
826               /* check for the enable_paint_unmapped flag on the actor
827                * and parents; if the flag is enabled at any point of this
828                * branch of the scene graph then all the later checks
829                * become pointless
830                */
831               while (iter != NULL)
832                 {
833                   if (iter->priv->enable_paint_unmapped)
834                     return;
835
836                   iter = iter->priv->parent;
837                 }
838
839               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
840                 {
841                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
842                              "is not visible",
843                              _clutter_actor_get_debug_name (self),
844                              _clutter_actor_get_debug_name (priv->parent));
845                 }
846
847               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
848                 {
849                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
850                              "is not realized",
851                              _clutter_actor_get_debug_name (self),
852                              _clutter_actor_get_debug_name (priv->parent));
853                 }
854
855               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
856                 {
857                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
858                     g_warning ("Actor '%s' is mapped but its non-toplevel "
859                                "parent '%s' is not mapped",
860                                _clutter_actor_get_debug_name (self),
861                                _clutter_actor_get_debug_name (priv->parent));
862                 }
863             }
864         }
865     }
866 }
867
868 #endif /* CLUTTER_ENABLE_DEBUG */
869
870 static void
871 clutter_actor_set_mapped (ClutterActor *self,
872                           gboolean      mapped)
873 {
874   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
875     return;
876
877   if (mapped)
878     {
879       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
880       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
881     }
882   else
883     {
884       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
885       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
886     }
887 }
888
889 /* this function updates the mapped and realized states according to
890  * invariants, in the appropriate order.
891  */
892 static void
893 clutter_actor_update_map_state (ClutterActor  *self,
894                                 MapStateChange change)
895 {
896   gboolean was_mapped;
897
898   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
899
900   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
901     {
902       /* the mapped flag on top-level actors must be set by the
903        * per-backend implementation because it might be asynchronous.
904        *
905        * That is, the MAPPED flag on toplevels currently tracks the X
906        * server mapped-ness of the window, while the expected behavior
907        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
908        * This creates some weird complexity by breaking the invariant
909        * that if we're visible and all ancestors shown then we are
910        * also mapped - instead, we are mapped if all ancestors
911        * _possibly excepting_ the stage are mapped. The stage
912        * will map/unmap for example when it is minimized or
913        * moved to another workspace.
914        *
915        * So, the only invariant on the stage is that if visible it
916        * should be realized, and that it has to be visible to be
917        * mapped.
918        */
919       if (CLUTTER_ACTOR_IS_VISIBLE (self))
920         clutter_actor_realize (self);
921
922       switch (change)
923         {
924         case MAP_STATE_CHECK:
925           break;
926
927         case MAP_STATE_MAKE_MAPPED:
928           g_assert (!was_mapped);
929           clutter_actor_set_mapped (self, TRUE);
930           break;
931
932         case MAP_STATE_MAKE_UNMAPPED:
933           g_assert (was_mapped);
934           clutter_actor_set_mapped (self, FALSE);
935           break;
936
937         case MAP_STATE_MAKE_UNREALIZED:
938           /* we only use MAKE_UNREALIZED in unparent,
939            * and unparenting a stage isn't possible.
940            * If someone wants to just unrealize a stage
941            * then clutter_actor_unrealize() doesn't
942            * go through this codepath.
943            */
944           g_warning ("Trying to force unrealize stage is not allowed");
945           break;
946         }
947
948       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
949           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
950           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
951         {
952           g_warning ("Clutter toplevel of type '%s' is not visible, but "
953                      "it is somehow still mapped",
954                      _clutter_actor_get_debug_name (self));
955         }
956     }
957   else
958     {
959       ClutterActorPrivate *priv = self->priv;
960       ClutterActor *parent = priv->parent;
961       gboolean should_be_mapped;
962       gboolean may_be_realized;
963       gboolean must_be_realized;
964
965       should_be_mapped = FALSE;
966       may_be_realized = TRUE;
967       must_be_realized = FALSE;
968
969       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
970         {
971           may_be_realized = FALSE;
972         }
973       else
974         {
975           /* Maintain invariant that if parent is mapped, and we are
976            * visible, then we are mapped ...  unless parent is a
977            * stage, in which case we map regardless of parent's map
978            * state but do require stage to be visible and realized.
979            *
980            * If parent is realized, that does not force us to be
981            * realized; but if parent is unrealized, that does force
982            * us to be unrealized.
983            *
984            * The reason we don't force children to realize with
985            * parents is _clutter_actor_rerealize(); if we require that
986            * a realized parent means children are realized, then to
987            * unrealize an actor we would have to unrealize its
988            * parents, which would end up meaning unrealizing and
989            * hiding the entire stage. So we allow unrealizing a
990            * child (as long as that child is not mapped) while that
991            * child still has a realized parent.
992            *
993            * Also, if we unrealize from leaf nodes to root, and
994            * realize from root to leaf, the invariants are never
995            * violated if we allow children to be unrealized
996            * while parents are realized.
997            *
998            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
999            * to force us to unmap, even though parent is still
1000            * mapped. This is because we're unmapping from leaf nodes
1001            * up to root nodes.
1002            */
1003           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1004               change != MAP_STATE_MAKE_UNMAPPED)
1005             {
1006               gboolean parent_is_visible_realized_toplevel;
1007
1008               parent_is_visible_realized_toplevel =
1009                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1010                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1011                  CLUTTER_ACTOR_IS_REALIZED (parent));
1012
1013               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1014                   parent_is_visible_realized_toplevel)
1015                 {
1016                   must_be_realized = TRUE;
1017                   should_be_mapped = TRUE;
1018                 }
1019             }
1020
1021           /* if the actor has been set to be painted even if unmapped
1022            * then we should map it and check for realization as well;
1023            * this is an override for the branch of the scene graph
1024            * which begins with this node
1025            */
1026           if (priv->enable_paint_unmapped)
1027             {
1028               if (priv->parent == NULL)
1029                 g_warning ("Attempting to map an unparented actor '%s'",
1030                            _clutter_actor_get_debug_name (self));
1031
1032               should_be_mapped = TRUE;
1033               must_be_realized = TRUE;
1034             }
1035
1036           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1037             may_be_realized = FALSE;
1038         }
1039
1040       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1041         {
1042           if (parent == NULL)
1043             g_warning ("Attempting to map a child that does not "
1044                        "meet the necessary invariants: the actor '%s' "
1045                        "has no parent",
1046                        _clutter_actor_get_debug_name (self));
1047           else
1048             g_warning ("Attempting to map a child that does not "
1049                        "meet the necessary invariants: the actor '%s' "
1050                        "is parented to an unmapped actor '%s'",
1051                        _clutter_actor_get_debug_name (self),
1052                        _clutter_actor_get_debug_name (priv->parent));
1053         }
1054
1055       /* If in reparent, we temporarily suspend unmap and unrealize.
1056        *
1057        * We want to go in the order "realize, map" and "unmap, unrealize"
1058        */
1059
1060       /* Unmap */
1061       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1062         clutter_actor_set_mapped (self, FALSE);
1063
1064       /* Realize */
1065       if (must_be_realized)
1066         clutter_actor_realize (self);
1067
1068       /* if we must be realized then we may be, presumably */
1069       g_assert (!(must_be_realized && !may_be_realized));
1070
1071       /* Unrealize */
1072       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1073         clutter_actor_unrealize_not_hiding (self);
1074
1075       /* Map */
1076       if (should_be_mapped)
1077         {
1078           if (!must_be_realized)
1079             g_warning ("Somehow we think actor '%s' should be mapped but "
1080                        "not realized, which isn't allowed",
1081                        _clutter_actor_get_debug_name (self));
1082
1083           /* realization is allowed to fail (though I don't know what
1084            * an app is supposed to do about that - shouldn't it just
1085            * be a g_error? anyway, we have to avoid mapping if this
1086            * happens)
1087            */
1088           if (CLUTTER_ACTOR_IS_REALIZED (self))
1089             clutter_actor_set_mapped (self, TRUE);
1090         }
1091     }
1092
1093 #ifdef CLUTTER_ENABLE_DEBUG
1094   /* check all invariants were kept */
1095   clutter_actor_verify_map_state (self);
1096 #endif
1097 }
1098
1099 static void
1100 clutter_actor_real_map (ClutterActor *self)
1101 {
1102   ClutterActorPrivate *priv = self->priv;
1103   ClutterActor *stage, *iter;
1104
1105   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1106
1107   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1108                 _clutter_actor_get_debug_name (self));
1109
1110   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1111
1112   stage = _clutter_actor_get_stage_internal (self);
1113   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1114
1115   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1116                 priv->pick_id,
1117                 _clutter_actor_get_debug_name (self));
1118
1119   /* notify on parent mapped before potentially mapping
1120    * children, so apps see a top-down notification.
1121    */
1122   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1123
1124   for (iter = self->priv->first_child;
1125        iter != NULL;
1126        iter = iter->priv->next_sibling)
1127     {
1128       clutter_actor_map (iter);
1129     }
1130 }
1131
1132 /**
1133  * clutter_actor_map:
1134  * @self: A #ClutterActor
1135  *
1136  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1137  * and realizes its children if they are visible. Does nothing if the
1138  * actor is not visible.
1139  *
1140  * Calling this function is strongly disencouraged: the default
1141  * implementation of #ClutterActorClass.map() will map all the children
1142  * of an actor when mapping its parent.
1143  *
1144  * When overriding map, it is mandatory to chain up to the parent
1145  * implementation.
1146  *
1147  * Since: 1.0
1148  */
1149 void
1150 clutter_actor_map (ClutterActor *self)
1151 {
1152   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1153
1154   if (CLUTTER_ACTOR_IS_MAPPED (self))
1155     return;
1156
1157   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1158     return;
1159
1160   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1161 }
1162
1163 static void
1164 clutter_actor_real_unmap (ClutterActor *self)
1165 {
1166   ClutterActorPrivate *priv = self->priv;
1167   ClutterActor *iter;
1168
1169   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1170
1171   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1172                 _clutter_actor_get_debug_name (self));
1173
1174   for (iter = self->priv->first_child;
1175        iter != NULL;
1176        iter = iter->priv->next_sibling)
1177     {
1178       clutter_actor_unmap (iter);
1179     }
1180
1181   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1182
1183   /* clear the contents of the last paint volume, so that hiding + moving +
1184    * showing will not result in the wrong area being repainted
1185    */
1186   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1187   priv->last_paint_volume_valid = TRUE;
1188
1189   /* notify on parent mapped after potentially unmapping
1190    * children, so apps see a bottom-up notification.
1191    */
1192   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1193
1194   /* relinquish keyboard focus if we were unmapped while owning it */
1195   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1196     {
1197       ClutterStage *stage;
1198
1199       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1200
1201       if (stage != NULL)
1202         _clutter_stage_release_pick_id (stage, priv->pick_id);
1203
1204       priv->pick_id = -1;
1205
1206       if (stage != NULL &&
1207           clutter_stage_get_key_focus (stage) == self)
1208         {
1209           clutter_stage_set_key_focus (stage, NULL);
1210         }
1211     }
1212 }
1213
1214 /**
1215  * clutter_actor_unmap:
1216  * @self: A #ClutterActor
1217  *
1218  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1219  * unmaps its children if they were mapped.
1220  *
1221  * Calling this function is not encouraged: the default #ClutterActor
1222  * implementation of #ClutterActorClass.unmap() will also unmap any
1223  * eventual children by default when their parent is unmapped.
1224  *
1225  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1226  * chain up to the parent implementation.
1227  *
1228  * <note>It is important to note that the implementation of the
1229  * #ClutterActorClass.unmap() virtual function may be called after
1230  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1231  * implementation, but it is guaranteed to be called before the
1232  * #GObjectClass.finalize() implementation.</note>
1233  *
1234  * Since: 1.0
1235  */
1236 void
1237 clutter_actor_unmap (ClutterActor *self)
1238 {
1239   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1240
1241   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1242     return;
1243
1244   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1245 }
1246
1247 static void
1248 clutter_actor_real_show (ClutterActor *self)
1249 {
1250   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1251     {
1252       ClutterActorPrivate *priv = self->priv;
1253
1254       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1255
1256       /* we notify on the "visible" flag in the clutter_actor_show()
1257        * wrapper so the entire show signal emission completes first
1258        * (?)
1259        */
1260       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1261
1262       /* we queue a relayout unless the actor is inside a
1263        * container that explicitly told us not to
1264        */
1265       if (priv->parent != NULL &&
1266           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1267         {
1268           /* While an actor is hidden the parent may not have
1269            * allocated/requested so we need to start from scratch
1270            * and avoid the short-circuiting in
1271            * clutter_actor_queue_relayout().
1272            */
1273           priv->needs_width_request  = FALSE;
1274           priv->needs_height_request = FALSE;
1275           priv->needs_allocation     = FALSE;
1276           clutter_actor_queue_relayout (self);
1277         }
1278     }
1279 }
1280
1281 static inline void
1282 set_show_on_set_parent (ClutterActor *self,
1283                         gboolean      set_show)
1284 {
1285   ClutterActorPrivate *priv = self->priv;
1286
1287   set_show = !!set_show;
1288
1289   if (priv->show_on_set_parent == set_show)
1290     return;
1291
1292   if (priv->parent == NULL)
1293     {
1294       priv->show_on_set_parent = set_show;
1295       g_object_notify_by_pspec (G_OBJECT (self),
1296                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1297     }
1298 }
1299
1300 /**
1301  * clutter_actor_show:
1302  * @self: A #ClutterActor
1303  *
1304  * Flags an actor to be displayed. An actor that isn't shown will not
1305  * be rendered on the stage.
1306  *
1307  * Actors are visible by default.
1308  *
1309  * If this function is called on an actor without a parent, the
1310  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1311  * effect.
1312  */
1313 void
1314 clutter_actor_show (ClutterActor *self)
1315 {
1316   ClutterActorPrivate *priv;
1317
1318   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1319
1320   /* simple optimization */
1321   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1322     {
1323       /* we still need to set the :show-on-set-parent property, in
1324        * case show() is called on an unparented actor
1325        */
1326       set_show_on_set_parent (self, TRUE);
1327       return;
1328     }
1329
1330 #ifdef CLUTTER_ENABLE_DEBUG
1331   clutter_actor_verify_map_state (self);
1332 #endif
1333
1334   priv = self->priv;
1335
1336   g_object_freeze_notify (G_OBJECT (self));
1337
1338   set_show_on_set_parent (self, TRUE);
1339
1340   g_signal_emit (self, actor_signals[SHOW], 0);
1341   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1342
1343   if (priv->parent != NULL)
1344     clutter_actor_queue_redraw (priv->parent);
1345
1346   g_object_thaw_notify (G_OBJECT (self));
1347 }
1348
1349 /**
1350  * clutter_actor_show_all:
1351  * @self: a #ClutterActor
1352  *
1353  * Calls clutter_actor_show() on all children of an actor (if any).
1354  *
1355  * Since: 0.2
1356  *
1357  * Deprecated: 1.10: Actors are visible by default
1358  */
1359 void
1360 clutter_actor_show_all (ClutterActor *self)
1361 {
1362   ClutterActorClass *klass;
1363
1364   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1365
1366   klass = CLUTTER_ACTOR_GET_CLASS (self);
1367   if (klass->show_all)
1368     klass->show_all (self);
1369 }
1370
1371 static void
1372 clutter_actor_real_hide (ClutterActor *self)
1373 {
1374   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1375     {
1376       ClutterActorPrivate *priv = self->priv;
1377
1378       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1379
1380       /* we notify on the "visible" flag in the clutter_actor_hide()
1381        * wrapper so the entire hide signal emission completes first
1382        * (?)
1383        */
1384       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1385
1386       /* we queue a relayout unless the actor is inside a
1387        * container that explicitly told us not to
1388        */
1389       if (priv->parent != NULL &&
1390           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1391         clutter_actor_queue_relayout (priv->parent);
1392     }
1393 }
1394
1395 /**
1396  * clutter_actor_hide:
1397  * @self: A #ClutterActor
1398  *
1399  * Flags an actor to be hidden. A hidden actor will not be
1400  * rendered on the stage.
1401  *
1402  * Actors are visible by default.
1403  *
1404  * If this function is called on an actor without a parent, the
1405  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1406  * as a side-effect.
1407  */
1408 void
1409 clutter_actor_hide (ClutterActor *self)
1410 {
1411   ClutterActorPrivate *priv;
1412
1413   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1414
1415   /* simple optimization */
1416   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1417     {
1418       /* we still need to set the :show-on-set-parent property, in
1419        * case hide() is called on an unparented actor
1420        */
1421       set_show_on_set_parent (self, FALSE);
1422       return;
1423     }
1424
1425 #ifdef CLUTTER_ENABLE_DEBUG
1426   clutter_actor_verify_map_state (self);
1427 #endif
1428
1429   priv = self->priv;
1430
1431   g_object_freeze_notify (G_OBJECT (self));
1432
1433   set_show_on_set_parent (self, FALSE);
1434
1435   g_signal_emit (self, actor_signals[HIDE], 0);
1436   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1437
1438   if (priv->parent != NULL)
1439     clutter_actor_queue_redraw (priv->parent);
1440
1441   g_object_thaw_notify (G_OBJECT (self));
1442 }
1443
1444 /**
1445  * clutter_actor_hide_all:
1446  * @self: a #ClutterActor
1447  *
1448  * Calls clutter_actor_hide() on all child actors (if any).
1449  *
1450  * Since: 0.2
1451  *
1452  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1453  *   prevent its children from being painted as well.
1454  */
1455 void
1456 clutter_actor_hide_all (ClutterActor *self)
1457 {
1458   ClutterActorClass *klass;
1459
1460   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1461
1462   klass = CLUTTER_ACTOR_GET_CLASS (self);
1463   if (klass->hide_all)
1464     klass->hide_all (self);
1465 }
1466
1467 /**
1468  * clutter_actor_realize:
1469  * @self: A #ClutterActor
1470  *
1471  * Realization informs the actor that it is attached to a stage. It
1472  * can use this to allocate resources if it wanted to delay allocation
1473  * until it would be rendered. However it is perfectly acceptable for
1474  * an actor to create resources before being realized because Clutter
1475  * only ever has a single rendering context so that actor is free to
1476  * be moved from one stage to another.
1477  *
1478  * This function does nothing if the actor is already realized.
1479  *
1480  * Because a realized actor must have realized parent actors, calling
1481  * clutter_actor_realize() will also realize all parents of the actor.
1482  *
1483  * This function does not realize child actors, except in the special
1484  * case that realizing the stage, when the stage is visible, will
1485  * suddenly map (and thus realize) the children of the stage.
1486  **/
1487 void
1488 clutter_actor_realize (ClutterActor *self)
1489 {
1490   ClutterActorPrivate *priv;
1491
1492   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1493
1494   priv = self->priv;
1495
1496 #ifdef CLUTTER_ENABLE_DEBUG
1497   clutter_actor_verify_map_state (self);
1498 #endif
1499
1500   if (CLUTTER_ACTOR_IS_REALIZED (self))
1501     return;
1502
1503   /* To be realized, our parent actors must be realized first.
1504    * This will only succeed if we're inside a toplevel.
1505    */
1506   if (priv->parent != NULL)
1507     clutter_actor_realize (priv->parent);
1508
1509   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1510     {
1511       /* toplevels can be realized at any time */
1512     }
1513   else
1514     {
1515       /* "Fail" the realization if parent is missing or unrealized;
1516        * this should really be a g_warning() not some kind of runtime
1517        * failure; how can an app possibly recover? Instead it's a bug
1518        * in the app and the app should get an explanatory warning so
1519        * someone can fix it. But for now it's too hard to fix this
1520        * because e.g. ClutterTexture needs reworking.
1521        */
1522       if (priv->parent == NULL ||
1523           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1524         return;
1525     }
1526
1527   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1528
1529   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1530   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1531
1532   g_signal_emit (self, actor_signals[REALIZE], 0);
1533
1534   /* Stage actor is allowed to unset the realized flag again in its
1535    * default signal handler, though that is a pathological situation.
1536    */
1537
1538   /* If realization "failed" we'll have to update child state. */
1539   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1540 }
1541
1542 static void
1543 clutter_actor_real_unrealize (ClutterActor *self)
1544 {
1545   /* we must be unmapped (implying our children are also unmapped) */
1546   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1547 }
1548
1549 /**
1550  * clutter_actor_unrealize:
1551  * @self: A #ClutterActor
1552  *
1553  * Unrealization informs the actor that it may be being destroyed or
1554  * moved to another stage. The actor may want to destroy any
1555  * underlying graphics resources at this point. However it is
1556  * perfectly acceptable for it to retain the resources until the actor
1557  * is destroyed because Clutter only ever uses a single rendering
1558  * context and all of the graphics resources are valid on any stage.
1559  *
1560  * Because mapped actors must be realized, actors may not be
1561  * unrealized if they are mapped. This function hides the actor to be
1562  * sure it isn't mapped, an application-visible side effect that you
1563  * may not be expecting.
1564  *
1565  * This function should not be called by application code.
1566  */
1567 void
1568 clutter_actor_unrealize (ClutterActor *self)
1569 {
1570   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1571   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1572
1573 /* This function should not really be in the public API, because
1574  * there isn't a good reason to call it. ClutterActor will already
1575  * unrealize things for you when it's important to do so.
1576  *
1577  * If you were using clutter_actor_unrealize() in a dispose
1578  * implementation, then don't, just chain up to ClutterActor's
1579  * dispose.
1580  *
1581  * If you were using clutter_actor_unrealize() to implement
1582  * unrealizing children of your container, then don't, ClutterActor
1583  * will already take care of that.
1584  *
1585  * If you were using clutter_actor_unrealize() to re-realize to
1586  * create your resources in a different way, then use
1587  * _clutter_actor_rerealize() (inside Clutter) or just call your
1588  * code that recreates your resources directly (outside Clutter).
1589  */
1590
1591 #ifdef CLUTTER_ENABLE_DEBUG
1592   clutter_actor_verify_map_state (self);
1593 #endif
1594
1595   clutter_actor_hide (self);
1596
1597   clutter_actor_unrealize_not_hiding (self);
1598 }
1599
1600 static ClutterActorTraverseVisitFlags
1601 unrealize_actor_before_children_cb (ClutterActor *self,
1602                                     int depth,
1603                                     void *user_data)
1604 {
1605   /* If an actor is already unrealized we know its children have also
1606    * already been unrealized... */
1607   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1608     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1609
1610   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1611
1612   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1613 }
1614
1615 static ClutterActorTraverseVisitFlags
1616 unrealize_actor_after_children_cb (ClutterActor *self,
1617                                    int depth,
1618                                    void *user_data)
1619 {
1620   /* We want to unset the realized flag only _after_
1621    * child actors are unrealized, to maintain invariants.
1622    */
1623   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1624   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1625   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1626 }
1627
1628 /*
1629  * clutter_actor_unrealize_not_hiding:
1630  * @self: A #ClutterActor
1631  *
1632  * Unrealization informs the actor that it may be being destroyed or
1633  * moved to another stage. The actor may want to destroy any
1634  * underlying graphics resources at this point. However it is
1635  * perfectly acceptable for it to retain the resources until the actor
1636  * is destroyed because Clutter only ever uses a single rendering
1637  * context and all of the graphics resources are valid on any stage.
1638  *
1639  * Because mapped actors must be realized, actors may not be
1640  * unrealized if they are mapped. You must hide the actor or one of
1641  * its parents before attempting to unrealize.
1642  *
1643  * This function is separate from clutter_actor_unrealize() because it
1644  * does not automatically hide the actor.
1645  * Actors need not be hidden to be unrealized, they just need to
1646  * be unmapped. In fact we don't want to mess up the application's
1647  * setting of the "visible" flag, so hiding is very undesirable.
1648  *
1649  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1650  * backward compatibility.
1651  */
1652 static void
1653 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1654 {
1655   _clutter_actor_traverse (self,
1656                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1657                            unrealize_actor_before_children_cb,
1658                            unrealize_actor_after_children_cb,
1659                            NULL);
1660 }
1661
1662 /*
1663  * _clutter_actor_rerealize:
1664  * @self: A #ClutterActor
1665  * @callback: Function to call while unrealized
1666  * @data: data for callback
1667  *
1668  * If an actor is already unrealized, this just calls the callback.
1669  *
1670  * If it is realized, it unrealizes temporarily, calls the callback,
1671  * and then re-realizes the actor.
1672  *
1673  * As a side effect, leaves all children of the actor unrealized if
1674  * the actor was realized but not showing.  This is because when we
1675  * unrealize the actor temporarily we must unrealize its children
1676  * (e.g. children of a stage can't be realized if stage window is
1677  * gone). And we aren't clever enough to save the realization state of
1678  * all children. In most cases this should not matter, because
1679  * the children will automatically realize when they next become mapped.
1680  */
1681 void
1682 _clutter_actor_rerealize (ClutterActor    *self,
1683                           ClutterCallback  callback,
1684                           void            *data)
1685 {
1686   gboolean was_mapped;
1687   gboolean was_showing;
1688   gboolean was_realized;
1689
1690   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1691
1692 #ifdef CLUTTER_ENABLE_DEBUG
1693   clutter_actor_verify_map_state (self);
1694 #endif
1695
1696   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1697   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1698   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1699
1700   /* Must be unmapped to unrealize. Note we only have to hide this
1701    * actor if it was mapped (if all parents were showing).  If actor
1702    * is merely visible (but not mapped), then that's fine, we can
1703    * leave it visible.
1704    */
1705   if (was_mapped)
1706     clutter_actor_hide (self);
1707
1708   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1709
1710   /* unrealize self and all children */
1711   clutter_actor_unrealize_not_hiding (self);
1712
1713   if (callback != NULL)
1714     {
1715       (* callback) (self, data);
1716     }
1717
1718   if (was_showing)
1719     clutter_actor_show (self); /* will realize only if mapping implies it */
1720   else if (was_realized)
1721     clutter_actor_realize (self); /* realize self and all parents */
1722 }
1723
1724 static void
1725 clutter_actor_real_pick (ClutterActor       *self,
1726                          const ClutterColor *color)
1727 {
1728   /* the default implementation is just to paint a rectangle
1729    * with the same size of the actor using the passed color
1730    */
1731   if (clutter_actor_should_pick_paint (self))
1732     {
1733       ClutterActorBox box = { 0, };
1734       float width, height;
1735
1736       clutter_actor_get_allocation_box (self, &box);
1737
1738       width = box.x2 - box.x1;
1739       height = box.y2 - box.y1;
1740
1741       cogl_set_source_color4ub (color->red,
1742                                 color->green,
1743                                 color->blue,
1744                                 color->alpha);
1745
1746       cogl_rectangle (0, 0, width, height);
1747     }
1748
1749   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1750    * with existing container classes that override the pick() virtual
1751    * and chain up to the default implementation - otherwise we'll end up
1752    * painting our children twice.
1753    *
1754    * this has to go away for 2.0; hopefully along the pick() itself.
1755    */
1756   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1757     {
1758       ClutterActor *iter;
1759
1760       for (iter = self->priv->first_child;
1761            iter != NULL;
1762            iter = iter->priv->next_sibling)
1763         clutter_actor_paint (iter);
1764     }
1765 }
1766
1767 /**
1768  * clutter_actor_should_pick_paint:
1769  * @self: A #ClutterActor
1770  *
1771  * Should be called inside the implementation of the
1772  * #ClutterActor::pick virtual function in order to check whether
1773  * the actor should paint itself in pick mode or not.
1774  *
1775  * This function should never be called directly by applications.
1776  *
1777  * Return value: %TRUE if the actor should paint its silhouette,
1778  *   %FALSE otherwise
1779  */
1780 gboolean
1781 clutter_actor_should_pick_paint (ClutterActor *self)
1782 {
1783   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1784
1785   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1786       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1787        CLUTTER_ACTOR_IS_REACTIVE (self)))
1788     return TRUE;
1789
1790   return FALSE;
1791 }
1792
1793 static void
1794 clutter_actor_real_get_preferred_width (ClutterActor *self,
1795                                         gfloat        for_height,
1796                                         gfloat       *min_width_p,
1797                                         gfloat       *natural_width_p)
1798 {
1799   ClutterActorPrivate *priv = self->priv;
1800
1801   if (priv->n_children != 0 &&
1802       priv->layout_manager != NULL)
1803     {
1804       ClutterContainer *container = CLUTTER_CONTAINER (self);
1805
1806       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1807                     "for the preferred width",
1808                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1809                     priv->layout_manager);
1810
1811       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1812                                                   container,
1813                                                   for_height,
1814                                                   min_width_p,
1815                                                   natural_width_p);
1816
1817       return;
1818     }
1819
1820   /* Default implementation is always 0x0, usually an actor
1821    * using this default is relying on someone to set the
1822    * request manually
1823    */
1824   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1825
1826   if (min_width_p)
1827     *min_width_p = 0;
1828
1829   if (natural_width_p)
1830     *natural_width_p = 0;
1831 }
1832
1833 static void
1834 clutter_actor_real_get_preferred_height (ClutterActor *self,
1835                                          gfloat        for_width,
1836                                          gfloat       *min_height_p,
1837                                          gfloat       *natural_height_p)
1838 {
1839   ClutterActorPrivate *priv = self->priv;
1840
1841   if (priv->n_children != 0 &&
1842       priv->layout_manager != NULL)
1843     {
1844       ClutterContainer *container = CLUTTER_CONTAINER (self);
1845
1846       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1847                     "for the preferred height",
1848                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1849                     priv->layout_manager);
1850
1851       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1852                                                    container,
1853                                                    for_width,
1854                                                    min_height_p,
1855                                                    natural_height_p);
1856
1857       return;
1858     }
1859   /* Default implementation is always 0x0, usually an actor
1860    * using this default is relying on someone to set the
1861    * request manually
1862    */
1863   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1864
1865   if (min_height_p)
1866     *min_height_p = 0;
1867
1868   if (natural_height_p)
1869     *natural_height_p = 0;
1870 }
1871
1872 static void
1873 clutter_actor_store_old_geometry (ClutterActor    *self,
1874                                   ClutterActorBox *box)
1875 {
1876   *box = self->priv->allocation;
1877 }
1878
1879 static inline void
1880 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
1881                                           const ClutterActorBox *old)
1882 {
1883   ClutterActorPrivate *priv = self->priv;
1884   GObject *obj = G_OBJECT (self);
1885
1886   g_object_freeze_notify (obj);
1887
1888   /* to avoid excessive requisition or allocation cycles we
1889    * use the cached values.
1890    *
1891    * - if we don't have an allocation we assume that we need
1892    *   to notify anyway
1893    * - if we don't have a width or a height request we notify
1894    *   width and height
1895    * - if we have a valid allocation then we check the old
1896    *   bounding box with the current allocation and we notify
1897    *   the changes
1898    */
1899   if (priv->needs_allocation)
1900     {
1901       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1902       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1903       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1904       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1905     }
1906   else if (priv->needs_width_request || priv->needs_height_request)
1907     {
1908       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1909       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1910     }
1911   else
1912     {
1913       gfloat xu, yu;
1914       gfloat widthu, heightu;
1915
1916       xu = priv->allocation.x1;
1917       yu = priv->allocation.y1;
1918       widthu = priv->allocation.x2 - priv->allocation.x1;
1919       heightu = priv->allocation.y2 - priv->allocation.y1;
1920
1921       if (xu != old->x1)
1922         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1923
1924       if (yu != old->y1)
1925         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1926
1927       if (widthu != (old->x2 - old->x1))
1928         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1929
1930       if (heightu != (old->y2 - old->y1))
1931         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1932     }
1933
1934   g_object_thaw_notify (obj);
1935 }
1936
1937 /*< private >
1938  * clutter_actor_set_allocation_internal:
1939  * @self: a #ClutterActor
1940  * @box: a #ClutterActorBox
1941  * @flags: allocation flags
1942  *
1943  * Stores the allocation of @self.
1944  *
1945  * This function only performs basic storage and property notification.
1946  *
1947  * This function should be called by clutter_actor_set_allocation()
1948  * and by the default implementation of #ClutterActorClass.allocate().
1949  *
1950  * Return value: %TRUE if the allocation of the #ClutterActor has been
1951  *   changed, and %FALSE otherwise
1952  */
1953 static inline gboolean
1954 clutter_actor_set_allocation_internal (ClutterActor           *self,
1955                                        const ClutterActorBox  *box,
1956                                        ClutterAllocationFlags  flags)
1957 {
1958   ClutterActorPrivate *priv = self->priv;
1959   GObject *obj;
1960   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
1961   gboolean flags_changed;
1962   gboolean retval;
1963   ClutterActorBox old_alloc = { 0, };
1964
1965   obj = G_OBJECT (self);
1966
1967   g_object_freeze_notify (obj);
1968
1969   clutter_actor_store_old_geometry (self, &old_alloc);
1970
1971   x1_changed = priv->allocation.x1 != box->x1;
1972   y1_changed = priv->allocation.y1 != box->y1;
1973   x2_changed = priv->allocation.x2 != box->x2;
1974   y2_changed = priv->allocation.y2 != box->y2;
1975
1976   flags_changed = priv->allocation_flags != flags;
1977
1978   priv->allocation = *box;
1979   priv->allocation_flags = flags;
1980
1981   /* allocation is authoritative */
1982   priv->needs_width_request = FALSE;
1983   priv->needs_height_request = FALSE;
1984   priv->needs_allocation = FALSE;
1985
1986   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
1987     {
1988       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
1989                     _clutter_actor_get_debug_name (self));
1990
1991       priv->transform_valid = FALSE;
1992
1993       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
1994
1995       retval = TRUE;
1996     }
1997   else
1998     retval = FALSE;
1999
2000   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2001
2002   g_object_thaw_notify (obj);
2003
2004   return retval;
2005 }
2006
2007 static void clutter_actor_real_allocate (ClutterActor           *self,
2008                                          const ClutterActorBox  *box,
2009                                          ClutterAllocationFlags  flags);
2010
2011 static inline void
2012 clutter_actor_maybe_layout_children (ClutterActor           *self,
2013                                      const ClutterActorBox  *allocation,
2014                                      ClutterAllocationFlags  flags)
2015 {
2016   ClutterActorPrivate *priv = self->priv;
2017
2018   /* this is going to be a bit hard to follow, so let's put an explanation
2019    * here.
2020    *
2021    * we want ClutterActor to have a default layout manager if the actor was
2022    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2023    *
2024    * we also want any subclass of ClutterActor that does not override the
2025    * ::allocate() virtual function to delegate to a layout manager.
2026    *
2027    * finally, we want to allow people subclassing ClutterActor and overriding
2028    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2029    *
2030    * on the other hand, we want existing actor subclasses overriding the
2031    * ::allocate() virtual function and chaining up to the parent's
2032    * implementation to continue working without allocating their children
2033    * twice, or without entering an allocation loop.
2034    *
2035    * for the first two points, we check if the class of the actor is
2036    * overridding the ::allocate() virtual function; if it isn't, then we
2037    * follow through with checking whether we have children and a layout
2038    * manager, and eventually calling clutter_layout_manager_allocate().
2039    *
2040    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2041    * allocation flags that we got passed, and if it is present, we continue
2042    * with the check above.
2043    *
2044    * if neither of these two checks yields a positive result, we just
2045    * assume that the ::allocate() virtual function that resulted in this
2046    * function being called will also allocate the children of the actor.
2047    */
2048
2049   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2050     goto check_layout;
2051
2052   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2053     goto check_layout;
2054
2055   return;
2056
2057 check_layout:
2058   if (priv->n_children != 0 &&
2059       priv->layout_manager != NULL)
2060     {
2061       ClutterContainer *container = CLUTTER_CONTAINER (self);
2062       ClutterAllocationFlags children_flags;
2063       ClutterActorBox children_box;
2064
2065       /* normalize the box passed to the layout manager */
2066       children_box.x1 = children_box.y1 = 0.f;
2067       children_box.x2 = (allocation->x2 - allocation->x1);
2068       children_box.y2 = (allocation->y2 - allocation->y1);
2069
2070       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2071        * the actor's children, since it refers only to the current
2072        * actor's allocation.
2073        */
2074       children_flags = flags;
2075       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2076
2077       CLUTTER_NOTE (LAYOUT,
2078                     "Allocating %d children of %s "
2079                     "at { %.2f, %.2f - %.2f x %.2f } "
2080                     "using %s",
2081                     priv->n_children,
2082                     _clutter_actor_get_debug_name (self),
2083                     allocation->x1,
2084                     allocation->y1,
2085                     (allocation->x2 - allocation->x1),
2086                     (allocation->y2 - allocation->y1),
2087                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2088
2089       clutter_layout_manager_allocate (priv->layout_manager,
2090                                        container,
2091                                        &children_box,
2092                                        children_flags);
2093     }
2094 }
2095
2096 static void
2097 clutter_actor_real_allocate (ClutterActor           *self,
2098                              const ClutterActorBox  *box,
2099                              ClutterAllocationFlags  flags)
2100 {
2101   ClutterActorPrivate *priv = self->priv;
2102   gboolean changed;
2103
2104   g_object_freeze_notify (G_OBJECT (self));
2105
2106   changed = clutter_actor_set_allocation_internal (self, box, flags);
2107
2108   /* we allocate our children before we notify changes in our geometry,
2109    * so that people connecting to properties will be able to get valid
2110    * data out of the sub-tree of the scene graph that has this actor at
2111    * the root.
2112    */
2113   clutter_actor_maybe_layout_children (self, box, flags);
2114
2115   if (changed)
2116     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2117                    &priv->allocation,
2118                    priv->allocation_flags);
2119
2120   g_object_thaw_notify (G_OBJECT (self));
2121 }
2122
2123 static void
2124 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2125                                     ClutterActor *origin)
2126 {
2127   /* no point in queuing a redraw on a destroyed actor */
2128   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2129     return;
2130
2131   /* NB: We can't bail out early here if the actor is hidden in case
2132    * the actor bas been cloned. In this case the clone will need to
2133    * receive the signal so it can queue its own redraw.
2134    */
2135
2136   /* calls klass->queue_redraw in default handler */
2137   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2138 }
2139
2140 static void
2141 clutter_actor_real_queue_redraw (ClutterActor *self,
2142                                  ClutterActor *origin)
2143 {
2144   ClutterActor *parent;
2145
2146   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2147                 _clutter_actor_get_debug_name (self),
2148                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2149                                : "same actor");
2150
2151   /* no point in queuing a redraw on a destroyed actor */
2152   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2153     return;
2154
2155   /* If the queue redraw is coming from a child then the actor has
2156      become dirty and any queued effect is no longer valid */
2157   if (self != origin)
2158     {
2159       self->priv->is_dirty = TRUE;
2160       self->priv->effect_to_redraw = NULL;
2161     }
2162
2163   /* If the actor isn't visible, we still had to emit the signal
2164    * to allow for a ClutterClone, but the appearance of the parent
2165    * won't change so we don't have to propagate up the hierarchy.
2166    */
2167   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2168     return;
2169
2170   /* Although we could determine here that a full stage redraw
2171    * has already been queued and immediately bail out, we actually
2172    * guarantee that we will propagate a queue-redraw signal to our
2173    * parent at least once so that it's possible to implement a
2174    * container that tracks which of its children have queued a
2175    * redraw.
2176    */
2177   if (self->priv->propagated_one_redraw)
2178     {
2179       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2180       if (stage != NULL &&
2181           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2182         return;
2183     }
2184
2185   self->priv->propagated_one_redraw = TRUE;
2186
2187   /* notify parents, if they are all visible eventually we'll
2188    * queue redraw on the stage, which queues the redraw idle.
2189    */
2190   parent = clutter_actor_get_parent (self);
2191   if (parent != NULL)
2192     {
2193       /* this will go up recursively */
2194       _clutter_actor_signal_queue_redraw (parent, origin);
2195     }
2196 }
2197
2198 static void
2199 clutter_actor_real_queue_relayout (ClutterActor *self)
2200 {
2201   ClutterActorPrivate *priv = self->priv;
2202
2203   /* no point in queueing a redraw on a destroyed actor */
2204   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2205     return;
2206
2207   priv->needs_width_request  = TRUE;
2208   priv->needs_height_request = TRUE;
2209   priv->needs_allocation     = TRUE;
2210
2211   /* reset the cached size requests */
2212   memset (priv->width_requests, 0,
2213           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2214   memset (priv->height_requests, 0,
2215           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2216
2217   /* We need to go all the way up the hierarchy */
2218   if (priv->parent != NULL)
2219     _clutter_actor_queue_only_relayout (priv->parent);
2220 }
2221
2222 /**
2223  * clutter_actor_apply_relative_transform_to_point:
2224  * @self: A #ClutterActor
2225  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2226  *   default #ClutterStage
2227  * @point: A point as #ClutterVertex
2228  * @vertex: (out caller-allocates): The translated #ClutterVertex
2229  *
2230  * Transforms @point in coordinates relative to the actor into
2231  * ancestor-relative coordinates using the relevant transform
2232  * stack (i.e. scale, rotation, etc).
2233  *
2234  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2235  * this case, the coordinates returned will be the coordinates on
2236  * the stage before the projection is applied. This is different from
2237  * the behaviour of clutter_actor_apply_transform_to_point().
2238  *
2239  * Since: 0.6
2240  */
2241 void
2242 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2243                                                  ClutterActor        *ancestor,
2244                                                  const ClutterVertex *point,
2245                                                  ClutterVertex       *vertex)
2246 {
2247   gfloat w;
2248   CoglMatrix matrix;
2249
2250   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2251   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2252   g_return_if_fail (point != NULL);
2253   g_return_if_fail (vertex != NULL);
2254
2255   *vertex = *point;
2256   w = 1.0;
2257
2258   if (ancestor == NULL)
2259     ancestor = _clutter_actor_get_stage_internal (self);
2260
2261   if (ancestor == NULL)
2262     {
2263       *vertex = *point;
2264       return;
2265     }
2266
2267   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2268   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2269 }
2270
2271 static gboolean
2272 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2273                                          const ClutterVertex *vertices_in,
2274                                          ClutterVertex *vertices_out,
2275                                          int n_vertices)
2276 {
2277   ClutterActor *stage;
2278   CoglMatrix modelview;
2279   CoglMatrix projection;
2280   float viewport[4];
2281
2282   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2283
2284   stage = _clutter_actor_get_stage_internal (self);
2285
2286   /* We really can't do anything meaningful in this case so don't try
2287    * to do any transform */
2288   if (stage == NULL)
2289     return FALSE;
2290
2291   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2292    * that gets us to stage coordinates, we want to go all the way to eye
2293    * coordinates */
2294   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2295
2296   /* Fetch the projection and viewport */
2297   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2298   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2299                                &viewport[0],
2300                                &viewport[1],
2301                                &viewport[2],
2302                                &viewport[3]);
2303
2304   _clutter_util_fully_transform_vertices (&modelview,
2305                                           &projection,
2306                                           viewport,
2307                                           vertices_in,
2308                                           vertices_out,
2309                                           n_vertices);
2310
2311   return TRUE;
2312 }
2313
2314 /**
2315  * clutter_actor_apply_transform_to_point:
2316  * @self: A #ClutterActor
2317  * @point: A point as #ClutterVertex
2318  * @vertex: (out caller-allocates): The translated #ClutterVertex
2319  *
2320  * Transforms @point in coordinates relative to the actor
2321  * into screen-relative coordinates with the current actor
2322  * transformation (i.e. scale, rotation, etc)
2323  *
2324  * Since: 0.4
2325  **/
2326 void
2327 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2328                                         const ClutterVertex *point,
2329                                         ClutterVertex       *vertex)
2330 {
2331   g_return_if_fail (point != NULL);
2332   g_return_if_fail (vertex != NULL);
2333   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2334 }
2335
2336 /*
2337  * _clutter_actor_get_relative_transformation_matrix:
2338  * @self: The actor whose coordinate space you want to transform from.
2339  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2340  *            or %NULL if you want to transform all the way to eye coordinates.
2341  * @matrix: A #CoglMatrix to store the transformation
2342  *
2343  * This gets a transformation @matrix that will transform coordinates from the
2344  * coordinate space of @self into the coordinate space of @ancestor.
2345  *
2346  * For example if you need a matrix that can transform the local actor
2347  * coordinates of @self into stage coordinates you would pass the actor's stage
2348  * pointer as the @ancestor.
2349  *
2350  * If you pass %NULL then the transformation will take you all the way through
2351  * to eye coordinates. This can be useful if you want to extract the entire
2352  * modelview transform that Clutter applies before applying the projection
2353  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2354  * using cogl_set_modelview_matrix() for example then you would want a matrix
2355  * that transforms into eye coordinates.
2356  *
2357  * <note><para>This function explicitly initializes the given @matrix. If you just
2358  * want clutter to multiply a relative transformation with an existing matrix
2359  * you can use clutter_actor_apply_relative_transformation_matrix()
2360  * instead.</para></note>
2361  *
2362  */
2363 /* XXX: We should consider caching the stage relative modelview along with
2364  * the actor itself */
2365 static void
2366 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2367                                                    ClutterActor *ancestor,
2368                                                    CoglMatrix *matrix)
2369 {
2370   cogl_matrix_init_identity (matrix);
2371
2372   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2373 }
2374
2375 /* Project the given @box into stage window coordinates, writing the
2376  * transformed vertices to @verts[]. */
2377 static gboolean
2378 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2379                                           const ClutterActorBox *box,
2380                                           ClutterVertex          verts[])
2381 {
2382   ClutterVertex box_vertices[4];
2383
2384   box_vertices[0].x = box->x1;
2385   box_vertices[0].y = box->y1;
2386   box_vertices[0].z = 0;
2387   box_vertices[1].x = box->x2;
2388   box_vertices[1].y = box->y1;
2389   box_vertices[1].z = 0;
2390   box_vertices[2].x = box->x1;
2391   box_vertices[2].y = box->y2;
2392   box_vertices[2].z = 0;
2393   box_vertices[3].x = box->x2;
2394   box_vertices[3].y = box->y2;
2395   box_vertices[3].z = 0;
2396
2397   return
2398     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2399 }
2400
2401 /**
2402  * clutter_actor_get_allocation_vertices:
2403  * @self: A #ClutterActor
2404  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2405  *   against, or %NULL to use the #ClutterStage
2406  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2407  *   location for an array of 4 #ClutterVertex in which to store the result
2408  *
2409  * Calculates the transformed coordinates of the four corners of the
2410  * actor in the plane of @ancestor. The returned vertices relate to
2411  * the #ClutterActorBox coordinates as follows:
2412  * <itemizedlist>
2413  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2414  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2415  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2416  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2417  * </itemizedlist>
2418  *
2419  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2420  * this case, the coordinates returned will be the coordinates on
2421  * the stage before the projection is applied. This is different from
2422  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2423  *
2424  * Since: 0.6
2425  */
2426 void
2427 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2428                                        ClutterActor  *ancestor,
2429                                        ClutterVertex  verts[])
2430 {
2431   ClutterActorPrivate *priv;
2432   ClutterActorBox box;
2433   ClutterVertex vertices[4];
2434   CoglMatrix modelview;
2435
2436   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2437   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2438
2439   if (ancestor == NULL)
2440     ancestor = _clutter_actor_get_stage_internal (self);
2441
2442   /* Fallback to a NOP transform if the actor isn't parented under a
2443    * stage. */
2444   if (ancestor == NULL)
2445     ancestor = self;
2446
2447   priv = self->priv;
2448
2449   /* if the actor needs to be allocated we force a relayout, so that
2450    * we will have valid values to use in the transformations */
2451   if (priv->needs_allocation)
2452     {
2453       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2454       if (stage)
2455         _clutter_stage_maybe_relayout (stage);
2456       else
2457         {
2458           box.x1 = box.y1 = 0;
2459           /* The result isn't really meaningful in this case but at
2460            * least try to do something *vaguely* reasonable... */
2461           clutter_actor_get_size (self, &box.x2, &box.y2);
2462         }
2463     }
2464
2465   clutter_actor_get_allocation_box (self, &box);
2466
2467   vertices[0].x = box.x1;
2468   vertices[0].y = box.y1;
2469   vertices[0].z = 0;
2470   vertices[1].x = box.x2;
2471   vertices[1].y = box.y1;
2472   vertices[1].z = 0;
2473   vertices[2].x = box.x1;
2474   vertices[2].y = box.y2;
2475   vertices[2].z = 0;
2476   vertices[3].x = box.x2;
2477   vertices[3].y = box.y2;
2478   vertices[3].z = 0;
2479
2480   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2481                                                      &modelview);
2482
2483   cogl_matrix_transform_points (&modelview,
2484                                 3,
2485                                 sizeof (ClutterVertex),
2486                                 vertices,
2487                                 sizeof (ClutterVertex),
2488                                 vertices,
2489                                 4);
2490 }
2491
2492 /**
2493  * clutter_actor_get_abs_allocation_vertices:
2494  * @self: A #ClutterActor
2495  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2496  *   of 4 #ClutterVertex where to store the result.
2497  *
2498  * Calculates the transformed screen coordinates of the four corners of
2499  * the actor; the returned vertices relate to the #ClutterActorBox
2500  * coordinates  as follows:
2501  * <itemizedlist>
2502  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2503  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2504  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2505  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2506  * </itemizedlist>
2507  *
2508  * Since: 0.4
2509  */
2510 void
2511 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2512                                            ClutterVertex  verts[])
2513 {
2514   ClutterActorPrivate *priv;
2515   ClutterActorBox actor_space_allocation;
2516
2517   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2518
2519   priv = self->priv;
2520
2521   /* if the actor needs to be allocated we force a relayout, so that
2522    * the actor allocation box will be valid for
2523    * _clutter_actor_transform_and_project_box()
2524    */
2525   if (priv->needs_allocation)
2526     {
2527       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2528       /* There's nothing meaningful we can do now */
2529       if (!stage)
2530         return;
2531
2532       _clutter_stage_maybe_relayout (stage);
2533     }
2534
2535   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2536    * own coordinate space... */
2537   actor_space_allocation.x1 = 0;
2538   actor_space_allocation.y1 = 0;
2539   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2540   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2541   _clutter_actor_transform_and_project_box (self,
2542                                             &actor_space_allocation,
2543                                             verts);
2544 }
2545
2546 static void
2547 clutter_actor_real_apply_transform (ClutterActor *self,
2548                                     CoglMatrix   *matrix)
2549 {
2550   ClutterActorPrivate *priv = self->priv;
2551
2552   if (!priv->transform_valid)
2553     {
2554       CoglMatrix *transform = &priv->transform;
2555       const ClutterTransformInfo *info;
2556
2557       info = _clutter_actor_get_transform_info_or_defaults (self);
2558
2559       cogl_matrix_init_identity (transform);
2560
2561       cogl_matrix_translate (transform,
2562                              priv->allocation.x1,
2563                              priv->allocation.y1,
2564                              0.0);
2565
2566       if (priv->z)
2567         cogl_matrix_translate (transform, 0, 0, priv->z);
2568
2569       /*
2570        * because the rotation involves translations, we must scale
2571        * before applying the rotations (if we apply the scale after
2572        * the rotations, the translations included in the rotation are
2573        * not scaled and so the entire object will move on the screen
2574        * as a result of rotating it).
2575        */
2576       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2577         {
2578           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2579                                         &info->scale_center,
2580                                         cogl_matrix_scale (transform,
2581                                                            info->scale_x,
2582                                                            info->scale_y,
2583                                                            1.0));
2584         }
2585
2586       if (info->rz_angle)
2587         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2588                                       &info->rz_center,
2589                                       cogl_matrix_rotate (transform,
2590                                                           info->rz_angle,
2591                                                           0, 0, 1.0));
2592
2593       if (info->ry_angle)
2594         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2595                                       &info->ry_center,
2596                                       cogl_matrix_rotate (transform,
2597                                                           info->ry_angle,
2598                                                           0, 1.0, 0));
2599
2600       if (info->rx_angle)
2601         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2602                                       &info->rx_center,
2603                                       cogl_matrix_rotate (transform,
2604                                                           info->rx_angle,
2605                                                           1.0, 0, 0));
2606
2607       if (!clutter_anchor_coord_is_zero (&info->anchor))
2608         {
2609           gfloat x, y, z;
2610
2611           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2612           cogl_matrix_translate (transform, -x, -y, -z);
2613         }
2614
2615       priv->transform_valid = TRUE;
2616     }
2617
2618   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2619 }
2620
2621 /* Applies the transforms associated with this actor to the given
2622  * matrix. */
2623 void
2624 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2625                                           CoglMatrix *matrix)
2626 {
2627   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2628 }
2629
2630 /*
2631  * clutter_actor_apply_relative_transformation_matrix:
2632  * @self: The actor whose coordinate space you want to transform from.
2633  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2634  *            or %NULL if you want to transform all the way to eye coordinates.
2635  * @matrix: A #CoglMatrix to apply the transformation too.
2636  *
2637  * This multiplies a transform with @matrix that will transform coordinates
2638  * from the coordinate space of @self into the coordinate space of @ancestor.
2639  *
2640  * For example if you need a matrix that can transform the local actor
2641  * coordinates of @self into stage coordinates you would pass the actor's stage
2642  * pointer as the @ancestor.
2643  *
2644  * If you pass %NULL then the transformation will take you all the way through
2645  * to eye coordinates. This can be useful if you want to extract the entire
2646  * modelview transform that Clutter applies before applying the projection
2647  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2648  * using cogl_set_modelview_matrix() for example then you would want a matrix
2649  * that transforms into eye coordinates.
2650  *
2651  * <note>This function doesn't initialize the given @matrix, it simply
2652  * multiplies the requested transformation matrix with the existing contents of
2653  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2654  * before calling this function, or you can use
2655  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2656  */
2657 void
2658 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2659                                                      ClutterActor *ancestor,
2660                                                      CoglMatrix *matrix)
2661 {
2662   ClutterActor *parent;
2663
2664   /* Note we terminate before ever calling stage->apply_transform()
2665    * since that would conceptually be relative to the underlying
2666    * window OpenGL coordinates so we'd need a special @ancestor
2667    * value to represent the fake parent of the stage. */
2668   if (self == ancestor)
2669     return;
2670
2671   parent = clutter_actor_get_parent (self);
2672
2673   if (parent != NULL)
2674     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2675                                                          matrix);
2676
2677   _clutter_actor_apply_modelview_transform (self, matrix);
2678 }
2679
2680 static void
2681 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2682                                        ClutterPaintVolume *pv,
2683                                        const char *label,
2684                                        const CoglColor *color)
2685 {
2686   static CoglPipeline *outline = NULL;
2687   CoglPrimitive *prim;
2688   ClutterVertex line_ends[12 * 2];
2689   int n_vertices;
2690   CoglContext *ctx =
2691     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2692   /* XXX: at some point we'll query this from the stage but we can't
2693    * do that until the osx backend uses Cogl natively. */
2694   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2695
2696   if (outline == NULL)
2697     outline = cogl_pipeline_new (ctx);
2698
2699   _clutter_paint_volume_complete (pv);
2700
2701   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2702
2703   /* Front face */
2704   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2705   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2706   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2707   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2708
2709   if (!pv->is_2d)
2710     {
2711       /* Back face */
2712       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2713       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2714       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2715       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2716
2717       /* Lines connecting front face to back face */
2718       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2719       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2720       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2721       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2722     }
2723
2724   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2725                                 n_vertices,
2726                                 (CoglVertexP3 *)line_ends);
2727
2728   cogl_pipeline_set_color (outline, color);
2729   cogl_framebuffer_draw_primitive (fb, outline, prim);
2730   cogl_object_unref (prim);
2731
2732   if (label)
2733     {
2734       PangoLayout *layout;
2735       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2736       pango_layout_set_text (layout, label, -1);
2737       cogl_pango_render_layout (layout,
2738                                 pv->vertices[0].x,
2739                                 pv->vertices[0].y,
2740                                 color,
2741                                 0);
2742       g_object_unref (layout);
2743     }
2744 }
2745
2746 static void
2747 _clutter_actor_draw_paint_volume (ClutterActor *self)
2748 {
2749   ClutterPaintVolume *pv;
2750   CoglColor color;
2751
2752   pv = _clutter_actor_get_paint_volume_mutable (self);
2753   if (!pv)
2754     {
2755       gfloat width, height;
2756       ClutterPaintVolume fake_pv;
2757
2758       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2759       _clutter_paint_volume_init_static (&fake_pv, stage);
2760
2761       clutter_actor_get_size (self, &width, &height);
2762       clutter_paint_volume_set_width (&fake_pv, width);
2763       clutter_paint_volume_set_height (&fake_pv, height);
2764
2765       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2766       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2767                                              _clutter_actor_get_debug_name (self),
2768                                              &color);
2769
2770       clutter_paint_volume_free (&fake_pv);
2771     }
2772   else
2773     {
2774       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2775       _clutter_actor_draw_paint_volume_full (self, pv,
2776                                              _clutter_actor_get_debug_name (self),
2777                                              &color);
2778     }
2779 }
2780
2781 static void
2782 _clutter_actor_paint_cull_result (ClutterActor *self,
2783                                   gboolean success,
2784                                   ClutterCullResult result)
2785 {
2786   ClutterPaintVolume *pv;
2787   CoglColor color;
2788
2789   if (success)
2790     {
2791       if (result == CLUTTER_CULL_RESULT_IN)
2792         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2793       else if (result == CLUTTER_CULL_RESULT_OUT)
2794         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2795       else
2796         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2797     }
2798   else
2799     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2800
2801   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2802     _clutter_actor_draw_paint_volume_full (self, pv,
2803                                            _clutter_actor_get_debug_name (self),
2804                                            &color);
2805   else
2806     {
2807       PangoLayout *layout;
2808       char *label =
2809         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2810       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2811       cogl_set_source_color (&color);
2812
2813       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2814       pango_layout_set_text (layout, label, -1);
2815       cogl_pango_render_layout (layout,
2816                                 0,
2817                                 0,
2818                                 &color,
2819                                 0);
2820       g_free (label);
2821       g_object_unref (layout);
2822     }
2823 }
2824
2825 static int clone_paint_level = 0;
2826
2827 void
2828 _clutter_actor_push_clone_paint (void)
2829 {
2830   clone_paint_level++;
2831 }
2832
2833 void
2834 _clutter_actor_pop_clone_paint (void)
2835 {
2836   clone_paint_level--;
2837 }
2838
2839 static gboolean
2840 in_clone_paint (void)
2841 {
2842   return clone_paint_level > 0;
2843 }
2844
2845 /* Returns TRUE if the actor can be ignored */
2846 /* FIXME: we should return a ClutterCullResult, and
2847  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2848  * means there's no point in trying to cull descendants of the current
2849  * node. */
2850 static gboolean
2851 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2852 {
2853   ClutterActorPrivate *priv = self->priv;
2854   ClutterActor *stage;
2855   const ClutterPlane *stage_clip;
2856
2857   if (!priv->last_paint_volume_valid)
2858     {
2859       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2860                     "->last_paint_volume_valid == FALSE",
2861                     _clutter_actor_get_debug_name (self));
2862       return FALSE;
2863     }
2864
2865   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2866     return FALSE;
2867
2868   stage = _clutter_actor_get_stage_internal (self);
2869   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2870   if (G_UNLIKELY (!stage_clip))
2871     {
2872       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2873                     "No stage clip set",
2874                     _clutter_actor_get_debug_name (self));
2875       return FALSE;
2876     }
2877
2878   if (cogl_get_draw_framebuffer () !=
2879       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2880     {
2881       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2882                     "Current framebuffer doesn't correspond to stage",
2883                     _clutter_actor_get_debug_name (self));
2884       return FALSE;
2885     }
2886
2887   *result_out =
2888     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2889   return TRUE;
2890 }
2891
2892 static void
2893 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2894 {
2895   ClutterActorPrivate *priv = self->priv;
2896   const ClutterPaintVolume *pv;
2897
2898   if (priv->last_paint_volume_valid)
2899     {
2900       clutter_paint_volume_free (&priv->last_paint_volume);
2901       priv->last_paint_volume_valid = FALSE;
2902     }
2903
2904   pv = clutter_actor_get_paint_volume (self);
2905   if (!pv)
2906     {
2907       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2908                     "Actor failed to report a paint volume",
2909                     _clutter_actor_get_debug_name (self));
2910       return;
2911     }
2912
2913   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2914
2915   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2916                                             NULL); /* eye coordinates */
2917
2918   priv->last_paint_volume_valid = TRUE;
2919 }
2920
2921 static inline gboolean
2922 actor_has_shader_data (ClutterActor *self)
2923 {
2924   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
2925 }
2926
2927 guint32
2928 _clutter_actor_get_pick_id (ClutterActor *self)
2929 {
2930   if (self->priv->pick_id < 0)
2931     return 0;
2932
2933   return self->priv->pick_id;
2934 }
2935
2936 /* This is the same as clutter_actor_add_effect except that it doesn't
2937    queue a redraw and it doesn't notify on the effect property */
2938 static void
2939 _clutter_actor_add_effect_internal (ClutterActor  *self,
2940                                     ClutterEffect *effect)
2941 {
2942   ClutterActorPrivate *priv = self->priv;
2943
2944   if (priv->effects == NULL)
2945     {
2946       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
2947       priv->effects->actor = self;
2948     }
2949
2950   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2951 }
2952
2953 /* This is the same as clutter_actor_remove_effect except that it doesn't
2954    queue a redraw and it doesn't notify on the effect property */
2955 static void
2956 _clutter_actor_remove_effect_internal (ClutterActor  *self,
2957                                        ClutterEffect *effect)
2958 {
2959   ClutterActorPrivate *priv = self->priv;
2960
2961   if (priv->effects == NULL)
2962     return;
2963
2964   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2965 }
2966
2967 static gboolean
2968 needs_flatten_effect (ClutterActor *self)
2969 {
2970   ClutterActorPrivate *priv = self->priv;
2971
2972   if (G_UNLIKELY (clutter_paint_debug_flags &
2973                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
2974     return FALSE;
2975
2976   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
2977     return TRUE;
2978   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
2979     {
2980       if (clutter_actor_get_paint_opacity (self) < 255 &&
2981           clutter_actor_has_overlaps (self))
2982         return TRUE;
2983     }
2984
2985   return FALSE;
2986 }
2987
2988 static void
2989 add_or_remove_flatten_effect (ClutterActor *self)
2990 {
2991   ClutterActorPrivate *priv = self->priv;
2992
2993   /* Add or remove the flatten effect depending on the
2994      offscreen-redirect property. */
2995   if (needs_flatten_effect (self))
2996     {
2997       if (priv->flatten_effect == NULL)
2998         {
2999           ClutterActorMeta *actor_meta;
3000           gint priority;
3001
3002           priv->flatten_effect = _clutter_flatten_effect_new ();
3003           /* Keep a reference to the effect so that we can queue
3004              redraws from it */
3005           g_object_ref_sink (priv->flatten_effect);
3006
3007           /* Set the priority of the effect to high so that it will
3008              always be applied to the actor first. It uses an internal
3009              priority so that it won't be visible to applications */
3010           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3011           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3012           _clutter_actor_meta_set_priority (actor_meta, priority);
3013
3014           /* This will add the effect without queueing a redraw */
3015           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3016         }
3017     }
3018   else
3019     {
3020       if (priv->flatten_effect != NULL)
3021         {
3022           /* Destroy the effect so that it will lose its fbo cache of
3023              the actor */
3024           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3025           g_object_unref (priv->flatten_effect);
3026           priv->flatten_effect = NULL;
3027         }
3028     }
3029 }
3030
3031 static void
3032 clutter_actor_real_paint (ClutterActor *actor)
3033 {
3034   ClutterActorPrivate *priv = actor->priv;
3035   ClutterActor *iter;
3036
3037   /* paint the background color, if set */
3038   if (priv->bg_color_set)
3039     {
3040       float width, height;
3041       guint8 real_alpha;
3042
3043       clutter_actor_box_get_size (&priv->allocation, &width, &height);
3044
3045       real_alpha = clutter_actor_get_paint_opacity_internal (actor)
3046                  * priv->bg_color.alpha
3047                  / 255;
3048
3049       cogl_set_source_color4ub (priv->bg_color.red,
3050                                 priv->bg_color.green,
3051                                 priv->bg_color.blue,
3052                                 real_alpha);
3053
3054       cogl_rectangle (0, 0, width, height);
3055     }
3056
3057   for (iter = priv->first_child;
3058        iter != NULL;
3059        iter = iter->priv->next_sibling)
3060     {
3061       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3062                     _clutter_actor_get_debug_name (iter),
3063                     _clutter_actor_get_debug_name (actor),
3064                     iter->priv->allocation.x1,
3065                     iter->priv->allocation.y1,
3066                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3067                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3068
3069       clutter_actor_paint (iter);
3070     }
3071 }
3072
3073 /**
3074  * clutter_actor_paint:
3075  * @self: A #ClutterActor
3076  *
3077  * Renders the actor to display.
3078  *
3079  * This function should not be called directly by applications.
3080  * Call clutter_actor_queue_redraw() to queue paints, instead.
3081  *
3082  * This function is context-aware, and will either cause a
3083  * regular paint or a pick paint.
3084  *
3085  * This function will emit the #ClutterActor::paint signal or
3086  * the #ClutterActor::pick signal, depending on the context.
3087  *
3088  * This function does not paint the actor if the actor is set to 0,
3089  * unless it is performing a pick paint.
3090  */
3091 void
3092 clutter_actor_paint (ClutterActor *self)
3093 {
3094   ClutterActorPrivate *priv;
3095   ClutterPickMode pick_mode;
3096   gboolean clip_set = FALSE;
3097   gboolean shader_applied = FALSE;
3098
3099   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3100                           "Actor real-paint counter",
3101                           "Increments each time any actor is painted",
3102                           0 /* no application private data */);
3103   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3104                           "Actor pick-paint counter",
3105                           "Increments each time any actor is painted "
3106                           "for picking",
3107                           0 /* no application private data */);
3108
3109   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3110
3111   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3112     return;
3113
3114   priv = self->priv;
3115
3116   pick_mode = _clutter_context_get_pick_mode ();
3117
3118   if (pick_mode == CLUTTER_PICK_NONE)
3119     priv->propagated_one_redraw = FALSE;
3120
3121   /* It's an important optimization that we consider painting of
3122    * actors with 0 opacity to be a NOP... */
3123   if (pick_mode == CLUTTER_PICK_NONE &&
3124       /* ignore top-levels, since they might be transparent */
3125       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3126       /* Use the override opacity if its been set */
3127       ((priv->opacity_override >= 0) ?
3128        priv->opacity_override : priv->opacity) == 0)
3129     return;
3130
3131   /* if we aren't paintable (not in a toplevel with all
3132    * parents paintable) then do nothing.
3133    */
3134   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3135     return;
3136
3137   /* mark that we are in the paint process */
3138   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3139
3140   cogl_push_matrix();
3141
3142   if (priv->enable_model_view_transform)
3143     {
3144       CoglMatrix matrix;
3145
3146       /* XXX: It could be better to cache the modelview with the actor
3147        * instead of progressively building up the transformations on
3148        * the matrix stack every time we paint. */
3149       cogl_get_modelview_matrix (&matrix);
3150       _clutter_actor_apply_modelview_transform (self, &matrix);
3151
3152 #ifdef CLUTTER_ENABLE_DEBUG
3153       /* Catch when out-of-band transforms have been made by actors not as part
3154        * of an apply_transform vfunc... */
3155       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3156         {
3157           CoglMatrix expected_matrix;
3158
3159           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3160                                                              &expected_matrix);
3161
3162           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3163             {
3164               GString *buf = g_string_sized_new (1024);
3165               ClutterActor *parent;
3166
3167               parent = self;
3168               while (parent != NULL)
3169                 {
3170                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3171
3172                   if (parent->priv->parent != NULL)
3173                     g_string_append (buf, "->");
3174
3175                   parent = parent->priv->parent;
3176                 }
3177
3178               g_warning ("Unexpected transform found when painting actor "
3179                          "\"%s\". This will be caused by one of the actor's "
3180                          "ancestors (%s) using the Cogl API directly to transform "
3181                          "children instead of using ::apply_transform().",
3182                          _clutter_actor_get_debug_name (self),
3183                          buf->str);
3184
3185               g_string_free (buf, TRUE);
3186             }
3187         }
3188 #endif /* CLUTTER_ENABLE_DEBUG */
3189
3190       cogl_set_modelview_matrix (&matrix);
3191     }
3192
3193   if (priv->has_clip)
3194     {
3195       cogl_clip_push_rectangle (priv->clip.x,
3196                                 priv->clip.y,
3197                                 priv->clip.x + priv->clip.width,
3198                                 priv->clip.y + priv->clip.height);
3199       clip_set = TRUE;
3200     }
3201   else if (priv->clip_to_allocation)
3202     {
3203       gfloat width, height;
3204
3205       width  = priv->allocation.x2 - priv->allocation.x1;
3206       height = priv->allocation.y2 - priv->allocation.y1;
3207
3208       cogl_clip_push_rectangle (0, 0, width, height);
3209       clip_set = TRUE;
3210     }
3211
3212   if (pick_mode == CLUTTER_PICK_NONE)
3213     {
3214       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3215
3216       /* We check whether we need to add the flatten effect before
3217          each paint so that we can avoid having a mechanism for
3218          applications to notify when the value of the
3219          has_overlaps virtual changes. */
3220       add_or_remove_flatten_effect (self);
3221     }
3222   else
3223     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3224
3225   /* We save the current paint volume so that the next time the
3226    * actor queues a redraw we can constrain the redraw to just
3227    * cover the union of the new bounding box and the old.
3228    *
3229    * We also fetch the current paint volume to perform culling so
3230    * we can avoid painting actors outside the current clip region.
3231    *
3232    * If we are painting inside a clone, we should neither update
3233    * the paint volume or use it to cull painting, since the paint
3234    * box represents the location of the source actor on the
3235    * screen.
3236    *
3237    * XXX: We are starting to do a lot of vertex transforms on
3238    * the CPU in a typical paint, so at some point we should
3239    * audit these and consider caching some things.
3240    *
3241    * NB: We don't perform culling while picking at this point because
3242    * clutter-stage.c doesn't setup the clipping planes appropriately.
3243    *
3244    * NB: We don't want to update the last-paint-volume during picking
3245    * because the last-paint-volume is used to determine the old screen
3246    * space location of an actor that has moved so we can know the
3247    * minimal region to redraw to clear an old view of the actor. If we
3248    * update this during picking then by the time we come around to
3249    * paint then the last-paint-volume would likely represent the new
3250    * actor position not the old.
3251    */
3252   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3253     {
3254       gboolean success;
3255       /* annoyingly gcc warns if uninitialized even though
3256        * the initialization is redundant :-( */
3257       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3258
3259       if (G_LIKELY ((clutter_paint_debug_flags &
3260                      (CLUTTER_DEBUG_DISABLE_CULLING |
3261                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3262                     (CLUTTER_DEBUG_DISABLE_CULLING |
3263                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3264         _clutter_actor_update_last_paint_volume (self);
3265
3266       success = cull_actor (self, &result);
3267
3268       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3269         _clutter_actor_paint_cull_result (self, success, result);
3270       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3271         goto done;
3272     }
3273
3274   if (priv->effects == NULL)
3275     {
3276       if (pick_mode == CLUTTER_PICK_NONE &&
3277           actor_has_shader_data (self))
3278         {
3279           _clutter_actor_shader_pre_paint (self, FALSE);
3280           shader_applied = TRUE;
3281         }
3282
3283       priv->next_effect_to_paint = NULL;
3284     }
3285   else
3286     priv->next_effect_to_paint =
3287       _clutter_meta_group_peek_metas (priv->effects);
3288
3289   clutter_actor_continue_paint (self);
3290
3291   if (shader_applied)
3292     _clutter_actor_shader_post_paint (self);
3293
3294   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3295                   pick_mode == CLUTTER_PICK_NONE))
3296     _clutter_actor_draw_paint_volume (self);
3297
3298 done:
3299   /* If we make it here then the actor has run through a complete
3300      paint run including all the effects so it's no longer dirty */
3301   if (pick_mode == CLUTTER_PICK_NONE)
3302     priv->is_dirty = FALSE;
3303
3304   if (clip_set)
3305     cogl_clip_pop();
3306
3307   cogl_pop_matrix();
3308
3309   /* paint sequence complete */
3310   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3311 }
3312
3313 /**
3314  * clutter_actor_continue_paint:
3315  * @self: A #ClutterActor
3316  *
3317  * Run the next stage of the paint sequence. This function should only
3318  * be called within the implementation of the ‘run’ virtual of a
3319  * #ClutterEffect. It will cause the run method of the next effect to
3320  * be applied, or it will paint the actual actor if the current effect
3321  * is the last effect in the chain.
3322  *
3323  * Since: 1.8
3324  */
3325 void
3326 clutter_actor_continue_paint (ClutterActor *self)
3327 {
3328   ClutterActorPrivate *priv;
3329
3330   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3331   /* This should only be called from with in the ‘run’ implementation
3332      of a ClutterEffect */
3333   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3334
3335   priv = self->priv;
3336
3337   /* Skip any effects that are disabled */
3338   while (priv->next_effect_to_paint &&
3339          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3340     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3341
3342   /* If this has come from the last effect then we'll just paint the
3343      actual actor */
3344   if (priv->next_effect_to_paint == NULL)
3345     {
3346       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3347         {
3348           g_signal_emit (self, actor_signals[PAINT], 0);
3349         }
3350       else
3351         {
3352           ClutterColor col = { 0, };
3353
3354           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3355
3356           /* Actor will then paint silhouette of itself in supplied
3357            * color.  See clutter_stage_get_actor_at_pos() for where
3358            * picking is enabled.
3359            */
3360           g_signal_emit (self, actor_signals[PICK], 0, &col);
3361         }
3362     }
3363   else
3364     {
3365       ClutterEffect *old_current_effect;
3366       ClutterEffectPaintFlags run_flags = 0;
3367
3368       /* Cache the current effect so that we can put it back before
3369          returning */
3370       old_current_effect = priv->current_effect;
3371
3372       priv->current_effect = priv->next_effect_to_paint->data;
3373       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3374
3375       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3376         {
3377           if (priv->is_dirty)
3378             {
3379               /* If there's an effect queued with this redraw then all
3380                  effects up to that one will be considered dirty. It
3381                  is expected the queued effect will paint the cached
3382                  image and not call clutter_actor_continue_paint again
3383                  (although it should work ok if it does) */
3384               if (priv->effect_to_redraw == NULL ||
3385                   priv->current_effect != priv->effect_to_redraw)
3386                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3387             }
3388
3389           _clutter_effect_paint (priv->current_effect, run_flags);
3390         }
3391       else
3392         {
3393           /* We can't determine when an actor has been modified since
3394              its last pick so lets just assume it has always been
3395              modified */
3396           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3397
3398           _clutter_effect_pick (priv->current_effect, run_flags);
3399         }
3400
3401       priv->current_effect = old_current_effect;
3402     }
3403 }
3404
3405 static ClutterActorTraverseVisitFlags
3406 invalidate_queue_redraw_entry (ClutterActor *self,
3407                                int           depth,
3408                                gpointer      user_data)
3409 {
3410   ClutterActorPrivate *priv = self->priv;
3411
3412   if (priv->queue_redraw_entry != NULL)
3413     {
3414       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3415       priv->queue_redraw_entry = NULL;
3416     }
3417
3418   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3419 }
3420
3421 static inline void
3422 remove_child (ClutterActor *self,
3423               ClutterActor *child)
3424 {
3425   ClutterActor *prev_sibling, *next_sibling;
3426
3427   prev_sibling = child->priv->prev_sibling;
3428   next_sibling = child->priv->next_sibling;
3429
3430   if (prev_sibling != NULL)
3431     prev_sibling->priv->next_sibling = next_sibling;
3432
3433   if (next_sibling != NULL)
3434     next_sibling->priv->prev_sibling = prev_sibling;
3435
3436   if (self->priv->first_child == child)
3437     self->priv->first_child = next_sibling;
3438
3439   if (self->priv->last_child == child)
3440     self->priv->last_child = prev_sibling;
3441
3442   child->priv->parent = NULL;
3443   child->priv->prev_sibling = NULL;
3444   child->priv->next_sibling = NULL;
3445 }
3446
3447 typedef enum {
3448   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3449   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3450   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3451   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3452   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3453   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3454
3455   /* default flags for public API */
3456   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3457                                     REMOVE_CHILD_EMIT_PARENT_SET |
3458                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3459                                     REMOVE_CHILD_CHECK_STATE |
3460                                     REMOVE_CHILD_FLUSH_QUEUE |
3461                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3462
3463   /* flags for legacy/deprecated API */
3464   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3465                                     REMOVE_CHILD_FLUSH_QUEUE |
3466                                     REMOVE_CHILD_EMIT_PARENT_SET |
3467                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3468 } ClutterActorRemoveChildFlags;
3469
3470 /*< private >
3471  * clutter_actor_remove_child_internal:
3472  * @self: a #ClutterActor
3473  * @child: the child of @self that has to be removed
3474  * @flags: control the removal operations
3475  *
3476  * Removes @child from the list of children of @self.
3477  */
3478 static void
3479 clutter_actor_remove_child_internal (ClutterActor                 *self,
3480                                      ClutterActor                 *child,
3481                                      ClutterActorRemoveChildFlags  flags)
3482 {
3483   ClutterActor *old_first, *old_last;
3484   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3485   gboolean flush_queue;
3486   gboolean notify_first_last;
3487   gboolean was_mapped;
3488
3489   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3490   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3491   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3492   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3493   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3494   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3495
3496   g_object_freeze_notify (G_OBJECT (self));
3497
3498   if (destroy_meta)
3499     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3500
3501   if (check_state)
3502     {
3503       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3504
3505       /* we need to unrealize *before* we set parent_actor to NULL,
3506        * because in an unrealize method actors are dissociating from the
3507        * stage, which means they need to be able to
3508        * clutter_actor_get_stage().
3509        *
3510        * yhis should unmap and unrealize, unless we're reparenting.
3511        */
3512       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3513     }
3514   else
3515     was_mapped = FALSE;
3516
3517   if (flush_queue)
3518     {
3519       /* We take this opportunity to invalidate any queue redraw entry
3520        * associated with the actor and descendants since we won't be able to
3521        * determine the appropriate stage after this.
3522        *
3523        * we do this after we updated the mapped state because actors might
3524        * end up queueing redraws inside their mapped/unmapped virtual
3525        * functions, and if we invalidate the redraw entry we could end up
3526        * with an inconsistent state and weird memory corruption. see
3527        * bugs:
3528        *
3529        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3530        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3531        */
3532       _clutter_actor_traverse (child,
3533                                0,
3534                                invalidate_queue_redraw_entry,
3535                                NULL,
3536                                NULL);
3537     }
3538
3539   old_first = self->priv->first_child;
3540   old_last = self->priv->last_child;
3541
3542   remove_child (self, child);
3543
3544   self->priv->n_children -= 1;
3545
3546   self->priv->age += 1;
3547
3548   /* clutter_actor_reparent() will emit ::parent-set for us */
3549   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3550     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3551
3552   /* if the child was mapped then we need to relayout ourselves to account
3553    * for the removed child
3554    */
3555   if (was_mapped)
3556     clutter_actor_queue_relayout (self);
3557
3558   /* we need to emit the signal before dropping the reference */
3559   if (emit_actor_removed)
3560     g_signal_emit_by_name (self, "actor-removed", child);
3561
3562   if (notify_first_last)
3563     {
3564       if (old_first != self->priv->first_child)
3565         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3566
3567       if (old_last != self->priv->last_child)
3568         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3569     }
3570
3571   g_object_thaw_notify (G_OBJECT (self));
3572
3573   /* remove the reference we acquired in clutter_actor_add_child() */
3574   g_object_unref (child);
3575 }
3576
3577 static const ClutterTransformInfo default_transform_info = {
3578   0.0, { 0, },          /* rotation-x */
3579   0.0, { 0, },          /* rotation-y */
3580   0.0, { 0, },          /* rotation-z */
3581
3582   1.0, 1.0, { 0, },     /* scale */
3583
3584   { 0, },               /* anchor */
3585 };
3586
3587 /*< private >
3588  * _clutter_actor_get_transform_info_or_defaults:
3589  * @self: a #ClutterActor
3590  *
3591  * Retrieves the ClutterTransformInfo structure associated to an actor.
3592  *
3593  * If the actor does not have a ClutterTransformInfo structure associated
3594  * to it, then the default structure will be returned.
3595  *
3596  * This function should only be used for getters.
3597  *
3598  * Return value: a const pointer to the ClutterTransformInfo structure
3599  */
3600 const ClutterTransformInfo *
3601 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3602 {
3603   ClutterTransformInfo *info;
3604
3605   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3606   if (info != NULL)
3607     return info;
3608
3609   return &default_transform_info;
3610 }
3611
3612 static void
3613 clutter_transform_info_free (gpointer data)
3614 {
3615   if (data != NULL)
3616     g_slice_free (ClutterTransformInfo, data);
3617 }
3618
3619 /*< private >
3620  * _clutter_actor_get_transform_info:
3621  * @self: a #ClutterActor
3622  *
3623  * Retrieves a pointer to the ClutterTransformInfo structure.
3624  *
3625  * If the actor does not have a ClutterTransformInfo associated to it, one
3626  * will be created and initialized to the default values.
3627  *
3628  * This function should be used for setters.
3629  *
3630  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3631  * instead.
3632  *
3633  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3634  *   structure
3635  */
3636 ClutterTransformInfo *
3637 _clutter_actor_get_transform_info (ClutterActor *self)
3638 {
3639   ClutterTransformInfo *info;
3640
3641   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3642   if (info == NULL)
3643     {
3644       info = g_slice_new (ClutterTransformInfo);
3645
3646       *info = default_transform_info;
3647
3648       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3649                                info,
3650                                clutter_transform_info_free);
3651     }
3652
3653   return info;
3654 }
3655
3656 /*< private >
3657  * clutter_actor_set_rotation_angle_internal:
3658  * @self: a #ClutterActor
3659  * @axis: the axis of the angle to change
3660  * @angle: the angle of rotation
3661  *
3662  * Sets the rotation angle on the given axis without affecting the
3663  * rotation center point.
3664  */
3665 static inline void
3666 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3667                                            ClutterRotateAxis  axis,
3668                                            gdouble            angle)
3669 {
3670   GObject *obj = G_OBJECT (self);
3671   ClutterTransformInfo *info;
3672
3673   info = _clutter_actor_get_transform_info (self);
3674
3675   g_object_freeze_notify (obj);
3676
3677   switch (axis)
3678     {
3679     case CLUTTER_X_AXIS:
3680       info->rx_angle = angle;
3681       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3682       break;
3683
3684     case CLUTTER_Y_AXIS:
3685       info->ry_angle = angle;
3686       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3687       break;
3688
3689     case CLUTTER_Z_AXIS:
3690       info->rz_angle = angle;
3691       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3692       break;
3693     }
3694
3695   self->priv->transform_valid = FALSE;
3696
3697   g_object_thaw_notify (obj);
3698
3699   clutter_actor_queue_redraw (self);
3700 }
3701
3702 /*< private >
3703  * clutter_actor_set_rotation_center_internal:
3704  * @self: a #ClutterActor
3705  * @axis: the axis of the center to change
3706  * @center: the coordinates of the rotation center
3707  *
3708  * Sets the rotation center on the given axis without affecting the
3709  * rotation angle.
3710  */
3711 static inline void
3712 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3713                                             ClutterRotateAxis    axis,
3714                                             const ClutterVertex *center)
3715 {
3716   GObject *obj = G_OBJECT (self);
3717   ClutterTransformInfo *info;
3718   ClutterVertex v = { 0, 0, 0 };
3719
3720   info = _clutter_actor_get_transform_info (self);
3721
3722   if (center != NULL)
3723     v = *center;
3724
3725   g_object_freeze_notify (obj);
3726
3727   switch (axis)
3728     {
3729     case CLUTTER_X_AXIS:
3730       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3731       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3732       break;
3733
3734     case CLUTTER_Y_AXIS:
3735       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3736       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3737       break;
3738
3739     case CLUTTER_Z_AXIS:
3740       /* if the previously set rotation center was fractional, then
3741        * setting explicit coordinates will have to notify the
3742        * :rotation-center-z-gravity property as well
3743        */
3744       if (info->rz_center.is_fractional)
3745         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3746
3747       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3748       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3749       break;
3750     }
3751
3752   self->priv->transform_valid = FALSE;
3753
3754   g_object_thaw_notify (obj);
3755
3756   clutter_actor_queue_redraw (self);
3757 }
3758
3759 static inline void
3760 clutter_actor_set_scale_factor (ClutterActor      *self,
3761                                 ClutterRotateAxis  axis,
3762                                 gdouble            factor)
3763 {
3764   GObject *obj = G_OBJECT (self);
3765   ClutterTransformInfo *info;
3766
3767   info = _clutter_actor_get_transform_info (self);
3768
3769   g_object_freeze_notify (obj);
3770
3771   switch (axis)
3772     {
3773     case CLUTTER_X_AXIS:
3774       info->scale_x = factor;
3775       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
3776       break;
3777
3778     case CLUTTER_Y_AXIS:
3779       info->scale_y = factor;
3780       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
3781       break;
3782
3783     default:
3784       g_assert_not_reached ();
3785     }
3786
3787   self->priv->transform_valid = FALSE;
3788
3789   clutter_actor_queue_redraw (self);
3790
3791   g_object_thaw_notify (obj);
3792 }
3793
3794 static inline void
3795 clutter_actor_set_scale_center (ClutterActor      *self,
3796                                 ClutterRotateAxis  axis,
3797                                 gfloat             coord)
3798 {
3799   GObject *obj = G_OBJECT (self);
3800   ClutterTransformInfo *info;
3801   gfloat center_x, center_y;
3802
3803   info = _clutter_actor_get_transform_info (self);
3804
3805   g_object_freeze_notify (obj);
3806
3807   /* get the current scale center coordinates */
3808   clutter_anchor_coord_get_units (self, &info->scale_center,
3809                                   &center_x,
3810                                   &center_y,
3811                                   NULL);
3812
3813   /* we need to notify this too, because setting explicit coordinates will
3814    * change the gravity as a side effect
3815    */
3816   if (info->scale_center.is_fractional)
3817     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
3818
3819   switch (axis)
3820     {
3821     case CLUTTER_X_AXIS:
3822       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
3823       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
3824       break;
3825
3826     case CLUTTER_Y_AXIS:
3827       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
3828       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
3829       break;
3830
3831     default:
3832       g_assert_not_reached ();
3833     }
3834
3835   self->priv->transform_valid = FALSE;
3836
3837   clutter_actor_queue_redraw (self);
3838
3839   g_object_thaw_notify (obj);
3840 }
3841
3842 static inline void
3843 clutter_actor_set_anchor_coord (ClutterActor      *self,
3844                                 ClutterRotateAxis  axis,
3845                                 gfloat             coord)
3846 {
3847   GObject *obj = G_OBJECT (self);
3848   ClutterTransformInfo *info;
3849   gfloat anchor_x, anchor_y;
3850
3851   info = _clutter_actor_get_transform_info (self);
3852
3853   g_object_freeze_notify (obj);
3854
3855   clutter_anchor_coord_get_units (self, &info->anchor,
3856                                   &anchor_x,
3857                                   &anchor_y,
3858                                   NULL);
3859
3860   if (info->anchor.is_fractional)
3861     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
3862
3863   switch (axis)
3864     {
3865     case CLUTTER_X_AXIS:
3866       clutter_anchor_coord_set_units (&info->anchor,
3867                                       coord,
3868                                       anchor_y,
3869                                       0.0);
3870       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
3871       break;
3872
3873     case CLUTTER_Y_AXIS:
3874       clutter_anchor_coord_set_units (&info->anchor,
3875                                       anchor_x,
3876                                       coord,
3877                                       0.0);
3878       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
3879       break;
3880
3881     default:
3882       g_assert_not_reached ();
3883     }
3884
3885   self->priv->transform_valid = FALSE;
3886
3887   clutter_actor_queue_redraw (self);
3888
3889   g_object_thaw_notify (obj);
3890 }
3891
3892 static void
3893 clutter_actor_set_property (GObject      *object,
3894                             guint         prop_id,
3895                             const GValue *value,
3896                             GParamSpec   *pspec)
3897 {
3898   ClutterActor *actor = CLUTTER_ACTOR (object);
3899   ClutterActorPrivate *priv = actor->priv;
3900
3901   switch (prop_id)
3902     {
3903     case PROP_X:
3904       clutter_actor_set_x (actor, g_value_get_float (value));
3905       break;
3906
3907     case PROP_Y:
3908       clutter_actor_set_y (actor, g_value_get_float (value));
3909       break;
3910
3911     case PROP_WIDTH:
3912       clutter_actor_set_width (actor, g_value_get_float (value));
3913       break;
3914
3915     case PROP_HEIGHT:
3916       clutter_actor_set_height (actor, g_value_get_float (value));
3917       break;
3918
3919     case PROP_FIXED_X:
3920       clutter_actor_set_x (actor, g_value_get_float (value));
3921       break;
3922
3923     case PROP_FIXED_Y:
3924       clutter_actor_set_y (actor, g_value_get_float (value));
3925       break;
3926
3927     case PROP_FIXED_POSITION_SET:
3928       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
3929       break;
3930
3931     case PROP_MIN_WIDTH:
3932       clutter_actor_set_min_width (actor, g_value_get_float (value));
3933       break;
3934
3935     case PROP_MIN_HEIGHT:
3936       clutter_actor_set_min_height (actor, g_value_get_float (value));
3937       break;
3938
3939     case PROP_NATURAL_WIDTH:
3940       clutter_actor_set_natural_width (actor, g_value_get_float (value));
3941       break;
3942
3943     case PROP_NATURAL_HEIGHT:
3944       clutter_actor_set_natural_height (actor, g_value_get_float (value));
3945       break;
3946
3947     case PROP_MIN_WIDTH_SET:
3948       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
3949       break;
3950
3951     case PROP_MIN_HEIGHT_SET:
3952       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
3953       break;
3954
3955     case PROP_NATURAL_WIDTH_SET:
3956       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
3957       break;
3958
3959     case PROP_NATURAL_HEIGHT_SET:
3960       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
3961       break;
3962
3963     case PROP_REQUEST_MODE:
3964       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
3965       break;
3966
3967     case PROP_DEPTH:
3968       clutter_actor_set_depth (actor, g_value_get_float (value));
3969       break;
3970
3971     case PROP_OPACITY:
3972       clutter_actor_set_opacity (actor, g_value_get_uint (value));
3973       break;
3974
3975     case PROP_OFFSCREEN_REDIRECT:
3976       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
3977       break;
3978
3979     case PROP_NAME:
3980       clutter_actor_set_name (actor, g_value_get_string (value));
3981       break;
3982
3983     case PROP_VISIBLE:
3984       if (g_value_get_boolean (value) == TRUE)
3985         clutter_actor_show (actor);
3986       else
3987         clutter_actor_hide (actor);
3988       break;
3989
3990     case PROP_SCALE_X:
3991       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
3992                                       g_value_get_double (value));
3993       break;
3994
3995     case PROP_SCALE_Y:
3996       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
3997                                       g_value_get_double (value));
3998       break;
3999
4000     case PROP_SCALE_CENTER_X:
4001       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4002                                       g_value_get_float (value));
4003       break;
4004
4005     case PROP_SCALE_CENTER_Y:
4006       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4007                                       g_value_get_float (value));
4008       break;
4009
4010     case PROP_SCALE_GRAVITY:
4011       {
4012         const ClutterTransformInfo *info;
4013         ClutterGravity gravity;
4014
4015         info = _clutter_actor_get_transform_info_or_defaults (actor);
4016         gravity = g_value_get_enum (value);
4017
4018         clutter_actor_set_scale_with_gravity (actor,
4019                                               info->scale_x,
4020                                               info->scale_y,
4021                                               gravity);
4022       }
4023       break;
4024
4025     case PROP_CLIP:
4026       {
4027         const ClutterGeometry *geom = g_value_get_boxed (value);
4028
4029         clutter_actor_set_clip (actor,
4030                                 geom->x, geom->y,
4031                                 geom->width, geom->height);
4032       }
4033       break;
4034
4035     case PROP_CLIP_TO_ALLOCATION:
4036       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4037       break;
4038
4039     case PROP_REACTIVE:
4040       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4041       break;
4042
4043     case PROP_ROTATION_ANGLE_X:
4044       clutter_actor_set_rotation_angle_internal (actor,
4045                                                  CLUTTER_X_AXIS,
4046                                                  g_value_get_double (value));
4047       break;
4048
4049     case PROP_ROTATION_ANGLE_Y:
4050       clutter_actor_set_rotation_angle_internal (actor,
4051                                                  CLUTTER_Y_AXIS,
4052                                                  g_value_get_double (value));
4053       break;
4054
4055     case PROP_ROTATION_ANGLE_Z:
4056       clutter_actor_set_rotation_angle_internal (actor,
4057                                                  CLUTTER_Z_AXIS,
4058                                                  g_value_get_double (value));
4059       break;
4060
4061     case PROP_ROTATION_CENTER_X:
4062       clutter_actor_set_rotation_center_internal (actor,
4063                                                   CLUTTER_X_AXIS,
4064                                                   g_value_get_boxed (value));
4065       break;
4066
4067     case PROP_ROTATION_CENTER_Y:
4068       clutter_actor_set_rotation_center_internal (actor,
4069                                                   CLUTTER_Y_AXIS,
4070                                                   g_value_get_boxed (value));
4071       break;
4072
4073     case PROP_ROTATION_CENTER_Z:
4074       clutter_actor_set_rotation_center_internal (actor,
4075                                                   CLUTTER_Z_AXIS,
4076                                                   g_value_get_boxed (value));
4077       break;
4078
4079     case PROP_ROTATION_CENTER_Z_GRAVITY:
4080       {
4081         const ClutterTransformInfo *info;
4082
4083         info = _clutter_actor_get_transform_info_or_defaults (actor);
4084         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4085                                                    g_value_get_enum (value));
4086       }
4087       break;
4088
4089     case PROP_ANCHOR_X:
4090       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4091                                       g_value_get_float (value));
4092       break;
4093
4094     case PROP_ANCHOR_Y:
4095       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4096                                       g_value_get_float (value));
4097       break;
4098
4099     case PROP_ANCHOR_GRAVITY:
4100       clutter_actor_set_anchor_point_from_gravity (actor,
4101                                                    g_value_get_enum (value));
4102       break;
4103
4104     case PROP_SHOW_ON_SET_PARENT:
4105       priv->show_on_set_parent = g_value_get_boolean (value);
4106       break;
4107
4108     case PROP_TEXT_DIRECTION:
4109       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4110       break;
4111
4112     case PROP_ACTIONS:
4113       clutter_actor_add_action (actor, g_value_get_object (value));
4114       break;
4115
4116     case PROP_CONSTRAINTS:
4117       clutter_actor_add_constraint (actor, g_value_get_object (value));
4118       break;
4119
4120     case PROP_EFFECT:
4121       clutter_actor_add_effect (actor, g_value_get_object (value));
4122       break;
4123
4124     case PROP_LAYOUT_MANAGER:
4125       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4126       break;
4127
4128     case PROP_X_ALIGN:
4129       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4130       break;
4131
4132     case PROP_Y_ALIGN:
4133       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4134       break;
4135
4136     case PROP_MARGIN_TOP:
4137       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4138       break;
4139
4140     case PROP_MARGIN_BOTTOM:
4141       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4142       break;
4143
4144     case PROP_MARGIN_LEFT:
4145       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4146       break;
4147
4148     case PROP_MARGIN_RIGHT:
4149       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4150       break;
4151
4152     case PROP_BACKGROUND_COLOR:
4153       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4154       break;
4155
4156     default:
4157       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4158       break;
4159     }
4160 }
4161
4162 static void
4163 clutter_actor_get_property (GObject    *object,
4164                             guint       prop_id,
4165                             GValue     *value,
4166                             GParamSpec *pspec)
4167 {
4168   ClutterActor *actor = CLUTTER_ACTOR (object);
4169   ClutterActorPrivate *priv = actor->priv;
4170
4171   switch (prop_id)
4172     {
4173     case PROP_X:
4174       g_value_set_float (value, clutter_actor_get_x (actor));
4175       break;
4176
4177     case PROP_Y:
4178       g_value_set_float (value, clutter_actor_get_y (actor));
4179       break;
4180
4181     case PROP_WIDTH:
4182       g_value_set_float (value, clutter_actor_get_width (actor));
4183       break;
4184
4185     case PROP_HEIGHT:
4186       g_value_set_float (value, clutter_actor_get_height (actor));
4187       break;
4188
4189     case PROP_FIXED_X:
4190       {
4191         const ClutterLayoutInfo *info;
4192
4193         info = _clutter_actor_get_layout_info_or_defaults (actor);
4194         g_value_set_float (value, info->fixed_x);
4195       }
4196       break;
4197
4198     case PROP_FIXED_Y:
4199       {
4200         const ClutterLayoutInfo *info;
4201
4202         info = _clutter_actor_get_layout_info_or_defaults (actor);
4203         g_value_set_float (value, info->fixed_y);
4204       }
4205       break;
4206
4207     case PROP_FIXED_POSITION_SET:
4208       g_value_set_boolean (value, priv->position_set);
4209       break;
4210
4211     case PROP_MIN_WIDTH:
4212       {
4213         const ClutterLayoutInfo *info;
4214
4215         info = _clutter_actor_get_layout_info_or_defaults (actor);
4216         g_value_set_float (value, info->min_width);
4217       }
4218       break;
4219
4220     case PROP_MIN_HEIGHT:
4221       {
4222         const ClutterLayoutInfo *info;
4223
4224         info = _clutter_actor_get_layout_info_or_defaults (actor);
4225         g_value_set_float (value, info->min_height);
4226       }
4227       break;
4228
4229     case PROP_NATURAL_WIDTH:
4230       {
4231         const ClutterLayoutInfo *info;
4232
4233         info = _clutter_actor_get_layout_info_or_defaults (actor);
4234         g_value_set_float (value, info->natural_width);
4235       }
4236       break;
4237
4238     case PROP_NATURAL_HEIGHT:
4239       {
4240         const ClutterLayoutInfo *info;
4241
4242         info = _clutter_actor_get_layout_info_or_defaults (actor);
4243         g_value_set_float (value, info->natural_height);
4244       }
4245       break;
4246
4247     case PROP_MIN_WIDTH_SET:
4248       g_value_set_boolean (value, priv->min_width_set);
4249       break;
4250
4251     case PROP_MIN_HEIGHT_SET:
4252       g_value_set_boolean (value, priv->min_height_set);
4253       break;
4254
4255     case PROP_NATURAL_WIDTH_SET:
4256       g_value_set_boolean (value, priv->natural_width_set);
4257       break;
4258
4259     case PROP_NATURAL_HEIGHT_SET:
4260       g_value_set_boolean (value, priv->natural_height_set);
4261       break;
4262
4263     case PROP_REQUEST_MODE:
4264       g_value_set_enum (value, priv->request_mode);
4265       break;
4266
4267     case PROP_ALLOCATION:
4268       g_value_set_boxed (value, &priv->allocation);
4269       break;
4270
4271     case PROP_DEPTH:
4272       g_value_set_float (value, clutter_actor_get_depth (actor));
4273       break;
4274
4275     case PROP_OPACITY:
4276       g_value_set_uint (value, priv->opacity);
4277       break;
4278
4279     case PROP_OFFSCREEN_REDIRECT:
4280       g_value_set_enum (value, priv->offscreen_redirect);
4281       break;
4282
4283     case PROP_NAME:
4284       g_value_set_string (value, priv->name);
4285       break;
4286
4287     case PROP_VISIBLE:
4288       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4289       break;
4290
4291     case PROP_MAPPED:
4292       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4293       break;
4294
4295     case PROP_REALIZED:
4296       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4297       break;
4298
4299     case PROP_HAS_CLIP:
4300       g_value_set_boolean (value, priv->has_clip);
4301       break;
4302
4303     case PROP_CLIP:
4304       {
4305         ClutterGeometry clip;
4306
4307         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4308         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4309         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4310         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4311
4312         g_value_set_boxed (value, &clip);
4313       }
4314       break;
4315
4316     case PROP_CLIP_TO_ALLOCATION:
4317       g_value_set_boolean (value, priv->clip_to_allocation);
4318       break;
4319
4320     case PROP_SCALE_X:
4321       {
4322         const ClutterTransformInfo *info;
4323
4324         info = _clutter_actor_get_transform_info_or_defaults (actor);
4325         g_value_set_double (value, info->scale_x);
4326       }
4327       break;
4328
4329     case PROP_SCALE_Y:
4330       {
4331         const ClutterTransformInfo *info;
4332
4333         info = _clutter_actor_get_transform_info_or_defaults (actor);
4334         g_value_set_double (value, info->scale_y);
4335       }
4336       break;
4337
4338     case PROP_SCALE_CENTER_X:
4339       {
4340         gfloat center;
4341
4342         clutter_actor_get_scale_center (actor, &center, NULL);
4343
4344         g_value_set_float (value, center);
4345       }
4346       break;
4347
4348     case PROP_SCALE_CENTER_Y:
4349       {
4350         gfloat center;
4351
4352         clutter_actor_get_scale_center (actor, NULL, &center);
4353
4354         g_value_set_float (value, center);
4355       }
4356       break;
4357
4358     case PROP_SCALE_GRAVITY:
4359       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4360       break;
4361
4362     case PROP_REACTIVE:
4363       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4364       break;
4365
4366     case PROP_ROTATION_ANGLE_X:
4367       {
4368         const ClutterTransformInfo *info;
4369
4370         info = _clutter_actor_get_transform_info_or_defaults (actor);
4371         g_value_set_double (value, info->rx_angle);
4372       }
4373       break;
4374
4375     case PROP_ROTATION_ANGLE_Y:
4376       {
4377         const ClutterTransformInfo *info;
4378
4379         info = _clutter_actor_get_transform_info_or_defaults (actor);
4380         g_value_set_double (value, info->ry_angle);
4381       }
4382       break;
4383
4384     case PROP_ROTATION_ANGLE_Z:
4385       {
4386         const ClutterTransformInfo *info;
4387
4388         info = _clutter_actor_get_transform_info_or_defaults (actor);
4389         g_value_set_double (value, info->rz_angle);
4390       }
4391       break;
4392
4393     case PROP_ROTATION_CENTER_X:
4394       {
4395         ClutterVertex center;
4396
4397         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4398                                     &center.x,
4399                                     &center.y,
4400                                     &center.z);
4401
4402         g_value_set_boxed (value, &center);
4403       }
4404       break;
4405
4406     case PROP_ROTATION_CENTER_Y:
4407       {
4408         ClutterVertex center;
4409
4410         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4411                                     &center.x,
4412                                     &center.y,
4413                                     &center.z);
4414
4415         g_value_set_boxed (value, &center);
4416       }
4417       break;
4418
4419     case PROP_ROTATION_CENTER_Z:
4420       {
4421         ClutterVertex center;
4422
4423         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4424                                     &center.x,
4425                                     &center.y,
4426                                     &center.z);
4427
4428         g_value_set_boxed (value, &center);
4429       }
4430       break;
4431
4432     case PROP_ROTATION_CENTER_Z_GRAVITY:
4433       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4434       break;
4435
4436     case PROP_ANCHOR_X:
4437       {
4438         const ClutterTransformInfo *info;
4439         gfloat anchor_x;
4440
4441         info = _clutter_actor_get_transform_info_or_defaults (actor);
4442         clutter_anchor_coord_get_units (actor, &info->anchor,
4443                                         &anchor_x,
4444                                         NULL,
4445                                         NULL);
4446         g_value_set_float (value, anchor_x);
4447       }
4448       break;
4449
4450     case PROP_ANCHOR_Y:
4451       {
4452         const ClutterTransformInfo *info;
4453         gfloat anchor_y;
4454
4455         info = _clutter_actor_get_transform_info_or_defaults (actor);
4456         clutter_anchor_coord_get_units (actor, &info->anchor,
4457                                         NULL,
4458                                         &anchor_y,
4459                                         NULL);
4460         g_value_set_float (value, anchor_y);
4461       }
4462       break;
4463
4464     case PROP_ANCHOR_GRAVITY:
4465       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4466       break;
4467
4468     case PROP_SHOW_ON_SET_PARENT:
4469       g_value_set_boolean (value, priv->show_on_set_parent);
4470       break;
4471
4472     case PROP_TEXT_DIRECTION:
4473       g_value_set_enum (value, priv->text_direction);
4474       break;
4475
4476     case PROP_HAS_POINTER:
4477       g_value_set_boolean (value, priv->has_pointer);
4478       break;
4479
4480     case PROP_LAYOUT_MANAGER:
4481       g_value_set_object (value, priv->layout_manager);
4482       break;
4483
4484     case PROP_X_ALIGN:
4485       {
4486         const ClutterLayoutInfo *info;
4487
4488         info = _clutter_actor_get_layout_info_or_defaults (actor);
4489         g_value_set_enum (value, info->x_align);
4490       }
4491       break;
4492
4493     case PROP_Y_ALIGN:
4494       {
4495         const ClutterLayoutInfo *info;
4496
4497         info = _clutter_actor_get_layout_info_or_defaults (actor);
4498         g_value_set_enum (value, info->y_align);
4499       }
4500       break;
4501
4502     case PROP_MARGIN_TOP:
4503       {
4504         const ClutterLayoutInfo *info;
4505
4506         info = _clutter_actor_get_layout_info_or_defaults (actor);
4507         g_value_set_float (value, info->margin.top);
4508       }
4509       break;
4510
4511     case PROP_MARGIN_BOTTOM:
4512       {
4513         const ClutterLayoutInfo *info;
4514
4515         info = _clutter_actor_get_layout_info_or_defaults (actor);
4516         g_value_set_float (value, info->margin.bottom);
4517       }
4518       break;
4519
4520     case PROP_MARGIN_LEFT:
4521       {
4522         const ClutterLayoutInfo *info;
4523
4524         info = _clutter_actor_get_layout_info_or_defaults (actor);
4525         g_value_set_float (value, info->margin.left);
4526       }
4527       break;
4528
4529     case PROP_MARGIN_RIGHT:
4530       {
4531         const ClutterLayoutInfo *info;
4532
4533         info = _clutter_actor_get_layout_info_or_defaults (actor);
4534         g_value_set_float (value, info->margin.right);
4535       }
4536       break;
4537
4538     case PROP_BACKGROUND_COLOR_SET:
4539       g_value_set_boolean (value, priv->bg_color_set);
4540       break;
4541
4542     case PROP_BACKGROUND_COLOR:
4543       g_value_set_boxed (value, &priv->bg_color);
4544       break;
4545
4546     case PROP_FIRST_CHILD:
4547       g_value_set_object (value, priv->first_child);
4548       break;
4549
4550     case PROP_LAST_CHILD:
4551       g_value_set_object (value, priv->last_child);
4552       break;
4553
4554     default:
4555       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4556       break;
4557     }
4558 }
4559
4560 static void
4561 clutter_actor_dispose (GObject *object)
4562 {
4563   ClutterActor *self = CLUTTER_ACTOR (object);
4564   ClutterActorPrivate *priv = self->priv;
4565
4566   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4567                 priv->id,
4568                 g_type_name (G_OBJECT_TYPE (self)),
4569                 object->ref_count);
4570
4571   g_signal_emit (self, actor_signals[DESTROY], 0);
4572
4573   /* avoid recursing when called from clutter_actor_destroy() */
4574   if (priv->parent != NULL)
4575     {
4576       ClutterActor *parent = priv->parent;
4577
4578       /* go through the Container implementation unless this
4579        * is an internal child and has been marked as such.
4580        *
4581        * removing the actor from its parent will reset the
4582        * realized and mapped states.
4583        */
4584       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4585         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4586       else
4587         clutter_actor_remove_child_internal (parent, self,
4588                                              REMOVE_CHILD_LEGACY_FLAGS);
4589     }
4590
4591   /* parent must be gone at this point */
4592   g_assert (priv->parent == NULL);
4593
4594   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4595     {
4596       /* can't be mapped or realized with no parent */
4597       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4598       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4599     }
4600
4601   g_clear_object (&priv->pango_context);
4602   g_clear_object (&priv->actions);
4603   g_clear_object (&priv->constraints);
4604   g_clear_object (&priv->effects);
4605   g_clear_object (&priv->flatten_effect);
4606
4607   if (priv->layout_manager != NULL)
4608     {
4609       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4610       g_object_unref (priv->layout_manager);
4611       priv->layout_manager = NULL;
4612     }
4613
4614   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4615 }
4616
4617 static void
4618 clutter_actor_finalize (GObject *object)
4619 {
4620   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4621
4622   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4623                 priv->name != NULL ? priv->name : "<none>",
4624                 priv->id,
4625                 g_type_name (G_OBJECT_TYPE (object)));
4626
4627   _clutter_context_release_id (priv->id);
4628
4629   g_free (priv->name);
4630
4631   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4632 }
4633
4634
4635 /**
4636  * clutter_actor_get_accessible:
4637  * @self: a #ClutterActor
4638  *
4639  * Returns the accessible object that describes the actor to an
4640  * assistive technology.
4641  *
4642  * If no class-specific #AtkObject implementation is available for the
4643  * actor instance in question, it will inherit an #AtkObject
4644  * implementation from the first ancestor class for which such an
4645  * implementation is defined.
4646  *
4647  * The documentation of the <ulink
4648  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4649  * library contains more information about accessible objects and
4650  * their uses.
4651  *
4652  * Returns: (transfer none): the #AtkObject associated with @actor
4653  */
4654 AtkObject *
4655 clutter_actor_get_accessible (ClutterActor *self)
4656 {
4657   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4658
4659   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4660 }
4661
4662 static AtkObject *
4663 clutter_actor_real_get_accessible (ClutterActor *actor)
4664 {
4665   return atk_gobject_accessible_for_object (G_OBJECT (actor));
4666 }
4667
4668 static AtkObject *
4669 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4670 {
4671   AtkObject *accessible;
4672
4673   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4674   if (accessible != NULL)
4675     g_object_ref (accessible);
4676
4677   return accessible;
4678 }
4679
4680 static void
4681 atk_implementor_iface_init (AtkImplementorIface *iface)
4682 {
4683   iface->ref_accessible = _clutter_actor_ref_accessible;
4684 }
4685
4686 static gboolean
4687 clutter_actor_update_default_paint_volume (ClutterActor       *self,
4688                                            ClutterPaintVolume *volume)
4689 {
4690   ClutterActorPrivate *priv = self->priv;
4691   gboolean res = FALSE;
4692
4693   /* we start from the allocation */
4694   clutter_paint_volume_set_width (volume,
4695                                   priv->allocation.x2 - priv->allocation.x1);
4696   clutter_paint_volume_set_height (volume,
4697                                    priv->allocation.y2 - priv->allocation.y1);
4698
4699   /* if the actor has a clip set then we have a pretty definite
4700    * size for the paint volume: the actor cannot possibly paint
4701    * outside the clip region.
4702    */
4703   if (priv->clip_to_allocation)
4704     {
4705       /* the allocation has already been set, so we just flip the
4706        * return value
4707        */
4708       res = TRUE;
4709     }
4710   else
4711     {
4712       ClutterActor *child;
4713
4714       if (priv->has_clip &&
4715           priv->clip.width >= 0 &&
4716           priv->clip.height >= 0)
4717         {
4718           ClutterVertex origin;
4719
4720           origin.x = priv->clip.x;
4721           origin.y = priv->clip.y;
4722           origin.z = 0;
4723
4724           clutter_paint_volume_set_origin (volume, &origin);
4725           clutter_paint_volume_set_width (volume, priv->clip.width);
4726           clutter_paint_volume_set_height (volume, priv->clip.height);
4727
4728           res = TRUE;
4729         }
4730
4731       /* if we don't have children we just bail out here... */
4732       if (priv->n_children == 0)
4733         return res;
4734
4735       /* ...but if we have children then we ask for their paint volume in
4736        * our coordinates. if any of our children replies that it doesn't
4737        * have a paint volume, we bail out
4738        */
4739       for (child = priv->first_child;
4740            child != NULL;
4741            child = child->priv->next_sibling)
4742         {
4743           const ClutterPaintVolume *child_volume;
4744
4745           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4746           if (child_volume == NULL)
4747             {
4748               res = FALSE;
4749               break;
4750             }
4751
4752           clutter_paint_volume_union (volume, child_volume);
4753           res = TRUE;
4754         }
4755     }
4756
4757   return res;
4758
4759 }
4760
4761 static gboolean
4762 clutter_actor_real_get_paint_volume (ClutterActor       *self,
4763                                      ClutterPaintVolume *volume)
4764 {
4765   ClutterActorClass *klass;
4766   gboolean res;
4767
4768   klass = CLUTTER_ACTOR_GET_CLASS (self);
4769
4770   /* XXX - this thoroughly sucks, but we don't want to penalize users
4771    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
4772    * redraw. This should go away in 2.0.
4773    */
4774   if (klass->paint == clutter_actor_real_paint &&
4775       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
4776     {
4777       res = TRUE;
4778     }
4779   else
4780     {
4781       /* this is the default return value: we cannot know if a class
4782        * is going to paint outside its allocation, so we take the
4783        * conservative approach.
4784        */
4785       res = FALSE;
4786     }
4787
4788   if (clutter_actor_update_default_paint_volume (self, volume))
4789     return res;
4790
4791   return FALSE;
4792 }
4793
4794 /**
4795  * clutter_actor_get_default_paint_volume:
4796  * @self: a #ClutterActor
4797  *
4798  * Retrieves the default paint volume for @self.
4799  *
4800  * This function provides the same #ClutterPaintVolume that would be
4801  * computed by the default implementation inside #ClutterActor of the
4802  * #ClutterActorClass.get_paint_volume() virtual function.
4803  *
4804  * This function should only be used by #ClutterActor subclasses that
4805  * cannot chain up to the parent implementation when computing their
4806  * paint volume.
4807  *
4808  * Return value: (transfer none): a pointer to the default
4809  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
4810  *   the actor could not compute a valid paint volume. The returned value
4811  *   is not guaranteed to be stable across multiple frames, so if you
4812  *   want to retain it, you will need to copy it using
4813  *   clutter_paint_volume_copy().
4814  *
4815  * Since: 1.10
4816  */
4817 const ClutterPaintVolume *
4818 clutter_actor_get_default_paint_volume (ClutterActor *self)
4819 {
4820   ClutterPaintVolume volume;
4821   ClutterPaintVolume *res;
4822
4823   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4824
4825   res = NULL;
4826   _clutter_paint_volume_init_static (&volume, self);
4827   if (clutter_actor_update_default_paint_volume (self, &volume))
4828     {
4829       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
4830
4831       if (stage != NULL)
4832         {
4833           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
4834           _clutter_paint_volume_copy_static (&volume, res);
4835         }
4836     }
4837
4838   clutter_paint_volume_free (&volume);
4839
4840   return res;
4841 }
4842
4843 static gboolean
4844 clutter_actor_real_has_overlaps (ClutterActor *self)
4845 {
4846   /* By default we'll assume that all actors need an offscreen redirect to get
4847    * the correct opacity. Actors such as ClutterTexture that would never need
4848    * an offscreen redirect can override this to return FALSE. */
4849   return TRUE;
4850 }
4851
4852 static void
4853 clutter_actor_real_destroy (ClutterActor *actor)
4854 {
4855   ClutterActorIter iter;
4856
4857   clutter_actor_iter_init (&iter, actor);
4858   while (clutter_actor_iter_next (&iter, NULL))
4859     clutter_actor_iter_destroy (&iter);
4860 }
4861
4862 static GObject *
4863 clutter_actor_constructor (GType gtype,
4864                            guint n_props,
4865                            GObjectConstructParam *props)
4866 {
4867   GObjectClass *gobject_class;
4868   ClutterActor *self;
4869   GObject *retval;
4870
4871   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
4872   retval = gobject_class->constructor (gtype, n_props, props);
4873   self = CLUTTER_ACTOR (retval);
4874
4875   if (self->priv->layout_manager == NULL)
4876     {
4877       ClutterLayoutManager *default_layout;
4878
4879       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
4880
4881       default_layout = clutter_fixed_layout_new ();
4882       clutter_actor_set_layout_manager (self, default_layout);
4883     }
4884
4885   return retval;
4886 }
4887
4888 static void
4889 clutter_actor_class_init (ClutterActorClass *klass)
4890 {
4891   GObjectClass *object_class = G_OBJECT_CLASS (klass);
4892
4893   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
4894   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
4895   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
4896
4897   object_class->constructor = clutter_actor_constructor;
4898   object_class->set_property = clutter_actor_set_property;
4899   object_class->get_property = clutter_actor_get_property;
4900   object_class->dispose = clutter_actor_dispose;
4901   object_class->finalize = clutter_actor_finalize;
4902
4903   klass->show = clutter_actor_real_show;
4904   klass->show_all = clutter_actor_show;
4905   klass->hide = clutter_actor_real_hide;
4906   klass->hide_all = clutter_actor_hide;
4907   klass->map = clutter_actor_real_map;
4908   klass->unmap = clutter_actor_real_unmap;
4909   klass->unrealize = clutter_actor_real_unrealize;
4910   klass->pick = clutter_actor_real_pick;
4911   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
4912   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
4913   klass->allocate = clutter_actor_real_allocate;
4914   klass->queue_redraw = clutter_actor_real_queue_redraw;
4915   klass->queue_relayout = clutter_actor_real_queue_relayout;
4916   klass->apply_transform = clutter_actor_real_apply_transform;
4917   klass->get_accessible = clutter_actor_real_get_accessible;
4918   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
4919   klass->has_overlaps = clutter_actor_real_has_overlaps;
4920   klass->paint = clutter_actor_real_paint;
4921   klass->destroy = clutter_actor_real_destroy;
4922
4923   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
4924
4925   /**
4926    * ClutterActor:x:
4927    *
4928    * X coordinate of the actor in pixels. If written, forces a fixed
4929    * position for the actor. If read, returns the fixed position if any,
4930    * otherwise the allocation if available, otherwise 0.
4931    */
4932   obj_props[PROP_X] =
4933     g_param_spec_float ("x",
4934                         P_("X coordinate"),
4935                         P_("X coordinate of the actor"),
4936                         -G_MAXFLOAT, G_MAXFLOAT,
4937                         0.0,
4938                         CLUTTER_PARAM_READWRITE);
4939
4940   /**
4941    * ClutterActor:y:
4942    *
4943    * Y coordinate of the actor in pixels. If written, forces a fixed
4944    * position for the actor.  If read, returns the fixed position if
4945    * any, otherwise the allocation if available, otherwise 0.
4946    */
4947   obj_props[PROP_Y] =
4948     g_param_spec_float ("y",
4949                         P_("Y coordinate"),
4950                         P_("Y coordinate of the actor"),
4951                         -G_MAXFLOAT, G_MAXFLOAT,
4952                         0.0,
4953                         CLUTTER_PARAM_READWRITE);
4954
4955   /**
4956    * ClutterActor:width:
4957    *
4958    * Width of the actor (in pixels). If written, forces the minimum and
4959    * natural size request of the actor to the given width. If read, returns
4960    * the allocated width if available, otherwise the width request.
4961    */
4962   obj_props[PROP_WIDTH] =
4963     g_param_spec_float ("width",
4964                         P_("Width"),
4965                         P_("Width of the actor"),
4966                         0.0, G_MAXFLOAT,
4967                         0.0,
4968                         CLUTTER_PARAM_READWRITE);
4969
4970   /**
4971    * ClutterActor:height:
4972    *
4973    * Height of the actor (in pixels).  If written, forces the minimum and
4974    * natural size request of the actor to the given height. If read, returns
4975    * the allocated height if available, otherwise the height request.
4976    */
4977   obj_props[PROP_HEIGHT] =
4978     g_param_spec_float ("height",
4979                         P_("Height"),
4980                         P_("Height of the actor"),
4981                         0.0, G_MAXFLOAT,
4982                         0.0,
4983                         CLUTTER_PARAM_READWRITE);
4984
4985   /**
4986    * ClutterActor:fixed-x:
4987    *
4988    * The fixed X position of the actor in pixels.
4989    *
4990    * Writing this property sets #ClutterActor:fixed-position-set
4991    * property as well, as a side effect
4992    *
4993    * Since: 0.8
4994    */
4995   obj_props[PROP_FIXED_X] =
4996     g_param_spec_float ("fixed-x",
4997                         P_("Fixed X"),
4998                         P_("Forced X position of the actor"),
4999                         -G_MAXFLOAT, G_MAXFLOAT,
5000                         0.0,
5001                         CLUTTER_PARAM_READWRITE);
5002
5003   /**
5004    * ClutterActor:fixed-y:
5005    *
5006    * The fixed Y position of the actor in pixels.
5007    *
5008    * Writing this property sets the #ClutterActor:fixed-position-set
5009    * property as well, as a side effect
5010    *
5011    * Since: 0.8
5012    */
5013   obj_props[PROP_FIXED_Y] =
5014     g_param_spec_float ("fixed-y",
5015                         P_("Fixed Y"),
5016                         P_("Forced Y position of the actor"),
5017                         -G_MAXFLOAT, G_MAXFLOAT,
5018                         0,
5019                         CLUTTER_PARAM_READWRITE);
5020
5021   /**
5022    * ClutterActor:fixed-position-set:
5023    *
5024    * This flag controls whether the #ClutterActor:fixed-x and
5025    * #ClutterActor:fixed-y properties are used
5026    *
5027    * Since: 0.8
5028    */
5029   obj_props[PROP_FIXED_POSITION_SET] =
5030     g_param_spec_boolean ("fixed-position-set",
5031                           P_("Fixed position set"),
5032                           P_("Whether to use fixed positioning for the actor"),
5033                           FALSE,
5034                           CLUTTER_PARAM_READWRITE);
5035
5036   /**
5037    * ClutterActor:min-width:
5038    *
5039    * A forced minimum width request for the actor, in pixels
5040    *
5041    * Writing this property sets the #ClutterActor:min-width-set property
5042    * as well, as a side effect.
5043    *
5044    *This property overrides the usual width request of the actor.
5045    *
5046    * Since: 0.8
5047    */
5048   obj_props[PROP_MIN_WIDTH] =
5049     g_param_spec_float ("min-width",
5050                         P_("Min Width"),
5051                         P_("Forced minimum width request for the actor"),
5052                         0.0, G_MAXFLOAT,
5053                         0.0,
5054                         CLUTTER_PARAM_READWRITE);
5055
5056   /**
5057    * ClutterActor:min-height:
5058    *
5059    * A forced minimum height request for the actor, in pixels
5060    *
5061    * Writing this property sets the #ClutterActor:min-height-set property
5062    * as well, as a side effect. This property overrides the usual height
5063    * request of the actor.
5064    *
5065    * Since: 0.8
5066    */
5067   obj_props[PROP_MIN_HEIGHT] =
5068     g_param_spec_float ("min-height",
5069                         P_("Min Height"),
5070                         P_("Forced minimum height request for the actor"),
5071                         0.0, G_MAXFLOAT,
5072                         0.0,
5073                         CLUTTER_PARAM_READWRITE);
5074
5075   /**
5076    * ClutterActor:natural-width:
5077    *
5078    * A forced natural width request for the actor, in pixels
5079    *
5080    * Writing this property sets the #ClutterActor:natural-width-set
5081    * property as well, as a side effect. This property overrides the
5082    * usual width request of the actor
5083    *
5084    * Since: 0.8
5085    */
5086   obj_props[PROP_NATURAL_WIDTH] =
5087     g_param_spec_float ("natural-width",
5088                         P_("Natural Width"),
5089                         P_("Forced natural width request for the actor"),
5090                         0.0, G_MAXFLOAT,
5091                         0.0,
5092                         CLUTTER_PARAM_READWRITE);
5093
5094   /**
5095    * ClutterActor:natural-height:
5096    *
5097    * A forced natural height request for the actor, in pixels
5098    *
5099    * Writing this property sets the #ClutterActor:natural-height-set
5100    * property as well, as a side effect. This property overrides the
5101    * usual height request of the actor
5102    *
5103    * Since: 0.8
5104    */
5105   obj_props[PROP_NATURAL_HEIGHT] =
5106     g_param_spec_float ("natural-height",
5107                         P_("Natural Height"),
5108                         P_("Forced natural height request for the actor"),
5109                         0.0, G_MAXFLOAT,
5110                         0.0,
5111                         CLUTTER_PARAM_READWRITE);
5112
5113   /**
5114    * ClutterActor:min-width-set:
5115    *
5116    * This flag controls whether the #ClutterActor:min-width property
5117    * is used
5118    *
5119    * Since: 0.8
5120    */
5121   obj_props[PROP_MIN_WIDTH_SET] =
5122     g_param_spec_boolean ("min-width-set",
5123                           P_("Minimum width set"),
5124                           P_("Whether to use the min-width property"),
5125                           FALSE,
5126                           CLUTTER_PARAM_READWRITE);
5127
5128   /**
5129    * ClutterActor:min-height-set:
5130    *
5131    * This flag controls whether the #ClutterActor:min-height property
5132    * is used
5133    *
5134    * Since: 0.8
5135    */
5136   obj_props[PROP_MIN_HEIGHT_SET] =
5137     g_param_spec_boolean ("min-height-set",
5138                           P_("Minimum height set"),
5139                           P_("Whether to use the min-height property"),
5140                           FALSE,
5141                           CLUTTER_PARAM_READWRITE);
5142
5143   /**
5144    * ClutterActor:natural-width-set:
5145    *
5146    * This flag controls whether the #ClutterActor:natural-width property
5147    * is used
5148    *
5149    * Since: 0.8
5150    */
5151   obj_props[PROP_NATURAL_WIDTH_SET] =
5152     g_param_spec_boolean ("natural-width-set",
5153                           P_("Natural width set"),
5154                           P_("Whether to use the natural-width property"),
5155                           FALSE,
5156                           CLUTTER_PARAM_READWRITE);
5157
5158   /**
5159    * ClutterActor:natural-height-set:
5160    *
5161    * This flag controls whether the #ClutterActor:natural-height property
5162    * is used
5163    *
5164    * Since: 0.8
5165    */
5166   obj_props[PROP_NATURAL_HEIGHT_SET] =
5167     g_param_spec_boolean ("natural-height-set",
5168                           P_("Natural height set"),
5169                           P_("Whether to use the natural-height property"),
5170                           FALSE,
5171                           CLUTTER_PARAM_READWRITE);
5172
5173   /**
5174    * ClutterActor:allocation:
5175    *
5176    * The allocation for the actor, in pixels
5177    *
5178    * This is property is read-only, but you might monitor it to know when an
5179    * actor moves or resizes
5180    *
5181    * Since: 0.8
5182    */
5183   obj_props[PROP_ALLOCATION] =
5184     g_param_spec_boxed ("allocation",
5185                         P_("Allocation"),
5186                         P_("The actor's allocation"),
5187                         CLUTTER_TYPE_ACTOR_BOX,
5188                         CLUTTER_PARAM_READABLE);
5189
5190   /**
5191    * ClutterActor:request-mode:
5192    *
5193    * Request mode for the #ClutterActor. The request mode determines the
5194    * type of geometry management used by the actor, either height for width
5195    * (the default) or width for height.
5196    *
5197    * For actors implementing height for width, the parent container should get
5198    * the preferred width first, and then the preferred height for that width.
5199    *
5200    * For actors implementing width for height, the parent container should get
5201    * the preferred height first, and then the preferred width for that height.
5202    *
5203    * For instance:
5204    *
5205    * |[
5206    *   ClutterRequestMode mode;
5207    *   gfloat natural_width, min_width;
5208    *   gfloat natural_height, min_height;
5209    *
5210    *   mode = clutter_actor_get_request_mode (child);
5211    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5212    *     {
5213    *       clutter_actor_get_preferred_width (child, -1,
5214    *                                          &amp;min_width,
5215    *                                          &amp;natural_width);
5216    *       clutter_actor_get_preferred_height (child, natural_width,
5217    *                                           &amp;min_height,
5218    *                                           &amp;natural_height);
5219    *     }
5220    *   else
5221    *     {
5222    *       clutter_actor_get_preferred_height (child, -1,
5223    *                                           &amp;min_height,
5224    *                                           &amp;natural_height);
5225    *       clutter_actor_get_preferred_width (child, natural_height,
5226    *                                          &amp;min_width,
5227    *                                          &amp;natural_width);
5228    *     }
5229    * ]|
5230    *
5231    * will retrieve the minimum and natural width and height depending on the
5232    * preferred request mode of the #ClutterActor "child".
5233    *
5234    * The clutter_actor_get_preferred_size() function will implement this
5235    * check for you.
5236    *
5237    * Since: 0.8
5238    */
5239   obj_props[PROP_REQUEST_MODE] =
5240     g_param_spec_enum ("request-mode",
5241                        P_("Request Mode"),
5242                        P_("The actor's request mode"),
5243                        CLUTTER_TYPE_REQUEST_MODE,
5244                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5245                        CLUTTER_PARAM_READWRITE);
5246
5247   /**
5248    * ClutterActor:depth:
5249    *
5250    * The position of the actor on the Z axis
5251    *
5252    * Since: 0.6
5253    */
5254   obj_props[PROP_DEPTH] =
5255     g_param_spec_float ("depth",
5256                         P_("Depth"),
5257                         P_("Position on the Z axis"),
5258                         -G_MAXFLOAT, G_MAXFLOAT,
5259                         0.0,
5260                         CLUTTER_PARAM_READWRITE);
5261
5262   /**
5263    * ClutterActor:opacity:
5264    *
5265    * Opacity of an actor, between 0 (fully transparent) and
5266    * 255 (fully opaque)
5267    */
5268   obj_props[PROP_OPACITY] =
5269     g_param_spec_uint ("opacity",
5270                        P_("Opacity"),
5271                        P_("Opacity of an actor"),
5272                        0, 255,
5273                        255,
5274                        CLUTTER_PARAM_READWRITE);
5275
5276   /**
5277    * ClutterActor:offscreen-redirect:
5278    *
5279    * Determines the conditions in which the actor will be redirected
5280    * to an offscreen framebuffer while being painted. For example this
5281    * can be used to cache an actor in a framebuffer or for improved
5282    * handling of transparent actors. See
5283    * clutter_actor_set_offscreen_redirect() for details.
5284    *
5285    * Since: 1.8
5286    */
5287   obj_props[PROP_OFFSCREEN_REDIRECT] =
5288     g_param_spec_flags ("offscreen-redirect",
5289                         P_("Offscreen redirect"),
5290                         P_("Flags controlling when to flatten the actor into a single image"),
5291                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5292                         0,
5293                         CLUTTER_PARAM_READWRITE);
5294
5295   /**
5296    * ClutterActor:visible:
5297    *
5298    * Whether the actor is set to be visible or not
5299    *
5300    * See also #ClutterActor:mapped
5301    */
5302   obj_props[PROP_VISIBLE] =
5303     g_param_spec_boolean ("visible",
5304                           P_("Visible"),
5305                           P_("Whether the actor is visible or not"),
5306                           FALSE,
5307                           CLUTTER_PARAM_READWRITE);
5308
5309   /**
5310    * ClutterActor:mapped:
5311    *
5312    * Whether the actor is mapped (will be painted when the stage
5313    * to which it belongs is mapped)
5314    *
5315    * Since: 1.0
5316    */
5317   obj_props[PROP_MAPPED] =
5318     g_param_spec_boolean ("mapped",
5319                           P_("Mapped"),
5320                           P_("Whether the actor will be painted"),
5321                           FALSE,
5322                           CLUTTER_PARAM_READABLE);
5323
5324   /**
5325    * ClutterActor:realized:
5326    *
5327    * Whether the actor has been realized
5328    *
5329    * Since: 1.0
5330    */
5331   obj_props[PROP_REALIZED] =
5332     g_param_spec_boolean ("realized",
5333                           P_("Realized"),
5334                           P_("Whether the actor has been realized"),
5335                           FALSE,
5336                           CLUTTER_PARAM_READABLE);
5337
5338   /**
5339    * ClutterActor:reactive:
5340    *
5341    * Whether the actor is reactive to events or not
5342    *
5343    * Only reactive actors will emit event-related signals
5344    *
5345    * Since: 0.6
5346    */
5347   obj_props[PROP_REACTIVE] =
5348     g_param_spec_boolean ("reactive",
5349                           P_("Reactive"),
5350                           P_("Whether the actor is reactive to events"),
5351                           FALSE,
5352                           CLUTTER_PARAM_READWRITE);
5353
5354   /**
5355    * ClutterActor:has-clip:
5356    *
5357    * Whether the actor has the #ClutterActor:clip property set or not
5358    */
5359   obj_props[PROP_HAS_CLIP] =
5360     g_param_spec_boolean ("has-clip",
5361                           P_("Has Clip"),
5362                           P_("Whether the actor has a clip set"),
5363                           FALSE,
5364                           CLUTTER_PARAM_READABLE);
5365
5366   /**
5367    * ClutterActor:clip:
5368    *
5369    * The clip region for the actor, in actor-relative coordinates
5370    *
5371    * Every part of the actor outside the clip region will not be
5372    * painted
5373    */
5374   obj_props[PROP_CLIP] =
5375     g_param_spec_boxed ("clip",
5376                         P_("Clip"),
5377                         P_("The clip region for the actor"),
5378                         CLUTTER_TYPE_GEOMETRY,
5379                         CLUTTER_PARAM_READWRITE);
5380
5381   /**
5382    * ClutterActor:name:
5383    *
5384    * The name of the actor
5385    *
5386    * Since: 0.2
5387    */
5388   obj_props[PROP_NAME] =
5389     g_param_spec_string ("name",
5390                          P_("Name"),
5391                          P_("Name of the actor"),
5392                          NULL,
5393                          CLUTTER_PARAM_READWRITE);
5394
5395   /**
5396    * ClutterActor:scale-x:
5397    *
5398    * The horizontal scale of the actor
5399    *
5400    * Since: 0.6
5401    */
5402   obj_props[PROP_SCALE_X] =
5403     g_param_spec_double ("scale-x",
5404                          P_("Scale X"),
5405                          P_("Scale factor on the X axis"),
5406                          0.0, G_MAXDOUBLE,
5407                          1.0,
5408                          CLUTTER_PARAM_READWRITE);
5409
5410   /**
5411    * ClutterActor:scale-y:
5412    *
5413    * The vertical scale of the actor
5414    *
5415    * Since: 0.6
5416    */
5417   obj_props[PROP_SCALE_Y] =
5418     g_param_spec_double ("scale-y",
5419                          P_("Scale Y"),
5420                          P_("Scale factor on the Y axis"),
5421                          0.0, G_MAXDOUBLE,
5422                          1.0,
5423                          CLUTTER_PARAM_READWRITE);
5424
5425   /**
5426    * ClutterActor:scale-center-x:
5427    *
5428    * The horizontal center point for scaling
5429    *
5430    * Since: 1.0
5431    */
5432   obj_props[PROP_SCALE_CENTER_X] =
5433     g_param_spec_float ("scale-center-x",
5434                         P_("Scale Center X"),
5435                         P_("Horizontal scale center"),
5436                         -G_MAXFLOAT, G_MAXFLOAT,
5437                         0.0,
5438                         CLUTTER_PARAM_READWRITE);
5439
5440   /**
5441    * ClutterActor:scale-center-y:
5442    *
5443    * The vertical center point for scaling
5444    *
5445    * Since: 1.0
5446    */
5447   obj_props[PROP_SCALE_CENTER_Y] =
5448     g_param_spec_float ("scale-center-y",
5449                         P_("Scale Center Y"),
5450                         P_("Vertical scale center"),
5451                         -G_MAXFLOAT, G_MAXFLOAT,
5452                         0.0,
5453                         CLUTTER_PARAM_READWRITE);
5454
5455   /**
5456    * ClutterActor:scale-gravity:
5457    *
5458    * The center point for scaling expressed as a #ClutterGravity
5459    *
5460    * Since: 1.0
5461    */
5462   obj_props[PROP_SCALE_GRAVITY] =
5463     g_param_spec_enum ("scale-gravity",
5464                        P_("Scale Gravity"),
5465                        P_("The center of scaling"),
5466                        CLUTTER_TYPE_GRAVITY,
5467                        CLUTTER_GRAVITY_NONE,
5468                        CLUTTER_PARAM_READWRITE);
5469
5470   /**
5471    * ClutterActor:rotation-angle-x:
5472    *
5473    * The rotation angle on the X axis
5474    *
5475    * Since: 0.6
5476    */
5477   obj_props[PROP_ROTATION_ANGLE_X] =
5478     g_param_spec_double ("rotation-angle-x",
5479                          P_("Rotation Angle X"),
5480                          P_("The rotation angle on the X axis"),
5481                          -G_MAXDOUBLE, G_MAXDOUBLE,
5482                          0.0,
5483                          CLUTTER_PARAM_READWRITE);
5484
5485   /**
5486    * ClutterActor:rotation-angle-y:
5487    *
5488    * The rotation angle on the Y axis
5489    *
5490    * Since: 0.6
5491    */
5492   obj_props[PROP_ROTATION_ANGLE_Y] =
5493     g_param_spec_double ("rotation-angle-y",
5494                          P_("Rotation Angle Y"),
5495                          P_("The rotation angle on the Y axis"),
5496                          -G_MAXDOUBLE, G_MAXDOUBLE,
5497                          0.0,
5498                          CLUTTER_PARAM_READWRITE);
5499
5500   /**
5501    * ClutterActor:rotation-angle-z:
5502    *
5503    * The rotation angle on the Z axis
5504    *
5505    * Since: 0.6
5506    */
5507   obj_props[PROP_ROTATION_ANGLE_Z] =
5508     g_param_spec_double ("rotation-angle-z",
5509                          P_("Rotation Angle Z"),
5510                          P_("The rotation angle on the Z axis"),
5511                          -G_MAXDOUBLE, G_MAXDOUBLE,
5512                          0.0,
5513                          CLUTTER_PARAM_READWRITE);
5514
5515   /**
5516    * ClutterActor:rotation-center-x:
5517    *
5518    * The rotation center on the X axis.
5519    *
5520    * Since: 0.6
5521    */
5522   obj_props[PROP_ROTATION_CENTER_X] =
5523     g_param_spec_boxed ("rotation-center-x",
5524                         P_("Rotation Center X"),
5525                         P_("The rotation center on the X axis"),
5526                         CLUTTER_TYPE_VERTEX,
5527                         CLUTTER_PARAM_READWRITE);
5528
5529   /**
5530    * ClutterActor:rotation-center-y:
5531    *
5532    * The rotation center on the Y axis.
5533    *
5534    * Since: 0.6
5535    */
5536   obj_props[PROP_ROTATION_CENTER_Y] =
5537     g_param_spec_boxed ("rotation-center-y",
5538                         P_("Rotation Center Y"),
5539                         P_("The rotation center on the Y axis"),
5540                         CLUTTER_TYPE_VERTEX,
5541                         CLUTTER_PARAM_READWRITE);
5542
5543   /**
5544    * ClutterActor:rotation-center-z:
5545    *
5546    * The rotation center on the Z axis.
5547    *
5548    * Since: 0.6
5549    */
5550   obj_props[PROP_ROTATION_CENTER_Z] =
5551     g_param_spec_boxed ("rotation-center-z",
5552                         P_("Rotation Center Z"),
5553                         P_("The rotation center on the Z axis"),
5554                         CLUTTER_TYPE_VERTEX,
5555                         CLUTTER_PARAM_READWRITE);
5556
5557   /**
5558    * ClutterActor:rotation-center-z-gravity:
5559    *
5560    * The rotation center on the Z axis expressed as a #ClutterGravity.
5561    *
5562    * Since: 1.0
5563    */
5564   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5565     g_param_spec_enum ("rotation-center-z-gravity",
5566                        P_("Rotation Center Z Gravity"),
5567                        P_("Center point for rotation around the Z axis"),
5568                        CLUTTER_TYPE_GRAVITY,
5569                        CLUTTER_GRAVITY_NONE,
5570                        CLUTTER_PARAM_READWRITE);
5571
5572   /**
5573    * ClutterActor:anchor-x:
5574    *
5575    * The X coordinate of an actor's anchor point, relative to
5576    * the actor coordinate space, in pixels
5577    *
5578    * Since: 0.8
5579    */
5580   obj_props[PROP_ANCHOR_X] =
5581     g_param_spec_float ("anchor-x",
5582                         P_("Anchor X"),
5583                         P_("X coordinate of the anchor point"),
5584                         -G_MAXFLOAT, G_MAXFLOAT,
5585                         0,
5586                         CLUTTER_PARAM_READWRITE);
5587
5588   /**
5589    * ClutterActor:anchor-y:
5590    *
5591    * The Y coordinate of an actor's anchor point, relative to
5592    * the actor coordinate space, in pixels
5593    *
5594    * Since: 0.8
5595    */
5596   obj_props[PROP_ANCHOR_Y] =
5597     g_param_spec_float ("anchor-y",
5598                         P_("Anchor Y"),
5599                         P_("Y coordinate of the anchor point"),
5600                         -G_MAXFLOAT, G_MAXFLOAT,
5601                         0,
5602                         CLUTTER_PARAM_READWRITE);
5603
5604   /**
5605    * ClutterActor:anchor-gravity:
5606    *
5607    * The anchor point expressed as a #ClutterGravity
5608    *
5609    * Since: 1.0
5610    */
5611   obj_props[PROP_ANCHOR_GRAVITY] =
5612     g_param_spec_enum ("anchor-gravity",
5613                        P_("Anchor Gravity"),
5614                        P_("The anchor point as a ClutterGravity"),
5615                        CLUTTER_TYPE_GRAVITY,
5616                        CLUTTER_GRAVITY_NONE,
5617                        CLUTTER_PARAM_READWRITE);
5618
5619   /**
5620    * ClutterActor:show-on-set-parent:
5621    *
5622    * If %TRUE, the actor is automatically shown when parented.
5623    *
5624    * Calling clutter_actor_hide() on an actor which has not been
5625    * parented will set this property to %FALSE as a side effect.
5626    *
5627    * Since: 0.8
5628    */
5629   obj_props[PROP_SHOW_ON_SET_PARENT] =
5630     g_param_spec_boolean ("show-on-set-parent",
5631                           P_("Show on set parent"),
5632                           P_("Whether the actor is shown when parented"),
5633                           TRUE,
5634                           CLUTTER_PARAM_READWRITE);
5635
5636   /**
5637    * ClutterActor:clip-to-allocation:
5638    *
5639    * Whether the clip region should track the allocated area
5640    * of the actor.
5641    *
5642    * This property is ignored if a clip area has been explicitly
5643    * set using clutter_actor_set_clip().
5644    *
5645    * Since: 1.0
5646    */
5647   obj_props[PROP_CLIP_TO_ALLOCATION] =
5648     g_param_spec_boolean ("clip-to-allocation",
5649                           P_("Clip to Allocation"),
5650                           P_("Sets the clip region to track the actor's allocation"),
5651                           FALSE,
5652                           CLUTTER_PARAM_READWRITE);
5653
5654   /**
5655    * ClutterActor:text-direction:
5656    *
5657    * The direction of the text inside a #ClutterActor.
5658    *
5659    * Since: 1.0
5660    */
5661   obj_props[PROP_TEXT_DIRECTION] =
5662     g_param_spec_enum ("text-direction",
5663                        P_("Text Direction"),
5664                        P_("Direction of the text"),
5665                        CLUTTER_TYPE_TEXT_DIRECTION,
5666                        CLUTTER_TEXT_DIRECTION_LTR,
5667                        CLUTTER_PARAM_READWRITE);
5668
5669   /**
5670    * ClutterActor:has-pointer:
5671    *
5672    * Whether the actor contains the pointer of a #ClutterInputDevice
5673    * or not.
5674    *
5675    * Since: 1.2
5676    */
5677   obj_props[PROP_HAS_POINTER] =
5678     g_param_spec_boolean ("has-pointer",
5679                           P_("Has Pointer"),
5680                           P_("Whether the actor contains the pointer of an input device"),
5681                           FALSE,
5682                           CLUTTER_PARAM_READABLE);
5683
5684   /**
5685    * ClutterActor:actions:
5686    *
5687    * Adds a #ClutterAction to the actor
5688    *
5689    * Since: 1.4
5690    */
5691   obj_props[PROP_ACTIONS] =
5692     g_param_spec_object ("actions",
5693                          P_("Actions"),
5694                          P_("Adds an action to the actor"),
5695                          CLUTTER_TYPE_ACTION,
5696                          CLUTTER_PARAM_WRITABLE);
5697
5698   /**
5699    * ClutterActor:constraints:
5700    *
5701    * Adds a #ClutterConstraint to the actor
5702    *
5703    * Since: 1.4
5704    */
5705   obj_props[PROP_CONSTRAINTS] =
5706     g_param_spec_object ("constraints",
5707                          P_("Constraints"),
5708                          P_("Adds a constraint to the actor"),
5709                          CLUTTER_TYPE_CONSTRAINT,
5710                          CLUTTER_PARAM_WRITABLE);
5711
5712   /**
5713    * ClutterActor:effect:
5714    *
5715    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
5716    *
5717    * Since: 1.4
5718    */
5719   obj_props[PROP_EFFECT] =
5720     g_param_spec_object ("effect",
5721                          P_("Effect"),
5722                          P_("Add an effect to be applied on the actor"),
5723                          CLUTTER_TYPE_EFFECT,
5724                          CLUTTER_PARAM_WRITABLE);
5725
5726   /**
5727    * ClutterActor:layout-manager:
5728    *
5729    * A delegate object for controlling the layout of the children of
5730    * an actor.
5731    *
5732    * Since: 1.10
5733    */
5734   obj_props[PROP_LAYOUT_MANAGER] =
5735     g_param_spec_object ("layout-manager",
5736                          P_("Layout Manager"),
5737                          P_("The object controlling the layout of an actor's children"),
5738                          CLUTTER_TYPE_LAYOUT_MANAGER,
5739                          CLUTTER_PARAM_READWRITE);
5740
5741
5742   /**
5743    * ClutterActor:x-align:
5744    *
5745    * The alignment of an actor on the X axis, if the actor has been given
5746    * extra space for its allocation.
5747    *
5748    * Since: 1.10
5749    */
5750   obj_props[PROP_X_ALIGN] =
5751     g_param_spec_enum ("x-align",
5752                        P_("X Alignment"),
5753                        P_("The alignment of the actor on the X axis within its allocation"),
5754                        CLUTTER_TYPE_ACTOR_ALIGN,
5755                        CLUTTER_ACTOR_ALIGN_FILL,
5756                        CLUTTER_PARAM_READWRITE);
5757
5758   /**
5759    * ClutterActor:y-align:
5760    *
5761    * The alignment of an actor on the Y axis, if the actor has been given
5762    * extra space for its allocation.
5763    *
5764    * Since: 1.10
5765    */
5766   obj_props[PROP_Y_ALIGN] =
5767     g_param_spec_enum ("y-align",
5768                        P_("Y Alignment"),
5769                        P_("The alignment of the actor on the Y axis within its allocation"),
5770                        CLUTTER_TYPE_ACTOR_ALIGN,
5771                        CLUTTER_ACTOR_ALIGN_FILL,
5772                        CLUTTER_PARAM_READWRITE);
5773
5774   /**
5775    * ClutterActor:margin-top:
5776    *
5777    * The margin (in pixels) from the top of the actor.
5778    *
5779    * This property adds a margin to the actor's preferred size; the margin
5780    * will be automatically taken into account when allocating the actor.
5781    *
5782    * Since: 1.10
5783    */
5784   obj_props[PROP_MARGIN_TOP] =
5785     g_param_spec_float ("margin-top",
5786                         P_("Margin Top"),
5787                         P_("Extra space at the top"),
5788                         0.0, G_MAXFLOAT,
5789                         0.0,
5790                         CLUTTER_PARAM_READWRITE);
5791
5792   /**
5793    * ClutterActor:margin-bottom:
5794    *
5795    * The margin (in pixels) from the bottom of the actor.
5796    *
5797    * This property adds a margin to the actor's preferred size; the margin
5798    * will be automatically taken into account when allocating the actor.
5799    *
5800    * Since: 1.10
5801    */
5802   obj_props[PROP_MARGIN_BOTTOM] =
5803     g_param_spec_float ("margin-bottom",
5804                         P_("Margin Bottom"),
5805                         P_("Extra space at the bottom"),
5806                         0.0, G_MAXFLOAT,
5807                         0.0,
5808                         CLUTTER_PARAM_READWRITE);
5809
5810   /**
5811    * ClutterActor:margin-left:
5812    *
5813    * The margin (in pixels) from the left of the actor.
5814    *
5815    * This property adds a margin to the actor's preferred size; the margin
5816    * will be automatically taken into account when allocating the actor.
5817    *
5818    * Since: 1.10
5819    */
5820   obj_props[PROP_MARGIN_LEFT] =
5821     g_param_spec_float ("margin-left",
5822                         P_("Margin Left"),
5823                         P_("Extra space at the left"),
5824                         0.0, G_MAXFLOAT,
5825                         0.0,
5826                         CLUTTER_PARAM_READWRITE);
5827
5828   /**
5829    * ClutterActor:margin-right:
5830    *
5831    * The margin (in pixels) from the right of the actor.
5832    *
5833    * This property adds a margin to the actor's preferred size; the margin
5834    * will be automatically taken into account when allocating the actor.
5835    *
5836    * Since: 1.10
5837    */
5838   obj_props[PROP_MARGIN_RIGHT] =
5839     g_param_spec_float ("margin-right",
5840                         P_("Margin Right"),
5841                         P_("Extra space at the right"),
5842                         0.0, G_MAXFLOAT,
5843                         0.0,
5844                         CLUTTER_PARAM_READWRITE);
5845
5846   /**
5847    * ClutterActor:background-color-set:
5848    *
5849    * Whether the #ClutterActor:background-color property has been set.
5850    *
5851    * Since: 1.10
5852    */
5853   obj_props[PROP_BACKGROUND_COLOR_SET] =
5854     g_param_spec_boolean ("background-color-set",
5855                           P_("Background Color Set"),
5856                           P_("Whether the background color is set"),
5857                           FALSE,
5858                           CLUTTER_PARAM_READABLE);
5859
5860   /**
5861    * ClutterActor:background-color:
5862    *
5863    * Paints a solid fill of the actor's allocation using the specified
5864    * color.
5865    *
5866    * Since: 1.10
5867    */
5868   obj_props[PROP_BACKGROUND_COLOR] =
5869     clutter_param_spec_color ("background-color",
5870                               P_("Background color"),
5871                               P_("The actor's background color"),
5872                               CLUTTER_COLOR_Transparent,
5873                               CLUTTER_PARAM_READWRITE);
5874
5875   /**
5876    * ClutterActor:first-child:
5877    *
5878    * The actor's first child.
5879    *
5880    * Since: 1.10
5881    */
5882   obj_props[PROP_FIRST_CHILD] =
5883     g_param_spec_object ("first-child",
5884                          P_("First Child"),
5885                          P_("The actor's first child"),
5886                          CLUTTER_TYPE_ACTOR,
5887                          CLUTTER_PARAM_READABLE);
5888
5889   /**
5890    * ClutterActor:last-child:
5891    *
5892    * The actor's last child.
5893    *
5894    * Since: 1.10
5895    */
5896   obj_props[PROP_LAST_CHILD] =
5897     g_param_spec_object ("last-child",
5898                          P_("Last Child"),
5899                          P_("The actor's last child"),
5900                          CLUTTER_TYPE_ACTOR,
5901                          CLUTTER_PARAM_READABLE);
5902
5903   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
5904
5905   /**
5906    * ClutterActor::destroy:
5907    * @actor: the #ClutterActor which emitted the signal
5908    *
5909    * The ::destroy signal notifies that all references held on the
5910    * actor which emitted it should be released.
5911    *
5912    * The ::destroy signal should be used by all holders of a reference
5913    * on @actor.
5914    *
5915    * This signal might result in the finalization of the #ClutterActor
5916    * if all references are released.
5917    *
5918    * Composite actors and actors implementing the #ClutterContainer
5919    * interface should override the default implementation of the
5920    * class handler of this signal and call clutter_actor_destroy() on
5921    * their children. When overriding the default class handler, it is
5922    * required to chain up to the parent's implementation.
5923    *
5924    * Since: 0.2
5925    */
5926   actor_signals[DESTROY] =
5927     g_signal_new (I_("destroy"),
5928                   G_TYPE_FROM_CLASS (object_class),
5929                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
5930                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
5931                   NULL, NULL,
5932                   _clutter_marshal_VOID__VOID,
5933                   G_TYPE_NONE, 0);
5934   /**
5935    * ClutterActor::show:
5936    * @actor: the object which received the signal
5937    *
5938    * The ::show signal is emitted when an actor is visible and
5939    * rendered on the stage.
5940    *
5941    * Since: 0.2
5942    */
5943   actor_signals[SHOW] =
5944     g_signal_new (I_("show"),
5945                   G_TYPE_FROM_CLASS (object_class),
5946                   G_SIGNAL_RUN_FIRST,
5947                   G_STRUCT_OFFSET (ClutterActorClass, show),
5948                   NULL, NULL,
5949                   _clutter_marshal_VOID__VOID,
5950                   G_TYPE_NONE, 0);
5951   /**
5952    * ClutterActor::hide:
5953    * @actor: the object which received the signal
5954    *
5955    * The ::hide signal is emitted when an actor is no longer rendered
5956    * on the stage.
5957    *
5958    * Since: 0.2
5959    */
5960   actor_signals[HIDE] =
5961     g_signal_new (I_("hide"),
5962                   G_TYPE_FROM_CLASS (object_class),
5963                   G_SIGNAL_RUN_FIRST,
5964                   G_STRUCT_OFFSET (ClutterActorClass, hide),
5965                   NULL, NULL,
5966                   _clutter_marshal_VOID__VOID,
5967                   G_TYPE_NONE, 0);
5968   /**
5969    * ClutterActor::parent-set:
5970    * @actor: the object which received the signal
5971    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
5972    *
5973    * This signal is emitted when the parent of the actor changes.
5974    *
5975    * Since: 0.2
5976    */
5977   actor_signals[PARENT_SET] =
5978     g_signal_new (I_("parent-set"),
5979                   G_TYPE_FROM_CLASS (object_class),
5980                   G_SIGNAL_RUN_LAST,
5981                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
5982                   NULL, NULL,
5983                   _clutter_marshal_VOID__OBJECT,
5984                   G_TYPE_NONE, 1,
5985                   CLUTTER_TYPE_ACTOR);
5986
5987   /**
5988    * ClutterActor::queue-redraw:
5989    * @actor: the actor we're bubbling the redraw request through
5990    * @origin: the actor which initiated the redraw request
5991    *
5992    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
5993    * is called on @origin.
5994    *
5995    * The default implementation for #ClutterActor chains up to the
5996    * parent actor and queues a redraw on the parent, thus "bubbling"
5997    * the redraw queue up through the actor graph. The default
5998    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
5999    * in a main loop idle handler.
6000    *
6001    * Note that the @origin actor may be the stage, or a container; it
6002    * does not have to be a leaf node in the actor graph.
6003    *
6004    * Toolkits embedding a #ClutterStage which require a redraw and
6005    * relayout cycle can stop the emission of this signal using the
6006    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6007    * themselves, like:
6008    *
6009    * |[
6010    *   static void
6011    *   on_redraw_complete (gpointer data)
6012    *   {
6013    *     ClutterStage *stage = data;
6014    *
6015    *     /&ast; execute the Clutter drawing pipeline &ast;/
6016    *     clutter_stage_ensure_redraw (stage);
6017    *   }
6018    *
6019    *   static void
6020    *   on_stage_queue_redraw (ClutterStage *stage)
6021    *   {
6022    *     /&ast; this prevents the default handler to run &ast;/
6023    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6024    *
6025    *     /&ast; queue a redraw with the host toolkit and call
6026    *      &ast; a function when the redraw has been completed
6027    *      &ast;/
6028    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6029    *   }
6030    * ]|
6031    *
6032    * <note><para>This signal is emitted before the Clutter paint
6033    * pipeline is executed. If you want to know when the pipeline has
6034    * been completed you should connect to the ::paint signal on the
6035    * Stage with g_signal_connect_after().</para></note>
6036    *
6037    * Since: 1.0
6038    */
6039   actor_signals[QUEUE_REDRAW] =
6040     g_signal_new (I_("queue-redraw"),
6041                   G_TYPE_FROM_CLASS (object_class),
6042                   G_SIGNAL_RUN_LAST,
6043                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6044                   NULL, NULL,
6045                   _clutter_marshal_VOID__OBJECT,
6046                   G_TYPE_NONE, 1,
6047                   CLUTTER_TYPE_ACTOR);
6048
6049   /**
6050    * ClutterActor::queue-relayout
6051    * @actor: the actor being queued for relayout
6052    *
6053    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6054    * is called on an actor.
6055    *
6056    * The default implementation for #ClutterActor chains up to the
6057    * parent actor and queues a relayout on the parent, thus "bubbling"
6058    * the relayout queue up through the actor graph.
6059    *
6060    * The main purpose of this signal is to allow relayout to be propagated
6061    * properly in the procense of #ClutterClone actors. Applications will
6062    * not normally need to connect to this signal.
6063    *
6064    * Since: 1.2
6065    */
6066   actor_signals[QUEUE_RELAYOUT] =
6067     g_signal_new (I_("queue-relayout"),
6068                   G_TYPE_FROM_CLASS (object_class),
6069                   G_SIGNAL_RUN_LAST,
6070                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6071                   NULL, NULL,
6072                   _clutter_marshal_VOID__VOID,
6073                   G_TYPE_NONE, 0);
6074
6075   /**
6076    * ClutterActor::event:
6077    * @actor: the actor which received the event
6078    * @event: a #ClutterEvent
6079    *
6080    * The ::event signal is emitted each time an event is received
6081    * by the @actor. This signal will be emitted on every actor,
6082    * following the hierarchy chain, until it reaches the top-level
6083    * container (the #ClutterStage).
6084    *
6085    * Return value: %TRUE if the event has been handled by the actor,
6086    *   or %FALSE to continue the emission.
6087    *
6088    * Since: 0.6
6089    */
6090   actor_signals[EVENT] =
6091     g_signal_new (I_("event"),
6092                   G_TYPE_FROM_CLASS (object_class),
6093                   G_SIGNAL_RUN_LAST,
6094                   G_STRUCT_OFFSET (ClutterActorClass, event),
6095                   _clutter_boolean_handled_accumulator, NULL,
6096                   _clutter_marshal_BOOLEAN__BOXED,
6097                   G_TYPE_BOOLEAN, 1,
6098                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6099   /**
6100    * ClutterActor::button-press-event:
6101    * @actor: the actor which received the event
6102    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6103    *
6104    * The ::button-press-event signal is emitted each time a mouse button
6105    * is pressed on @actor.
6106    *
6107    * Return value: %TRUE if the event has been handled by the actor,
6108    *   or %FALSE to continue the emission.
6109    *
6110    * Since: 0.6
6111    */
6112   actor_signals[BUTTON_PRESS_EVENT] =
6113     g_signal_new (I_("button-press-event"),
6114                   G_TYPE_FROM_CLASS (object_class),
6115                   G_SIGNAL_RUN_LAST,
6116                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6117                   _clutter_boolean_handled_accumulator, NULL,
6118                   _clutter_marshal_BOOLEAN__BOXED,
6119                   G_TYPE_BOOLEAN, 1,
6120                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6121   /**
6122    * ClutterActor::button-release-event:
6123    * @actor: the actor which received the event
6124    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6125    *
6126    * The ::button-release-event signal is emitted each time a mouse button
6127    * is released on @actor.
6128    *
6129    * Return value: %TRUE if the event has been handled by the actor,
6130    *   or %FALSE to continue the emission.
6131    *
6132    * Since: 0.6
6133    */
6134   actor_signals[BUTTON_RELEASE_EVENT] =
6135     g_signal_new (I_("button-release-event"),
6136                   G_TYPE_FROM_CLASS (object_class),
6137                   G_SIGNAL_RUN_LAST,
6138                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6139                   _clutter_boolean_handled_accumulator, NULL,
6140                   _clutter_marshal_BOOLEAN__BOXED,
6141                   G_TYPE_BOOLEAN, 1,
6142                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6143   /**
6144    * ClutterActor::scroll-event:
6145    * @actor: the actor which received the event
6146    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6147    *
6148    * The ::scroll-event signal is emitted each time the mouse is
6149    * scrolled on @actor
6150    *
6151    * Return value: %TRUE if the event has been handled by the actor,
6152    *   or %FALSE to continue the emission.
6153    *
6154    * Since: 0.6
6155    */
6156   actor_signals[SCROLL_EVENT] =
6157     g_signal_new (I_("scroll-event"),
6158                   G_TYPE_FROM_CLASS (object_class),
6159                   G_SIGNAL_RUN_LAST,
6160                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6161                   _clutter_boolean_handled_accumulator, NULL,
6162                   _clutter_marshal_BOOLEAN__BOXED,
6163                   G_TYPE_BOOLEAN, 1,
6164                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6165   /**
6166    * ClutterActor::key-press-event:
6167    * @actor: the actor which received the event
6168    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6169    *
6170    * The ::key-press-event signal is emitted each time a keyboard button
6171    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6172    *
6173    * Return value: %TRUE if the event has been handled by the actor,
6174    *   or %FALSE to continue the emission.
6175    *
6176    * Since: 0.6
6177    */
6178   actor_signals[KEY_PRESS_EVENT] =
6179     g_signal_new (I_("key-press-event"),
6180                   G_TYPE_FROM_CLASS (object_class),
6181                   G_SIGNAL_RUN_LAST,
6182                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6183                   _clutter_boolean_handled_accumulator, NULL,
6184                   _clutter_marshal_BOOLEAN__BOXED,
6185                   G_TYPE_BOOLEAN, 1,
6186                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6187   /**
6188    * ClutterActor::key-release-event:
6189    * @actor: the actor which received the event
6190    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6191    *
6192    * The ::key-release-event signal is emitted each time a keyboard button
6193    * is released while @actor has key focus (see
6194    * clutter_stage_set_key_focus()).
6195    *
6196    * Return value: %TRUE if the event has been handled by the actor,
6197    *   or %FALSE to continue the emission.
6198    *
6199    * Since: 0.6
6200    */
6201   actor_signals[KEY_RELEASE_EVENT] =
6202     g_signal_new (I_("key-release-event"),
6203                   G_TYPE_FROM_CLASS (object_class),
6204                   G_SIGNAL_RUN_LAST,
6205                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6206                   _clutter_boolean_handled_accumulator, NULL,
6207                   _clutter_marshal_BOOLEAN__BOXED,
6208                   G_TYPE_BOOLEAN, 1,
6209                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6210   /**
6211    * ClutterActor::motion-event:
6212    * @actor: the actor which received the event
6213    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6214    *
6215    * The ::motion-event signal is emitted each time the mouse pointer is
6216    * moved over @actor.
6217    *
6218    * Return value: %TRUE if the event has been handled by the actor,
6219    *   or %FALSE to continue the emission.
6220    *
6221    * Since: 0.6
6222    */
6223   actor_signals[MOTION_EVENT] =
6224     g_signal_new (I_("motion-event"),
6225                   G_TYPE_FROM_CLASS (object_class),
6226                   G_SIGNAL_RUN_LAST,
6227                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6228                   _clutter_boolean_handled_accumulator, NULL,
6229                   _clutter_marshal_BOOLEAN__BOXED,
6230                   G_TYPE_BOOLEAN, 1,
6231                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6232
6233   /**
6234    * ClutterActor::key-focus-in:
6235    * @actor: the actor which now has key focus
6236    *
6237    * The ::key-focus-in signal is emitted when @actor receives key focus.
6238    *
6239    * Since: 0.6
6240    */
6241   actor_signals[KEY_FOCUS_IN] =
6242     g_signal_new (I_("key-focus-in"),
6243                   G_TYPE_FROM_CLASS (object_class),
6244                   G_SIGNAL_RUN_LAST,
6245                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6246                   NULL, NULL,
6247                   _clutter_marshal_VOID__VOID,
6248                   G_TYPE_NONE, 0);
6249
6250   /**
6251    * ClutterActor::key-focus-out:
6252    * @actor: the actor which now has key focus
6253    *
6254    * The ::key-focus-out signal is emitted when @actor loses key focus.
6255    *
6256    * Since: 0.6
6257    */
6258   actor_signals[KEY_FOCUS_OUT] =
6259     g_signal_new (I_("key-focus-out"),
6260                   G_TYPE_FROM_CLASS (object_class),
6261                   G_SIGNAL_RUN_LAST,
6262                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6263                   NULL, NULL,
6264                   _clutter_marshal_VOID__VOID,
6265                   G_TYPE_NONE, 0);
6266
6267   /**
6268    * ClutterActor::enter-event:
6269    * @actor: the actor which the pointer has entered.
6270    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6271    *
6272    * The ::enter-event signal is emitted when the pointer enters the @actor
6273    *
6274    * Return value: %TRUE if the event has been handled by the actor,
6275    *   or %FALSE to continue the emission.
6276    *
6277    * Since: 0.6
6278    */
6279   actor_signals[ENTER_EVENT] =
6280     g_signal_new (I_("enter-event"),
6281                   G_TYPE_FROM_CLASS (object_class),
6282                   G_SIGNAL_RUN_LAST,
6283                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6284                   _clutter_boolean_handled_accumulator, NULL,
6285                   _clutter_marshal_BOOLEAN__BOXED,
6286                   G_TYPE_BOOLEAN, 1,
6287                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6288
6289   /**
6290    * ClutterActor::leave-event:
6291    * @actor: the actor which the pointer has left
6292    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6293    *
6294    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6295    *
6296    * Return value: %TRUE if the event has been handled by the actor,
6297    *   or %FALSE to continue the emission.
6298    *
6299    * Since: 0.6
6300    */
6301   actor_signals[LEAVE_EVENT] =
6302     g_signal_new (I_("leave-event"),
6303                   G_TYPE_FROM_CLASS (object_class),
6304                   G_SIGNAL_RUN_LAST,
6305                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6306                   _clutter_boolean_handled_accumulator, NULL,
6307                   _clutter_marshal_BOOLEAN__BOXED,
6308                   G_TYPE_BOOLEAN, 1,
6309                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6310
6311   /**
6312    * ClutterActor::captured-event:
6313    * @actor: the actor which received the signal
6314    * @event: a #ClutterEvent
6315    *
6316    * The ::captured-event signal is emitted when an event is captured
6317    * by Clutter. This signal will be emitted starting from the top-level
6318    * container (the #ClutterStage) to the actor which received the event
6319    * going down the hierarchy. This signal can be used to intercept every
6320    * event before the specialized events (like
6321    * ClutterActor::button-press-event or ::key-released-event) are
6322    * emitted.
6323    *
6324    * Return value: %TRUE if the event has been handled by the actor,
6325    *   or %FALSE to continue the emission.
6326    *
6327    * Since: 0.6
6328    */
6329   actor_signals[CAPTURED_EVENT] =
6330     g_signal_new (I_("captured-event"),
6331                   G_TYPE_FROM_CLASS (object_class),
6332                   G_SIGNAL_RUN_LAST,
6333                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6334                   _clutter_boolean_handled_accumulator, NULL,
6335                   _clutter_marshal_BOOLEAN__BOXED,
6336                   G_TYPE_BOOLEAN, 1,
6337                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6338
6339   /**
6340    * ClutterActor::paint:
6341    * @actor: the #ClutterActor that received the signal
6342    *
6343    * The ::paint signal is emitted each time an actor is being painted.
6344    *
6345    * Subclasses of #ClutterActor should override the class signal handler
6346    * and paint themselves in that function.
6347    *
6348    * It is possible to connect a handler to the ::paint signal in order
6349    * to set up some custom aspect of a paint.
6350    *
6351    * Since: 0.8
6352    */
6353   actor_signals[PAINT] =
6354     g_signal_new (I_("paint"),
6355                   G_TYPE_FROM_CLASS (object_class),
6356                   G_SIGNAL_RUN_LAST,
6357                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6358                   NULL, NULL,
6359                   _clutter_marshal_VOID__VOID,
6360                   G_TYPE_NONE, 0);
6361   /**
6362    * ClutterActor::realize:
6363    * @actor: the #ClutterActor that received the signal
6364    *
6365    * The ::realize signal is emitted each time an actor is being
6366    * realized.
6367    *
6368    * Since: 0.8
6369    */
6370   actor_signals[REALIZE] =
6371     g_signal_new (I_("realize"),
6372                   G_TYPE_FROM_CLASS (object_class),
6373                   G_SIGNAL_RUN_LAST,
6374                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6375                   NULL, NULL,
6376                   _clutter_marshal_VOID__VOID,
6377                   G_TYPE_NONE, 0);
6378   /**
6379    * ClutterActor::unrealize:
6380    * @actor: the #ClutterActor that received the signal
6381    *
6382    * The ::unrealize signal is emitted each time an actor is being
6383    * unrealized.
6384    *
6385    * Since: 0.8
6386    */
6387   actor_signals[UNREALIZE] =
6388     g_signal_new (I_("unrealize"),
6389                   G_TYPE_FROM_CLASS (object_class),
6390                   G_SIGNAL_RUN_LAST,
6391                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6392                   NULL, NULL,
6393                   _clutter_marshal_VOID__VOID,
6394                   G_TYPE_NONE, 0);
6395
6396   /**
6397    * ClutterActor::pick:
6398    * @actor: the #ClutterActor that received the signal
6399    * @color: the #ClutterColor to be used when picking
6400    *
6401    * The ::pick signal is emitted each time an actor is being painted
6402    * in "pick mode". The pick mode is used to identify the actor during
6403    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6404    * The actor should paint its shape using the passed @pick_color.
6405    *
6406    * Subclasses of #ClutterActor should override the class signal handler
6407    * and paint themselves in that function.
6408    *
6409    * It is possible to connect a handler to the ::pick signal in order
6410    * to set up some custom aspect of a paint in pick mode.
6411    *
6412    * Since: 1.0
6413    */
6414   actor_signals[PICK] =
6415     g_signal_new (I_("pick"),
6416                   G_TYPE_FROM_CLASS (object_class),
6417                   G_SIGNAL_RUN_LAST,
6418                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6419                   NULL, NULL,
6420                   _clutter_marshal_VOID__BOXED,
6421                   G_TYPE_NONE, 1,
6422                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6423
6424   /**
6425    * ClutterActor::allocation-changed:
6426    * @actor: the #ClutterActor that emitted the signal
6427    * @box: a #ClutterActorBox with the new allocation
6428    * @flags: #ClutterAllocationFlags for the allocation
6429    *
6430    * The ::allocation-changed signal is emitted when the
6431    * #ClutterActor:allocation property changes. Usually, application
6432    * code should just use the notifications for the :allocation property
6433    * but if you want to track the allocation flags as well, for instance
6434    * to know whether the absolute origin of @actor changed, then you might
6435    * want use this signal instead.
6436    *
6437    * Since: 1.0
6438    */
6439   actor_signals[ALLOCATION_CHANGED] =
6440     g_signal_new (I_("allocation-changed"),
6441                   G_TYPE_FROM_CLASS (object_class),
6442                   G_SIGNAL_RUN_LAST,
6443                   0,
6444                   NULL, NULL,
6445                   _clutter_marshal_VOID__BOXED_FLAGS,
6446                   G_TYPE_NONE, 2,
6447                   CLUTTER_TYPE_ACTOR_BOX,
6448                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6449 }
6450
6451 static void
6452 clutter_actor_init (ClutterActor *self)
6453 {
6454   ClutterActorPrivate *priv;
6455
6456   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6457
6458   priv->id = _clutter_context_acquire_id (self);
6459   priv->pick_id = -1;
6460
6461   priv->opacity = 0xff;
6462   priv->show_on_set_parent = TRUE;
6463
6464   priv->needs_width_request = TRUE;
6465   priv->needs_height_request = TRUE;
6466   priv->needs_allocation = TRUE;
6467
6468   priv->cached_width_age = 1;
6469   priv->cached_height_age = 1;
6470
6471   priv->opacity_override = -1;
6472   priv->enable_model_view_transform = TRUE;
6473
6474   /* Initialize an empty paint volume to start with */
6475   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6476   priv->last_paint_volume_valid = TRUE;
6477
6478   priv->transform_valid = FALSE;
6479 }
6480
6481 /**
6482  * clutter_actor_new:
6483  *
6484  * Creates a new #ClutterActor.
6485  *
6486  * A newly created actor has a floating reference, which will be sunk
6487  * when it is added to another actor.
6488  *
6489  * Return value: (transfer full): the newly created #ClutterActor
6490  *
6491  * Since: 1.10
6492  */
6493 ClutterActor *
6494 clutter_actor_new (void)
6495 {
6496   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6497 }
6498
6499 /**
6500  * clutter_actor_destroy:
6501  * @self: a #ClutterActor
6502  *
6503  * Destroys an actor.  When an actor is destroyed, it will break any
6504  * references it holds to other objects.  If the actor is inside a
6505  * container, the actor will be removed.
6506  *
6507  * When you destroy a container, its children will be destroyed as well.
6508  *
6509  * Note: you cannot destroy the #ClutterStage returned by
6510  * clutter_stage_get_default().
6511  */
6512 void
6513 clutter_actor_destroy (ClutterActor *self)
6514 {
6515   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6516
6517   g_object_ref (self);
6518
6519   /* avoid recursion while destroying */
6520   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6521     {
6522       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6523
6524       g_object_run_dispose (G_OBJECT (self));
6525
6526       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6527     }
6528
6529   g_object_unref (self);
6530 }
6531
6532 void
6533 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6534                                     ClutterPaintVolume *clip)
6535 {
6536   ClutterActorPrivate *priv = self->priv;
6537   ClutterPaintVolume *pv;
6538   gboolean clipped;
6539
6540   /* If we've been explicitly passed a clip volume then there's
6541    * nothing more to calculate, but otherwise the only thing we know
6542    * is that the change is constrained to the given actor.
6543    *
6544    * The idea is that if we know the paint volume for where the actor
6545    * was last drawn (in eye coordinates) and we also have the paint
6546    * volume for where it will be drawn next (in actor coordinates)
6547    * then if we queue a redraw for both these volumes that will cover
6548    * everything that needs to be redrawn to clear the old view and
6549    * show the latest view of the actor.
6550    *
6551    * Don't clip this redraw if we don't know what position we had for
6552    * the previous redraw since we don't know where to set the clip so
6553    * it will clear the actor as it is currently.
6554    */
6555   if (clip)
6556     {
6557       _clutter_actor_set_queue_redraw_clip (self, clip);
6558       clipped = TRUE;
6559     }
6560   else if (G_LIKELY (priv->last_paint_volume_valid))
6561     {
6562       pv = _clutter_actor_get_paint_volume_mutable (self);
6563       if (pv)
6564         {
6565           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6566
6567           /* make sure we redraw the actors old position... */
6568           _clutter_actor_set_queue_redraw_clip (stage,
6569                                                 &priv->last_paint_volume);
6570           _clutter_actor_signal_queue_redraw (stage, stage);
6571           _clutter_actor_set_queue_redraw_clip (stage, NULL);
6572
6573           /* XXX: Ideally the redraw signal would take a clip volume
6574            * argument, but that would be an ABI break. Until we can
6575            * break the ABI we pass the argument out-of-band
6576            */
6577
6578           /* setup the clip for the actors new position... */
6579           _clutter_actor_set_queue_redraw_clip (self, pv);
6580           clipped = TRUE;
6581         }
6582       else
6583         clipped = FALSE;
6584     }
6585   else
6586     clipped = FALSE;
6587
6588   _clutter_actor_signal_queue_redraw (self, self);
6589
6590   /* Just in case anyone is manually firing redraw signals without
6591    * using the public queue_redraw() API we are careful to ensure that
6592    * our out-of-band clip member is cleared before returning...
6593    *
6594    * Note: A NULL clip denotes a full-stage, un-clipped redraw
6595    */
6596   if (G_LIKELY (clipped))
6597     _clutter_actor_set_queue_redraw_clip (self, NULL);
6598
6599   priv->queue_redraw_entry = NULL;
6600 }
6601
6602 static void
6603 _clutter_actor_get_allocation_clip (ClutterActor *self,
6604                                     ClutterActorBox *clip)
6605 {
6606   ClutterActorBox allocation;
6607
6608   /* XXX: we don't care if we get an out of date allocation here
6609    * because clutter_actor_queue_redraw_with_clip knows to ignore
6610    * the clip if the actor's allocation is invalid.
6611    *
6612    * This is noted because clutter_actor_get_allocation_box does some
6613    * unnecessary work to support buggy code with a comment suggesting
6614    * that it could be changed later which would be good for this use
6615    * case!
6616    */
6617   clutter_actor_get_allocation_box (self, &allocation);
6618
6619   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6620    * actor's own coordinate space but the allocation is in parent
6621    * coordinates */
6622   clip->x1 = 0;
6623   clip->y1 = 0;
6624   clip->x2 = allocation.x2 - allocation.x1;
6625   clip->y2 = allocation.y2 - allocation.y1;
6626 }
6627
6628 void
6629 _clutter_actor_queue_redraw_full (ClutterActor       *self,
6630                                   ClutterRedrawFlags  flags,
6631                                   ClutterPaintVolume *volume,
6632                                   ClutterEffect      *effect)
6633 {
6634   ClutterActorPrivate *priv = self->priv;
6635   ClutterPaintVolume allocation_pv;
6636   ClutterPaintVolume *pv;
6637   gboolean should_free_pv;
6638   ClutterActor *stage;
6639
6640   /* Here's an outline of the actor queue redraw mechanism:
6641    *
6642    * The process starts in one of the following two functions which
6643    * are wrappers for this function:
6644    * clutter_actor_queue_redraw
6645    * _clutter_actor_queue_redraw_with_clip
6646    *
6647    * additionally, an effect can queue a redraw by wrapping this
6648    * function in clutter_effect_queue_rerun
6649    *
6650    * This functions queues an entry in a list associated with the
6651    * stage which is a list of actors that queued a redraw while
6652    * updating the timelines, performing layouting and processing other
6653    * mainloop sources before the next paint starts.
6654    *
6655    * We aim to minimize the processing done at this point because
6656    * there is a good chance other events will happen while updating
6657    * the scenegraph that would invalidate any expensive work we might
6658    * otherwise try to do here. For example we don't try and resolve
6659    * the screen space bounding box of an actor at this stage so as to
6660    * minimize how much of the screen redraw because it's possible
6661    * something else will happen which will force a full redraw anyway.
6662    *
6663    * When all updates are complete and we come to paint the stage then
6664    * we iterate this list and actually emit the "queue-redraw" signals
6665    * for each of the listed actors which will bubble up to the stage
6666    * for each actor and at that point we will transform the actors
6667    * paint volume into screen coordinates to determine the clip region
6668    * for what needs to be redrawn in the next paint.
6669    *
6670    * Besides minimizing redundant work another reason for this
6671    * deferred design is that it's more likely we will be able to
6672    * determine the paint volume of an actor once we've finished
6673    * updating the scenegraph because its allocation should be up to
6674    * date. NB: If we can't determine an actors paint volume then we
6675    * can't automatically queue a clipped redraw which can make a big
6676    * difference to performance.
6677    *
6678    * So the control flow goes like this:
6679    * One of clutter_actor_queue_redraw,
6680    *        _clutter_actor_queue_redraw_with_clip
6681    *     or clutter_effect_queue_rerun
6682    *
6683    * then control moves to:
6684    *   _clutter_stage_queue_actor_redraw
6685    *
6686    * later during _clutter_stage_do_update, once relayouting is done
6687    * and the scenegraph has been updated we will call:
6688    * _clutter_stage_finish_queue_redraws
6689    *
6690    * _clutter_stage_finish_queue_redraws will call
6691    * _clutter_actor_finish_queue_redraw for each listed actor.
6692    * Note: actors *are* allowed to queue further redraws during this
6693    * process (considering clone actors or texture_new_from_actor which
6694    * respond to their source queueing a redraw by queuing a redraw
6695    * themselves). We repeat the process until the list is empty.
6696    *
6697    * This will result in the "queue-redraw" signal being fired for
6698    * each actor which will pass control to the default signal handler:
6699    * clutter_actor_real_queue_redraw
6700    *
6701    * This will bubble up to the stages handler:
6702    * clutter_stage_real_queue_redraw
6703    *
6704    * clutter_stage_real_queue_redraw will transform the actors paint
6705    * volume into screen space and add it as a clip region for the next
6706    * paint.
6707    */
6708
6709   /* ignore queueing a redraw for actors being destroyed */
6710   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6711     return;
6712
6713   stage = _clutter_actor_get_stage_internal (self);
6714
6715   /* Ignore queueing a redraw for actors not descended from a stage */
6716   if (stage == NULL)
6717     return;
6718
6719   /* ignore queueing a redraw on stages that are being destroyed */
6720   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
6721     return;
6722
6723   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
6724     {
6725       ClutterActorBox allocation_clip;
6726       ClutterVertex origin;
6727
6728       /* If the actor doesn't have a valid allocation then we will
6729        * queue a full stage redraw. */
6730       if (priv->needs_allocation)
6731         {
6732           /* NB: NULL denotes an undefined clip which will result in a
6733            * full redraw... */
6734           _clutter_actor_set_queue_redraw_clip (self, NULL);
6735           _clutter_actor_signal_queue_redraw (self, self);
6736           return;
6737         }
6738
6739       _clutter_paint_volume_init_static (&allocation_pv, self);
6740       pv = &allocation_pv;
6741
6742       _clutter_actor_get_allocation_clip (self, &allocation_clip);
6743
6744       origin.x = allocation_clip.x1;
6745       origin.y = allocation_clip.y1;
6746       origin.z = 0;
6747       clutter_paint_volume_set_origin (pv, &origin);
6748       clutter_paint_volume_set_width (pv,
6749                                       allocation_clip.x2 - allocation_clip.x1);
6750       clutter_paint_volume_set_height (pv,
6751                                        allocation_clip.y2 -
6752                                        allocation_clip.y1);
6753       should_free_pv = TRUE;
6754     }
6755   else
6756     {
6757       pv = volume;
6758       should_free_pv = FALSE;
6759     }
6760
6761   self->priv->queue_redraw_entry =
6762     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
6763                                        priv->queue_redraw_entry,
6764                                        self,
6765                                        pv);
6766
6767   if (should_free_pv)
6768     clutter_paint_volume_free (pv);
6769
6770   /* If this is the first redraw queued then we can directly use the
6771      effect parameter */
6772   if (!priv->is_dirty)
6773     priv->effect_to_redraw = effect;
6774   /* Otherwise we need to merge it with the existing effect parameter */
6775   else if (effect != NULL)
6776     {
6777       /* If there's already an effect then we need to use whichever is
6778          later in the chain of actors. Otherwise a full redraw has
6779          already been queued on the actor so we need to ignore the
6780          effect parameter */
6781       if (priv->effect_to_redraw != NULL)
6782         {
6783           if (priv->effects == NULL)
6784             g_warning ("Redraw queued with an effect that is "
6785                        "not applied to the actor");
6786           else
6787             {
6788               const GList *l;
6789
6790               for (l = _clutter_meta_group_peek_metas (priv->effects);
6791                    l != NULL;
6792                    l = l->next)
6793                 {
6794                   if (l->data == priv->effect_to_redraw ||
6795                       l->data == effect)
6796                     priv->effect_to_redraw = l->data;
6797                 }
6798             }
6799         }
6800     }
6801   else
6802     {
6803       /* If no effect is specified then we need to redraw the whole
6804          actor */
6805       priv->effect_to_redraw = NULL;
6806     }
6807
6808   priv->is_dirty = TRUE;
6809 }
6810
6811 /**
6812  * clutter_actor_queue_redraw:
6813  * @self: A #ClutterActor
6814  *
6815  * Queues up a redraw of an actor and any children. The redraw occurs
6816  * once the main loop becomes idle (after the current batch of events
6817  * has been processed, roughly).
6818  *
6819  * Applications rarely need to call this, as redraws are handled
6820  * automatically by modification functions.
6821  *
6822  * This function will not do anything if @self is not visible, or
6823  * if the actor is inside an invisible part of the scenegraph.
6824  *
6825  * Also be aware that painting is a NOP for actors with an opacity of
6826  * 0
6827  *
6828  * When you are implementing a custom actor you must queue a redraw
6829  * whenever some private state changes that will affect painting or
6830  * picking of your actor.
6831  */
6832 void
6833 clutter_actor_queue_redraw (ClutterActor *self)
6834 {
6835   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6836
6837   _clutter_actor_queue_redraw_full (self,
6838                                     0, /* flags */
6839                                     NULL, /* clip volume */
6840                                     NULL /* effect */);
6841 }
6842
6843 /*< private >
6844  * _clutter_actor_queue_redraw_with_clip:
6845  * @self: A #ClutterActor
6846  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
6847  *   this queue redraw.
6848  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
6849  *   redrawn or %NULL if you are just using a @flag to state your
6850  *   desired clipping.
6851  *
6852  * Queues up a clipped redraw of an actor and any children. The redraw
6853  * occurs once the main loop becomes idle (after the current batch of
6854  * events has been processed, roughly).
6855  *
6856  * If no flags are given the clip volume is defined by @volume
6857  * specified in actor coordinates and tells Clutter that only content
6858  * within this volume has been changed so Clutter can optionally
6859  * optimize the redraw.
6860  *
6861  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
6862  * should be %NULL and this tells Clutter to use the actor's current
6863  * allocation as a clip box. This flag can only be used for 2D actors,
6864  * because any actor with depth may be projected outside its
6865  * allocation.
6866  *
6867  * Applications rarely need to call this, as redraws are handled
6868  * automatically by modification functions.
6869  *
6870  * This function will not do anything if @self is not visible, or if
6871  * the actor is inside an invisible part of the scenegraph.
6872  *
6873  * Also be aware that painting is a NOP for actors with an opacity of
6874  * 0
6875  *
6876  * When you are implementing a custom actor you must queue a redraw
6877  * whenever some private state changes that will affect painting or
6878  * picking of your actor.
6879  */
6880 void
6881 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
6882                                        ClutterRedrawFlags  flags,
6883                                        ClutterPaintVolume *volume)
6884 {
6885   _clutter_actor_queue_redraw_full (self,
6886                                     flags, /* flags */
6887                                     volume, /* clip volume */
6888                                     NULL /* effect */);
6889 }
6890
6891 static void
6892 _clutter_actor_queue_only_relayout (ClutterActor *self)
6893 {
6894   ClutterActorPrivate *priv = self->priv;
6895
6896   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6897     return;
6898
6899   if (priv->needs_width_request &&
6900       priv->needs_height_request &&
6901       priv->needs_allocation)
6902     return; /* save some cpu cycles */
6903
6904 #if CLUTTER_ENABLE_DEBUG
6905   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
6906     {
6907       g_warning ("The actor '%s' is currently inside an allocation "
6908                  "cycle; calling clutter_actor_queue_relayout() is "
6909                  "not recommended",
6910                  _clutter_actor_get_debug_name (self));
6911     }
6912 #endif /* CLUTTER_ENABLE_DEBUG */
6913
6914   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
6915 }
6916
6917 /**
6918  * clutter_actor_queue_redraw_with_clip:
6919  * @self: a #ClutterActor
6920  * @clip: (allow-none): a rectangular clip region, or %NULL
6921  *
6922  * Queues a redraw on @self limited to a specific, actor-relative
6923  * rectangular area.
6924  *
6925  * If @clip is %NULL this function is equivalent to
6926  * clutter_actor_queue_redraw().
6927  *
6928  * Since: 1.10
6929  */
6930 void
6931 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
6932                                       const cairo_rectangle_int_t *clip)
6933 {
6934   ClutterPaintVolume volume;
6935   ClutterVertex origin;
6936
6937   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6938
6939   if (clip == NULL)
6940     {
6941       clutter_actor_queue_redraw (self);
6942       return;
6943     }
6944
6945   _clutter_paint_volume_init_static (&volume, self);
6946
6947   origin.x = clip->x;
6948   origin.y = clip->y;
6949   origin.z = 0.0f;
6950
6951   clutter_paint_volume_set_origin (&volume, &origin);
6952   clutter_paint_volume_set_width (&volume, clip->width);
6953   clutter_paint_volume_set_height (&volume, clip->height);
6954
6955   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
6956
6957   clutter_paint_volume_free (&volume);
6958 }
6959
6960 /**
6961  * clutter_actor_queue_relayout:
6962  * @self: A #ClutterActor
6963  *
6964  * Indicates that the actor's size request or other layout-affecting
6965  * properties may have changed. This function is used inside #ClutterActor
6966  * subclass implementations, not by applications directly.
6967  *
6968  * Queueing a new layout automatically queues a redraw as well.
6969  *
6970  * Since: 0.8
6971  */
6972 void
6973 clutter_actor_queue_relayout (ClutterActor *self)
6974 {
6975   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6976
6977   _clutter_actor_queue_only_relayout (self);
6978   clutter_actor_queue_redraw (self);
6979 }
6980
6981 /**
6982  * clutter_actor_get_preferred_size:
6983  * @self: a #ClutterActor
6984  * @min_width_p: (out) (allow-none): return location for the minimum
6985  *   width, or %NULL
6986  * @min_height_p: (out) (allow-none): return location for the minimum
6987  *   height, or %NULL
6988  * @natural_width_p: (out) (allow-none): return location for the natural
6989  *   width, or %NULL
6990  * @natural_height_p: (out) (allow-none): return location for the natural
6991  *   height, or %NULL
6992  *
6993  * Computes the preferred minimum and natural size of an actor, taking into
6994  * account the actor's geometry management (either height-for-width
6995  * or width-for-height).
6996  *
6997  * The width and height used to compute the preferred height and preferred
6998  * width are the actor's natural ones.
6999  *
7000  * If you need to control the height for the preferred width, or the width for
7001  * the preferred height, you should use clutter_actor_get_preferred_width()
7002  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7003  * geometry management using the #ClutterActor:request-mode property.
7004  *
7005  * Since: 0.8
7006  */
7007 void
7008 clutter_actor_get_preferred_size (ClutterActor *self,
7009                                   gfloat       *min_width_p,
7010                                   gfloat       *min_height_p,
7011                                   gfloat       *natural_width_p,
7012                                   gfloat       *natural_height_p)
7013 {
7014   ClutterActorPrivate *priv;
7015   gfloat min_width, min_height;
7016   gfloat natural_width, natural_height;
7017
7018   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7019
7020   priv = self->priv;
7021
7022   min_width = min_height = 0;
7023   natural_width = natural_height = 0;
7024
7025   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7026     {
7027       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7028       clutter_actor_get_preferred_width (self, -1,
7029                                          &min_width,
7030                                          &natural_width);
7031       clutter_actor_get_preferred_height (self, natural_width,
7032                                           &min_height,
7033                                           &natural_height);
7034     }
7035   else
7036     {
7037       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7038       clutter_actor_get_preferred_height (self, -1,
7039                                           &min_height,
7040                                           &natural_height);
7041       clutter_actor_get_preferred_width (self, natural_height,
7042                                          &min_width,
7043                                          &natural_width);
7044     }
7045
7046   if (min_width_p)
7047     *min_width_p = min_width;
7048
7049   if (min_height_p)
7050     *min_height_p = min_height;
7051
7052   if (natural_width_p)
7053     *natural_width_p = natural_width;
7054
7055   if (natural_height_p)
7056     *natural_height_p = natural_height;
7057 }
7058
7059 /*< private >
7060  * effective_align:
7061  * @align: a #ClutterActorAlign
7062  * @direction: a #ClutterTextDirection
7063  *
7064  * Retrieves the correct alignment depending on the text direction
7065  *
7066  * Return value: the effective alignment
7067  */
7068 static ClutterActorAlign
7069 effective_align (ClutterActorAlign    align,
7070                  ClutterTextDirection direction)
7071 {
7072   ClutterActorAlign res;
7073
7074   switch (align)
7075     {
7076     case CLUTTER_ACTOR_ALIGN_START:
7077       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7078           ? CLUTTER_ACTOR_ALIGN_END
7079           : CLUTTER_ACTOR_ALIGN_START;
7080       break;
7081
7082     case CLUTTER_ACTOR_ALIGN_END:
7083       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7084           ? CLUTTER_ACTOR_ALIGN_START
7085           : CLUTTER_ACTOR_ALIGN_END;
7086       break;
7087
7088     default:
7089       res = align;
7090       break;
7091     }
7092
7093   return res;
7094 }
7095
7096 static inline void
7097 adjust_for_margin (float  margin_start,
7098                    float  margin_end,
7099                    float *minimum_size,
7100                    float *natural_size,
7101                    float *allocated_start,
7102                    float *allocated_end)
7103 {
7104   *minimum_size -= (margin_start + margin_end);
7105   *natural_size -= (margin_start + margin_end);
7106   *allocated_start += margin_start;
7107   *allocated_end -= margin_end;
7108 }
7109
7110 static inline void
7111 adjust_for_alignment (ClutterActorAlign  alignment,
7112                       float              natural_size,
7113                       float             *allocated_start,
7114                       float             *allocated_end)
7115 {
7116   float allocated_size = *allocated_end - *allocated_start;
7117
7118   switch (alignment)
7119     {
7120     case CLUTTER_ACTOR_ALIGN_FILL:
7121       /* do nothing */
7122       break;
7123
7124     case CLUTTER_ACTOR_ALIGN_START:
7125       /* keep start */
7126       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7127       break;
7128
7129     case CLUTTER_ACTOR_ALIGN_END:
7130       if (allocated_size > natural_size)
7131         {
7132           *allocated_start += (allocated_size - natural_size);
7133           *allocated_end = *allocated_start + natural_size;
7134         }
7135       break;
7136
7137     case CLUTTER_ACTOR_ALIGN_CENTER:
7138       if (allocated_size > natural_size)
7139         {
7140           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7141           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7142         }
7143       break;
7144     }
7145 }
7146
7147 /*< private >
7148  * clutter_actor_adjust_width:
7149  * @self: a #ClutterActor
7150  * @minimum_width: (inout): the actor's preferred minimum width, which
7151  *   will be adjusted depending on the margin
7152  * @natural_width: (inout): the actor's preferred natural width, which
7153  *   will be adjusted depending on the margin
7154  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7155  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7156  *
7157  * Adjusts the preferred and allocated position and size of an actor,
7158  * depending on the margin and alignment properties.
7159  */
7160 static void
7161 clutter_actor_adjust_width (ClutterActor *self,
7162                             gfloat       *minimum_width,
7163                             gfloat       *natural_width,
7164                             gfloat       *adjusted_x1,
7165                             gfloat       *adjusted_x2)
7166 {
7167   ClutterTextDirection text_dir;
7168   const ClutterLayoutInfo *info;
7169
7170   info = _clutter_actor_get_layout_info_or_defaults (self);
7171   text_dir = clutter_actor_get_text_direction (self);
7172
7173   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7174
7175   /* this will tweak natural_width to remove the margin, so that
7176    * adjust_for_alignment() will use the correct size
7177    */
7178   adjust_for_margin (info->margin.left, info->margin.right,
7179                      minimum_width, natural_width,
7180                      adjusted_x1, adjusted_x2);
7181
7182   adjust_for_alignment (effective_align (info->x_align, text_dir),
7183                         *natural_width,
7184                         adjusted_x1, adjusted_x2);
7185 }
7186
7187 /*< private >
7188  * clutter_actor_adjust_height:
7189  * @self: a #ClutterActor
7190  * @minimum_height: (inout): the actor's preferred minimum height, which
7191  *   will be adjusted depending on the margin
7192  * @natural_height: (inout): the actor's preferred natural height, which
7193  *   will be adjusted depending on the margin
7194  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7195  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7196  *
7197  * Adjusts the preferred and allocated position and size of an actor,
7198  * depending on the margin and alignment properties.
7199  */
7200 static void
7201 clutter_actor_adjust_height (ClutterActor *self,
7202                              gfloat       *minimum_height,
7203                              gfloat       *natural_height,
7204                              gfloat       *adjusted_y1,
7205                              gfloat       *adjusted_y2)
7206 {
7207   const ClutterLayoutInfo *info;
7208
7209   info = _clutter_actor_get_layout_info_or_defaults (self);
7210
7211   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7212
7213   /* this will tweak natural_height to remove the margin, so that
7214    * adjust_for_alignment() will use the correct size
7215    */
7216   adjust_for_margin (info->margin.top, info->margin.bottom,
7217                      minimum_height, natural_height,
7218                      adjusted_y1,
7219                      adjusted_y2);
7220
7221   /* we don't use effective_align() here, because text direction
7222    * only affects the horizontal axis
7223    */
7224   adjust_for_alignment (info->y_align,
7225                         *natural_height,
7226                         adjusted_y1,
7227                         adjusted_y2);
7228
7229 }
7230
7231 /* looks for a cached size request for this for_size. If not
7232  * found, returns the oldest entry so it can be overwritten */
7233 static gboolean
7234 _clutter_actor_get_cached_size_request (gfloat         for_size,
7235                                         SizeRequest   *cached_size_requests,
7236                                         SizeRequest  **result)
7237 {
7238   guint i;
7239
7240   *result = &cached_size_requests[0];
7241
7242   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7243     {
7244       SizeRequest *sr;
7245
7246       sr = &cached_size_requests[i];
7247
7248       if (sr->age > 0 &&
7249           sr->for_size == for_size)
7250         {
7251           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7252           *result = sr;
7253           return TRUE;
7254         }
7255       else if (sr->age < (*result)->age)
7256         {
7257           *result = sr;
7258         }
7259     }
7260
7261   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7262
7263   return FALSE;
7264 }
7265
7266 /**
7267  * clutter_actor_get_preferred_width:
7268  * @self: A #ClutterActor
7269  * @for_height: available height when computing the preferred width,
7270  *   or a negative value to indicate that no height is defined
7271  * @min_width_p: (out) (allow-none): return location for minimum width,
7272  *   or %NULL
7273  * @natural_width_p: (out) (allow-none): return location for the natural
7274  *   width, or %NULL
7275  *
7276  * Computes the requested minimum and natural widths for an actor,
7277  * optionally depending on the specified height, or if they are
7278  * already computed, returns the cached values.
7279  *
7280  * An actor may not get its request - depending on the layout
7281  * manager that's in effect.
7282  *
7283  * A request should not incorporate the actor's scale or anchor point;
7284  * those transformations do not affect layout, only rendering.
7285  *
7286  * Since: 0.8
7287  */
7288 void
7289 clutter_actor_get_preferred_width (ClutterActor *self,
7290                                    gfloat        for_height,
7291                                    gfloat       *min_width_p,
7292                                    gfloat       *natural_width_p)
7293 {
7294   float request_min_width, request_natural_width;
7295   SizeRequest *cached_size_request;
7296   const ClutterLayoutInfo *info;
7297   ClutterActorPrivate *priv;
7298   gboolean found_in_cache;
7299
7300   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7301
7302   priv = self->priv;
7303
7304   info = _clutter_actor_get_layout_info_or_defaults (self);
7305
7306   /* we shortcircuit the case of a fixed size set using set_width() */
7307   if (priv->min_width_set && priv->natural_width_set)
7308     {
7309       if (min_width_p != NULL)
7310         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7311
7312       if (natural_width_p != NULL)
7313         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7314
7315       return;
7316     }
7317
7318   /* the remaining cases are:
7319    *
7320    *   - either min_width or natural_width have been set
7321    *   - neither min_width or natural_width have been set
7322    *
7323    * in both cases, we go through the cache (and through the actor in case
7324    * of cache misses) and determine the authoritative value depending on
7325    * the *_set flags.
7326    */
7327
7328   if (!priv->needs_width_request)
7329     {
7330       found_in_cache =
7331         _clutter_actor_get_cached_size_request (for_height,
7332                                                 priv->width_requests,
7333                                                 &cached_size_request);
7334     }
7335   else
7336     {
7337       /* if the actor needs a width request we use the first slot */
7338       found_in_cache = FALSE;
7339       cached_size_request = &priv->width_requests[0];
7340     }
7341
7342   if (!found_in_cache)
7343     {
7344       gfloat minimum_width, natural_width;
7345       ClutterActorClass *klass;
7346
7347       minimum_width = natural_width = 0;
7348
7349       /* adjust for the margin */
7350       if (for_height >= 0)
7351         {
7352           for_height -= (info->margin.top + info->margin.bottom);
7353           if (for_height < 0)
7354             for_height = 0;
7355         }
7356
7357       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7358
7359       klass = CLUTTER_ACTOR_GET_CLASS (self);
7360       klass->get_preferred_width (self, for_height,
7361                                   &minimum_width,
7362                                   &natural_width);
7363
7364       /* adjust for the margin */
7365       minimum_width += (info->margin.left + info->margin.right);
7366       natural_width += (info->margin.left + info->margin.right);
7367
7368       /* Due to accumulated float errors, it's better not to warn
7369        * on this, but just fix it.
7370        */
7371       if (natural_width < minimum_width)
7372         natural_width = minimum_width;
7373
7374       cached_size_request->min_size = minimum_width;
7375       cached_size_request->natural_size = natural_width;
7376       cached_size_request->for_size = for_height;
7377       cached_size_request->age = priv->cached_width_age;
7378
7379       priv->cached_width_age += 1;
7380       priv->needs_width_request = FALSE;
7381     }
7382
7383   if (!priv->min_width_set)
7384     request_min_width = cached_size_request->min_size;
7385   else
7386     request_min_width = info->min_width;
7387
7388   if (!priv->natural_width_set)
7389     request_natural_width = cached_size_request->natural_size;
7390   else
7391     request_natural_width = info->natural_width;
7392
7393   if (min_width_p)
7394     *min_width_p = request_min_width;
7395
7396   if (natural_width_p)
7397     *natural_width_p = request_natural_width;
7398 }
7399
7400 /**
7401  * clutter_actor_get_preferred_height:
7402  * @self: A #ClutterActor
7403  * @for_width: available width to assume in computing desired height,
7404  *   or a negative value to indicate that no width is defined
7405  * @min_height_p: (out) (allow-none): return location for minimum height,
7406  *   or %NULL
7407  * @natural_height_p: (out) (allow-none): return location for natural
7408  *   height, or %NULL
7409  *
7410  * Computes the requested minimum and natural heights for an actor,
7411  * or if they are already computed, returns the cached values.
7412  *
7413  * An actor may not get its request - depending on the layout
7414  * manager that's in effect.
7415  *
7416  * A request should not incorporate the actor's scale or anchor point;
7417  * those transformations do not affect layout, only rendering.
7418  *
7419  * Since: 0.8
7420  */
7421 void
7422 clutter_actor_get_preferred_height (ClutterActor *self,
7423                                     gfloat        for_width,
7424                                     gfloat       *min_height_p,
7425                                     gfloat       *natural_height_p)
7426 {
7427   float request_min_height, request_natural_height;
7428   SizeRequest *cached_size_request;
7429   const ClutterLayoutInfo *info;
7430   ClutterActorPrivate *priv;
7431   gboolean found_in_cache;
7432
7433   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7434
7435   priv = self->priv;
7436
7437   info = _clutter_actor_get_layout_info_or_defaults (self);
7438
7439   /* we shortcircuit the case of a fixed size set using set_height() */
7440   if (priv->min_height_set && priv->natural_height_set)
7441     {
7442       if (min_height_p != NULL)
7443         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7444
7445       if (natural_height_p != NULL)
7446         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7447
7448       return;
7449     }
7450
7451   /* the remaining cases are:
7452    *
7453    *   - either min_height or natural_height have been set
7454    *   - neither min_height or natural_height have been set
7455    *
7456    * in both cases, we go through the cache (and through the actor in case
7457    * of cache misses) and determine the authoritative value depending on
7458    * the *_set flags.
7459    */
7460
7461   if (!priv->needs_height_request)
7462     {
7463       found_in_cache =
7464         _clutter_actor_get_cached_size_request (for_width,
7465                                                 priv->height_requests,
7466                                                 &cached_size_request);
7467     }
7468   else
7469     {
7470       found_in_cache = FALSE;
7471       cached_size_request = &priv->height_requests[0];
7472     }
7473
7474   if (!found_in_cache)
7475     {
7476       gfloat minimum_height, natural_height;
7477       ClutterActorClass *klass;
7478
7479       minimum_height = natural_height = 0;
7480
7481       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7482
7483       /* adjust for margin */
7484       if (for_width >= 0)
7485         {
7486           for_width -= (info->margin.left + info->margin.right);
7487           if (for_width < 0)
7488             for_width = 0;
7489         }
7490
7491       klass = CLUTTER_ACTOR_GET_CLASS (self);
7492       klass->get_preferred_height (self, for_width,
7493                                    &minimum_height,
7494                                    &natural_height);
7495
7496       /* adjust for margin */
7497       minimum_height += (info->margin.top + info->margin.bottom);
7498       natural_height += (info->margin.top + info->margin.bottom);
7499
7500       /* Due to accumulated float errors, it's better not to warn
7501        * on this, but just fix it.
7502        */
7503       if (natural_height < minimum_height)
7504         natural_height = minimum_height;
7505
7506       cached_size_request->min_size = minimum_height;
7507       cached_size_request->natural_size = natural_height;
7508       cached_size_request->for_size = for_width;
7509       cached_size_request->age = priv->cached_height_age;
7510
7511       priv->cached_height_age += 1;
7512       priv->needs_height_request = FALSE;
7513     }
7514
7515   if (!priv->min_height_set)
7516     request_min_height = cached_size_request->min_size;
7517   else
7518     request_min_height = info->min_height;
7519
7520   if (!priv->natural_height_set)
7521     request_natural_height = cached_size_request->natural_size;
7522   else
7523     request_natural_height = info->natural_height;
7524
7525   if (min_height_p)
7526     *min_height_p = request_min_height;
7527
7528   if (natural_height_p)
7529     *natural_height_p = request_natural_height;
7530 }
7531
7532 /**
7533  * clutter_actor_get_allocation_box:
7534  * @self: A #ClutterActor
7535  * @box: (out): the function fills this in with the actor's allocation
7536  *
7537  * Gets the layout box an actor has been assigned. The allocation can
7538  * only be assumed valid inside a paint() method; anywhere else, it
7539  * may be out-of-date.
7540  *
7541  * An allocation does not incorporate the actor's scale or anchor point;
7542  * those transformations do not affect layout, only rendering.
7543  *
7544  * <note>Do not call any of the clutter_actor_get_allocation_*() family
7545  * of functions inside the implementation of the get_preferred_width()
7546  * or get_preferred_height() virtual functions.</note>
7547  *
7548  * Since: 0.8
7549  */
7550 void
7551 clutter_actor_get_allocation_box (ClutterActor    *self,
7552                                   ClutterActorBox *box)
7553 {
7554   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7555
7556   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7557    * which limits calling get_allocation to inside paint() basically; or
7558    * we can 2) force a layout, which could be expensive if someone calls
7559    * get_allocation somewhere silly; or we can 3) just return the latest
7560    * value, allowing it to be out-of-date, and assume people know what
7561    * they are doing.
7562    *
7563    * The least-surprises approach that keeps existing code working is
7564    * likely to be 2). People can end up doing some inefficient things,
7565    * though, and in general code that requires 2) is probably broken.
7566    */
7567
7568   /* this implements 2) */
7569   if (G_UNLIKELY (self->priv->needs_allocation))
7570     {
7571       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7572
7573       /* do not queue a relayout on an unparented actor */
7574       if (stage)
7575         _clutter_stage_maybe_relayout (stage);
7576     }
7577
7578   /* commenting out the code above and just keeping this assigment
7579    * implements 3)
7580    */
7581   *box = self->priv->allocation;
7582 }
7583
7584 /**
7585  * clutter_actor_get_allocation_geometry:
7586  * @self: A #ClutterActor
7587  * @geom: (out): allocation geometry in pixels
7588  *
7589  * Gets the layout box an actor has been assigned.  The allocation can
7590  * only be assumed valid inside a paint() method; anywhere else, it
7591  * may be out-of-date.
7592  *
7593  * An allocation does not incorporate the actor's scale or anchor point;
7594  * those transformations do not affect layout, only rendering.
7595  *
7596  * The returned rectangle is in pixels.
7597  *
7598  * Since: 0.8
7599  */
7600 void
7601 clutter_actor_get_allocation_geometry (ClutterActor    *self,
7602                                        ClutterGeometry *geom)
7603 {
7604   ClutterActorBox box;
7605
7606   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7607   g_return_if_fail (geom != NULL);
7608
7609   clutter_actor_get_allocation_box (self, &box);
7610
7611   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7612   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7613   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7614   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7615 }
7616
7617 static void
7618 clutter_actor_update_constraints (ClutterActor    *self,
7619                                   ClutterActorBox *allocation)
7620 {
7621   ClutterActorPrivate *priv = self->priv;
7622   const GList *constraints, *l;
7623
7624   if (priv->constraints == NULL)
7625     return;
7626
7627   constraints = _clutter_meta_group_peek_metas (priv->constraints);
7628   for (l = constraints; l != NULL; l = l->next)
7629     {
7630       ClutterConstraint *constraint = l->data;
7631       ClutterActorMeta *meta = l->data;
7632
7633       if (clutter_actor_meta_get_enabled (meta))
7634         {
7635           _clutter_constraint_update_allocation (constraint,
7636                                                  self,
7637                                                  allocation);
7638         }
7639     }
7640 }
7641
7642 /*< private >
7643  * clutter_actor_adjust_allocation:
7644  * @self: a #ClutterActor
7645  * @allocation: (inout): the allocation to adjust
7646  *
7647  * Adjusts the passed allocation box taking into account the actor's
7648  * layout information, like alignment, expansion, and margin.
7649  */
7650 static void
7651 clutter_actor_adjust_allocation (ClutterActor    *self,
7652                                  ClutterActorBox *allocation)
7653 {
7654   ClutterActorBox adj_allocation;
7655   float alloc_width, alloc_height;
7656   float min_width, min_height;
7657   float nat_width, nat_height;
7658   ClutterRequestMode req_mode;
7659
7660   adj_allocation = *allocation;
7661
7662   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
7663
7664   /* we want to hit the cache, so we use the public API */
7665   req_mode = clutter_actor_get_request_mode (self);
7666
7667   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7668     {
7669       clutter_actor_get_preferred_width (self, -1,
7670                                          &min_width,
7671                                          &nat_width);
7672       clutter_actor_get_preferred_height (self, alloc_width,
7673                                           &min_height,
7674                                           &nat_height);
7675     }
7676   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
7677     {
7678       clutter_actor_get_preferred_height (self, -1,
7679                                           &min_height,
7680                                           &nat_height);
7681       clutter_actor_get_preferred_height (self, alloc_height,
7682                                           &min_width,
7683                                           &nat_width);
7684     }
7685
7686 #ifdef CLUTTER_ENABLE_DEBUG
7687   /* warn about underallocations */
7688   if (_clutter_diagnostic_enabled () &&
7689       (floorf (min_width - alloc_width) > 0 ||
7690        floorf (min_height - alloc_height) > 0))
7691     {
7692       ClutterActor *parent = clutter_actor_get_parent (self);
7693
7694       /* the only actors that are allowed to be underallocated are the Stage,
7695        * as it doesn't have an implicit size, and Actors that specifically
7696        * told us that they want to opt-out from layout control mechanisms
7697        * through the NO_LAYOUT escape hatch.
7698        */
7699       if (parent != NULL &&
7700           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
7701         {
7702           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
7703                      "of %.2f x %.2f from its parent actor '%s', but its "
7704                      "requested minimum size is of %.2f x %.2f",
7705                      _clutter_actor_get_debug_name (self),
7706                      alloc_width, alloc_height,
7707                      _clutter_actor_get_debug_name (parent),
7708                      min_width, min_height);
7709         }
7710     }
7711 #endif
7712
7713   clutter_actor_adjust_width (self,
7714                               &min_width,
7715                               &nat_width,
7716                               &adj_allocation.x1,
7717                               &adj_allocation.x2);
7718
7719   clutter_actor_adjust_height (self,
7720                                &min_height,
7721                                &nat_height,
7722                                &adj_allocation.y1,
7723                                &adj_allocation.y2);
7724
7725   /* we maintain the invariant that an allocation cannot be adjusted
7726    * to be outside the parent-given box
7727    */
7728   if (adj_allocation.x1 < allocation->x1 ||
7729       adj_allocation.y1 < allocation->y1 ||
7730       adj_allocation.x2 > allocation->x2 ||
7731       adj_allocation.y2 > allocation->y2)
7732     {
7733       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
7734                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
7735                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
7736                  _clutter_actor_get_debug_name (self),
7737                  adj_allocation.x1, adj_allocation.y1,
7738                  adj_allocation.x2 - adj_allocation.x1,
7739                  adj_allocation.y2 - adj_allocation.y1,
7740                  allocation->x1, allocation->y1,
7741                  allocation->x2 - allocation->x1,
7742                  allocation->y2 - allocation->y1);
7743       return;
7744     }
7745
7746   *allocation = adj_allocation;
7747 }
7748
7749 /**
7750  * clutter_actor_allocate:
7751  * @self: A #ClutterActor
7752  * @box: new allocation of the actor, in parent-relative coordinates
7753  * @flags: flags that control the allocation
7754  *
7755  * Called by the parent of an actor to assign the actor its size.
7756  * Should never be called by applications (except when implementing
7757  * a container or layout manager).
7758  *
7759  * Actors can know from their allocation box whether they have moved
7760  * with respect to their parent actor. The @flags parameter describes
7761  * additional information about the allocation, for instance whether
7762  * the parent has moved with respect to the stage, for example because
7763  * a grandparent's origin has moved.
7764  *
7765  * Since: 0.8
7766  */
7767 void
7768 clutter_actor_allocate (ClutterActor           *self,
7769                         const ClutterActorBox  *box,
7770                         ClutterAllocationFlags  flags)
7771 {
7772   ClutterActorPrivate *priv;
7773   ClutterActorClass *klass;
7774   ClutterActorBox old_allocation, real_allocation;
7775   gboolean origin_changed, child_moved, size_changed;
7776   gboolean stage_allocation_changed;
7777
7778   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7779   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
7780     {
7781       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
7782                  "which isn't a descendent of the stage!\n",
7783                  self, _clutter_actor_get_debug_name (self));
7784       return;
7785     }
7786
7787   priv = self->priv;
7788
7789   old_allocation = priv->allocation;
7790   real_allocation = *box;
7791
7792   /* constraints are allowed to modify the allocation only here; we do
7793    * this prior to all the other checks so that we can bail out if the
7794    * allocation did not change
7795    */
7796   clutter_actor_update_constraints (self, &real_allocation);
7797
7798   /* adjust the allocation depending on the align/margin properties */
7799   clutter_actor_adjust_allocation (self, &real_allocation);
7800
7801   if (real_allocation.x2 < real_allocation.x1 ||
7802       real_allocation.y2 < real_allocation.y1)
7803     {
7804       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
7805                  _clutter_actor_get_debug_name (self),
7806                  real_allocation.x2 - real_allocation.x1,
7807                  real_allocation.y2 - real_allocation.y1);
7808     }
7809
7810   /* we allow 0-sized actors, but not negative-sized ones */
7811   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
7812   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
7813
7814   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
7815
7816   child_moved = (real_allocation.x1 != old_allocation.x1 ||
7817                  real_allocation.y1 != old_allocation.y1);
7818
7819   size_changed = (real_allocation.x2 != old_allocation.x2 ||
7820                   real_allocation.y2 != old_allocation.y2);
7821
7822   if (origin_changed || child_moved || size_changed)
7823     stage_allocation_changed = TRUE;
7824   else
7825     stage_allocation_changed = FALSE;
7826
7827   /* If we get an allocation "out of the blue"
7828    * (we did not queue relayout), then we want to
7829    * ignore it. But if we have needs_allocation set,
7830    * we want to guarantee that allocate() virtual
7831    * method is always called, i.e. that queue_relayout()
7832    * always results in an allocate() invocation on
7833    * an actor.
7834    *
7835    * The optimization here is to avoid re-allocating
7836    * actors that did not queue relayout and were
7837    * not moved.
7838    */
7839   if (!priv->needs_allocation && !stage_allocation_changed)
7840     {
7841       CLUTTER_NOTE (LAYOUT, "No allocation needed");
7842       return;
7843     }
7844
7845   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
7846    * clutter_actor_allocate(), it indicates whether the parent has its
7847    * absolute origin moved; when passed in to ClutterActor::allocate()
7848    * virtual method though, it indicates whether the child has its
7849    * absolute origin moved.  So we set it when child_moved is TRUE
7850    */
7851   if (child_moved)
7852     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
7853
7854   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7855
7856   klass = CLUTTER_ACTOR_GET_CLASS (self);
7857   klass->allocate (self, &real_allocation, flags);
7858
7859   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7860
7861   if (stage_allocation_changed)
7862     clutter_actor_queue_redraw (self);
7863 }
7864
7865 /**
7866  * clutter_actor_set_allocation:
7867  * @self: a #ClutterActor
7868  * @box: a #ClutterActorBox
7869  * @flags: allocation flags
7870  *
7871  * Stores the allocation of @self as defined by @box.
7872  *
7873  * This function can only be called from within the implementation of
7874  * the #ClutterActorClass.allocate() virtual function.
7875  *
7876  * The allocation should have been adjusted to take into account constraints,
7877  * alignment, and margin properties. If you are implementing a #ClutterActor
7878  * subclass that provides its own layout management policy for its children
7879  * instead of using a #ClutterLayoutManager delegate, you should not call
7880  * this function on the children of @self; instead, you should call
7881  * clutter_actor_allocate(), which will adjust the allocation box for
7882  * you.
7883  *
7884  * This function should only be used by subclasses of #ClutterActor
7885  * that wish to store their allocation but cannot chain up to the
7886  * parent's implementation; the default implementation of the
7887  * #ClutterActorClass.allocate() virtual function will call this
7888  * function.
7889  *
7890  * It is important to note that, while chaining up was the recommended
7891  * behaviour for #ClutterActor subclasses prior to the introduction of
7892  * this function, it is recommended to call clutter_actor_set_allocation()
7893  * instead.
7894  *
7895  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
7896  * to handle the allocation of its children, this function will call
7897  * the clutter_layout_manager_allocate() function only if the
7898  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
7899  * expected that the subclass will call clutter_layout_manager_allocate()
7900  * by itself. For instance, the following code:
7901  *
7902  * |[
7903  * static void
7904  * my_actor_allocate (ClutterActor *actor,
7905  *                    const ClutterActorBox *allocation,
7906  *                    ClutterAllocationFlags flags)
7907  * {
7908  *   ClutterActorBox new_alloc;
7909  *   ClutterAllocationFlags new_flags;
7910  *
7911  *   adjust_allocation (allocation, &amp;new_alloc);
7912  *
7913  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
7914  *
7915  *   /&ast; this will use the layout manager set on the actor &ast;/
7916  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
7917  * }
7918  * ]|
7919  *
7920  * is equivalent to this:
7921  *
7922  * |[
7923  * static void
7924  * my_actor_allocate (ClutterActor *actor,
7925  *                    const ClutterActorBox *allocation,
7926  *                    ClutterAllocationFlags flags)
7927  * {
7928  *   ClutterLayoutManager *layout;
7929  *   ClutterActorBox new_alloc;
7930  *
7931  *   adjust_allocation (allocation, &amp;new_alloc);
7932  *
7933  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
7934  *
7935  *   layout = clutter_actor_get_layout_manager (actor);
7936  *   clutter_layout_manager_allocate (layout,
7937  *                                    CLUTTER_CONTAINER (actor),
7938  *                                    &amp;new_alloc,
7939  *                                    flags);
7940  * }
7941  * ]|
7942  *
7943  * Since: 1.10
7944  */
7945 void
7946 clutter_actor_set_allocation (ClutterActor           *self,
7947                               const ClutterActorBox  *box,
7948                               ClutterAllocationFlags  flags)
7949 {
7950   ClutterActorPrivate *priv;
7951   gboolean changed;
7952
7953   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7954   g_return_if_fail (box != NULL);
7955
7956   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
7957     {
7958       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
7959                   "can only be called from within the implementation of "
7960                   "the ClutterActor::allocate() virtual function.");
7961       return;
7962     }
7963
7964   priv = self->priv;
7965
7966   g_object_freeze_notify (G_OBJECT (self));
7967
7968   changed = clutter_actor_set_allocation_internal (self, box, flags);
7969
7970   /* we allocate our children before we notify changes in our geometry,
7971    * so that people connecting to properties will be able to get valid
7972    * data out of the sub-tree of the scene graph that has this actor at
7973    * the root.
7974    */
7975   clutter_actor_maybe_layout_children (self, box, flags);
7976
7977   if (changed)
7978     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
7979                    &priv->allocation,
7980                    priv->allocation_flags);
7981
7982   g_object_thaw_notify (G_OBJECT (self));
7983 }
7984
7985 /**
7986  * clutter_actor_set_geometry:
7987  * @self: A #ClutterActor
7988  * @geometry: A #ClutterGeometry
7989  *
7990  * Sets the actor's fixed position and forces its minimum and natural
7991  * size, in pixels. This means the untransformed actor will have the
7992  * given geometry. This is the same as calling clutter_actor_set_position()
7993  * and clutter_actor_set_size().
7994  *
7995  * Deprecated: 1.10: Use clutter_actor_set_position() and
7996  *   clutter_actor_set_size() instead.
7997  */
7998 void
7999 clutter_actor_set_geometry (ClutterActor          *self,
8000                             const ClutterGeometry *geometry)
8001 {
8002   g_object_freeze_notify (G_OBJECT (self));
8003
8004   clutter_actor_set_position (self, geometry->x, geometry->y);
8005   clutter_actor_set_size (self, geometry->width, geometry->height);
8006
8007   g_object_thaw_notify (G_OBJECT (self));
8008 }
8009
8010 /**
8011  * clutter_actor_get_geometry:
8012  * @self: A #ClutterActor
8013  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8014  *
8015  * Gets the size and position of an actor relative to its parent
8016  * actor. This is the same as calling clutter_actor_get_position() and
8017  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8018  * requested size and position if the actor's allocation is invalid.
8019  *
8020  * Deprecated: 1.10: Use clutter_actor_get_position() and
8021  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8022  *   instead.
8023  */
8024 void
8025 clutter_actor_get_geometry (ClutterActor    *self,
8026                             ClutterGeometry *geometry)
8027 {
8028   gfloat x, y, width, height;
8029
8030   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8031   g_return_if_fail (geometry != NULL);
8032
8033   clutter_actor_get_position (self, &x, &y);
8034   clutter_actor_get_size (self, &width, &height);
8035
8036   geometry->x = (int) x;
8037   geometry->y = (int) y;
8038   geometry->width = (int) width;
8039   geometry->height = (int) height;
8040 }
8041
8042 /**
8043  * clutter_actor_set_position:
8044  * @self: A #ClutterActor
8045  * @x: New left position of actor in pixels.
8046  * @y: New top position of actor in pixels.
8047  *
8048  * Sets the actor's fixed position in pixels relative to any parent
8049  * actor.
8050  *
8051  * If a layout manager is in use, this position will override the
8052  * layout manager and force a fixed position.
8053  */
8054 void
8055 clutter_actor_set_position (ClutterActor *self,
8056                             gfloat        x,
8057                             gfloat        y)
8058 {
8059   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8060
8061   g_object_freeze_notify (G_OBJECT (self));
8062
8063   clutter_actor_set_x (self, x);
8064   clutter_actor_set_y (self, y);
8065
8066   g_object_thaw_notify (G_OBJECT (self));
8067 }
8068
8069 /**
8070  * clutter_actor_get_fixed_position_set:
8071  * @self: A #ClutterActor
8072  *
8073  * Checks whether an actor has a fixed position set (and will thus be
8074  * unaffected by any layout manager).
8075  *
8076  * Return value: %TRUE if the fixed position is set on the actor
8077  *
8078  * Since: 0.8
8079  */
8080 gboolean
8081 clutter_actor_get_fixed_position_set (ClutterActor *self)
8082 {
8083   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8084
8085   return self->priv->position_set;
8086 }
8087
8088 /**
8089  * clutter_actor_set_fixed_position_set:
8090  * @self: A #ClutterActor
8091  * @is_set: whether to use fixed position
8092  *
8093  * Sets whether an actor has a fixed position set (and will thus be
8094  * unaffected by any layout manager).
8095  *
8096  * Since: 0.8
8097  */
8098 void
8099 clutter_actor_set_fixed_position_set (ClutterActor *self,
8100                                       gboolean      is_set)
8101 {
8102   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8103
8104   if (self->priv->position_set == (is_set != FALSE))
8105     return;
8106
8107   self->priv->position_set = is_set != FALSE;
8108   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8109
8110   clutter_actor_queue_relayout (self);
8111 }
8112
8113 /**
8114  * clutter_actor_move_by:
8115  * @self: A #ClutterActor
8116  * @dx: Distance to move Actor on X axis.
8117  * @dy: Distance to move Actor on Y axis.
8118  *
8119  * Moves an actor by the specified distance relative to its current
8120  * position in pixels.
8121  *
8122  * This function modifies the fixed position of an actor and thus removes
8123  * it from any layout management. Another way to move an actor is with an
8124  * anchor point, see clutter_actor_set_anchor_point().
8125  *
8126  * Since: 0.2
8127  */
8128 void
8129 clutter_actor_move_by (ClutterActor *self,
8130                        gfloat        dx,
8131                        gfloat        dy)
8132 {
8133   const ClutterLayoutInfo *info;
8134   gfloat x, y;
8135
8136   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8137
8138   info = _clutter_actor_get_layout_info_or_defaults (self);
8139   x = info->fixed_x;
8140   y = info->fixed_y;
8141
8142   clutter_actor_set_position (self, x + dx, y + dy);
8143 }
8144
8145 static void
8146 clutter_actor_set_min_width (ClutterActor *self,
8147                              gfloat        min_width)
8148 {
8149   ClutterActorPrivate *priv = self->priv;
8150   ClutterActorBox old = { 0, };
8151   ClutterLayoutInfo *info;
8152
8153   /* if we are setting the size on a top-level actor and the
8154    * backend only supports static top-levels (e.g. framebuffers)
8155    * then we ignore the passed value and we override it with
8156    * the stage implementation's preferred size.
8157    */
8158   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8159       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8160     return;
8161
8162   info = _clutter_actor_get_layout_info (self);
8163
8164   if (priv->min_width_set && min_width == info->min_width)
8165     return;
8166
8167   g_object_freeze_notify (G_OBJECT (self));
8168
8169   clutter_actor_store_old_geometry (self, &old);
8170
8171   info->min_width = min_width;
8172   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8173   clutter_actor_set_min_width_set (self, TRUE);
8174
8175   clutter_actor_notify_if_geometry_changed (self, &old);
8176
8177   g_object_thaw_notify (G_OBJECT (self));
8178
8179   clutter_actor_queue_relayout (self);
8180 }
8181
8182 static void
8183 clutter_actor_set_min_height (ClutterActor *self,
8184                               gfloat        min_height)
8185
8186 {
8187   ClutterActorPrivate *priv = self->priv;
8188   ClutterActorBox old = { 0, };
8189   ClutterLayoutInfo *info;
8190
8191   /* if we are setting the size on a top-level actor and the
8192    * backend only supports static top-levels (e.g. framebuffers)
8193    * then we ignore the passed value and we override it with
8194    * the stage implementation's preferred size.
8195    */
8196   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8197       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8198     return;
8199
8200   info = _clutter_actor_get_layout_info (self);
8201
8202   if (priv->min_height_set && min_height == info->min_height)
8203     return;
8204
8205   g_object_freeze_notify (G_OBJECT (self));
8206
8207   clutter_actor_store_old_geometry (self, &old);
8208
8209   info->min_height = min_height;
8210   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8211   clutter_actor_set_min_height_set (self, TRUE);
8212
8213   clutter_actor_notify_if_geometry_changed (self, &old);
8214
8215   g_object_thaw_notify (G_OBJECT (self));
8216
8217   clutter_actor_queue_relayout (self);
8218 }
8219
8220 static void
8221 clutter_actor_set_natural_width (ClutterActor *self,
8222                                  gfloat        natural_width)
8223 {
8224   ClutterActorPrivate *priv = self->priv;
8225   ClutterActorBox old = { 0, };
8226   ClutterLayoutInfo *info;
8227
8228   /* if we are setting the size on a top-level actor and the
8229    * backend only supports static top-levels (e.g. framebuffers)
8230    * then we ignore the passed value and we override it with
8231    * the stage implementation's preferred size.
8232    */
8233   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8234       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8235     return;
8236
8237   info = _clutter_actor_get_layout_info (self);
8238
8239   if (priv->natural_width_set && natural_width == info->natural_width)
8240     return;
8241
8242   g_object_freeze_notify (G_OBJECT (self));
8243
8244   clutter_actor_store_old_geometry (self, &old);
8245
8246   info->natural_width = natural_width;
8247   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8248   clutter_actor_set_natural_width_set (self, TRUE);
8249
8250   clutter_actor_notify_if_geometry_changed (self, &old);
8251
8252   g_object_thaw_notify (G_OBJECT (self));
8253
8254   clutter_actor_queue_relayout (self);
8255 }
8256
8257 static void
8258 clutter_actor_set_natural_height (ClutterActor *self,
8259                                   gfloat        natural_height)
8260 {
8261   ClutterActorPrivate *priv = self->priv;
8262   ClutterActorBox old = { 0, };
8263   ClutterLayoutInfo *info;
8264
8265   /* if we are setting the size on a top-level actor and the
8266    * backend only supports static top-levels (e.g. framebuffers)
8267    * then we ignore the passed value and we override it with
8268    * the stage implementation's preferred size.
8269    */
8270   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8271       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8272     return;
8273
8274   info = _clutter_actor_get_layout_info (self);
8275
8276   if (priv->natural_height_set && natural_height == info->natural_height)
8277     return;
8278
8279   g_object_freeze_notify (G_OBJECT (self));
8280
8281   clutter_actor_store_old_geometry (self, &old);
8282
8283   info->natural_height = natural_height;
8284   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8285   clutter_actor_set_natural_height_set (self, TRUE);
8286
8287   clutter_actor_notify_if_geometry_changed (self, &old);
8288
8289   g_object_thaw_notify (G_OBJECT (self));
8290
8291   clutter_actor_queue_relayout (self);
8292 }
8293
8294 static void
8295 clutter_actor_set_min_width_set (ClutterActor *self,
8296                                  gboolean      use_min_width)
8297 {
8298   ClutterActorPrivate *priv = self->priv;
8299   ClutterActorBox old = { 0, };
8300
8301   if (priv->min_width_set == (use_min_width != FALSE))
8302     return;
8303
8304   clutter_actor_store_old_geometry (self, &old);
8305
8306   priv->min_width_set = use_min_width != FALSE;
8307   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8308
8309   clutter_actor_notify_if_geometry_changed (self, &old);
8310
8311   clutter_actor_queue_relayout (self);
8312 }
8313
8314 static void
8315 clutter_actor_set_min_height_set (ClutterActor *self,
8316                                   gboolean      use_min_height)
8317 {
8318   ClutterActorPrivate *priv = self->priv;
8319   ClutterActorBox old = { 0, };
8320
8321   if (priv->min_height_set == (use_min_height != FALSE))
8322     return;
8323
8324   clutter_actor_store_old_geometry (self, &old);
8325
8326   priv->min_height_set = use_min_height != FALSE;
8327   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8328
8329   clutter_actor_notify_if_geometry_changed (self, &old);
8330
8331   clutter_actor_queue_relayout (self);
8332 }
8333
8334 static void
8335 clutter_actor_set_natural_width_set (ClutterActor *self,
8336                                      gboolean      use_natural_width)
8337 {
8338   ClutterActorPrivate *priv = self->priv;
8339   ClutterActorBox old = { 0, };
8340
8341   if (priv->natural_width_set == (use_natural_width != FALSE))
8342     return;
8343
8344   clutter_actor_store_old_geometry (self, &old);
8345
8346   priv->natural_width_set = use_natural_width != FALSE;
8347   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8348
8349   clutter_actor_notify_if_geometry_changed (self, &old);
8350
8351   clutter_actor_queue_relayout (self);
8352 }
8353
8354 static void
8355 clutter_actor_set_natural_height_set (ClutterActor *self,
8356                                       gboolean      use_natural_height)
8357 {
8358   ClutterActorPrivate *priv = self->priv;
8359   ClutterActorBox old = { 0, };
8360
8361   if (priv->natural_height_set == (use_natural_height != FALSE))
8362     return;
8363
8364   clutter_actor_store_old_geometry (self, &old);
8365
8366   priv->natural_height_set = use_natural_height != FALSE;
8367   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8368
8369   clutter_actor_notify_if_geometry_changed (self, &old);
8370
8371   clutter_actor_queue_relayout (self);
8372 }
8373
8374 /**
8375  * clutter_actor_set_request_mode:
8376  * @self: a #ClutterActor
8377  * @mode: the request mode
8378  *
8379  * Sets the geometry request mode of @self.
8380  *
8381  * The @mode determines the order for invoking
8382  * clutter_actor_get_preferred_width() and
8383  * clutter_actor_get_preferred_height()
8384  *
8385  * Since: 1.2
8386  */
8387 void
8388 clutter_actor_set_request_mode (ClutterActor       *self,
8389                                 ClutterRequestMode  mode)
8390 {
8391   ClutterActorPrivate *priv;
8392
8393   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8394
8395   priv = self->priv;
8396
8397   if (priv->request_mode == mode)
8398     return;
8399
8400   priv->request_mode = mode;
8401
8402   priv->needs_width_request = TRUE;
8403   priv->needs_height_request = TRUE;
8404
8405   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8406
8407   clutter_actor_queue_relayout (self);
8408 }
8409
8410 /**
8411  * clutter_actor_get_request_mode:
8412  * @self: a #ClutterActor
8413  *
8414  * Retrieves the geometry request mode of @self
8415  *
8416  * Return value: the request mode for the actor
8417  *
8418  * Since: 1.2
8419  */
8420 ClutterRequestMode
8421 clutter_actor_get_request_mode (ClutterActor *self)
8422 {
8423   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8424                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8425
8426   return self->priv->request_mode;
8427 }
8428
8429 /* variant of set_width() without checks and without notification
8430  * freeze+thaw, for internal usage only
8431  */
8432 static inline void
8433 clutter_actor_set_width_internal (ClutterActor *self,
8434                                   gfloat        width)
8435 {
8436   if (width >= 0)
8437     {
8438       /* the Stage will use the :min-width to control the minimum
8439        * width to be resized to, so we should not be setting it
8440        * along with the :natural-width
8441        */
8442       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8443         clutter_actor_set_min_width (self, width);
8444
8445       clutter_actor_set_natural_width (self, width);
8446     }
8447   else
8448     {
8449       /* we only unset the :natural-width for the Stage */
8450       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8451         clutter_actor_set_min_width_set (self, FALSE);
8452
8453       clutter_actor_set_natural_width_set (self, FALSE);
8454     }
8455 }
8456
8457 /* variant of set_height() without checks and without notification
8458  * freeze+thaw, for internal usage only
8459  */
8460 static inline void
8461 clutter_actor_set_height_internal (ClutterActor *self,
8462                                    gfloat        height)
8463 {
8464   if (height >= 0)
8465     {
8466       /* see the comment above in set_width_internal() */
8467       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8468         clutter_actor_set_min_height (self, height);
8469
8470       clutter_actor_set_natural_height (self, height);
8471     }
8472   else
8473     {
8474       /* see the comment above in set_width_internal() */
8475       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8476         clutter_actor_set_min_height_set (self, FALSE);
8477
8478       clutter_actor_set_natural_height_set (self, FALSE);
8479     }
8480 }
8481
8482 /**
8483  * clutter_actor_set_size:
8484  * @self: A #ClutterActor
8485  * @width: New width of actor in pixels, or -1
8486  * @height: New height of actor in pixels, or -1
8487  *
8488  * Sets the actor's size request in pixels. This overrides any
8489  * "normal" size request the actor would have. For example
8490  * a text actor might normally request the size of the text;
8491  * this function would force a specific size instead.
8492  *
8493  * If @width and/or @height are -1 the actor will use its
8494  * "normal" size request instead of overriding it, i.e.
8495  * you can "unset" the size with -1.
8496  *
8497  * This function sets or unsets both the minimum and natural size.
8498  */
8499 void
8500 clutter_actor_set_size (ClutterActor *self,
8501                         gfloat        width,
8502                         gfloat        height)
8503 {
8504   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8505
8506   g_object_freeze_notify (G_OBJECT (self));
8507
8508   clutter_actor_set_width_internal (self, width);
8509   clutter_actor_set_height_internal (self, height);
8510
8511   g_object_thaw_notify (G_OBJECT (self));
8512 }
8513
8514 /**
8515  * clutter_actor_get_size:
8516  * @self: A #ClutterActor
8517  * @width: (out) (allow-none): return location for the width, or %NULL.
8518  * @height: (out) (allow-none): return location for the height, or %NULL.
8519  *
8520  * This function tries to "do what you mean" and return
8521  * the size an actor will have. If the actor has a valid
8522  * allocation, the allocation will be returned; otherwise,
8523  * the actors natural size request will be returned.
8524  *
8525  * If you care whether you get the request vs. the allocation, you
8526  * should probably call a different function like
8527  * clutter_actor_get_allocation_box() or
8528  * clutter_actor_get_preferred_width().
8529  *
8530  * Since: 0.2
8531  */
8532 void
8533 clutter_actor_get_size (ClutterActor *self,
8534                         gfloat       *width,
8535                         gfloat       *height)
8536 {
8537   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8538
8539   if (width)
8540     *width = clutter_actor_get_width (self);
8541
8542   if (height)
8543     *height = clutter_actor_get_height (self);
8544 }
8545
8546 /**
8547  * clutter_actor_get_position:
8548  * @self: a #ClutterActor
8549  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8550  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8551  *
8552  * This function tries to "do what you mean" and tell you where the
8553  * actor is, prior to any transformations. Retrieves the fixed
8554  * position of an actor in pixels, if one has been set; otherwise, if
8555  * the allocation is valid, returns the actor's allocated position;
8556  * otherwise, returns 0,0.
8557  *
8558  * The returned position is in pixels.
8559  *
8560  * Since: 0.6
8561  */
8562 void
8563 clutter_actor_get_position (ClutterActor *self,
8564                             gfloat       *x,
8565                             gfloat       *y)
8566 {
8567   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8568
8569   if (x)
8570     *x = clutter_actor_get_x (self);
8571
8572   if (y)
8573     *y = clutter_actor_get_y (self);
8574 }
8575
8576 /**
8577  * clutter_actor_get_transformed_position:
8578  * @self: A #ClutterActor
8579  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8580  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8581  *
8582  * Gets the absolute position of an actor, in pixels relative to the stage.
8583  *
8584  * Since: 0.8
8585  */
8586 void
8587 clutter_actor_get_transformed_position (ClutterActor *self,
8588                                         gfloat       *x,
8589                                         gfloat       *y)
8590 {
8591   ClutterVertex v1;
8592   ClutterVertex v2;
8593
8594   v1.x = v1.y = v1.z = 0;
8595   clutter_actor_apply_transform_to_point (self, &v1, &v2);
8596
8597   if (x)
8598     *x = v2.x;
8599
8600   if (y)
8601     *y = v2.y;
8602 }
8603
8604 /**
8605  * clutter_actor_get_transformed_size:
8606  * @self: A #ClutterActor
8607  * @width: (out) (allow-none): return location for the width, or %NULL
8608  * @height: (out) (allow-none): return location for the height, or %NULL
8609  *
8610  * Gets the absolute size of an actor in pixels, taking into account the
8611  * scaling factors.
8612  *
8613  * If the actor has a valid allocation, the allocated size will be used.
8614  * If the actor has not a valid allocation then the preferred size will
8615  * be transformed and returned.
8616  *
8617  * If you want the transformed allocation, see
8618  * clutter_actor_get_abs_allocation_vertices() instead.
8619  *
8620  * <note>When the actor (or one of its ancestors) is rotated around the
8621  * X or Y axis, it no longer appears as on the stage as a rectangle, but
8622  * as a generic quadrangle; in that case this function returns the size
8623  * of the smallest rectangle that encapsulates the entire quad. Please
8624  * note that in this case no assumptions can be made about the relative
8625  * position of this envelope to the absolute position of the actor, as
8626  * returned by clutter_actor_get_transformed_position(); if you need this
8627  * information, you need to use clutter_actor_get_abs_allocation_vertices()
8628  * to get the coords of the actual quadrangle.</note>
8629  *
8630  * Since: 0.8
8631  */
8632 void
8633 clutter_actor_get_transformed_size (ClutterActor *self,
8634                                     gfloat       *width,
8635                                     gfloat       *height)
8636 {
8637   ClutterActorPrivate *priv;
8638   ClutterVertex v[4];
8639   gfloat x_min, x_max, y_min, y_max;
8640   gint i;
8641
8642   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8643
8644   priv = self->priv;
8645
8646   /* if the actor hasn't been allocated yet, get the preferred
8647    * size and transform that
8648    */
8649   if (priv->needs_allocation)
8650     {
8651       gfloat natural_width, natural_height;
8652       ClutterActorBox box;
8653
8654       /* Make a fake allocation to transform.
8655        *
8656        * NB: _clutter_actor_transform_and_project_box expects a box in
8657        * the actor's coordinate space... */
8658
8659       box.x1 = 0;
8660       box.y1 = 0;
8661
8662       natural_width = natural_height = 0;
8663       clutter_actor_get_preferred_size (self, NULL, NULL,
8664                                         &natural_width,
8665                                         &natural_height);
8666
8667       box.x2 = natural_width;
8668       box.y2 = natural_height;
8669
8670       _clutter_actor_transform_and_project_box (self, &box, v);
8671     }
8672   else
8673     clutter_actor_get_abs_allocation_vertices (self, v);
8674
8675   x_min = x_max = v[0].x;
8676   y_min = y_max = v[0].y;
8677
8678   for (i = 1; i < G_N_ELEMENTS (v); ++i)
8679     {
8680       if (v[i].x < x_min)
8681         x_min = v[i].x;
8682
8683       if (v[i].x > x_max)
8684         x_max = v[i].x;
8685
8686       if (v[i].y < y_min)
8687         y_min = v[i].y;
8688
8689       if (v[i].y > y_max)
8690         y_max = v[i].y;
8691     }
8692
8693   if (width)
8694     *width  = x_max - x_min;
8695
8696   if (height)
8697     *height = y_max - y_min;
8698 }
8699
8700 /**
8701  * clutter_actor_get_width:
8702  * @self: A #ClutterActor
8703  *
8704  * Retrieves the width of a #ClutterActor.
8705  *
8706  * If the actor has a valid allocation, this function will return the
8707  * width of the allocated area given to the actor.
8708  *
8709  * If the actor does not have a valid allocation, this function will
8710  * return the actor's natural width, that is the preferred width of
8711  * the actor.
8712  *
8713  * If you care whether you get the preferred width or the width that
8714  * has been assigned to the actor, you should probably call a different
8715  * function like clutter_actor_get_allocation_box() to retrieve the
8716  * allocated size or clutter_actor_get_preferred_width() to retrieve the
8717  * preferred width.
8718  *
8719  * If an actor has a fixed width, for instance a width that has been
8720  * assigned using clutter_actor_set_width(), the width returned will
8721  * be the same value.
8722  *
8723  * Return value: the width of the actor, in pixels
8724  */
8725 gfloat
8726 clutter_actor_get_width (ClutterActor *self)
8727 {
8728   ClutterActorPrivate *priv;
8729
8730   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8731
8732   priv = self->priv;
8733
8734   if (priv->needs_allocation)
8735     {
8736       gfloat natural_width = 0;
8737
8738       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8739         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8740       else
8741         {
8742           gfloat natural_height = 0;
8743
8744           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8745           clutter_actor_get_preferred_width (self, natural_height,
8746                                              NULL,
8747                                              &natural_width);
8748         }
8749
8750       return natural_width;
8751     }
8752   else
8753     return priv->allocation.x2 - priv->allocation.x1;
8754 }
8755
8756 /**
8757  * clutter_actor_get_height:
8758  * @self: A #ClutterActor
8759  *
8760  * Retrieves the height of a #ClutterActor.
8761  *
8762  * If the actor has a valid allocation, this function will return the
8763  * height of the allocated area given to the actor.
8764  *
8765  * If the actor does not have a valid allocation, this function will
8766  * return the actor's natural height, that is the preferred height of
8767  * the actor.
8768  *
8769  * If you care whether you get the preferred height or the height that
8770  * has been assigned to the actor, you should probably call a different
8771  * function like clutter_actor_get_allocation_box() to retrieve the
8772  * allocated size or clutter_actor_get_preferred_height() to retrieve the
8773  * preferred height.
8774  *
8775  * If an actor has a fixed height, for instance a height that has been
8776  * assigned using clutter_actor_set_height(), the height returned will
8777  * be the same value.
8778  *
8779  * Return value: the height of the actor, in pixels
8780  */
8781 gfloat
8782 clutter_actor_get_height (ClutterActor *self)
8783 {
8784   ClutterActorPrivate *priv;
8785
8786   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8787
8788   priv = self->priv;
8789
8790   if (priv->needs_allocation)
8791     {
8792       gfloat natural_height = 0;
8793
8794       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8795         {
8796           gfloat natural_width = 0;
8797
8798           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8799           clutter_actor_get_preferred_height (self, natural_width,
8800                                               NULL, &natural_height);
8801         }
8802       else
8803         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8804
8805       return natural_height;
8806     }
8807   else
8808     return priv->allocation.y2 - priv->allocation.y1;
8809 }
8810
8811 /**
8812  * clutter_actor_set_width:
8813  * @self: A #ClutterActor
8814  * @width: Requested new width for the actor, in pixels, or -1
8815  *
8816  * Forces a width on an actor, causing the actor's preferred width
8817  * and height (if any) to be ignored.
8818  *
8819  * If @width is -1 the actor will use its preferred width request
8820  * instead of overriding it, i.e. you can "unset" the width with -1.
8821  *
8822  * This function sets both the minimum and natural size of the actor.
8823  *
8824  * since: 0.2
8825  */
8826 void
8827 clutter_actor_set_width (ClutterActor *self,
8828                          gfloat        width)
8829 {
8830   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8831
8832   g_object_freeze_notify (G_OBJECT (self));
8833
8834   clutter_actor_set_width_internal (self, width);
8835
8836   g_object_thaw_notify (G_OBJECT (self));
8837 }
8838
8839 /**
8840  * clutter_actor_set_height:
8841  * @self: A #ClutterActor
8842  * @height: Requested new height for the actor, in pixels, or -1
8843  *
8844  * Forces a height on an actor, causing the actor's preferred width
8845  * and height (if any) to be ignored.
8846  *
8847  * If @height is -1 the actor will use its preferred height instead of
8848  * overriding it, i.e. you can "unset" the height with -1.
8849  *
8850  * This function sets both the minimum and natural size of the actor.
8851  *
8852  * since: 0.2
8853  */
8854 void
8855 clutter_actor_set_height (ClutterActor *self,
8856                           gfloat        height)
8857 {
8858   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8859
8860   g_object_freeze_notify (G_OBJECT (self));
8861
8862   clutter_actor_set_height_internal (self, height);
8863
8864   g_object_thaw_notify (G_OBJECT (self));
8865 }
8866
8867 /**
8868  * clutter_actor_set_x:
8869  * @self: a #ClutterActor
8870  * @x: the actor's position on the X axis
8871  *
8872  * Sets the actor's X coordinate, relative to its parent, in pixels.
8873  *
8874  * Overrides any layout manager and forces a fixed position for
8875  * the actor.
8876  *
8877  * Since: 0.6
8878  */
8879 void
8880 clutter_actor_set_x (ClutterActor *self,
8881                      gfloat        x)
8882 {
8883   ClutterActorBox old = { 0, };
8884   ClutterActorPrivate *priv;
8885   ClutterLayoutInfo *info;
8886
8887   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8888
8889   priv = self->priv;
8890
8891   info = _clutter_actor_get_layout_info (self);
8892
8893   if (priv->position_set && info->fixed_x == x)
8894     return;
8895
8896   clutter_actor_store_old_geometry (self, &old);
8897
8898   info->fixed_x = x;
8899   clutter_actor_set_fixed_position_set (self, TRUE);
8900
8901   clutter_actor_notify_if_geometry_changed (self, &old);
8902
8903   clutter_actor_queue_relayout (self);
8904 }
8905
8906 /**
8907  * clutter_actor_set_y:
8908  * @self: a #ClutterActor
8909  * @y: the actor's position on the Y axis
8910  *
8911  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
8912  *
8913  * Overrides any layout manager and forces a fixed position for
8914  * the actor.
8915  *
8916  * Since: 0.6
8917  */
8918 void
8919 clutter_actor_set_y (ClutterActor *self,
8920                      gfloat        y)
8921 {
8922   ClutterActorBox old = { 0, };
8923   ClutterActorPrivate *priv;
8924   ClutterLayoutInfo *info;
8925
8926   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8927
8928   priv = self->priv;
8929
8930   info = _clutter_actor_get_layout_info (self);
8931
8932   if (priv->position_set && info->fixed_y == y)
8933     return;
8934
8935   clutter_actor_store_old_geometry (self, &old);
8936
8937   info->fixed_y = y;
8938   clutter_actor_set_fixed_position_set (self, TRUE);
8939
8940   clutter_actor_notify_if_geometry_changed (self, &old);
8941
8942   clutter_actor_queue_relayout (self);
8943 }
8944
8945 /**
8946  * clutter_actor_get_x:
8947  * @self: A #ClutterActor
8948  *
8949  * Retrieves the X coordinate of a #ClutterActor.
8950  *
8951  * This function tries to "do what you mean", by returning the
8952  * correct value depending on the actor's state.
8953  *
8954  * If the actor has a valid allocation, this function will return
8955  * the X coordinate of the origin of the allocation box.
8956  *
8957  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
8958  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8959  * function will return that coordinate.
8960  *
8961  * If both the allocation and a fixed position are missing, this function
8962  * will return 0.
8963  *
8964  * Return value: the X coordinate, in pixels, ignoring any
8965  *   transformation (i.e. scaling, rotation)
8966  */
8967 gfloat
8968 clutter_actor_get_x (ClutterActor *self)
8969 {
8970   ClutterActorPrivate *priv;
8971
8972   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8973
8974   priv = self->priv;
8975
8976   if (priv->needs_allocation)
8977     {
8978       if (priv->position_set)
8979         {
8980           const ClutterLayoutInfo *info;
8981
8982           info = _clutter_actor_get_layout_info_or_defaults (self);
8983
8984           return info->fixed_x;
8985         }
8986       else
8987         return 0;
8988     }
8989   else
8990     return priv->allocation.x1;
8991 }
8992
8993 /**
8994  * clutter_actor_get_y:
8995  * @self: A #ClutterActor
8996  *
8997  * Retrieves the Y coordinate of a #ClutterActor.
8998  *
8999  * This function tries to "do what you mean", by returning the
9000  * correct value depending on the actor's state.
9001  *
9002  * If the actor has a valid allocation, this function will return
9003  * the Y coordinate of the origin of the allocation box.
9004  *
9005  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9006  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9007  * function will return that coordinate.
9008  *
9009  * If both the allocation and a fixed position are missing, this function
9010  * will return 0.
9011  *
9012  * Return value: the Y coordinate, in pixels, ignoring any
9013  *   transformation (i.e. scaling, rotation)
9014  */
9015 gfloat
9016 clutter_actor_get_y (ClutterActor *self)
9017 {
9018   ClutterActorPrivate *priv;
9019
9020   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9021
9022   priv = self->priv;
9023
9024   if (priv->needs_allocation)
9025     {
9026       if (priv->position_set)
9027         {
9028           const ClutterLayoutInfo *info;
9029
9030           info = _clutter_actor_get_layout_info_or_defaults (self);
9031
9032           return info->fixed_y;
9033         }
9034       else
9035         return 0;
9036     }
9037   else
9038     return priv->allocation.y1;
9039 }
9040
9041 /**
9042  * clutter_actor_set_scale:
9043  * @self: A #ClutterActor
9044  * @scale_x: double factor to scale actor by horizontally.
9045  * @scale_y: double factor to scale actor by vertically.
9046  *
9047  * Scales an actor with the given factors. The scaling is relative to
9048  * the scale center and the anchor point. The scale center is
9049  * unchanged by this function and defaults to 0,0.
9050  *
9051  * Since: 0.2
9052  */
9053 void
9054 clutter_actor_set_scale (ClutterActor *self,
9055                          gdouble       scale_x,
9056                          gdouble       scale_y)
9057 {
9058   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9059
9060   g_object_freeze_notify (G_OBJECT (self));
9061
9062   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9063   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9064
9065   g_object_thaw_notify (G_OBJECT (self));
9066 }
9067
9068 /**
9069  * clutter_actor_set_scale_full:
9070  * @self: A #ClutterActor
9071  * @scale_x: double factor to scale actor by horizontally.
9072  * @scale_y: double factor to scale actor by vertically.
9073  * @center_x: X coordinate of the center of the scale.
9074  * @center_y: Y coordinate of the center of the scale
9075  *
9076  * Scales an actor with the given factors around the given center
9077  * point. The center point is specified in pixels relative to the
9078  * anchor point (usually the top left corner of the actor).
9079  *
9080  * Since: 1.0
9081  */
9082 void
9083 clutter_actor_set_scale_full (ClutterActor *self,
9084                               gdouble       scale_x,
9085                               gdouble       scale_y,
9086                               gfloat        center_x,
9087                               gfloat        center_y)
9088 {
9089   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9090
9091   g_object_freeze_notify (G_OBJECT (self));
9092
9093   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9094   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9095   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9096   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9097
9098   g_object_thaw_notify (G_OBJECT (self));
9099 }
9100
9101 /**
9102  * clutter_actor_set_scale_with_gravity:
9103  * @self: A #ClutterActor
9104  * @scale_x: double factor to scale actor by horizontally.
9105  * @scale_y: double factor to scale actor by vertically.
9106  * @gravity: the location of the scale center expressed as a compass
9107  * direction.
9108  *
9109  * Scales an actor with the given factors around the given
9110  * center point. The center point is specified as one of the compass
9111  * directions in #ClutterGravity. For example, setting it to north
9112  * will cause the top of the actor to remain unchanged and the rest of
9113  * the actor to expand left, right and downwards.
9114  *
9115  * Since: 1.0
9116  */
9117 void
9118 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9119                                       gdouble         scale_x,
9120                                       gdouble         scale_y,
9121                                       ClutterGravity  gravity)
9122 {
9123   ClutterTransformInfo *info;
9124   GObject *obj;
9125
9126   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9127
9128   obj = G_OBJECT (self);
9129
9130   g_object_freeze_notify (obj);
9131
9132   info = _clutter_actor_get_transform_info (self);
9133   info->scale_x = scale_x;
9134   info->scale_y = scale_y;
9135
9136   if (gravity == CLUTTER_GRAVITY_NONE)
9137     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9138   else
9139     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9140
9141   self->priv->transform_valid = FALSE;
9142
9143   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9144   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9145   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9146   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9147   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9148
9149   clutter_actor_queue_redraw (self);
9150
9151   g_object_thaw_notify (obj);
9152 }
9153
9154 /**
9155  * clutter_actor_get_scale:
9156  * @self: A #ClutterActor
9157  * @scale_x: (out) (allow-none): Location to store horizonal
9158  *   scale factor, or %NULL.
9159  * @scale_y: (out) (allow-none): Location to store vertical
9160  *   scale factor, or %NULL.
9161  *
9162  * Retrieves an actors scale factors.
9163  *
9164  * Since: 0.2
9165  */
9166 void
9167 clutter_actor_get_scale (ClutterActor *self,
9168                          gdouble      *scale_x,
9169                          gdouble      *scale_y)
9170 {
9171   const ClutterTransformInfo *info;
9172
9173   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9174
9175   info = _clutter_actor_get_transform_info_or_defaults (self);
9176
9177   if (scale_x)
9178     *scale_x = info->scale_x;
9179
9180   if (scale_y)
9181     *scale_y = info->scale_y;
9182 }
9183
9184 /**
9185  * clutter_actor_get_scale_center:
9186  * @self: A #ClutterActor
9187  * @center_x: (out) (allow-none): Location to store the X position
9188  *   of the scale center, or %NULL.
9189  * @center_y: (out) (allow-none): Location to store the Y position
9190  *   of the scale center, or %NULL.
9191  *
9192  * Retrieves the scale center coordinate in pixels relative to the top
9193  * left corner of the actor. If the scale center was specified using a
9194  * #ClutterGravity this will calculate the pixel offset using the
9195  * current size of the actor.
9196  *
9197  * Since: 1.0
9198  */
9199 void
9200 clutter_actor_get_scale_center (ClutterActor *self,
9201                                 gfloat       *center_x,
9202                                 gfloat       *center_y)
9203 {
9204   const ClutterTransformInfo *info;
9205
9206   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9207
9208   info = _clutter_actor_get_transform_info_or_defaults (self);
9209
9210   clutter_anchor_coord_get_units (self, &info->scale_center,
9211                                   center_x,
9212                                   center_y,
9213                                   NULL);
9214 }
9215
9216 /**
9217  * clutter_actor_get_scale_gravity:
9218  * @self: A #ClutterActor
9219  *
9220  * Retrieves the scale center as a compass direction. If the scale
9221  * center was specified in pixels or units this will return
9222  * %CLUTTER_GRAVITY_NONE.
9223  *
9224  * Return value: the scale gravity
9225  *
9226  * Since: 1.0
9227  */
9228 ClutterGravity
9229 clutter_actor_get_scale_gravity (ClutterActor *self)
9230 {
9231   const ClutterTransformInfo *info;
9232
9233   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9234
9235   info = _clutter_actor_get_transform_info_or_defaults (self);
9236
9237   return clutter_anchor_coord_get_gravity (&info->scale_center);
9238 }
9239
9240 /**
9241  * clutter_actor_set_opacity:
9242  * @self: A #ClutterActor
9243  * @opacity: New opacity value for the actor.
9244  *
9245  * Sets the actor's opacity, with zero being completely transparent and
9246  * 255 (0xff) being fully opaque.
9247  */
9248 void
9249 clutter_actor_set_opacity (ClutterActor *self,
9250                            guint8        opacity)
9251 {
9252   ClutterActorPrivate *priv;
9253
9254   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9255
9256   priv = self->priv;
9257
9258   if (priv->opacity != opacity)
9259     {
9260       priv->opacity = opacity;
9261
9262       /* Queue a redraw from the flatten effect so that it can use
9263          its cached image if available instead of having to redraw the
9264          actual actor. If it doesn't end up using the FBO then the
9265          effect is still able to continue the paint anyway. If there
9266          is no flatten effect yet then this is equivalent to queueing
9267          a full redraw */
9268       _clutter_actor_queue_redraw_full (self,
9269                                         0, /* flags */
9270                                         NULL, /* clip */
9271                                         priv->flatten_effect);
9272
9273       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9274     }
9275 }
9276
9277 /*
9278  * clutter_actor_get_paint_opacity_internal:
9279  * @self: a #ClutterActor
9280  *
9281  * Retrieves the absolute opacity of the actor, as it appears on the stage
9282  *
9283  * This function does not do type checks
9284  *
9285  * Return value: the absolute opacity of the actor
9286  */
9287 static guint8
9288 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9289 {
9290   ClutterActorPrivate *priv = self->priv;
9291   ClutterActor *parent;
9292
9293   /* override the top-level opacity to always be 255; even in
9294    * case of ClutterStage:use-alpha being TRUE we want the rest
9295    * of the scene to be painted
9296    */
9297   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9298     return 255;
9299
9300   if (priv->opacity_override >= 0)
9301     return priv->opacity_override;
9302
9303   parent = priv->parent;
9304
9305   /* Factor in the actual actors opacity with parents */
9306   if (parent != NULL)
9307     {
9308       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9309
9310       if (opacity != 0xff)
9311         return (opacity * priv->opacity) / 0xff;
9312     }
9313
9314   return priv->opacity;
9315
9316 }
9317
9318 /**
9319  * clutter_actor_get_paint_opacity:
9320  * @self: A #ClutterActor
9321  *
9322  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9323  *
9324  * This function traverses the hierarchy chain and composites the opacity of
9325  * the actor with that of its parents.
9326  *
9327  * This function is intended for subclasses to use in the paint virtual
9328  * function, to paint themselves with the correct opacity.
9329  *
9330  * Return value: The actor opacity value.
9331  *
9332  * Since: 0.8
9333  */
9334 guint8
9335 clutter_actor_get_paint_opacity (ClutterActor *self)
9336 {
9337   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9338
9339   return clutter_actor_get_paint_opacity_internal (self);
9340 }
9341
9342 /**
9343  * clutter_actor_get_opacity:
9344  * @self: a #ClutterActor
9345  *
9346  * Retrieves the opacity value of an actor, as set by
9347  * clutter_actor_set_opacity().
9348  *
9349  * For retrieving the absolute opacity of the actor inside a paint
9350  * virtual function, see clutter_actor_get_paint_opacity().
9351  *
9352  * Return value: the opacity of the actor
9353  */
9354 guint8
9355 clutter_actor_get_opacity (ClutterActor *self)
9356 {
9357   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9358
9359   return self->priv->opacity;
9360 }
9361
9362 /**
9363  * clutter_actor_set_offscreen_redirect:
9364  * @self: A #ClutterActor
9365  * @redirect: New offscreen redirect flags for the actor.
9366  *
9367  * Defines the circumstances where the actor should be redirected into
9368  * an offscreen image. The offscreen image is used to flatten the
9369  * actor into a single image while painting for two main reasons.
9370  * Firstly, when the actor is painted a second time without any of its
9371  * contents changing it can simply repaint the cached image without
9372  * descending further down the actor hierarchy. Secondly, it will make
9373  * the opacity look correct even if there are overlapping primitives
9374  * in the actor.
9375  *
9376  * Caching the actor could in some cases be a performance win and in
9377  * some cases be a performance lose so it is important to determine
9378  * which value is right for an actor before modifying this value. For
9379  * example, there is never any reason to flatten an actor that is just
9380  * a single texture (such as a #ClutterTexture) because it is
9381  * effectively already cached in an image so the offscreen would be
9382  * redundant. Also if the actor contains primitives that are far apart
9383  * with a large transparent area in the middle (such as a large
9384  * CluterGroup with a small actor in the top left and a small actor in
9385  * the bottom right) then the cached image will contain the entire
9386  * image of the large area and the paint will waste time blending all
9387  * of the transparent pixels in the middle.
9388  *
9389  * The default method of implementing opacity on a container simply
9390  * forwards on the opacity to all of the children. If the children are
9391  * overlapping then it will appear as if they are two separate glassy
9392  * objects and there will be a break in the color where they
9393  * overlap. By redirecting to an offscreen buffer it will be as if the
9394  * two opaque objects are combined into one and then made transparent
9395  * which is usually what is expected.
9396  *
9397  * The image below demonstrates the difference between redirecting and
9398  * not. The image shows two Clutter groups, each containing a red and
9399  * a green rectangle which overlap. The opacity on the group is set to
9400  * 128 (which is 50%). When the offscreen redirect is not used, the
9401  * red rectangle can be seen through the blue rectangle as if the two
9402  * rectangles were separately transparent. When the redirect is used
9403  * the group as a whole is transparent instead so the red rectangle is
9404  * not visible where they overlap.
9405  *
9406  * <figure id="offscreen-redirect">
9407  *   <title>Sample of using an offscreen redirect for transparency</title>
9408  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
9409  * </figure>
9410  *
9411  * The default value for this property is 0, so we effectively will
9412  * never redirect an actor offscreen by default. This means that there
9413  * are times that transparent actors may look glassy as described
9414  * above. The reason this is the default is because there is a
9415  * performance trade off between quality and performance here. In many
9416  * cases the default form of glassy opacity looks good enough, but if
9417  * it's not you will need to set the
9418  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9419  * redirection for opacity.
9420  *
9421  * Custom actors that don't contain any overlapping primitives are
9422  * recommended to override the has_overlaps() virtual to return %FALSE
9423  * for maximum efficiency.
9424  *
9425  * Since: 1.8
9426  */
9427 void
9428 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9429                                       ClutterOffscreenRedirect redirect)
9430 {
9431   ClutterActorPrivate *priv;
9432
9433   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9434
9435   priv = self->priv;
9436
9437   if (priv->offscreen_redirect != redirect)
9438     {
9439       priv->offscreen_redirect = redirect;
9440
9441       /* Queue a redraw from the effect so that it can use its cached
9442          image if available instead of having to redraw the actual
9443          actor. If it doesn't end up using the FBO then the effect is
9444          still able to continue the paint anyway. If there is no
9445          effect then this is equivalent to queuing a full redraw */
9446       _clutter_actor_queue_redraw_full (self,
9447                                         0, /* flags */
9448                                         NULL, /* clip */
9449                                         priv->flatten_effect);
9450
9451       g_object_notify_by_pspec (G_OBJECT (self),
9452                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
9453     }
9454 }
9455
9456 /**
9457  * clutter_actor_get_offscreen_redirect:
9458  * @self: a #ClutterActor
9459  *
9460  * Retrieves whether to redirect the actor to an offscreen buffer, as
9461  * set by clutter_actor_set_offscreen_redirect().
9462  *
9463  * Return value: the value of the offscreen-redirect property of the actor
9464  *
9465  * Since: 1.8
9466  */
9467 ClutterOffscreenRedirect
9468 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9469 {
9470   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9471
9472   return self->priv->offscreen_redirect;
9473 }
9474
9475 /**
9476  * clutter_actor_set_name:
9477  * @self: A #ClutterActor
9478  * @name: Textual tag to apply to actor
9479  *
9480  * Sets the given name to @self. The name can be used to identify
9481  * a #ClutterActor.
9482  */
9483 void
9484 clutter_actor_set_name (ClutterActor *self,
9485                         const gchar  *name)
9486 {
9487   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9488
9489   g_free (self->priv->name);
9490   self->priv->name = g_strdup (name);
9491
9492   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
9493 }
9494
9495 /**
9496  * clutter_actor_get_name:
9497  * @self: A #ClutterActor
9498  *
9499  * Retrieves the name of @self.
9500  *
9501  * Return value: the name of the actor, or %NULL. The returned string is
9502  *   owned by the actor and should not be modified or freed.
9503  */
9504 const gchar *
9505 clutter_actor_get_name (ClutterActor *self)
9506 {
9507   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9508
9509   return self->priv->name;
9510 }
9511
9512 /**
9513  * clutter_actor_get_gid:
9514  * @self: A #ClutterActor
9515  *
9516  * Retrieves the unique id for @self.
9517  *
9518  * Return value: Globally unique value for this object instance.
9519  *
9520  * Since: 0.6
9521  *
9522  * Deprecated: 1.8: The id is not used any longer.
9523  */
9524 guint32
9525 clutter_actor_get_gid (ClutterActor *self)
9526 {
9527   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9528
9529   return self->priv->id;
9530 }
9531
9532 /**
9533  * clutter_actor_set_depth:
9534  * @self: a #ClutterActor
9535  * @depth: Z co-ord
9536  *
9537  * Sets the Z coordinate of @self to @depth.
9538  *
9539  * The unit used by @depth is dependant on the perspective setup. See
9540  * also clutter_stage_set_perspective().
9541  */
9542 void
9543 clutter_actor_set_depth (ClutterActor *self,
9544                          gfloat        depth)
9545 {
9546   ClutterActorPrivate *priv;
9547
9548   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9549
9550   priv = self->priv;
9551
9552   if (priv->z != depth)
9553     {
9554       /* Sets Z value - XXX 2.0: should we invert? */
9555       priv->z = depth;
9556
9557       priv->transform_valid = FALSE;
9558
9559       /* FIXME - remove this crap; sadly, there are still containers
9560        * in Clutter that depend on this utter brain damage
9561        */
9562       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
9563
9564       clutter_actor_queue_redraw (self);
9565
9566       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
9567     }
9568 }
9569
9570 /**
9571  * clutter_actor_get_depth:
9572  * @self: a #ClutterActor
9573  *
9574  * Retrieves the depth of @self.
9575  *
9576  * Return value: the depth of the actor
9577  */
9578 gfloat
9579 clutter_actor_get_depth (ClutterActor *self)
9580 {
9581   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
9582
9583   return self->priv->z;
9584 }
9585
9586 /**
9587  * clutter_actor_set_rotation:
9588  * @self: a #ClutterActor
9589  * @axis: the axis of rotation
9590  * @angle: the angle of rotation
9591  * @x: X coordinate of the rotation center
9592  * @y: Y coordinate of the rotation center
9593  * @z: Z coordinate of the rotation center
9594  *
9595  * Sets the rotation angle of @self around the given axis.
9596  *
9597  * The rotation center coordinates used depend on the value of @axis:
9598  * <itemizedlist>
9599  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
9600  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
9601  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
9602  * </itemizedlist>
9603  *
9604  * The rotation coordinates are relative to the anchor point of the
9605  * actor, set using clutter_actor_set_anchor_point(). If no anchor
9606  * point is set, the upper left corner is assumed as the origin.
9607  *
9608  * Since: 0.8
9609  */
9610 void
9611 clutter_actor_set_rotation (ClutterActor      *self,
9612                             ClutterRotateAxis  axis,
9613                             gdouble            angle,
9614                             gfloat             x,
9615                             gfloat             y,
9616                             gfloat             z)
9617 {
9618   ClutterVertex v;
9619
9620   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9621
9622   v.x = x;
9623   v.y = y;
9624   v.z = z;
9625
9626   g_object_freeze_notify (G_OBJECT (self));
9627
9628   clutter_actor_set_rotation_angle_internal (self, axis, angle);
9629   clutter_actor_set_rotation_center_internal (self, axis, &v);
9630
9631   g_object_thaw_notify (G_OBJECT (self));
9632 }
9633
9634 /**
9635  * clutter_actor_set_z_rotation_from_gravity:
9636  * @self: a #ClutterActor
9637  * @angle: the angle of rotation
9638  * @gravity: the center point of the rotation
9639  *
9640  * Sets the rotation angle of @self around the Z axis using the center
9641  * point specified as a compass point. For example to rotate such that
9642  * the center of the actor remains static you can use
9643  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
9644  * will move accordingly.
9645  *
9646  * Since: 1.0
9647  */
9648 void
9649 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
9650                                            gdouble         angle,
9651                                            ClutterGravity  gravity)
9652 {
9653   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9654
9655   if (gravity == CLUTTER_GRAVITY_NONE)
9656     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
9657   else
9658     {
9659       GObject *obj = G_OBJECT (self);
9660       ClutterTransformInfo *info;
9661
9662       info = _clutter_actor_get_transform_info (self);
9663
9664       g_object_freeze_notify (obj);
9665
9666       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
9667
9668       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
9669       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
9670       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
9671
9672       g_object_thaw_notify (obj);
9673     }
9674 }
9675
9676 /**
9677  * clutter_actor_get_rotation:
9678  * @self: a #ClutterActor
9679  * @axis: the axis of rotation
9680  * @x: (out): return value for the X coordinate of the center of rotation
9681  * @y: (out): return value for the Y coordinate of the center of rotation
9682  * @z: (out): return value for the Z coordinate of the center of rotation
9683  *
9684  * Retrieves the angle and center of rotation on the given axis,
9685  * set using clutter_actor_set_rotation().
9686  *
9687  * Return value: the angle of rotation
9688  *
9689  * Since: 0.8
9690  */
9691 gdouble
9692 clutter_actor_get_rotation (ClutterActor      *self,
9693                             ClutterRotateAxis  axis,
9694                             gfloat            *x,
9695                             gfloat            *y,
9696                             gfloat            *z)
9697 {
9698   const ClutterTransformInfo *info;
9699   const AnchorCoord *anchor_coord;
9700   gdouble retval = 0;
9701
9702   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9703
9704   info = _clutter_actor_get_transform_info_or_defaults (self);
9705
9706   switch (axis)
9707     {
9708     case CLUTTER_X_AXIS:
9709       anchor_coord = &info->rx_center;
9710       retval = info->rx_angle;
9711       break;
9712
9713     case CLUTTER_Y_AXIS:
9714       anchor_coord = &info->ry_center;
9715       retval = info->ry_angle;
9716       break;
9717
9718     case CLUTTER_Z_AXIS:
9719       anchor_coord = &info->rz_center;
9720       retval = info->rz_angle;
9721       break;
9722
9723     default:
9724       anchor_coord = NULL;
9725       retval = 0.0;
9726       break;
9727     }
9728
9729   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
9730
9731   return retval;
9732 }
9733
9734 /**
9735  * clutter_actor_get_z_rotation_gravity:
9736  * @self: A #ClutterActor
9737  *
9738  * Retrieves the center for the rotation around the Z axis as a
9739  * compass direction. If the center was specified in pixels or units
9740  * this will return %CLUTTER_GRAVITY_NONE.
9741  *
9742  * Return value: the Z rotation center
9743  *
9744  * Since: 1.0
9745  */
9746 ClutterGravity
9747 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
9748 {
9749   const ClutterTransformInfo *info;
9750
9751   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
9752
9753   info = _clutter_actor_get_transform_info_or_defaults (self);
9754
9755   return clutter_anchor_coord_get_gravity (&info->rz_center);
9756 }
9757
9758 /**
9759  * clutter_actor_set_clip:
9760  * @self: A #ClutterActor
9761  * @xoff: X offset of the clip rectangle
9762  * @yoff: Y offset of the clip rectangle
9763  * @width: Width of the clip rectangle
9764  * @height: Height of the clip rectangle
9765  *
9766  * Sets clip area for @self. The clip area is always computed from the
9767  * upper left corner of the actor, even if the anchor point is set
9768  * otherwise.
9769  *
9770  * Since: 0.6
9771  */
9772 void
9773 clutter_actor_set_clip (ClutterActor *self,
9774                         gfloat        xoff,
9775                         gfloat        yoff,
9776                         gfloat        width,
9777                         gfloat        height)
9778 {
9779   ClutterActorPrivate *priv;
9780
9781   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9782
9783   priv = self->priv;
9784
9785   if (priv->has_clip &&
9786       priv->clip.x == xoff &&
9787       priv->clip.y == yoff &&
9788       priv->clip.width == width &&
9789       priv->clip.height == height)
9790     return;
9791
9792   priv->clip.x = xoff;
9793   priv->clip.y = yoff;
9794   priv->clip.width = width;
9795   priv->clip.height = height;
9796
9797   priv->has_clip = TRUE;
9798
9799   clutter_actor_queue_redraw (self);
9800
9801   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9802   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
9803 }
9804
9805 /**
9806  * clutter_actor_remove_clip:
9807  * @self: A #ClutterActor
9808  *
9809  * Removes clip area from @self.
9810  */
9811 void
9812 clutter_actor_remove_clip (ClutterActor *self)
9813 {
9814   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9815
9816   if (!self->priv->has_clip)
9817     return;
9818
9819   self->priv->has_clip = FALSE;
9820
9821   clutter_actor_queue_redraw (self);
9822
9823   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9824 }
9825
9826 /**
9827  * clutter_actor_has_clip:
9828  * @self: a #ClutterActor
9829  *
9830  * Determines whether the actor has a clip area set or not.
9831  *
9832  * Return value: %TRUE if the actor has a clip area set.
9833  *
9834  * Since: 0.1.1
9835  */
9836 gboolean
9837 clutter_actor_has_clip (ClutterActor *self)
9838 {
9839   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9840
9841   return self->priv->has_clip;
9842 }
9843
9844 /**
9845  * clutter_actor_get_clip:
9846  * @self: a #ClutterActor
9847  * @xoff: (out) (allow-none): return location for the X offset of
9848  *   the clip rectangle, or %NULL
9849  * @yoff: (out) (allow-none): return location for the Y offset of
9850  *   the clip rectangle, or %NULL
9851  * @width: (out) (allow-none): return location for the width of
9852  *   the clip rectangle, or %NULL
9853  * @height: (out) (allow-none): return location for the height of
9854  *   the clip rectangle, or %NULL
9855  *
9856  * Gets the clip area for @self, if any is set
9857  *
9858  * Since: 0.6
9859  */
9860 void
9861 clutter_actor_get_clip (ClutterActor *self,
9862                         gfloat       *xoff,
9863                         gfloat       *yoff,
9864                         gfloat       *width,
9865                         gfloat       *height)
9866 {
9867   ClutterActorPrivate *priv;
9868
9869   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9870
9871   priv = self->priv;
9872
9873   if (!priv->has_clip)
9874     return;
9875
9876   if (xoff != NULL)
9877     *xoff = priv->clip.x;
9878
9879   if (yoff != NULL)
9880     *yoff = priv->clip.y;
9881
9882   if (width != NULL)
9883     *width = priv->clip.width;
9884
9885   if (height != NULL)
9886     *height = priv->clip.height;
9887 }
9888
9889 /**
9890  * clutter_actor_get_children:
9891  * @self: a #ClutterActor
9892  *
9893  * Retrieves the list of children of @self.
9894  *
9895  * Return value: (transfer container) (element-type ClutterActor): A newly
9896  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
9897  *   done.
9898  *
9899  * Since: 1.10
9900  */
9901 GList *
9902 clutter_actor_get_children (ClutterActor *self)
9903 {
9904   ClutterActor *iter;
9905   GList *res;
9906
9907   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9908
9909   /* we walk the list backward so that we can use prepend(),
9910    * which is O(1)
9911    */
9912   for (iter = self->priv->last_child, res = NULL;
9913        iter != NULL;
9914        iter = iter->priv->prev_sibling)
9915     {
9916       res = g_list_prepend (res, iter);
9917     }
9918
9919   return res;
9920 }
9921
9922 /*< private >
9923  * insert_child_at_depth:
9924  * @self: a #ClutterActor
9925  * @child: a #ClutterActor
9926  *
9927  * Inserts @child inside the list of children held by @self, using
9928  * the depth as the insertion criteria.
9929  *
9930  * This sadly makes the insertion not O(1), but we can keep the
9931  * list sorted so that the painters algorithm we use for painting
9932  * the children will work correctly.
9933  */
9934 static void
9935 insert_child_at_depth (ClutterActor *self,
9936                        ClutterActor *child,
9937                        gpointer      dummy G_GNUC_UNUSED)
9938 {
9939   ClutterActor *iter;
9940
9941   child->priv->parent = self;
9942
9943   /* special-case the first child */
9944   if (self->priv->n_children == 0)
9945     {
9946       self->priv->first_child = child;
9947       self->priv->last_child = child;
9948
9949       child->priv->next_sibling = NULL;
9950       child->priv->prev_sibling = NULL;
9951
9952       return;
9953     }
9954
9955   /* Find the right place to insert the child so that it will still be
9956      sorted and the child will be after all of the actors at the same
9957      dept */
9958   for (iter = self->priv->first_child;
9959        iter != NULL;
9960        iter = iter->priv->next_sibling)
9961     {
9962       if (iter->priv->z > child->priv->z)
9963         break;
9964     }
9965
9966   if (iter != NULL)
9967     {
9968       ClutterActor *tmp = iter->priv->prev_sibling;
9969
9970       if (tmp != NULL)
9971         tmp->priv->next_sibling = child;
9972
9973       /* Insert the node before the found one */
9974       child->priv->prev_sibling = iter->priv->prev_sibling;
9975       child->priv->next_sibling = iter;
9976       iter->priv->prev_sibling = child;
9977     }
9978   else
9979     {
9980       ClutterActor *tmp = self->priv->last_child;
9981
9982       if (tmp != NULL)
9983         tmp->priv->next_sibling = child;
9984
9985       /* insert the node at the end of the list */
9986       child->priv->prev_sibling = self->priv->last_child;
9987       child->priv->next_sibling = NULL;
9988     }
9989
9990   if (child->priv->prev_sibling == NULL)
9991     self->priv->first_child = child;
9992
9993   if (child->priv->next_sibling == NULL)
9994     self->priv->last_child = child;
9995 }
9996
9997 static void
9998 insert_child_at_index (ClutterActor *self,
9999                        ClutterActor *child,
10000                        gpointer      data_)
10001 {
10002   gint index_ = GPOINTER_TO_INT (data_);
10003
10004   child->priv->parent = self;
10005
10006   if (index_ == 0)
10007     {
10008       ClutterActor *tmp = self->priv->first_child;
10009
10010       if (tmp != NULL)
10011         tmp->priv->prev_sibling = child;
10012
10013       child->priv->prev_sibling = NULL;
10014       child->priv->next_sibling = tmp;
10015     }
10016   else if (index_ < 0 || index_ >= self->priv->n_children)
10017     {
10018       ClutterActor *tmp = self->priv->last_child;
10019
10020       if (tmp != NULL)
10021         tmp->priv->next_sibling = child;
10022
10023       child->priv->prev_sibling = tmp;
10024       child->priv->next_sibling = NULL;
10025     }
10026   else
10027     {
10028       ClutterActor *iter;
10029       int i;
10030
10031       for (iter = self->priv->first_child, i = 0;
10032            iter != NULL;
10033            iter = iter->priv->next_sibling, i += 1)
10034         {
10035           if (index_ == i)
10036             {
10037               ClutterActor *tmp = iter->priv->prev_sibling;
10038
10039               child->priv->prev_sibling = tmp;
10040               child->priv->next_sibling = iter;
10041
10042               iter->priv->prev_sibling = child;
10043
10044               if (tmp != NULL)
10045                 tmp->priv->next_sibling = child;
10046
10047               break;
10048             }
10049         }
10050     }
10051
10052   if (child->priv->prev_sibling == NULL)
10053     self->priv->first_child = child;
10054
10055   if (child->priv->next_sibling == NULL)
10056     self->priv->last_child = child;
10057 }
10058
10059 static void
10060 insert_child_above (ClutterActor *self,
10061                     ClutterActor *child,
10062                     gpointer      data)
10063 {
10064   ClutterActor *sibling = data;
10065
10066   child->priv->parent = self;
10067
10068   if (sibling == NULL)
10069     sibling = self->priv->last_child;
10070
10071   child->priv->prev_sibling = sibling;
10072
10073   if (sibling != NULL)
10074     {
10075       ClutterActor *tmp = sibling->priv->next_sibling;
10076
10077       child->priv->next_sibling = tmp;
10078
10079       if (tmp != NULL)
10080         tmp->priv->prev_sibling = child;
10081
10082       sibling->priv->next_sibling = child;
10083     }
10084   else
10085     child->priv->next_sibling = NULL;
10086
10087   if (child->priv->prev_sibling == NULL)
10088     self->priv->first_child = child;
10089
10090   if (child->priv->next_sibling == NULL)
10091     self->priv->last_child = child;
10092 }
10093
10094 static void
10095 insert_child_below (ClutterActor *self,
10096                     ClutterActor *child,
10097                     gpointer      data)
10098 {
10099   ClutterActor *sibling = data;
10100
10101   child->priv->parent = self;
10102
10103   if (sibling == NULL)
10104     sibling = self->priv->first_child;
10105
10106   child->priv->next_sibling = sibling;
10107
10108   if (sibling != NULL)
10109     {
10110       ClutterActor *tmp = sibling->priv->prev_sibling;
10111
10112       child->priv->prev_sibling = tmp;
10113
10114       if (tmp != NULL)
10115         tmp->priv->next_sibling = child;
10116
10117       sibling->priv->prev_sibling = child;
10118     }
10119   else
10120     child->priv->prev_sibling = NULL;
10121
10122   if (child->priv->prev_sibling == NULL)
10123     self->priv->first_child = child;
10124
10125   if (child->priv->next_sibling == NULL)
10126     self->priv->last_child = child;
10127 }
10128
10129 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10130                                            ClutterActor *child,
10131                                            gpointer      data);
10132
10133 typedef enum {
10134   ADD_CHILD_CREATE_META       = 1 << 0,
10135   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10136   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10137   ADD_CHILD_CHECK_STATE       = 1 << 3,
10138   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10139
10140   /* default flags for public API */
10141   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10142                                ADD_CHILD_EMIT_PARENT_SET |
10143                                ADD_CHILD_EMIT_ACTOR_ADDED |
10144                                ADD_CHILD_CHECK_STATE |
10145                                ADD_CHILD_NOTIFY_FIRST_LAST,
10146
10147   /* flags for legacy/deprecated API */
10148   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10149                                ADD_CHILD_CHECK_STATE |
10150                                ADD_CHILD_NOTIFY_FIRST_LAST
10151 } ClutterActorAddChildFlags;
10152
10153 /*< private >
10154  * clutter_actor_add_child_internal:
10155  * @self: a #ClutterActor
10156  * @child: a #ClutterActor
10157  * @flags: control flags for actions
10158  * @add_func: delegate function
10159  * @data: (closure): data to pass to @add_func
10160  *
10161  * Adds @child to the list of children of @self.
10162  *
10163  * The actual insertion inside the list is delegated to @add_func: this
10164  * function will just set up the state, perform basic checks, and emit
10165  * signals.
10166  *
10167  * The @flags argument is used to perform additional operations.
10168  */
10169 static inline void
10170 clutter_actor_add_child_internal (ClutterActor              *self,
10171                                   ClutterActor              *child,
10172                                   ClutterActorAddChildFlags  flags,
10173                                   ClutterActorAddChildFunc   add_func,
10174                                   gpointer                   data)
10175 {
10176   ClutterTextDirection text_dir;
10177   gboolean create_meta;
10178   gboolean emit_parent_set, emit_actor_added;
10179   gboolean check_state;
10180   gboolean notify_first_last;
10181   ClutterActor *old_first_child, *old_last_child;
10182
10183   if (child->priv->parent != NULL)
10184     {
10185       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10186                  "use clutter_actor_remove_child() first.",
10187                  _clutter_actor_get_debug_name (child),
10188                  _clutter_actor_get_debug_name (child->priv->parent));
10189       return;
10190     }
10191
10192   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10193     {
10194       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10195                  "a child of another actor.",
10196                  _clutter_actor_get_debug_name (child));
10197       return;
10198     }
10199
10200 #if 0
10201   /* XXX - this check disallows calling methods that change the stacking
10202    * order within the destruction sequence, by triggering a critical
10203    * warning first, and leaving the actor in an undefined state, which
10204    * then ends up being caught by an assertion.
10205    *
10206    * the reproducible sequence is:
10207    *
10208    *   - actor gets destroyed;
10209    *   - another actor, linked to the first, will try to change the
10210    *     stacking order of the first actor;
10211    *   - changing the stacking order is a composite operation composed
10212    *     by the following steps:
10213    *     1. ref() the child;
10214    *     2. remove_child_internal(), which removes the reference;
10215    *     3. add_child_internal(), which adds a reference;
10216    *   - the state of the actor is not changed between (2) and (3), as
10217    *     it could be an expensive recomputation;
10218    *   - if (3) bails out, then the actor is in an undefined state, but
10219    *     still alive;
10220    *   - the destruction sequence terminates, but the actor is unparented
10221    *     while its state indicates being parented instead.
10222    *   - assertion failure.
10223    *
10224    * the obvious fix would be to decompose each set_child_*_sibling()
10225    * method into proper remove_child()/add_child(), with state validation;
10226    * this may cause excessive work, though, and trigger a cascade of other
10227    * bugs in code that assumes that a change in the stacking order is an
10228    * atomic operation.
10229    *
10230    * another potential fix is to just remove this check here, and let
10231    * code doing stacking order changes inside the destruction sequence
10232    * of an actor continue doing the work.
10233    *
10234    * the third fix is to silently bail out early from every
10235    * set_child_*_sibling() and set_child_at_index() method, and avoid
10236    * doing work.
10237    *
10238    * I have a preference for the second solution, since it involves the
10239    * least amount of work, and the least amount of code duplication.
10240    *
10241    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10242    */
10243   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10244     {
10245       g_warning ("The actor '%s' is currently being destroyed, and "
10246                  "cannot be added as a child of another actor.",
10247                  _clutter_actor_get_debug_name (child));
10248       return;
10249     }
10250 #endif
10251
10252   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10253   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10254   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10255   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10256   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10257
10258   old_first_child = self->priv->first_child;
10259   old_last_child = self->priv->last_child;
10260
10261   g_object_freeze_notify (G_OBJECT (self));
10262
10263   if (create_meta)
10264     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10265
10266   g_object_ref_sink (child);
10267   child->priv->parent = NULL;
10268   child->priv->next_sibling = NULL;
10269   child->priv->prev_sibling = NULL;
10270
10271   /* delegate the actual insertion */
10272   add_func (self, child, data);
10273
10274   g_assert (child->priv->parent == self);
10275
10276   self->priv->n_children += 1;
10277
10278   self->priv->age += 1;
10279
10280   /* if push_internal() has been called then we automatically set
10281    * the flag on the actor
10282    */
10283   if (self->priv->internal_child)
10284     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10285
10286   /* clutter_actor_reparent() will emit ::parent-set for us */
10287   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10288     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10289
10290   if (check_state)
10291     {
10292       /* If parent is mapped or realized, we need to also be mapped or
10293        * realized once we're inside the parent.
10294        */
10295       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10296
10297       /* propagate the parent's text direction to the child */
10298       text_dir = clutter_actor_get_text_direction (self);
10299       clutter_actor_set_text_direction (child, text_dir);
10300     }
10301
10302   if (child->priv->show_on_set_parent)
10303     clutter_actor_show (child);
10304
10305   if (CLUTTER_ACTOR_IS_MAPPED (child))
10306     clutter_actor_queue_redraw (child);
10307
10308   /* maintain the invariant that if an actor needs layout,
10309    * its parents do as well
10310    */
10311   if (child->priv->needs_width_request ||
10312       child->priv->needs_height_request ||
10313       child->priv->needs_allocation)
10314     {
10315       /* we work around the short-circuiting we do
10316        * in clutter_actor_queue_relayout() since we
10317        * want to force a relayout
10318        */
10319       child->priv->needs_width_request = TRUE;
10320       child->priv->needs_height_request = TRUE;
10321       child->priv->needs_allocation = TRUE;
10322
10323       clutter_actor_queue_relayout (child->priv->parent);
10324     }
10325
10326   if (emit_actor_added)
10327     g_signal_emit_by_name (self, "actor-added", child);
10328
10329   if (notify_first_last)
10330     {
10331       if (old_first_child != self->priv->first_child)
10332         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10333
10334       if (old_last_child != self->priv->last_child)
10335         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10336     }
10337
10338   g_object_thaw_notify (G_OBJECT (self));
10339 }
10340
10341 /**
10342  * clutter_actor_add_child:
10343  * @self: a #ClutterActor
10344  * @child: a #ClutterActor
10345  *
10346  * Adds @child to the children of @self.
10347  *
10348  * This function will acquire a reference on @child that will only
10349  * be released when calling clutter_actor_remove_child().
10350  *
10351  * This function will take into consideration the #ClutterActor:depth
10352  * of @child, and will keep the list of children sorted.
10353  *
10354  * This function will emit the #ClutterContainer::actor-added signal
10355  * on @self.
10356  *
10357  * Since: 1.10
10358  */
10359 void
10360 clutter_actor_add_child (ClutterActor *self,
10361                          ClutterActor *child)
10362 {
10363   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10364   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10365   g_return_if_fail (self != child);
10366   g_return_if_fail (child->priv->parent == NULL);
10367
10368   clutter_actor_add_child_internal (self, child,
10369                                     ADD_CHILD_DEFAULT_FLAGS,
10370                                     insert_child_at_depth,
10371                                     NULL);
10372 }
10373
10374 /**
10375  * clutter_actor_insert_child_at_index:
10376  * @self: a #ClutterActor
10377  * @child: a #ClutterActor
10378  * @index_: the index
10379  *
10380  * Inserts @child into the list of children of @self, using the
10381  * given @index_. If @index_ is greater than the number of children
10382  * in @self, or is less than 0, then the new child is added at the end.
10383  *
10384  * This function will acquire a reference on @child that will only
10385  * be released when calling clutter_actor_remove_child().
10386  *
10387  * This function will not take into consideration the #ClutterActor:depth
10388  * of @child.
10389  *
10390  * This function will emit the #ClutterContainer::actor-added signal
10391  * on @self.
10392  *
10393  * Since: 1.10
10394  */
10395 void
10396 clutter_actor_insert_child_at_index (ClutterActor *self,
10397                                      ClutterActor *child,
10398                                      gint          index_)
10399 {
10400   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10401   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10402   g_return_if_fail (self != child);
10403   g_return_if_fail (child->priv->parent == NULL);
10404
10405   clutter_actor_add_child_internal (self, child,
10406                                     ADD_CHILD_DEFAULT_FLAGS,
10407                                     insert_child_at_index,
10408                                     GINT_TO_POINTER (index_));
10409 }
10410
10411 /**
10412  * clutter_actor_insert_child_above:
10413  * @self: a #ClutterActor
10414  * @child: a #ClutterActor
10415  * @sibling: (allow-none): a child of @self, or %NULL
10416  *
10417  * Inserts @child into the list of children of @self, above another
10418  * child of @self or, if @sibling is %NULL, above all the children
10419  * of @self.
10420  *
10421  * This function will acquire a reference on @child that will only
10422  * be released when calling clutter_actor_remove_child().
10423  *
10424  * This function will not take into consideration the #ClutterActor:depth
10425  * of @child.
10426  *
10427  * This function will emit the #ClutterContainer::actor-added signal
10428  * on @self.
10429  *
10430  * Since: 1.10
10431  */
10432 void
10433 clutter_actor_insert_child_above (ClutterActor *self,
10434                                   ClutterActor *child,
10435                                   ClutterActor *sibling)
10436 {
10437   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10438   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10439   g_return_if_fail (self != child);
10440   g_return_if_fail (child != sibling);
10441   g_return_if_fail (child->priv->parent == NULL);
10442   g_return_if_fail (sibling == NULL ||
10443                     (CLUTTER_IS_ACTOR (sibling) &&
10444                      sibling->priv->parent == self));
10445
10446   clutter_actor_add_child_internal (self, child,
10447                                     ADD_CHILD_DEFAULT_FLAGS,
10448                                     insert_child_above,
10449                                     sibling);
10450 }
10451
10452 /**
10453  * clutter_actor_insert_child_below:
10454  * @self: a #ClutterActor
10455  * @child: a #ClutterActor
10456  * @sibling: (allow-none): a child of @self, or %NULL
10457  *
10458  * Inserts @child into the list of children of @self, below another
10459  * child of @self or, if @sibling is %NULL, below all the children
10460  * of @self.
10461  *
10462  * This function will acquire a reference on @child that will only
10463  * be released when calling clutter_actor_remove_child().
10464  *
10465  * This function will not take into consideration the #ClutterActor:depth
10466  * of @child.
10467  *
10468  * This function will emit the #ClutterContainer::actor-added signal
10469  * on @self.
10470  *
10471  * Since: 1.10
10472  */
10473 void
10474 clutter_actor_insert_child_below (ClutterActor *self,
10475                                   ClutterActor *child,
10476                                   ClutterActor *sibling)
10477 {
10478   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10479   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10480   g_return_if_fail (self != child);
10481   g_return_if_fail (child != sibling);
10482   g_return_if_fail (child->priv->parent == NULL);
10483   g_return_if_fail (sibling == NULL ||
10484                     (CLUTTER_IS_ACTOR (sibling) &&
10485                      sibling->priv->parent == self));
10486
10487   clutter_actor_add_child_internal (self, child,
10488                                     ADD_CHILD_DEFAULT_FLAGS,
10489                                     insert_child_below,
10490                                     sibling);
10491 }
10492
10493 /**
10494  * clutter_actor_set_parent:
10495  * @self: A #ClutterActor
10496  * @parent: A new #ClutterActor parent
10497  *
10498  * Sets the parent of @self to @parent.
10499  *
10500  * This function will result in @parent acquiring a reference on @self,
10501  * eventually by sinking its floating reference first. The reference
10502  * will be released by clutter_actor_unparent().
10503  *
10504  * This function should only be called by legacy #ClutterActor<!-- -->s
10505  * implementing the #ClutterContainer interface.
10506  *
10507  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
10508  */
10509 void
10510 clutter_actor_set_parent (ClutterActor *self,
10511                           ClutterActor *parent)
10512 {
10513   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10514   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
10515   g_return_if_fail (self != parent);
10516   g_return_if_fail (self->priv->parent == NULL);
10517
10518   /* as this function will be called inside ClutterContainer::add
10519    * implementations or when building up a composite actor, we have
10520    * to preserve the old behaviour, and not create child meta or
10521    * emit the ::actor-added signal, to avoid recursion or double
10522    * emissions
10523    */
10524   clutter_actor_add_child_internal (parent, self,
10525                                     ADD_CHILD_LEGACY_FLAGS,
10526                                     insert_child_at_depth,
10527                                     NULL);
10528 }
10529
10530 /**
10531  * clutter_actor_get_parent:
10532  * @self: A #ClutterActor
10533  *
10534  * Retrieves the parent of @self.
10535  *
10536  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
10537  *  if no parent is set
10538  */
10539 ClutterActor *
10540 clutter_actor_get_parent (ClutterActor *self)
10541 {
10542   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10543
10544   return self->priv->parent;
10545 }
10546
10547 /**
10548  * clutter_actor_get_paint_visibility:
10549  * @self: A #ClutterActor
10550  *
10551  * Retrieves the 'paint' visibility of an actor recursively checking for non
10552  * visible parents.
10553  *
10554  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
10555  *
10556  * Return Value: %TRUE if the actor is visibile and will be painted.
10557  *
10558  * Since: 0.8.4
10559  */
10560 gboolean
10561 clutter_actor_get_paint_visibility (ClutterActor *actor)
10562 {
10563   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
10564
10565   return CLUTTER_ACTOR_IS_MAPPED (actor);
10566 }
10567
10568 /**
10569  * clutter_actor_remove_child:
10570  * @self: a #ClutterActor
10571  * @child: a #ClutterActor
10572  *
10573  * Removes @child from the children of @self.
10574  *
10575  * This function will release the reference added by
10576  * clutter_actor_add_child(), so if you want to keep using @child
10577  * you will have to acquire a referenced on it before calling this
10578  * function.
10579  *
10580  * This function will emit the #ClutterContainer::actor-removed
10581  * signal on @self.
10582  *
10583  * Since: 1.10
10584  */
10585 void
10586 clutter_actor_remove_child (ClutterActor *self,
10587                             ClutterActor *child)
10588 {
10589   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10590   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10591   g_return_if_fail (self != child);
10592   g_return_if_fail (child->priv->parent != NULL);
10593   g_return_if_fail (child->priv->parent == self);
10594
10595   clutter_actor_remove_child_internal (self, child,
10596                                        REMOVE_CHILD_DEFAULT_FLAGS);
10597 }
10598
10599 /**
10600  * clutter_actor_remove_all_children:
10601  * @self: a #ClutterActor
10602  *
10603  * Removes all children of @self.
10604  *
10605  * This function releases the reference added by inserting a child actor
10606  * in the list of children of @self.
10607  *
10608  * If the reference count of a child drops to zero, the child will be
10609  * destroyed. If you want to ensure the destruction of all the children
10610  * of @self, use clutter_actor_destroy_all_children().
10611  *
10612  * Since: 1.10
10613  */
10614 void
10615 clutter_actor_remove_all_children (ClutterActor *self)
10616 {
10617   ClutterActorIter iter;
10618
10619   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10620
10621   if (self->priv->n_children == 0)
10622     return;
10623
10624   g_object_freeze_notify (G_OBJECT (self));
10625
10626   clutter_actor_iter_init (&iter, self);
10627   while (clutter_actor_iter_next (&iter, NULL))
10628     clutter_actor_iter_remove (&iter);
10629
10630   g_object_thaw_notify (G_OBJECT (self));
10631
10632   /* sanity check */
10633   g_assert (self->priv->first_child == NULL);
10634   g_assert (self->priv->last_child == NULL);
10635   g_assert (self->priv->n_children == 0);
10636 }
10637
10638 /**
10639  * clutter_actor_destroy_all_children:
10640  * @self: a #ClutterActor
10641  *
10642  * Destroys all children of @self.
10643  *
10644  * This function releases the reference added by inserting a child
10645  * actor in the list of children of @self, and ensures that the
10646  * #ClutterActor::destroy signal is emitted on each child of the
10647  * actor.
10648  *
10649  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
10650  * when its reference count drops to 0; the default handler of the
10651  * #ClutterActor::destroy signal will destroy all the children of an
10652  * actor. This function ensures that all children are destroyed, instead
10653  * of just removed from @self, unlike clutter_actor_remove_all_children()
10654  * which will merely release the reference and remove each child.
10655  *
10656  * Unless you acquired an additional reference on each child of @self
10657  * prior to calling clutter_actor_remove_all_children() and want to reuse
10658  * the actors, you should use clutter_actor_destroy_all_children() in
10659  * order to make sure that children are destroyed and signal handlers
10660  * are disconnected even in cases where circular references prevent this
10661  * from automatically happening through reference counting alone.
10662  *
10663  * Since: 1.10
10664  */
10665 void
10666 clutter_actor_destroy_all_children (ClutterActor *self)
10667 {
10668   ClutterActorIter iter;
10669
10670   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10671
10672   if (self->priv->n_children == 0)
10673     return;
10674
10675   g_object_freeze_notify (G_OBJECT (self));
10676
10677   clutter_actor_iter_init (&iter, self);
10678   while (clutter_actor_iter_next (&iter, NULL))
10679     clutter_actor_iter_destroy (&iter);
10680
10681   g_object_thaw_notify (G_OBJECT (self));
10682
10683   /* sanity check */
10684   g_assert (self->priv->first_child == NULL);
10685   g_assert (self->priv->last_child == NULL);
10686   g_assert (self->priv->n_children == 0);
10687 }
10688
10689 typedef struct _InsertBetweenData {
10690   ClutterActor *prev_sibling;
10691   ClutterActor *next_sibling;
10692 } InsertBetweenData;
10693
10694 static void
10695 insert_child_between (ClutterActor *self,
10696                       ClutterActor *child,
10697                       gpointer      data_)
10698 {
10699   InsertBetweenData *data = data_;
10700   ClutterActor *prev_sibling = data->prev_sibling;
10701   ClutterActor *next_sibling = data->next_sibling;
10702
10703   child->priv->parent = self;
10704   child->priv->prev_sibling = prev_sibling;
10705   child->priv->next_sibling = next_sibling;
10706
10707   if (prev_sibling != NULL)
10708     prev_sibling->priv->next_sibling = child;
10709
10710   if (next_sibling != NULL)
10711     next_sibling->priv->prev_sibling = child;
10712
10713   if (child->priv->prev_sibling == NULL)
10714     self->priv->first_child = child;
10715
10716   if (child->priv->next_sibling == NULL)
10717     self->priv->last_child = child;
10718 }
10719
10720 /**
10721  * clutter_actor_replace_child:
10722  * @self: a #ClutterActor
10723  * @old_child: the child of @self to replace
10724  * @new_child: the #ClutterActor to replace @old_child
10725  *
10726  * Replaces @old_child with @new_child in the list of children of @self.
10727  *
10728  * Since: 1.10
10729  */
10730 void
10731 clutter_actor_replace_child (ClutterActor *self,
10732                              ClutterActor *old_child,
10733                              ClutterActor *new_child)
10734 {
10735   ClutterActor *prev_sibling, *next_sibling;
10736   InsertBetweenData clos;
10737
10738   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10739   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
10740   g_return_if_fail (old_child->priv->parent == self);
10741   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
10742   g_return_if_fail (old_child != new_child);
10743   g_return_if_fail (new_child != self);
10744   g_return_if_fail (new_child->priv->parent == NULL);
10745
10746   prev_sibling = old_child->priv->prev_sibling;
10747   next_sibling = old_child->priv->next_sibling;
10748   clutter_actor_remove_child_internal (self, old_child,
10749                                        REMOVE_CHILD_DEFAULT_FLAGS);
10750
10751   clos.prev_sibling = prev_sibling;
10752   clos.next_sibling = next_sibling;
10753   clutter_actor_add_child_internal (self, new_child,
10754                                     ADD_CHILD_DEFAULT_FLAGS,
10755                                     insert_child_between,
10756                                     &clos);
10757 }
10758
10759 /**
10760  * clutter_actor_unparent:
10761  * @self: a #ClutterActor
10762  *
10763  * Removes the parent of @self.
10764  *
10765  * This will cause the parent of @self to release the reference
10766  * acquired when calling clutter_actor_set_parent(), so if you
10767  * want to keep @self you will have to acquire a reference of
10768  * your own, through g_object_ref().
10769  *
10770  * This function should only be called by legacy #ClutterActor<!-- -->s
10771  * implementing the #ClutterContainer interface.
10772  *
10773  * Since: 0.1.1
10774  *
10775  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
10776  */
10777 void
10778 clutter_actor_unparent (ClutterActor *self)
10779 {
10780   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10781
10782   if (self->priv->parent == NULL)
10783     return;
10784
10785   clutter_actor_remove_child_internal (self->priv->parent, self,
10786                                        REMOVE_CHILD_LEGACY_FLAGS);
10787 }
10788
10789 /**
10790  * clutter_actor_reparent:
10791  * @self: a #ClutterActor
10792  * @new_parent: the new #ClutterActor parent
10793  *
10794  * Resets the parent actor of @self.
10795  *
10796  * This function is logically equivalent to calling clutter_actor_unparent()
10797  * and clutter_actor_set_parent(), but more efficiently implemented, as it
10798  * ensures the child is not finalized when unparented, and emits the
10799  * #ClutterActor::parent-set signal only once.
10800  *
10801  * In reality, calling this function is less useful than it sounds, as some
10802  * application code may rely on changes in the intermediate state between
10803  * removal and addition of the actor from its old parent to the @new_parent.
10804  * Thus, it is strongly encouraged to avoid using this function in application
10805  * code.
10806  *
10807  * Since: 0.2
10808  *
10809  * Deprecated: 1.10: Use clutter_actor_remove_child() and
10810  *   clutter_actor_add_child() instead; remember to take a reference on
10811  *   the actor being removed before calling clutter_actor_remove_child()
10812  *   to avoid the reference count dropping to zero and the actor being
10813  *   destroyed.
10814  */
10815 void
10816 clutter_actor_reparent (ClutterActor *self,
10817                         ClutterActor *new_parent)
10818 {
10819   ClutterActorPrivate *priv;
10820
10821   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10822   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
10823   g_return_if_fail (self != new_parent);
10824
10825   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10826     {
10827       g_warning ("Cannot set a parent on a toplevel actor");
10828       return;
10829     }
10830
10831   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
10832     {
10833       g_warning ("Cannot set a parent currently being destroyed");
10834       return;
10835     }
10836
10837   priv = self->priv;
10838
10839   if (priv->parent != new_parent)
10840     {
10841       ClutterActor *old_parent;
10842
10843       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10844
10845       old_parent = priv->parent;
10846
10847       g_object_ref (self);
10848
10849       if (old_parent != NULL)
10850         {
10851          /* go through the Container implementation if this is a regular
10852           * child and not an internal one
10853           */
10854          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10855            {
10856              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
10857
10858              /* this will have to call unparent() */
10859              clutter_container_remove_actor (parent, self);
10860            }
10861          else
10862            clutter_actor_remove_child_internal (old_parent, self,
10863                                                 REMOVE_CHILD_LEGACY_FLAGS);
10864         }
10865
10866       /* Note, will call set_parent() */
10867       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10868         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
10869       else
10870         clutter_actor_add_child_internal (new_parent, self,
10871                                           ADD_CHILD_LEGACY_FLAGS,
10872                                           insert_child_at_depth,
10873                                           NULL);
10874
10875       /* we emit the ::parent-set signal once */
10876       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
10877
10878       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10879
10880       /* the IN_REPARENT flag suspends state updates */
10881       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
10882
10883       g_object_unref (self);
10884    }
10885 }
10886
10887 /**
10888  * clutter_actor_contains:
10889  * @self: A #ClutterActor
10890  * @descendant: A #ClutterActor, possibly contained in @self
10891  *
10892  * Determines if @descendant is contained inside @self (either as an
10893  * immediate child, or as a deeper descendant). If @self and
10894  * @descendant point to the same actor then it will also return %TRUE.
10895  *
10896  * Return value: whether @descendent is contained within @self
10897  *
10898  * Since: 1.4
10899  */
10900 gboolean
10901 clutter_actor_contains (ClutterActor *self,
10902                         ClutterActor *descendant)
10903 {
10904   ClutterActor *actor;
10905
10906   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10907   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
10908
10909   for (actor = descendant; actor; actor = actor->priv->parent)
10910     if (actor == self)
10911       return TRUE;
10912
10913   return FALSE;
10914 }
10915
10916 /**
10917  * clutter_actor_set_child_above_sibling:
10918  * @self: a #ClutterActor
10919  * @child: a #ClutterActor child of @self
10920  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10921  *
10922  * Sets @child to be above @sibling in the list of children of @self.
10923  *
10924  * If @sibling is %NULL, @child will be the new last child of @self.
10925  *
10926  * This function is logically equivalent to removing @child and using
10927  * clutter_actor_insert_child_above(), but it will not emit signals
10928  * or change state on @child.
10929  *
10930  * Since: 1.10
10931  */
10932 void
10933 clutter_actor_set_child_above_sibling (ClutterActor *self,
10934                                        ClutterActor *child,
10935                                        ClutterActor *sibling)
10936 {
10937   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10938   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10939   g_return_if_fail (child->priv->parent == self);
10940   g_return_if_fail (child != sibling);
10941   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10942
10943   if (sibling != NULL)
10944     g_return_if_fail (sibling->priv->parent == self);
10945
10946   /* we don't want to change the state of child, or emit signals, or
10947    * regenerate ChildMeta instances here, but we still want to follow
10948    * the correct sequence of steps encoded in remove_child() and
10949    * add_child(), so that correctness is ensured, and we only go
10950    * through one known code path.
10951    */
10952   g_object_ref (child);
10953   clutter_actor_remove_child_internal (self, child, 0);
10954   clutter_actor_add_child_internal (self, child,
10955                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10956                                     insert_child_above,
10957                                     sibling);
10958
10959   clutter_actor_queue_relayout (self);
10960 }
10961
10962 /**
10963  * clutter_actor_set_child_below_sibling:
10964  * @self: a #ClutterActor
10965  * @child: a #ClutterActor child of @self
10966  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10967  *
10968  * Sets @child to be below @sibling in the list of children of @self.
10969  *
10970  * If @sibling is %NULL, @child will be the new first child of @self.
10971  *
10972  * This function is logically equivalent to removing @self and using
10973  * clutter_actor_insert_child_below(), but it will not emit signals
10974  * or change state on @child.
10975  *
10976  * Since: 1.10
10977  */
10978 void
10979 clutter_actor_set_child_below_sibling (ClutterActor *self,
10980                                        ClutterActor *child,
10981                                        ClutterActor *sibling)
10982 {
10983   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10984   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10985   g_return_if_fail (child->priv->parent == self);
10986   g_return_if_fail (child != sibling);
10987   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10988
10989   if (sibling != NULL)
10990     g_return_if_fail (sibling->priv->parent == self);
10991
10992   /* see the comment in set_child_above_sibling() */
10993   g_object_ref (child);
10994   clutter_actor_remove_child_internal (self, child, 0);
10995   clutter_actor_add_child_internal (self, child,
10996                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10997                                     insert_child_below,
10998                                     sibling);
10999
11000   clutter_actor_queue_relayout (self);
11001 }
11002
11003 /**
11004  * clutter_actor_set_child_at_index:
11005  * @self: a #ClutterActor
11006  * @child: a #ClutterActor child of @self
11007  * @index_: the new index for @child
11008  *
11009  * Changes the index of @child in the list of children of @self.
11010  *
11011  * This function is logically equivalent to removing @child and
11012  * calling clutter_actor_insert_child_at_index(), but it will not
11013  * emit signals or change state on @child.
11014  *
11015  * Since: 1.10
11016  */
11017 void
11018 clutter_actor_set_child_at_index (ClutterActor *self,
11019                                   ClutterActor *child,
11020                                   gint          index_)
11021 {
11022   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11023   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11024   g_return_if_fail (child->priv->parent == self);
11025   g_return_if_fail (index_ <= self->priv->n_children);
11026
11027   g_object_ref (child);
11028   clutter_actor_remove_child_internal (self, child, 0);
11029   clutter_actor_add_child_internal (self, child,
11030                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11031                                     insert_child_at_index,
11032                                     GINT_TO_POINTER (index_));
11033
11034   clutter_actor_queue_relayout (self);
11035 }
11036
11037 /**
11038  * clutter_actor_raise:
11039  * @self: A #ClutterActor
11040  * @below: (allow-none): A #ClutterActor to raise above.
11041  *
11042  * Puts @self above @below.
11043  *
11044  * Both actors must have the same parent, and the parent must implement
11045  * the #ClutterContainer interface
11046  *
11047  * This function calls clutter_container_raise_child() internally.
11048  *
11049  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11050  */
11051 void
11052 clutter_actor_raise (ClutterActor *self,
11053                      ClutterActor *below)
11054 {
11055   ClutterActor *parent;
11056
11057   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11058
11059   parent = clutter_actor_get_parent (self);
11060   if (parent == NULL)
11061     {
11062       g_warning ("%s: Actor '%s' is not inside a container",
11063                  G_STRFUNC,
11064                  _clutter_actor_get_debug_name (self));
11065       return;
11066     }
11067
11068   if (below != NULL)
11069     {
11070       if (parent != clutter_actor_get_parent (below))
11071         {
11072           g_warning ("%s Actor '%s' is not in the same container as "
11073                      "actor '%s'",
11074                      G_STRFUNC,
11075                      _clutter_actor_get_debug_name (self),
11076                      _clutter_actor_get_debug_name (below));
11077           return;
11078         }
11079     }
11080
11081   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11082 }
11083
11084 /**
11085  * clutter_actor_lower:
11086  * @self: A #ClutterActor
11087  * @above: (allow-none): A #ClutterActor to lower below
11088  *
11089  * Puts @self below @above.
11090  *
11091  * Both actors must have the same parent, and the parent must implement
11092  * the #ClutterContainer interface.
11093  *
11094  * This function calls clutter_container_lower_child() internally.
11095  *
11096  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11097  */
11098 void
11099 clutter_actor_lower (ClutterActor *self,
11100                      ClutterActor *above)
11101 {
11102   ClutterActor *parent;
11103
11104   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11105
11106   parent = clutter_actor_get_parent (self);
11107   if (parent == NULL)
11108     {
11109       g_warning ("%s: Actor of type %s is not inside a container",
11110                  G_STRFUNC,
11111                  _clutter_actor_get_debug_name (self));
11112       return;
11113     }
11114
11115   if (above)
11116     {
11117       if (parent != clutter_actor_get_parent (above))
11118         {
11119           g_warning ("%s: Actor '%s' is not in the same container as "
11120                      "actor '%s'",
11121                      G_STRFUNC,
11122                      _clutter_actor_get_debug_name (self),
11123                      _clutter_actor_get_debug_name (above));
11124           return;
11125         }
11126     }
11127
11128   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11129 }
11130
11131 /**
11132  * clutter_actor_raise_top:
11133  * @self: A #ClutterActor
11134  *
11135  * Raises @self to the top.
11136  *
11137  * This function calls clutter_actor_raise() internally.
11138  *
11139  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11140  *   a %NULL sibling, instead.
11141  */
11142 void
11143 clutter_actor_raise_top (ClutterActor *self)
11144 {
11145   clutter_actor_raise (self, NULL);
11146 }
11147
11148 /**
11149  * clutter_actor_lower_bottom:
11150  * @self: A #ClutterActor
11151  *
11152  * Lowers @self to the bottom.
11153  *
11154  * This function calls clutter_actor_lower() internally.
11155  *
11156  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11157  *   a %NULL sibling, instead.
11158  */
11159 void
11160 clutter_actor_lower_bottom (ClutterActor *self)
11161 {
11162   clutter_actor_lower (self, NULL);
11163 }
11164
11165 /*
11166  * Event handling
11167  */
11168
11169 /**
11170  * clutter_actor_event:
11171  * @actor: a #ClutterActor
11172  * @event: a #ClutterEvent
11173  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11174  *
11175  * This function is used to emit an event on the main stage.
11176  * You should rarely need to use this function, except for
11177  * synthetising events.
11178  *
11179  * Return value: the return value from the signal emission: %TRUE
11180  *   if the actor handled the event, or %FALSE if the event was
11181  *   not handled
11182  *
11183  * Since: 0.6
11184  */
11185 gboolean
11186 clutter_actor_event (ClutterActor *actor,
11187                      ClutterEvent *event,
11188                      gboolean      capture)
11189 {
11190   gboolean retval = FALSE;
11191   gint signal_num = -1;
11192
11193   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11194   g_return_val_if_fail (event != NULL, FALSE);
11195
11196   g_object_ref (actor);
11197
11198   if (capture)
11199     {
11200       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11201                      event,
11202                      &retval);
11203       goto out;
11204     }
11205
11206   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11207
11208   if (!retval)
11209     {
11210       switch (event->type)
11211         {
11212         case CLUTTER_NOTHING:
11213           break;
11214         case CLUTTER_BUTTON_PRESS:
11215           signal_num = BUTTON_PRESS_EVENT;
11216           break;
11217         case CLUTTER_BUTTON_RELEASE:
11218           signal_num = BUTTON_RELEASE_EVENT;
11219           break;
11220         case CLUTTER_SCROLL:
11221           signal_num = SCROLL_EVENT;
11222           break;
11223         case CLUTTER_KEY_PRESS:
11224           signal_num = KEY_PRESS_EVENT;
11225           break;
11226         case CLUTTER_KEY_RELEASE:
11227           signal_num = KEY_RELEASE_EVENT;
11228           break;
11229         case CLUTTER_MOTION:
11230           signal_num = MOTION_EVENT;
11231           break;
11232         case CLUTTER_ENTER:
11233           signal_num = ENTER_EVENT;
11234           break;
11235         case CLUTTER_LEAVE:
11236           signal_num = LEAVE_EVENT;
11237           break;
11238         case CLUTTER_DELETE:
11239         case CLUTTER_DESTROY_NOTIFY:
11240         case CLUTTER_CLIENT_MESSAGE:
11241         default:
11242           signal_num = -1;
11243           break;
11244         }
11245
11246       if (signal_num != -1)
11247         g_signal_emit (actor, actor_signals[signal_num], 0,
11248                        event, &retval);
11249     }
11250
11251 out:
11252   g_object_unref (actor);
11253
11254   return retval;
11255 }
11256
11257 /**
11258  * clutter_actor_set_reactive:
11259  * @actor: a #ClutterActor
11260  * @reactive: whether the actor should be reactive to events
11261  *
11262  * Sets @actor as reactive. Reactive actors will receive events.
11263  *
11264  * Since: 0.6
11265  */
11266 void
11267 clutter_actor_set_reactive (ClutterActor *actor,
11268                             gboolean      reactive)
11269 {
11270   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11271
11272   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11273     return;
11274
11275   if (reactive)
11276     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11277   else
11278     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11279
11280   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11281 }
11282
11283 /**
11284  * clutter_actor_get_reactive:
11285  * @actor: a #ClutterActor
11286  *
11287  * Checks whether @actor is marked as reactive.
11288  *
11289  * Return value: %TRUE if the actor is reactive
11290  *
11291  * Since: 0.6
11292  */
11293 gboolean
11294 clutter_actor_get_reactive (ClutterActor *actor)
11295 {
11296   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11297
11298   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11299 }
11300
11301 /**
11302  * clutter_actor_get_anchor_point:
11303  * @self: a #ClutterActor
11304  * @anchor_x: (out): return location for the X coordinate of the anchor point
11305  * @anchor_y: (out): return location for the Y coordinate of the anchor point
11306  *
11307  * Gets the current anchor point of the @actor in pixels.
11308  *
11309  * Since: 0.6
11310  */
11311 void
11312 clutter_actor_get_anchor_point (ClutterActor *self,
11313                                 gfloat       *anchor_x,
11314                                 gfloat       *anchor_y)
11315 {
11316   const ClutterTransformInfo *info;
11317
11318   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11319
11320   info = _clutter_actor_get_transform_info_or_defaults (self);
11321   clutter_anchor_coord_get_units (self, &info->anchor,
11322                                   anchor_x,
11323                                   anchor_y,
11324                                   NULL);
11325 }
11326
11327 /**
11328  * clutter_actor_set_anchor_point:
11329  * @self: a #ClutterActor
11330  * @anchor_x: X coordinate of the anchor point
11331  * @anchor_y: Y coordinate of the anchor point
11332  *
11333  * Sets an anchor point for @self. The anchor point is a point in the
11334  * coordinate space of an actor to which the actor position within its
11335  * parent is relative; the default is (0, 0), i.e. the top-left corner
11336  * of the actor.
11337  *
11338  * Since: 0.6
11339  */
11340 void
11341 clutter_actor_set_anchor_point (ClutterActor *self,
11342                                 gfloat        anchor_x,
11343                                 gfloat        anchor_y)
11344 {
11345   ClutterTransformInfo *info;
11346   ClutterActorPrivate *priv;
11347   gboolean changed = FALSE;
11348   gfloat old_anchor_x, old_anchor_y;
11349   GObject *obj;
11350
11351   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11352
11353   obj = G_OBJECT (self);
11354   priv = self->priv;
11355   info = _clutter_actor_get_transform_info (self);
11356
11357   g_object_freeze_notify (obj);
11358
11359   clutter_anchor_coord_get_units (self, &info->anchor,
11360                                   &old_anchor_x,
11361                                   &old_anchor_y,
11362                                   NULL);
11363
11364   if (info->anchor.is_fractional)
11365     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11366
11367   if (old_anchor_x != anchor_x)
11368     {
11369       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11370       changed = TRUE;
11371     }
11372
11373   if (old_anchor_y != anchor_y)
11374     {
11375       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11376       changed = TRUE;
11377     }
11378
11379   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11380
11381   if (changed)
11382     {
11383       priv->transform_valid = FALSE;
11384       clutter_actor_queue_redraw (self);
11385     }
11386
11387   g_object_thaw_notify (obj);
11388 }
11389
11390 /**
11391  * clutter_actor_get_anchor_point_gravity:
11392  * @self: a #ClutterActor
11393  *
11394  * Retrieves the anchor position expressed as a #ClutterGravity. If
11395  * the anchor point was specified using pixels or units this will
11396  * return %CLUTTER_GRAVITY_NONE.
11397  *
11398  * Return value: the #ClutterGravity used by the anchor point
11399  *
11400  * Since: 1.0
11401  */
11402 ClutterGravity
11403 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11404 {
11405   const ClutterTransformInfo *info;
11406
11407   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11408
11409   info = _clutter_actor_get_transform_info_or_defaults (self);
11410
11411   return clutter_anchor_coord_get_gravity (&info->anchor);
11412 }
11413
11414 /**
11415  * clutter_actor_move_anchor_point:
11416  * @self: a #ClutterActor
11417  * @anchor_x: X coordinate of the anchor point
11418  * @anchor_y: Y coordinate of the anchor point
11419  *
11420  * Sets an anchor point for the actor, and adjusts the actor postion so that
11421  * the relative position of the actor toward its parent remains the same.
11422  *
11423  * Since: 0.6
11424  */
11425 void
11426 clutter_actor_move_anchor_point (ClutterActor *self,
11427                                  gfloat        anchor_x,
11428                                  gfloat        anchor_y)
11429 {
11430   gfloat old_anchor_x, old_anchor_y;
11431   const ClutterTransformInfo *info;
11432
11433   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11434
11435   info = _clutter_actor_get_transform_info (self);
11436   clutter_anchor_coord_get_units (self, &info->anchor,
11437                                   &old_anchor_x,
11438                                   &old_anchor_y,
11439                                   NULL);
11440
11441   g_object_freeze_notify (G_OBJECT (self));
11442
11443   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
11444
11445   if (self->priv->position_set)
11446     clutter_actor_move_by (self,
11447                            anchor_x - old_anchor_x,
11448                            anchor_y - old_anchor_y);
11449
11450   g_object_thaw_notify (G_OBJECT (self));
11451 }
11452
11453 /**
11454  * clutter_actor_move_anchor_point_from_gravity:
11455  * @self: a #ClutterActor
11456  * @gravity: #ClutterGravity.
11457  *
11458  * Sets an anchor point on the actor based on the given gravity, adjusting the
11459  * actor postion so that its relative position within its parent remains
11460  * unchanged.
11461  *
11462  * Since version 1.0 the anchor point will be stored as a gravity so
11463  * that if the actor changes size then the anchor point will move. For
11464  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11465  * and later double the size of the actor, the anchor point will move
11466  * to the bottom right.
11467  *
11468  * Since: 0.6
11469  */
11470 void
11471 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
11472                                               ClutterGravity  gravity)
11473 {
11474   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
11475   const ClutterTransformInfo *info;
11476   ClutterActorPrivate *priv;
11477
11478   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11479
11480   priv = self->priv;
11481   info = _clutter_actor_get_transform_info (self);
11482
11483   g_object_freeze_notify (G_OBJECT (self));
11484
11485   clutter_anchor_coord_get_units (self, &info->anchor,
11486                                   &old_anchor_x,
11487                                   &old_anchor_y,
11488                                   NULL);
11489   clutter_actor_set_anchor_point_from_gravity (self, gravity);
11490   clutter_anchor_coord_get_units (self, &info->anchor,
11491                                   &new_anchor_x,
11492                                   &new_anchor_y,
11493                                   NULL);
11494
11495   if (priv->position_set)
11496     clutter_actor_move_by (self,
11497                            new_anchor_x - old_anchor_x,
11498                            new_anchor_y - old_anchor_y);
11499
11500   g_object_thaw_notify (G_OBJECT (self));
11501 }
11502
11503 /**
11504  * clutter_actor_set_anchor_point_from_gravity:
11505  * @self: a #ClutterActor
11506  * @gravity: #ClutterGravity.
11507  *
11508  * Sets an anchor point on the actor, based on the given gravity (this is a
11509  * convenience function wrapping clutter_actor_set_anchor_point()).
11510  *
11511  * Since version 1.0 the anchor point will be stored as a gravity so
11512  * that if the actor changes size then the anchor point will move. For
11513  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11514  * and later double the size of the actor, the anchor point will move
11515  * to the bottom right.
11516  *
11517  * Since: 0.6
11518  */
11519 void
11520 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
11521                                              ClutterGravity  gravity)
11522 {
11523   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11524
11525   if (gravity == CLUTTER_GRAVITY_NONE)
11526     clutter_actor_set_anchor_point (self, 0, 0);
11527   else
11528     {
11529       GObject *obj = G_OBJECT (self);
11530       ClutterTransformInfo *info;
11531
11532       g_object_freeze_notify (obj);
11533
11534       info = _clutter_actor_get_transform_info (self);
11535       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
11536
11537       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11538       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11539       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11540
11541       self->priv->transform_valid = FALSE;
11542
11543       clutter_actor_queue_redraw (self);
11544
11545       g_object_thaw_notify (obj);
11546     }
11547 }
11548
11549 static void
11550 clutter_container_iface_init (ClutterContainerIface *iface)
11551 {
11552   /* we don't override anything, as ClutterContainer already has a default
11553    * implementation that we can use, and which calls into our own API.
11554    */
11555 }
11556
11557 typedef enum
11558 {
11559   PARSE_X,
11560   PARSE_Y,
11561   PARSE_WIDTH,
11562   PARSE_HEIGHT,
11563   PARSE_ANCHOR_X,
11564   PARSE_ANCHOR_Y
11565 } ParseDimension;
11566
11567 static gfloat
11568 parse_units (ClutterActor   *self,
11569              ParseDimension  dimension,
11570              JsonNode       *node)
11571 {
11572   GValue value = { 0, };
11573   gfloat retval = 0;
11574
11575   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
11576     return 0;
11577
11578   json_node_get_value (node, &value);
11579
11580   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
11581     {
11582       retval = (gfloat) g_value_get_int64 (&value);
11583     }
11584   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
11585     {
11586       retval = g_value_get_double (&value);
11587     }
11588   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
11589     {
11590       ClutterUnits units;
11591       gboolean res;
11592
11593       res = clutter_units_from_string (&units, g_value_get_string (&value));
11594       if (res)
11595         retval = clutter_units_to_pixels (&units);
11596       else
11597         {
11598           g_warning ("Invalid value '%s': integers, strings or floating point "
11599                      "values can be used for the x, y, width and height "
11600                      "properties. Valid modifiers for strings are 'px', 'mm', "
11601                      "'pt' and 'em'.",
11602                      g_value_get_string (&value));
11603           retval = 0;
11604         }
11605     }
11606   else
11607     {
11608       g_warning ("Invalid value of type '%s': integers, strings of floating "
11609                  "point values can be used for the x, y, width, height "
11610                  "anchor-x and anchor-y properties.",
11611                  g_type_name (G_VALUE_TYPE (&value)));
11612     }
11613
11614   g_value_unset (&value);
11615
11616   return retval;
11617 }
11618
11619 typedef struct {
11620   ClutterRotateAxis axis;
11621
11622   gdouble angle;
11623
11624   gfloat center_x;
11625   gfloat center_y;
11626   gfloat center_z;
11627 } RotationInfo;
11628
11629 static inline gboolean
11630 parse_rotation_array (ClutterActor *actor,
11631                       JsonArray    *array,
11632                       RotationInfo *info)
11633 {
11634   JsonNode *element;
11635
11636   if (json_array_get_length (array) != 2)
11637     return FALSE;
11638
11639   /* angle */
11640   element = json_array_get_element (array, 0);
11641   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
11642     info->angle = json_node_get_double (element);
11643   else
11644     return FALSE;
11645
11646   /* center */
11647   element = json_array_get_element (array, 1);
11648   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
11649     {
11650       JsonArray *center = json_node_get_array (element);
11651
11652       if (json_array_get_length (center) != 2)
11653         return FALSE;
11654
11655       switch (info->axis)
11656         {
11657         case CLUTTER_X_AXIS:
11658           info->center_y = parse_units (actor, PARSE_Y,
11659                                         json_array_get_element (center, 0));
11660           info->center_z = parse_units (actor, PARSE_Y,
11661                                         json_array_get_element (center, 1));
11662           return TRUE;
11663
11664         case CLUTTER_Y_AXIS:
11665           info->center_x = parse_units (actor, PARSE_X,
11666                                         json_array_get_element (center, 0));
11667           info->center_z = parse_units (actor, PARSE_X,
11668                                         json_array_get_element (center, 1));
11669           return TRUE;
11670
11671         case CLUTTER_Z_AXIS:
11672           info->center_x = parse_units (actor, PARSE_X,
11673                                         json_array_get_element (center, 0));
11674           info->center_y = parse_units (actor, PARSE_Y,
11675                                         json_array_get_element (center, 1));
11676           return TRUE;
11677         }
11678     }
11679
11680   return FALSE;
11681 }
11682
11683 static gboolean
11684 parse_rotation (ClutterActor *actor,
11685                 JsonNode     *node,
11686                 RotationInfo *info)
11687 {
11688   JsonArray *array;
11689   guint len, i;
11690   gboolean retval = FALSE;
11691
11692   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
11693     {
11694       g_warning ("Invalid node of type '%s' found, expecting an array",
11695                  json_node_type_name (node));
11696       return FALSE;
11697     }
11698
11699   array = json_node_get_array (node);
11700   len = json_array_get_length (array);
11701
11702   for (i = 0; i < len; i++)
11703     {
11704       JsonNode *element = json_array_get_element (array, i);
11705       JsonObject *object;
11706       JsonNode *member;
11707
11708       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
11709         {
11710           g_warning ("Invalid node of type '%s' found, expecting an object",
11711                      json_node_type_name (element));
11712           return FALSE;
11713         }
11714
11715       object = json_node_get_object (element);
11716
11717       if (json_object_has_member (object, "x-axis"))
11718         {
11719           member = json_object_get_member (object, "x-axis");
11720
11721           info->axis = CLUTTER_X_AXIS;
11722
11723           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11724             {
11725               info->angle = json_node_get_double (member);
11726               retval = TRUE;
11727             }
11728           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11729             retval = parse_rotation_array (actor,
11730                                            json_node_get_array (member),
11731                                            info);
11732           else
11733             retval = FALSE;
11734         }
11735       else if (json_object_has_member (object, "y-axis"))
11736         {
11737           member = json_object_get_member (object, "y-axis");
11738
11739           info->axis = CLUTTER_Y_AXIS;
11740
11741           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11742             {
11743               info->angle = json_node_get_double (member);
11744               retval = TRUE;
11745             }
11746           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11747             retval = parse_rotation_array (actor,
11748                                            json_node_get_array (member),
11749                                            info);
11750           else
11751             retval = FALSE;
11752         }
11753       else if (json_object_has_member (object, "z-axis"))
11754         {
11755           member = json_object_get_member (object, "z-axis");
11756
11757           info->axis = CLUTTER_Z_AXIS;
11758
11759           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11760             {
11761               info->angle = json_node_get_double (member);
11762               retval = TRUE;
11763             }
11764           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11765             retval = parse_rotation_array (actor,
11766                                            json_node_get_array (member),
11767                                            info);
11768           else
11769             retval = FALSE;
11770         }
11771     }
11772
11773   return retval;
11774 }
11775
11776 static GSList *
11777 parse_actor_metas (ClutterScript *script,
11778                    ClutterActor  *actor,
11779                    JsonNode      *node)
11780 {
11781   GList *elements, *l;
11782   GSList *retval = NULL;
11783
11784   if (!JSON_NODE_HOLDS_ARRAY (node))
11785     return NULL;
11786
11787   elements = json_array_get_elements (json_node_get_array (node));
11788
11789   for (l = elements; l != NULL; l = l->next)
11790     {
11791       JsonNode *element = l->data;
11792       const gchar *id_ = _clutter_script_get_id_from_node (element);
11793       GObject *meta;
11794
11795       if (id_ == NULL || *id_ == '\0')
11796         continue;
11797
11798       meta = clutter_script_get_object (script, id_);
11799       if (meta == NULL)
11800         continue;
11801
11802       retval = g_slist_prepend (retval, meta);
11803     }
11804
11805   g_list_free (elements);
11806
11807   return g_slist_reverse (retval);
11808 }
11809
11810 static GSList *
11811 parse_behaviours (ClutterScript *script,
11812                   ClutterActor  *actor,
11813                   JsonNode      *node)
11814 {
11815   GList *elements, *l;
11816   GSList *retval = NULL;
11817
11818   if (!JSON_NODE_HOLDS_ARRAY (node))
11819     return NULL;
11820
11821   elements = json_array_get_elements (json_node_get_array (node));
11822
11823   for (l = elements; l != NULL; l = l->next)
11824     {
11825       JsonNode *element = l->data;
11826       const gchar *id_ = _clutter_script_get_id_from_node (element);
11827       GObject *behaviour;
11828
11829       if (id_ == NULL || *id_ == '\0')
11830         continue;
11831
11832       behaviour = clutter_script_get_object (script, id_);
11833       if (behaviour == NULL)
11834         continue;
11835
11836       retval = g_slist_prepend (retval, behaviour);
11837     }
11838
11839   g_list_free (elements);
11840
11841   return g_slist_reverse (retval);
11842 }
11843
11844 static gboolean
11845 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
11846                                  ClutterScript     *script,
11847                                  GValue            *value,
11848                                  const gchar       *name,
11849                                  JsonNode          *node)
11850 {
11851   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11852   gboolean retval = FALSE;
11853
11854   if ((name[0] == 'x' && name[1] == '\0') ||
11855       (name[0] == 'y' && name[1] == '\0') ||
11856       (strcmp (name, "width") == 0) ||
11857       (strcmp (name, "height") == 0) ||
11858       (strcmp (name, "anchor_x") == 0) ||
11859       (strcmp (name, "anchor_y") == 0))
11860     {
11861       ParseDimension dimension;
11862       gfloat units;
11863
11864       if (name[0] == 'x')
11865         dimension = PARSE_X;
11866       else if (name[0] == 'y')
11867         dimension = PARSE_Y;
11868       else if (name[0] == 'w')
11869         dimension = PARSE_WIDTH;
11870       else if (name[0] == 'h')
11871         dimension = PARSE_HEIGHT;
11872       else if (name[0] == 'a' && name[7] == 'x')
11873         dimension = PARSE_ANCHOR_X;
11874       else if (name[0] == 'a' && name[7] == 'y')
11875         dimension = PARSE_ANCHOR_Y;
11876       else
11877         return FALSE;
11878
11879       units = parse_units (actor, dimension, node);
11880
11881       /* convert back to pixels: all properties are pixel-based */
11882       g_value_init (value, G_TYPE_FLOAT);
11883       g_value_set_float (value, units);
11884
11885       retval = TRUE;
11886     }
11887   else if (strcmp (name, "rotation") == 0)
11888     {
11889       RotationInfo *info;
11890
11891       info = g_slice_new0 (RotationInfo);
11892       retval = parse_rotation (actor, node, info);
11893
11894       if (retval)
11895         {
11896           g_value_init (value, G_TYPE_POINTER);
11897           g_value_set_pointer (value, info);
11898         }
11899       else
11900         g_slice_free (RotationInfo, info);
11901     }
11902   else if (strcmp (name, "behaviours") == 0)
11903     {
11904       GSList *l;
11905
11906 #ifdef CLUTTER_ENABLE_DEBUG
11907       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
11908         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
11909                                      "and it should not be used in newly "
11910                                      "written ClutterScript definitions.");
11911 #endif
11912
11913       l = parse_behaviours (script, actor, node);
11914
11915       g_value_init (value, G_TYPE_POINTER);
11916       g_value_set_pointer (value, l);
11917
11918       retval = TRUE;
11919     }
11920   else if (strcmp (name, "actions") == 0 ||
11921            strcmp (name, "constraints") == 0 ||
11922            strcmp (name, "effects") == 0)
11923     {
11924       GSList *l;
11925
11926       l = parse_actor_metas (script, actor, node);
11927
11928       g_value_init (value, G_TYPE_POINTER);
11929       g_value_set_pointer (value, l);
11930
11931       retval = TRUE;
11932     }
11933
11934   return retval;
11935 }
11936
11937 static void
11938 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
11939                                    ClutterScript     *script,
11940                                    const gchar       *name,
11941                                    const GValue      *value)
11942 {
11943   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11944
11945 #ifdef CLUTTER_ENABLE_DEBUG
11946   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
11947     {
11948       gchar *tmp = g_strdup_value_contents (value);
11949
11950       CLUTTER_NOTE (SCRIPT,
11951                     "in ClutterActor::set_custom_property('%s') = %s",
11952                     name,
11953                     tmp);
11954
11955       g_free (tmp);
11956     }
11957 #endif /* CLUTTER_ENABLE_DEBUG */
11958
11959   if (strcmp (name, "rotation") == 0)
11960     {
11961       RotationInfo *info;
11962
11963       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11964         return;
11965
11966       info = g_value_get_pointer (value);
11967
11968       clutter_actor_set_rotation (actor,
11969                                   info->axis, info->angle,
11970                                   info->center_x,
11971                                   info->center_y,
11972                                   info->center_z);
11973
11974       g_slice_free (RotationInfo, info);
11975
11976       return;
11977     }
11978
11979   if (strcmp (name, "behaviours") == 0)
11980     {
11981       GSList *behaviours, *l;
11982
11983       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11984         return;
11985
11986       behaviours = g_value_get_pointer (value);
11987       for (l = behaviours; l != NULL; l = l->next)
11988         {
11989           ClutterBehaviour *behaviour = l->data;
11990
11991           clutter_behaviour_apply (behaviour, actor);
11992         }
11993
11994       g_slist_free (behaviours);
11995
11996       return;
11997     }
11998
11999   if (strcmp (name, "actions") == 0 ||
12000       strcmp (name, "constraints") == 0 ||
12001       strcmp (name, "effects") == 0)
12002     {
12003       GSList *metas, *l;
12004
12005       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12006         return;
12007
12008       metas = g_value_get_pointer (value);
12009       for (l = metas; l != NULL; l = l->next)
12010         {
12011           if (name[0] == 'a')
12012             clutter_actor_add_action (actor, l->data);
12013
12014           if (name[0] == 'c')
12015             clutter_actor_add_constraint (actor, l->data);
12016
12017           if (name[0] == 'e')
12018             clutter_actor_add_effect (actor, l->data);
12019         }
12020
12021       g_slist_free (metas);
12022
12023       return;
12024     }
12025
12026   g_object_set_property (G_OBJECT (scriptable), name, value);
12027 }
12028
12029 static void
12030 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12031 {
12032   iface->parse_custom_node = clutter_actor_parse_custom_node;
12033   iface->set_custom_property = clutter_actor_set_custom_property;
12034 }
12035
12036 static ClutterActorMeta *
12037 get_meta_from_animation_property (ClutterActor  *actor,
12038                                   const gchar   *name,
12039                                   gchar        **name_p)
12040 {
12041   ClutterActorPrivate *priv = actor->priv;
12042   ClutterActorMeta *meta = NULL;
12043   gchar **tokens;
12044
12045   /* if this is not a special property, fall through */
12046   if (name[0] != '@')
12047     return NULL;
12048
12049   /* detect the properties named using the following spec:
12050    *
12051    *   @<section>.<meta-name>.<property-name>
12052    *
12053    * where <section> can be one of the following:
12054    *
12055    *   - actions
12056    *   - constraints
12057    *   - effects
12058    *
12059    * and <meta-name> is the name set on a specific ActorMeta
12060    */
12061
12062   tokens = g_strsplit (name + 1, ".", -1);
12063   if (tokens == NULL || g_strv_length (tokens) != 3)
12064     {
12065       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12066                     name + 1);
12067       g_strfreev (tokens);
12068       return NULL;
12069     }
12070
12071   if (strcmp (tokens[0], "actions") == 0)
12072     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12073
12074   if (strcmp (tokens[0], "constraints") == 0)
12075     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12076
12077   if (strcmp (tokens[0], "effects") == 0)
12078     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12079
12080   if (name_p != NULL)
12081     *name_p = g_strdup (tokens[2]);
12082
12083   CLUTTER_NOTE (ANIMATION,
12084                 "Looking for property '%s' of object '%s' in section '%s'",
12085                 tokens[2],
12086                 tokens[1],
12087                 tokens[0]);
12088
12089   g_strfreev (tokens);
12090
12091   return meta;
12092 }
12093
12094 static GParamSpec *
12095 clutter_actor_find_property (ClutterAnimatable *animatable,
12096                              const gchar       *property_name)
12097 {
12098   ClutterActorMeta *meta = NULL;
12099   GObjectClass *klass = NULL;
12100   GParamSpec *pspec = NULL;
12101   gchar *p_name = NULL;
12102
12103   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12104                                            property_name,
12105                                            &p_name);
12106
12107   if (meta != NULL)
12108     {
12109       klass = G_OBJECT_GET_CLASS (meta);
12110
12111       pspec = g_object_class_find_property (klass, p_name);
12112     }
12113   else
12114     {
12115       klass = G_OBJECT_GET_CLASS (animatable);
12116
12117       pspec = g_object_class_find_property (klass, property_name);
12118     }
12119
12120   g_free (p_name);
12121
12122   return pspec;
12123 }
12124
12125 static void
12126 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12127                                  const gchar       *property_name,
12128                                  GValue            *initial)
12129 {
12130   ClutterActorMeta *meta = NULL;
12131   gchar *p_name = NULL;
12132
12133   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12134                                            property_name,
12135                                            &p_name);
12136
12137   if (meta != NULL)
12138     g_object_get_property (G_OBJECT (meta), p_name, initial);
12139   else
12140     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12141
12142   g_free (p_name);
12143 }
12144
12145 static void
12146 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12147                                const gchar       *property_name,
12148                                const GValue      *final)
12149 {
12150   ClutterActorMeta *meta = NULL;
12151   gchar *p_name = NULL;
12152
12153   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12154                                            property_name,
12155                                            &p_name);
12156   if (meta != NULL)
12157     g_object_set_property (G_OBJECT (meta), p_name, final);
12158   else
12159     g_object_set_property (G_OBJECT (animatable), property_name, final);
12160
12161   g_free (p_name);
12162 }
12163
12164 static void
12165 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12166 {
12167   iface->find_property = clutter_actor_find_property;
12168   iface->get_initial_state = clutter_actor_get_initial_state;
12169   iface->set_final_state = clutter_actor_set_final_state;
12170 }
12171
12172 /**
12173  * clutter_actor_transform_stage_point:
12174  * @self: A #ClutterActor
12175  * @x: (in): x screen coordinate of the point to unproject
12176  * @y: (in): y screen coordinate of the point to unproject
12177  * @x_out: (out): return location for the unprojected x coordinance
12178  * @y_out: (out): return location for the unprojected y coordinance
12179  *
12180  * This function translates screen coordinates (@x, @y) to
12181  * coordinates relative to the actor. For example, it can be used to translate
12182  * screen events from global screen coordinates into actor-local coordinates.
12183  *
12184  * The conversion can fail, notably if the transform stack results in the
12185  * actor being projected on the screen as a mere line.
12186  *
12187  * The conversion should not be expected to be pixel-perfect due to the
12188  * nature of the operation. In general the error grows when the skewing
12189  * of the actor rectangle on screen increases.
12190  *
12191  * <note><para>This function can be computationally intensive.</para></note>
12192  *
12193  * <note><para>This function only works when the allocation is up-to-date,
12194  * i.e. inside of paint().</para></note>
12195  *
12196  * Return value: %TRUE if conversion was successful.
12197  *
12198  * Since: 0.6
12199  */
12200 gboolean
12201 clutter_actor_transform_stage_point (ClutterActor *self,
12202                                      gfloat        x,
12203                                      gfloat        y,
12204                                      gfloat       *x_out,
12205                                      gfloat       *y_out)
12206 {
12207   ClutterVertex v[4];
12208   float ST[3][3];
12209   float RQ[3][3];
12210   int du, dv, xi, yi;
12211   float px, py;
12212   float xf, yf, wf, det;
12213   ClutterActorPrivate *priv;
12214
12215   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12216
12217   priv = self->priv;
12218
12219   /* This implementation is based on the quad -> quad projection algorithm
12220    * described by Paul Heckbert in:
12221    *
12222    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12223    *
12224    * and the sample implementation at:
12225    *
12226    *   http://www.cs.cmu.edu/~ph/src/texfund/
12227    *
12228    * Our texture is a rectangle with origin [0, 0], so we are mapping from
12229    * quad to rectangle only, which significantly simplifies things; the
12230    * function calls have been unrolled, and most of the math is done in fixed
12231    * point.
12232    */
12233
12234   clutter_actor_get_abs_allocation_vertices (self, v);
12235
12236   /* Keeping these as ints simplifies the multiplication (no significant
12237    * loss of precision here).
12238    */
12239   du = (int) (priv->allocation.x2 - priv->allocation.x1);
12240   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12241
12242   if (!du || !dv)
12243     return FALSE;
12244
12245 #define UX2FP(x)        (x)
12246 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12247
12248   /* First, find mapping from unit uv square to xy quadrilateral; this
12249    * equivalent to the pmap_square_quad() functions in the sample
12250    * implementation, which we can simplify, since our target is always
12251    * a rectangle.
12252    */
12253   px = v[0].x - v[1].x + v[3].x - v[2].x;
12254   py = v[0].y - v[1].y + v[3].y - v[2].y;
12255
12256   if (!px && !py)
12257     {
12258       /* affine transform */
12259       RQ[0][0] = UX2FP (v[1].x - v[0].x);
12260       RQ[1][0] = UX2FP (v[3].x - v[1].x);
12261       RQ[2][0] = UX2FP (v[0].x);
12262       RQ[0][1] = UX2FP (v[1].y - v[0].y);
12263       RQ[1][1] = UX2FP (v[3].y - v[1].y);
12264       RQ[2][1] = UX2FP (v[0].y);
12265       RQ[0][2] = 0;
12266       RQ[1][2] = 0;
12267       RQ[2][2] = 1.0;
12268     }
12269   else
12270     {
12271       /* projective transform */
12272       double dx1, dx2, dy1, dy2, del;
12273
12274       dx1 = UX2FP (v[1].x - v[3].x);
12275       dx2 = UX2FP (v[2].x - v[3].x);
12276       dy1 = UX2FP (v[1].y - v[3].y);
12277       dy2 = UX2FP (v[2].y - v[3].y);
12278
12279       del = DET2FP (dx1, dx2, dy1, dy2);
12280       if (!del)
12281         return FALSE;
12282
12283       /*
12284        * The division here needs to be done in floating point for
12285        * precisions reasons.
12286        */
12287       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12288       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12289       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12290       RQ[2][2] = 1.0;
12291       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12292       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12293       RQ[2][0] = UX2FP (v[0].x);
12294       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12295       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12296       RQ[2][1] = UX2FP (v[0].y);
12297     }
12298
12299   /*
12300    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12301    * square. Since our rectangle is based at 0,0 we only need to scale.
12302    */
12303   RQ[0][0] /= du;
12304   RQ[1][0] /= dv;
12305   RQ[0][1] /= du;
12306   RQ[1][1] /= dv;
12307   RQ[0][2] /= du;
12308   RQ[1][2] /= dv;
12309
12310   /*
12311    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12312    * inverse of that.
12313    */
12314   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12315   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12316   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12317   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12318   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12319   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12320   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12321   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12322   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12323
12324   /*
12325    * Check the resulting matrix is OK.
12326    */
12327   det = (RQ[0][0] * ST[0][0])
12328       + (RQ[0][1] * ST[0][1])
12329       + (RQ[0][2] * ST[0][2]);
12330   if (!det)
12331     return FALSE;
12332
12333   /*
12334    * Now transform our point with the ST matrix; the notional w
12335    * coordinate is 1, hence the last part is simply added.
12336    */
12337   xi = (int) x;
12338   yi = (int) y;
12339
12340   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
12341   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
12342   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
12343
12344   if (x_out)
12345     *x_out = xf / wf;
12346
12347   if (y_out)
12348     *y_out = yf / wf;
12349
12350 #undef UX2FP
12351 #undef DET2FP
12352
12353   return TRUE;
12354 }
12355
12356 /*
12357  * ClutterGeometry
12358  */
12359
12360 static ClutterGeometry*
12361 clutter_geometry_copy (const ClutterGeometry *geometry)
12362 {
12363   return g_slice_dup (ClutterGeometry, geometry);
12364 }
12365
12366 static void
12367 clutter_geometry_free (ClutterGeometry *geometry)
12368 {
12369   if (G_LIKELY (geometry != NULL))
12370     g_slice_free (ClutterGeometry, geometry);
12371 }
12372
12373 /**
12374  * clutter_geometry_union:
12375  * @geometry_a: a #ClutterGeometry
12376  * @geometry_b: another #ClutterGeometry
12377  * @result: (out): location to store the result
12378  *
12379  * Find the union of two rectangles represented as #ClutterGeometry.
12380  *
12381  * Since: 1.4
12382  */
12383 void
12384 clutter_geometry_union (const ClutterGeometry *geometry_a,
12385                         const ClutterGeometry *geometry_b,
12386                         ClutterGeometry       *result)
12387 {
12388   /* We don't try to handle rectangles that can't be represented
12389    * as a signed integer box */
12390   gint x_1 = MIN (geometry_a->x, geometry_b->x);
12391   gint y_1 = MIN (geometry_a->y, geometry_b->y);
12392   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
12393                   geometry_b->x + (gint)geometry_b->width);
12394   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
12395                   geometry_b->y + (gint)geometry_b->height);
12396   result->x = x_1;
12397   result->y = y_1;
12398   result->width = x_2 - x_1;
12399   result->height = y_2 - y_1;
12400 }
12401
12402 /**
12403  * clutter_geometry_intersects:
12404  * @geometry0: The first geometry to test
12405  * @geometry1: The second geometry to test
12406  *
12407  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
12408  * they do else %FALSE.
12409  *
12410  * Return value: %TRUE of @geometry0 and geometry1 intersect else
12411  * %FALSE.
12412  *
12413  * Since: 1.4
12414  */
12415 gboolean
12416 clutter_geometry_intersects (const ClutterGeometry *geometry0,
12417                              const ClutterGeometry *geometry1)
12418 {
12419   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
12420       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
12421       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
12422       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
12423     return FALSE;
12424   else
12425     return TRUE;
12426 }
12427
12428 static gboolean
12429 clutter_geometry_progress (const GValue *a,
12430                            const GValue *b,
12431                            gdouble       progress,
12432                            GValue       *retval)
12433 {
12434   const ClutterGeometry *a_geom = g_value_get_boxed (a);
12435   const ClutterGeometry *b_geom = g_value_get_boxed (b);
12436   ClutterGeometry res = { 0, };
12437   gint a_width = a_geom->width;
12438   gint b_width = b_geom->width;
12439   gint a_height = a_geom->height;
12440   gint b_height = b_geom->height;
12441
12442   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
12443   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
12444
12445   res.width = a_width + (b_width - a_width) * progress;
12446   res.height = a_height + (b_height - a_height) * progress;
12447
12448   g_value_set_boxed (retval, &res);
12449
12450   return TRUE;
12451 }
12452
12453 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
12454                                clutter_geometry_copy,
12455                                clutter_geometry_free,
12456                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
12457
12458 /*
12459  * ClutterVertices
12460  */
12461
12462 /**
12463  * clutter_vertex_new:
12464  * @x: X coordinate
12465  * @y: Y coordinate
12466  * @z: Z coordinate
12467  *
12468  * Creates a new #ClutterVertex for the point in 3D space
12469  * identified by the 3 coordinates @x, @y, @z
12470  *
12471  * Return value: the newly allocate #ClutterVertex. Use
12472  *   clutter_vertex_free() to free the resources
12473  *
12474  * Since: 1.0
12475  */
12476 ClutterVertex *
12477 clutter_vertex_new (gfloat x,
12478                     gfloat y,
12479                     gfloat z)
12480 {
12481   ClutterVertex *vertex;
12482
12483   vertex = g_slice_new (ClutterVertex);
12484   vertex->x = x;
12485   vertex->y = y;
12486   vertex->z = z;
12487
12488   return vertex;
12489 }
12490
12491 /**
12492  * clutter_vertex_copy:
12493  * @vertex: a #ClutterVertex
12494  *
12495  * Copies @vertex
12496  *
12497  * Return value: a newly allocated copy of #ClutterVertex. Use
12498  *   clutter_vertex_free() to free the allocated resources
12499  *
12500  * Since: 1.0
12501  */
12502 ClutterVertex *
12503 clutter_vertex_copy (const ClutterVertex *vertex)
12504 {
12505   if (G_LIKELY (vertex != NULL))
12506     return g_slice_dup (ClutterVertex, vertex);
12507
12508   return NULL;
12509 }
12510
12511 /**
12512  * clutter_vertex_free:
12513  * @vertex: a #ClutterVertex
12514  *
12515  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
12516  *
12517  * Since: 1.0
12518  */
12519 void
12520 clutter_vertex_free (ClutterVertex *vertex)
12521 {
12522   if (G_UNLIKELY (vertex != NULL))
12523     g_slice_free (ClutterVertex, vertex);
12524 }
12525
12526 /**
12527  * clutter_vertex_equal:
12528  * @vertex_a: a #ClutterVertex
12529  * @vertex_b: a #ClutterVertex
12530  *
12531  * Compares @vertex_a and @vertex_b for equality
12532  *
12533  * Return value: %TRUE if the passed #ClutterVertex are equal
12534  *
12535  * Since: 1.0
12536  */
12537 gboolean
12538 clutter_vertex_equal (const ClutterVertex *vertex_a,
12539                       const ClutterVertex *vertex_b)
12540 {
12541   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
12542
12543   if (vertex_a == vertex_b)
12544     return TRUE;
12545
12546   return vertex_a->x == vertex_b->x &&
12547          vertex_a->y == vertex_b->y &&
12548          vertex_a->z == vertex_b->z;
12549 }
12550
12551 static gboolean
12552 clutter_vertex_progress (const GValue *a,
12553                          const GValue *b,
12554                          gdouble       progress,
12555                          GValue       *retval)
12556 {
12557   const ClutterVertex *av = g_value_get_boxed (a);
12558   const ClutterVertex *bv = g_value_get_boxed (b);
12559   ClutterVertex res = { 0, };
12560
12561   res.x = av->x + (bv->x - av->x) * progress;
12562   res.y = av->y + (bv->y - av->y) * progress;
12563   res.z = av->z + (bv->z - av->z) * progress;
12564
12565   g_value_set_boxed (retval, &res);
12566
12567   return TRUE;
12568 }
12569
12570 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
12571                                clutter_vertex_copy,
12572                                clutter_vertex_free,
12573                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
12574
12575 /**
12576  * clutter_actor_is_rotated:
12577  * @self: a #ClutterActor
12578  *
12579  * Checks whether any rotation is applied to the actor.
12580  *
12581  * Return value: %TRUE if the actor is rotated.
12582  *
12583  * Since: 0.6
12584  */
12585 gboolean
12586 clutter_actor_is_rotated (ClutterActor *self)
12587 {
12588   const ClutterTransformInfo *info;
12589
12590   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12591
12592   info = _clutter_actor_get_transform_info_or_defaults (self);
12593
12594   if (info->rx_angle || info->ry_angle || info->rz_angle)
12595     return TRUE;
12596
12597   return FALSE;
12598 }
12599
12600 /**
12601  * clutter_actor_is_scaled:
12602  * @self: a #ClutterActor
12603  *
12604  * Checks whether the actor is scaled in either dimension.
12605  *
12606  * Return value: %TRUE if the actor is scaled.
12607  *
12608  * Since: 0.6
12609  */
12610 gboolean
12611 clutter_actor_is_scaled (ClutterActor *self)
12612 {
12613   const ClutterTransformInfo *info;
12614
12615   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12616
12617   info = _clutter_actor_get_transform_info_or_defaults (self);
12618
12619   if (info->scale_x != 1.0 || info->scale_y != 1.0)
12620     return TRUE;
12621
12622   return FALSE;
12623 }
12624
12625 ClutterActor *
12626 _clutter_actor_get_stage_internal (ClutterActor *actor)
12627 {
12628   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
12629     actor = actor->priv->parent;
12630
12631   return actor;
12632 }
12633
12634 /**
12635  * clutter_actor_get_stage:
12636  * @actor: a #ClutterActor
12637  *
12638  * Retrieves the #ClutterStage where @actor is contained.
12639  *
12640  * Return value: (transfer none) (type Clutter.Stage): the stage
12641  *   containing the actor, or %NULL
12642  *
12643  * Since: 0.8
12644  */
12645 ClutterActor *
12646 clutter_actor_get_stage (ClutterActor *actor)
12647 {
12648   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
12649
12650   return _clutter_actor_get_stage_internal (actor);
12651 }
12652
12653 /**
12654  * clutter_actor_allocate_available_size:
12655  * @self: a #ClutterActor
12656  * @x: the actor's X coordinate
12657  * @y: the actor's Y coordinate
12658  * @available_width: the maximum available width, or -1 to use the
12659  *   actor's natural width
12660  * @available_height: the maximum available height, or -1 to use the
12661  *   actor's natural height
12662  * @flags: flags controlling the allocation
12663  *
12664  * Allocates @self taking into account the #ClutterActor<!-- -->'s
12665  * preferred size, but limiting it to the maximum available width
12666  * and height provided.
12667  *
12668  * This function will do the right thing when dealing with the
12669  * actor's request mode.
12670  *
12671  * The implementation of this function is equivalent to:
12672  *
12673  * |[
12674  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12675  *     {
12676  *       clutter_actor_get_preferred_width (self, available_height,
12677  *                                          &amp;min_width,
12678  *                                          &amp;natural_width);
12679  *       width = CLAMP (natural_width, min_width, available_width);
12680  *
12681  *       clutter_actor_get_preferred_height (self, width,
12682  *                                           &amp;min_height,
12683  *                                           &amp;natural_height);
12684  *       height = CLAMP (natural_height, min_height, available_height);
12685  *     }
12686  *   else
12687  *     {
12688  *       clutter_actor_get_preferred_height (self, available_width,
12689  *                                           &amp;min_height,
12690  *                                           &amp;natural_height);
12691  *       height = CLAMP (natural_height, min_height, available_height);
12692  *
12693  *       clutter_actor_get_preferred_width (self, height,
12694  *                                          &amp;min_width,
12695  *                                          &amp;natural_width);
12696  *       width = CLAMP (natural_width, min_width, available_width);
12697  *     }
12698  *
12699  *   box.x1 = x; box.y1 = y;
12700  *   box.x2 = box.x1 + available_width;
12701  *   box.y2 = box.y1 + available_height;
12702  *   clutter_actor_allocate (self, &amp;box, flags);
12703  * ]|
12704  *
12705  * This function can be used by fluid layout managers to allocate
12706  * an actor's preferred size without making it bigger than the area
12707  * available for the container.
12708  *
12709  * Since: 1.0
12710  */
12711 void
12712 clutter_actor_allocate_available_size (ClutterActor           *self,
12713                                        gfloat                  x,
12714                                        gfloat                  y,
12715                                        gfloat                  available_width,
12716                                        gfloat                  available_height,
12717                                        ClutterAllocationFlags  flags)
12718 {
12719   ClutterActorPrivate *priv;
12720   gfloat width, height;
12721   gfloat min_width, min_height;
12722   gfloat natural_width, natural_height;
12723   ClutterActorBox box;
12724
12725   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12726
12727   priv = self->priv;
12728
12729   width = height = 0.0;
12730
12731   switch (priv->request_mode)
12732     {
12733     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
12734       clutter_actor_get_preferred_width (self, available_height,
12735                                          &min_width,
12736                                          &natural_width);
12737       width  = CLAMP (natural_width, min_width, available_width);
12738
12739       clutter_actor_get_preferred_height (self, width,
12740                                           &min_height,
12741                                           &natural_height);
12742       height = CLAMP (natural_height, min_height, available_height);
12743       break;
12744
12745     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
12746       clutter_actor_get_preferred_height (self, available_width,
12747                                           &min_height,
12748                                           &natural_height);
12749       height = CLAMP (natural_height, min_height, available_height);
12750
12751       clutter_actor_get_preferred_width (self, height,
12752                                          &min_width,
12753                                          &natural_width);
12754       width  = CLAMP (natural_width, min_width, available_width);
12755       break;
12756     }
12757
12758
12759   box.x1 = x;
12760   box.y1 = y;
12761   box.x2 = box.x1 + width;
12762   box.y2 = box.y1 + height;
12763   clutter_actor_allocate (self, &box, flags);
12764 }
12765
12766 /**
12767  * clutter_actor_allocate_preferred_size:
12768  * @self: a #ClutterActor
12769  * @flags: flags controlling the allocation
12770  *
12771  * Allocates the natural size of @self.
12772  *
12773  * This function is a utility call for #ClutterActor implementations
12774  * that allocates the actor's preferred natural size. It can be used
12775  * by fixed layout managers (like #ClutterGroup or so called
12776  * 'composite actors') inside the ClutterActor::allocate
12777  * implementation to give each child exactly how much space it
12778  * requires.
12779  *
12780  * This function is not meant to be used by applications. It is also
12781  * not meant to be used outside the implementation of the
12782  * ClutterActor::allocate virtual function.
12783  *
12784  * Since: 0.8
12785  */
12786 void
12787 clutter_actor_allocate_preferred_size (ClutterActor           *self,
12788                                        ClutterAllocationFlags  flags)
12789 {
12790   gfloat actor_x, actor_y;
12791   gfloat natural_width, natural_height;
12792   ClutterActorBox actor_box;
12793
12794   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12795
12796   actor_x = clutter_actor_get_x (self);
12797   actor_y = clutter_actor_get_y (self);
12798
12799   clutter_actor_get_preferred_size (self,
12800                                     NULL, NULL,
12801                                     &natural_width,
12802                                     &natural_height);
12803
12804   actor_box.x1 = actor_x;
12805   actor_box.y1 = actor_y;
12806   actor_box.x2 = actor_box.x1 + natural_width;
12807   actor_box.y2 = actor_box.y1 + natural_height;
12808
12809   clutter_actor_allocate (self, &actor_box, flags);
12810 }
12811
12812 /**
12813  * clutter_actor_allocate_align_fill:
12814  * @self: a #ClutterActor
12815  * @box: a #ClutterActorBox, containing the available width and height
12816  * @x_align: the horizontal alignment, between 0 and 1
12817  * @y_align: the vertical alignment, between 0 and 1
12818  * @x_fill: whether the actor should fill horizontally
12819  * @y_fill: whether the actor should fill vertically
12820  * @flags: allocation flags to be passed to clutter_actor_allocate()
12821  *
12822  * Allocates @self by taking into consideration the available allocation
12823  * area; an alignment factor on either axis; and whether the actor should
12824  * fill the allocation on either axis.
12825  *
12826  * The @box should contain the available allocation width and height;
12827  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
12828  * allocation will be offset by their value.
12829  *
12830  * This function takes into consideration the geometry request specified by
12831  * the #ClutterActor:request-mode property, and the text direction.
12832  *
12833  * This function is useful for fluid layout managers, like #ClutterBinLayout
12834  * or #ClutterTableLayout
12835  *
12836  * Since: 1.4
12837  */
12838 void
12839 clutter_actor_allocate_align_fill (ClutterActor           *self,
12840                                    const ClutterActorBox  *box,
12841                                    gdouble                 x_align,
12842                                    gdouble                 y_align,
12843                                    gboolean                x_fill,
12844                                    gboolean                y_fill,
12845                                    ClutterAllocationFlags  flags)
12846 {
12847   ClutterActorPrivate *priv;
12848   ClutterActorBox allocation = { 0, };
12849   gfloat x_offset, y_offset;
12850   gfloat available_width, available_height;
12851   gfloat child_width, child_height;
12852
12853   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12854   g_return_if_fail (box != NULL);
12855   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
12856   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
12857
12858   priv = self->priv;
12859
12860   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
12861   clutter_actor_box_get_size (box, &available_width, &available_height);
12862
12863   if (available_width < 0)
12864     available_width = 0;
12865
12866   if (available_height < 0)
12867     available_height = 0;
12868
12869   if (x_fill)
12870     {
12871       allocation.x1 = x_offset;
12872       allocation.x2 = allocation.x1 + available_width;
12873     }
12874
12875   if (y_fill)
12876     {
12877       allocation.y1 = y_offset;
12878       allocation.y2 = allocation.y1 + available_height;
12879     }
12880
12881   /* if we are filling horizontally and vertically then we're done */
12882   if (x_fill && y_fill)
12883     goto out;
12884
12885   child_width = child_height = 0.0f;
12886
12887   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12888     {
12889       gfloat min_width, natural_width;
12890       gfloat min_height, natural_height;
12891
12892       clutter_actor_get_preferred_width (self, available_height,
12893                                          &min_width,
12894                                          &natural_width);
12895
12896       child_width = CLAMP (natural_width, min_width, available_width);
12897
12898       if (!y_fill)
12899         {
12900           clutter_actor_get_preferred_height (self, child_width,
12901                                               &min_height,
12902                                               &natural_height);
12903
12904           child_height = CLAMP (natural_height, min_height, available_height);
12905         }
12906     }
12907   else
12908     {
12909       gfloat min_width, natural_width;
12910       gfloat min_height, natural_height;
12911
12912       clutter_actor_get_preferred_height (self, available_width,
12913                                           &min_height,
12914                                           &natural_height);
12915
12916       child_height = CLAMP (natural_height, min_height, available_height);
12917
12918       if (!x_fill)
12919         {
12920           clutter_actor_get_preferred_width (self, child_height,
12921                                              &min_width,
12922                                              &natural_width);
12923
12924           child_width = CLAMP (natural_width, min_width, available_width);
12925         }
12926     }
12927
12928   /* invert the horizontal alignment for RTL languages */
12929   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
12930     x_align = 1.0 - x_align;
12931
12932   if (!x_fill)
12933     {
12934       allocation.x1 = x_offset
12935                     + ((available_width - child_width) * x_align);
12936       allocation.x2 = allocation.x1 + child_width;
12937     }
12938
12939   if (!y_fill)
12940     {
12941       allocation.y1 = y_offset
12942                     + ((available_height - child_height) * y_align);
12943       allocation.y2 = allocation.y1 + child_height;
12944     }
12945
12946 out:
12947   clutter_actor_box_clamp_to_pixel (&allocation);
12948   clutter_actor_allocate (self, &allocation, flags);
12949 }
12950
12951 /**
12952  * clutter_actor_grab_key_focus:
12953  * @self: a #ClutterActor
12954  *
12955  * Sets the key focus of the #ClutterStage including @self
12956  * to this #ClutterActor.
12957  *
12958  * Since: 1.0
12959  */
12960 void
12961 clutter_actor_grab_key_focus (ClutterActor *self)
12962 {
12963   ClutterActor *stage;
12964
12965   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12966
12967   stage = _clutter_actor_get_stage_internal (self);
12968   if (stage != NULL)
12969     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
12970 }
12971
12972 /**
12973  * clutter_actor_get_pango_context:
12974  * @self: a #ClutterActor
12975  *
12976  * Retrieves the #PangoContext for @self. The actor's #PangoContext
12977  * is already configured using the appropriate font map, resolution
12978  * and font options.
12979  *
12980  * Unlike clutter_actor_create_pango_context(), this context is owend
12981  * by the #ClutterActor and it will be updated each time the options
12982  * stored by the #ClutterBackend change.
12983  *
12984  * You can use the returned #PangoContext to create a #PangoLayout
12985  * and render text using cogl_pango_render_layout() to reuse the
12986  * glyphs cache also used by Clutter.
12987  *
12988  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
12989  *   The returned #PangoContext is owned by the actor and should not be
12990  *   unreferenced by the application code
12991  *
12992  * Since: 1.0
12993  */
12994 PangoContext *
12995 clutter_actor_get_pango_context (ClutterActor *self)
12996 {
12997   ClutterActorPrivate *priv;
12998
12999   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13000
13001   priv = self->priv;
13002
13003   if (priv->pango_context != NULL)
13004     return priv->pango_context;
13005
13006   priv->pango_context = _clutter_context_get_pango_context ();
13007   g_object_ref (priv->pango_context);
13008
13009   return priv->pango_context;
13010 }
13011
13012 /**
13013  * clutter_actor_create_pango_context:
13014  * @self: a #ClutterActor
13015  *
13016  * Creates a #PangoContext for the given actor. The #PangoContext
13017  * is already configured using the appropriate font map, resolution
13018  * and font options.
13019  *
13020  * See also clutter_actor_get_pango_context().
13021  *
13022  * Return value: (transfer full): the newly created #PangoContext.
13023  *   Use g_object_unref() on the returned value to deallocate its
13024  *   resources
13025  *
13026  * Since: 1.0
13027  */
13028 PangoContext *
13029 clutter_actor_create_pango_context (ClutterActor *self)
13030 {
13031   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13032
13033   return _clutter_context_create_pango_context ();
13034 }
13035
13036 /**
13037  * clutter_actor_create_pango_layout:
13038  * @self: a #ClutterActor
13039  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13040  *
13041  * Creates a new #PangoLayout from the same #PangoContext used
13042  * by the #ClutterActor. The #PangoLayout is already configured
13043  * with the font map, resolution and font options, and the
13044  * given @text.
13045  *
13046  * If you want to keep around a #PangoLayout created by this
13047  * function you will have to connect to the #ClutterBackend::font-changed
13048  * and #ClutterBackend::resolution-changed signals, and call
13049  * pango_layout_context_changed() in response to them.
13050  *
13051  * Return value: (transfer full): the newly created #PangoLayout.
13052  *   Use g_object_unref() when done
13053  *
13054  * Since: 1.0
13055  */
13056 PangoLayout *
13057 clutter_actor_create_pango_layout (ClutterActor *self,
13058                                    const gchar  *text)
13059 {
13060   PangoContext *context;
13061   PangoLayout *layout;
13062
13063   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13064
13065   context = clutter_actor_get_pango_context (self);
13066   layout = pango_layout_new (context);
13067
13068   if (text)
13069     pango_layout_set_text (layout, text, -1);
13070
13071   return layout;
13072 }
13073
13074 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13075  * ClutterOffscreenEffect.
13076  */
13077 void
13078 _clutter_actor_set_opacity_override (ClutterActor *self,
13079                                      gint          opacity)
13080 {
13081   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13082
13083   self->priv->opacity_override = opacity;
13084 }
13085
13086 gint
13087 _clutter_actor_get_opacity_override (ClutterActor *self)
13088 {
13089   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13090
13091   return self->priv->opacity_override;
13092 }
13093
13094 /* Allows you to disable applying the actors model view transform during
13095  * a paint. Used by ClutterClone. */
13096 void
13097 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13098                                                 gboolean      enable)
13099 {
13100   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13101
13102   self->priv->enable_model_view_transform = enable;
13103 }
13104
13105 void
13106 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13107                                           gboolean      enable)
13108 {
13109   ClutterActorPrivate *priv;
13110
13111   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13112
13113   priv = self->priv;
13114
13115   priv->enable_paint_unmapped = enable;
13116
13117   if (priv->enable_paint_unmapped)
13118     {
13119       /* Make sure that the parents of the widget are realized first;
13120        * otherwise checks in clutter_actor_update_map_state() will
13121        * fail.
13122        */
13123       clutter_actor_realize (self);
13124
13125       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13126     }
13127   else
13128     {
13129       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13130     }
13131 }
13132
13133 static void
13134 clutter_anchor_coord_get_units (ClutterActor      *self,
13135                                 const AnchorCoord *coord,
13136                                 gfloat            *x,
13137                                 gfloat            *y,
13138                                 gfloat            *z)
13139 {
13140   if (coord->is_fractional)
13141     {
13142       gfloat actor_width, actor_height;
13143
13144       clutter_actor_get_size (self, &actor_width, &actor_height);
13145
13146       if (x)
13147         *x = actor_width * coord->v.fraction.x;
13148
13149       if (y)
13150         *y = actor_height * coord->v.fraction.y;
13151
13152       if (z)
13153         *z = 0;
13154     }
13155   else
13156     {
13157       if (x)
13158         *x = coord->v.units.x;
13159
13160       if (y)
13161         *y = coord->v.units.y;
13162
13163       if (z)
13164         *z = coord->v.units.z;
13165     }
13166 }
13167
13168 static void
13169 clutter_anchor_coord_set_units (AnchorCoord *coord,
13170                                 gfloat       x,
13171                                 gfloat       y,
13172                                 gfloat       z)
13173 {
13174   coord->is_fractional = FALSE;
13175   coord->v.units.x = x;
13176   coord->v.units.y = y;
13177   coord->v.units.z = z;
13178 }
13179
13180 static ClutterGravity
13181 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13182 {
13183   if (coord->is_fractional)
13184     {
13185       if (coord->v.fraction.x == 0.0)
13186         {
13187           if (coord->v.fraction.y == 0.0)
13188             return CLUTTER_GRAVITY_NORTH_WEST;
13189           else if (coord->v.fraction.y == 0.5)
13190             return CLUTTER_GRAVITY_WEST;
13191           else if (coord->v.fraction.y == 1.0)
13192             return CLUTTER_GRAVITY_SOUTH_WEST;
13193           else
13194             return CLUTTER_GRAVITY_NONE;
13195         }
13196       else if (coord->v.fraction.x == 0.5)
13197         {
13198           if (coord->v.fraction.y == 0.0)
13199             return CLUTTER_GRAVITY_NORTH;
13200           else if (coord->v.fraction.y == 0.5)
13201             return CLUTTER_GRAVITY_CENTER;
13202           else if (coord->v.fraction.y == 1.0)
13203             return CLUTTER_GRAVITY_SOUTH;
13204           else
13205             return CLUTTER_GRAVITY_NONE;
13206         }
13207       else if (coord->v.fraction.x == 1.0)
13208         {
13209           if (coord->v.fraction.y == 0.0)
13210             return CLUTTER_GRAVITY_NORTH_EAST;
13211           else if (coord->v.fraction.y == 0.5)
13212             return CLUTTER_GRAVITY_EAST;
13213           else if (coord->v.fraction.y == 1.0)
13214             return CLUTTER_GRAVITY_SOUTH_EAST;
13215           else
13216             return CLUTTER_GRAVITY_NONE;
13217         }
13218       else
13219         return CLUTTER_GRAVITY_NONE;
13220     }
13221   else
13222     return CLUTTER_GRAVITY_NONE;
13223 }
13224
13225 static void
13226 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
13227                                   ClutterGravity  gravity)
13228 {
13229   switch (gravity)
13230     {
13231     case CLUTTER_GRAVITY_NORTH:
13232       coord->v.fraction.x = 0.5;
13233       coord->v.fraction.y = 0.0;
13234       break;
13235
13236     case CLUTTER_GRAVITY_NORTH_EAST:
13237       coord->v.fraction.x = 1.0;
13238       coord->v.fraction.y = 0.0;
13239       break;
13240
13241     case CLUTTER_GRAVITY_EAST:
13242       coord->v.fraction.x = 1.0;
13243       coord->v.fraction.y = 0.5;
13244       break;
13245
13246     case CLUTTER_GRAVITY_SOUTH_EAST:
13247       coord->v.fraction.x = 1.0;
13248       coord->v.fraction.y = 1.0;
13249       break;
13250
13251     case CLUTTER_GRAVITY_SOUTH:
13252       coord->v.fraction.x = 0.5;
13253       coord->v.fraction.y = 1.0;
13254       break;
13255
13256     case CLUTTER_GRAVITY_SOUTH_WEST:
13257       coord->v.fraction.x = 0.0;
13258       coord->v.fraction.y = 1.0;
13259       break;
13260
13261     case CLUTTER_GRAVITY_WEST:
13262       coord->v.fraction.x = 0.0;
13263       coord->v.fraction.y = 0.5;
13264       break;
13265
13266     case CLUTTER_GRAVITY_NORTH_WEST:
13267       coord->v.fraction.x = 0.0;
13268       coord->v.fraction.y = 0.0;
13269       break;
13270
13271     case CLUTTER_GRAVITY_CENTER:
13272       coord->v.fraction.x = 0.5;
13273       coord->v.fraction.y = 0.5;
13274       break;
13275
13276     default:
13277       coord->v.fraction.x = 0.0;
13278       coord->v.fraction.y = 0.0;
13279       break;
13280     }
13281
13282   coord->is_fractional = TRUE;
13283 }
13284
13285 static gboolean
13286 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13287 {
13288   if (coord->is_fractional)
13289     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13290   else
13291     return (coord->v.units.x == 0.0
13292             && coord->v.units.y == 0.0
13293             && coord->v.units.z == 0.0);
13294 }
13295
13296 /**
13297  * clutter_actor_get_flags:
13298  * @self: a #ClutterActor
13299  *
13300  * Retrieves the flags set on @self
13301  *
13302  * Return value: a bitwise or of #ClutterActorFlags or 0
13303  *
13304  * Since: 1.0
13305  */
13306 ClutterActorFlags
13307 clutter_actor_get_flags (ClutterActor *self)
13308 {
13309   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13310
13311   return self->flags;
13312 }
13313
13314 /**
13315  * clutter_actor_set_flags:
13316  * @self: a #ClutterActor
13317  * @flags: the flags to set
13318  *
13319  * Sets @flags on @self
13320  *
13321  * This function will emit notifications for the changed properties
13322  *
13323  * Since: 1.0
13324  */
13325 void
13326 clutter_actor_set_flags (ClutterActor      *self,
13327                          ClutterActorFlags  flags)
13328 {
13329   ClutterActorFlags old_flags;
13330   GObject *obj;
13331   gboolean was_reactive_set, reactive_set;
13332   gboolean was_realized_set, realized_set;
13333   gboolean was_mapped_set, mapped_set;
13334   gboolean was_visible_set, visible_set;
13335
13336   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13337
13338   if (self->flags == flags)
13339     return;
13340
13341   obj = G_OBJECT (self);
13342   g_object_ref (obj);
13343   g_object_freeze_notify (obj);
13344
13345   old_flags = self->flags;
13346
13347   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13348   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13349   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13350   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13351
13352   self->flags |= flags;
13353
13354   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13355   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13356   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13357   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13358
13359   if (reactive_set != was_reactive_set)
13360     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13361
13362   if (realized_set != was_realized_set)
13363     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13364
13365   if (mapped_set != was_mapped_set)
13366     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13367
13368   if (visible_set != was_visible_set)
13369     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13370
13371   g_object_thaw_notify (obj);
13372   g_object_unref (obj);
13373 }
13374
13375 /**
13376  * clutter_actor_unset_flags:
13377  * @self: a #ClutterActor
13378  * @flags: the flags to unset
13379  *
13380  * Unsets @flags on @self
13381  *
13382  * This function will emit notifications for the changed properties
13383  *
13384  * Since: 1.0
13385  */
13386 void
13387 clutter_actor_unset_flags (ClutterActor      *self,
13388                            ClutterActorFlags  flags)
13389 {
13390   ClutterActorFlags old_flags;
13391   GObject *obj;
13392   gboolean was_reactive_set, reactive_set;
13393   gboolean was_realized_set, realized_set;
13394   gboolean was_mapped_set, mapped_set;
13395   gboolean was_visible_set, visible_set;
13396
13397   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13398
13399   obj = G_OBJECT (self);
13400   g_object_freeze_notify (obj);
13401
13402   old_flags = self->flags;
13403
13404   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13405   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13406   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13407   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13408
13409   self->flags &= ~flags;
13410
13411   if (self->flags == old_flags)
13412     return;
13413
13414   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13415   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13416   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13417   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13418
13419   if (reactive_set != was_reactive_set)
13420     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13421
13422   if (realized_set != was_realized_set)
13423     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13424
13425   if (mapped_set != was_mapped_set)
13426     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13427
13428   if (visible_set != was_visible_set)
13429     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13430
13431   g_object_thaw_notify (obj);
13432 }
13433
13434 /**
13435  * clutter_actor_get_transformation_matrix:
13436  * @self: a #ClutterActor
13437  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
13438  *
13439  * Retrieves the transformations applied to @self relative to its
13440  * parent.
13441  *
13442  * Since: 1.0
13443  */
13444 void
13445 clutter_actor_get_transformation_matrix (ClutterActor *self,
13446                                          CoglMatrix   *matrix)
13447 {
13448   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13449
13450   cogl_matrix_init_identity (matrix);
13451
13452   _clutter_actor_apply_modelview_transform (self, matrix);
13453 }
13454
13455 void
13456 _clutter_actor_set_in_clone_paint (ClutterActor *self,
13457                                    gboolean      is_in_clone_paint)
13458 {
13459   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13460   self->priv->in_clone_paint = is_in_clone_paint;
13461 }
13462
13463 /**
13464  * clutter_actor_is_in_clone_paint:
13465  * @self: a #ClutterActor
13466  *
13467  * Checks whether @self is being currently painted by a #ClutterClone
13468  *
13469  * This function is useful only inside the ::paint virtual function
13470  * implementations or within handlers for the #ClutterActor::paint
13471  * signal
13472  *
13473  * This function should not be used by applications
13474  *
13475  * Return value: %TRUE if the #ClutterActor is currently being painted
13476  *   by a #ClutterClone, and %FALSE otherwise
13477  *
13478  * Since: 1.0
13479  */
13480 gboolean
13481 clutter_actor_is_in_clone_paint (ClutterActor *self)
13482 {
13483   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13484
13485   return self->priv->in_clone_paint;
13486 }
13487
13488 static gboolean
13489 set_direction_recursive (ClutterActor *actor,
13490                          gpointer      user_data)
13491 {
13492   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
13493
13494   clutter_actor_set_text_direction (actor, text_dir);
13495
13496   return TRUE;
13497 }
13498
13499 /**
13500  * clutter_actor_set_text_direction:
13501  * @self: a #ClutterActor
13502  * @text_dir: the text direction for @self
13503  *
13504  * Sets the #ClutterTextDirection for an actor
13505  *
13506  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
13507  *
13508  * If @self implements #ClutterContainer then this function will recurse
13509  * inside all the children of @self (including the internal ones).
13510  *
13511  * Composite actors not implementing #ClutterContainer, or actors requiring
13512  * special handling when the text direction changes, should connect to
13513  * the #GObject::notify signal for the #ClutterActor:text-direction property
13514  *
13515  * Since: 1.2
13516  */
13517 void
13518 clutter_actor_set_text_direction (ClutterActor         *self,
13519                                   ClutterTextDirection  text_dir)
13520 {
13521   ClutterActorPrivate *priv;
13522
13523   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13524   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
13525
13526   priv = self->priv;
13527
13528   if (priv->text_direction != text_dir)
13529     {
13530       priv->text_direction = text_dir;
13531
13532       /* we need to emit the notify::text-direction first, so that
13533        * the sub-classes can catch that and do specific handling of
13534        * the text direction; see clutter_text_direction_changed_cb()
13535        * inside clutter-text.c
13536        */
13537       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
13538
13539       _clutter_actor_foreach_child (self, set_direction_recursive,
13540                                     GINT_TO_POINTER (text_dir));
13541
13542       clutter_actor_queue_relayout (self);
13543     }
13544 }
13545
13546 void
13547 _clutter_actor_set_has_pointer (ClutterActor *self,
13548                                 gboolean      has_pointer)
13549 {
13550   ClutterActorPrivate *priv = self->priv;
13551
13552   if (priv->has_pointer != has_pointer)
13553     {
13554       priv->has_pointer = has_pointer;
13555
13556       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
13557     }
13558 }
13559
13560 /**
13561  * clutter_actor_get_text_direction:
13562  * @self: a #ClutterActor
13563  *
13564  * Retrieves the value set using clutter_actor_set_text_direction()
13565  *
13566  * If no text direction has been previously set, the default text
13567  * direction, as returned by clutter_get_default_text_direction(), will
13568  * be returned instead
13569  *
13570  * Return value: the #ClutterTextDirection for the actor
13571  *
13572  * Since: 1.2
13573  */
13574 ClutterTextDirection
13575 clutter_actor_get_text_direction (ClutterActor *self)
13576 {
13577   ClutterActorPrivate *priv;
13578
13579   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
13580                         CLUTTER_TEXT_DIRECTION_LTR);
13581
13582   priv = self->priv;
13583
13584   /* if no direction has been set yet use the default */
13585   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
13586     priv->text_direction = clutter_get_default_text_direction ();
13587
13588   return priv->text_direction;
13589 }
13590
13591 /**
13592  * clutter_actor_push_internal:
13593  * @self: a #ClutterActor
13594  *
13595  * Should be used by actors implementing the #ClutterContainer and with
13596  * internal children added through clutter_actor_set_parent(), for instance:
13597  *
13598  * |[
13599  *   static void
13600  *   my_actor_init (MyActor *self)
13601  *   {
13602  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
13603  *
13604  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
13605  *
13606  *     /&ast; calling clutter_actor_set_parent() now will result in
13607  *      &ast; the internal flag being set on a child of MyActor
13608  *      &ast;/
13609  *
13610  *     /&ast; internal child - a background texture &ast;/
13611  *     self->priv->background_tex = clutter_texture_new ();
13612  *     clutter_actor_set_parent (self->priv->background_tex,
13613  *                               CLUTTER_ACTOR (self));
13614  *
13615  *     /&ast; internal child - a label &ast;/
13616  *     self->priv->label = clutter_text_new ();
13617  *     clutter_actor_set_parent (self->priv->label,
13618  *                               CLUTTER_ACTOR (self));
13619  *
13620  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
13621  *
13622  *     /&ast; calling clutter_actor_set_parent() now will not result in
13623  *      &ast; the internal flag being set on a child of MyActor
13624  *      &ast;/
13625  *   }
13626  * ]|
13627  *
13628  * This function will be used by Clutter to toggle an "internal child"
13629  * flag whenever clutter_actor_set_parent() is called; internal children
13630  * are handled differently by Clutter, specifically when destroying their
13631  * parent.
13632  *
13633  * Call clutter_actor_pop_internal() when you finished adding internal
13634  * children.
13635  *
13636  * Nested calls to clutter_actor_push_internal() are allowed, but each
13637  * one must by followed by a clutter_actor_pop_internal() call.
13638  *
13639  * Since: 1.2
13640  *
13641  * Deprecated: 1.10: All children of an actor are accessible through
13642  *   the #ClutterActor API, and #ClutterActor implements the
13643  *   #ClutterContainer interface, so this function is only useful
13644  *   for legacy containers overriding the default implementation.
13645  */
13646 void
13647 clutter_actor_push_internal (ClutterActor *self)
13648 {
13649   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13650
13651   self->priv->internal_child += 1;
13652 }
13653
13654 /**
13655  * clutter_actor_pop_internal:
13656  * @self: a #ClutterActor
13657  *
13658  * Disables the effects of clutter_actor_push_internal().
13659  *
13660  * Since: 1.2
13661  *
13662  * Deprecated: 1.10: All children of an actor are accessible through
13663  *   the #ClutterActor API. This function is only useful for legacy
13664  *   containers overriding the default implementation of the
13665  *   #ClutterContainer interface.
13666  */
13667 void
13668 clutter_actor_pop_internal (ClutterActor *self)
13669 {
13670   ClutterActorPrivate *priv;
13671
13672   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13673
13674   priv = self->priv;
13675
13676   if (priv->internal_child == 0)
13677     {
13678       g_warning ("Mismatched %s: you need to call "
13679                  "clutter_actor_push_composite() at least once before "
13680                  "calling this function", G_STRFUNC);
13681       return;
13682     }
13683
13684   priv->internal_child -= 1;
13685 }
13686
13687 /**
13688  * clutter_actor_has_pointer:
13689  * @self: a #ClutterActor
13690  *
13691  * Checks whether an actor contains the pointer of a
13692  * #ClutterInputDevice
13693  *
13694  * Return value: %TRUE if the actor contains the pointer, and
13695  *   %FALSE otherwise
13696  *
13697  * Since: 1.2
13698  */
13699 gboolean
13700 clutter_actor_has_pointer (ClutterActor *self)
13701 {
13702   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13703
13704   return self->priv->has_pointer;
13705 }
13706
13707 /* XXX: This is a workaround for not being able to break the ABI of
13708  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
13709  * clutter_actor_queue_clipped_redraw() for details.
13710  */
13711 ClutterPaintVolume *
13712 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
13713 {
13714   return g_object_get_data (G_OBJECT (self),
13715                             "-clutter-actor-queue-redraw-clip");
13716 }
13717
13718 void
13719 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
13720                                       ClutterPaintVolume *clip)
13721 {
13722   g_object_set_data (G_OBJECT (self),
13723                      "-clutter-actor-queue-redraw-clip",
13724                      clip);
13725 }
13726
13727 /**
13728  * clutter_actor_has_allocation:
13729  * @self: a #ClutterActor
13730  *
13731  * Checks if the actor has an up-to-date allocation assigned to
13732  * it. This means that the actor should have an allocation: it's
13733  * visible and has a parent. It also means that there is no
13734  * outstanding relayout request in progress for the actor or its
13735  * children (There might be other outstanding layout requests in
13736  * progress that will cause the actor to get a new allocation
13737  * when the stage is laid out, however).
13738  *
13739  * If this function returns %FALSE, then the actor will normally
13740  * be allocated before it is next drawn on the screen.
13741  *
13742  * Return value: %TRUE if the actor has an up-to-date allocation
13743  *
13744  * Since: 1.4
13745  */
13746 gboolean
13747 clutter_actor_has_allocation (ClutterActor *self)
13748 {
13749   ClutterActorPrivate *priv;
13750
13751   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13752
13753   priv = self->priv;
13754
13755   return priv->parent != NULL &&
13756          CLUTTER_ACTOR_IS_VISIBLE (self) &&
13757          !priv->needs_allocation;
13758 }
13759
13760 /**
13761  * clutter_actor_add_action:
13762  * @self: a #ClutterActor
13763  * @action: a #ClutterAction
13764  *
13765  * Adds @action to the list of actions applied to @self
13766  *
13767  * A #ClutterAction can only belong to one actor at a time
13768  *
13769  * The #ClutterActor will hold a reference on @action until either
13770  * clutter_actor_remove_action() or clutter_actor_clear_actions()
13771  * is called
13772  *
13773  * Since: 1.4
13774  */
13775 void
13776 clutter_actor_add_action (ClutterActor  *self,
13777                           ClutterAction *action)
13778 {
13779   ClutterActorPrivate *priv;
13780
13781   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13782   g_return_if_fail (CLUTTER_IS_ACTION (action));
13783
13784   priv = self->priv;
13785
13786   if (priv->actions == NULL)
13787     {
13788       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13789       priv->actions->actor = self;
13790     }
13791
13792   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
13793
13794   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13795 }
13796
13797 /**
13798  * clutter_actor_add_action_with_name:
13799  * @self: a #ClutterActor
13800  * @name: the name to set on the action
13801  * @action: a #ClutterAction
13802  *
13803  * A convenience function for setting the name of a #ClutterAction
13804  * while adding it to the list of actions applied to @self
13805  *
13806  * This function is the logical equivalent of:
13807  *
13808  * |[
13809  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13810  *   clutter_actor_add_action (self, action);
13811  * ]|
13812  *
13813  * Since: 1.4
13814  */
13815 void
13816 clutter_actor_add_action_with_name (ClutterActor  *self,
13817                                     const gchar   *name,
13818                                     ClutterAction *action)
13819 {
13820   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13821   g_return_if_fail (name != NULL);
13822   g_return_if_fail (CLUTTER_IS_ACTION (action));
13823
13824   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13825   clutter_actor_add_action (self, action);
13826 }
13827
13828 /**
13829  * clutter_actor_remove_action:
13830  * @self: a #ClutterActor
13831  * @action: a #ClutterAction
13832  *
13833  * Removes @action from the list of actions applied to @self
13834  *
13835  * The reference held by @self on the #ClutterAction will be released
13836  *
13837  * Since: 1.4
13838  */
13839 void
13840 clutter_actor_remove_action (ClutterActor  *self,
13841                              ClutterAction *action)
13842 {
13843   ClutterActorPrivate *priv;
13844
13845   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13846   g_return_if_fail (CLUTTER_IS_ACTION (action));
13847
13848   priv = self->priv;
13849
13850   if (priv->actions == NULL)
13851     return;
13852
13853   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
13854
13855   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13856 }
13857
13858 /**
13859  * clutter_actor_remove_action_by_name:
13860  * @self: a #ClutterActor
13861  * @name: the name of the action to remove
13862  *
13863  * Removes the #ClutterAction with the given name from the list
13864  * of actions applied to @self
13865  *
13866  * Since: 1.4
13867  */
13868 void
13869 clutter_actor_remove_action_by_name (ClutterActor *self,
13870                                      const gchar  *name)
13871 {
13872   ClutterActorPrivate *priv;
13873   ClutterActorMeta *meta;
13874
13875   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13876   g_return_if_fail (name != NULL);
13877
13878   priv = self->priv;
13879
13880   if (priv->actions == NULL)
13881     return;
13882
13883   meta = _clutter_meta_group_get_meta (priv->actions, name);
13884   if (meta == NULL)
13885     return;
13886
13887   _clutter_meta_group_remove_meta (priv->actions, meta);
13888
13889   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13890 }
13891
13892 /**
13893  * clutter_actor_get_actions:
13894  * @self: a #ClutterActor
13895  *
13896  * Retrieves the list of actions applied to @self
13897  *
13898  * Return value: (transfer container) (element-type Clutter.Action): a copy
13899  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
13900  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13901  *   allocated by the returned #GList
13902  *
13903  * Since: 1.4
13904  */
13905 GList *
13906 clutter_actor_get_actions (ClutterActor *self)
13907 {
13908   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13909
13910   if (self->priv->actions == NULL)
13911     return NULL;
13912
13913   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
13914 }
13915
13916 /**
13917  * clutter_actor_get_action:
13918  * @self: a #ClutterActor
13919  * @name: the name of the action to retrieve
13920  *
13921  * Retrieves the #ClutterAction with the given name in the list
13922  * of actions applied to @self
13923  *
13924  * Return value: (transfer none): a #ClutterAction for the given
13925  *   name, or %NULL. The returned #ClutterAction is owned by the
13926  *   actor and it should not be unreferenced directly
13927  *
13928  * Since: 1.4
13929  */
13930 ClutterAction *
13931 clutter_actor_get_action (ClutterActor *self,
13932                           const gchar  *name)
13933 {
13934   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13935   g_return_val_if_fail (name != NULL, NULL);
13936
13937   if (self->priv->actions == NULL)
13938     return NULL;
13939
13940   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
13941 }
13942
13943 /**
13944  * clutter_actor_clear_actions:
13945  * @self: a #ClutterActor
13946  *
13947  * Clears the list of actions applied to @self
13948  *
13949  * Since: 1.4
13950  */
13951 void
13952 clutter_actor_clear_actions (ClutterActor *self)
13953 {
13954   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13955
13956   if (self->priv->actions == NULL)
13957     return;
13958
13959   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
13960 }
13961
13962 /**
13963  * clutter_actor_add_constraint:
13964  * @self: a #ClutterActor
13965  * @constraint: a #ClutterConstraint
13966  *
13967  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
13968  * to @self
13969  *
13970  * The #ClutterActor will hold a reference on the @constraint until
13971  * either clutter_actor_remove_constraint() or
13972  * clutter_actor_clear_constraints() is called.
13973  *
13974  * Since: 1.4
13975  */
13976 void
13977 clutter_actor_add_constraint (ClutterActor      *self,
13978                               ClutterConstraint *constraint)
13979 {
13980   ClutterActorPrivate *priv;
13981
13982   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13983   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13984
13985   priv = self->priv;
13986
13987   if (priv->constraints == NULL)
13988     {
13989       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13990       priv->constraints->actor = self;
13991     }
13992
13993   _clutter_meta_group_add_meta (priv->constraints,
13994                                 CLUTTER_ACTOR_META (constraint));
13995   clutter_actor_queue_relayout (self);
13996
13997   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
13998 }
13999
14000 /**
14001  * clutter_actor_add_constraint_with_name:
14002  * @self: a #ClutterActor
14003  * @name: the name to set on the constraint
14004  * @constraint: a #ClutterConstraint
14005  *
14006  * A convenience function for setting the name of a #ClutterConstraint
14007  * while adding it to the list of constraints applied to @self
14008  *
14009  * This function is the logical equivalent of:
14010  *
14011  * |[
14012  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14013  *   clutter_actor_add_constraint (self, constraint);
14014  * ]|
14015  *
14016  * Since: 1.4
14017  */
14018 void
14019 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14020                                         const gchar       *name,
14021                                         ClutterConstraint *constraint)
14022 {
14023   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14024   g_return_if_fail (name != NULL);
14025   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14026
14027   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14028   clutter_actor_add_constraint (self, constraint);
14029 }
14030
14031 /**
14032  * clutter_actor_remove_constraint:
14033  * @self: a #ClutterActor
14034  * @constraint: a #ClutterConstraint
14035  *
14036  * Removes @constraint from the list of constraints applied to @self
14037  *
14038  * The reference held by @self on the #ClutterConstraint will be released
14039  *
14040  * Since: 1.4
14041  */
14042 void
14043 clutter_actor_remove_constraint (ClutterActor      *self,
14044                                  ClutterConstraint *constraint)
14045 {
14046   ClutterActorPrivate *priv;
14047
14048   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14049   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14050
14051   priv = self->priv;
14052
14053   if (priv->constraints == NULL)
14054     return;
14055
14056   _clutter_meta_group_remove_meta (priv->constraints,
14057                                    CLUTTER_ACTOR_META (constraint));
14058   clutter_actor_queue_relayout (self);
14059
14060   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14061 }
14062
14063 /**
14064  * clutter_actor_remove_constraint_by_name:
14065  * @self: a #ClutterActor
14066  * @name: the name of the constraint to remove
14067  *
14068  * Removes the #ClutterConstraint with the given name from the list
14069  * of constraints applied to @self
14070  *
14071  * Since: 1.4
14072  */
14073 void
14074 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14075                                          const gchar  *name)
14076 {
14077   ClutterActorPrivate *priv;
14078   ClutterActorMeta *meta;
14079
14080   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14081   g_return_if_fail (name != NULL);
14082
14083   priv = self->priv;
14084
14085   if (priv->constraints == NULL)
14086     return;
14087
14088   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14089   if (meta == NULL)
14090     return;
14091
14092   _clutter_meta_group_remove_meta (priv->constraints, meta);
14093   clutter_actor_queue_relayout (self);
14094 }
14095
14096 /**
14097  * clutter_actor_get_constraints:
14098  * @self: a #ClutterActor
14099  *
14100  * Retrieves the list of constraints applied to @self
14101  *
14102  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14103  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14104  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14105  *   allocated by the returned #GList
14106  *
14107  * Since: 1.4
14108  */
14109 GList *
14110 clutter_actor_get_constraints (ClutterActor *self)
14111 {
14112   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14113
14114   if (self->priv->constraints == NULL)
14115     return NULL;
14116
14117   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14118 }
14119
14120 /**
14121  * clutter_actor_get_constraint:
14122  * @self: a #ClutterActor
14123  * @name: the name of the constraint to retrieve
14124  *
14125  * Retrieves the #ClutterConstraint with the given name in the list
14126  * of constraints applied to @self
14127  *
14128  * Return value: (transfer none): a #ClutterConstraint for the given
14129  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14130  *   actor and it should not be unreferenced directly
14131  *
14132  * Since: 1.4
14133  */
14134 ClutterConstraint *
14135 clutter_actor_get_constraint (ClutterActor *self,
14136                               const gchar  *name)
14137 {
14138   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14139   g_return_val_if_fail (name != NULL, NULL);
14140
14141   if (self->priv->constraints == NULL)
14142     return NULL;
14143
14144   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14145 }
14146
14147 /**
14148  * clutter_actor_clear_constraints:
14149  * @self: a #ClutterActor
14150  *
14151  * Clears the list of constraints applied to @self
14152  *
14153  * Since: 1.4
14154  */
14155 void
14156 clutter_actor_clear_constraints (ClutterActor *self)
14157 {
14158   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14159
14160   if (self->priv->constraints == NULL)
14161     return;
14162
14163   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14164
14165   clutter_actor_queue_relayout (self);
14166 }
14167
14168 /**
14169  * clutter_actor_set_clip_to_allocation:
14170  * @self: a #ClutterActor
14171  * @clip_set: %TRUE to apply a clip tracking the allocation
14172  *
14173  * Sets whether @self should be clipped to the same size as its
14174  * allocation
14175  *
14176  * Since: 1.4
14177  */
14178 void
14179 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14180                                       gboolean      clip_set)
14181 {
14182   ClutterActorPrivate *priv;
14183
14184   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14185
14186   clip_set = !!clip_set;
14187
14188   priv = self->priv;
14189
14190   if (priv->clip_to_allocation != clip_set)
14191     {
14192       priv->clip_to_allocation = clip_set;
14193
14194       clutter_actor_queue_redraw (self);
14195
14196       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14197     }
14198 }
14199
14200 /**
14201  * clutter_actor_get_clip_to_allocation:
14202  * @self: a #ClutterActor
14203  *
14204  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14205  *
14206  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14207  *
14208  * Since: 1.4
14209  */
14210 gboolean
14211 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14212 {
14213   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14214
14215   return self->priv->clip_to_allocation;
14216 }
14217
14218 /**
14219  * clutter_actor_add_effect:
14220  * @self: a #ClutterActor
14221  * @effect: a #ClutterEffect
14222  *
14223  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14224  *
14225  * The #ClutterActor will hold a reference on the @effect until either
14226  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14227  * called.
14228  *
14229  * Since: 1.4
14230  */
14231 void
14232 clutter_actor_add_effect (ClutterActor  *self,
14233                           ClutterEffect *effect)
14234 {
14235   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14236   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14237
14238   _clutter_actor_add_effect_internal (self, effect);
14239
14240   clutter_actor_queue_redraw (self);
14241
14242   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14243 }
14244
14245 /**
14246  * clutter_actor_add_effect_with_name:
14247  * @self: a #ClutterActor
14248  * @name: the name to set on the effect
14249  * @effect: a #ClutterEffect
14250  *
14251  * A convenience function for setting the name of a #ClutterEffect
14252  * while adding it to the list of effectss applied to @self
14253  *
14254  * This function is the logical equivalent of:
14255  *
14256  * |[
14257  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14258  *   clutter_actor_add_effect (self, effect);
14259  * ]|
14260  *
14261  * Since: 1.4
14262  */
14263 void
14264 clutter_actor_add_effect_with_name (ClutterActor  *self,
14265                                     const gchar   *name,
14266                                     ClutterEffect *effect)
14267 {
14268   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14269   g_return_if_fail (name != NULL);
14270   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14271
14272   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14273   clutter_actor_add_effect (self, effect);
14274 }
14275
14276 /**
14277  * clutter_actor_remove_effect:
14278  * @self: a #ClutterActor
14279  * @effect: a #ClutterEffect
14280  *
14281  * Removes @effect from the list of effects applied to @self
14282  *
14283  * The reference held by @self on the #ClutterEffect will be released
14284  *
14285  * Since: 1.4
14286  */
14287 void
14288 clutter_actor_remove_effect (ClutterActor  *self,
14289                              ClutterEffect *effect)
14290 {
14291   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14292   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14293
14294   _clutter_actor_remove_effect_internal (self, effect);
14295
14296   clutter_actor_queue_redraw (self);
14297
14298   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14299 }
14300
14301 /**
14302  * clutter_actor_remove_effect_by_name:
14303  * @self: a #ClutterActor
14304  * @name: the name of the effect to remove
14305  *
14306  * Removes the #ClutterEffect with the given name from the list
14307  * of effects applied to @self
14308  *
14309  * Since: 1.4
14310  */
14311 void
14312 clutter_actor_remove_effect_by_name (ClutterActor *self,
14313                                      const gchar  *name)
14314 {
14315   ClutterActorPrivate *priv;
14316   ClutterActorMeta *meta;
14317
14318   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14319   g_return_if_fail (name != NULL);
14320
14321   priv = self->priv;
14322
14323   if (priv->effects == NULL)
14324     return;
14325
14326   meta = _clutter_meta_group_get_meta (priv->effects, name);
14327   if (meta == NULL)
14328     return;
14329
14330   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
14331 }
14332
14333 /**
14334  * clutter_actor_get_effects:
14335  * @self: a #ClutterActor
14336  *
14337  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
14338  *
14339  * Return value: (transfer container) (element-type Clutter.Effect): a list
14340  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
14341  *   list are owned by Clutter and they should not be freed. You should
14342  *   free the returned list using g_list_free() when done
14343  *
14344  * Since: 1.4
14345  */
14346 GList *
14347 clutter_actor_get_effects (ClutterActor *self)
14348 {
14349   ClutterActorPrivate *priv;
14350
14351   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14352
14353   priv = self->priv;
14354
14355   if (priv->effects == NULL)
14356     return NULL;
14357
14358   return _clutter_meta_group_get_metas_no_internal (priv->effects);
14359 }
14360
14361 /**
14362  * clutter_actor_get_effect:
14363  * @self: a #ClutterActor
14364  * @name: the name of the effect to retrieve
14365  *
14366  * Retrieves the #ClutterEffect with the given name in the list
14367  * of effects applied to @self
14368  *
14369  * Return value: (transfer none): a #ClutterEffect for the given
14370  *   name, or %NULL. The returned #ClutterEffect is owned by the
14371  *   actor and it should not be unreferenced directly
14372  *
14373  * Since: 1.4
14374  */
14375 ClutterEffect *
14376 clutter_actor_get_effect (ClutterActor *self,
14377                           const gchar  *name)
14378 {
14379   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14380   g_return_val_if_fail (name != NULL, NULL);
14381
14382   if (self->priv->effects == NULL)
14383     return NULL;
14384
14385   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
14386 }
14387
14388 /**
14389  * clutter_actor_clear_effects:
14390  * @self: a #ClutterActor
14391  *
14392  * Clears the list of effects applied to @self
14393  *
14394  * Since: 1.4
14395  */
14396 void
14397 clutter_actor_clear_effects (ClutterActor *self)
14398 {
14399   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14400
14401   if (self->priv->effects == NULL)
14402     return;
14403
14404   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
14405
14406   clutter_actor_queue_redraw (self);
14407 }
14408
14409 /**
14410  * clutter_actor_has_key_focus:
14411  * @self: a #ClutterActor
14412  *
14413  * Checks whether @self is the #ClutterActor that has key focus
14414  *
14415  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
14416  *
14417  * Since: 1.4
14418  */
14419 gboolean
14420 clutter_actor_has_key_focus (ClutterActor *self)
14421 {
14422   ClutterActor *stage;
14423
14424   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14425
14426   stage = _clutter_actor_get_stage_internal (self);
14427   if (stage == NULL)
14428     return FALSE;
14429
14430   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
14431 }
14432
14433 static gboolean
14434 _clutter_actor_get_paint_volume_real (ClutterActor *self,
14435                                       ClutterPaintVolume *pv)
14436 {
14437   ClutterActorPrivate *priv = self->priv;
14438
14439   /* Actors are only expected to report a valid paint volume
14440    * while they have a valid allocation. */
14441   if (G_UNLIKELY (priv->needs_allocation))
14442     {
14443       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14444                     "Actor needs allocation",
14445                     _clutter_actor_get_debug_name (self));
14446       return FALSE;
14447     }
14448
14449   /* Check if there are any handlers connected to the paint
14450    * signal. If there are then all bets are off for what the paint
14451    * volume for this actor might possibly be!
14452    *
14453    * XXX: It's expected that this is going to end up being quite a
14454    * costly check to have to do here, but we haven't come up with
14455    * another solution that can reliably catch paint signal handlers at
14456    * the right time to either avoid artefacts due to invalid stage
14457    * clipping or due to incorrect culling.
14458    *
14459    * Previously we checked in clutter_actor_paint(), but at that time
14460    * we may already be using a stage clip that could be derived from
14461    * an invalid paint-volume. We used to try and handle that by
14462    * queuing a follow up, unclipped, redraw but still the previous
14463    * checking wasn't enough to catch invalid volumes involved in
14464    * culling (considering that containers may derive their volume from
14465    * children that haven't yet been painted)
14466    *
14467    * Longer term, improved solutions could be:
14468    * - Disallow painting in the paint signal, only allow using it
14469    *   for tracking when paints happen. We can add another API that
14470    *   allows monkey patching the paint of arbitrary actors but in a
14471    *   more controlled way and that also supports modifying the
14472    *   paint-volume.
14473    * - If we could be notified somehow when signal handlers are
14474    *   connected we wouldn't have to poll for handlers like this.
14475    */
14476   if (g_signal_has_handler_pending (self,
14477                                     actor_signals[PAINT],
14478                                     0,
14479                                     TRUE))
14480     {
14481       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14482                     "Actor has \"paint\" signal handlers",
14483                     _clutter_actor_get_debug_name (self));
14484       return FALSE;
14485     }
14486
14487   _clutter_paint_volume_init_static (pv, self);
14488
14489   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
14490     {
14491       clutter_paint_volume_free (pv);
14492       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14493                     "Actor failed to report a volume",
14494                     _clutter_actor_get_debug_name (self));
14495       return FALSE;
14496     }
14497
14498   /* since effects can modify the paint volume, we allow them to actually
14499    * do this by making get_paint_volume() "context sensitive"
14500    */
14501   if (priv->effects != NULL)
14502     {
14503       if (priv->current_effect != NULL)
14504         {
14505           const GList *effects, *l;
14506
14507           /* if we are being called from within the paint sequence of
14508            * an actor, get the paint volume up to the current effect
14509            */
14510           effects = _clutter_meta_group_peek_metas (priv->effects);
14511           for (l = effects;
14512                l != NULL || (l != NULL && l->data != priv->current_effect);
14513                l = l->next)
14514             {
14515               if (!_clutter_effect_get_paint_volume (l->data, pv))
14516                 {
14517                   clutter_paint_volume_free (pv);
14518                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14519                                 "Effect (%s) failed to report a volume",
14520                                 _clutter_actor_get_debug_name (self),
14521                                 _clutter_actor_meta_get_debug_name (l->data));
14522                   return FALSE;
14523                 }
14524             }
14525         }
14526       else
14527         {
14528           const GList *effects, *l;
14529
14530           /* otherwise, get the cumulative volume */
14531           effects = _clutter_meta_group_peek_metas (priv->effects);
14532           for (l = effects; l != NULL; l = l->next)
14533             if (!_clutter_effect_get_paint_volume (l->data, pv))
14534               {
14535                 clutter_paint_volume_free (pv);
14536                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14537                               "Effect (%s) failed to report a volume",
14538                               _clutter_actor_get_debug_name (self),
14539                               _clutter_actor_meta_get_debug_name (l->data));
14540                 return FALSE;
14541               }
14542         }
14543     }
14544
14545   return TRUE;
14546 }
14547
14548 /* The public clutter_actor_get_paint_volume API returns a const
14549  * pointer since we return a pointer directly to the cached
14550  * PaintVolume associated with the actor and don't want the user to
14551  * inadvertently modify it, but for internal uses we sometimes need
14552  * access to the same PaintVolume but need to apply some book-keeping
14553  * modifications to it so we don't want a const pointer.
14554  */
14555 static ClutterPaintVolume *
14556 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
14557 {
14558   ClutterActorPrivate *priv;
14559
14560   priv = self->priv;
14561
14562   if (priv->paint_volume_valid)
14563     clutter_paint_volume_free (&priv->paint_volume);
14564
14565   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
14566     {
14567       priv->paint_volume_valid = TRUE;
14568       return &priv->paint_volume;
14569     }
14570   else
14571     {
14572       priv->paint_volume_valid = FALSE;
14573       return NULL;
14574     }
14575 }
14576
14577 /**
14578  * clutter_actor_get_paint_volume:
14579  * @self: a #ClutterActor
14580  *
14581  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
14582  * when a paint volume can't be determined.
14583  *
14584  * The paint volume is defined as the 3D space occupied by an actor
14585  * when being painted.
14586  *
14587  * This function will call the <function>get_paint_volume()</function>
14588  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
14589  * should not usually care about overriding the default implementation,
14590  * unless they are, for instance: painting outside their allocation, or
14591  * actors with a depth factor (not in terms of #ClutterActor:depth but real
14592  * 3D depth).
14593  *
14594  * <note>2D actors overriding <function>get_paint_volume()</function>
14595  * ensure their volume has a depth of 0. (This will be true so long as
14596  * you don't call clutter_paint_volume_set_depth().)</note>
14597  *
14598  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
14599  *   or %NULL if no volume could be determined. The returned pointer
14600  *   is not guaranteed to be valid across multiple frames; if you want
14601  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
14602  *
14603  * Since: 1.6
14604  */
14605 const ClutterPaintVolume *
14606 clutter_actor_get_paint_volume (ClutterActor *self)
14607 {
14608   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14609
14610   return _clutter_actor_get_paint_volume_mutable (self);
14611 }
14612
14613 /**
14614  * clutter_actor_get_transformed_paint_volume:
14615  * @self: a #ClutterActor
14616  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
14617  *    (or %NULL for the stage)
14618  *
14619  * Retrieves the 3D paint volume of an actor like
14620  * clutter_actor_get_paint_volume() does (Please refer to the
14621  * documentation of clutter_actor_get_paint_volume() for more
14622  * details.) and it additionally transforms the paint volume into the
14623  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
14624  * is passed for @relative_to_ancestor)
14625  *
14626  * This can be used by containers that base their paint volume on
14627  * the volume of their children. Such containers can query the
14628  * transformed paint volume of all of its children and union them
14629  * together using clutter_paint_volume_union().
14630  *
14631  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
14632  *   or %NULL if no volume could be determined. The returned pointer is
14633  *   not guaranteed to be valid across multiple frames; if you wish to
14634  *   keep it, you will have to copy it using clutter_paint_volume_copy().
14635  *
14636  * Since: 1.6
14637  */
14638 const ClutterPaintVolume *
14639 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
14640                                             ClutterActor *relative_to_ancestor)
14641 {
14642   const ClutterPaintVolume *volume;
14643   ClutterActor *stage;
14644   ClutterPaintVolume *transformed_volume;
14645
14646   stage = _clutter_actor_get_stage_internal (self);
14647   if (G_UNLIKELY (stage == NULL))
14648     return NULL;
14649
14650   if (relative_to_ancestor == NULL)
14651     relative_to_ancestor = stage;
14652
14653   volume = clutter_actor_get_paint_volume (self);
14654   if (volume == NULL)
14655     return NULL;
14656
14657   transformed_volume =
14658     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
14659
14660   _clutter_paint_volume_copy_static (volume, transformed_volume);
14661
14662   _clutter_paint_volume_transform_relative (transformed_volume,
14663                                             relative_to_ancestor);
14664
14665   return transformed_volume;
14666 }
14667
14668 /**
14669  * clutter_actor_get_paint_box:
14670  * @self: a #ClutterActor
14671  * @box: (out): return location for a #ClutterActorBox
14672  *
14673  * Retrieves the paint volume of the passed #ClutterActor, and
14674  * transforms it into a 2D bounding box in stage coordinates.
14675  *
14676  * This function is useful to determine the on screen area occupied by
14677  * the actor. The box is only an approximation and may often be
14678  * considerably larger due to the optimizations used to calculate the
14679  * box. The box is never smaller though, so it can reliably be used
14680  * for culling.
14681  *
14682  * There are times when a 2D paint box can't be determined, e.g.
14683  * because the actor isn't yet parented under a stage or because
14684  * the actor is unable to determine a paint volume.
14685  *
14686  * Return value: %TRUE if a 2D paint box could be determined, else
14687  * %FALSE.
14688  *
14689  * Since: 1.6
14690  */
14691 gboolean
14692 clutter_actor_get_paint_box (ClutterActor    *self,
14693                              ClutterActorBox *box)
14694 {
14695   ClutterActor *stage;
14696   ClutterPaintVolume *pv;
14697
14698   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14699   g_return_val_if_fail (box != NULL, FALSE);
14700
14701   stage = _clutter_actor_get_stage_internal (self);
14702   if (G_UNLIKELY (!stage))
14703     return FALSE;
14704
14705   pv = _clutter_actor_get_paint_volume_mutable (self);
14706   if (G_UNLIKELY (!pv))
14707     return FALSE;
14708
14709   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
14710
14711   return TRUE;
14712 }
14713
14714 /**
14715  * clutter_actor_has_overlaps:
14716  * @self: A #ClutterActor
14717  *
14718  * Asks the actor's implementation whether it may contain overlapping
14719  * primitives.
14720  *
14721  * For example; Clutter may use this to determine whether the painting
14722  * should be redirected to an offscreen buffer to correctly implement
14723  * the opacity property.
14724  *
14725  * Custom actors can override the default response by implementing the
14726  * #ClutterActor <function>has_overlaps</function> virtual function. See
14727  * clutter_actor_set_offscreen_redirect() for more information.
14728  *
14729  * Return value: %TRUE if the actor may have overlapping primitives, and
14730  *   %FALSE otherwise
14731  *
14732  * Since: 1.8
14733  */
14734 gboolean
14735 clutter_actor_has_overlaps (ClutterActor *self)
14736 {
14737   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14738
14739   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
14740 }
14741
14742 /**
14743  * clutter_actor_has_effects:
14744  * @self: A #ClutterActor
14745  *
14746  * Returns whether the actor has any effects applied.
14747  *
14748  * Return value: %TRUE if the actor has any effects,
14749  *   %FALSE otherwise
14750  *
14751  * Since: 1.10
14752  */
14753 gboolean
14754 clutter_actor_has_effects (ClutterActor *self)
14755 {
14756   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14757
14758   if (self->priv->effects == NULL)
14759     return FALSE;
14760
14761   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
14762 }
14763
14764 /**
14765  * clutter_actor_has_constraints:
14766  * @self: A #ClutterActor
14767  *
14768  * Returns whether the actor has any constraints applied.
14769  *
14770  * Return value: %TRUE if the actor has any constraints,
14771  *   %FALSE otherwise
14772  *
14773  * Since: 1.10
14774  */
14775 gboolean
14776 clutter_actor_has_constraints (ClutterActor *self)
14777 {
14778   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14779
14780   return self->priv->constraints != NULL;
14781 }
14782
14783 /**
14784  * clutter_actor_has_actions:
14785  * @self: A #ClutterActor
14786  *
14787  * Returns whether the actor has any actions applied.
14788  *
14789  * Return value: %TRUE if the actor has any actions,
14790  *   %FALSE otherwise
14791  *
14792  * Since: 1.10
14793  */
14794 gboolean
14795 clutter_actor_has_actions (ClutterActor *self)
14796 {
14797   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14798
14799   return self->priv->actions != NULL;
14800 }
14801
14802 /**
14803  * clutter_actor_get_n_children:
14804  * @self: a #ClutterActor
14805  *
14806  * Retrieves the number of children of @self.
14807  *
14808  * Return value: the number of children of an actor
14809  *
14810  * Since: 1.10
14811  */
14812 gint
14813 clutter_actor_get_n_children (ClutterActor *self)
14814 {
14815   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14816
14817   return self->priv->n_children;
14818 }
14819
14820 /**
14821  * clutter_actor_get_child_at_index:
14822  * @self: a #ClutterActor
14823  * @index_: the position in the list of children
14824  *
14825  * Retrieves the actor at the given @index_ inside the list of
14826  * children of @self.
14827  *
14828  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
14829  *
14830  * Since: 1.10
14831  */
14832 ClutterActor *
14833 clutter_actor_get_child_at_index (ClutterActor *self,
14834                                   gint          index_)
14835 {
14836   ClutterActor *iter;
14837   int i;
14838
14839   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14840   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
14841
14842   for (iter = self->priv->first_child, i = 0;
14843        iter != NULL && i < index_;
14844        iter = iter->priv->next_sibling, i += 1)
14845     ;
14846
14847   return iter;
14848 }
14849
14850 /*< private >
14851  * _clutter_actor_foreach_child:
14852  * @actor: The actor whos children you want to iterate
14853  * @callback: The function to call for each child
14854  * @user_data: Private data to pass to @callback
14855  *
14856  * Calls a given @callback once for each child of the specified @actor and
14857  * passing the @user_data pointer each time.
14858  *
14859  * Return value: returns %TRUE if all children were iterated, else
14860  *    %FALSE if a callback broke out of iteration early.
14861  */
14862 gboolean
14863 _clutter_actor_foreach_child (ClutterActor           *self,
14864                               ClutterForeachCallback  callback,
14865                               gpointer                user_data)
14866 {
14867   ClutterActorPrivate *priv = self->priv;
14868   ClutterActor *iter;
14869   gboolean cont;
14870
14871   for (cont = TRUE, iter = priv->first_child;
14872        cont && iter != NULL;
14873        iter = iter->priv->next_sibling)
14874     {
14875       cont = callback (iter, user_data);
14876     }
14877
14878   return cont;
14879 }
14880
14881 /* For debugging purposes this gives us a simple way to print out
14882  * the scenegraph e.g in gdb using:
14883  * [|
14884  *   _clutter_actor_traverse (stage,
14885  *                            0,
14886  *                            _clutter_debug_print_actor_cb,
14887  *                            NULL,
14888  *                            NULL);
14889  * |]
14890  */
14891 ClutterActorTraverseVisitFlags
14892 _clutter_debug_print_actor_cb (ClutterActor *actor,
14893                                int depth,
14894                                void *user_data)
14895 {
14896   g_print ("%*s%s:%p\n",
14897            depth * 2, "",
14898            _clutter_actor_get_debug_name (actor),
14899            actor);
14900
14901   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14902 }
14903
14904 static void
14905 _clutter_actor_traverse_breadth (ClutterActor           *actor,
14906                                  ClutterTraverseCallback callback,
14907                                  gpointer                user_data)
14908 {
14909   GQueue *queue = g_queue_new ();
14910   ClutterActor dummy;
14911   int current_depth = 0;
14912
14913   g_queue_push_tail (queue, actor);
14914   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
14915
14916   while ((actor = g_queue_pop_head (queue)))
14917     {
14918       ClutterActorTraverseVisitFlags flags;
14919
14920       if (actor == &dummy)
14921         {
14922           current_depth++;
14923           g_queue_push_tail (queue, &dummy);
14924           continue;
14925         }
14926
14927       flags = callback (actor, current_depth, user_data);
14928       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14929         break;
14930       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14931         {
14932           ClutterActor *iter;
14933
14934           for (iter = actor->priv->first_child;
14935                iter != NULL;
14936                iter = iter->priv->next_sibling)
14937             {
14938               g_queue_push_tail (queue, iter);
14939             }
14940         }
14941     }
14942
14943   g_queue_free (queue);
14944 }
14945
14946 static ClutterActorTraverseVisitFlags
14947 _clutter_actor_traverse_depth (ClutterActor           *actor,
14948                                ClutterTraverseCallback before_children_callback,
14949                                ClutterTraverseCallback after_children_callback,
14950                                int                     current_depth,
14951                                gpointer                user_data)
14952 {
14953   ClutterActorTraverseVisitFlags flags;
14954
14955   flags = before_children_callback (actor, current_depth, user_data);
14956   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14957     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14958
14959   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14960     {
14961       ClutterActor *iter;
14962
14963       for (iter = actor->priv->first_child;
14964            iter != NULL;
14965            iter = iter->priv->next_sibling)
14966         {
14967           flags = _clutter_actor_traverse_depth (iter,
14968                                                  before_children_callback,
14969                                                  after_children_callback,
14970                                                  current_depth + 1,
14971                                                  user_data);
14972
14973           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14974             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14975         }
14976     }
14977
14978   if (after_children_callback)
14979     return after_children_callback (actor, current_depth, user_data);
14980   else
14981     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14982 }
14983
14984 /* _clutter_actor_traverse:
14985  * @actor: The actor to start traversing the graph from
14986  * @flags: These flags may affect how the traversal is done
14987  * @before_children_callback: A function to call before visiting the
14988  *   children of the current actor.
14989  * @after_children_callback: A function to call after visiting the
14990  *   children of the current actor. (Ignored if
14991  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
14992  * @user_data: The private data to pass to the callbacks
14993  *
14994  * Traverses the scenegraph starting at the specified @actor and
14995  * descending through all its children and its children's children.
14996  * For each actor traversed @before_children_callback and
14997  * @after_children_callback are called with the specified
14998  * @user_data, before and after visiting that actor's children.
14999  *
15000  * The callbacks can return flags that affect the ongoing traversal
15001  * such as by skipping over an actors children or bailing out of
15002  * any further traversing.
15003  */
15004 void
15005 _clutter_actor_traverse (ClutterActor              *actor,
15006                          ClutterActorTraverseFlags  flags,
15007                          ClutterTraverseCallback    before_children_callback,
15008                          ClutterTraverseCallback    after_children_callback,
15009                          gpointer                   user_data)
15010 {
15011   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15012     _clutter_actor_traverse_breadth (actor,
15013                                      before_children_callback,
15014                                      user_data);
15015   else /* DEPTH_FIRST */
15016     _clutter_actor_traverse_depth (actor,
15017                                    before_children_callback,
15018                                    after_children_callback,
15019                                    0, /* start depth */
15020                                    user_data);
15021 }
15022
15023 static void
15024 on_layout_manager_changed (ClutterLayoutManager *manager,
15025                            ClutterActor         *self)
15026 {
15027   clutter_actor_queue_relayout (self);
15028 }
15029
15030 /**
15031  * clutter_actor_set_layout_manager:
15032  * @self: a #ClutterActor
15033  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15034  *
15035  * Sets the #ClutterLayoutManager delegate object that will be used to
15036  * lay out the children of @self.
15037  *
15038  * The #ClutterActor will take a reference on the passed @manager which
15039  * will be released either when the layout manager is removed, or when
15040  * the actor is destroyed.
15041  *
15042  * Since: 1.10
15043  */
15044 void
15045 clutter_actor_set_layout_manager (ClutterActor         *self,
15046                                   ClutterLayoutManager *manager)
15047 {
15048   ClutterActorPrivate *priv;
15049
15050   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15051   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15052
15053   priv = self->priv;
15054
15055   if (priv->layout_manager != NULL)
15056     {
15057       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15058                                             G_CALLBACK (on_layout_manager_changed),
15059                                             self);
15060       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15061       g_object_unref (priv->layout_manager);
15062     }
15063
15064   priv->layout_manager = manager;
15065
15066   if (priv->layout_manager != NULL)
15067     {
15068       g_object_ref_sink (priv->layout_manager);
15069       clutter_layout_manager_set_container (priv->layout_manager,
15070                                             CLUTTER_CONTAINER (self));
15071       g_signal_connect (priv->layout_manager, "layout-changed",
15072                         G_CALLBACK (on_layout_manager_changed),
15073                         self);
15074     }
15075
15076   clutter_actor_queue_relayout (self);
15077
15078   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15079 }
15080
15081 /**
15082  * clutter_actor_get_layout_manager:
15083  * @self: a #ClutterActor
15084  *
15085  * Retrieves the #ClutterLayoutManager used by @self.
15086  *
15087  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15088  *   or %NULL
15089  *
15090  * Since: 1.10
15091  */
15092 ClutterLayoutManager *
15093 clutter_actor_get_layout_manager (ClutterActor *self)
15094 {
15095   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15096
15097   return self->priv->layout_manager;
15098 }
15099
15100 static const ClutterLayoutInfo default_layout_info = {
15101   0.f,                          /* fixed-x */
15102   0.f,                          /* fixed-y */
15103   { 0, 0, 0, 0 },               /* margin */
15104   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15105   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15106   0.f, 0.f,                     /* min_width, natural_width */
15107   0.f, 0.f,                     /* natual_width, natural_height */
15108 };
15109
15110 static void
15111 layout_info_free (gpointer data)
15112 {
15113   if (G_LIKELY (data != NULL))
15114     g_slice_free (ClutterLayoutInfo, data);
15115 }
15116
15117 /*< private >
15118  * _clutter_actor_get_layout_info:
15119  * @self: a #ClutterActor
15120  *
15121  * Retrieves a pointer to the ClutterLayoutInfo structure.
15122  *
15123  * If the actor does not have a ClutterLayoutInfo associated to it, one
15124  * will be created and initialized to the default values.
15125  *
15126  * This function should be used for setters.
15127  *
15128  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15129  * instead.
15130  *
15131  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15132  */
15133 ClutterLayoutInfo *
15134 _clutter_actor_get_layout_info (ClutterActor *self)
15135 {
15136   ClutterLayoutInfo *retval;
15137
15138   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15139   if (retval == NULL)
15140     {
15141       retval = g_slice_new (ClutterLayoutInfo);
15142
15143       *retval = default_layout_info;
15144
15145       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15146                                retval,
15147                                layout_info_free);
15148     }
15149
15150   return retval;
15151 }
15152
15153 /*< private >
15154  * _clutter_actor_get_layout_info_or_defaults:
15155  * @self: a #ClutterActor
15156  *
15157  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15158  *
15159  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15160  * then the default structure will be returned.
15161  *
15162  * This function should only be used for getters.
15163  *
15164  * Return value: a const pointer to the ClutterLayoutInfo structure
15165  */
15166 const ClutterLayoutInfo *
15167 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15168 {
15169   const ClutterLayoutInfo *info;
15170
15171   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15172   if (info == NULL)
15173     return &default_layout_info;
15174
15175   return info;
15176 }
15177
15178 /**
15179  * clutter_actor_set_x_align:
15180  * @self: a #ClutterActor
15181  * @x_align: the horizontal alignment policy
15182  *
15183  * Sets the horizontal alignment policy of a #ClutterActor, in case the
15184  * actor received extra horizontal space.
15185  *
15186  * See also the #ClutterActor:x-align property.
15187  *
15188  * Since: 1.10
15189  */
15190 void
15191 clutter_actor_set_x_align (ClutterActor      *self,
15192                            ClutterActorAlign  x_align)
15193 {
15194   ClutterLayoutInfo *info;
15195
15196   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15197
15198   info = _clutter_actor_get_layout_info (self);
15199
15200   if (info->x_align != x_align)
15201     {
15202       info->x_align = x_align;
15203
15204       clutter_actor_queue_relayout (self);
15205
15206       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15207     }
15208 }
15209
15210 /**
15211  * clutter_actor_get_x_align:
15212  * @self: a #ClutterActor
15213  *
15214  * Retrieves the horizontal alignment policy set using
15215  * clutter_actor_set_x_align().
15216  *
15217  * Return value: the horizontal alignment policy.
15218  *
15219  * Since: 1.10
15220  */
15221 ClutterActorAlign
15222 clutter_actor_get_x_align (ClutterActor *self)
15223 {
15224   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15225
15226   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15227 }
15228
15229 /**
15230  * clutter_actor_set_y_align:
15231  * @self: a #ClutterActor
15232  * @y_align: the vertical alignment policy
15233  *
15234  * Sets the vertical alignment policy of a #ClutterActor, in case the
15235  * actor received extra vertical space.
15236  *
15237  * See also the #ClutterActor:y-align property.
15238  *
15239  * Since: 1.10
15240  */
15241 void
15242 clutter_actor_set_y_align (ClutterActor      *self,
15243                            ClutterActorAlign  y_align)
15244 {
15245   ClutterLayoutInfo *info;
15246
15247   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15248
15249   info = _clutter_actor_get_layout_info (self);
15250
15251   if (info->y_align != y_align)
15252     {
15253       info->y_align = y_align;
15254
15255       clutter_actor_queue_relayout (self);
15256
15257       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15258     }
15259 }
15260
15261 /**
15262  * clutter_actor_get_y_align:
15263  * @self: a #ClutterActor
15264  *
15265  * Retrieves the vertical alignment policy set using
15266  * clutter_actor_set_y_align().
15267  *
15268  * Return value: the vertical alignment policy.
15269  *
15270  * Since: 1.10
15271  */
15272 ClutterActorAlign
15273 clutter_actor_get_y_align (ClutterActor *self)
15274 {
15275   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15276
15277   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15278 }
15279
15280
15281 /**
15282  * clutter_margin_new:
15283  *
15284  * Creates a new #ClutterMargin.
15285  *
15286  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15287  *   clutter_margin_free() to free the resources associated with it when
15288  *   done.
15289  *
15290  * Since: 1.10
15291  */
15292 ClutterMargin *
15293 clutter_margin_new (void)
15294 {
15295   return g_slice_new0 (ClutterMargin);
15296 }
15297
15298 /**
15299  * clutter_margin_copy:
15300  * @margin_: a #ClutterMargin
15301  *
15302  * Creates a new #ClutterMargin and copies the contents of @margin_ into
15303  * the newly created structure.
15304  *
15305  * Return value: (transfer full): a copy of the #ClutterMargin.
15306  *
15307  * Since: 1.10
15308  */
15309 ClutterMargin *
15310 clutter_margin_copy (const ClutterMargin *margin_)
15311 {
15312   if (G_LIKELY (margin_ != NULL))
15313     return g_slice_dup (ClutterMargin, margin_);
15314
15315   return NULL;
15316 }
15317
15318 /**
15319  * clutter_margin_free:
15320  * @margin_: a #ClutterMargin
15321  *
15322  * Frees the resources allocated by clutter_margin_new() and
15323  * clutter_margin_copy().
15324  *
15325  * Since: 1.10
15326  */
15327 void
15328 clutter_margin_free (ClutterMargin *margin_)
15329 {
15330   if (G_LIKELY (margin_ != NULL))
15331     g_slice_free (ClutterMargin, margin_);
15332 }
15333
15334 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
15335                      clutter_margin_copy,
15336                      clutter_margin_free)
15337
15338 /**
15339  * clutter_actor_set_margin:
15340  * @self: a #ClutterActor
15341  * @margin: a #ClutterMargin
15342  *
15343  * Sets all the components of the margin of a #ClutterActor.
15344  *
15345  * Since: 1.10
15346  */
15347 void
15348 clutter_actor_set_margin (ClutterActor        *self,
15349                           const ClutterMargin *margin)
15350 {
15351   ClutterLayoutInfo *info;
15352   gboolean changed;
15353   GObject *obj;
15354
15355   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15356   g_return_if_fail (margin != NULL);
15357
15358   obj = G_OBJECT (self);
15359   changed = FALSE;
15360
15361   g_object_freeze_notify (obj);
15362
15363   info = _clutter_actor_get_layout_info (self);
15364
15365   if (info->margin.top != margin->top)
15366     {
15367       info->margin.top = margin->top;
15368       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
15369       changed = TRUE;
15370     }
15371
15372   if (info->margin.right != margin->right)
15373     {
15374       info->margin.right = margin->right;
15375       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
15376       changed = TRUE;
15377     }
15378
15379   if (info->margin.bottom != margin->bottom)
15380     {
15381       info->margin.bottom = margin->bottom;
15382       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
15383       changed = TRUE;
15384     }
15385
15386   if (info->margin.left != margin->left)
15387     {
15388       info->margin.left = margin->left;
15389       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
15390       changed = TRUE;
15391     }
15392
15393   if (changed)
15394     clutter_actor_queue_relayout (self);
15395
15396   g_object_thaw_notify (obj);
15397 }
15398
15399 /**
15400  * clutter_actor_get_margin:
15401  * @self: a #ClutterActor
15402  * @margin: (out caller-allocates): return location for a #ClutterMargin
15403  *
15404  * Retrieves all the components of the margin of a #ClutterActor.
15405  *
15406  * Since: 1.10
15407  */
15408 void
15409 clutter_actor_get_margin (ClutterActor  *self,
15410                           ClutterMargin *margin)
15411 {
15412   const ClutterLayoutInfo *info;
15413
15414   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15415   g_return_if_fail (margin != NULL);
15416
15417   info = _clutter_actor_get_layout_info_or_defaults (self);
15418
15419   *margin = info->margin;
15420 }
15421
15422 /**
15423  * clutter_actor_set_margin_top:
15424  * @self: a #ClutterActor
15425  * @margin: the top margin
15426  *
15427  * Sets the margin from the top of a #ClutterActor.
15428  *
15429  * Since: 1.10
15430  */
15431 void
15432 clutter_actor_set_margin_top (ClutterActor *self,
15433                               gfloat        margin)
15434 {
15435   ClutterLayoutInfo *info;
15436
15437   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15438   g_return_if_fail (margin >= 0.f);
15439
15440   info = _clutter_actor_get_layout_info (self);
15441
15442   if (info->margin.top == margin)
15443     return;
15444
15445   info->margin.top = margin;
15446
15447   clutter_actor_queue_relayout (self);
15448
15449   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
15450 }
15451
15452 /**
15453  * clutter_actor_get_margin_top:
15454  * @self: a #ClutterActor
15455  *
15456  * Retrieves the top margin of a #ClutterActor.
15457  *
15458  * Return value: the top margin
15459  *
15460  * Since: 1.10
15461  */
15462 gfloat
15463 clutter_actor_get_margin_top (ClutterActor *self)
15464 {
15465   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15466
15467   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
15468 }
15469
15470 /**
15471  * clutter_actor_set_margin_bottom:
15472  * @self: a #ClutterActor
15473  * @margin: the bottom margin
15474  *
15475  * Sets the margin from the bottom of a #ClutterActor.
15476  *
15477  * Since: 1.10
15478  */
15479 void
15480 clutter_actor_set_margin_bottom (ClutterActor *self,
15481                                  gfloat        margin)
15482 {
15483   ClutterLayoutInfo *info;
15484
15485   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15486   g_return_if_fail (margin >= 0.f);
15487
15488   info = _clutter_actor_get_layout_info (self);
15489
15490   if (info->margin.bottom == margin)
15491     return;
15492
15493   info->margin.bottom = margin;
15494
15495   clutter_actor_queue_relayout (self);
15496
15497   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
15498 }
15499
15500 /**
15501  * clutter_actor_get_margin_bottom:
15502  * @self: a #ClutterActor
15503  *
15504  * Retrieves the bottom margin of a #ClutterActor.
15505  *
15506  * Return value: the bottom margin
15507  *
15508  * Since: 1.10
15509  */
15510 gfloat
15511 clutter_actor_get_margin_bottom (ClutterActor *self)
15512 {
15513   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15514
15515   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
15516 }
15517
15518 /**
15519  * clutter_actor_set_margin_left:
15520  * @self: a #ClutterActor
15521  * @margin: the left margin
15522  *
15523  * Sets the margin from the left of a #ClutterActor.
15524  *
15525  * Since: 1.10
15526  */
15527 void
15528 clutter_actor_set_margin_left (ClutterActor *self,
15529                                gfloat        margin)
15530 {
15531   ClutterLayoutInfo *info;
15532
15533   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15534   g_return_if_fail (margin >= 0.f);
15535
15536   info = _clutter_actor_get_layout_info (self);
15537
15538   if (info->margin.left == margin)
15539     return;
15540
15541   info->margin.left = margin;
15542
15543   clutter_actor_queue_relayout (self);
15544
15545   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
15546 }
15547
15548 /**
15549  * clutter_actor_get_margin_left:
15550  * @self: a #ClutterActor
15551  *
15552  * Retrieves the left margin of a #ClutterActor.
15553  *
15554  * Return value: the left margin
15555  *
15556  * Since: 1.10
15557  */
15558 gfloat
15559 clutter_actor_get_margin_left (ClutterActor *self)
15560 {
15561   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15562
15563   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
15564 }
15565
15566 /**
15567  * clutter_actor_set_margin_right:
15568  * @self: a #ClutterActor
15569  * @margin: the right margin
15570  *
15571  * Sets the margin from the right of a #ClutterActor.
15572  *
15573  * Since: 1.10
15574  */
15575 void
15576 clutter_actor_set_margin_right (ClutterActor *self,
15577                                 gfloat        margin)
15578 {
15579   ClutterLayoutInfo *info;
15580
15581   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15582   g_return_if_fail (margin >= 0.f);
15583
15584   info = _clutter_actor_get_layout_info (self);
15585
15586   if (info->margin.right == margin)
15587     return;
15588
15589   info->margin.right = margin;
15590
15591   clutter_actor_queue_relayout (self);
15592
15593   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
15594 }
15595
15596 /**
15597  * clutter_actor_get_margin_right:
15598  * @self: a #ClutterActor
15599  *
15600  * Retrieves the right margin of a #ClutterActor.
15601  *
15602  * Return value: the right margin
15603  *
15604  * Since: 1.10
15605  */
15606 gfloat
15607 clutter_actor_get_margin_right (ClutterActor *self)
15608 {
15609   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15610
15611   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
15612 }
15613
15614 /**
15615  * clutter_actor_set_background_color:
15616  * @self: a #ClutterActor
15617  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
15618  *  set color
15619  *
15620  * Sets the background color of a #ClutterActor.
15621  *
15622  * The background color will be used to cover the whole allocation of the
15623  * actor. The default background color of an actor is transparent.
15624  *
15625  * To check whether an actor has a background color, you can use the
15626  * #ClutterActor:background-color-set actor property.
15627  *
15628  * Since: 1.10
15629  */
15630 void
15631 clutter_actor_set_background_color (ClutterActor       *self,
15632                                     const ClutterColor *color)
15633 {
15634   ClutterActorPrivate *priv;
15635
15636   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15637
15638   priv = self->priv;
15639
15640   if (color == NULL)
15641     {
15642       priv->bg_color_set = FALSE;
15643       g_object_notify_by_pspec (G_OBJECT (self),
15644                                 obj_props[PROP_BACKGROUND_COLOR_SET]);
15645       return;
15646     }
15647
15648   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
15649     return;
15650
15651   priv->bg_color = *color;
15652   priv->bg_color_set = TRUE;
15653
15654   clutter_actor_queue_redraw (self);
15655
15656   g_object_notify_by_pspec (G_OBJECT (self),
15657                             obj_props[PROP_BACKGROUND_COLOR_SET]);
15658   g_object_notify_by_pspec (G_OBJECT (self),
15659                             obj_props[PROP_BACKGROUND_COLOR]);
15660 }
15661
15662 /**
15663  * clutter_actor_get_background_color:
15664  * @self: a #ClutterActor
15665  * @color: (out caller-allocates): return location for a #ClutterColor
15666  *
15667  * Retrieves the color set using clutter_actor_set_background_color().
15668  *
15669  * Since: 1.10
15670  */
15671 void
15672 clutter_actor_get_background_color (ClutterActor *self,
15673                                     ClutterColor *color)
15674 {
15675   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15676   g_return_if_fail (color != NULL);
15677
15678   *color = self->priv->bg_color;
15679 }
15680
15681 /**
15682  * clutter_actor_get_previous_sibling:
15683  * @self: a #ClutterActor
15684  *
15685  * Retrieves the sibling of @self that comes before it in the list
15686  * of children of @self's parent.
15687  *
15688  * The returned pointer is only valid until the scene graph changes; it
15689  * is not safe to modify the list of children of @self while iterating
15690  * it.
15691  *
15692  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15693  *
15694  * Since: 1.10
15695  */
15696 ClutterActor *
15697 clutter_actor_get_previous_sibling (ClutterActor *self)
15698 {
15699   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15700
15701   return self->priv->prev_sibling;
15702 }
15703
15704 /**
15705  * clutter_actor_get_next_sibling:
15706  * @self: a #ClutterActor
15707  *
15708  * Retrieves the sibling of @self that comes after it in the list
15709  * of children of @self's parent.
15710  *
15711  * The returned pointer is only valid until the scene graph changes; it
15712  * is not safe to modify the list of children of @self while iterating
15713  * it.
15714  *
15715  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15716  *
15717  * Since: 1.10
15718  */
15719 ClutterActor *
15720 clutter_actor_get_next_sibling (ClutterActor *self)
15721 {
15722   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15723
15724   return self->priv->next_sibling;
15725 }
15726
15727 /**
15728  * clutter_actor_get_first_child:
15729  * @self: a #ClutterActor
15730  *
15731  * Retrieves the first child of @self.
15732  *
15733  * The returned pointer is only valid until the scene graph changes; it
15734  * is not safe to modify the list of children of @self while iterating
15735  * it.
15736  *
15737  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15738  *
15739  * Since: 1.10
15740  */
15741 ClutterActor *
15742 clutter_actor_get_first_child (ClutterActor *self)
15743 {
15744   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15745
15746   return self->priv->first_child;
15747 }
15748
15749 /**
15750  * clutter_actor_get_last_child:
15751  * @self: a #ClutterActor
15752  *
15753  * Retrieves the last child of @self.
15754  *
15755  * The returned pointer is only valid until the scene graph changes; it
15756  * is not safe to modify the list of children of @self while iterating
15757  * it.
15758  *
15759  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15760  *
15761  * Since: 1.10
15762  */
15763 ClutterActor *
15764 clutter_actor_get_last_child (ClutterActor *self)
15765 {
15766   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15767
15768   return self->priv->last_child;
15769 }
15770
15771 /* easy way to have properly named fields instead of the dummy ones
15772  * we use in the public structure
15773  */
15774 typedef struct _RealActorIter
15775 {
15776   ClutterActor *root;           /* dummy1 */
15777   ClutterActor *current;        /* dummy2 */
15778   gpointer padding_1;           /* dummy3 */
15779   gint age;                     /* dummy4 */
15780   gpointer padding_2;           /* dummy5 */
15781 } RealActorIter;
15782
15783 /**
15784  * clutter_actor_iter_init:
15785  * @iter: a #ClutterActorIter
15786  * @root: a #ClutterActor
15787  *
15788  * Initializes a #ClutterActorIter, which can then be used to iterate
15789  * efficiently over a section of the scene graph, and associates it
15790  * with @root.
15791  *
15792  * Modifying the scene graph section that contains @root will invalidate
15793  * the iterator.
15794  *
15795  * |[
15796  *   ClutterActorIter iter;
15797  *   ClutterActor *child;
15798  *
15799  *   clutter_actor_iter_init (&iter, container);
15800  *   while (clutter_actor_iter_next (&iter, &child))
15801  *     {
15802  *       /&ast; do something with child &ast;/
15803  *     }
15804  * ]|
15805  *
15806  * Since: 1.10
15807  */
15808 void
15809 clutter_actor_iter_init (ClutterActorIter *iter,
15810                          ClutterActor     *root)
15811 {
15812   RealActorIter *ri = (RealActorIter *) iter;
15813
15814   g_return_if_fail (iter != NULL);
15815   g_return_if_fail (CLUTTER_IS_ACTOR (root));
15816
15817   ri->root = root;
15818   ri->current = NULL;
15819   ri->age = root->priv->age;
15820 }
15821
15822 /**
15823  * clutter_actor_iter_next:
15824  * @iter: a #ClutterActorIter
15825  * @child: (out): return location for a #ClutterActor
15826  *
15827  * Advances the @iter and retrieves the next child of the root #ClutterActor
15828  * that was used to initialize the #ClutterActorIterator.
15829  *
15830  * If the iterator can advance, this function returns %TRUE and sets the
15831  * @child argument.
15832  *
15833  * If the iterator cannot advance, this function returns %FALSE, and
15834  * the contents of @child are undefined.
15835  *
15836  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15837  *
15838  * Since: 1.10
15839  */
15840 gboolean
15841 clutter_actor_iter_next (ClutterActorIter  *iter,
15842                          ClutterActor     **child)
15843 {
15844   RealActorIter *ri = (RealActorIter *) iter;
15845
15846   g_return_val_if_fail (iter != NULL, FALSE);
15847   g_return_val_if_fail (ri->root != NULL, FALSE);
15848 #ifndef G_DISABLE_ASSERT
15849   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15850 #endif
15851
15852   if (ri->current == NULL)
15853     ri->current = ri->root->priv->first_child;
15854   else
15855     ri->current = ri->current->priv->next_sibling;
15856
15857   if (child != NULL)
15858     *child = ri->current;
15859
15860   return ri->current != NULL;
15861 }
15862
15863 /**
15864  * clutter_actor_iter_prev:
15865  * @iter: a #ClutterActorIter
15866  * @child: (out): return location for a #ClutterActor
15867  *
15868  * Advances the @iter and retrieves the previous child of the root
15869  * #ClutterActor that was used to initialize the #ClutterActorIterator.
15870  *
15871  * If the iterator can advance, this function returns %TRUE and sets the
15872  * @child argument.
15873  *
15874  * If the iterator cannot advance, this function returns %FALSE, and
15875  * the contents of @child are undefined.
15876  *
15877  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15878  *
15879  * Since: 1.10
15880  */
15881 gboolean
15882 clutter_actor_iter_prev (ClutterActorIter  *iter,
15883                          ClutterActor     **child)
15884 {
15885   RealActorIter *ri = (RealActorIter *) iter;
15886
15887   g_return_val_if_fail (iter != NULL, FALSE);
15888   g_return_val_if_fail (ri->root != NULL, FALSE);
15889 #ifndef G_DISABLE_ASSERT
15890   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15891 #endif
15892
15893   if (ri->current == NULL)
15894     ri->current = ri->root->priv->last_child;
15895   else
15896     ri->current = ri->current->priv->prev_sibling;
15897
15898   if (child != NULL)
15899     *child = ri->current;
15900
15901   return ri->current != NULL;
15902 }
15903
15904 /**
15905  * clutter_actor_iter_remove:
15906  * @iter: a #ClutterActorIter
15907  *
15908  * Safely removes the #ClutterActor currently pointer to by the iterator
15909  * from its parent.
15910  *
15911  * This function can only be called after clutter_actor_iter_next() or
15912  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15913  * than once for the same actor.
15914  *
15915  * This function will call clutter_actor_remove_child() internally.
15916  *
15917  * Since: 1.10
15918  */
15919 void
15920 clutter_actor_iter_remove (ClutterActorIter *iter)
15921 {
15922   RealActorIter *ri = (RealActorIter *) iter;
15923   ClutterActor *cur;
15924
15925   g_return_if_fail (iter != NULL);
15926   g_return_if_fail (ri->root != NULL);
15927 #ifndef G_DISABLE_ASSERT
15928   g_return_if_fail (ri->age == ri->root->priv->age);
15929 #endif
15930   g_return_if_fail (ri->current != NULL);
15931
15932   cur = ri->current;
15933
15934   if (cur != NULL)
15935     {
15936       ri->current = cur->priv->prev_sibling;
15937
15938       clutter_actor_remove_child_internal (ri->root, cur,
15939                                            REMOVE_CHILD_DEFAULT_FLAGS);
15940
15941       ri->age += 1;
15942     }
15943 }
15944
15945 /**
15946  * clutter_actor_iter_destroy:
15947  * @iter: a #ClutterActorIter
15948  *
15949  * Safely destroys the #ClutterActor currently pointer to by the iterator
15950  * from its parent.
15951  *
15952  * This function can only be called after clutter_actor_iter_next() or
15953  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15954  * than once for the same actor.
15955  *
15956  * This function will call clutter_actor_destroy() internally.
15957  *
15958  * Since: 1.10
15959  */
15960 void
15961 clutter_actor_iter_destroy (ClutterActorIter *iter)
15962 {
15963   RealActorIter *ri = (RealActorIter *) iter;
15964   ClutterActor *cur;
15965
15966   g_return_if_fail (iter != NULL);
15967   g_return_if_fail (ri->root != NULL);
15968 #ifndef G_DISABLE_ASSERT
15969   g_return_if_fail (ri->age == ri->root->priv->age);
15970 #endif
15971   g_return_if_fail (ri->current != NULL);
15972
15973   cur = ri->current;
15974
15975   if (cur != NULL)
15976     {
15977       ri->current = cur->priv->prev_sibling;
15978
15979       clutter_actor_destroy (cur);
15980
15981       ri->age += 1;
15982     }
15983 }